struct / union in initializer, RFE #901.
[sdcc.git] / sdcc / device / lib / sm83 / divint.s
blob2e012a9db3b1c7da48460aa67bc8cd42d6f053db
1 ;--------------------------------------------------------------------------
2 ; div.s
4 ; Copyright (C) 2000, Michael Hope
5 ; Copyright (C) 2021, Sebastian 'basxto' Riedel (sdcc@basxto.de)
6 ; Copyright (c) 2021, Philipp Klaus Krause
8 ; This library is free software; you can redistribute it and/or modify it
9 ; under the terms of the GNU General Public License as published by the
10 ; Free Software Foundation; either version 2, or (at your option) any
11 ; later version.
13 ; This library is distributed in the hope that it will be useful,
14 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ; GNU General Public License for more details.
18 ; You should have received a copy of the GNU General Public License
19 ; along with this library; see the file COPYING. If not, write to the
20 ; Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
21 ; MA 02110-1301, USA.
23 ; As a special exception, if you link this library with other files,
24 ; some of which are compiled with SDCC, to produce an executable,
25 ; this library does not by itself cause the resulting executable to
26 ; be covered by the GNU General Public License. This exception does
27 ; not however invalidate any other reasons why the executable file
28 ; might be covered by the GNU General Public License.
29 ;--------------------------------------------------------------------------
31 ;; Originally from GBDK by Pascal Felber.
32 .area _CODE
34 .globl __divsuchar
35 .globl __modsuchar
36 .globl __divuschar
37 .globl __moduschar
38 .globl __divschar
39 .globl __modschar
40 .globl __divsint
41 .globl __modsint
42 .globl __divuchar
43 .globl __moduchar
44 .globl __divuint
45 .globl __moduint
47 __divsuchar:
48 ld c, a
49 ld b, #0
51 jp signexte
53 __modsuchar:
54 ld c, a
55 ld b, #0
57 call signexte
59 ld c, e
60 ld b, d
62 ret
64 __divuschar:
65 ld d, #0
67 ld c, a ; Sign extend
68 rlca
69 sbc a
70 ld b,a
72 jp .div16
74 __moduschar:
75 ld d, #0
77 ld c, a ; Sign extend
78 rlca
79 sbc a
80 ld b,a
82 call .div16
84 ld c, e
85 ld b, d
87 ret
89 __divschar:
90 ld c, a
92 call .div8
94 ret
96 __modschar:
97 ld c, a
99 call .div8
101 ld c, e
102 ld b, d
106 __divsint:
107 ld a, e
108 ld e, c
109 ld c, a
111 ld a, d
112 ld d, b
113 ld b, a
115 jp .div16
117 __modsint:
118 ld a, e
119 ld e, c
120 ld c, a
122 ld a, d
123 ld d, b
124 ld b, a
126 call .div16
128 ld c, e
129 ld b, d
133 ;; Unsigned
134 __divuchar:
135 ld c, a
137 call .divu8
141 __moduchar:
142 ld c, a
144 call .divu8
146 ld c, e
147 ld b, d
151 __divuint:
152 ld a, e
153 ld e, c
154 ld c, a
156 ld a, d
157 ld d, b
158 ld b, a
160 jp .divu16
162 __moduint:
163 ld a, e
164 ld e, c
165 ld c, a
167 ld a, d
168 ld d, b
169 ld b, a
171 call .divu16
173 ld c, e
174 ld b, d
178 .div8::
179 .mod8::
180 ld a,c ; Sign extend
181 rlca
182 sbc a
183 ld b,a
184 signexte:
185 ld a, e ; Sign extend
186 rlca
187 sbc a
188 ld d, a
190 ; Fall through to .div16
192 ;; 16-bit division
194 ;; Entry conditions
195 ;; BC = dividend
196 ;; DE = divisor
198 ;; Exit conditions
199 ;; BC = quotient
200 ;; DE = remainder
201 ;; If divisor is non-zero, carry=0
202 ;; If divisor is 0, carry=1 and both quotient and remainder are 0
204 ;; Register used: AF,BC,DE,HL
205 .div16::
206 .mod16::
207 ;; Determine sign of quotient by xor-ing high bytes of dividend
208 ;; and divisor. Quotient is positive if signs are the same, negative
209 ;; if signs are different
210 ;; Remainder has same sign as dividend
211 ld a,b ; Get high byte of dividend
212 push af ; Save as sign of remainder
213 xor d ; Xor with high byte of divisor
214 push af ; Save sign of quotient
216 ;; Take absolute value of divisor
217 bit 7,d
218 jr Z,.chkde ; Jump if divisor is positive
219 sub a ; Subtract divisor from 0
220 sub e
221 ld e,a
222 sbc a ; Propagate borrow (A=0xFF if borrow)
223 sub d
224 ld d,a
225 ;; Take absolute value of dividend
226 .chkde:
227 bit 7,b
228 jr Z,.dodiv ; Jump if dividend is positive
229 sub a ; Subtract dividend from 0
230 sub c
231 ld c,a
232 sbc a ; Propagate borrow (A=0xFF if borrow)
233 sub b
234 ld b,a
235 ;; Divide absolute values
236 .dodiv:
237 call .divu16
238 jr C,.exit ; Exit if divide by zero
239 ;; Negate quotient if it is negative
240 pop af ; recover sign of quotient
241 and #0x80
242 jr Z,.dorem ; Jump if quotient is positive
243 sub a ; Subtract quotient from 0
244 sub c
245 ld c,a
246 sbc a ; Propagate borrow (A=0xFF if borrow)
247 sub b
248 ld b,a
249 .dorem:
250 ;; Negate remainder if it is negative
251 pop af ; recover sign of remainder
252 and #0x80
253 ret Z ; Return if remainder is positive
254 sub a ; Subtract remainder from 0
255 sub e
256 ld e,a
257 sbc a ; Propagate remainder (A=0xFF if borrow)
258 sub d
259 ld d,a
261 .exit:
262 pop af
263 pop af
266 .divu8::
267 .modu8::
268 ld b,#0x00
269 ld d,b
270 ; Fall through to divu16
272 .divu16::
273 .modu16::
274 ;; Check for division by zero
275 ld a,e
276 or d
277 jr NZ,.divide ; Branch if divisor is non-zero
278 ld bc,#0x00 ; Divide by zero error
279 ld d,b
280 ld e,c
281 scf ; Set carry, invalid result
283 .divide:
284 ld l,c ; L = low byte of dividend/quotient
285 ld h,b ; H = high byte of dividend/quotient
286 ld bc,#0x00 ; BC = remainder
287 or a ; Clear carry to start
288 ld a,#16 ; 16 bits in dividend
289 .dvloop:
290 ;; Shift next bit of quotient into bit 0 of dividend
291 ;; Shift next MSB of dividend into LSB of remainder
292 ;; BC holds both dividend and quotient. While we shift a bit from
293 ;; MSB of dividend, we shift next bit of quotient in from carry
294 ;; HL holds remainder
295 ;; Do a 32-bit left shift, shifting carry to L, L to H,
296 ;; H to C, C to B
297 push af ; save number of bits remaining
298 rl l ; Carry (next bit of quotient) to bit 0
299 rl h ; Shift remaining bytes
300 rl c
301 rl b ; Clears carry since BC was 0
302 ;; If remainder is >= divisor, next bit of quotient is 1. This
303 ;; bit goes to carry
304 push bc ; Save current remainder
305 ld a,c ; Subtract divisor from remainder
306 sbc e
307 ld c,a
308 ld a,b
309 sbc d
310 ld b,a
311 ccf ; Complement borrow so 1 indicates a
312 ; successful subtraction (this is the
313 ; next bit of quotient)
314 jr C,.drop ; Jump if remainder is >= dividend
315 pop bc ; Otherwise, restore remainder
316 pop af ; recover # bits remaining, carry flag destroyed
317 dec a
318 or a ; restore (clear) the carry flag
319 jr NZ,.dvloop
320 jr .nodrop
321 .drop:
322 pop af ; faster and smaller than 2x inc sp
323 pop af ; recover # bits remaining, carry flag destroyed
324 dec a
325 scf ; restore (set) the carry flag
326 jr NZ,.dvloop
327 jr .nodrop
328 .nodrop:
329 ;; Shift last carry bit into quotient
330 ld d,b ; DE = remainder
331 ld e,c
332 rl l ; Carry to L
333 ld c,l ; C = low byte of quotient
334 rl h
335 ld b,h ; B = high byte of quotient
336 or a ; Clear carry, valid result