]> 4ch.mooo.com Git - 16.git/blob - 16/wf3d8086/h_ldiv.asm
code miraculously works on real hardware
[16.git] / 16 / wf3d8086 / h_ldiv.asm
1 ;[]-----------------------------------------------------------------[]\r
2 ;|      H_LDIV.ASM -- long division routine                          |\r
3 ;|                                                                   |\r
4 ;|      C/C++ Run Time Library        Version 4.0                    |\r
5 ;|                                                                   |\r
6 ;|      Copyright (c) 1987, 1991 by Borland International Inc.       |\r
7 ;|      All Rights Reserved.                                         |\r
8 ;[]-----------------------------------------------------------------[]\r
9 .model medium\r
10         INCLUDE RULES.ASI\r
11 .386C   ;JAB - we use 386 instructions\r
12 \r
13 _TEXT   segment public byte 'CODE'\r
14         assume  cs:_TEXT\r
15         public  LDIV@\r
16         public  F_LDIV@\r
17         public  N_LDIV@\r
18         public  LUDIV@\r
19         public  F_LUDIV@\r
20                 public  N_LUDIV@\r
21         public  LMOD@\r
22         public  F_LMOD@\r
23                 public  N_LMOD@\r
24         public  LUMOD@\r
25         public  F_LUMOD@\r
26                 public  N_LUMOD@\r
27 \r
28 N_LDIV@:\r
29                 pop     cx                      ;fix up far return\r
30                 push    cs\r
31                 push    cx\r
32 LDIV@:\r
33 F_LDIV@:\r
34         xor     cx,cx                   ; signed divide\r
35         jmp     short common\r
36 \r
37 ;       JAB\r
38 ;\r
39 ;       If we're using a 386 or better, the two instructions above get patched\r
40 ;               to be NOP's (4 of them). So, instead of using the looping code,\r
41 ;               we use the 386's long divide instruction.\r
42 ;\r
43 ;       The stack after setting up the stack frame:\r
44 ;               12[bp]: divisor (high word)\r
45 ;               10[bp]: divisor (low word)\r
46 ;                8[bp]: dividend (high word)\r
47 ;                6[bp]: dividend (low word)\r
48 ;                4[bp]: return CS\r
49 ;                2[bp]: return IP\r
50 ;                0[bp]: previous BP\r
51 ;\r
52         IDEAL\r
53 \r
54         push bp\r
55         mov     bp,sp   ;Save BP, and set it equal to stack\r
56 \r
57         mov     eax,[DWORD PTR bp+6]\r
58         cdq\r
59         idiv [DWORD PTR bp+10]\r
60         mov     edx,eax\r
61         shr     edx,16\r
62 \r
63         pop     bp              ;Restore BP\r
64         retf    8       ;Return to original caller\r
65 \r
66         MASM\r
67 \r
68 N_LUDIV@:\r
69                 pop     cx                      ;fix up far return\r
70                 push    cs\r
71                 push    cx\r
72 LUDIV@:\r
73 F_LUDIV@:\r
74         mov     cx,1                    ; unsigned divide\r
75         jmp     short common\r
76 \r
77 N_LMOD@:\r
78                 pop     cx                      ;fix up far return\r
79                 push    cs\r
80                 push    cx\r
81 LMOD@:\r
82 F_LMOD@:\r
83         mov     cx,2                    ; signed remainder\r
84         jmp     short   common\r
85 \r
86 N_LUMOD@:\r
87                 pop     cx                      ;fix up far return\r
88                 push    cs\r
89                 push    cx\r
90 LUMOD@:\r
91 F_LUMOD@:\r
92         mov     cx,3                    ; unsigned remainder\r
93 \r
94 ;\r
95 ;       di now contains a two bit control value.  The low order\r
96 ;       bit (test mask of 1) is on if the operation is unsigned,\r
97 ;       signed otherwise.  The next bit (test mask of 2) is on if\r
98 ;       the operation returns the remainder, quotient otherwise.\r
99 ;\r
100 common:\r
101         push    bp\r
102         push    si\r
103         push    di\r
104         mov     bp,sp                   ; set up frame\r
105         mov     di,cx\r
106 ;\r
107 ;       dividend is pushed last, therefore the first in the args\r
108 ;       divisor next.\r
109 ;\r
110         mov     ax,10[bp]               ; get the first low word\r
111         mov     dx,12[bp]               ; get the first high word\r
112         mov     bx,14[bp]               ; get the second low word\r
113         mov     cx,16[bp]               ; get the second high word\r
114 \r
115         or      cx,cx\r
116         jnz     slow@ldiv               ; both high words are zero\r
117 \r
118         or      dx,dx\r
119         jz      quick@ldiv\r
120 \r
121         or      bx,bx\r
122         jz      quick@ldiv              ; if cx:bx == 0 force a zero divide\r
123                                         ; we don't expect this to actually\r
124                                         ; work\r
125 \r
126 slow@ldiv:\r
127 \r
128         test    di,1                    ; signed divide?\r
129         jnz     positive                ; no: skip\r
130 ;\r
131 ;               Signed division should be done.  Convert negative\r
132 ;               values to positive and do an unsigned division.\r
133 ;               Store the sign value in the next higher bit of\r
134 ;               di (test mask of 4).  Thus when we are done, testing\r
135 ;               that bit will determine the sign of the result.\r
136 ;\r
137         or      dx,dx                   ; test sign of dividend\r
138         jns     onepos\r
139         neg     dx\r
140         neg     ax\r
141         sbb     dx,0                    ; negate dividend\r
142         or      di,0Ch\r
143 onepos:\r
144         or      cx,cx                   ; test sign of divisor\r
145         jns     positive\r
146         neg     cx\r
147         neg     bx\r
148         sbb     cx,0                    ; negate divisor\r
149         xor     di,4\r
150 positive:\r
151         mov     bp,cx\r
152         mov     cx,32                   ; shift counter\r
153         push    di                      ; save the flags\r
154 ;\r
155 ;       Now the stack looks something like this:\r
156 ;\r
157 ;               16[bp]: divisor (high word)\r
158 ;               14[bp]: divisor (low word)\r
159 ;               12[bp]: dividend (high word)\r
160 ;               10[bp]: dividend (low word)\r
161 ;                8[bp]: return CS\r
162 ;                6[bp]: return IP\r
163 ;                4[bp]: previous BP\r
164 ;                2[bp]: previous SI\r
165 ;                 [bp]: previous DI\r
166 ;               -2[bp]: control bits\r
167 ;                       01 - Unsigned divide\r
168 ;                       02 - Remainder wanted\r
169 ;                       04 - Negative quotient\r
170 ;                       08 - Negative remainder\r
171 ;\r
172         xor     di,di                   ; fake a 64 bit dividend\r
173         xor     si,si                   ;\r
174 xloop:\r
175         shl     ax,1                    ; shift dividend left one bit\r
176         rcl     dx,1\r
177         rcl     si,1\r
178         rcl     di,1\r
179         cmp     di,bp                   ; dividend larger?\r
180         jb      nosub\r
181         ja      subtract\r
182         cmp     si,bx                   ; maybe\r
183         jb      nosub\r
184 subtract:\r
185         sub     si,bx\r
186         sbb     di,bp                   ; subtract the divisor\r
187         inc     ax                      ; build quotient\r
188 nosub:\r
189         loop    xloop\r
190 ;\r
191 ;       When done with the loop the four register value look like:\r
192 ;\r
193 ;       |     di     |     si     |     dx     |     ax     |\r
194 ;       |        remainder        |         quotient        |\r
195 ;\r
196         pop     bx                      ; get control bits\r
197         test    bx,2                    ; remainder?\r
198         jz      usequo\r
199         mov     ax,si\r
200         mov     dx,di                   ; use remainder\r
201         shr     bx,1                    ; shift in the remainder sign bit\r
202 usequo:\r
203         test    bx,4                    ; needs negative\r
204         jz      finish\r
205         neg     dx\r
206         neg     ax\r
207         sbb     dx,0                    ; negate\r
208 finish:\r
209         pop     di\r
210         pop     si\r
211         pop     bp\r
212         retf    8\r
213 \r
214 quick@ldiv:\r
215         div     bx                      ; unsigned divide\r
216                                         ; DX = remainder AX = quotient\r
217         test    di,2                    ; want remainder?\r
218         jz      quick@quo\r
219                 xchg    ax,dx\r
220 \r
221 quick@quo:\r
222 \r
223         xor     dx,dx\r
224                 jmp     short finish\r
225 \r
226 _TEXT   ends\r
227         end\r