| ;*** | |
| ;lldiv.asm - signed long divide routine | |
| ; | |
| ; Copyright (c) Microsoft Corporation. All rights reserved. | |
| ; SPDX-License-Identifier: BSD-2-Clause-Patent | |
| ; | |
| ;Purpose: | |
| ; defines the signed long divide routine | |
| ; __alldiv | |
| ; | |
| ;Original Implemenation: MSVC 14.29.30133 | |
| ; | |
| ;******************************************************************************* | |
| .686 | |
| .model flat,C | |
| .code | |
| ;*** | |
| ;lldiv - signed long divide | |
| ; | |
| ;Purpose: | |
| ; Does a signed long divide of the arguments. Arguments are | |
| ; not changed. | |
| ; | |
| ;Entry: | |
| ; Arguments are passed on the stack: | |
| ; 1st pushed: divisor (QWORD) | |
| ; 2nd pushed: dividend (QWORD) | |
| ; | |
| ;Exit: | |
| ; EDX:EAX contains the quotient (dividend/divisor) | |
| ; NOTE: this routine removes the parameters from the stack. | |
| ; | |
| ;Uses: | |
| ; ECX | |
| ; | |
| ;Exceptions: | |
| ; | |
| ;******************************************************************************* | |
| _alldiv PROC NEAR | |
| HIWORD EQU [4] ; | |
| LOWORD EQU [0] | |
| push edi | |
| push esi | |
| push ebx | |
| ; Set up the local stack and save the index registers. When this is done | |
| ; the stack frame will look as follows (assuming that the expression a/b will | |
| ; generate a call to lldiv(a, b)): | |
| ; | |
| ; ----------------- | |
| ; | | | |
| ; |---------------| | |
| ; | | | |
| ; |--divisor (b)--| | |
| ; | | | |
| ; |---------------| | |
| ; | | | |
| ; |--dividend (a)-| | |
| ; | | | |
| ; |---------------| | |
| ; | return addr** | | |
| ; |---------------| | |
| ; | EDI | | |
| ; |---------------| | |
| ; | ESI | | |
| ; |---------------| | |
| ; ESP---->| EBX | | |
| ; ----------------- | |
| ; | |
| DVND equ [esp + 16] ; stack address of dividend (a) | |
| DVSR equ [esp + 24] ; stack address of divisor (b) | |
| ; Determine sign of the result (edi = 0 if result is positive, non-zero | |
| ; otherwise) and make operands positive. | |
| xor edi,edi ; result sign assumed positive | |
| mov eax,HIWORD(DVND) ; hi word of a | |
| or eax,eax ; test to see if signed | |
| jge short L1 ; skip rest if a is already positive | |
| inc edi ; complement result sign flag | |
| mov edx,LOWORD(DVND) ; lo word of a | |
| neg eax ; make a positive | |
| neg edx | |
| sbb eax,0 | |
| mov HIWORD(DVND),eax ; save positive value | |
| mov LOWORD(DVND),edx | |
| L1: | |
| mov eax,HIWORD(DVSR) ; hi word of b | |
| or eax,eax ; test to see if signed | |
| jge short L2 ; skip rest if b is already positive | |
| inc edi ; complement the result sign flag | |
| mov edx,LOWORD(DVSR) ; lo word of a | |
| neg eax ; make b positive | |
| neg edx | |
| sbb eax,0 | |
| mov HIWORD(DVSR),eax ; save positive value | |
| mov LOWORD(DVSR),edx | |
| L2: | |
| ; | |
| ; Now do the divide. First look to see if the divisor is less than 4194304K. | |
| ; If so, then we can use a simple algorithm with word divides, otherwise | |
| ; things get a little more complex. | |
| ; | |
| ; NOTE - eax currently contains the high order word of DVSR | |
| ; | |
| or eax,eax ; check to see if divisor < 4194304K | |
| jnz short L3 ; nope, gotta do this the hard way | |
| mov ecx,LOWORD(DVSR) ; load divisor | |
| mov eax,HIWORD(DVND) ; load high word of dividend | |
| xor edx,edx | |
| div ecx ; eax <- high order bits of quotient | |
| mov ebx,eax ; save high bits of quotient | |
| mov eax,LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend | |
| div ecx ; eax <- low order bits of quotient | |
| mov edx,ebx ; edx:eax <- quotient | |
| jmp short L4 ; set sign, restore stack and return | |
| ; | |
| ; Here we do it the hard way. Remember, eax contains the high word of DVSR | |
| ; | |
| L3: | |
| mov ebx,eax ; ebx:ecx <- divisor | |
| mov ecx,LOWORD(DVSR) | |
| mov edx,HIWORD(DVND) ; edx:eax <- dividend | |
| mov eax,LOWORD(DVND) | |
| L5: | |
| shr ebx,1 ; shift divisor right one bit | |
| rcr ecx,1 | |
| shr edx,1 ; shift dividend right one bit | |
| rcr eax,1 | |
| or ebx,ebx | |
| jnz short L5 ; loop until divisor < 4194304K | |
| div ecx ; now divide, ignore remainder | |
| mov esi,eax ; save quotient | |
| ; | |
| ; We may be off by one, so to check, we will multiply the quotient | |
| ; by the divisor and check the result against the orignal dividend | |
| ; Note that we must also check for overflow, which can occur if the | |
| ; dividend is close to 2**64 and the quotient is off by 1. | |
| ; | |
| mul dword ptr HIWORD(DVSR) ; QUOT * HIWORD(DVSR) | |
| mov ecx,eax | |
| mov eax,LOWORD(DVSR) | |
| mul esi ; QUOT * LOWORD(DVSR) | |
| add edx,ecx ; EDX:EAX = QUOT * DVSR | |
| jc short L6 ; carry means Quotient is off by 1 | |
| ; | |
| ; do long compare here between original dividend and the result of the | |
| ; multiply in edx:eax. If original is larger or equal, we are ok, otherwise | |
| ; subtract one (1) from the quotient. | |
| ; | |
| cmp edx,HIWORD(DVND) ; compare hi words of result and original | |
| ja short L6 ; if result > original, do subtract | |
| jb short L7 ; if result < original, we are ok | |
| cmp eax,LOWORD(DVND) ; hi words are equal, compare lo words | |
| jbe short L7 ; if less or equal we are ok, else subtract | |
| L6: | |
| dec esi ; subtract 1 from quotient | |
| L7: | |
| xor edx,edx ; edx:eax <- quotient | |
| mov eax,esi | |
| ; | |
| ; Just the cleanup left to do. edx:eax contains the quotient. Set the sign | |
| ; according to the save value, cleanup the stack, and return. | |
| ; | |
| L4: | |
| dec edi ; check to see if result is negative | |
| jnz short L8 ; if EDI == 0, result should be negative | |
| neg edx ; otherwise, negate the result | |
| neg eax | |
| sbb edx,0 | |
| ; | |
| ; Restore the saved registers and return. | |
| ; | |
| L8: | |
| pop ebx | |
| pop esi | |
| pop edi | |
| ret 16 | |
| _alldiv ENDP | |
| end |