gbdk-2020 | GameBoy Development Kit |
| download: https://git.y1.nz/archives/gbdk.tar.gz | |
| README | Files | Log | Refs | LICENSE |
gbdk-lib/libc/asm/sm83/div.s
1 ;--------------------------------------------------------------------------
2 ; div.s
3 ;
4 ; Copyright (c) 2026, Phidias618
5 ;
6 ;--------------------------------------------------------------------------
7
8 .module divmod
9 .area _CODE
10
11 .globl __divuchar
12 .globl __moduchar
13 .globl __divuint
14 .globl __moduint
15
16 .globl __divsuchar
17 .globl __modsuchar
18 .globl __divuschar
19 .globl __moduschar
20 .globl __divschar
21 .globl __modschar
22
23 .globl __divsint
24 .globl __modsint
25
26
27 ; unsigned division
28
29 __moduchar:
30 ld c, e
31 ld e, a
32 xor a
33 ld b, a
34 ld d, a
35 __moduint:
36 call .divmod_uint_bcde
37
38 ld c, e
39 ld b, d
40
41 ret
42
43 .divmod_uchar_bcde:
44 __divuchar:
45 ld c, e
46 ld e, a
47 xor a
48 ld b, a
49 ld d, a
50 ; Fall through .divmod_uint_bcde
51 .divmod_uint_bcde:
52 __divuint::
53 ; computes the quotient and the remainder of X / Y
54 ; X is stored in de
55 ; Y is stored in bc
56 ; outputs the quotient in bc
57 ; outputs the remainder in de
58 ; if Y = 0 then the carry is set and quotient = 0 and remainder = 0
59 ; otherwise the carry is cleared
60
61
62 ; stores -Y in hl and check that -Y is not zero
63 xor a
64 sub c
65 ld l, a
66 sbc a
67 sub b
68 ld h, a
69
70 or l
71 jr z, .division_by_zero
72
73 ; if X < Y then
74 ; return quotient = 0 and remainder = X
75 ; else
76 ; computes the largest (Y << K) such that (Y << K) <= X
77 ; put the 17 bit value -(Y << (K + 1)) into hl with the MSB stored using the carry
78 ; put K, using a base 1 representation, using the most significant bits of bc
79 ld bc, #0
80
81 ld a, e
82 add l
83 ld a, d
84 adc h
85 jr c, 10$
86 ; X < Y
87 ; bc already stores 0
88 ret
89 0$:
90 rr b
91 rr c
92 10$:
93 add hl, hl
94 jr nc, 1$
95
96 ld a, e
97 add l
98 ld a, d
99 adc h
100 jr c, 0$
101 scf
102 1$:
103
104 ; swaps the content of hl and de
105 ld a, h
106 ld h, d
107 ld d, a
108
109 ld a, l
110 ld l, e
111 ld e, a
112
113 ; computes X / Y one bit at a time using the following algorithm
114 ; r = X
115 ; q = 0
116 ; while K >= 0
117 ; b = 0
118 ; if (Y << K) <= r then
119 ; r += -(Y << K)
120 ; b = 1
121 ; q = (q << 1) | b
122 ; K -= 1
123 ;
124 ;
125 ; r is stored in hl
126 ; q is stored in bc
127 ; storing both q and K in bc will not create issue as they will not use the same bits at the same time
128 ; -(Y << K) is stored in de
129 2$:
130 ; on the first iteration :
131 ; this shifts DE such that DE now stores -(Y << K)
132 ; on every iteration but the first:
133 ; transforms -(Y << K) into -(Y << (K-1))
134 ; sra d is not used as the MSB should always be filled with a 1 when shifting de
135 ; this works because the carry will always be set if this is not the first iteration
136 rr d
137 rr e
138
139 ; compare remainder with (Y << K)
140 ld a, e
141 add l
142 ld a, d
143 adc h
144
145 jr nc, 3$
146 add hl, de
147 3$:
148 ; fill bc with one bit of the result and decrements K at the same time
149 rl c
150 rl b
151
152 jr c, 2$
153 ret_hl_in_de:
154 ld d, h
155 ld e, l
156 ; status of the registers
157 ; bc = quotient
158 ; de = remainder
159 ; carry = 0 if Y != 0, 1 if Y == 0
160
161 ret
162 .division_by_zero:
163 ; returns both a quotient of 0 and a remainder of 0
164 ; if this is reached, then bc = 0
165 scf
166 jr ret_hl_in_de
167
168
169 ; mixed sign division
170
171 __modsuchar:
172 call .divmod_suchar_bcde
173 ld b, d
174 ld c, e
175 ret
176 .divmod_suchar_bcde:
177 __divsuchar:
178 ld d, #0
179 ld c, e
180 ld e, a
181
182 jr signext_c
183
184 __moduschar:
185 call .divmod_uschar_bcde
186 ld b, d
187 ld c, e
188 ret
189 .divmod_uschar_bcde:
190 __divuschar:
191 ld b, #0
192 ld c, e
193 ld e, a
194 add a
195 sbc a
196 ld d, a
197
198 jr .divmod_sint_bcde
199
200 ; signed division
201
202 __modschar:
203 call .divmod_schar_bcde
204 ld b, d
205 ld c, e
206 ret
207 __modsint::
208 call .divmod_sint_bcde
209 ld b, d
210 ld c, e
211 ret
212
213 ; these 2 functions exists for compatibility reasons
214 .div8::
215 .mod8::
216 ld a, c
217 ; Fall through .divmod_schar_bcde
218 .divmod_schar_bcde:
219 __divschar:
220 ld c, e
221 ld e, a
222 add a
223 sbc a
224 ld d, a
225 signext_c:
226 ld a, c
227 rlca
228 sbc a
229 ld b, a
230 ; Fall through .divmod_sint_bcde
231 .divmod_sint_bcde:
232 __divsint::
233 ; saves the sign of the quotient as the carry and the sign of the remainder as the 7th bit of A
234 ld a, d ; high byte of dividend
235 xor b ; high byte of divisor
236 rla ; save the 7th bit of A as the carry
237 ld a, d
238 push af
239
240 ; take the absolute value of de
241 add a
242 jr nc, 0$
243
244 xor a
245 sub e
246 ld e, a
247 sbc a
248 sub d
249 ld d, a
250 0$:
251 ; take the absolute value of bc
252 bit 7, b
253 jr z, 1$
254
255 xor a
256 sub c
257 ld c, a
258 sbc a
259 sub b
260 ld b, a
261 1$:
262 call .divmod_uint_bcde
263 jr c, .error
264 pop af ; retrieve the signs the the quotient and the sign of the remainder
265
266 jr nc, 2$
267 ld l, a ; saves the sign of the remainder
268 ; negates the quotient
269 xor a
270 sub c
271 ld c, a
272 sbc a
273 sub b
274 ld b, a
275
276 ld a, l
277 2$:
278 rlca
279 ret nc
280 ; negates the remainder
281 xor a
282 sub e
283 ld e, a
284 sbc a
285 sub d
286 ld d, a
287
288 or a ; clears the carry
289 ret
290 .error:
291 pop hl ; do not pop af in order to preserve the carry as set
292 ret
293
294
295 ; the following functions are here in order to not break compatibility
296
297 ;; 16-bit division
298 ;;
299 ;; Entry conditions
300 ;; BC = dividend
301 ;; DE = divisor
302 ;;
303 ;; Exit conditions
304 ;; BC = quotient
305 ;; DE = remainder
306 ;; If divisor is non-zero, carry=0
307 ;; If divisor is 0, carry=1 and both quotient and remainder are 0
308 ;;
309 ;; Register used: AF,BC,DE,HL
310 .div16::
311 .mod16::
312 ld hl, #.divmod_sint_bcde
313 swap_bc_de_jp_hl:
314 ld a, b
315 ld b, d
316 ld d, a
317
318 ld a, c
319 ld c, e
320 ld e, a
321
322 jp (hl)
323 .divu8::
324 .modu8::
325 ld b,#0x00
326 ld d,b
327 ; Fall through to .divu16
328 .divu16::
329 .modu16::
330 ld hl, #.divmod_uint_bcde
331 jr swap_bc_de_jp_hl
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.