92d2ee2f81df742ff962ee4453d2b43ec5622a5b
[fw/sdcc] / device / lib / z80 / div.s
1         ;; Originally from GBDK by Pascal Felber.
2         .area   _CODE
3
4 __divschar_rr_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_rr_hds::
14         ld      c,l
15         
16         call    .div8
17
18         ld      l,c
19         ld      h,b
20                 
21         ret
22         
23 __modschar_rr_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_rr_hds::
33         ld      c,l
34
35         call    .div8
36
37         ld      l,e
38         ld      h,d
39                 
40         ret
41
42 __divsint_rr_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_rr_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_rr_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_rr_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_rr_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_rr_hds::     
103         push    ix
104         ld      ix,#0
105         add     ix,sp
106
107         ld      c,8(ix)
108         ld      e,9(ix)
109         call    .divu8
110
111         ld      l,c
112         ld      h,b
113                 
114         pop     ix
115         ret
116         
117 __moduchar_rr_s::       
118         ld      hl,#2+1
119         add     hl,sp
120         
121         ld      e,(hl)
122         dec     hl
123         ld      l,(hl)
124         
125         ;; Fall through
126 __moduchar_rr_hds::
127         push    ix
128         ld      ix,#0
129         add     ix,sp
130
131         ld      c,8(ix)
132         ld      e,9(ix)
133         call    .divu8
134
135         ld      l,e
136         ld      h,d
137                 
138         pop     ix
139         ret
140
141 __divuint_rr_s::                
142         ld      hl,#2+3
143         add     hl,sp
144         
145         ld      d,(hl)
146         dec     hl
147         ld      e,(hl)
148         dec     hl
149         ld      a,(hl)
150         dec     hl
151         ld      l,(hl)
152         ld      h,a
153
154         ;; Fall through
155 __divuint_rr_hds::
156         ld      b,h
157         ld      c,l
158         call    .divu16
159
160         ld      l,c
161         ld      h,b
162         
163         ret
164         
165 __moduint_rr_s::                
166         ld      hl,#2+3
167         add     hl,sp
168         
169         ld      d,(hl)
170         dec     hl
171         ld      e,(hl)
172         dec     hl
173         ld      a,(hl)
174         dec     hl
175         ld      l,(hl)
176         ld      h,a
177         ;; Fall through
178         
179 __moduint_rr_hds::
180         ld      b,h
181         ld      c,l
182
183         call    .divu16
184
185         ld      l,e
186         ld      h,d
187         
188         ret
189         
190 .div8::
191 .mod8::
192         LD      A,C             ; Sign extend
193         RLCA
194         SBC     A
195         LD      B,A
196         LD      A,E             ; Sign extend
197         RLCA
198         SBC     A
199         LD      D,A
200
201         ; Fall through to .div16
202         
203         ;; 16-bit division
204         ;; 
205         ;; Entry conditions
206         ;;   BC = dividend
207         ;;   DE = divisor
208         ;; 
209         ;; Exit conditions
210         ;;   BC = quotient
211         ;;   DE = remainder
212         ;;   If divisor is non-zero, carry=0
213         ;;   If divisor is 0, carry=1 and both quotient and remainder are 0
214         ;;
215         ;; Register used: AF,BC,DE,HL
216 .div16::
217 .mod16::
218         ;; Determine sign of quotient by xor-ing high bytes of dividend
219         ;;  and divisor. Quotient is positive if signs are the same, negative
220         ;;  if signs are different
221         ;; Remainder has same sign as dividend
222         LD      A,B             ; Get high byte of dividend
223         LD      (.srem),A       ; Save as sign of remainder
224         XOR     D               ; Xor with high byte of divisor
225         LD      (.squot),A      ; Save sign of quotient
226         ;; Take absolute value of divisor
227         BIT     7,D
228         jp      Z,.chkde        ; Jump if divisor is positive
229         SUB     A               ; Substract divisor from 0
230         SUB     E
231         LD      E,A
232         SBC     A               ; Propagate borrow (A=0xFF if borrow)
233         SUB     D
234         LD      D,A
235         ;; Take absolute value of dividend
236 .chkde:
237         BIT     7,B
238         jp      Z,.dodiv        ; Jump if dividend is positive
239         SUB     A               ; Substract dividend from 0
240         SUB     C
241         LD      C,A
242         SBC     A               ; Propagate borrow (A=0xFF if borrow)
243         SUB     B
244         LD      B,A
245         ;; Divide absolute values
246 .dodiv:
247         CALL    .divu16
248         RET     C               ; Exit if divide by zero
249         ;; Negate quotient if it is negative
250         LD      A,(.squot)
251         AND     #0x80
252         jp      Z,.dorem        ; Jump if quotient is positive
253         SUB     A               ; Substract quotient from 0
254         SUB     C
255         LD      C,A
256         SBC     A               ; Propagate borrow (A=0xFF if borrow)
257         SUB     B
258         LD      B,A
259 .dorem:
260         ;; Negate remainder if it is negative
261         LD      A,(.srem)
262         AND     #0x80
263         RET     Z               ; Return if remainder is positive
264         SUB     A               ; Substract remainder from 0
265         SUB     E
266         LD      E,A
267         SBC     A               ; Propagate remainder (A=0xFF if borrow)
268         SUB     D
269         LD      D,A
270         RET
271
272 .divu8::
273 .modu8::
274         LD      B,#0x00
275         LD      D,B
276         ; Fall through to divu16
277
278 .divu16::
279 .modu16::
280         ;; Check for division by zero
281         LD      A,E
282         OR      D
283         jp      NZ,.divide      ; Branch if divisor is non-zero
284         LD      BC,#0x00        ; Divide by zero error
285         LD      D,B
286         LD      E,C
287         SCF                     ; Set carry, invalid result
288         RET
289 .divide:
290         ld      hl,#0
291 ;       LD      L,C             ; L = low byte of dividend/quotient
292 ;       LD      H,B             ; H = high byte of dividend/quotient
293 ;       LD      BC,#0x00        ; BC = remainder
294         OR      A               ; Clear carry to start
295         ex      af,af
296         LD      A,#16           ; 16 bits in dividend
297 .dvloop:
298         ;; Shift next bit of quotient into bit 0 of dividend
299         ;; Shift next MSB of dividend into LSB of remainder
300         ;; BC holds both dividend and quotient. While we shift a bit from
301         ;;  MSB of dividend, we shift next bit of quotient in from carry
302         ;; HL holds remainder
303         ;; Do a 32-bit left shift, shifting carry to L, L to H,
304         ;;  H to C, C to B
305         ex      af,af'
306         RL      C               ; Carry (next bit of quotient) to bit 0
307         RL      B               ; Clears carry since BC was 0
308         adc     hl,hl           
309
310         ;; If remainder is >= divisor, next bit of quotient is 1. This
311         ;;  bit goes to carry
312         PUSH    HL              ; Save current remainder
313         sbc     hl,de
314 ;       LD      A,C             ; Substract divisor from remainder
315 ;       SBC     E
316 ;       LD      C,A
317 ;       LD      A,B
318 ;       SBC     D
319 ;       LD      B,A
320         CCF                     ; Complement borrow so 1 indicates a
321                                 ;  successful substraction (this is the
322                                 ;  next bit of quotient)
323         jp      C,.drop         ; Jump if remainder is >= dividend
324         POP     HL              ; Otherwise, restore remainder
325         jp      .nodrop
326 .drop:
327         INC     SP
328         INC     SP
329 .nodrop:
330         ex      af,af'
331         DEC     A               ; DEC does not affect carry flag
332         jp      NZ,.dvloop
333         ex      af,af'
334         ;; Shift last carry bit into quotient
335         LD      D,H             ; DE = remainder
336         LD      E,L
337         RL      C               ; Carry to L
338 ;       LD      C,L             ; C = low byte of quotient
339         RL      B
340 ;       LD      B,H             ; B = high byte of quotient
341         OR      A               ; Clear carry, valid result
342         RET
343
344         .area   _BSS
345
346 .srem:
347         .ds 0x01                ; Sign of quotient
348 .squot:
349         .ds 0x01                ; Sign of remainder
350 .dcnt:
351         .ds 0x01                ; Counter for division