--- /dev/null
+;[]-----------------------------------------------------------------[]\r
+;| H_LDIV.ASM -- long division routine |\r
+;| |\r
+;| C/C++ Run Time Library Version 4.0 |\r
+;| |\r
+;| Copyright (c) 1987, 1991 by Borland International Inc. |\r
+;| All Rights Reserved. |\r
+;[]-----------------------------------------------------------------[]\r
+.model medium\r
+ INCLUDE RULES.ASI\r
+.386C ;JAB - we use 386 instructions\r
+\r
+_TEXT segment public byte 'CODE'\r
+ assume cs:_TEXT\r
+ public LDIV@\r
+ public F_LDIV@\r
+ public N_LDIV@\r
+ public LUDIV@\r
+ public F_LUDIV@\r
+ public N_LUDIV@\r
+ public LMOD@\r
+ public F_LMOD@\r
+ public N_LMOD@\r
+ public LUMOD@\r
+ public F_LUMOD@\r
+ public N_LUMOD@\r
+\r
+N_LDIV@:\r
+ pop cx ;fix up far return\r
+ push cs\r
+ push cx\r
+LDIV@:\r
+F_LDIV@:\r
+ xor cx,cx ; signed divide\r
+ jmp short common\r
+\r
+; JAB\r
+;\r
+; If we're using a 386 or better, the two instructions above get patched\r
+; to be NOP's (4 of them). So, instead of using the looping code,\r
+; we use the 386's long divide instruction.\r
+;\r
+; The stack after setting up the stack frame:\r
+; 12[bp]: divisor (high word)\r
+; 10[bp]: divisor (low word)\r
+; 8[bp]: dividend (high word)\r
+; 6[bp]: dividend (low word)\r
+; 4[bp]: return CS\r
+; 2[bp]: return IP\r
+; 0[bp]: previous BP\r
+;\r
+ IDEAL\r
+\r
+ push bp\r
+ mov bp,sp ;Save BP, and set it equal to stack\r
+\r
+ mov eax,[DWORD PTR bp+6]\r
+ cdq\r
+ idiv [DWORD PTR bp+10]\r
+ mov edx,eax\r
+ shr edx,16\r
+\r
+ pop bp ;Restore BP\r
+ retf 8 ;Return to original caller\r
+\r
+ MASM\r
+\r
+N_LUDIV@:\r
+ pop cx ;fix up far return\r
+ push cs\r
+ push cx\r
+LUDIV@:\r
+F_LUDIV@:\r
+ mov cx,1 ; unsigned divide\r
+ jmp short common\r
+\r
+N_LMOD@:\r
+ pop cx ;fix up far return\r
+ push cs\r
+ push cx\r
+LMOD@:\r
+F_LMOD@:\r
+ mov cx,2 ; signed remainder\r
+ jmp short common\r
+\r
+N_LUMOD@:\r
+ pop cx ;fix up far return\r
+ push cs\r
+ push cx\r
+LUMOD@:\r
+F_LUMOD@:\r
+ mov cx,3 ; unsigned remainder\r
+\r
+;\r
+; di now contains a two bit control value. The low order\r
+; bit (test mask of 1) is on if the operation is unsigned,\r
+; signed otherwise. The next bit (test mask of 2) is on if\r
+; the operation returns the remainder, quotient otherwise.\r
+;\r
+common:\r
+ push bp\r
+ push si\r
+ push di\r
+ mov bp,sp ; set up frame\r
+ mov di,cx\r
+;\r
+; dividend is pushed last, therefore the first in the args\r
+; divisor next.\r
+;\r
+ mov ax,10[bp] ; get the first low word\r
+ mov dx,12[bp] ; get the first high word\r
+ mov bx,14[bp] ; get the second low word\r
+ mov cx,16[bp] ; get the second high word\r
+\r
+ or cx,cx\r
+ jnz slow@ldiv ; both high words are zero\r
+\r
+ or dx,dx\r
+ jz quick@ldiv\r
+\r
+ or bx,bx\r
+ jz quick@ldiv ; if cx:bx == 0 force a zero divide\r
+ ; we don't expect this to actually\r
+ ; work\r
+\r
+slow@ldiv:\r
+\r
+ test di,1 ; signed divide?\r
+ jnz positive ; no: skip\r
+;\r
+; Signed division should be done. Convert negative\r
+; values to positive and do an unsigned division.\r
+; Store the sign value in the next higher bit of\r
+; di (test mask of 4). Thus when we are done, testing\r
+; that bit will determine the sign of the result.\r
+;\r
+ or dx,dx ; test sign of dividend\r
+ jns onepos\r
+ neg dx\r
+ neg ax\r
+ sbb dx,0 ; negate dividend\r
+ or di,0Ch\r
+onepos:\r
+ or cx,cx ; test sign of divisor\r
+ jns positive\r
+ neg cx\r
+ neg bx\r
+ sbb cx,0 ; negate divisor\r
+ xor di,4\r
+positive:\r
+ mov bp,cx\r
+ mov cx,32 ; shift counter\r
+ push di ; save the flags\r
+;\r
+; Now the stack looks something like this:\r
+;\r
+; 16[bp]: divisor (high word)\r
+; 14[bp]: divisor (low word)\r
+; 12[bp]: dividend (high word)\r
+; 10[bp]: dividend (low word)\r
+; 8[bp]: return CS\r
+; 6[bp]: return IP\r
+; 4[bp]: previous BP\r
+; 2[bp]: previous SI\r
+; [bp]: previous DI\r
+; -2[bp]: control bits\r
+; 01 - Unsigned divide\r
+; 02 - Remainder wanted\r
+; 04 - Negative quotient\r
+; 08 - Negative remainder\r
+;\r
+ xor di,di ; fake a 64 bit dividend\r
+ xor si,si ;\r
+xloop:\r
+ shl ax,1 ; shift dividend left one bit\r
+ rcl dx,1\r
+ rcl si,1\r
+ rcl di,1\r
+ cmp di,bp ; dividend larger?\r
+ jb nosub\r
+ ja subtract\r
+ cmp si,bx ; maybe\r
+ jb nosub\r
+subtract:\r
+ sub si,bx\r
+ sbb di,bp ; subtract the divisor\r
+ inc ax ; build quotient\r
+nosub:\r
+ loop xloop\r
+;\r
+; When done with the loop the four register value look like:\r
+;\r
+; | di | si | dx | ax |\r
+; | remainder | quotient |\r
+;\r
+ pop bx ; get control bits\r
+ test bx,2 ; remainder?\r
+ jz usequo\r
+ mov ax,si\r
+ mov dx,di ; use remainder\r
+ shr bx,1 ; shift in the remainder sign bit\r
+usequo:\r
+ test bx,4 ; needs negative\r
+ jz finish\r
+ neg dx\r
+ neg ax\r
+ sbb dx,0 ; negate\r
+finish:\r
+ pop di\r
+ pop si\r
+ pop bp\r
+ retf 8\r
+\r
+quick@ldiv:\r
+ div bx ; unsigned divide\r
+ ; DX = remainder AX = quotient\r
+ test di,2 ; want remainder?\r
+ jz quick@quo\r
+ xchg ax,dx\r
+\r
+quick@quo:\r
+\r
+ xor dx,dx\r
+ jmp short finish\r
+\r
+_TEXT ends\r
+ end\r