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