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
This commit is contained in:
Nick Clifton 2015-04-16 07:57:56 +00:00 committed by Nick Clifton
parent 8a474dc5d7
commit 72ed112686
13 changed files with 1497 additions and 61 deletions

View File

@ -1,3 +1,39 @@
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
@ -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 <amodra@gmail.com>
PR target/65408

View File

@ -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

View File

@ -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"

View File

@ -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;

View File

@ -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 \

View File

@ -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")]
)

View File

@ -27,21 +27,24 @@ 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)
EnumValue
Enum(rl78_mul_types) String(rl78) Value(MUL_RL78)
Enum(rl78_mul_types) String(g10) Value(MUL_NONE)
EnumValue
Enum(rl78_mul_types) String(g13) Value(MUL_G13)
EnumValue
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
Use all registers, reserving none for interrupt handlers.
@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,3 +1,10 @@
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

View File

@ -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

View File

@ -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