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