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/aulldvrm_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 __aulldvrm 40 41/* FUNCTIONS ***************************************************************/ 42.code 43 44__aulldvrm: 45 46// ulldvrm - unsigned long divide and remainder 47// 48// Purpose: 49// Does a unsigned long divide and remainder of the arguments. Arguments 50// are not changed. 51// 52// Entry: 53// Arguments are passed on the stack: 54// 1st pushed: divisor (QWORD) 55// 2nd pushed: dividend (QWORD) 56// 57// Exit: 58// EDX:EAX contains the quotient (dividend/divisor) 59// EBX:ECX contains the remainder (divided % divisor) 60// NOTE: this routine removes the parameters from the stack. 61// 62// Uses: 63// ECX 64// 65 push esi 66 67// Set up the local stack and save the index registers. When this is done 68// the stack frame will look as follows (assuming that the expression a/b will 69// generate a call to aulldvrm(a, b)): 70// 71// ----------------- 72// | | 73// |---------------| 74// | | 75// |--divisor (b)--| 76// | | 77// |---------------| 78// | | 79// |--dividend (a)-| 80// | | 81// |---------------| 82// | return addr** | 83// |---------------| 84// ESP---->| ESI | 85// ----------------- 86// 87 88#undef DVNDLO 89#undef DVNDHI 90#undef DVSRLO 91#undef DVSRHI 92#define DVNDLO [esp + 8] // stack address of dividend (a) 93#define DVNDHI [esp + 12] // stack address of dividend (a) 94#define DVSRLO [esp + 16] // stack address of divisor (b) 95#define DVSRHI [esp + 20] // stack address of divisor (b) 96 97// 98// Now do the divide. First look to see if the divisor is less than 4194304K. 99// If so, then we can use a simple algorithm with word divides, otherwise 100// things get a little more complex. 101// 102 103 mov eax,DVSRHI // check to see if divisor < 4194304K 104 or eax,eax 105 jnz short .L1 // nope, gotta do this the hard way 106 mov ecx,DVSRLO // load divisor 107 mov eax,DVNDHI // load high word of dividend 108 xor edx,edx 109 div ecx // get high order bits of quotient 110 mov ebx,eax // save high bits of quotient 111 mov eax,DVNDLO // edx:eax <- remainder:lo word of dividend 112 div ecx // get low order bits of quotient 113 mov esi,eax // ebx:esi <- quotient 114 115// 116// Now we need to do a multiply so that we can compute the remainder. 117// 118 mov eax,ebx // set up high word of quotient 119 mul dword ptr DVSRLO // HIWORD(QUOT) * DVSR 120 mov ecx,eax // save the result in ecx 121 mov eax,esi // set up low word of quotient 122 mul dword ptr DVSRLO // LOWORD(QUOT) * DVSR 123 add edx,ecx // EDX:EAX = QUOT * DVSR 124 jmp short .L2 // complete remainder calculation 125 126// 127// Here we do it the hard way. Remember, eax contains DVSRHI 128// 129 130.L1: 131 mov ecx,eax // ecx:ebx <- divisor 132 mov ebx,DVSRLO 133 mov edx,DVNDHI // edx:eax <- dividend 134 mov eax,DVNDLO 135.L3: 136 shr ecx,1 // shift divisor right one bit// hi bit <- 0 137 rcr ebx,1 138 shr edx,1 // shift dividend right one bit// hi bit <- 0 139 rcr eax,1 140 or ecx,ecx 141 jnz short .L3 // loop until divisor < 4194304K 142 div ebx // now divide, ignore remainder 143 mov esi,eax // save quotient 144 145// 146// We may be off by one, so to check, we will multiply the quotient 147// by the divisor and check the result against the orignal dividend 148// Note that we must also check for overflow, which can occur if the 149// dividend is close to 2**64 and the quotient is off by 1. 150// 151 152 mul dword ptr DVSRHI // QUOT * DVSRHI 153 mov ecx,eax 154 mov eax,DVSRLO 155 mul esi // QUOT * DVSRLO 156 add edx,ecx // EDX:EAX = QUOT * DVSR 157 jc short .L4 // carry means Quotient is off by 1 158 159// 160// do long compare here between original dividend and the result of the 161// multiply in edx:eax. If original is larger or equal, we are ok, otherwise 162// subtract one (1) from the quotient. 163// 164 165 cmp edx,DVNDHI // compare hi words of result and original 166 ja short .L4 // if result > original, do subtract 167 jb short .L5 // if result < original, we are ok 168 cmp eax,DVNDLO // hi words are equal, compare lo words 169 jbe short .L5 // if less or equal we are ok, else subtract 170.L4: 171 dec esi // subtract 1 from quotient 172 sub eax,DVSRLO // subtract divisor from result 173 sbb edx,DVSRHI 174.L5: 175 xor ebx,ebx // ebx:esi <- quotient 176 177.L2: 178// 179// Calculate remainder by subtracting the result from the original dividend. 180// Since the result is already in a register, we will do the subtract in the 181// opposite direction and negate the result. 182// 183 184 sub eax,DVNDLO // subtract dividend from result 185 sbb edx,DVNDHI 186 neg edx // otherwise, negate the result 187 neg eax 188 sbb edx,0 189 190// 191// Now we need to get the quotient into edx:eax and the remainder into ebx:ecx. 192// 193 mov ecx,edx 194 mov edx,ebx 195 mov ebx,ecx 196 mov ecx,eax 197 mov eax,esi 198// 199// Just the cleanup left to do. edx:eax contains the quotient. 200// Restore the saved registers and return. 201// 202 203 pop esi 204 205 ret 16 206 207END 208