Changed default documentation dir to share/doc/sdcc
[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         ld      c,l
104         call    .divu8
105
106         ld      l,c
107         ld      h,b
108         
109         ret
110         
111 __moduchar_rr_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_rr_hds::
121         ld      c,l
122         call    .divu8
123
124         ld      l,e
125         ld      h,d
126
127         ret
128
129 __divuint_rr_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_rr_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_rr_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_rr_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