Imported Upstream version 2.9.0
[debian/cc1111] / device / lib / gbz80 / div.s
1         ;; Originally from GBDK by Pascal Felber.
2         .area   _CODE
3
4 __divschar_rrx_s::
5         ld      hl,#2+1
6         add     hl,sp
7
8         ld      e,(hl)
9         dec     hl
10         ld      l,(hl)
11
12         ;; Fall through
13 __divschar_rrx_hds::
14         ld      c,l
15
16         call    .div8
17
18         ld      e,c
19         ld      d,b
20
21         ret
22
23 __modschar_rrx_s::
24         ld      hl,#2+1
25         add     hl,sp
26
27         ld      e,(hl)
28         dec     hl
29         ld      l,(hl)
30
31         ;; Fall through
32 __modschar_rrx_hds::
33         ld      c,l
34
35         call    .div8
36
37         ;; Already in DE
38
39         ret
40
41 __divsint_rrx_s::
42         ld      hl,#2+3
43         add     hl,sp
44
45         ld      d,(hl)
46         dec     hl
47         ld      e,(hl)
48         dec     hl
49         ld      a,(hl)
50         dec     hl
51         ld      l,(hl)
52         ld      h,a
53
54         ;; Fall through
55 __divsint_rrx_hds::
56         ld      b,h
57         ld      c,l
58
59         call    .div16
60
61         ld      e,c
62         ld      d,b
63
64         ret
65
66 __modsint_rrx_s::
67         ld      hl,#2+3
68         add     hl,sp
69
70         ld      d,(hl)
71         dec     hl
72         ld      e,(hl)
73         dec     hl
74         ld      a,(hl)
75         dec     hl
76         ld      l,(hl)
77         ld      h,a
78
79         ;; Fall through
80 __modsint_rrx_hds::
81         ld      b,h
82         ld      c,l
83
84         call    .div16
85
86         ;; Already in DE
87
88         ret
89
90         ;; Unsigned
91 __divuchar_rrx_s::
92         ld      hl,#2+1
93         add     hl,sp
94
95         ld      e,(hl)
96         dec     hl
97         ld      l,(hl)
98
99         ;; Fall through
100 __divuchar_rrx_hds::
101         ld      c,l
102         call    .divu8
103
104         ld      e,c
105         ld      d,b
106
107         ret
108
109 __moduchar_rrx_s::
110         ld      hl,#2+1
111         add     hl,sp
112
113         ld      e,(hl)
114         dec     hl
115         ld      l,(hl)
116
117         ;; Fall through
118 __moduchar_rrx_hds::
119         ld      c,l
120         call    .divu8
121
122         ;; Already in DE
123
124         ret
125
126 __divuint_rrx_s::
127         ld      hl,#2+3
128         add     hl,sp
129
130         ld      d,(hl)
131         dec     hl
132         ld      e,(hl)
133         dec     hl
134         ld      a,(hl)
135         dec     hl
136         ld      l,(hl)
137         ld      h,a
138
139         ;; Fall through
140 __divuint_rrx_hds::
141         ld      b,h
142         ld      c,l
143         call    .divu16
144
145         ld      e,c
146         ld      d,b
147
148         ret
149
150 __moduint_rrx_s::
151         ld      hl,#2+3
152         add     hl,sp
153
154         ld      d,(hl)
155         dec     hl
156         ld      e,(hl)
157         dec     hl
158         ld      a,(hl)
159         dec     hl
160         ld      l,(hl)
161         ld      h,a
162         ;; Fall through
163
164 __moduint_rrx_hds::
165         ld      b,h
166         ld      c,l
167
168         call    .divu16
169
170         ;; Already in DE
171
172         ret
173
174 .div8::
175 .mod8::
176         ld      a,c             ; Sign extend
177         rlca
178         sbc     a
179         ld      b,a
180         ld      a,e             ; Sign extend
181         rlca
182         sbc     a
183         ld      d,a
184
185         ; Fall through to .div16
186
187         ;; 16-bit division
188         ;;
189         ;; Entry conditions
190         ;;   BC = dividend
191         ;;   DE = divisor
192         ;;
193         ;; Exit conditions
194         ;;   BC = quotient
195         ;;   DE = remainder
196         ;;   If divisor is non-zero, carry=0
197         ;;   If divisor is 0, carry=1 and both quotient and remainder are 0
198         ;;
199         ;; Register used: AF,BC,DE,HL
200 .div16::
201 .mod16::
202         ;; Determine sign of quotient by xor-ing high bytes of dividend
203         ;;  and divisor. Quotient is positive if signs are the same, negative
204         ;;  if signs are different
205         ;; Remainder has same sign as dividend
206         ld      a,b             ; Get high byte of dividend
207         push    af              ; Save as sign of remainder
208         xor     d               ; Xor with high byte of divisor
209         push    af              ; Save sign of quotient
210
211         ;; Take absolute value of divisor
212         bit     7,d
213         jr      Z,.chkde        ; Jump if divisor is positive
214         sub     a               ; Substract divisor from 0
215         sub     e
216         ld      e,a
217         sbc     a               ; Propagate borrow (A=0xFF if borrow)
218         sub     d
219         ld      d,a
220         ;; Take absolute value of dividend
221 .chkde:
222         bit     7,b
223         jr      Z,.dodiv        ; Jump if dividend is positive
224         sub     a               ; Substract dividend from 0
225         sub     c
226         ld      c,a
227         sbc     a               ; Propagate borrow (A=0xFF if borrow)
228         sub     b
229         ld      b,a
230         ;; Divide absolute values
231 .dodiv:
232         call    .divu16
233         jr      C,.exit         ; Exit if divide by zero
234         ;; Negate quotient if it is negative
235         pop     af              ; recover sign of quotient
236         and     #0x80
237         jr      Z,.dorem        ; Jump if quotient is positive
238         sub     a               ; Substract quotient from 0
239         sub     c
240         ld      c,a
241         sbc     a               ; Propagate borrow (A=0xFF if borrow)
242         sub     b
243         ld      b,a
244 .dorem:
245         ;; Negate remainder if it is negative
246         pop     af              ; recover sign of remainder
247         and     #0x80
248         ret     Z               ; Return if remainder is positive
249         sub     a               ; Substract remainder from 0
250         sub     e
251         ld      e,a
252         sbc     a               ; Propagate remainder (A=0xFF if borrow)
253         sub     d
254         ld      d,a
255         ret
256 .exit:
257         pop     af
258         pop     af
259         ret
260
261 .divu8::
262 .modu8::
263         ld      b,#0x00
264         ld      d,b
265         ; Fall through to divu16
266
267 .divu16::
268 .modu16::
269         ;; Check for division by zero
270         ld      a,e
271         or      d
272         jr      NZ,.divide      ; Branch if divisor is non-zero
273         ld      bc,#0x00        ; Divide by zero error
274         ld      d,b
275         ld      e,c
276         scf                     ; Set carry, invalid result
277         ret
278 .divide:
279         ld      l,c             ; L = low byte of dividend/quotient
280         ld      h,b             ; H = high byte of dividend/quotient
281         ld      bc,#0x00        ; BC = remainder
282         or      a               ; Clear carry to start
283         ld      a,#16           ; 16 bits in dividend
284 .dvloop:
285         ;; Shift next bit of quotient into bit 0 of dividend
286         ;; Shift next MSB of dividend into LSB of remainder
287         ;; BC holds both dividend and quotient. While we shift a bit from
288         ;;  MSB of dividend, we shift next bit of quotient in from carry
289         ;; HL holds remainder
290         ;; Do a 32-bit left shift, shifting carry to L, L to H,
291         ;;  H to C, C to B
292         push    af              ; save number of bits remaining
293         rl      l               ; Carry (next bit of quotient) to bit 0
294         rl      h               ; Shift remaining bytes
295         rl      c
296         rl      b               ; Clears carry since BC was 0
297         ;; If remainder is >= divisor, next bit of quotient is 1. This
298         ;;  bit goes to carry
299         push    bc              ; Save current remainder
300         ld      a,c             ; Substract divisor from remainder
301         sbc     e
302         ld      c,a
303         ld      a,b
304         sbc     d
305         ld      b,a
306         ccf                     ; Complement borrow so 1 indicates a
307                                 ;  successful substraction (this is the
308                                 ;  next bit of quotient)
309         jr      C,.drop         ; Jump if remainder is >= dividend
310         pop     bc              ; Otherwise, restore remainder
311         pop     af              ; recover # bits remaining, carry flag destroyed
312         dec     a
313         or      a               ; restore (clear) the carry flag
314         jr      NZ,.dvloop
315         jr      .nodrop
316 .drop:
317         inc     sp
318         inc     sp
319         pop     af              ; recover # bits remaining, carry flag destroyed
320         dec     a
321         scf                     ; restore (set) the carry flag
322         jr      NZ,.dvloop
323         jr      .nodrop
324 .nodrop:
325         ;; Shift last carry bit into quotient
326         ld      d,b             ; DE = remainder
327         ld      e,c
328         rl      l               ; Carry to L
329         ld      c,l             ; C = low byte of quotient
330         rl      h
331         ld      b,h             ; B = high byte of quotient
332         or      a               ; Clear carry, valid result
333         ret