1 ;; Machine Description for Renesas RL78 processors
2 ;; Copyright (C) 2011-2017 Free Software Foundation, Inc.
3 ;; Contributed by Red Hat.
5 ;; This file is part of GCC.
7 ;; GCC is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation; either version 3, or (at your option)
12 ;; GCC is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;; GNU General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with GCC; see the file COPYING3. If not see
19 ;; <http://www.gnu.org/licenses/>.
50 (UNS_TRAMPOLINE_INIT 20)
51 (UNS_TRAMPOLINE_UNINIT 21)
52 (UNS_NONLOCAL_GOTO 22)
62 (define_mode_iterator QHI [QI HI])
64 (include "predicates.md")
65 (include "constraints.md")
66 (include "rl78-expand.md")
67 (include "rl78-virt.md")
68 (include "rl78-real.md")
70 (define_attr "is_g13_muldiv_insn" "yes,no" (const_string "no"))
72 ;; Function Prologue/Epilogue Instructions
74 (define_expand "prologue"
77 "rl78_expand_prologue (); DONE;"
80 (define_expand "epilogue"
83 "rl78_expand_epilogue (); DONE;"
86 (define_expand "sibcall_epilogue"
92 (define_insn "rl78_return"
98 (define_insn "interrupt_return"
99 [(unspec_volatile [(return)] UNS_RETI) ]
104 (define_insn "brk_interrupt_return"
105 [(unspec_volatile [(return)] UNS_RETB) ]
110 (define_expand "eh_return"
111 [(match_operand:HI 0 "")]
113 "rl78_expand_eh_epilogue (operands[0]);
118 ;; These are used only by prologue/epilogue so it's "safe" to pass
119 ;; virtual registers.
121 [(set (reg:HI SP_REG)
122 (plus:HI (reg:HI SP_REG)
124 (set (mem:HI (reg:HI SP_REG))
125 (match_operand:HI 0 "register_operand" "ABDT,vZint"))]
133 [(set (match_operand:HI 0 "register_operand" "=ABDT,vZint")
134 (mem:HI (reg:HI SP_REG)))
136 (plus:HI (reg:HI SP_REG)
144 (define_insn "sel_rb"
145 [(unspec_volatile [(match_operand 0 "immediate_operand" "")] UNS_SET_RB)]
150 (define_insn "trampoline_init"
151 [(set (match_operand 0 "register_operand" "=Z08W")
152 (unspec_volatile [(match_operand 1 "register_operand" "Z08W")
153 (match_operand 2 "register_operand" "Z10W")
154 ] UNS_TRAMPOLINE_INIT))
157 "call !!___trampoline_init ; %0 <= %1 %2"
160 (define_insn "trampoline_uninit"
161 [(unspec_volatile [(const_int 0)] UNS_TRAMPOLINE_UNINIT)
164 "call !!___trampoline_uninit"
167 ;; GCC restores $fp *before* using it to access values on the *old*
168 ;; frame. So, we do it ourselves, to ensure this is not the case.
169 ;; Note that while %1 is usually a label_ref, we allow for a
170 ;; non-immediate as well.
171 (define_expand "nonlocal_goto"
173 (unspec_volatile [(match_operand 0 "") ;; fp (ignore)
174 (match_operand 1 "") ;; target
175 (match_operand 2 "") ;; sp
176 (match_operand 3 "") ;; ?
177 ] UNS_NONLOCAL_GOTO))
180 "emit_jump_insn (gen_nonlocal_goto_insn (operands[0], operands[1], operands[2], operands[3]));
185 (define_insn "nonlocal_goto_insn"
187 (unspec_volatile [(match_operand 0 "" "") ;; fp (ignore)
188 (match_operand 1 "" "vi") ;; target
189 (match_operand 2 "" "vi") ;; sp
190 (match_operand 3 "" "vi") ;; ?
191 ] UNS_NONLOCAL_GOTO))
204 (define_expand "es_addr"
205 [(unspec:SI [(reg:QI ES_REG)
206 (match_operand:HI 0 "")
212 ;;======================================================================
214 ;; "macro" insns - cases where inline chunks of code are more
215 ;; efficient than anything else.
217 (define_expand "addsi3"
218 [(set (match_operand:SI 0 "nonimmediate_operand" "=&vm")
219 (plus:SI (match_operand:SI 1 "general_operand" "vim")
220 (match_operand 2 "general_operand" "vim")))
223 "emit_insn (gen_addsi3_internal_virt (operands[0], operands[1], operands[2]));
227 (define_insn "addsi3_internal_virt"
228 [(set (match_operand:SI 0 "nonimmediate_operand" "=v,&vm, vm")
229 (plus:SI (match_operand:SI 1 "general_operand" "0, vim, vim")
230 (match_operand 2 "general_operand" "vim,vim,vim")))
231 (clobber (reg:HI AX_REG))
232 (clobber (reg:HI BC_REG))
234 "rl78_virt_insns_ok ()"
236 [(set_attr "valloc" "macax")]
239 (define_insn "addsi3_internal_real"
240 [(set (match_operand:SI 0 "nonimmediate_operand" "=v,&vU, vU")
241 (plus:SI (match_operand:SI 1 "general_operand" "+0, viU, viU")
242 (match_operand 2 "general_operand" "viWabWhlWh1,viWabWhlWh1,viWabWhlWh1")))
243 (clobber (reg:HI AX_REG))
244 (clobber (reg:HI BC_REG))
246 "rl78_real_insns_ok ()"
247 { return rl78_addsi3_internal (operands, which_alternative); }
248 [(set_attr "valloc" "macax")]
251 (define_expand "subsi3"
252 [(set (match_operand:SI 0 "nonimmediate_operand")
253 (minus:SI (match_operand:SI 1 "general_operand")
254 (match_operand 2 "general_operand")))
257 "emit_insn (gen_subsi3_internal_virt (operands[0], operands[1], operands[2]));
261 (define_insn "subsi3_internal_virt"
262 [(set (match_operand:SI 0 "nonimmediate_operand" "=v,&vm, vm")
263 (minus:SI (match_operand:SI 1 "general_operand" "0, vim, vim")
264 (match_operand 2 "general_operand" "vim,vim,vim")))
265 (clobber (reg:HI AX_REG))
266 (clobber (reg:HI BC_REG))
268 "rl78_virt_insns_ok ()"
270 [(set_attr "valloc" "macax")]
273 (define_insn "subsi3_internal_real"
274 [(set (match_operand:SI 0 "nonimmediate_operand" "=v,&vU, vU")
275 (minus:SI (match_operand:SI 1 "general_operand" "+0, viU, viU")
276 (match_operand 2 "general_operand" "viWabWhlWh1,viWabWhlWh1,viWabWhlWh1")))
277 (clobber (reg:HI AX_REG))
278 (clobber (reg:HI BC_REG))
280 "rl78_real_insns_ok ()"
282 movw ax,%h1 \;subw ax,%h2 \;movw %h0, ax \;movw ax,%H1 \;sknc \;decw ax \;subw ax,%H2 \;movw %H0,ax
283 movw ax,%h1 \;subw ax,%h2 \;movw %h0, ax \;movw ax,%H1 \;sknc \;decw ax \;subw ax,%H2 \;movw %H0,ax
284 movw ax,%h1 \;subw ax,%h2 \;movw bc, ax \;movw ax,%H1 \;sknc \;decw ax \;subw ax,%H2 \;movw %H0,ax \;movw ax,bc \;movw %h0, ax"
285 [(set_attr "valloc" "macax")]
288 (define_expand "mulqi3"
290 [(set (match_operand:QI 0 "register_operand")
291 (mult:QI (match_operand:QI 1 "general_operand")
292 (match_operand:QI 2 "nonmemory_operand")))
293 (clobber (reg:HI AX_REG))
296 "" ; mulu supported by all targets
300 (define_expand "mulhi3"
301 [(set (match_operand:HI 0 "register_operand")
302 (mult:HI (match_operand:HI 1 "general_operand")
303 (match_operand:HI 2 "nonmemory_operand")))
308 emit_insn (gen_mulhi3_g14 (operands[0], operands[1], operands[2]));
309 else /* RL78_MUL_G13 */
310 emit_insn (gen_mulhi3_g13 (operands[0], operands[1], operands[2]));
315 (define_expand "mulsi3"
316 [(set (match_operand:SI 0 "register_operand")
317 (mult:SI (match_operand:SI 1 "general_operand")
318 (match_operand:SI 2 "nonmemory_operand")))
323 emit_insn (gen_mulsi3_g14 (operands[0], operands[1], operands[2]));
324 else /* RL78_MUL_G13 */
325 emit_insn (gen_mulsi3_g13 (operands[0], operands[1], operands[2]));
330 (define_insn "*mulqi3_rl78"
331 [(set (match_operand:QI 0 "register_operand" "=&v")
332 (mult:QI (match_operand:QI 1 "general_operand" "viU")
333 (match_operand:QI 2 "general_operand" "vi")))
334 (clobber (reg:HI AX_REG))
336 "" ; mulu supported by all targets
337 "; mulqi macro %0 = %1 * %2
344 ; end of mulqi macro"
345 [(set_attr "valloc" "macax")]
348 (define_insn "mulhi3_g14"
349 [(set (match_operand:HI 0 "register_operand" "=&v")
350 (mult:HI (match_operand:HI 1 "general_operand" "viU")
351 (match_operand:HI 2 "general_operand" "vi")))
352 (clobber (reg:HI AX_REG))
353 (clobber (reg:HI BC_REG))
356 "; G14 mulhi macro %0 = %1 * %2
359 mulhu ; bcax = bc * ax
361 ; end of mulhi macro"
362 [(set_attr "valloc" "macax")]
365 (define_insn "mulhi3_g13"
366 [(set (match_operand:HI 0 "register_operand" "=&v")
367 (mult:HI (match_operand:HI 1 "general_operand" "viU")
368 (match_operand:HI 2 "general_operand" "vi")))
369 (clobber (reg:HI AX_REG))
372 "; G13 mulhi macro %0 = %1 * %2
374 mov !0xf00e8, a ; MDUC
376 movw 0xffff0, ax ; MDAL
378 movw 0xffff2, ax ; MDAH
379 nop ; mdb = mdal * mdah
380 movw ax, 0xffff6 ; MDBL
382 ; end of mulhi macro"
383 [(set_attr "valloc" "macax")
384 (set_attr "is_g13_muldiv_insn" "yes")]
387 ;; 0xFFFF0 is MACR(L). 0xFFFF2 is MACR(H) but we don't care about it
388 ;; because we're only using the lower 16 bits (which is the upper 16
389 ;; bits of the result).
390 (define_insn "mulsi3_g14"
391 [(set (match_operand:SI 0 "register_operand" "=&v")
392 (mult:SI (match_operand:SI 1 "general_operand" "viU")
393 (match_operand:SI 2 "general_operand" "vi")))
394 (clobber (reg:HI AX_REG))
395 (clobber (reg:HI BC_REG))
398 "; G14 mulsi macro %0 = %1 * %2
401 MULHU ; bcax = bc * ax
407 MACHU ; MACR += bc * ax
410 MACHU ; MACR += bc * ax
413 ; end of mulsi macro"
414 [(set_attr "valloc" "macax")]
417 ;; 0xFFFF0 is MDAL. 0xFFFF2 is MDAH.
418 ;; 0xFFFF6 is MDBL. 0xFFFF4 is MDBH.
419 ;; 0xF00E0 is MDCL. 0xF00E2 is MDCH.
421 ;; Warning: this matches the silicon not the documentation.
422 (define_insn "mulsi3_g13"
423 [(set (match_operand:SI 0 "register_operand" "=&v")
424 (mult:SI (match_operand:SI 1 "general_operand" "viU")
425 (match_operand:SI 2 "general_operand" "viU")))
426 (clobber (reg:HI AX_REG))
427 (clobber (reg:HI BC_REG))
430 "; G13 mulsi macro %0 = %1 * %2
432 mov !0xf00e8, a ; MDUC
434 movw 0xffff0, ax ; MDAL
436 movw 0xffff2, ax ; MDAH
437 nop ; mdb = mdal * mdah
438 movw ax, 0xffff6 ; MDBL
442 mov !0xf00e8, a ; MDUC
443 movw ax, 0xffff4 ; MDBH
444 movw !0xf00e0, ax ; MDCL
446 movw !0xf00e2, ax ; MDCL
448 movw 0xffff0, ax ; MDAL
450 movw 0xffff2, ax ; MDAH
451 nop ; mdc += mdal * mdah
454 mov !0xf00e8, a ; MDUC
456 movw 0xffff0, ax ; MDAL
458 movw 0xffff2, ax ; MDAH
459 nop ; mdc += mdal * mdah
460 nop ; Additional nop for MAC
461 movw ax, !0xf00e0 ; MDCL
463 ; end of mulsi macro"
464 [(set_attr "valloc" "macax")
465 (set_attr "is_g13_muldiv_insn" "yes")]
468 (define_expand "udivmodhi4"
470 [(set (match_operand:HI 0 "register_operand")
471 (udiv:HI (match_operand:HI 1 "register_operand")
472 (match_operand:HI 2 "register_operand")))
473 (set (match_operand:HI 3 "register_operand")
474 (umod:HI (match_dup 1) (match_dup 2)))
475 (clobber (reg:HI AX_REG))
476 (clobber (reg:HI DE_REG))
483 (define_insn "*udivmodhi4_g14"
484 [(set (match_operand:HI 0 "register_operand" "=v")
485 (udiv:HI (match_operand:HI 1 "register_operand" "v")
486 (match_operand:HI 2 "register_operand" "v")))
487 (set (match_operand:HI 3 "register_operand" "=v")
488 (umod:HI (match_dup 1) (match_dup 2)))
489 (clobber (reg:HI AX_REG))
490 (clobber (reg:HI DE_REG))
494 if (find_reg_note (insn, REG_UNUSED, operands[3]))
495 return "; G14 udivhi macro %0 = %1 / %2 \n\
498 push psw ; Save the current interrupt status \n\
499 di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
500 divhu ; ax = ax / de \n\
501 pop psw ; Restore saved interrupt status \n\
503 ; end of udivhi macro";
504 else if (find_reg_note (insn, REG_UNUSED, operands[0]))
505 return "; G14 umodhi macro %3 = %1 %% %2 \n\
508 push psw ; Save the current interrupt status \n\
509 di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
510 divhu ; de = ax %% de \n\
511 pop psw ; Restore saved interrupt status \n\
514 ; end of umodhi macro";
516 return "; G14 udivmodhi macro %0 = %1 / %2 and %3 = %1 %% %2 \n\
519 push psw ; Save the current interrupt status \n\
520 di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
521 divhu ; ax = ax / de, de = ax %% de \n\
522 pop psw ; Restore saved interrupt status \n\
526 ; end of udivmodhi macro";
528 [(set_attr "valloc" "divhi")]
531 (define_expand "udivmodsi4"
533 [(set (match_operand:SI 0 "register_operand")
534 (udiv:SI (match_operand:SI 1 "register_operand")
535 (match_operand:SI 2 "register_operand")))
536 (set (match_operand:SI 3 "register_operand")
537 (umod:SI (match_dup 1) (match_dup 2)))
540 "! RL78_MUL_NONE && ! optimize_size"
543 emit_insn (gen_udivmodsi4_g14 (operands[0], operands[1], operands[2], operands[3]));
544 else /* RL78_MUL_G13 */
545 emit_insn (gen_udivmodsi4_g13 (operands[0], operands[1], operands[2], operands[3]));
550 (define_insn "udivmodsi4_g14"
551 [(set (match_operand:SI 0 "register_operand" "=v")
552 (udiv:SI (match_operand:SI 1 "register_operand" "v")
553 (match_operand:SI 2 "register_operand" "v")))
554 (set (match_operand:SI 3 "register_operand" "=v")
555 (umod:SI (match_dup 1) (match_dup 2)))
556 (clobber (reg:HI AX_REG))
557 (clobber (reg:HI BC_REG))
558 (clobber (reg:HI DE_REG))
559 (clobber (reg:HI HL_REG))
563 if (find_reg_note (insn, REG_UNUSED, operands[3]))
564 return "; G14 udivsi macro %0 = %1 / %2 \n\
569 push psw ; Save the current interrupt status \n\
570 di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
571 divwu ; bcax = bcax / hlde \n\
572 pop psw ; Restore saved interrupt status \n\
576 ; end of udivsi macro";
577 else if (find_reg_note (insn, REG_UNUSED, operands[0]))
578 return "; G14 umodsi macro %3 = %1 %% %2 \n\
583 push psw ; Save the current interrupt status \n\
584 di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
585 divwu ; hlde = bcax %% hlde \n\
586 pop psw ; Restore saved interrupt status \n\
591 ; end of umodsi macro";
593 return "; G14 udivmodsi macro %0 = %1 / %2 and %3 = %1 %% %2 \n\
598 push psw ; Save the current interrupt status \n\
599 di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
600 divwu ; bcax = bcax / hlde, hlde = bcax %% hlde \n\
601 pop psw ; Restore saved interrupt status \n\
609 ; end of udivmodsi macro";
611 [(set_attr "valloc" "divsi")]
614 ;; Warning: these values match the silicon not the documentation.
615 ;; 0xFFFF0 is MDAL. 0xFFFF2 is MDAH.
616 ;; 0xFFFF6 is MDBL. 0xFFFF4 is MDBH.
617 ;; 0xF00E0 is MDCL. 0xF00E2 is MDCH.
620 (define_insn "udivmodsi4_g13"
621 [(set (match_operand:SI 0 "register_operand" "=v")
622 (udiv:SI (match_operand:SI 1 "register_operand" "v")
623 (match_operand:SI 2 "register_operand" "v")))
624 (set (match_operand:SI 3 "register_operand" "=v")
625 (umod:SI (match_dup 1) (match_dup 2)))
626 (clobber (reg:HI AX_REG))
630 if (find_reg_note (insn, REG_UNUSED, operands[3]))
631 return "; G13 udivsi macro %0 = %1 / %2 \n\
632 mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 \n\
633 mov !0xf00e8, a ; This preps the peripheral for division without interrupt generation \n\
635 movw 0xffff2, ax ; MDAH \n\
637 movw 0xffff0, ax ; MDAL \n\
639 movw 0xffff4, ax ; MDBH \n\
641 movw 0xffff6, ax ; MDBL \n\
642 mov a, #0xC1 ; Set the DIVST bit in MDUC \n\
643 mov !0xf00e8, a ; This starts the division op \n\
644 1: mov a, !0xf00e8 ; Wait 16 clocks or until DIVST is clear \n\
646 movw ax, 0xffff0 ; Read the quotient \n\
650 ; end of udivsi macro";
651 else if (find_reg_note (insn, REG_UNUSED, operands[0]))
652 return "; G13 umodsi macro %3 = %1 %% %2 \n\
653 mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 \n\
654 mov !0xf00e8, a ; This preps the peripheral for division without interrupt generation \n\
656 movw 0xffff2, ax ; MDAH \n\
658 movw 0xffff0, ax ; MDAL \n\
660 movw 0xffff4, ax ; MDBH \n\
662 movw 0xffff6, ax ; MDBL \n\
663 mov a, #0xC1 ; Set the DIVST bit in MDUC \n\
664 mov !0xf00e8, a ; This starts the division op \n\
665 1: mov a, !0xf00e8 ; Wait 16 clocks or until DIVST is clear \n\
667 movw ax, !0xf00e0 ; Read the remainder \n\
669 movw ax, !0xf00e2 \n\
671 ; end of umodsi macro";
673 return "; G13 udivmodsi macro %0 = %1 / %2 and %3 = %1 %% %2 \n\
674 mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 \n\
675 mov !0xf00e8, a ; This preps the peripheral for division without interrupt generation \n\
677 movw 0xffff2, ax ; MDAH \n\
679 movw 0xffff0, ax ; MDAL \n\
681 movw 0xffff4, ax ; MDBH \n\
683 movw 0xffff6, ax ; MDBL \n\
684 mov a, #0xC1 ; Set the DIVST bit in MDUC \n\
685 mov !0xf00e8, a ; This starts the division op \n\
686 1: mov a, !0xf00e8 ; Wait 16 clocks or until DIVST is clear \n\
688 movw ax, 0xffff0 ; Read the quotient \n\
692 movw ax, !0xf00e0 ; Read the remainder \n\
694 movw ax, !0xf00e2 \n\
696 ; end of udivmodsi macro";
698 [(set_attr "valloc" "macax")
699 (set_attr "is_g13_muldiv_insn" "yes")]