]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/rl78/divmodhi.S
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / rl78 / divmodhi.S
CommitLineData
ceb2fc49 1/* HImode div/mod functions for the GCC support library for the Renesas RL78 processors.
a945c346 2 Copyright (C) 2012-2024 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
30START_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
92END_FUNC ___divhi3
93
94;----------------------------------------------------------------------
95
96START_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
158END_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
187START_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
2141: 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
2451: 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
252END_FUNC ___divhi3
253
254;----------------------------------------------------------------------
255
256START_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
2831: 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
3141: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
315 bt a.0, $1b
316
317 _Negate MDCL r8
318 ret
319
320END_FUNC ___modhi3
321
322;----------------------------------------------------------------------
323
324START_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
3411: 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
348END_FUNC ___udivhi3
349
350;----------------------------------------------------------------------
351
352START_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
3691: 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
376END_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
414num_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
464den_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
475shift_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
504main_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
526next_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
542enter_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
551main_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 562START_FUNC ___udivhi3
ceb2fc49 563 ;; r8 = 4[sp] / 6[sp]
52a1ff8b 564 call $!__generic_hidiv
ceb2fc49 565 ret
52a1ff8b 566END_FUNC ___udivhi3
ceb2fc49
DD
567
568
52a1ff8b 569START_FUNC ___umodhi3
ceb2fc49 570 ;; r8 = 4[sp] % 6[sp]
52a1ff8b 571 call $!__generic_himod
ceb2fc49 572 ret
52a1ff8b 573END_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
586START_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
598div_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
607div_signed_den:
608 ;; neg [sp+6]
609 movw ax, sp
610 addw ax, #6
52a1ff8b 611 NEG_AX
ceb2fc49
DD
612 mov e, #1
613div_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
624div_skip_restore_num:
625 xor a, e
626 bz $div_no_neg
627 movw ax, #r8
52a1ff8b 628 NEG_AX
ceb2fc49
DD
629div_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
636div_skip_restore_den:
637 ret
52a1ff8b 638END_FUNC ___divhi3
ceb2fc49
DD
639
640
52a1ff8b 641START_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
653mod_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
662mod_signed_den:
663 ;; neg [sp+6]
664 movw ax, sp
665 addw ax, #6
52a1ff8b 666 NEG_AX
ceb2fc49 667mod_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
679mod_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
686mod_skip_restore_den:
687 ret
52a1ff8b 688END_FUNC ___modhi3
72ed1126
NC
689
690;----------------------------------------------------------------------
691
692#else
693
694#error "Unknown RL78 hardware multiply/divide support"
695
696#endif