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