* device/lib/gbz80/crt0.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 .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         ld      (.srem),a       ; Save as sign of remainder
212         xor     d               ; Xor with high byte of divisor
213         ld      (.squot),a      ; Save sign of quotient
214         ;; Take absolute value of divisor
215         bit     7,d
216         jp      Z,.chkde        ; Jump if divisor is positive
217         sub     a               ; Substract divisor from 0
218         sub     e
219         ld      e,a
220         sbc     a               ; Propagate borrow (A=0xFF if borrow)
221         sub     d
222         ld      d,a
223         ;; Take absolute value of dividend
224 .chkde:
225         bit     7,b
226         jp      Z,.dodiv        ; Jump if dividend is positive
227         sub     a               ; Substract dividend from 0
228         sub     c
229         ld      c,a
230         sbc     a               ; Propagate borrow (A=0xFF if borrow)
231         sub     b
232         ld      b,a
233         ;; Divide absolute values
234 .dodiv:
235         call    .divu16
236         ret     C               ; Exit if divide by zero
237         ;; Negate quotient if it is negative
238         ld      a,(.squot)
239         and     #0x80
240         jp      Z,.dorem        ; Jump if quotient is positive
241         sub     a               ; Substract quotient from 0
242         sub     c
243         ld      c,a
244         sbc     a               ; Propagate borrow (A=0xFF if borrow)
245         sub     b
246         ld      b,a
247 .dorem:
248         ;; Negate remainder if it is negative
249         ld      a,(.srem)
250         and     #0x80
251         ret     Z               ; Return if remainder is positive
252         sub     a               ; Substract remainder from 0
253         sub     e
254         ld      e,a
255         sbc     a               ; Propagate remainder (A=0xFF if borrow)
256         sub     d
257         ld      d,a
258         ret
259
260 .divu8::
261 .modu8::
262         ld      b,#0x00
263         ld      d,b
264         ; Fall through to divu16
265
266 .divu16::
267 .modu16::
268         ;; Check for division by zero
269         ld      a,e
270         or      d
271         jp      NZ,.divide      ; Branch if divisor is non-zero
272         ld      bc,#0x00        ; Divide by zero error
273         ld      d,b
274         ld      e,c
275         scf                     ; Set carry, invalid result
276         ret
277 .divide:
278         ld      hl,#0
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         ex      af,af
284         ld      a,#16           ; 16 bits in dividend
285 .dvloop:
286         ;; Shift next bit of quotient into bit 0 of dividend
287         ;; Shift next MSB of dividend into LSB of remainder
288         ;; BC holds both dividend and quotient. While we shift a bit from
289         ;;  MSB of dividend, we shift next bit of quotient in from carry
290         ;; HL holds remainder
291         ;; Do a 32-bit left shift, shifting carry to L, L to H,
292         ;;  H to C, C to B
293         ex      af,af'
294         rl      c               ; Carry (next bit of quotient) to bit 0
295         rl      b               ; Clears carry since BC was 0
296         adc     hl,hl
297
298         ;; If remainder is >= divisor, next bit of quotient is 1. This
299         ;;  bit goes to carry
300         push    hl              ; Save current remainder
301         sbc     hl,de
302 ;       ld      a,c             ; Substract divisor from remainder
303 ;       sbc     e
304 ;       ld      c,a
305 ;       ld      a,b
306 ;       sbc     d
307 ;       ld      b,a
308         ccf                     ; Complement borrow so 1 indicates a
309                                 ;  successful substraction (this is the
310                                 ;  next bit of quotient)
311         jp      C,.drop         ; Jump if remainder is >= dividend
312         pop     hl              ; Otherwise, restore remainder
313         jp      .nodrop
314 .drop:
315         inc     sp
316         inc     sp
317 .nodrop:
318         ex      af,af'
319         dec     a               ; DEC does not affect carry flag
320         jp      NZ,.dvloop
321         ex      af,af'
322         ;; Shift last carry bit into quotient
323         ld      d,h             ; DE = remainder
324         ld      e,l
325         rl      c               ; Carry to L
326 ;       ld      c,l             ; C = low byte of quotient
327         rl      b
328 ;       ld      b,h             ; B = high byte of quotient
329         or      a               ; Clear carry, valid result
330         ret
331
332         .area   BSS
333
334 .srem:
335         .ds 0x01                ; Sign of quotient
336 .squot:
337         .ds 0x01                ; Sign of remainder
338 .dcnt:
339         .ds 0x01                ; Counter for division