* src/z80/gen.c: Fixed up generator to pass the regresion tests, specifically fixing...
[fw/sdcc] / 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         LD      (.srem),A       ; Save as sign of remainder
208         XOR     D               ; Xor with high byte of divisor
209         LD      (.squot),A      ; Save sign of quotient
210         ;; Take absolute value of divisor
211         BIT     7,D
212         JR      Z,.chkde        ; Jump if divisor is positive
213         SUB     A               ; Substract divisor from 0
214         SUB     E
215         LD      E,A
216         SBC     A               ; Propagate borrow (A=0xFF if borrow)
217         SUB     D
218         LD      D,A
219         ;; Take absolute value of dividend
220 .chkde:
221         BIT     7,B
222         JR      Z,.dodiv        ; Jump if dividend is positive
223         SUB     A               ; Substract dividend from 0
224         SUB     C
225         LD      C,A
226         SBC     A               ; Propagate borrow (A=0xFF if borrow)
227         SUB     B
228         LD      B,A
229         ;; Divide absolute values
230 .dodiv:
231         CALL    .divu16
232         RET     C               ; Exit if divide by zero
233         ;; Negate quotient if it is negative
234         LD      A,(.squot)
235         AND     #0x80
236         JR      Z,.dorem        ; Jump if quotient is positive
237         SUB     A               ; Substract quotient from 0
238         SUB     C
239         LD      C,A
240         SBC     A               ; Propagate borrow (A=0xFF if borrow)
241         SUB     B
242         LD      B,A
243 .dorem:
244         ;; Negate remainder if it is negative
245         LD      A,(.srem)
246         AND     #0x80
247         RET     Z               ; Return if remainder is positive
248         SUB     A               ; Substract remainder from 0
249         SUB     E
250         LD      E,A
251         SBC     A               ; Propagate remainder (A=0xFF if borrow)
252         SUB     D
253         LD      D,A
254         RET
255
256 .divu8::
257 .modu8::
258         LD      B,#0x00
259         LD      D,B
260         ; Fall through to divu16
261
262 .divu16::
263 .modu16::
264         ;; Check for division by zero
265         LD      A,E
266         OR      D
267         JR      NZ,.divide      ; Branch if divisor is non-zero
268         LD      BC,#0x00        ; Divide by zero error
269         LD      D,B
270         LD      E,C
271         SCF                     ; Set carry, invalid result
272         RET
273 .divide:
274         LD      L,C             ; L = low byte of dividend/quotient
275         LD      H,B             ; H = high byte of dividend/quotient
276         LD      BC,#0x00        ; BC = remainder
277         OR      A               ; Clear carry to start
278         LD      A,#16           ; 16 bits in dividend
279 .dvloop:
280         ;; Shift next bit of quotient into bit 0 of dividend
281         ;; Shift next MSB of dividend into LSB of remainder
282         ;; BC holds both dividend and quotient. While we shift a bit from
283         ;;  MSB of dividend, we shift next bit of quotient in from carry
284         ;; HL holds remainder
285         ;; Do a 32-bit left shift, shifting carry to L, L to H,
286         ;;  H to C, C to B
287         LD      (.dcnt),A
288         RL      L               ; Carry (next bit of quotient) to bit 0
289         RL      H               ; Shift remaining bytes
290         RL      C
291         RL      B               ; Clears carry since BC was 0
292         ;; If remainder is >= divisor, next bit of quotient is 1. This
293         ;;  bit goes to carry
294         PUSH    BC              ; Save current remainder
295         LD      A,C             ; Substract divisor from remainder
296         SBC     E
297         LD      C,A
298         LD      A,B
299         SBC     D
300         LD      B,A
301         CCF                     ; Complement borrow so 1 indicates a
302                                 ;  successful substraction (this is the
303                                 ;  next bit of quotient)
304         JR      C,.drop         ; Jump if remainder is >= dividend
305         POP     BC              ; Otherwise, restore remainder
306         JR      .nodrop
307 .drop:
308         INC     SP
309         INC     SP
310 .nodrop:
311         LD      A,(.dcnt)
312         DEC     A               ; DEC does not affect carry flag
313         JR      NZ,.dvloop
314         ;; Shift last carry bit into quotient
315         LD      D,B             ; DE = remainder
316         LD      E,C
317         RL      L               ; Carry to L
318         LD      C,L             ; C = low byte of quotient
319         RL      H
320         LD      B,H             ; B = high byte of quotient
321         OR      A               ; Clear carry, valid result
322         RET
323
324         .area   _BSS
325
326 .srem:
327         .ds 0x01                ; Sign of quotient
328 .squot:
329         .ds 0x01                ; Sign of remainder
330 .dcnt:
331         .ds 0x01                ; Counter for division