* device/lib/z80/mul.s (__mulsuchar_rrx_s, __muluschar_rrx_s),
[fw/sdcc] / device / lib / z80 / 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      l,c
19         ld      h,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         ld      l,e
38         ld      h,d
39
40         ret
41
42 __divsint_rrx_s::
43         ld      hl,#2+3
44         add     hl,sp
45
46         ld      d,(hl)
47         dec     hl
48         ld      e,(hl)
49         dec     hl
50         ld      a,(hl)
51         dec     hl
52         ld      l,(hl)
53         ld      h,a
54
55         ;; Fall through
56 __divsint_rrx_hds::
57         ld      b,h
58         ld      c,l
59
60         call    .div16
61
62         ld      l,c
63         ld      h,b
64
65         ret
66
67 __modsint_rrx_s::
68         ld      hl,#2+3
69         add     hl,sp
70
71         ld      d,(hl)
72         dec     hl
73         ld      e,(hl)
74         dec     hl
75         ld      a,(hl)
76         dec     hl
77         ld      l,(hl)
78         ld      h,a
79
80         ;; Fall through
81 __modsint_rrx_hds::
82         ld      b,h
83         ld      c,l
84
85         call    .div16
86
87         ld      l,e
88         ld      h,d
89
90         ret
91
92         ;; Unsigned
93 __divuchar_rrx_s::
94         ld      hl,#2+1
95         add     hl,sp
96
97         ld      e,(hl)
98         dec     hl
99         ld      l,(hl)
100
101         ;; Fall through
102 __divuchar_rrx_hds::
103         ld      c,l
104         call    .divu8
105
106         ld      l,c
107         ld      h,b
108
109         ret
110
111 __moduchar_rrx_s::
112         ld      hl,#2+1
113         add     hl,sp
114
115         ld      e,(hl)
116         dec     hl
117         ld      l,(hl)
118
119         ;; Fall through
120 __moduchar_rrx_hds::
121         ld      c,l
122         call    .divu8
123
124         ld      l,e
125         ld      h,d
126
127         ret
128
129 __divuint_rrx_s::
130         ld      hl,#2+3
131         add     hl,sp
132
133         ld      d,(hl)
134         dec     hl
135         ld      e,(hl)
136         dec     hl
137         ld      a,(hl)
138         dec     hl
139         ld      l,(hl)
140         ld      h,a
141
142         ;; Fall through
143 __divuint_rrx_hds::
144         ld      b,h
145         ld      c,l
146         call    .divu16
147
148         ld      l,c
149         ld      h,b
150
151         ret
152
153 __moduint_rrx_s::
154         ld      hl,#2+3
155         add     hl,sp
156
157         ld      d,(hl)
158         dec     hl
159         ld      e,(hl)
160         dec     hl
161         ld      a,(hl)
162         dec     hl
163         ld      l,(hl)
164         ld      h,a
165         ;; Fall through
166
167 __moduint_rrx_hds::
168         ld      b,h
169         ld      c,l
170
171         call    .divu16
172
173         ld      l,e
174         ld      h,d
175
176         ret
177
178 __divsuchar_rrx_s::
179         ld      hl,#2+1
180         add     hl,sp
181
182         ld      e,(hl)
183         dec     hl
184         ld      c,(hl)
185         ld      b, #0
186
187         call    signexte
188
189         ld      l,c
190         ld      h,b
191
192         ret
193
194 __modsuchar_rrx_s::
195         ld      hl,#2+1
196         add     hl,sp
197
198         ld      e,(hl)
199         dec     hl
200         ld      c,(hl)
201         ld      b, #0
202
203         call    signexte
204
205         ld      l,e
206         ld      h,d
207
208         ret
209
210 __divuschar_rrx_s::
211         ld      hl,#2+1
212         add     hl,sp
213
214         ld      e,(hl)
215         ld      d, #0
216         dec     hl
217         ld      c,(hl)
218
219         ld      a,c             ; Sign extend
220         rlca
221         sbc     a
222         ld      b,a
223
224         call    .div16
225
226         ld      l,c
227         ld      h,b
228
229         ret
230
231 __moduschar_rrx_s::
232         ld      hl,#2+1
233         add     hl,sp
234
235         ld      e,(hl)
236         ld      d, #0
237         dec     hl
238         ld      c,(hl)
239
240         ld      a,c             ; Sign extend
241         rlca
242         sbc     a
243         ld      b,a
244
245         call    .div16
246
247         ld      l,e
248         ld      h,d
249
250         ret
251
252 .div8::
253 .mod8::
254         ld      a,c             ; Sign extend
255         rlca
256         sbc     a
257         ld      b,a
258 signexte:
259         ld      a,e             ; Sign extend
260         rlca
261         sbc     a
262         ld      d,a
263
264         ; Fall through to .div16
265
266         ;; 16-bit division
267         ;;
268         ;; Entry conditions
269         ;;   BC = dividend
270         ;;   DE = divisor
271         ;;
272         ;; Exit conditions
273         ;;   BC = quotient
274         ;;   DE = remainder
275         ;;   If divisor is non-zero, carry=0
276         ;;   If divisor is 0, carry=1 and both quotient and remainder are 0
277         ;;
278         ;; Register used: AF,BC,DE,HL
279 .div16::
280 .mod16::
281         ;; Determine sign of quotient by xor-ing high bytes of dividend
282         ;;  and divisor. Quotient is positive if signs are the same, negative
283         ;;  if signs are different
284         ;; Remainder has same sign as dividend
285         ld      a,b             ; Get high byte of dividend
286         push    af              ; Save as sign of remainder
287         xor     d               ; Xor with high byte of divisor
288         push    af              ; Save sign of quotient
289
290         ;; Take absolute value of divisor
291         bit     7,d
292         jr      Z,.chkde        ; Jump if divisor is positive
293         sub     a               ; Substract divisor from 0
294         sub     e
295         ld      e,a
296         sbc     a               ; Propagate borrow (A=0xFF if borrow)
297         sub     d
298         ld      d,a
299         ;; Take absolute value of dividend
300 .chkde:
301         bit     7,b
302         jr      Z,.dodiv        ; Jump if dividend is positive
303         sub     a               ; Substract dividend from 0
304         sub     c
305         ld      c,a
306         sbc     a               ; Propagate borrow (A=0xFF if borrow)
307         sub     b
308         ld      b,a
309         ;; Divide absolute values
310 .dodiv:
311         call    .divu16
312         jr      C,.exit         ; Exit if divide by zero
313         ;; Negate quotient if it is negative
314         pop     af              ; recover sign of quotient
315         and     #0x80
316         jr      Z,.dorem        ; Jump if quotient is positive
317         sub     a               ; Substract quotient from 0
318         sub     c
319         ld      c,a
320         sbc     a               ; Propagate borrow (A=0xFF if borrow)
321         sub     b
322         ld      b,a
323 .dorem:
324         ;; Negate remainder if it is negative
325         pop     af              ; recover sign of remainder
326         and     #0x80
327         ret     Z               ; Return if remainder is positive
328         sub     a               ; Substract remainder from 0
329         sub     e
330         ld      e,a
331         sbc     a               ; Propagate remainder (A=0xFF if borrow)
332         sub     d
333         ld      d,a
334         ret
335 .exit:
336         pop     af
337         pop     af
338         ret
339
340 .divu8::
341 .modu8::
342         ld      b,#0x00
343         ld      d,b
344         ; Fall through to divu16
345
346 .divu16::
347 .modu16::
348         ;; Check for division by zero
349         ld      a,e
350         or      d
351         jr      NZ,.divide      ; Branch if divisor is non-zero
352         ld      bc,#0x00        ; Divide by zero error
353         ld      d,b
354         ld      e,c
355         scf                     ; Set carry, invalid result
356         ret
357 .divide:
358         ld      hl,#0
359 ;       ld      l,c             ; L = low byte of dividend/quotient
360 ;       ld      h,b             ; H = high byte of dividend/quotient
361 ;       ld      bc,#0x00        ; BC = remainder
362         or      a               ; Clear carry to start
363         ex      af,af'
364         ld      a,#16           ; 16 bits in dividend
365 .dvloop:
366         ;; Shift next bit of quotient into bit 0 of dividend
367         ;; Shift next MSB of dividend into LSB of remainder
368         ;; BC holds both dividend and quotient. While we shift a bit from
369         ;;  MSB of dividend, we shift next bit of quotient in from carry
370         ;; HL holds remainder
371         ;; Do a 32-bit left shift, shifting carry to L, L to H,
372         ;;  H to C, C to B
373         ex      af,af'
374         rl      c               ; Carry (next bit of quotient) to bit 0
375         rl      b               ; Clears carry since BC was 0
376         adc     hl,hl
377
378         ;; If remainder is >= divisor, next bit of quotient is 1. This
379         ;;  bit goes to carry
380         push    hl              ; Save current remainder
381         sbc     hl,de
382 ;       ld      a,c             ; Substract divisor from remainder
383 ;       sbc     e
384 ;       ld      c,a
385 ;       ld      a,b
386 ;       sbc     d
387 ;       ld      b,a
388         ccf                     ; Complement borrow so 1 indicates a
389                                 ;  successful substraction (this is the
390                                 ;  next bit of quotient)
391         jr      C,.drop         ; Jump if remainder is >= dividend
392         pop     hl              ; Otherwise, restore remainder
393         jr      .nodrop
394 .drop:
395         inc     sp
396         inc     sp
397 .nodrop:
398         ex      af,af'
399         dec     a               ; DEC does not affect carry flag
400         jp      NZ,.dvloop
401         ex      af,af'
402         ;; Shift last carry bit into quotient
403         ld      d,h             ; DE = remainder
404         ld      e,l
405         rl      c               ; Carry to L
406 ;       ld      c,l             ; C = low byte of quotient
407         rl      b
408 ;       ld      b,h             ; B = high byte of quotient
409         or      a               ; Clear carry, valid result
410         ret