]>
Commit | Line | Data |
---|---|---|
ceb2fc49 | 1 | /* HImode div/mod functions for the GCC support library for the Renesas RL78 processors. |
99dee823 | 2 | Copyright (C) 2012-2021 Free Software Foundation, Inc. |
ceb2fc49 DD |
3 | Contributed by Red Hat. |
4 | ||
5 | This file is part of GCC. | |
6 | ||
7 | GCC is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 3, or (at your option) | |
10 | any later version. | |
11 | ||
12 | GCC is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | Under Section 7 of GPL version 3, you are granted additional | |
18 | permissions described in the GCC Runtime Library Exception, version | |
19 | 3.1, as published by the Free Software Foundation. | |
20 | ||
21 | You should have received a copy of the GNU General Public License and | |
22 | a copy of the GCC Runtime Library Exception along with this program; | |
23 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
24 | <http://www.gnu.org/licenses/>. */ | |
25 | ||
ceb2fc49 DD |
26 | #include "vregs.h" |
27 | ||
72ed1126 NC |
28 | #if defined __RL78_MUL_G14__ |
29 | ||
30 | START_FUNC ___divhi3 | |
31 | ;; r8 = 4[sp] / 6[sp] | |
32 | ||
33 | ;; Test for a negative denumerator. | |
34 | movw ax, [sp+6] | |
35 | mov1 cy, a.7 | |
36 | movw de, ax | |
37 | bc $__div_neg_den | |
38 | ||
39 | ;; Test for a negative numerator. | |
40 | movw ax, [sp+4] | |
41 | mov1 cy, a.7 | |
42 | bc $__div_neg_num | |
43 | ||
44 | ;; Neither are negative - we can use the unsigned divide instruction. | |
45 | __div_no_convert: | |
46 | push psw | |
47 | di | |
48 | divhu | |
49 | pop psw | |
50 | ||
51 | movw r8, ax | |
52 | ret | |
53 | ||
54 | __div_neg_den: | |
55 | ;; Negate the denumerator (which is in DE) | |
56 | clrw ax | |
57 | subw ax, de | |
58 | movw de, ax | |
59 | ||
60 | ;; Test for a negative numerator. | |
61 | movw ax, [sp+4] | |
62 | mov1 cy, a.7 | |
63 | ;; If it is not negative then we perform the division and then negate the result. | |
64 | bnc $__div_then_convert | |
65 | ||
66 | ;; Otherwise we negate the numerator and then go with an unsigned division. | |
67 | movw bc, ax | |
68 | clrw ax | |
69 | subw ax, bc | |
70 | br $__div_no_convert | |
71 | ||
72 | __div_neg_num: | |
73 | ;; Negate the numerator (which is in AX) | |
74 | ;; We know that the denumerator is positive. | |
75 | movw bc, ax | |
76 | clrw ax | |
77 | subw ax, bc | |
78 | ||
79 | __div_then_convert: | |
80 | push psw | |
81 | di | |
82 | divhu | |
83 | pop psw | |
84 | ||
85 | ;; Negate result and transfer into r8 | |
86 | movw bc, ax | |
87 | clrw ax | |
88 | subw ax, bc | |
89 | movw r8, ax | |
90 | ret | |
91 | ||
92 | END_FUNC ___divhi3 | |
93 | ||
94 | ;---------------------------------------------------------------------- | |
95 | ||
96 | START_FUNC ___modhi3 | |
97 | ;; r8 = 4[sp] % 6[sp] | |
98 | ||
99 | ;; Test for a negative denumerator. | |
100 | movw ax, [sp+6] | |
101 | mov1 cy, a.7 | |
102 | movw de, ax | |
103 | bc $__mod_neg_den | |
104 | ||
105 | ;; Test for a negative numerator. | |
106 | movw ax, [sp+4] | |
107 | mov1 cy, a.7 | |
108 | bc $__mod_neg_num | |
109 | ||
110 | ;; Neither are negative - we can use the unsigned divide instruction. | |
111 | __mod_no_convert: | |
112 | push psw | |
113 | di | |
114 | divhu | |
115 | pop psw | |
116 | ||
117 | movw ax, de | |
118 | movw r8, ax | |
119 | ret | |
120 | ||
121 | __mod_neg_den: | |
122 | ;; Negate the denumerator (which is in DE) | |
123 | clrw ax | |
124 | subw ax, de | |
125 | movw de, ax | |
126 | ||
127 | ;; Test for a negative numerator. | |
128 | movw ax, [sp+4] | |
129 | mov1 cy, a.7 | |
130 | ;; If it is not negative then we perform the modulo operation without conversion. | |
131 | bnc $__mod_no_convert | |
132 | ||
133 | ;; Otherwise we negate the numerator and then go with an unsigned modulo operation. | |
134 | movw bc, ax | |
135 | clrw ax | |
136 | subw ax, bc | |
137 | br $__mod_then_convert | |
138 | ||
139 | __mod_neg_num: | |
140 | ;; Negate the numerator (which is in AX) | |
141 | ;; We know that the denumerator is positive. | |
142 | movw bc, ax | |
143 | clrw ax | |
144 | subw ax, bc | |
145 | ||
146 | __mod_then_convert: | |
147 | push psw | |
148 | di | |
149 | divhu | |
150 | pop psw | |
151 | ||
152 | ;; Negate result and transfer into r8 | |
153 | clrw ax | |
154 | subw ax, de | |
155 | movw r8, ax | |
156 | ret | |
157 | ||
158 | END_FUNC ___modhi3 | |
159 | ||
160 | ;---------------------------------------------------------------------- | |
161 | ||
162 | #elif defined __RL78_MUL_G13__ | |
163 | ||
164 | ;; The G13 S2 core does not have a 16 bit divide peripheral. | |
165 | ;; So instead we perform a 32-bit divide and twiddle the inputs | |
166 | ;; as necessary. | |
167 | ||
168 | ;; Hardware registers. Note - these values match the silicon, not the documentation. | |
169 | MDAL = 0xffff0 | |
170 | MDAH = 0xffff2 | |
171 | MDBL = 0xffff6 | |
172 | MDBH = 0xffff4 | |
173 | MDCL = 0xf00e0 | |
174 | MDCH = 0xf00e2 | |
175 | MDUC = 0xf00e8 | |
176 | ||
177 | .macro _Negate src, dest | |
178 | movw ax, !\src | |
179 | movw bc, ax | |
180 | clrw ax | |
181 | subw ax, bc | |
182 | movw \dest, ax | |
183 | .endm | |
184 | ||
185 | ;---------------------------------------------------------------------- | |
186 | ||
187 | START_FUNC ___divhi3 | |
188 | ;; r8 = 4[sp] / 6[sp] (signed division) | |
189 | ||
190 | mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 | |
191 | mov !MDUC, a ; This preps the peripheral for division without interrupt generation | |
192 | ||
193 | clrw ax ; Clear the top 16-bits of the divisor and dividend | |
194 | movw MDBH, ax | |
195 | movw MDAH, ax | |
196 | ||
197 | ;; Load and test for a negative denumerator. | |
198 | movw ax, [sp+6] | |
199 | movw MDBL, ax | |
200 | mov1 cy, a.7 | |
201 | bc $__div_neg_den | |
202 | ||
203 | ;; Load and test for a negative numerator. | |
204 | movw ax, [sp+4] | |
205 | mov1 cy, a.7 | |
206 | movw MDAL, ax | |
207 | bc $__div_neg_num | |
208 | ||
209 | ;; Neither are negative - we can use the unsigned divide hardware. | |
210 | __div_no_convert: | |
211 | mov a, #0xC1 ; Set the DIVST bit in MDUC | |
212 | mov !MDUC, a ; This starts the division op | |
213 | ||
214 | 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear | |
215 | bt a.0, $1b | |
216 | ||
217 | movw ax, MDAL ; Read the result | |
218 | movw r8, ax | |
219 | ret | |
220 | ||
221 | __div_neg_den: | |
222 | ;; Negate the denumerator (which is in MDBL) | |
223 | _Negate MDBL MDBL | |
224 | ||
225 | ;; Load and test for a negative numerator. | |
226 | movw ax, [sp+4] | |
227 | mov1 cy, a.7 | |
228 | movw MDAL, ax | |
229 | ;; If it is not negative then we perform the division and then negate the result. | |
230 | bnc $__div_then_convert | |
231 | ||
232 | ;; Otherwise we negate the numerator and then go with a straightforward unsigned division. | |
233 | _Negate MDAL MDAL | |
234 | br $!__div_no_convert | |
235 | ||
236 | __div_neg_num: | |
237 | ;; Negate the numerator (which is in MDAL) | |
238 | ;; We know that the denumerator is positive. | |
239 | _Negate MDAL MDAL | |
240 | ||
241 | __div_then_convert: | |
242 | mov a, #0xC1 ; Set the DIVST bit in MDUC | |
243 | mov !MDUC, a ; This starts the division op | |
244 | ||
245 | 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear | |
246 | bt a.0, $1b | |
247 | ||
248 | ;; Negate result and transfer into r8 | |
249 | _Negate MDAL r8 | |
250 | ret | |
251 | ||
252 | END_FUNC ___divhi3 | |
253 | ||
254 | ;---------------------------------------------------------------------- | |
255 | ||
256 | START_FUNC ___modhi3 | |
257 | ;; r8 = 4[sp] % 6[sp] (signed modulus) | |
258 | ||
259 | mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 | |
260 | mov !MDUC, a ; This preps the peripheral for division without interrupt generation | |
261 | ||
262 | clrw ax ; Clear the top 16-bits of the divisor and dividend | |
263 | movw MDBH, ax | |
264 | movw MDAH, ax | |
265 | ||
266 | ;; Load and test for a negative denumerator. | |
267 | movw ax, [sp+6] | |
268 | movw MDBL, ax | |
269 | mov1 cy, a.7 | |
270 | bc $__mod_neg_den | |
271 | ||
272 | ;; Load and test for a negative numerator. | |
273 | movw ax, [sp+4] | |
274 | mov1 cy, a.7 | |
275 | movw MDAL, ax | |
276 | bc $__mod_neg_num | |
277 | ||
278 | ;; Neither are negative - we can use the unsigned divide hardware | |
279 | __mod_no_convert: | |
280 | mov a, #0xC1 ; Set the DIVST bit in MDUC | |
281 | mov !MDUC, a ; This starts the division op | |
282 | ||
283 | 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear | |
284 | bt a.0, $1b | |
285 | ||
286 | movw ax, !MDCL ; Read the remainder | |
287 | movw r8, ax | |
288 | ret | |
289 | ||
290 | __mod_neg_den: | |
291 | ;; Negate the denumerator (which is in MDBL) | |
292 | _Negate MDBL MDBL | |
293 | ||
294 | ;; Load and test for a negative numerator. | |
295 | movw ax, [sp+4] | |
296 | mov1 cy, a.7 | |
297 | movw MDAL, ax | |
298 | ;; If it is not negative then we perform the modulo operation without conversion. | |
299 | bnc $__mod_no_convert | |
300 | ||
301 | ;; Otherwise we negate the numerator and then go with a modulo followed by negation. | |
302 | _Negate MDAL MDAL | |
303 | br $!__mod_then_convert | |
304 | ||
305 | __mod_neg_num: | |
306 | ;; Negate the numerator (which is in MDAL) | |
307 | ;; We know that the denumerator is positive. | |
308 | _Negate MDAL MDAL | |
309 | ||
310 | __mod_then_convert: | |
311 | mov a, #0xC1 ; Set the DIVST bit in MDUC | |
312 | mov !MDUC, a ; This starts the division op | |
313 | ||
314 | 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear | |
315 | bt a.0, $1b | |
316 | ||
317 | _Negate MDCL r8 | |
318 | ret | |
319 | ||
320 | END_FUNC ___modhi3 | |
321 | ||
322 | ;---------------------------------------------------------------------- | |
323 | ||
324 | START_FUNC ___udivhi3 | |
325 | ;; r8 = 4[sp] / 6[sp] (unsigned division) | |
326 | ||
327 | mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 | |
328 | mov !MDUC, a ; This preps the peripheral for division without interrupt generation | |
329 | ||
330 | movw ax, [sp+4] ; Load the divisor | |
331 | movw MDAL, ax | |
332 | movw ax, [sp+6] ; Load the dividend | |
333 | movw MDBL, ax | |
334 | clrw ax | |
335 | movw MDAH, ax | |
336 | movw MDBH, ax | |
337 | ||
338 | mov a, #0xC1 ; Set the DIVST bit in MDUC | |
339 | mov !MDUC, a ; This starts the division op | |
340 | ||
341 | 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear | |
342 | bt a.0, $1b | |
343 | ||
344 | movw ax, !MDAL ; Read the remainder | |
345 | movw r8, ax | |
346 | ret | |
347 | ||
348 | END_FUNC ___udivhi3 | |
349 | ||
350 | ;---------------------------------------------------------------------- | |
351 | ||
352 | START_FUNC ___umodhi3 | |
353 | ;; r8 = 4[sp] % 6[sp] (unsigned modulus) | |
354 | ||
355 | mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 | |
356 | mov !MDUC, a ; This preps the peripheral for division without interrupt generation | |
357 | ||
358 | movw ax, [sp+4] ; Load the divisor | |
359 | movw MDAL, ax | |
360 | movw ax, [sp+6] ; Load the dividend | |
361 | movw MDBL, ax | |
362 | clrw ax | |
363 | movw MDAH, ax | |
364 | movw MDBH, ax | |
365 | ||
366 | mov a, #0xC1 ; Set the DIVST bit in MDUC | |
367 | mov !MDUC, a ; This starts the division op | |
368 | ||
369 | 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear | |
370 | bt a.0, $1b | |
371 | ||
372 | movw ax, !MDCL ; Read the remainder | |
373 | movw r8, ax | |
374 | ret | |
375 | ||
376 | END_FUNC ___umodhi3 | |
377 | ||
378 | ;---------------------------------------------------------------------- | |
379 | ||
380 | #elif defined __RL78_MUL_NONE__ | |
381 | ||
52a1ff8b | 382 | .macro MAKE_GENERIC which,need_result |
ceb2fc49 DD |
383 | |
384 | .if \need_result | |
385 | quot = r8 | |
386 | num = r10 | |
387 | den = r12 | |
388 | bit = r14 | |
389 | .else | |
390 | num = r8 | |
391 | quot = r10 | |
392 | den = r12 | |
393 | bit = r14 | |
394 | .endif | |
395 | ||
396 | quotB0 = quot | |
397 | quotB1 = quot+1 | |
398 | ||
399 | numB0 = num | |
400 | numB1 = num+1 | |
401 | ||
402 | denB0 = den | |
403 | denB1 = den+1 | |
404 | ||
405 | bitB0 = bit | |
406 | bitB1 = bit+1 | |
407 | ||
ceb2fc49 DD |
408 | #define bit bc |
409 | #define bitB0 c | |
410 | #define bitB1 b | |
52a1ff8b NC |
411 | |
412 | START_FUNC __generic_hidivmod\which | |
ceb2fc49 DD |
413 | |
414 | num_lt_den\which: | |
415 | .if \need_result | |
416 | movw r8, #0 | |
417 | .else | |
418 | movw ax, [sp+8] | |
419 | movw r8, ax | |
420 | .endif | |
421 | ret | |
422 | ||
423 | ;; These routines leave DE alone - the signed functions use DE | |
424 | ;; to store sign information that must remain intact | |
425 | ||
426 | .if \need_result | |
52a1ff8b NC |
427 | .global __generic_hidiv |
428 | __generic_hidiv: | |
ceb2fc49 DD |
429 | |
430 | .else | |
431 | ||
52a1ff8b NC |
432 | .global __generic_himod |
433 | __generic_himod: | |
ceb2fc49 DD |
434 | |
435 | .endif | |
436 | ||
437 | ;; (quot,rem) = 8[sp] /% 10[sp] | |
438 | ||
439 | movw hl, sp | |
440 | movw ax, [hl+10] ; denH | |
441 | cmpw ax, [hl+8] ; numH | |
442 | bh $num_lt_den\which | |
443 | ||
444 | ;; (quot,rem) = 16[sp] /% 20[sp] | |
445 | ||
446 | ;; copy numerator | |
447 | movw ax, [hl+8] | |
448 | movw num, ax | |
449 | ||
450 | ;; copy denomonator | |
451 | movw ax, [hl+10] | |
452 | movw den, ax | |
453 | ||
454 | movw ax, den | |
455 | cmpw ax, #0 | |
456 | bnz $den_not_zero\which | |
793aa938 KP |
457 | .if \need_result |
458 | movw quot, #0 | |
459 | .else | |
ceb2fc49 | 460 | movw num, #0 |
793aa938 | 461 | .endif |
ceb2fc49 DD |
462 | ret |
463 | ||
464 | den_not_zero\which: | |
465 | .if \need_result | |
466 | ;; zero out quot | |
467 | movw quot, #0 | |
468 | .endif | |
469 | ||
470 | ;; initialize bit to 1 | |
471 | movw bit, #1 | |
472 | ||
473 | ; while (den < num && !(den & (1L << BITS_MINUS_1))) | |
474 | ||
475 | shift_den_bit\which: | |
476 | movw ax, den | |
477 | mov1 cy,a.7 | |
478 | bc $enter_main_loop\which | |
479 | cmpw ax, num | |
480 | bh $enter_main_loop\which | |
481 | ||
482 | ;; den <<= 1 | |
483 | ; movw ax, den ; already has it from the cmpw above | |
484 | shlw ax, 1 | |
485 | movw den, ax | |
486 | ||
487 | ;; bit <<= 1 | |
488 | .if \need_result | |
489 | #ifdef bit | |
490 | shlw bit, 1 | |
491 | #else | |
492 | movw ax, bit | |
493 | shlw ax, 1 | |
494 | movw bit, ax | |
495 | #endif | |
496 | .else | |
497 | ;; if we don't need to compute the quotent, we don't need an | |
498 | ;; actual bit *mask*, we just need to keep track of which bit | |
499 | inc bitB0 | |
500 | .endif | |
501 | ||
502 | br $shift_den_bit\which | |
503 | ||
504 | main_loop\which: | |
505 | ||
506 | ;; if (num >= den) (cmp den > num) | |
507 | movw ax, den | |
508 | cmpw ax, num | |
509 | bh $next_loop\which | |
510 | ||
511 | ;; num -= den | |
512 | movw ax, num | |
513 | subw ax, den | |
514 | movw num, ax | |
515 | ||
516 | .if \need_result | |
517 | ;; res |= bit | |
518 | mov a, quotB0 | |
519 | or a, bitB0 | |
520 | mov quotB0, a | |
521 | mov a, quotB1 | |
522 | or a, bitB1 | |
523 | mov quotB1, a | |
524 | .endif | |
525 | ||
526 | next_loop\which: | |
527 | ||
528 | ;; den >>= 1 | |
529 | movw ax, den | |
530 | shrw ax, 1 | |
531 | movw den, ax | |
532 | ||
533 | .if \need_result | |
534 | ;; bit >>= 1 | |
535 | movw ax, bit | |
536 | shrw ax, 1 | |
537 | movw bit, ax | |
538 | .else | |
539 | dec bitB0 | |
540 | .endif | |
541 | ||
542 | enter_main_loop\which: | |
543 | .if \need_result | |
544 | movw ax, bit | |
545 | cmpw ax, #0 | |
546 | .else | |
547 | cmp0 bitB0 | |
548 | .endif | |
549 | bnz $main_loop\which | |
550 | ||
551 | main_loop_done\which: | |
552 | ret | |
52a1ff8b NC |
553 | END_FUNC __generic_hidivmod\which |
554 | .endm | |
555 | ;---------------------------------------------------------------------- | |
ceb2fc49 | 556 | |
52a1ff8b NC |
557 | MAKE_GENERIC _d 1 |
558 | MAKE_GENERIC _m 0 | |
ceb2fc49 DD |
559 | |
560 | ;---------------------------------------------------------------------- | |
561 | ||
52a1ff8b | 562 | START_FUNC ___udivhi3 |
ceb2fc49 | 563 | ;; r8 = 4[sp] / 6[sp] |
52a1ff8b | 564 | call $!__generic_hidiv |
ceb2fc49 | 565 | ret |
52a1ff8b | 566 | END_FUNC ___udivhi3 |
ceb2fc49 DD |
567 | |
568 | ||
52a1ff8b | 569 | START_FUNC ___umodhi3 |
ceb2fc49 | 570 | ;; r8 = 4[sp] % 6[sp] |
52a1ff8b | 571 | call $!__generic_himod |
ceb2fc49 | 572 | ret |
52a1ff8b | 573 | END_FUNC ___umodhi3 |
ceb2fc49 DD |
574 | |
575 | ;---------------------------------------------------------------------- | |
576 | ||
52a1ff8b | 577 | .macro NEG_AX |
ceb2fc49 DD |
578 | movw hl, ax |
579 | movw ax, #0 | |
580 | subw ax, [hl] | |
581 | movw [hl], ax | |
52a1ff8b | 582 | .endm |
ceb2fc49 | 583 | |
52a1ff8b NC |
584 | ;---------------------------------------------------------------------- |
585 | ||
586 | START_FUNC ___divhi3 | |
ceb2fc49 DD |
587 | ;; r8 = 4[sp] / 6[sp] |
588 | movw de, #0 | |
589 | mov a, [sp+5] | |
590 | mov1 cy, a.7 | |
591 | bc $div_signed_num | |
592 | mov a, [sp+7] | |
593 | mov1 cy, a.7 | |
594 | bc $div_signed_den | |
52a1ff8b | 595 | call $!__generic_hidiv |
ceb2fc49 DD |
596 | ret |
597 | ||
598 | div_signed_num: | |
599 | ;; neg [sp+4] | |
600 | movw ax, sp | |
601 | addw ax, #4 | |
52a1ff8b | 602 | NEG_AX |
ceb2fc49 DD |
603 | mov d, #1 |
604 | mov a, [sp+7] | |
605 | mov1 cy, a.7 | |
606 | bnc $div_unsigned_den | |
607 | div_signed_den: | |
608 | ;; neg [sp+6] | |
609 | movw ax, sp | |
610 | addw ax, #6 | |
52a1ff8b | 611 | NEG_AX |
ceb2fc49 DD |
612 | mov e, #1 |
613 | div_unsigned_den: | |
52a1ff8b | 614 | call $!__generic_hidiv |
ceb2fc49 DD |
615 | |
616 | mov a, d | |
617 | cmp0 a | |
618 | bz $div_skip_restore_num | |
619 | ;; We have to restore the numerator [sp+4] | |
620 | movw ax, sp | |
621 | addw ax, #4 | |
52a1ff8b | 622 | NEG_AX |
ceb2fc49 DD |
623 | mov a, d |
624 | div_skip_restore_num: | |
625 | xor a, e | |
626 | bz $div_no_neg | |
627 | movw ax, #r8 | |
52a1ff8b | 628 | NEG_AX |
ceb2fc49 DD |
629 | div_no_neg: |
630 | mov a, e | |
631 | cmp0 a | |
632 | bz $div_skip_restore_den | |
633 | movw ax, sp | |
634 | addw ax, #6 | |
52a1ff8b | 635 | NEG_AX |
ceb2fc49 DD |
636 | div_skip_restore_den: |
637 | ret | |
52a1ff8b | 638 | END_FUNC ___divhi3 |
ceb2fc49 DD |
639 | |
640 | ||
52a1ff8b | 641 | START_FUNC ___modhi3 |
ceb2fc49 DD |
642 | ;; r8 = 4[sp] % 6[sp] |
643 | movw de, #0 | |
644 | mov a, [sp+5] | |
645 | mov1 cy, a.7 | |
646 | bc $mod_signed_num | |
647 | mov a, [sp+7] | |
648 | mov1 cy, a.7 | |
649 | bc $mod_signed_den | |
52a1ff8b | 650 | call $!__generic_himod |
ceb2fc49 DD |
651 | ret |
652 | ||
653 | mod_signed_num: | |
654 | ;; neg [sp+4] | |
655 | movw ax, sp | |
656 | addw ax, #4 | |
52a1ff8b | 657 | NEG_AX |
ceb2fc49 DD |
658 | mov d, #1 |
659 | mov a, [sp+7] | |
660 | mov1 cy, a.7 | |
661 | bnc $mod_unsigned_den | |
662 | mod_signed_den: | |
663 | ;; neg [sp+6] | |
664 | movw ax, sp | |
665 | addw ax, #6 | |
52a1ff8b | 666 | NEG_AX |
ceb2fc49 | 667 | mod_unsigned_den: |
52a1ff8b | 668 | call $!__generic_himod |
ceb2fc49 DD |
669 | |
670 | mov a, d | |
671 | cmp0 a | |
672 | bz $mod_no_neg | |
673 | movw ax, #r8 | |
52a1ff8b | 674 | NEG_AX |
ceb2fc49 DD |
675 | ;; Also restore numerator |
676 | movw ax, sp | |
677 | addw ax, #4 | |
52a1ff8b | 678 | NEG_AX |
ceb2fc49 DD |
679 | mod_no_neg: |
680 | mov a, e | |
681 | cmp0 a | |
682 | bz $mod_skip_restore_den | |
683 | movw ax, sp | |
684 | addw ax, #6 | |
52a1ff8b | 685 | NEG_AX |
ceb2fc49 DD |
686 | mod_skip_restore_den: |
687 | ret | |
52a1ff8b | 688 | END_FUNC ___modhi3 |
72ed1126 NC |
689 | |
690 | ;---------------------------------------------------------------------- | |
691 | ||
692 | #else | |
693 | ||
694 | #error "Unknown RL78 hardware multiply/divide support" | |
695 | ||
696 | #endif |