;; Machine Description for Renesas RL78 processors ;; Copyright (C) 2011 Free Software Foundation, Inc. ;; Contributed by Red Hat. ;; This file is part of GCC. ;; GCC is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. ;; GCC is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GCC; see the file COPYING3. If not see ;; . (define_constants [ (AX_REG 0) (X_REG 0) (A_REG 1) (BC_REG 2) (C_REG 2) (B_REG 3) (DE_REG 4) (E_REG 4) (D_REG 5) (HL_REG 6) (L_REG 6) (H_REG 7) (FP_REG 22) (SP_REG 32) (CC_REG 33) (ES_REG 35) (CS_REG 36) (UNS_PROLOG 1) (UNS_EPILOG 1) (UNS_RETI 2) (UNS_RETB 3) (UNS_SET_RB 10) (UNS_TRAMPOLINE_INIT 20) (UNS_TRAMPOLINE_UNINIT 21) (UNS_NONLOCAL_GOTO 22) ]) (define_insn "nop" [(const_int 0)] "" "nop" ) (define_mode_iterator QHI [QI HI]) (include "predicates.md") (include "constraints.md") (include "rl78-expand.md") (include "rl78-virt.md") (include "rl78-real.md") ;; Function Prologue/Epilogue Instructions (define_expand "prologue" [(const_int 0)] "" "rl78_expand_prologue (); DONE;" ) (define_expand "epilogue" [(const_int 0)] "" "rl78_expand_epilogue (); DONE;" ) (define_expand "sibcall_epilogue" [(return)] "" "FAIL;" ) (define_insn "rl78_return" [(return)] "" "ret" ) (define_insn "interrupt_return" [(unspec_volatile [(return)] UNS_RETI) ] "" "reti" ) (define_insn "brk_interrupt_return" [(unspec_volatile [(return)] UNS_RETB) ] "" "retb" ) (define_expand "eh_return" [(match_operand:HI 0 "" "")] "" "rl78_expand_eh_epilogue (operands[0]); emit_barrier (); DONE;" ) ;; These are used only by prologue/epilogue so it's "safe" to pass ;; virtual registers. (define_insn "push" [(set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (const_int -2))) (set (mem:HI (reg:HI SP_REG)) (match_operand:HI 0 "register_operand" "ABDT,vZint"))] "" "@ push\t%v0 push\t%v0 ; %0" ) (define_insn "pop" [(set (match_operand:HI 0 "register_operand" "=ABDT,vZint") (mem:HI (reg:HI SP_REG))) (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (const_int 2)))] "" "@ pop\t%v0 pop\t%v0 ; %0" ) (define_insn "sel_rb" [(unspec_volatile [(match_operand 0 "immediate_operand" "")] UNS_SET_RB)] "" "sel\trb%u0" ) (define_insn "trampoline_init" [(set (match_operand 0 "register_operand" "=Z08W") (unspec_volatile [(match_operand 1 "register_operand" "Z08W") (match_operand 2 "register_operand" "Z10W") ] UNS_TRAMPOLINE_INIT)) ] "" "call !!___trampoline_init ; %0 <= %1 %2" ) (define_insn "trampoline_uninit" [(unspec_volatile [(const_int 0)] UNS_TRAMPOLINE_UNINIT) ] "" "call !!___trampoline_uninit" ) ;; GCC restores $fp *before* using it to access values on the *old* ;; frame. So, we do it ourselves, to ensure this is not the case. ;; Note that while %1 is usually a label_ref, we allow for a ;; non-immediate as well. (define_expand "nonlocal_goto" [(set (pc) (unspec_volatile [(match_operand 0 "" "") ;; fp (ignore) (match_operand 1 "" "vi") ;; target (match_operand 2 "" "vi") ;; sp (match_operand 3 "" "vi") ;; ? ] UNS_NONLOCAL_GOTO)) ] "" "emit_jump_insn (gen_nonlocal_goto_insn (operands[0], operands[1], operands[2], operands[3])); emit_barrier (); DONE;" ) (define_insn "nonlocal_goto_insn" [(set (pc) (unspec_volatile [(match_operand 0 "" "") ;; fp (ignore) (match_operand 1 "" "vi") ;; target (match_operand 2 "" "vi") ;; sp (match_operand 3 "" "vi") ;; ? ] UNS_NONLOCAL_GOTO)) ] "" "; nonlocal goto movw ax, %3 movw r22, ax movw ax, %2 movw sp, ax movw ax, %1 br ax " ) ;;====================================================================== ;; ;; "macro" insns - cases where inline chunks of code are more ;; efficient than anything else. (define_expand "addsi3" [(set (match_operand:SI 0 "register_operand" "=&v") (plus:SI (match_operand:SI 1 "nonmemory_operand" "vi") (match_operand 2 "nonmemory_operand" "vi"))) ] "" "if (!nonmemory_operand (operands[1], SImode)) operands[1] = force_reg (SImode, operands[1]); if (!nonmemory_operand (operands[1], SImode)) operands[2] = force_reg (SImode, operands[2]);" ) (define_insn "addsi3_internal" [(set (match_operand:SI 0 "register_operand" "=&v") (plus:SI (match_operand:SI 1 "nonmemory_operand" "vi") (match_operand:SI 2 "nonmemory_operand" "vi"))) ] "" "; addSI macro %0 = %1 + %2 movw ax, %h1 addw ax, %h2 movw %h0, ax movw ax,%H1 sknc incw ax addw ax,%H2 movw %H0,ax ; end of addSI macro" [(set_attr "valloc" "macax")] ) (define_expand "mulsi3" [(set (match_operand:SI 0 "register_operand" "=&v") (mult:SI (match_operand:SI 1 "nonmemory_operand" "vi") (match_operand:SI 2 "nonmemory_operand" "vi"))) ] "! RL78_MUL_NONE" "" ) ;; 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" [(set (match_operand:SI 0 "register_operand" "=&v") (mult:SI (match_operand:SI 1 "nonmemory_operand" "vi") (match_operand:SI 2 "nonmemory_operand" "vi"))) ] "RL78_MUL_RL78" "; mulsi macro %0 = %1 * %2 movw ax, %h1 movw bc, %h2 MULHU ; bcax = bc * ax movw %h0, ax movw ax, bc movw 0xffff0, ax movw ax, %H1 movw bc, %h2 MACHU ; MACR += bc * ax movw ax, %h1 movw bc, %H2 MACHU ; MACR += bc * ax movw ax, 0xffff0 movw %H0, ax ; end of mulsi macro" [(set_attr "valloc" "macax")] ) ;; 0xFFFF0 is MDAL. 0xFFFF2 is MDAH. ;; 0xFFFF4 is MDBL. 0xFFFF6 is MDBH. ;; 0xF00E0 is MDCL. 0xF00E2 is MDCH. ;; 0xF00E8 is MDUC. ;; Warning: this matches the documentation, not the silicon. (define_insn "mulsi3_g13" [(set (match_operand:SI 0 "register_operand" "=&v") (mult:SI (match_operand:SI 1 "nonmemory_operand" "vi") (match_operand:SI 2 "nonmemory_operand" "vi"))) ] "RL78_MUL_G13" "; mulsi macro %0 = %1 * %2 mov a, #0x00 mov !0xf00e8, a ; MDUC movw ax, %h1 movw 0xffff0, ax ; MDAL movw ax, %h2 movw 0xffff2, ax ; MDAH nop ; mdb = mdal * mdah movw ax, 0xffff4 ; MDBL movw %h0, ax mov a, #0x40 mov !0xf00e8, a ; MDUC movw ax, 0xffff6 ; MDBH movw !0xf00e0, ax ; MDCL movw ax, #0 movw !0xf00e2, ax ; MDCL movw ax, %H1 movw 0xffff0, ax ; MDAL movw ax, %h2 movw 0xffff2, ax ; MDAH nop ; mdc += mdal * mdah mov a, #0x40 mov !0xf00e8, a ; MDUC movw ax, %h1 movw 0xffff0, ax ; MDAL movw ax, %H2 movw 0xffff2, ax ; MDAH nop ; mdc += mdal * mdah movw ax, !0xf00e0 ; MDCL movw %H0, ax ; end of mulsi macro" [(set_attr "valloc" "macax")] )