* support/regression/tests/bug1057979.c:
[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 .div8::
179 .mod8::
180         ld      a,c             ; Sign extend
181         rlca
182         sbc     a
183         ld      b,a
184         ld      a,e             ; Sign extend
185         rlca
186         sbc     a
187         ld      d,a
188
189         ; Fall through to .div16
190
191         ;; 16-bit division
192         ;;
193         ;; Entry conditions
194         ;;   BC = dividend
195         ;;   DE = divisor
196         ;;
197         ;; Exit conditions
198         ;;   BC = quotient
199         ;;   DE = remainder
200         ;;   If divisor is non-zero, carry=0
201         ;;   If divisor is 0, carry=1 and both quotient and remainder are 0
202         ;;
203         ;; Register used: AF,BC,DE,HL
204 .div16::
205 .mod16::
206         ;; Determine sign of quotient by xor-ing high bytes of dividend
207         ;;  and divisor. Quotient is positive if signs are the same, negative
208         ;;  if signs are different
209         ;; Remainder has same sign as dividend
210         ld      a,b             ; Get high byte of dividend
211         push    af              ; Save as sign of remainder
212         xor     d               ; Xor with high byte of divisor
213         push    af              ; Save sign of quotient
214
215         ;; Take absolute value of divisor
216         bit     7,d
217         jr      Z,.chkde        ; Jump if divisor is positive
218         sub     a               ; Substract divisor from 0
219         sub     e
220         ld      e,a
221         sbc     a               ; Propagate borrow (A=0xFF if borrow)
222         sub     d
223         ld      d,a
224         ;; Take absolute value of dividend
225 .chkde:
226         bit     7,b
227         jr      Z,.dodiv        ; Jump if dividend is positive
228         sub     a               ; Substract dividend from 0
229         sub     c
230         ld      c,a
231         sbc     a               ; Propagate borrow (A=0xFF if borrow)
232         sub     b
233         ld      b,a
234         ;; Divide absolute values
235 .dodiv:
236         call    .divu16
237         jr      C,.exit         ; Exit if divide by zero
238         ;; Negate quotient if it is negative
239         pop     af              ; recover sign of quotient
240         and     #0x80
241         jr      Z,.dorem        ; Jump if quotient is positive
242         sub     a               ; Substract quotient from 0
243         sub     c
244         ld      c,a
245         sbc     a               ; Propagate borrow (A=0xFF if borrow)
246         sub     b
247         ld      b,a
248 .dorem:
249         ;; Negate remainder if it is negative
250         pop     af              ; recover sign of remainder
251         and     #0x80
252         ret     Z               ; Return if remainder is positive
253         sub     a               ; Substract remainder from 0
254         sub     e
255         ld      e,a
256         sbc     a               ; Propagate remainder (A=0xFF if borrow)
257         sub     d
258         ld      d,a
259         ret
260 .exit:
261         pop     af
262         pop     af
263         ret
264
265 .divu8::
266 .modu8::
267         ld      b,#0x00
268         ld      d,b
269         ; Fall through to divu16
270
271 .divu16::
272 .modu16::
273         ;; Check for division by zero
274         ld      a,e
275         or      d
276         jr      NZ,.divide      ; Branch if divisor is non-zero
277         ld      bc,#0x00        ; Divide by zero error
278         ld      d,b
279         ld      e,c
280         scf                     ; Set carry, invalid result
281         ret
282 .divide:
283         ld      hl,#0
284 ;       ld      l,c             ; L = low byte of dividend/quotient
285 ;       ld      h,b             ; H = high byte of dividend/quotient
286 ;       ld      bc,#0x00        ; BC = remainder
287         or      a               ; Clear carry to start
288         ex      af,af'
289         ld      a,#16           ; 16 bits in dividend
290 .dvloop:
291         ;; Shift next bit of quotient into bit 0 of dividend
292         ;; Shift next MSB of dividend into LSB of remainder
293         ;; BC holds both dividend and quotient. While we shift a bit from
294         ;;  MSB of dividend, we shift next bit of quotient in from carry
295         ;; HL holds remainder
296         ;; Do a 32-bit left shift, shifting carry to L, L to H,
297         ;;  H to C, C to B
298         ex      af,af'
299         rl      c               ; Carry (next bit of quotient) to bit 0
300         rl      b               ; Clears carry since BC was 0
301         adc     hl,hl
302
303         ;; If remainder is >= divisor, next bit of quotient is 1. This
304         ;;  bit goes to carry
305         push    hl              ; Save current remainder
306         sbc     hl,de
307 ;       ld      a,c             ; Substract divisor from remainder
308 ;       sbc     e
309 ;       ld      c,a
310 ;       ld      a,b
311 ;       sbc     d
312 ;       ld      b,a
313         ccf                     ; Complement borrow so 1 indicates a
314                                 ;  successful substraction (this is the
315                                 ;  next bit of quotient)
316         jr      C,.drop         ; Jump if remainder is >= dividend
317         pop     hl              ; Otherwise, restore remainder
318         jr      .nodrop
319 .drop:
320         inc     sp
321         inc     sp
322 .nodrop:
323         ex      af,af'
324         dec     a               ; DEC does not affect carry flag
325         jp      NZ,.dvloop
326         ex      af,af'
327         ;; Shift last carry bit into quotient
328         ld      d,h             ; DE = remainder
329         ld      e,l
330         rl      c               ; Carry to L
331 ;       ld      c,l             ; C = low byte of quotient
332         rl      b
333 ;       ld      b,h             ; B = high byte of quotient
334         or      a               ; Clear carry, valid result
335         ret