Re-worked the makefiles and includes to target z80 and gbz80 as well
[fw/sdcc] / device / lib / z80 / div.s
1         ;; Originally from GBDK by Pascal Felber.
2         .area   _CODE
3
4 __divschar::
5         push    bc
6         ld      c,l
7         
8         call    .div8
9
10         ld      l,c
11         ld      h,b
12                 
13         pop     bc
14         ret
15         
16 __modschar::
17         push    bc
18         ld      c,l
19
20         call    .div8
21
22         ld      l,e
23         ld      h,d
24                 
25         pop     bc
26         ret
27
28 __divsint::
29         push    bc
30         ld      b,h
31         ld      c,l
32
33         call    .div16
34
35         ld      l,c
36         ld      h,b
37         
38         pop     bc
39         ret
40         
41 __modsint::
42         push    bc
43         ld      b,h
44         ld      c,l
45
46         call    .div16
47
48         ld      l,e
49         ld      h,d
50         
51         pop     bc
52         ret
53
54         ;; Unsigned
55 __divuchar::    
56         push    de
57         push    bc
58         push    ix
59         ld      ix,#0
60         add     ix,sp
61
62         ld      c,8(ix)
63         ld      e,9(ix)
64         call    .divu8
65
66         ld      l,c
67         ld      h,b
68                 
69         pop     ix
70         pop     bc
71         pop     de
72         ret
73         
74 __moduchar::
75         push    de
76         push    bc
77         push    ix
78         ld      ix,#0
79         add     ix,sp
80
81         ld      c,8(ix)
82         ld      e,9(ix)
83         call    .divu8
84
85         ld      l,e
86         ld      h,d
87                 
88         pop     ix
89         pop     bc
90         pop     de
91         ret
92
93 __divuint::
94         push    bc
95         ld      b,h
96         ld      c,l
97         call    .divu16
98
99         ld      l,c
100         ld      h,b
101         
102         pop     bc
103         ret
104         
105 __moduint::
106         push    bc
107         ld      b,h
108         ld      c,l
109
110         call    .divu16
111
112         ld      l,e
113         ld      h,d
114         
115         pop     bc
116         ret
117         
118 .div8::
119 .mod8::
120         LD      A,C             ; Sign extend
121         RLCA
122         SBC     A
123         LD      B,A
124         LD      A,E             ; Sign extend
125         RLCA
126         SBC     A
127         LD      D,A
128
129         ; Fall through to .div16
130         
131         ;; 16-bit division
132         ;; 
133         ;; Entry conditions
134         ;;   BC = dividend
135         ;;   DE = divisor
136         ;; 
137         ;; Exit conditions
138         ;;   BC = quotient
139         ;;   DE = remainder
140         ;;   If divisor is non-zero, carry=0
141         ;;   If divisor is 0, carry=1 and both quotient and remainder are 0
142         ;;
143         ;; Register used: AF,BC,DE,HL
144 .div16::
145 .mod16::
146         ;; Determine sign of quotient by xor-ing high bytes of dividend
147         ;;  and divisor. Quotient is positive if signs are the same, negative
148         ;;  if signs are different
149         ;; Remainder has same sign as dividend
150         LD      A,B             ; Get high byte of dividend
151         LD      (.srem),A       ; Save as sign of remainder
152         XOR     D               ; Xor with high byte of divisor
153         LD      (.squot),A      ; Save sign of quotient
154         ;; Take absolute value of divisor
155         BIT     7,D
156         jp      Z,.chkde        ; Jump if divisor is positive
157         SUB     A               ; Substract divisor from 0
158         SUB     E
159         LD      E,A
160         SBC     A               ; Propagate borrow (A=0xFF if borrow)
161         SUB     D
162         LD      D,A
163         ;; Take absolute value of dividend
164 .chkde:
165         BIT     7,B
166         jp      Z,.dodiv        ; Jump if dividend is positive
167         SUB     A               ; Substract dividend from 0
168         SUB     C
169         LD      C,A
170         SBC     A               ; Propagate borrow (A=0xFF if borrow)
171         SUB     B
172         LD      B,A
173         ;; Divide absolute values
174 .dodiv:
175         CALL    .divu16
176         RET     C               ; Exit if divide by zero
177         ;; Negate quotient if it is negative
178         LD      A,(.squot)
179         AND     #0x80
180         jp      Z,.dorem        ; Jump if quotient is positive
181         SUB     A               ; Substract quotient from 0
182         SUB     C
183         LD      C,A
184         SBC     A               ; Propagate borrow (A=0xFF if borrow)
185         SUB     B
186         LD      B,A
187 .dorem:
188         ;; Negate remainder if it is negative
189         LD      A,(.srem)
190         AND     #0x80
191         RET     Z               ; Return if remainder is positive
192         SUB     A               ; Substract remainder from 0
193         SUB     E
194         LD      E,A
195         SBC     A               ; Propagate remainder (A=0xFF if borrow)
196         SUB     D
197         LD      D,A
198         RET
199
200 .divu8::
201 .modu8::
202         LD      B,#0x00
203         LD      D,B
204         ; Fall through to divu16
205
206 .divu16::
207 .modu16::
208         ;; Check for division by zero
209         LD      A,E
210         OR      D
211         jp      NZ,.divide      ; Branch if divisor is non-zero
212         LD      BC,#0x00        ; Divide by zero error
213         LD      D,B
214         LD      E,C
215         SCF                     ; Set carry, invalid result
216         RET
217 .divide:
218         ld      hl,#0
219 ;       LD      L,C             ; L = low byte of dividend/quotient
220 ;       LD      H,B             ; H = high byte of dividend/quotient
221 ;       LD      BC,#0x00        ; BC = remainder
222         OR      A               ; Clear carry to start
223         ex      af,af
224         LD      A,#16           ; 16 bits in dividend
225 .dvloop:
226         ;; Shift next bit of quotient into bit 0 of dividend
227         ;; Shift next MSB of dividend into LSB of remainder
228         ;; BC holds both dividend and quotient. While we shift a bit from
229         ;;  MSB of dividend, we shift next bit of quotient in from carry
230         ;; HL holds remainder
231         ;; Do a 32-bit left shift, shifting carry to L, L to H,
232         ;;  H to C, C to B
233         ex      af,af'
234         RL      C               ; Carry (next bit of quotient) to bit 0
235         RL      B               ; Clears carry since BC was 0
236         adc     hl,hl           
237
238         ;; If remainder is >= divisor, next bit of quotient is 1. This
239         ;;  bit goes to carry
240         PUSH    HL              ; Save current remainder
241         sbc     hl,de
242 ;       LD      A,C             ; Substract divisor from remainder
243 ;       SBC     E
244 ;       LD      C,A
245 ;       LD      A,B
246 ;       SBC     D
247 ;       LD      B,A
248         CCF                     ; Complement borrow so 1 indicates a
249                                 ;  successful substraction (this is the
250                                 ;  next bit of quotient)
251         jp      C,.drop         ; Jump if remainder is >= dividend
252         POP     HL              ; Otherwise, restore remainder
253         jp      .nodrop
254 .drop:
255         INC     SP
256         INC     SP
257 .nodrop:
258         ex      af,af'
259         DEC     A               ; DEC does not affect carry flag
260         jp      NZ,.dvloop
261         ex      af,af'
262         ;; Shift last carry bit into quotient
263         LD      D,H             ; DE = remainder
264         LD      E,L
265         RL      C               ; Carry to L
266 ;       LD      C,L             ; C = low byte of quotient
267         RL      B
268 ;       LD      B,H             ; B = high byte of quotient
269         OR      A               ; Clear carry, valid result
270         RET
271
272         .area   _BSS
273
274 .srem:
275         .ds 0x01                ; Sign of quotient
276 .squot:
277         .ds 0x01                ; Sign of remainder
278 .dcnt:
279         .ds 0x01                ; Counter for division