+2015-04-16 Nick Clifton <nickc@redhat.com>
+
+ * 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 <rguenther@suse.de>
* tree-ssa-ccp.c (likely_value): See if we have operands that
* 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 <amodra@gmail.com>
PR target/65408
{
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
;; 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 ------------------------
)
(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"
)
(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"
&& 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,
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;
break;
case VALLOC_UMUL:
rl78_alloc_physical_registers_umul (insn);
+ record_content (AX, NULL_RTX);
break;
case VALLOC_MACAX:
/* Macro that clobbers AX. */
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 ();
}
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
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);
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);
}
}
{
if (LABEL_P (insn))
break;
-
+
if (! INSN_P (insn))
continue;
\f
#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)
#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
*/
#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 \
)
(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
""
)
(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"
(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
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
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
[(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
; 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")]
+)
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
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)
# 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
-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
-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
-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
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}
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.
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.
false positives and is deactivated by default.
@end table
-
@item -Wbool-compare
@opindex Wno-bool-compare
@opindex Wbool-compare
@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
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
#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
+2015-04-16 Nick Clifton <nickc@redhat.com>
+
+ * 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 <gang.chen.5i5j@gmail.com>
* gthr-single.h (__GTHREAD_MUTEX_INIT_FUNCTION): Use empty
#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
mod_skip_restore_den:
ret
END_FUNC ___modhi3
+
+;----------------------------------------------------------------------
+
+#else
+
+#error "Unknown RL78 hardware multiply/divide support"
+
+#endif
#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
bitB2 = bit+2
bitB3 = bit+3
+;----------------------------------------------------------------------
+
START_FUNC __generic_sidivmod\which
num_lt_den\which:
.endif
ret
END_FUNC ___modsi3
+
+;----------------------------------------------------------------------
+
+#else
+
+#error "Unknown RL78 hardware multiply/divide support"
+
+#endif