]> 4ch.mooo.com Git - 16.git/blobdiff - 16/WOLFSRC/H_LDIV.ASM
got 8086 port of wolf3d to work and sod to work
[16.git] / 16 / WOLFSRC / H_LDIV.ASM
diff --git a/16/WOLFSRC/H_LDIV.ASM b/16/WOLFSRC/H_LDIV.ASM
new file mode 100755 (executable)
index 0000000..91916fa
--- /dev/null
@@ -0,0 +1,227 @@
+;[]-----------------------------------------------------------------[]\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