From 72ed1126861875a4fae0d75f994e35f1b79509bd Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 16 Apr 2015 07:57:56 +0000 Subject: [PATCH] rl78-opts.h (enum rl78_mul_types): Add MUL_G14 and MUL_UNINIT. * config/rl78/rl78-opts.h (enum rl78_mul_types): Add MUL_G14 and MUL_UNINIT. (enum rl78_cpu_type): New. * config/rl78/rl78-virt.md (attr valloc): Add divhi and divsi. (umulhi3_shift_virt): Remove m constraint from operand 1. (umulqihi3_virt): Likewise. * config/rl78/rl78.c (rl78_option_override): Add code to process -mcpu and -mmul options. (rl78_alloc_physical_registers): Add code to handle divhi and divsi valloc attributes. (set_origin): Likewise. * config/rl78/rl78.h (RL78_MUL_G14): Define. (TARGET_G10, TARGET_G13, TARGET_G14): Define. (TARGET_CPU_CPP_BUILTINS): Define __RL78_MUL_xxx__ and __RL78_Gxx__. (ASM_SPEC): Pass -mcpu on to assembler. * config/rl78/rl78.md (mulqi3): Add a clobber of AX. (mulqi3_rl78): Likewise. (mulhi3_g13): Likewise. (mulhi3): Generate the G13 or G14 versions of the insn directly. (mulsi3): Likewise. (mulhi3_g14): Add clobbers of AX and BC. (mulsi3_g14): Likewise. (mulsi3_g13): Likewise. (udivmodhi4, udivmodhi4_g14, udivmodsi4): New patterns. (udivmodsi4_g14, udivmodsi4_g13): New patterns. * config/rl78/rl78.opt (mmul): Initialise value to RL78_MUL_UNINIT. (mcpu): New option. (m13, m14, mrl78): New option aliases. * config/rl78/t-rl78 (MULTILIB_OPTIONS): Add mg13 and mg14. (MULTILIB_DIRNAMES): Add g13 and g14. * doc/invoke.texi: Document -mcpu and -mmul options. * config/rl78/divmodhi.S: Add G14 and G13 versions of the __divhi3 and __modhi3 functions. * config/rl78/divmodso.S: Add G14 and G13 versions of the __divsi3, __udivsi3, __modsi3 and __umodsi3 functions. From-SVN: r222142 --- gcc/ChangeLog | 37 ++ gcc/config/rl78/rl78-opts.h | 12 +- gcc/config/rl78/rl78-virt.md | 6 +- gcc/config/rl78/rl78.c | 104 +++- gcc/config/rl78/rl78.h | 35 +- gcc/config/rl78/rl78.md | 302 +++++++++- gcc/config/rl78/rl78.opt | 48 +- gcc/config/rl78/t-rl78 | 6 +- gcc/doc/invoke.texi | 84 ++- .../gcc.c-torture/execute/20101011-1.c | 12 + libgcc/ChangeLog | 7 + libgcc/config/rl78/divmodhi.S | 362 ++++++++++++ libgcc/config/rl78/divmodsi.S | 541 ++++++++++++++++++ 13 files changed, 1496 insertions(+), 60 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a3a2016c990..5ff0a23a1bb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,39 @@ +2015-04-16 Nick Clifton + + * config/rl78/rl78-opts.h (enum rl78_mul_types): Add MUL_G14 and + MUL_UNINIT. + (enum rl78_cpu_type): New. + * config/rl78/rl78-virt.md (attr valloc): Add divhi and divsi. + (umulhi3_shift_virt): Remove m constraint from operand 1. + (umulqihi3_virt): Likewise. + * config/rl78/rl78.c (rl78_option_override): Add code to process + -mcpu and -mmul options. + (rl78_alloc_physical_registers): Add code to handle divhi and + divsi valloc attributes. + (set_origin): Likewise. + * config/rl78/rl78.h (RL78_MUL_G14): Define. + (TARGET_G10, TARGET_G13, TARGET_G14): Define. + (TARGET_CPU_CPP_BUILTINS): Define __RL78_MUL_xxx__ and + __RL78_Gxx__. + (ASM_SPEC): Pass -mcpu on to assembler. + * config/rl78/rl78.md (mulqi3): Add a clobber of AX. + (mulqi3_rl78): Likewise. + (mulhi3_g13): Likewise. + (mulhi3): Generate the G13 or G14 versions of the insn directly. + (mulsi3): Likewise. + (mulhi3_g14): Add clobbers of AX and BC. + (mulsi3_g14): Likewise. + (mulsi3_g13): Likewise. + (udivmodhi4, udivmodhi4_g14, udivmodsi4): New patterns. + (udivmodsi4_g14, udivmodsi4_g13): New patterns. + * config/rl78/rl78.opt (mmul): Initialise value to + RL78_MUL_UNINIT. + (mcpu): New option. + (m13, m14, mrl78): New option aliases. + * config/rl78/t-rl78 (MULTILIB_OPTIONS): Add mg13 and mg14. + (MULTILIB_DIRNAMES): Add g13 and g14. + * doc/invoke.texi: Document -mcpu and -mmul options. + 2015-04-16 Richard Biener * tree-ssa-ccp.c (likely_value): See if we have operands that @@ -75,6 +111,7 @@ * config/rx/t-rx (MULTILIB_OPTIONS): Add mno-allow-string-insns. (MULTILIB_DIRNAMES): Add no-strings. * doc/invoke.texi: Document -mno-allow-string-insns. + 2015-04-15 Alan Modra PR target/65408 diff --git a/gcc/config/rl78/rl78-opts.h b/gcc/config/rl78/rl78-opts.h index 8d98d8daf54..6fa54cc1143 100644 --- a/gcc/config/rl78/rl78-opts.h +++ b/gcc/config/rl78/rl78-opts.h @@ -24,7 +24,17 @@ enum rl78_mul_types { MUL_NONE, MUL_RL78, - MUL_G13 + MUL_G13, + MUL_G14, + MUL_UNINIT +}; + +enum rl78_cpu_types +{ + CPU_G10, + CPU_G13, + CPU_G14, + CPU_UNINIT }; #endif diff --git a/gcc/config/rl78/rl78-virt.md b/gcc/config/rl78/rl78-virt.md index e90e156a8d1..c70beaec539 100644 --- a/gcc/config/rl78/rl78-virt.md +++ b/gcc/config/rl78/rl78-virt.md @@ -28,7 +28,7 @@ ;; instruction - op1 is of the form "a = op(b)", op2 is "a = b op c" ;; etc. -(define_attr "valloc" "op1,op2,ro1,cmp,umul,macax" +(define_attr "valloc" "op1,op2,ro1,cmp,umul,macax,divhi,divsi" (const_string "op2")) ;;---------- Moving ------------------------ @@ -113,7 +113,7 @@ ) (define_insn "*umulhi3_shift_virt" - [(set (match_operand:HI 0 "register_operand" "=vm") + [(set (match_operand:HI 0 "register_operand" "=v") (mult:HI (match_operand:HI 1 "rl78_nonfar_operand" "%vim") (match_operand:HI 2 "rl78_24_operand" "Ni")))] "rl78_virt_insns_ok () && !TARGET_G10" @@ -122,7 +122,7 @@ ) (define_insn "*umulqihi3_virt" - [(set (match_operand:HI 0 "register_operand" "=vm") + [(set (match_operand:HI 0 "register_operand" "=v") (mult:HI (zero_extend:HI (match_operand:QI 1 "rl78_nonfar_operand" "%vim")) (zero_extend:HI (match_operand:QI 2 "general_operand" "vim"))))] "rl78_virt_insns_ok () && !TARGET_G10" diff --git a/gcc/config/rl78/rl78.c b/gcc/config/rl78/rl78.c index a9d5f5aeaa9..64698045e8a 100644 --- a/gcc/config/rl78/rl78.c +++ b/gcc/config/rl78/rl78.c @@ -377,6 +377,48 @@ rl78_option_override (void) && strcmp (lang_hooks.name, "GNU GIMPLE")) /* Address spaces are currently only supported by C. */ error ("-mes0 can only be used with C"); + + switch (rl78_cpu_type) + { + case CPU_UNINIT: + rl78_cpu_type = CPU_G14; + if (rl78_mul_type == MUL_UNINIT) + rl78_mul_type = MUL_NONE; + break; + + case CPU_G10: + switch (rl78_mul_type) + { + case MUL_UNINIT: rl78_mul_type = MUL_NONE; break; + case MUL_NONE: break; + case MUL_G13: error ("-mmul=g13 cannot be used with -mcpu=g10"); break; + case MUL_G14: error ("-mmul=g14 cannot be used with -mcpu=g10"); break; + } + break; + + case CPU_G13: + switch (rl78_mul_type) + { + case MUL_UNINIT: rl78_mul_type = MUL_G13; break; + case MUL_NONE: break; + case MUL_G13: break; + /* The S2 core does not have mul/div instructions. */ + case MUL_G14: error ("-mmul=g14 cannot be used with -mcpu=g13"); break; + } + break; + + case CPU_G14: + switch (rl78_mul_type) + { + case MUL_UNINIT: rl78_mul_type = MUL_G14; break; + case MUL_NONE: break; + case MUL_G14: break; + /* The G14 core does not have the hardware multiply peripheral used by the + G13 core, hence you cannot use G13 multipliy routines on G14 hardware. */ + case MUL_G13: error ("-mmul=g13 cannot be used with -mcpu=g14"); break; + } + break; + } } /* Most registers are 8 bits. Some are 16 bits because, for example, @@ -3514,6 +3556,18 @@ rl78_alloc_physical_registers (void) record_content (BC, NULL_RTX); record_content (DE, NULL_RTX); } + else if (valloc_method == VALLOC_DIVHI) + { + record_content (AX, NULL_RTX); + record_content (BC, NULL_RTX); + } + else if (valloc_method == VALLOC_DIVSI) + { + record_content (AX, NULL_RTX); + record_content (BC, NULL_RTX); + record_content (DE, NULL_RTX); + record_content (HL, NULL_RTX); + } if (insn_ok_now (insn)) continue; @@ -3541,6 +3595,7 @@ rl78_alloc_physical_registers (void) break; case VALLOC_UMUL: rl78_alloc_physical_registers_umul (insn); + record_content (AX, NULL_RTX); break; case VALLOC_MACAX: /* Macro that clobbers AX. */ @@ -3549,6 +3604,18 @@ rl78_alloc_physical_registers (void) record_content (BC, NULL_RTX); record_content (DE, NULL_RTX); break; + case VALLOC_DIVSI: + rl78_alloc_address_registers_div (insn); + record_content (AX, NULL_RTX); + record_content (BC, NULL_RTX); + record_content (DE, NULL_RTX); + record_content (HL, NULL_RTX); + break; + case VALLOC_DIVHI: + rl78_alloc_address_registers_div (insn); + record_content (AX, NULL_RTX); + record_content (BC, NULL_RTX); + break; default: gcc_unreachable (); } @@ -3863,6 +3930,37 @@ set_origin (rtx pat, rtx_insn * insn, int * origins, int * age) age[i] = 0; } } + else if (get_attr_valloc (insn) == VALLOC_DIVHI) + { + if (dump_file) + fprintf (dump_file, "Resetting origin of AX/DE for DIVHI pattern.\n"); + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (i == A_REG + || i == X_REG + || i == D_REG + || i == E_REG + || origins[i] == A_REG + || origins[i] == X_REG + || origins[i] == D_REG + || origins[i] == E_REG) + { + origins[i] = i; + age[i] = 0; + } + } + else if (get_attr_valloc (insn) == VALLOC_DIVSI) + { + if (dump_file) + fprintf (dump_file, "Resetting origin of AX/BC/DE/HL for DIVSI pattern.\n"); + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (i <= 7 || origins[i] <= 7) + { + origins[i] = i; + age[i] = 0; + } + } if (GET_CODE (src) == ASHIFT || GET_CODE (src) == ASHIFTRT @@ -4087,7 +4185,7 @@ rl78_rtx_costs (rtx x, switch (code) { case MULT: - if (RL78_MUL_RL78) + if (RL78_MUL_G14) *total = COSTS_N_INSNS (14); else if (RL78_MUL_G13) *total = COSTS_N_INSNS (29); @@ -4407,7 +4505,7 @@ rl78_insert_attributes (tree decl, tree *attributes ATTRIBUTE_UNUSED) tree type = TREE_TYPE (decl); tree attr = TYPE_ATTRIBUTES (type); int q = TYPE_QUALS_NO_ADDR_SPACE (type) | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_FAR); - + TREE_TYPE (decl) = build_type_attribute_qual_variant (type, attr, q); } } @@ -4503,7 +4601,7 @@ rl78_flags_already_set (rtx op, rtx operand) { if (LABEL_P (insn)) break; - + if (! INSN_P (insn)) continue; diff --git a/gcc/config/rl78/rl78.h b/gcc/config/rl78/rl78.h index caa7f7f6541..066b0d1323c 100644 --- a/gcc/config/rl78/rl78.h +++ b/gcc/config/rl78/rl78.h @@ -20,20 +20,32 @@ #define RL78_MUL_NONE (rl78_mul_type == MUL_NONE) -#define RL78_MUL_RL78 (rl78_mul_type == MUL_RL78) #define RL78_MUL_G13 (rl78_mul_type == MUL_G13) +#define RL78_MUL_G14 (rl78_mul_type == MUL_G14) + +#define TARGET_G10 (rl78_cpu_type == CPU_G10) +#define TARGET_G13 (rl78_cpu_type == CPU_G13) +#define TARGET_G14 (rl78_cpu_type == CPU_G14) #define TARGET_CPU_CPP_BUILTINS() \ do \ { \ builtin_define ("__RL78__"); \ builtin_assert ("cpu=RL78"); \ - if (RL78_MUL_RL78) \ - builtin_define ("__RL78_MUL_RL78__"); \ - if (RL78_MUL_G13) \ + \ + if (RL78_MUL_NONE) \ + builtin_define ("__RL78_MUL_NONE__"); \ + else if (RL78_MUL_G13) \ builtin_define ("__RL78_MUL_G13__"); \ + else if (RL78_MUL_G14) \ + builtin_define ("__RL78_MUL_G14__"); \ + \ if (TARGET_G10) \ builtin_define ("__RL78_G10__"); \ + else if (TARGET_G13) \ + builtin_define ("__RL78_G13__"); \ + else if (TARGET_G14) \ + builtin_define ("__RL78_G14__"); \ } \ while (0) @@ -46,7 +58,14 @@ #undef ASM_SPEC #define ASM_SPEC "\ %{mrelax:-relax} \ -%{mg10} \ +%{mg10:--mg10} \ +%{mg13:--mg13} \ +%{mg14:--mg14} \ +%{mrl78:--mg14} \ +%{mcpu=g10:--mg10} \ +%{mcpu=g13:--mg13} \ +%{mcpu=g14:--mg14} \ +%{mcpu=rl78:--mg14} \ " #undef LINK_SPEC @@ -160,11 +179,11 @@ */ #define REGISTER_NAMES \ { \ - "x", "a", "c", "b", "e", "d", "l", "h", \ - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", \ + "x", "a", "c", "b", "e", "d", "l", "h", \ + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", \ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", \ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", \ - "sp", "ap", "psw", "es", "cs" \ + "sp", "ap", "psw", "es", "cs" \ } #define ADDITIONAL_REGISTER_NAMES \ diff --git a/gcc/config/rl78/rl78.md b/gcc/config/rl78/rl78.md index 258c139c867..2ea788e5817 100644 --- a/gcc/config/rl78/rl78.md +++ b/gcc/config/rl78/rl78.md @@ -288,10 +288,13 @@ ) (define_expand "mulqi3" - [(set (match_operand:QI 0 "register_operand") - (mult:QI (match_operand:QI 1 "general_operand") - (match_operand:QI 2 "nonmemory_operand"))) - ] + [(parallel + [(set (match_operand:QI 0 "register_operand") + (mult:QI (match_operand:QI 1 "general_operand") + (match_operand:QI 2 "nonmemory_operand"))) + (clobber (reg:HI AX_REG)) + ]) + ] "" ; mulu supported by all targets "" ) @@ -302,7 +305,13 @@ (match_operand:HI 2 "nonmemory_operand"))) ] "! RL78_MUL_NONE" - "" + { + if (RL78_MUL_G14) + emit_insn (gen_mulhi3_g14 (operands[0], operands[1], operands[2])); + else /* RL78_MUL_G13 */ + emit_insn (gen_mulhi3_g13 (operands[0], operands[1], operands[2])); + DONE; + } ) (define_expand "mulsi3" @@ -311,14 +320,21 @@ (match_operand:SI 2 "nonmemory_operand"))) ] "! RL78_MUL_NONE" - "" + { + if (RL78_MUL_G14) + emit_insn (gen_mulsi3_g14 (operands[0], operands[1], operands[2])); + else /* RL78_MUL_G13 */ + emit_insn (gen_mulsi3_g13 (operands[0], operands[1], operands[2])); + DONE; + } ) (define_insn "*mulqi3_rl78" [(set (match_operand:QI 0 "register_operand" "=&v") (mult:QI (match_operand:QI 1 "general_operand" "viU") (match_operand:QI 2 "general_operand" "vi"))) - ] + (clobber (reg:HI AX_REG)) + ] "" ; mulu supported by all targets "; mulqi macro %0 = %1 * %2 mov a, %h1 @@ -328,31 +344,34 @@ mov a, x mov %h0, a ; end of mulqi macro" -;; [(set_attr "valloc" "macax")] + [(set_attr "valloc" "macax")] ) -(define_insn "*mulhi3_rl78" +(define_insn "mulhi3_g14" [(set (match_operand:HI 0 "register_operand" "=&v") (mult:HI (match_operand:HI 1 "general_operand" "viU") (match_operand:HI 2 "general_operand" "vi"))) - ] - "RL78_MUL_RL78" - "; mulhi macro %0 = %1 * %2 + (clobber (reg:HI AX_REG)) + (clobber (reg:HI BC_REG)) + ] + "RL78_MUL_G14" + "; G14 mulhi macro %0 = %1 * %2 movw ax, %h1 movw bc, %h2 mulhu ; bcax = bc * ax movw %h0, ax ; end of mulhi macro" -;; [(set_attr "valloc" "macax")] + [(set_attr "valloc" "macax")] ) -(define_insn "*mulhi3_g13" +(define_insn "mulhi3_g13" [(set (match_operand:HI 0 "register_operand" "=&v") (mult:HI (match_operand:HI 1 "general_operand" "viU") (match_operand:HI 2 "general_operand" "vi"))) - ] + (clobber (reg:HI AX_REG)) + ] "RL78_MUL_G13" - "; mulhi macro %0 = %1 * %2 + "; G13 mulhi macro %0 = %1 * %2 mov a, #0x00 mov !0xf00e8, a ; MDUC movw ax, %h1 @@ -363,19 +382,21 @@ movw ax, 0xffff6 ; MDBL movw %h0, ax ; end of mulhi macro" -;; [(set_attr "valloc" "umul")] + [(set_attr "valloc" "macax")] ) ;; 0xFFFF0 is MACR(L). 0xFFFF2 is MACR(H) but we don't care about it ;; because we're only using the lower 16 bits (which is the upper 16 ;; bits of the result). -(define_insn "mulsi3_rl78" +(define_insn "mulsi3_g14" [(set (match_operand:SI 0 "register_operand" "=&v") (mult:SI (match_operand:SI 1 "general_operand" "viU") (match_operand:SI 2 "general_operand" "vi"))) - ] - "RL78_MUL_RL78" - "; mulsi macro %0 = %1 * %2 + (clobber (reg:HI AX_REG)) + (clobber (reg:HI BC_REG)) + ] + "RL78_MUL_G14" + "; G14 mulsi macro %0 = %1 * %2 movw ax, %h1 movw bc, %h2 MULHU ; bcax = bc * ax @@ -403,9 +424,11 @@ [(set (match_operand:SI 0 "register_operand" "=&v") (mult:SI (match_operand:SI 1 "general_operand" "viU") (match_operand:SI 2 "general_operand" "viU"))) - ] + (clobber (reg:HI AX_REG)) + (clobber (reg:HI BC_REG)) + ] "RL78_MUL_G13" - "; mulsi macro %0 = %1 * %2 + "; G13 mulsi macro %0 = %1 * %2 mov a, #0x00 mov !0xf00e8, a ; MDUC movw ax, %h1 @@ -441,3 +464,236 @@ ; end of mulsi macro" [(set_attr "valloc" "macax")] ) + +(define_expand "udivmodhi4" + [(parallel + [(set (match_operand:HI 0 "register_operand") + (udiv:HI (match_operand:HI 1 "register_operand") + (match_operand:HI 2 "register_operand"))) + (set (match_operand:HI 3 "register_operand") + (umod:HI (match_dup 1) (match_dup 2))) + (clobber (reg:HI AX_REG)) + (clobber (reg:HI DE_REG)) + ]) + ] + "RL78_MUL_G14" + "" +) + +(define_insn "*udivmodhi4_g14" + [(set (match_operand:HI 0 "register_operand" "=v") + (udiv:HI (match_operand:HI 1 "register_operand" "v") + (match_operand:HI 2 "register_operand" "v"))) + (set (match_operand:HI 3 "register_operand" "=v") + (umod:HI (match_dup 1) (match_dup 2))) + (clobber (reg:HI AX_REG)) + (clobber (reg:HI DE_REG)) + ] + "RL78_MUL_G14" + { + if (find_reg_note (insn, REG_UNUSED, operands[3])) + return "; G14 udivhi macro %0 = %1 / %2 \n\ + movw ax, %h1 \n\ + movw de, %h2 \n\ + push psw ; Save the current interrupt status \n\ + di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\ + divhu ; ax = ax / de \n\ + pop psw ; Restore saved interrupt status \n\ + movw %h0, ax \n\ + ; end of udivhi macro"; + else if (find_reg_note (insn, REG_UNUSED, operands[0])) + return "; G14 umodhi macro %3 = %1 %% %2 \n\ + movw ax, %h1 \n\ + movw de, %h2 \n\ + push psw ; Save the current interrupt status \n\ + di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\ + divhu ; de = ax %% de \n\ + pop psw ; Restore saved interrupt status \n\ + movw ax, de \n\ + movw %h3, ax \n\ + ; end of umodhi macro"; + else + return "; G14 udivmodhi macro %0 = %1 / %2 and %3 = %1 %% %2 \n\ + movw ax, %h1 \n\ + movw de, %h2 \n\ + push psw ; Save the current interrupt status \n\ + di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\ + divhu ; ax = ax / de, de = ax %% de \n\ + pop psw ; Restore saved interrupt status \n\ + movw %h0, ax \n\ + movw ax, de \n\ + movw %h3, ax \n\ + ; end of udivmodhi macro"; + } + [(set_attr "valloc" "divhi")] +) + +(define_expand "udivmodsi4" + [(parallel + [(set (match_operand:SI 0 "register_operand") + (udiv:SI (match_operand:SI 1 "register_operand") + (match_operand:SI 2 "register_operand"))) + (set (match_operand:SI 3 "register_operand") + (umod:SI (match_dup 1) (match_dup 2))) + ]) + ] + "! RL78_MUL_NONE && ! optimize_size" + { + if (RL78_MUL_G14) + emit_insn (gen_udivmodsi4_g14 (operands[0], operands[1], operands[2], operands[3])); + else /* RL78_MUL_G13 */ + emit_insn (gen_udivmodsi4_g13 (operands[0], operands[1], operands[2], operands[3])); + DONE; + } +) + +(define_insn "udivmodsi4_g14" + [(set (match_operand:SI 0 "register_operand" "=v") + (udiv:SI (match_operand:SI 1 "register_operand" "v") + (match_operand:SI 2 "register_operand" "v"))) + (set (match_operand:SI 3 "register_operand" "=v") + (umod:SI (match_dup 1) (match_dup 2))) + (clobber (reg:HI AX_REG)) + (clobber (reg:HI BC_REG)) + (clobber (reg:HI DE_REG)) + (clobber (reg:HI HL_REG)) + ] + "RL78_MUL_G14" + { + if (find_reg_note (insn, REG_UNUSED, operands[3])) + return "; G14 udivsi macro %0 = %1 / %2 \n\ + movw ax, %h1 \n\ + movw bc, %H1 \n\ + movw de, %h2 \n\ + movw hl, %H2 \n\ + push psw ; Save the current interrupt status \n\ + di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\ + divwu ; bcax = bcax / hlde \n\ + pop psw ; Restore saved interrupt status \n\ + movw %h0, ax \n\ + movw ax, bc \n\ + movw %H0, ax \n\ + ; end of udivsi macro"; + else if (find_reg_note (insn, REG_UNUSED, operands[0])) + return "; G14 umodsi macro %3 = %1 %% %2 \n\ + movw ax, %h1 \n\ + movw bc, %H1 \n\ + movw de, %h2 \n\ + movw hl, %H2 \n\ + push psw ; Save the current interrupt status \n\ + di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\ + divwu ; hlde = bcax %% hlde \n\ + pop psw ; Restore saved interrupt status \n\ + movw ax, de \n\ + movw %h3, ax \n\ + movw ax, hl \n\ + movw %H3, ax \n\ + ; end of umodsi macro"; + else + return "; G14 udivmodsi macro %0 = %1 / %2 and %3 = %1 %% %2 \n\ + movw ax, %h1 \n\ + movw bc, %H1 \n\ + movw de, %h2 \n\ + movw hl, %H2 \n\ + push psw ; Save the current interrupt status \n\ + di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\ + divwu ; bcax = bcax / hlde, hlde = bcax %% hlde \n\ + pop psw ; Restore saved interrupt status \n\ + movw %h0, ax \n\ + movw ax, bc \n\ + movw %H0, ax \n\ + movw ax, de \n\ + movw %h3, ax \n\ + movw ax, hl \n\ + movw %H3, ax \n\ + ; end of udivmodsi macro"; + } + [(set_attr "valloc" "divsi")] +) + +;; Warning: these values match the silicon not the documentation. +;; 0xFFFF0 is MDAL. 0xFFFF2 is MDAH. +;; 0xFFFF6 is MDBL. 0xFFFF4 is MDBH. +;; 0xF00E0 is MDCL. 0xF00E2 is MDCH. +;; 0xF00E8 is MDUC. + +(define_insn "udivmodsi4_g13" + [(set (match_operand:SI 0 "register_operand" "=v") + (udiv:SI (match_operand:SI 1 "register_operand" "v") + (match_operand:SI 2 "register_operand" "v"))) + (set (match_operand:SI 3 "register_operand" "=v") + (umod:SI (match_dup 1) (match_dup 2))) + (clobber (reg:HI AX_REG)) + ] + "RL78_MUL_G13" + { + if (find_reg_note (insn, REG_UNUSED, operands[3])) + return "; G13 udivsi macro %0 = %1 / %2 \n\ + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 \n\ + mov !0xf00e8, a ; This preps the peripheral for division without interrupt generation \n\ + movw ax, %H1 \n\ + movw 0xffff2, ax ; MDAH \n\ + movw ax, %h1 \n\ + movw 0xffff0, ax ; MDAL \n\ + movw ax, %H2 \n\ + movw 0xffff4, ax ; MDBH \n\ + movw ax, %h2 \n\ + movw 0xffff6, ax ; MDBL \n\ + mov a, #0xC1 ; Set the DIVST bit in MDUC \n\ + mov !0xf00e8, a ; This starts the division op \n\ +1: mov a, !0xf00e8 ; Wait 16 clocks or until DIVST is clear \n\ + bt a.0, $1b \n\ + movw ax, 0xffff0 ; Read the quotient \n\ + movw %h0, ax \n\ + movw ax, 0xffff2 \n\ + movw %H0, ax \n\ + ; end of udivsi macro"; + else if (find_reg_note (insn, REG_UNUSED, operands[0])) + return "; G13 umodsi macro %3 = %1 %% %2 \n\ + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 \n\ + mov !0xf00e8, a ; This preps the peripheral for division without interrupt generation \n\ + movw ax, %H1 \n\ + movw 0xffff2, ax ; MDAH \n\ + movw ax, %h1 \n\ + movw 0xffff0, ax ; MDAL \n\ + movw ax, %H2 \n\ + movw 0xffff4, ax ; MDBH \n\ + movw ax, %h2 \n\ + movw 0xffff6, ax ; MDBL \n\ + mov a, #0xC1 ; Set the DIVST bit in MDUC \n\ + mov !0xf00e8, a ; This starts the division op \n\ +1: mov a, !0xf00e8 ; Wait 16 clocks or until DIVST is clear \n\ + bt a.0, $1b \n\ + movw ax, !0xf00e0 ; Read the remainder \n\ + movw %h3, ax \n\ + movw ax, !0xf00e2 \n\ + movw %H3, ax \n\ + ; end of umodsi macro"; + else + return "; G13 udivmodsi macro %0 = %1 / %2 and %3 = %1 %% %2 \n\ + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 \n\ + mov !0xf00e8, a ; This preps the peripheral for division without interrupt generation \n\ + movw ax, %H1 \n\ + movw 0xffff2, ax ; MDAH \n\ + movw ax, %h1 \n\ + movw 0xffff0, ax ; MDAL \n\ + movw ax, %H2 \n\ + movw 0xffff4, ax ; MDBH \n\ + movw ax, %h2 \n\ + movw 0xffff6, ax ; MDBL \n\ + mov a, #0xC1 ; Set the DIVST bit in MDUC \n\ + mov !0xf00e8, a ; This starts the division op \n\ +1: mov a, !0xf00e8 ; Wait 16 clocks or until DIVST is clear \n\ + bt a.0, $1b \n\ + movw ax, 0xffff0 ; Read the quotient \n\ + movw %h0, ax \n\ + movw ax, 0xffff2 \n\ + movw %H0, ax \n\ + movw ax, !0xf00e0 ; Read the remainder \n\ + movw %h3, ax \n\ + movw ax, !0xf00e2 \n\ + movw %H3, ax \n\ + ; end of udivmodsi macro"; + } + [(set_attr "valloc" "macax")] +) diff --git a/gcc/config/rl78/rl78.opt b/gcc/config/rl78/rl78.opt index 1e4c14c706e..80b894a6e67 100644 --- a/gcc/config/rl78/rl78.opt +++ b/gcc/config/rl78/rl78.opt @@ -27,20 +27,23 @@ Target Report Use the simulator runtime. mmul= -Target RejectNegative Joined Var(rl78_mul_type) Report Tolower Enum(rl78_mul_types) Init(MUL_NONE) -Select hardware or software multiplication support. +Target RejectNegative Joined Var(rl78_mul_type) Report Tolower Enum(rl78_mul_types) Init(MUL_UNINIT) +Selects the type of hardware multiplication and division to use (none/g13/g14). Enum Name(rl78_mul_types) Type(enum rl78_mul_types) EnumValue -Enum(rl78_mul_types) String(none) Value(MUL_NONE) +Enum(rl78_mul_types) String(g10) Value(MUL_NONE) EnumValue -Enum(rl78_mul_types) String(rl78) Value(MUL_RL78) +Enum(rl78_mul_types) String(g13) Value(MUL_G13) EnumValue -Enum(rl78_mul_types) String(g13) Value(MUL_G13) +Enum(rl78_mul_types) String(g14) Value(MUL_G14) + +EnumValue +Enum(rl78_mul_types) String(rl78) Value(MUL_G14) mallregs Target Mask(ALLREGS) Report Optimization @@ -50,9 +53,40 @@ mrelax Target Report Optimization Enable assembler and linker relaxation. Enabled by default at -Os. +mcpu= +Target RejectNegative Joined Var(rl78_cpu_type) Report ToLower Enum(rl78_cpu_types) Init(CPU_UNINIT) +Selects the type of RL78 core being targeted (g10/g13/g14). The default is the G14. If set, also selects the hardware multiply support to be used. + +Enum +Name(rl78_cpu_types) Type(enum rl78_cpu_types) + +EnumValue +Enum(rl78_cpu_types) String(g10) Value(CPU_G10) + +EnumValue +Enum(rl78_cpu_types) String(g13) Value(CPU_G13) + +EnumValue +Enum(rl78_cpu_types) String(g14) Value(CPU_G14) + +EnumValue +Enum(rl78_cpu_types) String(rl78) Value(CPU_G14) + mg10 -Target Mask(G10) Report -Target the RL78/G10 series +Target RejectNegative Report Alias(mcpu=, g10) +Alias for -mcpu=g10 + +mg13 +Target RejectNegative Report Alias(mcpu=, g13) +Alias for -mcpu=g13 + +mg14 +Target RejectNegative Report Alias(mcpu=, g14) +Alias for -mcpu=g14 + +mrl78 +Target RejectNegative Report Alias(mcpu=, g14) +Alias for -mcpu=g14 mes0 Target Mask(ES0) diff --git a/gcc/config/rl78/t-rl78 b/gcc/config/rl78/t-rl78 index 262885564d1..bd8fab430e0 100644 --- a/gcc/config/rl78/t-rl78 +++ b/gcc/config/rl78/t-rl78 @@ -23,5 +23,7 @@ rl78-c.o: $(srcdir)/config/rl78/rl78-c.c $(RTL_H) $(TREE_H) $(CONFIG_H) $(TM_H) # Enable multilibs: -MULTILIB_OPTIONS = mg10 -MULTILIB_DIRNAMES = g10 +MULTILIB_OPTIONS = mg10/mg13/mg14 +MULTILIB_DIRNAMES = g10 g13 g14 + +MULTILIB_MATCHES = mg10=mcpu?g10 mg13=mcpu?g13 mg14=mcpu?g14 mg14=mcpu?rl78 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 18f69906248..bb173854663 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -265,7 +265,7 @@ Objective-C and Objective-C++ Dialects}. -Wmain -Wmaybe-uninitialized -Wmemset-transposed-args -Wmissing-braces @gol -Wmissing-field-initializers -Wmissing-include-dirs @gol -Wno-multichar -Wnonnull -Wnormalized=@r{[}none@r{|}id@r{|}nfc@r{|}nfkc@r{]} @gol - -Wodr -Wno-overflow -Wopenmp-simd @gol +-Wodr -Wno-overflow -Wopenmp-simd @gol -Woverlength-strings -Wpacked -Wpacked-bitfield-compat -Wpadded @gol -Wparentheses -Wpedantic-ms-format -Wno-pedantic-ms-format @gol -Wpointer-arith -Wno-pointer-to-int-cast @gol @@ -277,7 +277,7 @@ Objective-C and Objective-C++ Dialects}. -Wstack-protector -Wstack-usage=@var{len} -Wstrict-aliasing @gol -Wstrict-aliasing=n @gol -Wstrict-overflow -Wstrict-overflow=@var{n} @gol -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{]} @gol --Wsuggest-final-types @gol -Wsuggest-final-methods @gol -Wsuggest-override @gol +-Wsuggest-final-types @gol -Wsuggest-final-methods -Wsuggest-override @gol -Wmissing-format-attribute @gol -Wswitch -Wswitch-default -Wswitch-enum -Wswitch-bool -Wsync-nand @gol -Wsystem-headers -Wtrampolines -Wtrigraphs -Wtype-limits -Wundef @gol @@ -405,7 +405,7 @@ Objective-C and Objective-C++ Dialects}. -fisolate-erroneous-paths-dereference -fisolate-erroneous-paths-attribute @gol -fivopts -fkeep-inline-functions -fkeep-static-consts @gol -flive-range-shrinkage @gol --floop-block -floop-interchange -floop-strip-mine @gol +-floop-block -floop-interchange -floop-strip-mine @gol -floop-unroll-and-jam -floop-nest-optimize @gol -floop-parallelize-all -flra-remat -flto -flto-compression-level @gol -flto-partition=@var{alg} -flto-report -flto-report-wpa -fmerge-all-constants @gol @@ -870,7 +870,8 @@ Objective-C and Objective-C++ Dialects}. See RS/6000 and PowerPC Options. @emph{RL78 Options} -@gccoptlist{-msim -mmul=none -mmul=g13 -mmul=rl78 @gol +@gccoptlist{-msim -mmul=none -mmul=g13 -mmul=g14 -mallregs @gol +-mcpu=g10 -mcpu=g13 -mcpu=g14 -mg10 -mg13 -mg14 @gol -m64bit-doubles -m32bit-doubles} @emph{RS/6000 and PowerPC Options} @@ -1786,7 +1787,7 @@ Using this option is roughly equivalent to adding the The option @option{-fno-gnu89-inline} explicitly tells GCC to use the C99 semantics for @code{inline} when in C99 or gnu99 mode (i.e., it -specifies the default behavior). +specifies the default behavior). This option is not supported in @option{-std=c90} or @option{-std=gnu90} mode. @@ -2090,7 +2091,7 @@ Version 0 refers to the version conforming most closely to the C++ ABI specification. Therefore, the ABI obtained using version 0 will change in different versions of G++ as ABI bugs are fixed. -Version 1 is the version of the C++ ABI that first appeared in G++ 3.2. +Version 1 is the version of the C++ ABI that first appeared in G++ 3.2. Version 2 is the version of the C++ ABI that first appeared in G++ 3.4, and was the default through G++ 4.9. @@ -4354,7 +4355,6 @@ pointers. This warning level may give a larger number of false positives and is deactivated by default. @end table - @item -Wbool-compare @opindex Wno-bool-compare @opindex Wbool-compare @@ -5890,7 +5890,7 @@ Bounds Checker builtins}, for more information. @opindex fchkp-check-incomplete-type @opindex fno-chkp-check-incomplete-type Generate pointer bounds checks for variables with incomplete type. -Enabled by default. +Enabled by default. @item -fchkp-narrow-bounds @opindex fchkp-narrow-bounds @@ -18730,14 +18730,72 @@ Links in additional target libraries to support operation within a simulator. @item -mmul=none +@itemx -mmul=g10 @itemx -mmul=g13 +@itemx -mmul=g14 @itemx -mmul=rl78 @opindex mmul -Specifies the type of hardware multiplication support to be used. The -default is @samp{none}, which uses software multiplication functions. -The @samp{g13} option is for the hardware multiply/divide peripheral -only on the RL78/G13 targets. The @samp{rl78} option is for the -standard hardware multiplication defined in the RL78 software manual. +Specifies the type of hardware multiplication and division support to +be used. The simplest is @code{none}, which uses software for both +multiplication and division. This is the default. The @code{g13} +value is for the hardware multiply/divide peripheral found on the +RL78/G13 (S2 core) targets. The @code{g14} value selects the use of +the multiplication and division instructions supported by the RL78/G14 +(S3 core) parts. The value @code{rl78} is an alias for @code{g14} and +the value @code{mg10} is an alias for @code{none}. + +In addition a C preprocessor macro is defined, based upon the setting +of this option. Possible values are: @code{__RL78_MUL_NONE__}, +@code{__RL78_MUL_G13__} or @code{__RL78_MUL_G14__}. + +@item -mcpu=g10 +@itemx -mcpu=g13 +@itemx -mcpu=g14 +@itemx -mcpu=rl78 +@opindex mcpu +Specifies the RL78 core to target. The default is the G14 core, also +known as an S3 core or just RL78. The G13 or S2 core does not have +multiply or divide instructions, instead it uses a hardware peripheral +for these operations. The G10 or S1 core does not have register +banks, so it uses a different calling convention. + +If this option is set it also selects the type of hardware multiply +support to use, unless this is overridden by an explicit +@option{-mmul=none} option on the command line. Thus specifying +@option{-mcpu=g13} enables the use of the G13 hardware multiply +peripheral and specifying @option{-mcpu=g10} disables the use of +hardware multipications altogether. + +Note, although the RL78/G14 core is the default target, specifying +@option{-mcpu=g14} or @option{-mcpu=rl78} on the command line does +change the behaviour of the toolchain since it also enables G14 +hardware multiply support. If these options are not specified on the +command line then software multiplication routines will be used even +though the code targets the RL78 core. This is for backwards +compatibility with older toolchains which did not have hardware +multiply and divide support. + +In addition a C preprocessor macro is defined, based upon the setting +of this option. Possible values are: @code{__RL78_G10__}, +@code{__RL78_G13__} or @code{__RL78_G14__}. + +@item -mg10 +@itemx -mg13 +@itemx -mg14 +@itemx -mrl78 +@opindex mg10 +@opindex mg13 +@opindex mg14 +@opindex mrl78 +These are aliases for the corresponding @option{-mcpu=} option. They +are provided for backwards compatibility. + +@item -mallregs +@opindex mallregs +Allow the compiler to use all of the available registers. By default +registers @code{r24..r31} are reserved for use in interrupt handlers. +With this option enabled these registers can be used in ordinary +functions as well. @item -m64bit-doubles @itemx -m32bit-doubles diff --git a/gcc/testsuite/gcc.c-torture/execute/20101011-1.c b/gcc/testsuite/gcc.c-torture/execute/20101011-1.c index 34d03137e26..639d12de683 100644 --- a/gcc/testsuite/gcc.c-torture/execute/20101011-1.c +++ b/gcc/testsuite/gcc.c-torture/execute/20101011-1.c @@ -12,6 +12,18 @@ #elif defined (__sh__) /* On SH division by zero does not trap. */ # define DO_TEST 0 +#elif defined (__v850__) + /* On V850 division by zero does not trap. */ +# define DO_TEST 0 +#elif defined (__MSP430__) + /* On MSP430 division by zero does not trap. */ +# define DO_TEST 0 +#elif defined (__RL78__) + /* On RL78 division by zero does not trap. */ +# define DO_TEST 0 +#elif defined (__RX__) + /* On RX division by zero does not trap. */ +# define DO_TEST 0 #elif defined (__aarch64__) /* On AArch64 integer division by zero does not trap. */ # define DO_TEST 0 diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 611223ab645..a21afe86fc5 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,10 @@ +2015-04-16 Nick Clifton + + * config/rl78/divmodhi.S: Add G14 and G13 versions of the __divhi3 + and __modhi3 functions. + * config/rl78/divmodso.S: Add G14 and G13 versions of the + __divsi3, __udivsi3, __modsi3 and __umodsi3 functions. + 2015-04-15 Chen Gang * gthr-single.h (__GTHREAD_MUTEX_INIT_FUNCTION): Use empty diff --git a/libgcc/config/rl78/divmodhi.S b/libgcc/config/rl78/divmodhi.S index 4e5f3a2f1e6..adf91e2c9e6 100644 --- a/libgcc/config/rl78/divmodhi.S +++ b/libgcc/config/rl78/divmodhi.S @@ -25,6 +25,360 @@ #include "vregs.h" +#if defined __RL78_MUL_G14__ + +START_FUNC ___divhi3 + ;; r8 = 4[sp] / 6[sp] + + ;; Test for a negative denumerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw de, ax + bc $__div_neg_den + + ;; Test for a negative numerator. + movw ax, [sp+4] + mov1 cy, a.7 + bc $__div_neg_num + + ;; Neither are negative - we can use the unsigned divide instruction. +__div_no_convert: + push psw + di + divhu + pop psw + + movw r8, ax + ret + +__div_neg_den: + ;; Negate the denumerator (which is in DE) + clrw ax + subw ax, de + movw de, ax + + ;; Test for a negative numerator. + movw ax, [sp+4] + mov1 cy, a.7 + ;; If it is not negative then we perform the division and then negate the result. + bnc $__div_then_convert + + ;; Otherwise we negate the numerator and then go with an unsigned division. + movw bc, ax + clrw ax + subw ax, bc + br $__div_no_convert + +__div_neg_num: + ;; Negate the numerator (which is in AX) + ;; We know that the denumerator is positive. + movw bc, ax + clrw ax + subw ax, bc + +__div_then_convert: + push psw + di + divhu + pop psw + + ;; Negate result and transfer into r8 + movw bc, ax + clrw ax + subw ax, bc + movw r8, ax + ret + +END_FUNC ___divhi3 + +;---------------------------------------------------------------------- + +START_FUNC ___modhi3 + ;; r8 = 4[sp] % 6[sp] + + ;; Test for a negative denumerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw de, ax + bc $__mod_neg_den + + ;; Test for a negative numerator. + movw ax, [sp+4] + mov1 cy, a.7 + bc $__mod_neg_num + + ;; Neither are negative - we can use the unsigned divide instruction. +__mod_no_convert: + push psw + di + divhu + pop psw + + movw ax, de + movw r8, ax + ret + +__mod_neg_den: + ;; Negate the denumerator (which is in DE) + clrw ax + subw ax, de + movw de, ax + + ;; Test for a negative numerator. + movw ax, [sp+4] + mov1 cy, a.7 + ;; If it is not negative then we perform the modulo operation without conversion. + bnc $__mod_no_convert + + ;; Otherwise we negate the numerator and then go with an unsigned modulo operation. + movw bc, ax + clrw ax + subw ax, bc + br $__mod_then_convert + +__mod_neg_num: + ;; Negate the numerator (which is in AX) + ;; We know that the denumerator is positive. + movw bc, ax + clrw ax + subw ax, bc + +__mod_then_convert: + push psw + di + divhu + pop psw + + ;; Negate result and transfer into r8 + clrw ax + subw ax, de + movw r8, ax + ret + +END_FUNC ___modhi3 + +;---------------------------------------------------------------------- + +#elif defined __RL78_MUL_G13__ + + ;; The G13 S2 core does not have a 16 bit divide peripheral. + ;; So instead we perform a 32-bit divide and twiddle the inputs + ;; as necessary. + + ;; Hardware registers. Note - these values match the silicon, not the documentation. + MDAL = 0xffff0 + MDAH = 0xffff2 + MDBL = 0xffff6 + MDBH = 0xffff4 + MDCL = 0xf00e0 + MDCH = 0xf00e2 + MDUC = 0xf00e8 + +.macro _Negate src, dest + movw ax, !\src + movw bc, ax + clrw ax + subw ax, bc + movw \dest, ax +.endm + +;---------------------------------------------------------------------- + +START_FUNC ___divhi3 + ;; r8 = 4[sp] / 6[sp] (signed division) + + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 + mov !MDUC, a ; This preps the peripheral for division without interrupt generation + + clrw ax ; Clear the top 16-bits of the divisor and dividend + movw MDBH, ax + movw MDAH, ax + + ;; Load and test for a negative denumerator. + movw ax, [sp+6] + movw MDBL, ax + mov1 cy, a.7 + bc $__div_neg_den + + ;; Load and test for a negative numerator. + movw ax, [sp+4] + mov1 cy, a.7 + movw MDAL, ax + bc $__div_neg_num + + ;; Neither are negative - we can use the unsigned divide hardware. +__div_no_convert: + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, MDAL ; Read the result + movw r8, ax + ret + +__div_neg_den: + ;; Negate the denumerator (which is in MDBL) + _Negate MDBL MDBL + + ;; Load and test for a negative numerator. + movw ax, [sp+4] + mov1 cy, a.7 + movw MDAL, ax + ;; If it is not negative then we perform the division and then negate the result. + bnc $__div_then_convert + + ;; Otherwise we negate the numerator and then go with a straightforward unsigned division. + _Negate MDAL MDAL + br $!__div_no_convert + +__div_neg_num: + ;; Negate the numerator (which is in MDAL) + ;; We know that the denumerator is positive. + _Negate MDAL MDAL + +__div_then_convert: + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + ;; Negate result and transfer into r8 + _Negate MDAL r8 + ret + +END_FUNC ___divhi3 + +;---------------------------------------------------------------------- + +START_FUNC ___modhi3 + ;; r8 = 4[sp] % 6[sp] (signed modulus) + + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 + mov !MDUC, a ; This preps the peripheral for division without interrupt generation + + clrw ax ; Clear the top 16-bits of the divisor and dividend + movw MDBH, ax + movw MDAH, ax + + ;; Load and test for a negative denumerator. + movw ax, [sp+6] + movw MDBL, ax + mov1 cy, a.7 + bc $__mod_neg_den + + ;; Load and test for a negative numerator. + movw ax, [sp+4] + mov1 cy, a.7 + movw MDAL, ax + bc $__mod_neg_num + + ;; Neither are negative - we can use the unsigned divide hardware +__mod_no_convert: + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, !MDCL ; Read the remainder + movw r8, ax + ret + +__mod_neg_den: + ;; Negate the denumerator (which is in MDBL) + _Negate MDBL MDBL + + ;; Load and test for a negative numerator. + movw ax, [sp+4] + mov1 cy, a.7 + movw MDAL, ax + ;; If it is not negative then we perform the modulo operation without conversion. + bnc $__mod_no_convert + + ;; Otherwise we negate the numerator and then go with a modulo followed by negation. + _Negate MDAL MDAL + br $!__mod_then_convert + +__mod_neg_num: + ;; Negate the numerator (which is in MDAL) + ;; We know that the denumerator is positive. + _Negate MDAL MDAL + +__mod_then_convert: + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + _Negate MDCL r8 + ret + +END_FUNC ___modhi3 + +;---------------------------------------------------------------------- + +START_FUNC ___udivhi3 + ;; r8 = 4[sp] / 6[sp] (unsigned division) + + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 + mov !MDUC, a ; This preps the peripheral for division without interrupt generation + + movw ax, [sp+4] ; Load the divisor + movw MDAL, ax + movw ax, [sp+6] ; Load the dividend + movw MDBL, ax + clrw ax + movw MDAH, ax + movw MDBH, ax + + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, !MDAL ; Read the remainder + movw r8, ax + ret + +END_FUNC ___udivhi3 + +;---------------------------------------------------------------------- + +START_FUNC ___umodhi3 + ;; r8 = 4[sp] % 6[sp] (unsigned modulus) + + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 + mov !MDUC, a ; This preps the peripheral for division without interrupt generation + + movw ax, [sp+4] ; Load the divisor + movw MDAL, ax + movw ax, [sp+6] ; Load the dividend + movw MDBL, ax + clrw ax + movw MDAH, ax + movw MDBH, ax + + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, !MDCL ; Read the remainder + movw r8, ax + ret + +END_FUNC ___umodhi3 + +;---------------------------------------------------------------------- + +#elif defined __RL78_MUL_NONE__ + .macro MAKE_GENERIC which,need_result .if \need_result @@ -328,3 +682,11 @@ mod_no_neg: mod_skip_restore_den: ret END_FUNC ___modhi3 + +;---------------------------------------------------------------------- + +#else + +#error "Unknown RL78 hardware multiply/divide support" + +#endif diff --git a/libgcc/config/rl78/divmodsi.S b/libgcc/config/rl78/divmodsi.S index 7acaa86340b..987a9e31126 100644 --- a/libgcc/config/rl78/divmodsi.S +++ b/libgcc/config/rl78/divmodsi.S @@ -25,6 +25,537 @@ #include "vregs.h" +#if defined __RL78_MUL_G14__ + +START_FUNC ___divsi3 + ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp] + + ;; Load and test for a negative denumerator. + movw ax, [sp+8] + movw de, ax + movw ax, [sp+10] + mov1 cy, a.7 + movw hl, ax + bc $__div_neg_den + + ;; Load and test for a negative numerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw bc, ax + movw ax, [sp+4] + bc $__div_neg_num + + ;; Neither are negative - we can use the unsigned divide instruction. +__div_no_convert: + push psw + di + divwu + pop psw + + movw r8, ax + movw ax, bc + movw r10, ax + ret + +__div_neg_den: + ;; Negate the denumerator (which is in HLDE) + clrw ax + subw ax, de + movw de, ax + clrw ax + sknc + decw ax + subw ax, hl + movw hl, ax + + ;; Load and test for a negative numerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw bc, ax + movw ax, [sp+4] + ;; If it is not negative then we perform the division and then negate the result. + bnc $__div_then_convert + + ;; Otherwise we negate the numerator and then go with a straightforward unsigned division. + ;; The negation is complicated because AX, BC, DE and HL are already in use. + ;; ax: numL bc: numH r8: r10: + xchw ax, bc + ;; ax: numH bc: numL r8: r10: + movw r8, ax + ;; ax: bc: numL r8: numH r10: + clrw ax + ;; ax: 0 bc: numL r8: numH r10: + subw ax, bc + ;; ax: -numL bc: r8: numH r10: + movw r10, ax + ;; ax: bc: r8: numH r10: -numL + movw ax, r8 + ;; ax: numH bc: r8: r10: -numL + movw bc, ax + ;; ax: bc: numH r8: r10: -numL + clrw ax + ;; ax: 0 bc: numH r8: r10: -numL + sknc + decw ax + ;; ax: -1 bc: numH r8: r10: -numL + subw ax, bc + ;; ax: -numH bc: r8: r10: -numL + movw bc, ax + ;; ax: bc: -numH r8: r10: -numL + movw ax, r10 + ;; ax: -numL bc: -numH r8: r10: + br $!__div_no_convert + +__div_neg_num: + ;; Negate the numerator (which is in BCAX) + ;; We know that the denumerator is positive. + ;; Note - we temporarily overwrite DE. We know that we can safely load it again off the stack again. + movw de, ax + clrw ax + subw ax, de + movw de, ax + clrw ax + sknc + decw ax + subw ax, bc + movw bc, ax + + movw ax, [sp+8] + xchw ax, de + +__div_then_convert: + push psw + di + divwu + pop psw + + ;; Negate result (in BCAX) and transfer into r8,r10 + movw de, ax + clrw ax + subw ax, de + movw r8, ax + clrw ax + sknc + decw ax + subw ax, bc + movw r10, ax + ret + +END_FUNC ___divsi3 + +;---------------------------------------------------------------------- + +START_FUNC ___udivsi3 + ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp] + ;; Used when compiling with -Os specified. + + movw ax, [sp+10] + movw hl, ax + movw ax, [sp+8] + movw de, ax + movw ax, [sp+6] + movw bc, ax + movw ax, [sp+4] + push psw ; Save the current interrupt status + di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E + divwu ; bcax = bcax / hlde + pop psw ; Restore saved interrupt status + movw r8, ax + movw ax, bc + movw r10, ax + ret + +END_FUNC ___udivsi3 + +;---------------------------------------------------------------------- + +START_FUNC ___modsi3 + ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp] + + ;; Load and test for a negative denumerator. + movw ax, [sp+8] + movw de, ax + movw ax, [sp+10] + mov1 cy, a.7 + movw hl, ax + bc $__mod_neg_den + + ;; Load and test for a negative numerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw bc, ax + movw ax, [sp+4] + bc $__mod_neg_num + + ;; Neither are negative - we can use the unsigned divide instruction. +__mod_no_convert: + push psw + di + divwu + pop psw + + movw ax, de + movw r8, ax + movw ax, hl + movw r10, ax + ret + +__mod_neg_den: + ;; Negate the denumerator (which is in HLDE) + clrw ax + subw ax, de + movw de, ax + clrw ax + sknc + decw ax + subw ax, hl + movw hl, ax + + ;; Load and test for a negative numerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw bc, ax + movw ax, [sp+4] + ;; If it is not negative then we perform the modulo operation without conversion + bnc $__mod_no_convert + + ;; Otherwise we negate the numerator and then go with a modulo followed by negation. + ;; The negation is complicated because AX, BC, DE and HL are already in use. + xchw ax, bc + movw r8, ax + clrw ax + subw ax, bc + movw r10, ax + movw ax, r8 + movw bc, ax + clrw ax + sknc + decw ax + subw ax, bc + movw bc, ax + movw ax, r10 + br $!__mod_then_convert + +__mod_neg_num: + ;; Negate the numerator (which is in BCAX) + ;; We know that the denumerator is positive. + ;; Note - we temporarily overwrite DE. We know that we can safely load it again off the stack again. + movw de, ax + clrw ax + subw ax, de + movw de, ax + clrw ax + sknc + decw ax + subw ax, bc + movw bc, ax + + movw ax, [sp+8] + xchw ax, de + +__mod_then_convert: + push psw + di + divwu + pop psw + + ;; Negate result (in HLDE) and transfer into r8,r10 + clrw ax + subw ax, de + movw r8, ax + clrw ax + sknc + decw ax + subw ax, hl + movw r10, ax + ret + +END_FUNC ___modsi3 + +;---------------------------------------------------------------------- + +START_FUNC ___umodsi3 + ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp] + ;; Used when compiling with -Os specified. + + movw ax, [sp+10] + movw hl, ax + movw ax, [sp+8] + movw de, ax + movw ax, [sp+6] + movw bc, ax + movw ax, [sp+4] + push psw ; Save the current interrupt status + di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E + divwu ; hlde = bcax %% hlde + pop psw ; Restore saved interrupt status + movw ax, de + movw r8, ax + movw ax, hl + movw r10, ax + ret + +END_FUNC ___umodsi3 + +;---------------------------------------------------------------------- + +#elif defined __RL78_MUL_G13__ + +;---------------------------------------------------------------------- + + ;; Hardware registers. Note - these values match the silicon, not the documentation. + MDAL = 0xffff0 + MDAH = 0xffff2 + MDBL = 0xffff6 + MDBH = 0xffff4 + MDCL = 0xf00e0 + MDCH = 0xf00e2 + MDUC = 0xf00e8 + +.macro _Negate low, high + movw ax, \low + movw bc, ax + clrw ax + subw ax, bc + movw \low, ax + movw ax, \high + movw bc, ax + clrw ax + sknc + decw ax + subw ax, bc + movw \high, ax +.endm + +;---------------------------------------------------------------------- + +START_FUNC ___divsi3 + ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp] + + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 + mov !MDUC, a ; This preps the peripheral for division without interrupt generation + + ;; Load and test for a negative denumerator. + movw ax, [sp+8] + movw MDBL, ax + movw ax, [sp+10] + mov1 cy, a.7 + movw MDBH, ax + bc $__div_neg_den + + ;; Load and test for a negative numerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw MDAH, ax + movw ax, [sp+4] + movw MDAL, ax + bc $__div_neg_num + + ;; Neither are negative - we can use the unsigned divide hardware. +__div_no_convert: + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, MDAL ; Read the result + movw r8, ax + movw ax, MDAH + movw r10, ax + ret + +__div_neg_den: + ;; Negate the denumerator (which is in MDBL/MDBH) + _Negate MDBL MDBH + + ;; Load and test for a negative numerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw MDAH, ax + movw ax, [sp+4] + movw MDAL, ax + ;; If it is not negative then we perform the division and then negate the result. + bnc $__div_then_convert + + ;; Otherwise we negate the numerator and then go with a straightforward unsigned division. + _Negate MDAL MDAH + br $!__div_no_convert + +__div_neg_num: + ;; Negate the numerator (which is in MDAL/MDAH) + ;; We know that the denumerator is positive. + _Negate MDAL MDAH + +__div_then_convert: + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + ;; Negate result and transfer into r8,r10 + _Negate MDAL MDAH ; FIXME: This could be coded more efficiently. + movw r10, ax + movw ax, MDAL + movw r8, ax + + ret + +END_FUNC ___divsi3 + +;---------------------------------------------------------------------- + +START_FUNC ___modsi3 + ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp] + + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 + mov !MDUC, a ; This preps the peripheral for division without interrupt generation + + ;; Load and test for a negative denumerator. + movw ax, [sp+8] + movw MDBL, ax + movw ax, [sp+10] + mov1 cy, a.7 + movw MDBH, ax + bc $__mod_neg_den + + ;; Load and test for a negative numerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw MDAH, ax + movw ax, [sp+4] + movw MDAL, ax + bc $__mod_neg_num + + ;; Neither are negative - we can use the unsigned divide hardware +__mod_no_convert: + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, !MDCL ; Read the remainder + movw r8, ax + movw ax, !MDCH + movw r10, ax + ret + +__mod_neg_den: + ;; Negate the denumerator (which is in MDBL/MDBH) + _Negate MDBL MDBH + + ;; Load and test for a negative numerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw MDAH, ax + movw ax, [sp+4] + movw MDAL, ax + ;; If it is not negative then we perform the modulo operation without conversion + bnc $__mod_no_convert + + ;; Otherwise we negate the numerator and then go with a modulo followed by negation. + _Negate MDAL MDAH + br $!__mod_then_convert + +__mod_neg_num: + ;; Negate the numerator (which is in MDAL/MDAH) + ;; We know that the denumerator is positive. + _Negate MDAL MDAH + +__mod_then_convert: + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, !MDCL + movw bc, ax + clrw ax + subw ax, bc + movw r8, ax + movw ax, !MDCH + movw bc, ax + clrw ax + sknc + decw ax + subw ax, bc + movw r10, ax + ret + +END_FUNC ___modsi3 + +;---------------------------------------------------------------------- + +START_FUNC ___udivsi3 + ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp] + ;; Used when compilng with -Os specified. + + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 + mov !MDUC, a ; This preps the peripheral for division without interrupt generation + + movw ax, [sp+4] ; Load the divisor + movw MDAL, ax + movw ax, [sp+6] + movw MDAH, ax + movw ax, [sp+8] ; Load the dividend + movw MDBL, ax + movw ax, [sp+10] + movw MDBH, ax + + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, !MDAL ; Read the result + movw r8, ax + movw ax, !MDAH + movw r10, ax + ret + +END_FUNC ___udivsi3 + +;---------------------------------------------------------------------- + +START_FUNC ___umodsi3 + ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp] + ;; Used when compilng with -Os specified. + ;; Note - hardware address match the silicon, not the documentation + + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 + mov !MDUC, a ; This preps the peripheral for division without interrupt generation + + movw ax, [sp+4] ; Load the divisor + movw MDAL, ax + movw ax, [sp+6] + movw MDAH, ax + movw ax, [sp+8] ; Load the dividend + movw MDBL, ax + movw ax, [sp+10] + movw MDBH, ax + + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, !MDCL ; Read the remainder + movw r8, ax + movw ax, !MDCH + movw r10, ax + ret + +END_FUNC ___umodsi3 + +;---------------------------------------------------------------------- + +#elif defined __RL78_MUL_NONE__ + .macro MAKE_GENERIC which,need_result .if \need_result @@ -67,6 +598,8 @@ bitB2 = bit+2 bitB3 = bit+3 +;---------------------------------------------------------------------- + START_FUNC __generic_sidivmod\which num_lt_den\which: @@ -533,3 +1066,11 @@ mod_skip_restore_den: .endif ret END_FUNC ___modsi3 + +;---------------------------------------------------------------------- + +#else + +#error "Unknown RL78 hardware multiply/divide support" + +#endif -- 2.30.2