1/* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: Run-Time Library 5 * FILE: lib/sdk/crt/math/i386/alldvrm_asm.s 6 * PROGRAMER: Alex Ionescu (alex@relsoft.net) 7 * 8 * Copyright (C) 2002 Michael Ringgaard. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the project nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES// LOSS OF USE, DATA, OR PROFITS// OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#include <asm.inc> 38 39PUBLIC __alldvrm 40 41/* FUNCTIONS ***************************************************************/ 42.code 43 44__alldvrm: 45 push edi 46 push esi 47 push ebp 48 49// Set up the local stack and save the index registers. When this is done 50// the stack frame will look as follows (assuming that the expression a/b will 51// generate a call to alldvrm(a, b)): 52// 53// ----------------- 54// | | 55// |---------------| 56// | | 57// |--divisor (b)--| 58// | | 59// |---------------| 60// | | 61// |--dividend (a)-| 62// | | 63// |---------------| 64// | return addr** | 65// |---------------| 66// | EDI | 67// |---------------| 68// | ESI | 69// |---------------| 70// ESP---->| EBP | 71// ----------------- 72// 73 74#undef DVNDLO 75#undef DVNDHI 76#undef DVSRLO 77#undef DVSRHI 78#define DVNDLO [esp + 16] // stack address of dividend (a) 79#define DVNDHI [esp + 20] // stack address of dividend (a) 80#define DVSRLO [esp + 24] // stack address of divisor (b) 81#define DVSRHI [esp + 28] // stack address of divisor (b) 82 83// Determine sign of the quotient (edi = 0 if result is positive, non-zero 84// otherwise) and make operands positive. 85// Sign of the remainder is kept in ebp. 86 87 xor edi,edi // result sign assumed positive 88 xor ebp,ebp // result sign assumed positive 89 90 mov eax,DVNDHI // hi word of a 91 or eax,eax // test to see if signed 92 jge short .L1 // skip rest if a is already positive 93 inc edi // complement result sign flag 94 inc ebp // complement result sign flag 95 mov edx,DVNDLO // lo word of a 96 neg eax // make a positive 97 neg edx 98 sbb eax,0 99 mov DVNDHI,eax // save positive value 100 mov DVNDLO,edx 101.L1: 102 mov eax,DVSRHI // hi word of b 103 or eax,eax // test to see if signed 104 jge short .L2 // skip rest if b is already positive 105 inc edi // complement the result sign flag 106 mov edx,DVSRLO // lo word of a 107 neg eax // make b positive 108 neg edx 109 sbb eax,0 110 mov DVSRHI,eax // save positive value 111 mov DVSRLO,edx 112.L2: 113 114// 115// Now do the divide. First look to see if the divisor is less than 4194304K. 116// If so, then we can use a simple algorithm with word divides, otherwise 117// things get a little more complex. 118// 119// NOTE - eax currently contains the high order word of DVSR 120// 121 122 or eax,eax // check to see if divisor < 4194304K 123 jnz short .L3 // nope, gotta do this the hard way 124 mov ecx,DVSRLO // load divisor 125 mov eax,DVNDHI // load high word of dividend 126 xor edx,edx 127 div ecx // eax <- high order bits of quotient 128 mov ebx,eax // save high bits of quotient 129 mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend 130 div ecx // eax <- low order bits of quotient 131 mov esi,eax // ebx:esi <- quotient 132// 133// Now we need to do a multiply so that we can compute the remainder. 134// 135 mov eax,ebx // set up high word of quotient 136 mul dword ptr DVSRLO // HIWORD(QUOT) * DVSR 137 mov ecx,eax // save the result in ecx 138 mov eax,esi // set up low word of quotient 139 mul dword ptr DVSRLO // LOWORD(QUOT) * DVSR 140 add edx,ecx // EDX:EAX = QUOT * DVSR 141 jmp short .L4 // complete remainder calculation 142 143// 144// Here we do it the hard way. Remember, eax contains the high word of DVSR 145// 146 147.L3: 148 mov ebx,eax // ebx:ecx <- divisor 149 mov ecx,DVSRLO 150 mov edx,DVNDHI // edx:eax <- dividend 151 mov eax,DVNDLO 152.L5: 153 shr ebx,1 // shift divisor right one bit 154 rcr ecx,1 155 shr edx,1 // shift dividend right one bit 156 rcr eax,1 157 or ebx,ebx 158 jnz short .L5 // loop until divisor < 4194304K 159 div ecx // now divide, ignore remainder 160 mov esi,eax // save quotient 161 162// 163// We may be off by one, so to check, we will multiply the quotient 164// by the divisor and check the result against the orignal dividend 165// Note that we must also check for overflow, which can occur if the 166// dividend is close to 2**64 and the quotient is off by 1. 167// 168 169 mul dword ptr DVSRHI // QUOT * DVSRHI 170 mov ecx,eax 171 mov eax,DVSRLO 172 mul esi // QUOT * DVSRLO 173 add edx,ecx // EDX:EAX = QUOT * DVSR 174 jc short .L6 // carry means Quotient is off by 1 175 176// 177// do long compare here between original dividend and the result of the 178// multiply in edx:eax. If original is larger or equal, we are ok, otherwise 179// subtract one (1) from the quotient. 180// 181 182 cmp edx,DVNDHI // compare hi words of result and original 183 ja short .L6 // if result > original, do subtract 184 jb short .L7 // if result < original, we are ok 185 cmp eax,DVNDLO // hi words are equal, compare lo words 186 jbe short .L7 // if less or equal we are ok, else subtract 187.L6: 188 dec esi // subtract 1 from quotient 189 sub eax,DVSRLO // subtract divisor from result 190 sbb edx,DVSRHI 191.L7: 192 xor ebx,ebx // ebx:esi <- quotient 193 194.L4: 195// 196// Calculate remainder by subtracting the result from the original dividend. 197// Since the result is already in a register, we will do the subtract in the 198// opposite direction and negate the result if necessary. 199// 200 201 sub eax,DVNDLO // subtract dividend from result 202 sbb edx,DVNDHI 203 204// 205// Now check the result sign flag to see if the result is supposed to be positive 206// or negative. It is currently negated (because we subtracted in the 'wrong' 207// direction), so if the sign flag is set we are done, otherwise we must negate 208// the result to make it positive again. 209// 210 211 dec ebp // check result sign flag 212 jns short .L9 // result is ok, set up the quotient 213 neg edx // otherwise, negate the result 214 neg eax 215 sbb edx,0 216 217// 218// Now we need to get the quotient into edx:eax and the remainder into ebx:ecx. 219// 220.L9: 221 mov ecx,edx 222 mov edx,ebx 223 mov ebx,ecx 224 mov ecx,eax 225 mov eax,esi 226 227// 228// Just the cleanup left to do. edx:eax contains the quotient. Set the sign 229// according to the save value, cleanup the stack, and return. 230// 231 232 dec edi // check to see if result is negative 233 jnz short .L8 // if EDI == 0, result should be negative 234 neg edx // otherwise, negate the result 235 neg eax 236 sbb edx,0 237 238// 239// Restore the saved registers and return. 240// 241 242.L8: 243 pop ebp 244 pop esi 245 pop edi 246 247 ret 16 248 249END 250