divmodhi.S revision 1.1.1.7
1/* HImode div/mod functions for the GCC support library for the Renesas RL78 processors. 2 Copyright (C) 2012-2019 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 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 26#include "vregs.h" 27 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 382.macro MAKE_GENERIC which,need_result 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 408#define bit bc 409#define bitB0 c 410#define bitB1 b 411 412 START_FUNC __generic_hidivmod\which 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 427 .global __generic_hidiv 428__generic_hidiv: 429 430 .else 431 432 .global __generic_himod 433__generic_himod: 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 457 .if \need_result 458 movw quot, #0 459 .else 460 movw num, #0 461 .endif 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 553 END_FUNC __generic_hidivmod\which 554.endm 555;---------------------------------------------------------------------- 556 557 MAKE_GENERIC _d 1 558 MAKE_GENERIC _m 0 559 560;---------------------------------------------------------------------- 561 562START_FUNC ___udivhi3 563 ;; r8 = 4[sp] / 6[sp] 564 call $!__generic_hidiv 565 ret 566END_FUNC ___udivhi3 567 568 569START_FUNC ___umodhi3 570 ;; r8 = 4[sp] % 6[sp] 571 call $!__generic_himod 572 ret 573END_FUNC ___umodhi3 574 575;---------------------------------------------------------------------- 576 577.macro NEG_AX 578 movw hl, ax 579 movw ax, #0 580 subw ax, [hl] 581 movw [hl], ax 582.endm 583 584;---------------------------------------------------------------------- 585 586START_FUNC ___divhi3 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 595 call $!__generic_hidiv 596 ret 597 598div_signed_num: 599 ;; neg [sp+4] 600 movw ax, sp 601 addw ax, #4 602 NEG_AX 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 611 NEG_AX 612 mov e, #1 613div_unsigned_den: 614 call $!__generic_hidiv 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 622 NEG_AX 623 mov a, d 624div_skip_restore_num: 625 xor a, e 626 bz $div_no_neg 627 movw ax, #r8 628 NEG_AX 629div_no_neg: 630 mov a, e 631 cmp0 a 632 bz $div_skip_restore_den 633 movw ax, sp 634 addw ax, #6 635 NEG_AX 636div_skip_restore_den: 637 ret 638END_FUNC ___divhi3 639 640 641START_FUNC ___modhi3 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 650 call $!__generic_himod 651 ret 652 653mod_signed_num: 654 ;; neg [sp+4] 655 movw ax, sp 656 addw ax, #4 657 NEG_AX 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 666 NEG_AX 667mod_unsigned_den: 668 call $!__generic_himod 669 670 mov a, d 671 cmp0 a 672 bz $mod_no_neg 673 movw ax, #r8 674 NEG_AX 675 ;; Also restore numerator 676 movw ax, sp 677 addw ax, #4 678 NEG_AX 679mod_no_neg: 680 mov a, e 681 cmp0 a 682 bz $mod_skip_restore_den 683 movw ax, sp 684 addw ax, #6 685 NEG_AX 686mod_skip_restore_den: 687 ret 688END_FUNC ___modhi3 689 690;---------------------------------------------------------------------- 691 692#else 693 694#error "Unknown RL78 hardware multiply/divide support" 695 696#endif 697