Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/include/arch/i386-div64.h need to be fixed.

0001 /*                    The Quest Operating System
0002  *  Copyright (C) 2005-2010  Richard West, Boston University
0003  *
0004  *  This program is free software: you can redistribute it and/or modify
0005  *  it under the terms of the GNU General Public License as published by
0006  *  the Free Software Foundation, either version 3 of the License, or
0007  *  (at your option) any later version.
0008  *
0009  *  This program is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *  GNU General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU General Public License
0015  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 #ifndef __I386_DIV64_H__
0019 #define __I386_DIV64_H__
0020 #include"types.h"
0021 
0022 /* Courtesy of Linux */
0023 
0024 /*
0025  * do_div() is NOT a C function. It wants to return
0026  * two values (the quotient and the remainder), but
0027  * since that doesn't work very well in C, what it
0028  * does is:
0029  *
0030  * - modifies the 64-bit dividend _in_place_
0031  * - returns the 32-bit remainder
0032  *
0033  * This ends up being the most efficient "calling
0034  * convention" on x86.
0035  */
0036 #define do_div(n, base)                     \
0037 ({                              \
0038   unsigned long __upper, __low, __high, __mod, __base;          \
0039   __base = (base);                                              \
0040   asm("":"=a" (__low), "=d" (__high) : "A" (n));        \
0041   __upper = __high;                                             \
0042   if (__high) {                                                 \
0043     __upper = __high % (__base);                                \
0044     __high = __high / (__base);                                 \
0045   }                                                             \
0046   asm("divl %2":"=a" (__low), "=d" (__mod)                      \
0047       : "rm" (__base), "0" (__low), "1" (__upper));             \
0048   asm("":"=A" (n) : "a" (__low), "d" (__high));                 \
0049   __mod;                            \
0050  })
0051 
0052 static inline u64
0053 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
0054 {
0055   union {
0056     u64 v64;
0057     u32 v32[2];
0058   } d = { dividend };
0059   u32 upper;
0060 
0061   upper = d.v32[1];
0062   d.v32[1] = 0;
0063   if (upper >= divisor) {
0064     d.v32[1] = upper / divisor;
0065     upper %= divisor;
0066   }
0067   asm ("divl %2" : "=a" (d.v32[0]), "=d" (*remainder) :
0068        "rm" (divisor), "0" (d.v32[0]), "1" (upper));
0069   return d.v64;
0070 }
0071 #define div_u64_rem div_u64_rem
0072 
0073 /* 64bit divisor, dividend and result. dynamic precision */
0074 static inline uint64_t
0075 div64_64 (uint64_t dividend, uint64_t divisor)
0076 {
0077   uint32_t high, d;
0078 
0079   high = divisor >> 32;
0080   if (high) {
0081     unsigned int shift = fls(high);
0082 
0083     d = divisor >> shift;
0084     dividend >>= shift;
0085   } else
0086     d = divisor;
0087 
0088   do_div(dividend, d);
0089 
0090   return dividend;
0091 }
0092 
0093 #endif
0094 
0095 /*
0096  * Local Variables:
0097  * indent-tabs-mode: nil
0098  * mode: C
0099  * c-file-style: "gnu"
0100  * c-basic-offset: 2
0101  * End:
0102  */
0103 
0104 /* vi: set et sw=2 sts=2: */