; Fujitsu FR30 CPU description. -*- Scheme -*-
; Copyright 2011 Free Software Foundation, Inc.
;
; Contributed by Red Hat Inc;
;
; This file is part of the GNU Binutils.
;
; This program 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 of the License, or
; (at your option) any later version.
;
; This program 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 this program; if not, write to the Free Software
; Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
; MA 02110-1301, USA.
(define-rtl-version 0 8)
(include "simplify.inc")
; define-arch must appear first
(define-arch
(name fr30) ; name of cpu family
(comment "Fujitsu FR30")
(default-alignment forced)
(insn-lsb0? #f)
(machs fr30)
(isas fr30)
)
(define-isa
(name fr30)
(base-insn-bitsize 16)
(decode-assist (0 1 2 3 4 5 6 7)) ; Initial bitnumbers to decode insns by.
(liw-insns 1) ; The fr30 fetches 1 insn at a time.
(parallel-insns 1) ; The fr30 executes 1 insn at a time.
)
(define-cpu
; cpu names must be distinct from the architecture name and machine names.
; The "b" suffix stands for "base" and is the convention.
; The "f" suffix stands for "family" and is the convention.
(name fr30bf)
(comment "Fujitsu FR30 base family")
(endian big)
(word-bitsize 32)
)
(pipeline all "" () ((fetch) (decode) (execute) (writeback)))
; `state' is a list of variables for recording model state
(state
; bit mask of h-gr registers loaded from memory by previous insn
(load-regs UINT)
; bit mask of h-gr registers loaded from memory by current insn
(load-regs-pending UINT)
)
; The instruction fetch/execute cycle.
;
; This is how to fetch and decode an instruction.
; Leave it out for now
; (define-extract (const SI 0))
; This is how to execute a decoded instruction.
; Leave it out for now
; (define-execute (const SI 0))
; Instruction fields.
;
; Attributes:
; PCREL-ADDR: pc relative value (for reloc and disassembly purposes)
; ABS-ADDR: absolute address (for reloc and disassembly purposes?)
; RESERVED: bits are not used to decode insn, must be all 0
(dnf f-op1 "1st 4 bits of opcode" () 0 4)
(dnf f-op2 "2nd 4 bits of opcode" () 4 4)
(dnf f-op3 "3rd 4 bits of opcode" () 8 4)
(dnf f-op4 "4th 4 bits of opcode" () 12 4)
(dnf f-op5 "5th bit of opcode" () 4 1)
(dnf f-cc "condition code" () 4 4)
(dnf f-ccc "coprocessor calc code" () 16 8)
(dnf f-Rj "register Rj" () 8 4)
(dnf f-Ri "register Ri" () 12 4)
(dnf f-Rs1 "register Rs" () 8 4)
(dnf f-Rs2 "register Rs" () 12 4)
(dnf f-Rjc "register Rj" () 24 4)
(dnf f-Ric "register Ri" () 28 4)
(dnf f-CRj "coprocessor register" () 24 4)
(dnf f-CRi "coprocessor register" () 28 4)
(dnf f-u4 "4 bit 0 extended" () 8 4)
(dnf f-u4c "4 bit 0 extended" () 12 4)
(df f-i4 "4 bit sign extended" () 8 4 INT #f #f)
(df f-m4 "4 bit minus extended" () 8 4 UINT
; ??? This field takes a value in the range [-16,-1] but there
; doesn't seem a way to tell CGEN that. Use an unsigned field and
; disable range checks on insertion by masking. Restore the sign
; on extraction. CGEN generated documentation for insns that use
; this field will be wrong.
((value pc) (and WI value (const #xf)))
((value pc) (or WI value (const -16)))
)
(dnf f-u8 "8 bit unsigned" () 8 8)
(dnf f-i8 "8 bit unsigned" () 4 8)
(df f-udisp6 "6 bit unsigned offset" () 8 4 UINT
((value pc) (srl UWI value (const 2)))
((value pc) (sll UWI value (const 2)))
)
(df f-disp8 "8 bit signed offset" () 4 8 INT #f #f)
(df f-disp9 "9 bit signed offset" () 4 8 INT
((value pc) (sra WI value (const 1)))
((value pc) (mul WI value (const 2)))
)
(df f-disp10 "10 bit signed offset" () 4 8 INT
((value pc) (sra WI value (const 2)))
((value pc) (mul WI value (const 4)))
)
(df f-s10 "10 bit signed offset" () 8 8 INT
((value pc) (sra WI value (const 2)))
((value pc) (mul WI value (const 4)))
)
(df f-u10 "10 bit unsigned offset" () 8 8 UINT
((value pc) (srl UWI value (const 2)))
((value pc) (sll UWI value (const 2)))
)
(df f-rel9 "9 pc relative signed offset" (PCREL-ADDR) 8 8 INT
((value pc) (sra WI (sub WI value (add WI pc (const 2))) (const 1)))
((value pc) (add WI (mul WI value (const 2)) (add WI pc (const 2))))
)
(dnf f-dir8 "8 bit direct address" () 8 8)
(df f-dir9 "9 bit direct address" () 8 8 UINT
((value pc) (srl UWI value (const 1)))
((value pc) (sll UWI value (const 1)))
)
(df f-dir10 "10 bit direct address" () 8 8 UINT
((value pc) (srl UWI value (const 2)))
((value pc) (sll UWI value (const 2)))
)
(df f-rel12 "12 bit pc relative signed offset" (PCREL-ADDR) 5 11 INT
((value pc) (sra WI (sub WI value (add WI pc (const 2))) (const 1)))
((value pc) (add WI (mul WI value (const 2)) (add WI pc (const 2))))
)
(dnf f-reglist_hi_st "8 bit register mask for stm" () 8 8)
(dnf f-reglist_low_st "8 bit register mask for stm" () 8 8)
(dnf f-reglist_hi_ld "8 bit register mask for ldm" () 8 8)
(dnf f-reglist_low_ld "8 bit register mask for ldm" () 8 8)
; Enums.
; insn-op1: bits 0-3
; FIXME: should use die macro or some such
(define-normal-insn-enum insn-op1 "insn op1 enums" () OP1_ f-op1
("0" "1" "2" "3" "4" "5" "6" "7"
"8" "9" "A" "B" "C" "D" "E" "F")
)
; insn-op2: bits 4-7
; FIXME: should use die macro or some such
(define-normal-insn-enum insn-op2 "insn op2 enums" () OP2_ f-op2
("0" "1" "2" "3" "4" "5" "6" "7"
"8" "9" "A" "B" "C" "D" "E" "F")
)
; insn-op3: bits 8-11
; FIXME: should use die macro or some such
(define-normal-insn-enum insn-op3 "insn op3 enums" () OP3_ f-op3
("0" "1" "2" "3" "4" "5" "6" "7"
"8" "9" "A" "B" "C" "D" "E" "F")
)
; insn-op4: bits 12-15
; FIXME: should use die macro or some such
(define-normal-insn-enum insn-op4 "insn op4 enums" () OP4_ f-op4
("0")
)
; insn-op5: bit 4 (5th bit origin 0)
; FIXME: should use die macro or some such
(define-normal-insn-enum insn-op5 "insn op5 enums" () OP5_ f-op5
("0" "1")
)
; insn-cc: condition codes
; FIXME: should use die macro or some such
(define-normal-insn-enum insn-cc "insn cc enums" () CC_ f-cc
("ra" "no" "eq" "ne" "c" "nc" "n" "p" "v" "nv" "lt" "ge" "le" "gt" "ls" "hi")
)
; Hardware pieces.
; These entries list the elements of the raw hardware.
; They're also used to provide tables and other elements of the assembly
; language.
; These bits are actually part of the PS register but are accessed more
; often than the entire register, so define them directly. We can assemble
; the PS register from its components when necessary.
; Instruction Operands.
; These entries provide a layer between the assembler and the raw hardware
; description, and are used to refer to hardware elements in the semantic
; code. Usually there's a bit of over-specification, but in more complicated
; instruction sets there isn't.
; FR30 specific operand attributes:
(define-attr
(for operand)
(type boolean)
(name HASH-PREFIX)
(comment "immediates have an optional '#' prefix")
)
; ??? Convention says this should be o-sr, but then the insn definitions
; should refer to o-sr which is clumsy. The "o-" could be implicit, but
; then it should be implicit for all the symbols here, but then there would
; be confusion between (f-)simm8 and (h-)simm8.
; So for now the rule is exactly as it appears here.
(dnop dir8 "8 bit direct address" () h-uint f-dir8)
(dnop dir9 "9 bit direct address" () h-uint f-dir9)
(dnop dir10 "10 bit direct address" () h-uint f-dir10)
(dnop label9 "9 bit pc relative address" () h-iaddr f-rel9)
(dnop label12 "12 bit pc relative address" () h-iaddr f-rel12)
(binary-logical-op and and "reg/reg" OP1_8 OP2_2 and Rj Ri)
(binary-logical-op or or "reg/reg" OP1_9 OP2_2 or Rj Ri)
(binary-logical-op eor eor "reg/reg" OP1_9 OP2_A xor Rj Ri)
; This insn loads a value from where r15 points into the target register and
; then increments r15. If the target register is also r15, then the post
; increment is not performed.
;
(dni ldr15dr
"ld @R15+,Rs2"
()
"ld @$R15+,$Rs2"
(+ OP1_0 OP2_7 OP3_8 Rs2)
; This seems more straight forward, but doesn't work due to a problem in
; cgen. We're trying to not increment r15 if it is the target register.
; (sequence ()
; (set Rs2 (mem WI (reg h-gr 15)))
; (if (not (or (and (eq (ifield f-Rs2) (const 2))
; (eq sbit (const 0)))
; (and (eq (ifield f-Rs2) (const 3))
; (eq sbit (const 1)))))
; (set (reg h-gr 15) (add (reg h-gr 15) (const 4)))
; )
; )
(sequence ((WI tmp))
(set tmp (mem WI (reg h-gr 15))) ; save in case target is r15
(set (reg h-gr 15) (add (reg h-gr 15) (const 4)))
(set Rs2 tmp))
((fr30-1 (unit u-load)))
)
; These store insns predecrement r15 and then store the contents of the source
; register where r15 then points. If the source register is also r15, then the
; original value of r15 is stored.
;
(dni str15gr
"st Ri,@-R15 reg/mem"
()
"st $Ri,@-$R15"
(+ OP1_1 OP2_7 OP3_0 Ri)
(sequence ((WI tmp))
(set tmp Ri) ; save in case it's r15
(set (reg h-gr 15) (sub (reg h-gr 15) (const 4)))
(set (mem WI (reg h-gr 15)) tmp))
((fr30-1 (unit u-store)))
)
; These versions which use registers must appear before the other
; versions which use relative addresses due to a problem in cgen
; - DB.
(dni callr
"call @Ri"
(NOT-IN-DELAY-SLOT)
"call @$Ri"
(+ OP1_9 OP2_7 OP3_1 Ri)
(sequence ()
(set (reg h-dr 1) (add pc (const 2)))
(set pc Ri))
((fr30-1 (unit u-cti)))
)
(dni callrd
"call:d @Ri"
(NOT-IN-DELAY-SLOT)
"call:d @$Ri"
(+ OP1_9 OP2_F OP3_1 Ri)
(delay (const 1)
(sequence ()
(set (reg h-dr 1) (add pc (const 4)))
(set pc Ri)))
((fr30-1 (unit u-cti)))
)
; end of reordered insns
(dni ret
"return from subroutine"
(NOT-IN-DELAY-SLOT)
"ret"
(+ OP1_9 OP2_7 OP3_2 OP4_0)
(set pc (reg h-dr 1))
((fr30-1 (unit u-cti)))
)
(dni ret:d
"return from subroutine with delay slot"
(NOT-IN-DELAY-SLOT)
"ret:d"
(+ OP1_9 OP2_F OP3_2 OP4_0)
(delay (const 1)
(set pc (reg h-dr 1)))
((fr30-1 (unit u-cti)))
)
(dni int
"interrupt"
(NOT-IN-DELAY-SLOT)
"int $u8"
(+ OP1_1 OP2_F u8)
(sequence ()
; This is defered to fr30_int because for the breakpoint case
; we want to change as little of the machine state as possible.
; Push PS onto the system stack
;(set (reg h-dr 2) (sub (reg h-dr 2) (const 4)))
;(set UWI (mem UWI (reg h-dr 2)) ps)
; Push the return address onto the system stack
;(set (reg h-dr 2) (sub (reg h-dr 2) (const 4)))
;(set UWI (mem UWI (reg h-dr 2)) (add pc (const 2)))
; Set status bits
;(set ibit (const 0))
;(set sbit (const 0))
; We still should indicate what is modified by this insn.
(clobber (reg h-dr 2))
(clobber ibit)
(clobber sbit)
; ??? (clobber memory)?
; fr30_int handles operating vs user mode
(set WI pc (c-call WI "fr30_int" pc u8))
)
; This is more properly a cti, but branch stall calculation is different.
((fr30-1 (unit u-exec (cycles 6))))
)
(dni inte
"interrupt for emulator"
(NOT-IN-DELAY-SLOT)
"inte"
(+ OP1_9 OP2_F OP3_3 OP4_0)
(sequence ()
; This is defered to fr30_inte because for the breakpoint case
; we want to change as little of the machine state as possible.
; Push PS onto the system stack
;(set (reg h-dr 2) (sub (reg h-dr 2) (const 4)))
;(set UWI (mem UWI (reg h-dr 2)) ps)
; Push the return address onto the system stack
;(set (reg h-dr 2) (sub (reg h-dr 2) (const 4)))
;(set UWI (mem UWI (reg h-dr 2)) (add pc (const 2)))
; Set status bits
;(set ibit (const 0))
;(set ilm (const 4))
; We still should indicate what is modified by this insn.
(clobber (reg h-dr 2))
(clobber ibit)
(clobber ilm)
; ??? (clobber memory)?
; fr30_int handles operating vs user mode
(set WI pc (c-call WI "fr30_inte" pc))
)
; This is more properly a cti, but branch stall calculation is different.
((fr30-1 (unit u-exec (cycles 6))))
)
(dni reti
"return from interrupt"
(NOT-IN-DELAY-SLOT)
"reti"
(+ OP1_9 OP2_7 OP3_3 OP4_0)
(if (eq sbit (const 0))
(sequence ()
; Pop the return address from the system stack
(set UWI pc (mem UWI (reg h-dr 2)))
(set (reg h-dr 2) (add (reg h-dr 2) (const 4)))
; Pop PS from the system stack
(set UWI ps (mem UWI (reg h-dr 2)))
(set (reg h-dr 2) (add (reg h-dr 2) (const 4)))
)
(sequence ()
; Pop the return address from the user stack
(set UWI pc (mem UWI (reg h-dr 3)))
(set (reg h-dr 3) (add (reg h-dr 3) (const 4)))
; Pop PS from the user stack
(set UWI ps (mem UWI (reg h-dr 3)))
(set (reg h-dr 3) (add (reg h-dr 3) (const 4)))
)
)
; This is more properly a cti, but branch stall calculation is different.
((fr30-1 (unit u-exec (cycles 4))))
)
; Conditional branches with and without delay slots
;
(define-pmacro (cond-branch cc condition)
(begin
(dni (.sym b cc d)
(.str (.sym b cc :d) " label9")
(NOT-IN-DELAY-SLOT)
(.str (.sym b cc :d) " $label9")
(+ OP1_F (.sym CC_ cc) label9)
(delay (const 1)
(if condition (set pc label9)))
((fr30-1 (unit u-cti)))
)
(dni (.sym b cc)
(.str (.sym b cc) " label9")
(NOT-IN-DELAY-SLOT)
(.str (.sym b cc) " $label9")
(+ OP1_E (.sym CC_ cc) label9)
(if condition (set pc label9))
((fr30-1 (unit u-cti)))
)
)
)
(cond-branch ra (const BI 1))
(cond-branch no (const BI 0))
(cond-branch eq zbit)
(cond-branch ne (not zbit))
(cond-branch c cbit)
(cond-branch nc (not cbit))
(cond-branch n nbit)
(cond-branch p (not nbit))
(cond-branch v vbit)
(cond-branch nv (not vbit))
(cond-branch lt (xor vbit nbit))
(cond-branch ge (not (xor vbit nbit)))
(cond-branch le (or (xor vbit nbit) zbit))
(cond-branch gt (not (or (xor vbit nbit) zbit)))
(cond-branch ls (or cbit zbit))
(cond-branch hi (not (or cbit zbit)))
; These versions which move from reg to mem must appear before the other
; versions which use immediate addresses due to a problem in cgen
; - DB.
(r132dir dmovr13 dmov OP1_1 OP2_8 WI dir10)
(r132dir dmovr13h dmovh OP1_1 OP2_9 HI dir9)
(r132dir dmovr13b dmovb OP1_1 OP2_A QI dir8)
; Leave these insns as stubs for now, except for the increment of $Ri
;
(dni ldres
"ldres @Ri+,#u4"
()
"ldres @$Ri+,$u4"
(+ OP1_B OP2_C u4 Ri)
(set Ri (add Ri (const 4)))
()
)
(dni stres
"stres #u4,@Ri+"
()
"stres $u4,@$Ri+"
(+ OP1_B OP2_D u4 Ri)
(set Ri (add Ri (const 4)))
()
)
; Leave the coprocessor insns as stubs for now.
;
(define-pmacro (cop-stub name insn opc1 opc2 opc3 arg1 arg2)
(dni name
(.str insn " u4c,ccc,CRj," arg1 "," arg2)
(NOT-IN-DELAY-SLOT)
(.str insn " $u4c,$ccc,$" arg1 ",$" arg2)
(+ opc1 opc2 opc3 u4c ccc arg1 arg2)
(nop) ; STUB
()
)
)
(define-pmacro (ext-op name opc1 opc2 opc3 op mode mask)
(dni name
(.str name " Ri")
()
(.str name " $Ri")
(+ opc1 opc2 opc3 Ri)
(set Ri (op WI (and mode Ri mask)))
()
)
)