divmodsi.S revision 1.7 1 1.1 mrg /* SImode div/mod functions for the GCC support library for the Renesas RL78 processors.
2 1.7 mrg Copyright (C) 2012-2022 Free Software Foundation, Inc.
3 1.1 mrg Contributed by Red Hat.
4 1.1 mrg
5 1.1 mrg This file is part of GCC.
6 1.1 mrg
7 1.1 mrg GCC is free software; you can redistribute it and/or modify it
8 1.1 mrg under the terms of the GNU General Public License as published
9 1.1 mrg by the Free Software Foundation; either version 3, or (at your
10 1.1 mrg option) any later version.
11 1.1 mrg
12 1.1 mrg GCC is distributed in the hope that it will be useful, but WITHOUT
13 1.1 mrg ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 1.1 mrg or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 1.1 mrg License for more details.
16 1.1 mrg
17 1.1 mrg Under Section 7 of GPL version 3, you are granted additional
18 1.1 mrg permissions described in the GCC Runtime Library Exception, version
19 1.1 mrg 3.1, as published by the Free Software Foundation.
20 1.1 mrg
21 1.1 mrg You should have received a copy of the GNU General Public License and
22 1.1 mrg a copy of the GCC Runtime Library Exception along with this program;
23 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 1.1 mrg <http://www.gnu.org/licenses/>. */
25 1.1 mrg
26 1.1 mrg #include "vregs.h"
27 1.1 mrg
28 1.3 mrg #if defined __RL78_MUL_G14__
29 1.3 mrg
30 1.3 mrg START_FUNC ___divsi3
31 1.3 mrg ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
32 1.3 mrg
33 1.3 mrg ;; Load and test for a negative denumerator.
34 1.3 mrg movw ax, [sp+8]
35 1.3 mrg movw de, ax
36 1.3 mrg movw ax, [sp+10]
37 1.3 mrg mov1 cy, a.7
38 1.3 mrg movw hl, ax
39 1.3 mrg bc $__div_neg_den
40 1.3 mrg
41 1.3 mrg ;; Load and test for a negative numerator.
42 1.3 mrg movw ax, [sp+6]
43 1.3 mrg mov1 cy, a.7
44 1.3 mrg movw bc, ax
45 1.3 mrg movw ax, [sp+4]
46 1.3 mrg bc $__div_neg_num
47 1.3 mrg
48 1.3 mrg ;; Neither are negative - we can use the unsigned divide instruction.
49 1.3 mrg __div_no_convert:
50 1.3 mrg push psw
51 1.3 mrg di
52 1.3 mrg divwu
53 1.3 mrg pop psw
54 1.3 mrg
55 1.3 mrg movw r8, ax
56 1.3 mrg movw ax, bc
57 1.3 mrg movw r10, ax
58 1.3 mrg ret
59 1.3 mrg
60 1.3 mrg __div_neg_den:
61 1.3 mrg ;; Negate the denumerator (which is in HLDE)
62 1.3 mrg clrw ax
63 1.3 mrg subw ax, de
64 1.3 mrg movw de, ax
65 1.3 mrg clrw ax
66 1.3 mrg sknc
67 1.3 mrg decw ax
68 1.3 mrg subw ax, hl
69 1.3 mrg movw hl, ax
70 1.3 mrg
71 1.3 mrg ;; Load and test for a negative numerator.
72 1.3 mrg movw ax, [sp+6]
73 1.3 mrg mov1 cy, a.7
74 1.3 mrg movw bc, ax
75 1.3 mrg movw ax, [sp+4]
76 1.3 mrg ;; If it is not negative then we perform the division and then negate the result.
77 1.3 mrg bnc $__div_then_convert
78 1.3 mrg
79 1.3 mrg ;; Otherwise we negate the numerator and then go with a straightforward unsigned division.
80 1.3 mrg ;; The negation is complicated because AX, BC, DE and HL are already in use.
81 1.3 mrg ;; ax: numL bc: numH r8: r10:
82 1.3 mrg xchw ax, bc
83 1.3 mrg ;; ax: numH bc: numL r8: r10:
84 1.3 mrg movw r8, ax
85 1.3 mrg ;; ax: bc: numL r8: numH r10:
86 1.3 mrg clrw ax
87 1.3 mrg ;; ax: 0 bc: numL r8: numH r10:
88 1.3 mrg subw ax, bc
89 1.3 mrg ;; ax: -numL bc: r8: numH r10:
90 1.3 mrg movw r10, ax
91 1.3 mrg ;; ax: bc: r8: numH r10: -numL
92 1.3 mrg movw ax, r8
93 1.3 mrg ;; ax: numH bc: r8: r10: -numL
94 1.3 mrg movw bc, ax
95 1.3 mrg ;; ax: bc: numH r8: r10: -numL
96 1.3 mrg clrw ax
97 1.3 mrg ;; ax: 0 bc: numH r8: r10: -numL
98 1.3 mrg sknc
99 1.3 mrg decw ax
100 1.3 mrg ;; ax: -1 bc: numH r8: r10: -numL
101 1.3 mrg subw ax, bc
102 1.3 mrg ;; ax: -numH bc: r8: r10: -numL
103 1.3 mrg movw bc, ax
104 1.3 mrg ;; ax: bc: -numH r8: r10: -numL
105 1.3 mrg movw ax, r10
106 1.3 mrg ;; ax: -numL bc: -numH r8: r10:
107 1.3 mrg br $!__div_no_convert
108 1.3 mrg
109 1.3 mrg __div_neg_num:
110 1.3 mrg ;; Negate the numerator (which is in BCAX)
111 1.3 mrg ;; We know that the denumerator is positive.
112 1.3 mrg ;; Note - we temporarily overwrite DE. We know that we can safely load it again off the stack again.
113 1.3 mrg movw de, ax
114 1.3 mrg clrw ax
115 1.3 mrg subw ax, de
116 1.3 mrg movw de, ax
117 1.3 mrg clrw ax
118 1.3 mrg sknc
119 1.3 mrg decw ax
120 1.3 mrg subw ax, bc
121 1.3 mrg movw bc, ax
122 1.3 mrg
123 1.3 mrg movw ax, [sp+8]
124 1.3 mrg xchw ax, de
125 1.3 mrg
126 1.3 mrg __div_then_convert:
127 1.3 mrg push psw
128 1.3 mrg di
129 1.3 mrg divwu
130 1.3 mrg pop psw
131 1.3 mrg
132 1.3 mrg ;; Negate result (in BCAX) and transfer into r8,r10
133 1.3 mrg movw de, ax
134 1.3 mrg clrw ax
135 1.3 mrg subw ax, de
136 1.3 mrg movw r8, ax
137 1.3 mrg clrw ax
138 1.3 mrg sknc
139 1.3 mrg decw ax
140 1.3 mrg subw ax, bc
141 1.3 mrg movw r10, ax
142 1.3 mrg ret
143 1.3 mrg
144 1.3 mrg END_FUNC ___divsi3
145 1.3 mrg
146 1.3 mrg ;----------------------------------------------------------------------
147 1.3 mrg
148 1.3 mrg START_FUNC ___udivsi3
149 1.3 mrg ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
150 1.3 mrg ;; Used when compiling with -Os specified.
151 1.3 mrg
152 1.3 mrg movw ax, [sp+10]
153 1.3 mrg movw hl, ax
154 1.3 mrg movw ax, [sp+8]
155 1.3 mrg movw de, ax
156 1.3 mrg movw ax, [sp+6]
157 1.3 mrg movw bc, ax
158 1.3 mrg movw ax, [sp+4]
159 1.3 mrg push psw ; Save the current interrupt status
160 1.3 mrg di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E
161 1.3 mrg divwu ; bcax = bcax / hlde
162 1.3 mrg pop psw ; Restore saved interrupt status
163 1.3 mrg movw r8, ax
164 1.3 mrg movw ax, bc
165 1.3 mrg movw r10, ax
166 1.3 mrg ret
167 1.3 mrg
168 1.3 mrg END_FUNC ___udivsi3
169 1.3 mrg
170 1.3 mrg ;----------------------------------------------------------------------
171 1.3 mrg
172 1.3 mrg START_FUNC ___modsi3
173 1.3 mrg ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
174 1.3 mrg
175 1.3 mrg ;; Load and test for a negative denumerator.
176 1.3 mrg movw ax, [sp+8]
177 1.3 mrg movw de, ax
178 1.3 mrg movw ax, [sp+10]
179 1.3 mrg mov1 cy, a.7
180 1.3 mrg movw hl, ax
181 1.3 mrg bc $__mod_neg_den
182 1.3 mrg
183 1.3 mrg ;; Load and test for a negative numerator.
184 1.3 mrg movw ax, [sp+6]
185 1.3 mrg mov1 cy, a.7
186 1.3 mrg movw bc, ax
187 1.3 mrg movw ax, [sp+4]
188 1.3 mrg bc $__mod_neg_num
189 1.3 mrg
190 1.3 mrg ;; Neither are negative - we can use the unsigned divide instruction.
191 1.3 mrg __mod_no_convert:
192 1.3 mrg push psw
193 1.3 mrg di
194 1.3 mrg divwu
195 1.3 mrg pop psw
196 1.3 mrg
197 1.3 mrg movw ax, de
198 1.3 mrg movw r8, ax
199 1.3 mrg movw ax, hl
200 1.3 mrg movw r10, ax
201 1.3 mrg ret
202 1.3 mrg
203 1.3 mrg __mod_neg_den:
204 1.3 mrg ;; Negate the denumerator (which is in HLDE)
205 1.3 mrg clrw ax
206 1.3 mrg subw ax, de
207 1.3 mrg movw de, ax
208 1.3 mrg clrw ax
209 1.3 mrg sknc
210 1.3 mrg decw ax
211 1.3 mrg subw ax, hl
212 1.3 mrg movw hl, ax
213 1.3 mrg
214 1.3 mrg ;; Load and test for a negative numerator.
215 1.3 mrg movw ax, [sp+6]
216 1.3 mrg mov1 cy, a.7
217 1.3 mrg movw bc, ax
218 1.3 mrg movw ax, [sp+4]
219 1.3 mrg ;; If it is not negative then we perform the modulo operation without conversion
220 1.3 mrg bnc $__mod_no_convert
221 1.3 mrg
222 1.3 mrg ;; Otherwise we negate the numerator and then go with a modulo followed by negation.
223 1.3 mrg ;; The negation is complicated because AX, BC, DE and HL are already in use.
224 1.3 mrg xchw ax, bc
225 1.3 mrg movw r8, ax
226 1.3 mrg clrw ax
227 1.3 mrg subw ax, bc
228 1.3 mrg movw r10, ax
229 1.3 mrg movw ax, r8
230 1.3 mrg movw bc, ax
231 1.3 mrg clrw ax
232 1.3 mrg sknc
233 1.3 mrg decw ax
234 1.3 mrg subw ax, bc
235 1.3 mrg movw bc, ax
236 1.3 mrg movw ax, r10
237 1.3 mrg br $!__mod_then_convert
238 1.3 mrg
239 1.3 mrg __mod_neg_num:
240 1.3 mrg ;; Negate the numerator (which is in BCAX)
241 1.3 mrg ;; We know that the denumerator is positive.
242 1.3 mrg ;; Note - we temporarily overwrite DE. We know that we can safely load it again off the stack again.
243 1.3 mrg movw de, ax
244 1.3 mrg clrw ax
245 1.3 mrg subw ax, de
246 1.3 mrg movw de, ax
247 1.3 mrg clrw ax
248 1.3 mrg sknc
249 1.3 mrg decw ax
250 1.3 mrg subw ax, bc
251 1.3 mrg movw bc, ax
252 1.3 mrg
253 1.3 mrg movw ax, [sp+8]
254 1.3 mrg xchw ax, de
255 1.3 mrg
256 1.3 mrg __mod_then_convert:
257 1.3 mrg push psw
258 1.3 mrg di
259 1.3 mrg divwu
260 1.3 mrg pop psw
261 1.3 mrg
262 1.3 mrg ;; Negate result (in HLDE) and transfer into r8,r10
263 1.3 mrg clrw ax
264 1.3 mrg subw ax, de
265 1.3 mrg movw r8, ax
266 1.3 mrg clrw ax
267 1.3 mrg sknc
268 1.3 mrg decw ax
269 1.3 mrg subw ax, hl
270 1.3 mrg movw r10, ax
271 1.3 mrg ret
272 1.3 mrg
273 1.3 mrg END_FUNC ___modsi3
274 1.3 mrg
275 1.3 mrg ;----------------------------------------------------------------------
276 1.3 mrg
277 1.3 mrg START_FUNC ___umodsi3
278 1.3 mrg ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
279 1.3 mrg ;; Used when compiling with -Os specified.
280 1.3 mrg
281 1.3 mrg movw ax, [sp+10]
282 1.3 mrg movw hl, ax
283 1.3 mrg movw ax, [sp+8]
284 1.3 mrg movw de, ax
285 1.3 mrg movw ax, [sp+6]
286 1.3 mrg movw bc, ax
287 1.3 mrg movw ax, [sp+4]
288 1.3 mrg push psw ; Save the current interrupt status
289 1.3 mrg di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E
290 1.3 mrg divwu ; hlde = bcax %% hlde
291 1.3 mrg pop psw ; Restore saved interrupt status
292 1.3 mrg movw ax, de
293 1.3 mrg movw r8, ax
294 1.3 mrg movw ax, hl
295 1.3 mrg movw r10, ax
296 1.3 mrg ret
297 1.3 mrg
298 1.3 mrg END_FUNC ___umodsi3
299 1.3 mrg
300 1.3 mrg ;----------------------------------------------------------------------
301 1.3 mrg
302 1.3 mrg #elif defined __RL78_MUL_G13__
303 1.3 mrg
304 1.3 mrg ;----------------------------------------------------------------------
305 1.3 mrg
306 1.3 mrg ;; Hardware registers. Note - these values match the silicon, not the documentation.
307 1.3 mrg MDAL = 0xffff0
308 1.3 mrg MDAH = 0xffff2
309 1.3 mrg MDBL = 0xffff6
310 1.3 mrg MDBH = 0xffff4
311 1.3 mrg MDCL = 0xf00e0
312 1.3 mrg MDCH = 0xf00e2
313 1.3 mrg MDUC = 0xf00e8
314 1.3 mrg
315 1.3 mrg .macro _Negate low, high
316 1.3 mrg movw ax, \low
317 1.3 mrg movw bc, ax
318 1.3 mrg clrw ax
319 1.3 mrg subw ax, bc
320 1.3 mrg movw \low, ax
321 1.3 mrg movw ax, \high
322 1.3 mrg movw bc, ax
323 1.3 mrg clrw ax
324 1.3 mrg sknc
325 1.3 mrg decw ax
326 1.3 mrg subw ax, bc
327 1.3 mrg movw \high, ax
328 1.3 mrg .endm
329 1.3 mrg
330 1.3 mrg ;----------------------------------------------------------------------
331 1.3 mrg
332 1.3 mrg START_FUNC ___divsi3
333 1.3 mrg ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
334 1.3 mrg
335 1.3 mrg mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
336 1.3 mrg mov !MDUC, a ; This preps the peripheral for division without interrupt generation
337 1.3 mrg
338 1.3 mrg ;; Load and test for a negative denumerator.
339 1.3 mrg movw ax, [sp+8]
340 1.3 mrg movw MDBL, ax
341 1.3 mrg movw ax, [sp+10]
342 1.3 mrg mov1 cy, a.7
343 1.3 mrg movw MDBH, ax
344 1.3 mrg bc $__div_neg_den
345 1.3 mrg
346 1.3 mrg ;; Load and test for a negative numerator.
347 1.3 mrg movw ax, [sp+6]
348 1.3 mrg mov1 cy, a.7
349 1.3 mrg movw MDAH, ax
350 1.3 mrg movw ax, [sp+4]
351 1.3 mrg movw MDAL, ax
352 1.3 mrg bc $__div_neg_num
353 1.3 mrg
354 1.3 mrg ;; Neither are negative - we can use the unsigned divide hardware.
355 1.3 mrg __div_no_convert:
356 1.3 mrg mov a, #0xC1 ; Set the DIVST bit in MDUC
357 1.3 mrg mov !MDUC, a ; This starts the division op
358 1.3 mrg
359 1.3 mrg 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
360 1.3 mrg bt a.0, $1b
361 1.3 mrg
362 1.3 mrg movw ax, MDAL ; Read the result
363 1.3 mrg movw r8, ax
364 1.3 mrg movw ax, MDAH
365 1.3 mrg movw r10, ax
366 1.3 mrg ret
367 1.3 mrg
368 1.3 mrg __div_neg_den:
369 1.3 mrg ;; Negate the denumerator (which is in MDBL/MDBH)
370 1.3 mrg _Negate MDBL MDBH
371 1.3 mrg
372 1.3 mrg ;; Load and test for a negative numerator.
373 1.3 mrg movw ax, [sp+6]
374 1.3 mrg mov1 cy, a.7
375 1.3 mrg movw MDAH, ax
376 1.3 mrg movw ax, [sp+4]
377 1.3 mrg movw MDAL, ax
378 1.3 mrg ;; If it is not negative then we perform the division and then negate the result.
379 1.3 mrg bnc $__div_then_convert
380 1.3 mrg
381 1.3 mrg ;; Otherwise we negate the numerator and then go with a straightforward unsigned division.
382 1.3 mrg _Negate MDAL MDAH
383 1.3 mrg br $!__div_no_convert
384 1.3 mrg
385 1.3 mrg __div_neg_num:
386 1.3 mrg ;; Negate the numerator (which is in MDAL/MDAH)
387 1.3 mrg ;; We know that the denumerator is positive.
388 1.3 mrg _Negate MDAL MDAH
389 1.3 mrg
390 1.3 mrg __div_then_convert:
391 1.3 mrg mov a, #0xC1 ; Set the DIVST bit in MDUC
392 1.3 mrg mov !MDUC, a ; This starts the division op
393 1.3 mrg
394 1.3 mrg 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
395 1.3 mrg bt a.0, $1b
396 1.3 mrg
397 1.3 mrg ;; Negate result and transfer into r8,r10
398 1.3 mrg _Negate MDAL MDAH ; FIXME: This could be coded more efficiently.
399 1.3 mrg movw r10, ax
400 1.3 mrg movw ax, MDAL
401 1.3 mrg movw r8, ax
402 1.3 mrg
403 1.3 mrg ret
404 1.3 mrg
405 1.3 mrg END_FUNC ___divsi3
406 1.3 mrg
407 1.3 mrg ;----------------------------------------------------------------------
408 1.3 mrg
409 1.3 mrg START_FUNC ___modsi3
410 1.3 mrg ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
411 1.3 mrg
412 1.3 mrg mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
413 1.3 mrg mov !MDUC, a ; This preps the peripheral for division without interrupt generation
414 1.3 mrg
415 1.3 mrg ;; Load and test for a negative denumerator.
416 1.3 mrg movw ax, [sp+8]
417 1.3 mrg movw MDBL, ax
418 1.3 mrg movw ax, [sp+10]
419 1.3 mrg mov1 cy, a.7
420 1.3 mrg movw MDBH, ax
421 1.3 mrg bc $__mod_neg_den
422 1.3 mrg
423 1.3 mrg ;; Load and test for a negative numerator.
424 1.3 mrg movw ax, [sp+6]
425 1.3 mrg mov1 cy, a.7
426 1.3 mrg movw MDAH, ax
427 1.3 mrg movw ax, [sp+4]
428 1.3 mrg movw MDAL, ax
429 1.3 mrg bc $__mod_neg_num
430 1.3 mrg
431 1.3 mrg ;; Neither are negative - we can use the unsigned divide hardware
432 1.3 mrg __mod_no_convert:
433 1.3 mrg mov a, #0xC1 ; Set the DIVST bit in MDUC
434 1.3 mrg mov !MDUC, a ; This starts the division op
435 1.3 mrg
436 1.3 mrg 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
437 1.3 mrg bt a.0, $1b
438 1.3 mrg
439 1.3 mrg movw ax, !MDCL ; Read the remainder
440 1.3 mrg movw r8, ax
441 1.3 mrg movw ax, !MDCH
442 1.3 mrg movw r10, ax
443 1.3 mrg ret
444 1.3 mrg
445 1.3 mrg __mod_neg_den:
446 1.3 mrg ;; Negate the denumerator (which is in MDBL/MDBH)
447 1.3 mrg _Negate MDBL MDBH
448 1.3 mrg
449 1.3 mrg ;; Load and test for a negative numerator.
450 1.3 mrg movw ax, [sp+6]
451 1.3 mrg mov1 cy, a.7
452 1.3 mrg movw MDAH, ax
453 1.3 mrg movw ax, [sp+4]
454 1.3 mrg movw MDAL, ax
455 1.3 mrg ;; If it is not negative then we perform the modulo operation without conversion
456 1.3 mrg bnc $__mod_no_convert
457 1.3 mrg
458 1.3 mrg ;; Otherwise we negate the numerator and then go with a modulo followed by negation.
459 1.3 mrg _Negate MDAL MDAH
460 1.3 mrg br $!__mod_then_convert
461 1.3 mrg
462 1.3 mrg __mod_neg_num:
463 1.3 mrg ;; Negate the numerator (which is in MDAL/MDAH)
464 1.3 mrg ;; We know that the denumerator is positive.
465 1.3 mrg _Negate MDAL MDAH
466 1.3 mrg
467 1.3 mrg __mod_then_convert:
468 1.3 mrg mov a, #0xC1 ; Set the DIVST bit in MDUC
469 1.3 mrg mov !MDUC, a ; This starts the division op
470 1.3 mrg
471 1.3 mrg 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
472 1.3 mrg bt a.0, $1b
473 1.3 mrg
474 1.3 mrg movw ax, !MDCL
475 1.3 mrg movw bc, ax
476 1.3 mrg clrw ax
477 1.3 mrg subw ax, bc
478 1.3 mrg movw r8, ax
479 1.3 mrg movw ax, !MDCH
480 1.3 mrg movw bc, ax
481 1.3 mrg clrw ax
482 1.3 mrg sknc
483 1.3 mrg decw ax
484 1.3 mrg subw ax, bc
485 1.3 mrg movw r10, ax
486 1.3 mrg ret
487 1.3 mrg
488 1.3 mrg END_FUNC ___modsi3
489 1.3 mrg
490 1.3 mrg ;----------------------------------------------------------------------
491 1.3 mrg
492 1.3 mrg START_FUNC ___udivsi3
493 1.3 mrg ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
494 1.3 mrg ;; Used when compilng with -Os specified.
495 1.3 mrg
496 1.3 mrg mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
497 1.3 mrg mov !MDUC, a ; This preps the peripheral for division without interrupt generation
498 1.3 mrg
499 1.3 mrg movw ax, [sp+4] ; Load the divisor
500 1.3 mrg movw MDAL, ax
501 1.3 mrg movw ax, [sp+6]
502 1.3 mrg movw MDAH, ax
503 1.3 mrg movw ax, [sp+8] ; Load the dividend
504 1.3 mrg movw MDBL, ax
505 1.3 mrg movw ax, [sp+10]
506 1.3 mrg movw MDBH, ax
507 1.3 mrg
508 1.3 mrg mov a, #0xC1 ; Set the DIVST bit in MDUC
509 1.3 mrg mov !MDUC, a ; This starts the division op
510 1.3 mrg
511 1.3 mrg 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
512 1.3 mrg bt a.0, $1b
513 1.3 mrg
514 1.3 mrg movw ax, !MDAL ; Read the result
515 1.3 mrg movw r8, ax
516 1.3 mrg movw ax, !MDAH
517 1.3 mrg movw r10, ax
518 1.3 mrg ret
519 1.3 mrg
520 1.3 mrg END_FUNC ___udivsi3
521 1.3 mrg
522 1.3 mrg ;----------------------------------------------------------------------
523 1.3 mrg
524 1.3 mrg START_FUNC ___umodsi3
525 1.3 mrg ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
526 1.3 mrg ;; Used when compilng with -Os specified.
527 1.3 mrg ;; Note - hardware address match the silicon, not the documentation
528 1.3 mrg
529 1.3 mrg mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
530 1.3 mrg mov !MDUC, a ; This preps the peripheral for division without interrupt generation
531 1.3 mrg
532 1.3 mrg movw ax, [sp+4] ; Load the divisor
533 1.3 mrg movw MDAL, ax
534 1.3 mrg movw ax, [sp+6]
535 1.3 mrg movw MDAH, ax
536 1.3 mrg movw ax, [sp+8] ; Load the dividend
537 1.3 mrg movw MDBL, ax
538 1.3 mrg movw ax, [sp+10]
539 1.3 mrg movw MDBH, ax
540 1.3 mrg
541 1.3 mrg mov a, #0xC1 ; Set the DIVST bit in MDUC
542 1.3 mrg mov !MDUC, a ; This starts the division op
543 1.3 mrg
544 1.3 mrg 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
545 1.3 mrg bt a.0, $1b
546 1.3 mrg
547 1.3 mrg movw ax, !MDCL ; Read the remainder
548 1.3 mrg movw r8, ax
549 1.3 mrg movw ax, !MDCH
550 1.3 mrg movw r10, ax
551 1.3 mrg ret
552 1.3 mrg
553 1.3 mrg END_FUNC ___umodsi3
554 1.3 mrg
555 1.3 mrg ;----------------------------------------------------------------------
556 1.3 mrg
557 1.3 mrg #elif defined __RL78_MUL_NONE__
558 1.3 mrg
559 1.1 mrg .macro MAKE_GENERIC which,need_result
560 1.1 mrg
561 1.1 mrg .if \need_result
562 1.1 mrg quot = r8
563 1.1 mrg num = r12
564 1.1 mrg den = r16
565 1.1 mrg bit = r20
566 1.1 mrg .else
567 1.1 mrg num = r8
568 1.1 mrg quot = r12
569 1.1 mrg den = r16
570 1.1 mrg bit = r20
571 1.1 mrg .endif
572 1.1 mrg
573 1.1 mrg quotH = quot+2
574 1.1 mrg quotL = quot
575 1.1 mrg quotB0 = quot
576 1.1 mrg quotB1 = quot+1
577 1.1 mrg quotB2 = quot+2
578 1.1 mrg quotB3 = quot+3
579 1.1 mrg
580 1.1 mrg numH = num+2
581 1.1 mrg numL = num
582 1.1 mrg numB0 = num
583 1.1 mrg numB1 = num+1
584 1.1 mrg numB2 = num+2
585 1.1 mrg numB3 = num+3
586 1.1 mrg
587 1.1 mrg #define denH bc
588 1.1 mrg denL = den
589 1.1 mrg denB0 = den
590 1.1 mrg denB1 = den+1
591 1.1 mrg #define denB2 c
592 1.1 mrg #define denB3 b
593 1.1 mrg
594 1.1 mrg bitH = bit+2
595 1.1 mrg bitL = bit
596 1.1 mrg bitB0 = bit
597 1.1 mrg bitB1 = bit+1
598 1.1 mrg bitB2 = bit+2
599 1.1 mrg bitB3 = bit+3
600 1.1 mrg
601 1.3 mrg ;----------------------------------------------------------------------
602 1.3 mrg
603 1.1 mrg START_FUNC __generic_sidivmod\which
604 1.1 mrg
605 1.1 mrg num_lt_den\which:
606 1.1 mrg .if \need_result
607 1.1 mrg movw r8, #0
608 1.1 mrg movw r10, #0
609 1.1 mrg .else
610 1.1 mrg movw ax, [sp+8]
611 1.1 mrg movw r8, ax
612 1.1 mrg movw ax, [sp+10]
613 1.1 mrg movw r10, ax
614 1.1 mrg .endif
615 1.1 mrg ret
616 1.1 mrg
617 1.1 mrg shift_den_bit16\which:
618 1.1 mrg movw ax, denL
619 1.1 mrg movw denH, ax
620 1.1 mrg movw denL, #0
621 1.1 mrg .if \need_result
622 1.1 mrg movw ax, bitL
623 1.1 mrg movw bitH, ax
624 1.1 mrg movw bitL, #0
625 1.1 mrg .else
626 1.1 mrg mov a, bit
627 1.1 mrg add a, #16
628 1.1 mrg mov bit, a
629 1.1 mrg .endif
630 1.1 mrg br $shift_den_bit\which
631 1.1 mrg
632 1.1 mrg ;; These routines leave DE alone - the signed functions use DE
633 1.1 mrg ;; to store sign information that must remain intact
634 1.1 mrg
635 1.1 mrg .if \need_result
636 1.1 mrg .global __generic_sidiv
637 1.1 mrg __generic_sidiv:
638 1.1 mrg
639 1.1 mrg .else
640 1.1 mrg
641 1.1 mrg .global __generic_simod
642 1.1 mrg __generic_simod:
643 1.1 mrg
644 1.1 mrg .endif
645 1.1 mrg
646 1.1 mrg ;; (quot,rem) = 8[sp] /% 12[sp]
647 1.1 mrg
648 1.1 mrg movw hl, sp
649 1.1 mrg movw ax, [hl+14] ; denH
650 1.1 mrg cmpw ax, [hl+10] ; numH
651 1.1 mrg movw ax, [hl+12] ; denL
652 1.1 mrg sknz
653 1.1 mrg cmpw ax, [hl+8] ; numL
654 1.1 mrg bh $num_lt_den\which
655 1.1 mrg
656 1.1 mrg #ifdef __RL78_G10__
657 1.1 mrg movw ax, denL
658 1.1 mrg push ax
659 1.1 mrg movw ax, bitL
660 1.1 mrg push ax
661 1.1 mrg movw ax, bitH
662 1.1 mrg push ax
663 1.1 mrg #else
664 1.1 mrg sel rb2
665 1.1 mrg push ax ; denL
666 1.1 mrg ; push bc ; denH
667 1.1 mrg push de ; bitL
668 1.1 mrg push hl ; bitH - stored in BC
669 1.1 mrg sel rb0
670 1.1 mrg #endif
671 1.1 mrg
672 1.1 mrg ;; (quot,rem) = 16[sp] /% 20[sp]
673 1.1 mrg
674 1.1 mrg ;; copy numerator
675 1.1 mrg movw ax, [hl+8]
676 1.1 mrg movw numL, ax
677 1.1 mrg movw ax, [hl+10]
678 1.1 mrg movw numH, ax
679 1.1 mrg
680 1.1 mrg ;; copy denomonator
681 1.1 mrg movw ax, [hl+12]
682 1.1 mrg movw denL, ax
683 1.1 mrg movw ax, [hl+14]
684 1.1 mrg movw denH, ax
685 1.1 mrg
686 1.1 mrg movw ax, denL
687 1.1 mrg or a, denB2
688 1.1 mrg or a, denB3 ; not x
689 1.1 mrg cmpw ax, #0
690 1.1 mrg bnz $den_not_zero\which
691 1.3 mrg .if \need_result
692 1.3 mrg movw quotL, #0
693 1.3 mrg movw quotH, #0
694 1.3 mrg .else
695 1.1 mrg movw numL, #0
696 1.1 mrg movw numH, #0
697 1.3 mrg .endif
698 1.3 mrg br $!main_loop_done_himode\which
699 1.1 mrg
700 1.1 mrg den_not_zero\which:
701 1.1 mrg .if \need_result
702 1.1 mrg ;; zero out quot
703 1.1 mrg movw quotL, #0
704 1.1 mrg movw quotH, #0
705 1.1 mrg .endif
706 1.1 mrg
707 1.1 mrg ;; initialize bit to 1
708 1.1 mrg movw bitL, #1
709 1.1 mrg movw bitH, #0
710 1.1 mrg
711 1.1 mrg ; while (den < num && !(den & (1L << BITS_MINUS_1)))
712 1.1 mrg
713 1.1 mrg .if 1
714 1.1 mrg ;; see if we can short-circuit a bunch of shifts
715 1.1 mrg movw ax, denH
716 1.1 mrg cmpw ax, #0
717 1.1 mrg bnz $shift_den_bit\which
718 1.1 mrg movw ax, denL
719 1.1 mrg cmpw ax, numH
720 1.1 mrg bnh $shift_den_bit16\which
721 1.1 mrg .endif
722 1.1 mrg
723 1.1 mrg shift_den_bit\which:
724 1.1 mrg movw ax, denH
725 1.1 mrg mov1 cy,a.7
726 1.1 mrg bc $enter_main_loop\which
727 1.1 mrg cmpw ax, numH
728 1.1 mrg movw ax, denL ; we re-use this below
729 1.1 mrg sknz
730 1.1 mrg cmpw ax, numL
731 1.1 mrg bh $enter_main_loop\which
732 1.1 mrg
733 1.1 mrg ;; den <<= 1
734 1.1 mrg ; movw ax, denL ; already has it from the cmpw above
735 1.1 mrg shlw ax, 1
736 1.1 mrg movw denL, ax
737 1.1 mrg ; movw ax, denH
738 1.1 mrg rolwc denH, 1
739 1.1 mrg ; movw denH, ax
740 1.1 mrg
741 1.1 mrg ;; bit <<= 1
742 1.1 mrg .if \need_result
743 1.1 mrg movw ax, bitL
744 1.1 mrg shlw ax, 1
745 1.1 mrg movw bitL, ax
746 1.1 mrg movw ax, bitH
747 1.1 mrg rolwc ax, 1
748 1.1 mrg movw bitH, ax
749 1.1 mrg .else
750 1.1 mrg ;; if we don't need to compute the quotent, we don't need an
751 1.1 mrg ;; actual bit *mask*, we just need to keep track of which bit
752 1.1 mrg inc bitB0
753 1.1 mrg .endif
754 1.1 mrg
755 1.1 mrg br $shift_den_bit\which
756 1.1 mrg
757 1.1 mrg ;; while (bit)
758 1.1 mrg main_loop\which:
759 1.1 mrg
760 1.1 mrg ;; if (num >= den) (cmp den > num)
761 1.1 mrg movw ax, numH
762 1.1 mrg cmpw ax, denH
763 1.1 mrg movw ax, numL
764 1.1 mrg sknz
765 1.1 mrg cmpw ax, denL
766 1.1 mrg skz
767 1.1 mrg bnh $next_loop\which
768 1.1 mrg
769 1.1 mrg ;; num -= den
770 1.1 mrg ; movw ax, numL ; already has it from the cmpw above
771 1.1 mrg subw ax, denL
772 1.1 mrg movw numL, ax
773 1.1 mrg movw ax, numH
774 1.1 mrg sknc
775 1.1 mrg decw ax
776 1.1 mrg subw ax, denH
777 1.1 mrg movw numH, ax
778 1.1 mrg
779 1.1 mrg .if \need_result
780 1.1 mrg ;; res |= bit
781 1.1 mrg mov a, quotB0
782 1.1 mrg or a, bitB0
783 1.1 mrg mov quotB0, a
784 1.1 mrg mov a, quotB1
785 1.1 mrg or a, bitB1
786 1.1 mrg mov quotB1, a
787 1.1 mrg mov a, quotB2
788 1.1 mrg or a, bitB2
789 1.1 mrg mov quotB2, a
790 1.1 mrg mov a, quotB3
791 1.1 mrg or a, bitB3
792 1.1 mrg mov quotB3, a
793 1.1 mrg .endif
794 1.1 mrg
795 1.1 mrg next_loop\which:
796 1.1 mrg
797 1.1 mrg ;; den >>= 1
798 1.1 mrg movw ax, denH
799 1.1 mrg shrw ax, 1
800 1.1 mrg movw denH, ax
801 1.1 mrg mov a, denB1
802 1.1 mrg rorc a, 1
803 1.1 mrg mov denB1, a
804 1.1 mrg mov a, denB0
805 1.1 mrg rorc a, 1
806 1.1 mrg mov denB0, a
807 1.1 mrg
808 1.1 mrg ;; bit >>= 1
809 1.1 mrg .if \need_result
810 1.1 mrg movw ax, bitH
811 1.1 mrg shrw ax, 1
812 1.1 mrg movw bitH, ax
813 1.1 mrg mov a, bitB1
814 1.1 mrg rorc a, 1
815 1.1 mrg mov bitB1, a
816 1.1 mrg mov a, bitB0
817 1.1 mrg rorc a, 1
818 1.1 mrg mov bitB0, a
819 1.1 mrg .else
820 1.1 mrg dec bitB0
821 1.1 mrg .endif
822 1.1 mrg
823 1.1 mrg enter_main_loop\which:
824 1.1 mrg .if \need_result
825 1.1 mrg movw ax, bitH
826 1.1 mrg cmpw ax, #0
827 1.1 mrg bnz $main_loop\which
828 1.1 mrg .else
829 1.1 mrg cmp bitB0, #15
830 1.1 mrg bh $main_loop\which
831 1.1 mrg .endif
832 1.1 mrg ;; bit is HImode now; check others
833 1.1 mrg movw ax, numH ; numerator
834 1.1 mrg cmpw ax, #0
835 1.1 mrg bnz $bit_high_set\which
836 1.1 mrg movw ax, denH ; denominator
837 1.1 mrg cmpw ax, #0
838 1.1 mrg bz $switch_to_himode\which
839 1.1 mrg bit_high_set\which:
840 1.1 mrg .if \need_result
841 1.1 mrg movw ax, bitL
842 1.1 mrg cmpw ax, #0
843 1.1 mrg .else
844 1.1 mrg cmp0 bitB0
845 1.1 mrg .endif
846 1.1 mrg bnz $main_loop\which
847 1.1 mrg
848 1.1 mrg switch_to_himode\which:
849 1.1 mrg .if \need_result
850 1.1 mrg movw ax, bitL
851 1.1 mrg cmpw ax, #0
852 1.1 mrg .else
853 1.1 mrg cmp0 bitB0
854 1.1 mrg .endif
855 1.1 mrg bz $main_loop_done_himode\which
856 1.1 mrg
857 1.1 mrg ;; From here on in, r22, r14, and r18 are all zero
858 1.1 mrg ;; while (bit)
859 1.1 mrg main_loop_himode\which:
860 1.1 mrg
861 1.1 mrg ;; if (num >= den) (cmp den > num)
862 1.1 mrg movw ax, denL
863 1.1 mrg cmpw ax, numL
864 1.1 mrg bh $next_loop_himode\which
865 1.1 mrg
866 1.1 mrg ;; num -= den
867 1.1 mrg movw ax, numL
868 1.1 mrg subw ax, denL
869 1.1 mrg movw numL, ax
870 1.1 mrg movw ax, numH
871 1.1 mrg sknc
872 1.1 mrg decw ax
873 1.1 mrg subw ax, denH
874 1.1 mrg movw numH, ax
875 1.1 mrg
876 1.1 mrg .if \need_result
877 1.1 mrg ;; res |= bit
878 1.1 mrg mov a, quotB0
879 1.1 mrg or a, bitB0
880 1.1 mrg mov quotB0, a
881 1.1 mrg mov a, quotB1
882 1.1 mrg or a, bitB1
883 1.1 mrg mov quotB1, a
884 1.1 mrg .endif
885 1.1 mrg
886 1.1 mrg next_loop_himode\which:
887 1.1 mrg
888 1.1 mrg ;; den >>= 1
889 1.1 mrg movw ax, denL
890 1.1 mrg shrw ax, 1
891 1.1 mrg movw denL, ax
892 1.1 mrg
893 1.1 mrg .if \need_result
894 1.1 mrg ;; bit >>= 1
895 1.1 mrg movw ax, bitL
896 1.1 mrg shrw ax, 1
897 1.1 mrg movw bitL, ax
898 1.1 mrg .else
899 1.1 mrg dec bitB0
900 1.1 mrg .endif
901 1.1 mrg
902 1.1 mrg .if \need_result
903 1.1 mrg movw ax, bitL
904 1.1 mrg cmpw ax, #0
905 1.1 mrg .else
906 1.1 mrg cmp0 bitB0
907 1.1 mrg .endif
908 1.1 mrg bnz $main_loop_himode\which
909 1.1 mrg
910 1.1 mrg main_loop_done_himode\which:
911 1.1 mrg #ifdef __RL78_G10__
912 1.1 mrg pop ax
913 1.1 mrg movw bitH, ax
914 1.1 mrg pop ax
915 1.1 mrg movw bitL, ax
916 1.1 mrg pop ax
917 1.1 mrg movw denL, ax
918 1.1 mrg #else
919 1.1 mrg sel rb2
920 1.1 mrg pop hl ; bitH - stored in BC
921 1.1 mrg pop de ; bitL
922 1.1 mrg ; pop bc ; denH
923 1.1 mrg pop ax ; denL
924 1.1 mrg sel rb0
925 1.1 mrg #endif
926 1.1 mrg
927 1.1 mrg ret
928 1.1 mrg END_FUNC __generic_sidivmod\which
929 1.1 mrg .endm
930 1.1 mrg
931 1.1 mrg ;----------------------------------------------------------------------
932 1.1 mrg
933 1.1 mrg MAKE_GENERIC _d 1
934 1.1 mrg MAKE_GENERIC _m 0
935 1.1 mrg
936 1.1 mrg ;----------------------------------------------------------------------
937 1.1 mrg
938 1.1 mrg START_FUNC ___udivsi3
939 1.1 mrg ;; r8 = 4[sp] / 8[sp]
940 1.1 mrg call $!__generic_sidiv
941 1.1 mrg ret
942 1.1 mrg END_FUNC ___udivsi3
943 1.1 mrg
944 1.1 mrg
945 1.1 mrg START_FUNC ___umodsi3
946 1.1 mrg ;; r8 = 4[sp] % 8[sp]
947 1.1 mrg call $!__generic_simod
948 1.1 mrg ret
949 1.1 mrg END_FUNC ___umodsi3
950 1.1 mrg
951 1.1 mrg ;----------------------------------------------------------------------
952 1.1 mrg
953 1.1 mrg .macro NEG_AX
954 1.1 mrg movw hl, ax
955 1.1 mrg movw ax, #0
956 1.1 mrg subw ax, [hl]
957 1.1 mrg movw [hl], ax
958 1.1 mrg movw ax, #0
959 1.1 mrg sknc
960 1.1 mrg decw ax
961 1.1 mrg subw ax, [hl+2]
962 1.1 mrg movw [hl+2], ax
963 1.1 mrg .endm
964 1.1 mrg
965 1.1 mrg ;----------------------------------------------------------------------
966 1.1 mrg
967 1.1 mrg START_FUNC ___divsi3
968 1.1 mrg ;; r8 = 4[sp] / 8[sp]
969 1.1 mrg movw de, #0
970 1.1 mrg mov a, [sp+7]
971 1.1 mrg mov1 cy, a.7
972 1.1 mrg bc $div_signed_num
973 1.1 mrg mov a, [sp+11]
974 1.1 mrg mov1 cy, a.7
975 1.1 mrg bc $div_signed_den
976 1.1 mrg call $!__generic_sidiv
977 1.1 mrg ret
978 1.1 mrg
979 1.1 mrg div_signed_num:
980 1.1 mrg ;; neg [sp+4]
981 1.1 mrg movw ax, sp
982 1.1 mrg addw ax, #4
983 1.1 mrg NEG_AX
984 1.1 mrg mov d, #1
985 1.1 mrg mov a, [sp+11]
986 1.1 mrg mov1 cy, a.7
987 1.1 mrg bnc $div_unsigned_den
988 1.1 mrg div_signed_den:
989 1.1 mrg ;; neg [sp+8]
990 1.1 mrg movw ax, sp
991 1.1 mrg addw ax, #8
992 1.1 mrg NEG_AX
993 1.1 mrg mov e, #1
994 1.1 mrg div_unsigned_den:
995 1.1 mrg call $!__generic_sidiv
996 1.1 mrg
997 1.1 mrg mov a, d
998 1.1 mrg cmp0 a
999 1.1 mrg bz $div_skip_restore_num
1000 1.1 mrg ;; We have to restore the numerator [sp+4]
1001 1.1 mrg movw ax, sp
1002 1.1 mrg addw ax, #4
1003 1.1 mrg NEG_AX
1004 1.1 mrg mov a, d
1005 1.1 mrg div_skip_restore_num:
1006 1.1 mrg xor a, e
1007 1.1 mrg bz $div_no_neg
1008 1.1 mrg movw ax, #r8
1009 1.1 mrg NEG_AX
1010 1.1 mrg div_no_neg:
1011 1.1 mrg mov a, e
1012 1.1 mrg cmp0 a
1013 1.1 mrg bz $div_skip_restore_den
1014 1.1 mrg ;; We have to restore the denominator [sp+8]
1015 1.1 mrg movw ax, sp
1016 1.1 mrg addw ax, #8
1017 1.1 mrg NEG_AX
1018 1.1 mrg div_skip_restore_den:
1019 1.1 mrg ret
1020 1.1 mrg END_FUNC ___divsi3
1021 1.1 mrg
1022 1.1 mrg
1023 1.1 mrg START_FUNC ___modsi3
1024 1.1 mrg ;; r8 = 4[sp] % 8[sp]
1025 1.1 mrg movw de, #0
1026 1.1 mrg mov a, [sp+7]
1027 1.1 mrg mov1 cy, a.7
1028 1.1 mrg bc $mod_signed_num
1029 1.1 mrg mov a, [sp+11]
1030 1.1 mrg mov1 cy, a.7
1031 1.1 mrg bc $mod_signed_den
1032 1.1 mrg call $!__generic_simod
1033 1.1 mrg ret
1034 1.1 mrg
1035 1.1 mrg mod_signed_num:
1036 1.1 mrg ;; neg [sp+4]
1037 1.1 mrg movw ax, sp
1038 1.1 mrg addw ax, #4
1039 1.1 mrg NEG_AX
1040 1.1 mrg mov d, #1
1041 1.1 mrg mov a, [sp+11]
1042 1.1 mrg mov1 cy, a.7
1043 1.1 mrg bnc $mod_unsigned_den
1044 1.1 mrg mod_signed_den:
1045 1.1 mrg ;; neg [sp+8]
1046 1.1 mrg movw ax, sp
1047 1.1 mrg addw ax, #8
1048 1.1 mrg NEG_AX
1049 1.1 mrg mov e, #1
1050 1.1 mrg mod_unsigned_den:
1051 1.1 mrg call $!__generic_simod
1052 1.1 mrg
1053 1.1 mrg mov a, d
1054 1.1 mrg cmp0 a
1055 1.1 mrg bz $mod_no_neg
1056 1.1 mrg movw ax, #r8
1057 1.1 mrg NEG_AX
1058 1.1 mrg ;; We have to restore [sp+4] as well.
1059 1.1 mrg movw ax, sp
1060 1.1 mrg addw ax, #4
1061 1.1 mrg NEG_AX
1062 1.1 mrg mod_no_neg:
1063 1.1 mrg .if 1
1064 1.1 mrg mov a, e
1065 1.1 mrg cmp0 a
1066 1.1 mrg bz $mod_skip_restore_den
1067 1.1 mrg movw ax, sp
1068 1.1 mrg addw ax, #8
1069 1.1 mrg NEG_AX
1070 1.1 mrg mod_skip_restore_den:
1071 1.1 mrg .endif
1072 1.1 mrg ret
1073 1.1 mrg END_FUNC ___modsi3
1074 1.3 mrg
1075 1.3 mrg ;----------------------------------------------------------------------
1076 1.3 mrg
1077 1.3 mrg #else
1078 1.3 mrg
1079 1.3 mrg #error "Unknown RL78 hardware multiply/divide support"
1080 1.3 mrg
1081 1.3 mrg #endif
1082