ghidra/Ghidra/Processors/SuperH4/data/languages/SuperH4.sinc

3124 lines
75 KiB
Plaintext

# This module defines SuperH version 4, but should work against versions 1,2, and 3.
# There is a SuperH version 4A (which has 4 byte instruction length) which has instructions incompatable
# with this.
# Based on "Renesas SH-4 Software Manual: Rev 6.00 2006.09 (i.e. rej09b0318_sh_4sm.pdf)
# Here's a nice webpage with all the insns clearly shown
# http://shared-ptr.com/sh_insns.html
# Address Space:
# SuperH 4A has a 29-bit and a 32-bit address space mode,
# and can do 32-bit addressing in 29-bit mode with virtual addressing.
# The SH4 has a 29-bit physical address space, but can do 32-bit with virtual addressing.
#
# WARNING:
# WARNING:
# WARNING: Currently set up for 29-bit only for computed jumps/calls. This needs to be configurable.
# WARNING:
# NOTE: SuperH 4 and floating point disassembly and decompiling precision.
# Many of the floating point instructions can do either single or double precision calculations depending
# on a flag FPSCR_PR at runtime. This means at disassembly stage we don't have all the information required
# determine the arguments to some floating point instructions.
# NOTE: SuperH 4 and floating point disassembly and decompiling (fmov lengths).
# Some of the instructions can read and write floating point values in 4 or 8 byte values depending on the
# flag FPSCR_SZ. This means at disassembly stage we don't have all the information required to determine the
# arguments to some floating point instructions.
# Note that the FPSCR_PR flag is never examined during any of the fmov insns.
# NOTE: SuperH and banking
# When the RB flag is not set R1->R7 come from bank0 and when RB is set R1->R7 come from bank1. The RB mode is
# set in privileged mode. We don't currently simulate this behavior.
# NOTE: SuperH and floating point banking
# When the flag FPSCR_FR is not set fr0->fr15 come from bank0 and when FPSCR.FR is set fr0->fr15 come from bank1.
# We don't currently simulate this behavior.
# NOTE: SuperH and memory map registers
# There are 7 32bit control registers (SR, GBR, SSR, SPC, SGR, DBR, VBR) these are mapped to 2 different memory
# areas 0x1C000000 and 0xFC000000. We don't currently simulate this behavior.
# NOTE: SuperH/Renesas return value convention.
# Renesas and gcc return most values from a function in r0 but floats are return in fr0 and doubles in dr0.
# Ghidra calling spec has no way of specifying this behavior so such return values are not handled correctly.
# NOTE: SuperH/Renesas calling convention
# Renesas and gcc pass most values to a function via r4-r7 but floats are passed by fr4-fr7 and doubles in
# dr4, dr6, dr8, and dr10.
# NOTE: floating point errors
# In implementing the floating point pcode we ignored many of the possible error conditions floating point
# could cause. This allows us to produce much better looking decompiled code.
# NOTE: SuperH 4 Memory model
# SuperH 4 has a Memory Management Unit (i.e. MMU). Which means that depending on mode the memory can
# look very different. We don't model this behavior. We also don't simulate the MMU address translation,
# so all addresses are raw.
# Basic ================================================================================
define endian=$(ENDIAN); # Defined in file that includes this file
define alignment=2;
define space ram type=ram_space size=4 default;
define space register type=register_space size=4;
# Registers ============================================================================
# TODO deal with the 2 banks of registers
# TODO move os corret memory address
define register offset=0 size=4 [
r0 r1 r2 r3 r4 r5 r6 r7
r8 r9 r10 r11 r12 r13 r14 r15
R0_BANK R1_BANK R2_BANK R3_BANK R4_BANK R5_BANK R6_BANK R7_BANK
];
# This is where "BANK0" is with RB=0 (normal), causes duplicate pair error in SLEIGH
#define register offset=0 size=4 [
# R0_BANK0 R1_BANK0 R2_BANK0 R3_BANK0 R4_BANK0 R5_BANK0 R6_BANK0 R7_BANK0
#];
# This is where "BANK1" is with RB=1 (privileged), causes duplicate pair error in SLEIGH
#define register offset=0 size=4 [
# R0_BANK1 R1_BANK1 R2_BANK1 R3_BANK1 R4_BANK1 R5_BANK1 R6_BANK1 R7_BANK1
#];
@if ENDIAN == "big"
define register offset=512 size=4 [
fr0 fr1 fr2 fr3 fr4 fr5 fr6 fr7 fr8 fr9 fr10 fr11 fr12 fr13 fr14 fr15
xf0 xf1 xf2 xf3 xf4 xf5 xf6 xf7 xf8 xf9 xf10 xf11 xf12 xf13 xf14 xf15
];
@endif
@if ENDIAN == "little"
define register offset=512 size=4 [
fr1 fr0 fr3 fr2 fr5 fr4 fr7 fr6 fr9 fr8 fr11 fr10 fr13 fr12 fr15 fr14
xf0 xf1 xf2 xf3 xf4 xf5 xf6 xf7 xf8 xf9 xf10 xf11 xf12 xf13 xf14 xf15
];
@endif
define register offset=512 size=8 [
dr0 dr2 dr4 dr6 dr8 dr10 dr12 dr14
xd0 xd2 xd4 xd6 xd8 xd10 xd12 xd14
];
define register offset=512 size=16 [
fv0 fv4 fv8 fv12
];
# Control registers
define register offset=1024 size=4 [
GBR SR SSR SPC VBR SGR DBR
];
# SR component register fields (pseudo)
define register offset=1536 size=1 [
MD RB BL FD M Q IMASK S T
];
# System registers
define register offset=2048 size=4 [
MACH MACL PR PC FPSCR FPUL
];
# FPSCR component register fields (pseudo)
define register offset=2560 size=1 [
FPSCR_RM
FPSCR_FLAG
FPSCR_ENABLE
FPSCR_CAUSE
FPSCR_DN
FPSCR_PR
FPSCR_SZ
FPSCR_FR
];
@define T_FLAG "T"
@define S_FLAG "S"
@define IMASK "IMASK"
@define Q_FLAG "Q"
@define M_FLAG "M"
@define FD_FLAG "FD"
@define BL_FLAG "BL"
@define RB_FLAG "RB"
@define MD_FLAG "MD"
@define FPSCR_RM "FPSCR_RM"
@define FPSCR_FLAG "FPSCR_FLAG"
@define FPSCR_ENABLE "FPSCR_ENABLE"
@define FPSCR_CAUSE "FPSCR_CAUSE"
@define FPSCR_DN "FPSCR_DN"
@define FPSCR_PR "FPSCR_PR"
@define FPSCR_SZ "FPSCR_SZ"
@define FPSCR_FR "FPSCR_FR"
#
# SR pack and unpack support
#
# 0000 0000 0000 0000 0000 0000 0000 0001
@define T_MASK "0x00000001"
# 0000 0000 0000 0000 0000 0000 0000 0010
@define S_MASK "0x00000002"
# 0000 0000 0000 0000 0000 0000 1111 0000
@define IMASK_MASK "0x000000F0"
# 0000 0000 0000 0000 0000 0001 0000 0000
@define Q_MASK "0x00000100"
# 0000 0000 0000 0000 0000 0010 0000 0000
@define M_MASK "0x00000200"
# 0000 0000 0000 0000 1000 0000 0000 0000
@define FD_MASK "0x00008000"
# 0001 0000 0000 0000 0000 0000 0000 0000
@define BL_MASK "0x10000000"
# 0010 0000 0000 0000 0000 0000 0000 0000
@define RB_MASK "0x20000000"
# 0100 0000 0000 0000 0000 0000 0000 0000
@define MD_MASK "0x40000000"
@define T_SHIFT " 0"
@define S_SHIFT " 1"
@define IMASK_SHIFT " 4"
@define Q_SHIFT " 8"
@define M_SHIFT " 9"
@define FD_SHIFT "15"
@define BL_SHIFT "28"
@define RB_SHIFT "29"
@define MD_SHIFT "30"
macro genSRregister() {
SR =
(zext(T) << $(T_SHIFT)) |
(zext(S) << $(S_SHIFT)) |
(zext(IMASK) << $(IMASK_SHIFT)) |
(zext(Q) << $(Q_SHIFT)) |
(zext(M) << $(M_SHIFT)) |
(zext(FD) << $(FD_SHIFT)) |
(zext(BL) << $(BL_SHIFT)) |
(zext(RB) << $(RB_SHIFT)) |
(zext(MD) << $(MD_SHIFT));
}
macro splitSRregister() {
splitTemp:4 = (SR & $(T_MASK)) >> $(T_SHIFT);
T = splitTemp:1;
splitTemp = (SR & $(S_MASK)) >> $(S_SHIFT);
S = splitTemp:1;
splitTemp = (SR & $(IMASK_MASK)) >> $(IMASK_SHIFT);
IMASK = splitTemp:1;
splitTemp = (SR & $(Q_MASK)) >> $(Q_SHIFT);
Q = splitTemp:1;
splitTemp = (SR & $(M_MASK)) >> $(M_SHIFT);
M = splitTemp:1;
splitTemp = (SR & $(FD_MASK)) >> $(FD_SHIFT);
FD = splitTemp:1;
splitTemp = (SR & $(BL_MASK)) >> $(BL_SHIFT);
BL = splitTemp:1;
splitTemp = (SR & $(RB_MASK)) >> $(RB_SHIFT);
RB = splitTemp:1;
splitTemp = (SR & $(MD_MASK)) >> $(MD_SHIFT);
MD = splitTemp:1;
}
#
# FPSCR pack and unpack support
#
@define FPSCR_RM_SHIFT " 0"
@define FPSCR_FLAG_SHIFT " 2"
@define FPSCR_ENABLE_SHIFT " 7"
@define FPSCR_CAUSE_SHIFT "12"
@define FPSCR_DN_SHIFT "18"
@define FPSCR_PR_SHIFT "19"
@define FPSCR_SZ_SHIFT "20"
@define FPSCR_FR_SHIFT "21"
# 0000 0000 0000 0000 0000 0000 0000 0011
@define FPSCR_RM_MASK "0x00000003"
# 0000 0000 0000 0000 0000 0000 0111 1100
@define FPSCR_FLAG_MASK "0x0000007C"
# 0000 0000 0000 0000 0000 1111 1000 0000
@define FPSCR_ENABLE_MASK "0x00000F80"
# 0000 0000 0000 0011 1111 0000 0000 0000
@define FPSCR_CAUSE_MASK "0x0003F000"
# 0000 0000 0000 0100 0000 0000 0000 0000
@define FPSCR_DN_MASK "0x00040000"
# 0000 0000 0000 1000 0000 0000 0000 0000
@define FPSCR_PR_MASK "0x00080000"
# 0000 0000 0001 0000 0000 0000 0000 0000
@define FPSCR_SZ_MASK "0x00100000"
# 0000 0000 0010 0000 0000 0000 0000 0000
@define FPSCR_FR_MASK "0x00200000"
# Bits 22-31 are not used
macro genFPSCRregister() {
FPSCR =
(zext(FPSCR_RM) << $(FPSCR_RM_SHIFT)) |
(zext(FPSCR_FLAG) << $(FPSCR_FLAG_SHIFT)) |
(zext(FPSCR_ENABLE) << $(FPSCR_ENABLE_SHIFT)) |
(zext(FPSCR_CAUSE) << $(FPSCR_CAUSE_SHIFT)) |
(zext(FPSCR_DN) << $(FPSCR_DN_SHIFT)) |
(zext(FPSCR_PR) << $(FPSCR_PR_SHIFT)) |
(zext(FPSCR_SZ) << $(FPSCR_SZ_SHIFT)) |
(zext(FPSCR_FR) << $(FPSCR_FR_SHIFT));
}
macro splitFPSCRregister() {
splitTemp:4 = (FPSCR & $(FPSCR_RM_MASK)) >> $(FPSCR_RM_SHIFT);
FPSCR_RM = splitTemp:1;
splitTemp = (FPSCR & $(FPSCR_FLAG_MASK)) >> $(FPSCR_FLAG_SHIFT);
FPSCR_FLAG = splitTemp:1;
splitTemp = (FPSCR & $(FPSCR_ENABLE_MASK)) >> $(FPSCR_ENABLE_SHIFT);
FPSCR_ENABLE = splitTemp:1;
splitTemp = (FPSCR & $(FPSCR_CAUSE_MASK)) >> $(FPSCR_CAUSE_SHIFT);
FPSCR_CAUSE = splitTemp:1;
splitTemp = (FPSCR & $(FPSCR_DN_MASK)) >> $(FPSCR_DN_SHIFT);
FPSCR_DN = splitTemp:1;
splitTemp = (FPSCR & $(FPSCR_PR_MASK)) >> $(FPSCR_PR_SHIFT);
FPSCR_PR = splitTemp:1;
splitTemp = (FPSCR & $(FPSCR_SZ_MASK)) >> $(FPSCR_SZ_SHIFT);
FPSCR_SZ = splitTemp:1;
splitTemp = (FPSCR & $(FPSCR_FR_MASK)) >> $(FPSCR_FR_SHIFT);
FPSCR_FR = splitTemp:1;
}
# Fields =================================================================================
define token instr(16)
OP_0 = (12,15)
OP_1 = ( 0, 3)
OP_2 = ( 8,15)
OP_3 = ( 0,15)
OP_4 = ( 0, 7)
OP_5 = ( 0, 8)
OP_6 = ( 8, 8)
OP_7 = ( 0, 4)
OP_8 = ( 0, 9)
OP_9 = ( 7, 7)
OP_10 = ( 4, 4)
BANK = ( 4, 6) # bank register id
M_0 = ( 4, 7) # register id
M_1 = ( 5, 7) # register id
M_2 = ( 8, 9) # register id
FRM_0 = ( 4, 7) # float register id
DRM_1 = ( 5, 7) # double register id
XDM_1 = ( 5, 7) # double register id
XDRM = ( 4, 7) # double register id
FVM_2 = ( 8, 9) # fv register id
N_0 = ( 8,11) # register id
N_1 = ( 9,11) # register id
N_2 = (10,11) # register id
FRN_0 = ( 8,11) # float register id
DRN_1 = ( 9,11) # double register id
XDN_1 = ( 9,11) # double register id
XDRN = ( 8,11) # float register id
FVN_2 = (10,11) # fv register id
I_0 = ( 0, 7) signed # immediate
I_1 = ( 0,11) signed # immediate
I_2 = ( 0, 3) signed # immediate
U_0 = ( 0, 7) # immediate
U_1 = ( 0,11) # immediate
U_2 = ( 0, 3) # immediate
;
# Context variables ====================================================
# Attach variables =====================================================
# attach normal registers
attach variables [ N_0 M_0 ] [
r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15
];
# attach float registers
attach variables [ FRN_0 FRM_0] [
fr0 fr1 fr2 fr3 fr4 fr5 fr6 fr7 fr8 fr9 fr10 fr11 fr12 fr13 fr14 fr15
];
# attach double registers
attach variables [ DRN_1 DRM_1 ] [
dr0 dr2 dr4 dr6 dr8 dr10 dr12 dr14
];
# attach extended double registers
attach variables [ XDN_1 XDM_1 ] [
xd0 xd2 xd4 xd6 xd8 xd10 xd12 xd14
];
attach variables [ XDRN XDRM ] [
dr0 xd0 dr2 xd2 dr4 xd4 dr6 xd6 dr8 xd8 dr10 xd10 dr12 xd12 dr14 xd14
];
# attach vf registers
attach variables [ FVN_2 FVM_2 ] [
fv0 fv4 fv8 fv12
];
attach variables [ BANK ] [
R0_BANK R1_BANK R2_BANK R3_BANK R4_BANK R5_BANK R6_BANK R7_BANK
];
# Tables ================================================================
# Addressing Modes
#
# Register direct
# Rn EA is Rn.
#
# Register indirect
# @Rn Rn contains EA
#
# Register indirect with postincrement
# @Rn+ Rn contains EA
# After EA calculation:
# increment Rn by 1 for byte, 2 for word, 4 for long word, 8 quadword operand
#
# Register indirect with predecrement
# @-Rn Rn contains EA,
# Before EA calculation:
# increment Rn by 1 for byte, 2 for word, 4 for long word, 8 quadword operand
#
# Register indirect with displacement
# @(disp:4, Rn) EA is Rn + 4-bit displacement disp added. disp is zero extended,
# then multiplied by 1 for byte, 2 for word, 4 for long word operand size
#
# Indexed register indirect
# @(R0, Rn) EA is Rn + R0
#
# GBR indirect with displacement
# @(disp:8,GBR) EA is GBR contents with 8-bit displacement added.
# 8-bit displacement disp added. disp is zero extended,
# then multiplied by 1 for byte, 2 for word, 4 for long word operand size
#
# Indexed GBR indirect
# @(R0, GBR) EA is GBR + R0
#
# PC-relative with displacement
# @(disp:8, PC) EA is PC+4 + 8bit displacement. disp is zero extended,
# then multiplied by 1 for byte, 2 for word, 4 for long word operand size
#
# PC-relative
# disp:8 EA is PC+4 + 8-bit displacement.
# disp is sign-extended and multiplied by 2.
#
# PC-relative
# disp:12 EA is PC+4 + 12-bit displacement.
# disp is sign-extended and multiplied by 2.
#
# Rn EA is PC+4 + Rn.
#
M_0t: M_0 is M_0 { export M_0; }
N_0t: N_0 is N_0 { export N_0; }
N_0tjmp: @^N_0 is N_0 { export N_0; }
I_0t: "#"^I_0 is I_0 { tmp:4 = I_0; export tmp; }
U_0t: "#"^U_0 is U_0 { tmp:4 = U_0; export tmp; }
U_0t1: "#"^U_0^",@("^r0^","^GBR^")" is U_0 & r0 & GBR { tmp:1 = U_0; export tmp; }
I_0t_r0: "#"I_0^","^r0 is I_0 & r0 { tmp:4 = I_0; export tmp; }
U_0t_r0: "#"U_0^","^r0 is U_0 & r0 { tmp:4 = U_0; export tmp; }
I_0tbranch: dest is I_0 [ dest = inst_start + I_0*2 + 4; ] { export *:4 dest; }
I_1tbranch: dest is I_1 [ dest = inst_start + I_1*2 + 4; ] { export *:4 dest; }
sr_N_0t: SR^","^N_0 is N_0 & SR { export N_0; }
gbr_N_0t: GBR^","^N_0 is N_0 & GBR { export N_0; }
vbr_N_0t: VBR^","^N_0 is N_0 & VBR { export N_0; }
ssr_N_0t: SSR^","^N_0 is N_0 & SSR { export N_0; }
spc_N_0t: SPC^","^N_0 is N_0 & SPC { export N_0; }
sgr_N_0t: SGR^","^N_0 is N_0 & SGR { export N_0; }
dbr_N_0t: DBR^","^N_0 is N_0 & DBR { export N_0; }
sr_t: SR is OP_0 & SR { x:4 = 0; export x; } # dummy export, just looking for the display
gbr_t: GBR is OP_0 & GBR { x:4 = 0; export x; } # dummy export, just looking for the display
vbr_t: VBR is OP_0 & VBR { x:4 = 0; export x; } # dummy export, just looking for the display
ssr_t: SSR is OP_0 & SSR { x:4 = 0; export x; } # dummy export, just looking for the display
spc_t: SPC is OP_0 & SPC { x:4 = 0; export x; } # dummy export, just looking for the display
sgr_t: SGR is OP_0 & SGR { x:4 = 0; export x; } # dummy export, just looking for the display
dbr_t: DBR is OP_0 & DBR { x:4 = 0; export x; } # dummy export, just looking for the display
N_0t_sr: N_0^","^SR is N_0 & SR { export N_0; }
N_0t_gbr: N_0^","^GBR is N_0 & GBR { export N_0; }
N_0t_vbr: N_0^","^VBR is N_0 & VBR { export N_0; }
N_0t_ssr: N_0^","^SSR is N_0 & SSR { export N_0; }
N_0t_spc: N_0^","^SPC is N_0 & SPC { export N_0; }
# N_0t_sgr: N_0^","^SGR is N_0 & SGR { export N_0; }
N_0t_dbr: N_0^","^DBR is N_0 & DBR { export N_0; }
N_0t_bank: N_0 is N_0 { export N_0; }
N_0t_sr1: @^N_0^"+,"^SR is N_0 & SR { export N_0; }
N_0t_gbr1: @^N_0^"+,"^GBR is N_0 & GBR { export N_0; }
N_0t_vbr1: @^N_0^"+,"^VBR is N_0 & VBR { export N_0; }
N_0t_ssr1: @^N_0^"+,"^SSR is N_0 & SSR { export N_0; }
N_0t_spc1: @^N_0^"+,"^SPC is N_0 & SPC { export N_0; }
# N_0t_sgr1: @^N_0^"+,"^SGR is N_0 & SGR { export N_0;}
N_0t_dbr1: @^N_0^"+,"^DBR is N_0 & DBR { export N_0; }
N_0t_bank1: @^N_0^"+" is N_0 { export N_0; }
FR0_t: fr0 is OP_0 & fr0 { x:4 = 0; export x; } # dummy export, just looking for the display
XMTRX_t: "xmtrx" is OP_0 { x:4 = 0; export x; } # dummy export, just looking for the display
mach_t: MACH is OP_0 & MACH { x:4 = 0; export x; } # dummy export, just looking for the display
macl_t: MACL is OP_0 & MACL { x:4 = 0; export x; } # dummy export, just looking for the display
fpul_t: FPUL is OP_0 & FPUL { x:4 = 0; export x; } # dummy export, just looking for the display
fpscr_t: "FPSCR" is OP_0 { x:4 = 0; export x; } # dummy export, just looking for the display
mach_N_0t: MACH^","^N_0 is N_0 & MACH { export N_0; }
macl_N_0t: MACL^","^N_0 is N_0 & MACL { export N_0; }
pr_N_0t: PR^","^N_0 is N_0 & PR { export N_0; }
fpul_N_0t: FPUL^","N_0 is N_0 & FPUL { export N_0; }
fpscr_N_0t: "FPSCR"^","N_0 is N_0 { export N_0; }
N_0t_mach: N_0^","^MACH is N_0 & MACH { export N_0; }
N_0t_macl: N_0^","^MACL is N_0 & MACL { export N_0; }
N_0t_pr: N_0^","^PR is N_0 & PR { export N_0; }
N_0t_fpul: N_0^","^FPUL is N_0 & FPUL { export N_0; }
N_0t_fpscr: N_0^",fpscr" is N_0 { export N_0; }
N_0t_mach1: @^N_0^"+,"^MACH is N_0 & MACH { export N_0; }
N_0t_macl1: @^N_0^"+,"^MACL is N_0 & MACL { export N_0; }
N_0t_pr1: @^N_0^"+,"^PR is N_0 & PR { export N_0; }
N_0t_fpul1: @^N_0^"+,"^FPUL is N_0 & FPUL { export N_0; }
N_0t_fpscr1: @^N_0^"+,fpscr" is N_0 { export N_0; }
M_0t_at1: @^M_0 is M_0 { export M_0; }
N_0t_at1: @^N_0 is N_0 { export N_0; }
M_0t_at: @^M_0^+ is M_0 { export M_0; }
N_0t_at: @^N_0^+ is N_0 { export N_0; }
FRM_0t: FRM_0 is FRM_0 { export FRM_0; }
FRN_0t: FRN_0 is FRN_0 { export FRN_0; }
DRM_1t: DRM_1 is DRM_1 { export DRM_1; }
DRN_1t: DRN_1 is DRN_1 { export DRN_1; }
FVM_2t: FVM_2 is FVM_2 { export FVM_2; }
FVN_2t: FVN_2 is FVN_2 { export FVN_2; }
N_0t_at_with_r0: "@("^r0^","^N_0^")" is N_0 & r0 { export N_0; }
M_0t_at_with_r0: "@("^r0^","^M_0^")" is M_0 & r0 { export M_0; }
N_0t_at_neg: "@-"^N_0 is N_0 { export N_0; }
U_2t_M0_dispr01: "@("^disp^","^M_0^")" is U_2 & M_0 [ disp = U_2 * 1; ] { tmp4:4 = disp; export tmp4; }
U_2t_M0_dispr02: "@("^disp^","^M_0^")" is U_2 & M_0 [ disp = U_2 * 2; ] { tmp4:4 = disp; export tmp4; }
U_2t_M0_dispr04: "@("^disp^","^M_0^")" is U_2 & M_0 [ disp = U_2 * 4; ] { tmp4:4 = disp; export tmp4; }
U_2t_N0_dispr04: "@("^disp^","^N_0^")" is U_2 & N_0 [ disp = U_2 * 4; ] { tmp4:4 = disp; export tmp4; }
# Bug in SLEIGH, needed "* 1"
U_0t_gbr_at_1: "@("^disp,GBR^")" is U_0 & GBR [ disp = U_0 * 1; ] { tmp4:4 = disp + GBR; export tmp4; }
U_0t_gbr_at_2: "@("^disp,GBR^")" is U_0 & GBR [ disp = U_0 * 2; ] { tmp4:4 = disp + GBR; export tmp4; }
U_0t_gbr_at_4: "@("^disp,GBR^")" is U_0 & GBR [ disp = U_0 * 4; ] { tmp4:4 = disp + GBR; export tmp4; }
# Note: The 4 byte (MOVA) case needs the masking of the PC bottom 2 bits, page 345, paragraph 1:
# "a value with the lower 2 bits adjusted to B00 is used in address calculation."
# Note: Only the 4 byte case needs the masking of the PC bottom 2 bits, page 336, paragraph 3:
# "A value with the lower 2 bits adjusted to B00 is used in address calculation."
# (The 2 byte case always has the PC LSBit at 0 because all instructions are 2 byte aligned.)
U_0t_2pc: dest is U_0 [ dest = inst_start + U_0*2 + 4; ] { export *:2 dest; }
U_0t_4pc: dest is U_0 [ dest = ( inst_start & 0xfffffffc ) + U_0*4 + 4; ] { export *:4 dest; }
BANKt: BANK is BANK { export BANK; }
N_0txx: r0",@"^N_0 is r0 & N_0 { tmp:4 = N_0; export tmp; }
# Constructors =======================================================================
# Binary Addition
# pattern 0011nnnnmmmm1100
# text add <REG_M>,<REG_N>
# arch arch_sh_up
:add M_0t,N_0t is OP_0=0x3 & N_0t & M_0t & OP_1=0xc {
N_0t = N_0t + M_0t;
}
# Binary Addition
# pattern 0111nnnniiiiiiii
# text add #<imm>,<REG_N>
# arch arch_sh_up
:add I_0t,N_0t is OP_0=0x7 & N_0t & I_0t {
N_0t = I_0t + N_0t; # NOTE I_0t already signed extended
}
# Binary Addition with Carry
# pattern 0011nnnnmmmm1110
# text addc <REG_M>,<REG_N>
# arch arch_sh_up
:addc M_0t,N_0t is OP_0=0x3 & N_0t & M_0t & OP_1=0xe {
tmp1:4 = N_0t + M_0t;
tmp0:4 = N_0t;
N_0t = tmp1 + zext($(T_FLAG));
$(T_FLAG) = (tmp0 > tmp1);
if (tmp1 <= N_0t) goto <skip>;
$(T_FLAG) = 1;
<skip>
}
# Binary Addition with Overflow Check
# pattern 0011nnnnmmmm1111
# text addv <REG_M>,<REG_N>
# arch arch_sh_up
:addv M_0t,N_0t is OP_0=0x3 & N_0t & M_0t & OP_1=0xf {
dest:4 = 0;
dest = zext((!(N_0t s>= 0)));
src:4 = 0;
src = zext((!(M_0t s>= 0)));
src = src + dest;
N_0t = N_0t + M_0t;
ans:4 = 0;
ans = zext((!(N_0t s>= 0)));
ans = ans + dest;
bool:1 = ((src == 0) || (src == 2));
$(T_FLAG) = bool * (ans == 1) + !bool * ( 0 );
}
# Logical AND
# pattern 0010nnnnmmmm1001
# text and <REG_M>,<REG_N>
# arch arch_sh_up
:and M_0t,N_0t is OP_0=0x2 & N_0t & M_0t & OP_1=0x9 {
N_0t = N_0t & M_0t;
}
# Logical AND
# pattern 11001001iiiiiiii
# text and #<imm>,R0
# arch arch_sh_up
:and U_0t_r0 is OP_2=0xc9 & U_0t_r0 {
r0 = r0 & U_0t_r0;
}
# Logical AND
# pattern 11001101iiiiiiii
# text and.b #<imm>,@(R0,GBR)
# arch arch_sh_up
:and.b U_0t1 is OP_2=0xcd & U_0t1 {
*:1 (GBR + r0) = (*:1 (GBR + r0)) & U_0t1;
}
# Conditional Branch
# pattern 10001011iiiiiiii
# text bf <bdisp8>
# arch arch_sh_up
:bf I_0tbranch is OP_2=0x8b & I_0tbranch {
if ( $(T_FLAG) == 0 ) goto I_0tbranch;
}
# Conditional Branch with Delay
# pattern 10001111iiiiiiii
# text bf/s <bdisp8>
# arch arch_sh2_up
:bf^"/s" I_0tbranch is OP_2=0x8f & I_0tbranch {
local cond = $(T_FLAG);
delayslot(1);
if ( cond == 0 ) goto I_0tbranch;
}
# Unconditional Branch
# pattern 1010iiiiiiiiiiii
# text bra <bdisp12>
# arch arch_sh_up
:bra I_1tbranch is OP_0=0xa & I_1tbranch {
delayslot(1);
goto I_1tbranch;
}
# Unconditional Branch
# pattern 0000nnnn00100011
# text braf <REG_N>
# arch arch_sh2_up
:braf N_0 is OP_0=0x0 & N_0 & OP_4=0x23 {
local dest = N_0 + inst_next;
delayslot(1);
goto [dest];
}
# Branch to Subroutine Procedure
# pattern 1011iiiiiiiiiiii
# text bsr <bdisp12>
# arch arch_sh_up
:bsr I_1tbranch is OP_0=0xb & I_1tbranch {
delayslot(1);
call I_1tbranch;
}
# Branch to Subroutine Procedure
# pattern 0000nnnn00000011
# text bsrf <REG_N>
# arch arch_sh2_up
:bsrf N_0 is OP_0=0x0 & N_0 & OP_4=0x3 {
PR = inst_next;
local dest = N_0 + inst_next;
delayslot(1);
call [dest];
}
# Conditional Branch
# pattern 10001001iiiiiiii
# text bt <bdisp8>
# arch arch_sh_up
:bt I_0tbranch is OP_2=0x89 & I_0tbranch {
if ( $(T_FLAG) == 1 ) goto I_0tbranch;
}
# Conditional Branch with Delay
# pattern 10001101iiiiiiii
# text bt/s <bdisp8>
# arch arch_sh2_up
:bt^"/s" I_0tbranch is OP_2=0x8d & I_0tbranch {
local cond = $(T_FLAG);
delayslot(1);
if ( cond == 1 ) goto I_0tbranch;
}
# MAC Register Clear
# pattern 0000000000101000
# text clrmac
# arch arch_sh_up
:clrmac is OP_3=0x28 {
MACH = 0;
MACL = 0;
}
# S Bit Clear
# pattern 0000000001001000
# text clrs
# arch arch_sh_up
:clrs is OP_3=0x48 {
$(S_FLAG) = 0;
}
# T Bit Clear
# pattern 0000000000001000
# text clrt
# arch arch_sh_up
:clrt is OP_3=0x8 {
$(T_FLAG) = 0;
}
# Compare
# pattern 0011nnnnmmmm0000
# text cmp/eq <REG_M>,<REG_N>
# arch arch_sh_up
:cmp^"/eq" M_0t,N_0t is OP_0=0x3 & N_0t & M_0t & OP_1=0x0 {
$(T_FLAG) = ( N_0t == M_0t );
}
# Compare
# pattern 0011nnnnmmmm0011
# text cmp/ge <REG_M>,<REG_N>
# arch arch_sh_up
:cmp^"/ge" M_0t,N_0t is OP_0=0x3 & N_0t & M_0t & OP_1=0x3 {
$(T_FLAG) = ( N_0t s>= M_0t );
}
# Compare
# pattern 0011nnnnmmmm0111
# text cmp/gt <REG_M>,<REG_N>
# arch arch_sh_up
:cmp^"/gt" M_0t,N_0t is OP_0=0x3 & N_0t & M_0t & OP_1=0x7 {
$(T_FLAG) = ( N_0t s> M_0t);
}
# Compare
# pattern 0011nnnnmmmm0110
# text cmp/hi <REG_M>,<REG_N>
# arch arch_sh_up
:cmp^"/hi" M_0t,N_0t is OP_0=0x3 & N_0t & M_0t & OP_1=0x6 {
$(T_FLAG) = ( N_0t > M_0t );
}
# Compare
# pattern 0011nnnnmmmm0010
# text cmp/hs <REG_M>,<REG_N>
# arch arch_sh_up
:cmp^"/hs" M_0t,N_0t is OP_0=0x3 & N_0t & M_0t & OP_1=0x2 {
$(T_FLAG) = ( N_0t >= M_0t );
}
# Compare
# pattern 0100nnnn00010101
# text cmp/pl <REG_N>
# arch arch_sh_up
:cmp^"/pl" N_0t is OP_0=0x4 & N_0t & OP_4=0x15 {
$(T_FLAG) = ( N_0t s> 0 );
}
# Compare
# pattern 0100nnnn00010001
# text cmp/pz <REG_N>
# arch arch_sh_up
:cmp^"/pz" N_0t is OP_0=0x4 & N_0t & OP_4=0x11 {
$(T_FLAG) = ( N_0t s>= 0 );
}
# Compare
# pattern 0010nnnnmmmm1100
# text cmp/str <REG_M>,<REG_N>
# arch arch_sh_up
:cmp^"/str" M_0t,N_0t is OP_0=0x2 & N_0t & M_0t & OP_1=0xc {
temp:4 = M_0t ^ N_0t;
HH:4 = (temp & 0xFF000000) >> 24;
HL:4 = (temp & 0x00FF0000) >> 16;
LH:4 = (temp & 0x0000FF00) >> 8;
LL:4 = temp & 0x000000FF;
$(T_FLAG) = !((HH:1) && (HL:1) && (LH:1) && (LL:1));
}
# Compare
# pattern 10001111iiiiiiii
# pattern 10001000iiiiiiii
# text cmp/eq #<imm>,R0
# arch arch_sh_up
:cmp^"/eq" I_0t_r0 is OP_2=0x88 & I_0t_r0 {
$(T_FLAG) = ( r0 == I_0t_r0 );
}
# Initialization for Signed Division
# pattern 0010nnnnmmmm0111
# text div0s <REG_M>,<REG_N>
# arch arch_sh_up
:div0s M_0t,N_0t is OP_0=0x2 & N_0t & M_0t & OP_1=0x7 {
$(Q_FLAG) = ( (N_0t & 0x80000000) != 0 );
$(M_FLAG) = ( (M_0t & 0x80000000) != 0 );
$(T_FLAG) = ( $(M_FLAG) != $(Q_FLAG) );
}
# Initialization for Unsigned Division
# pattern 0000000000011001
# text div0u
# arch arch_sh_up
:div0u is OP_3=0x19 {
$(M_FLAG) = 0;
$(Q_FLAG) = 0;
$(T_FLAG) = 0;
}
# Division
# pattern 0011nnnnmmmm0100
# text div1 <REG_M>,<REG_N>
# arch arch_sh_up
:div1 M_0t,N_0t is OP_0=0x3 & OP_1=0x4 & M_0t & N_0t {
@ifdef DIV1_ORIGINAL_IS_BROKEN
tmp2:4 = M_0t;
N_0t = N_0t << 1;
N_0t = N_0t | zext($(T_FLAG)); # ???
tmp0:4 = N_0t;
N_0t = N_0t - zext((($(Q_FLAG)+$(M_FLAG))!=1))*tmp2 + zext(($(Q_FLAG)+$(M_FLAG))==1)*tmp2;
tmp1:1 = ( (($(Q_FLAG)+$(M_FLAG))!=1)*(N_0t > tmp0) + (($(Q_FLAG)+$(M_FLAG))==1)*(N_0t < tmp0));
$(Q_FLAG) = ((0x80000000 & N_0t)!=0);
Q1:1 = tmp1*($(Q_FLAG)!=0) + (tmp1==0)*($(Q_FLAG)==0);
Q2:1 = tmp1*($(Q_FLAG)==0) + (tmp1==0)*($(Q_FLAG)!=0);
$(Q_FLAG) = (($(M_FLAG)==1)*Q1 + ($(M_FLAG)!=1)*Q2);
$(T_FLAG) = ($(Q_FLAG)==$(M_FLAG));
@endif # DIV1_ORIGINAL_IS_BROKEN
# DIV1_WITH_FORWARD_BRANCHES_WORKS_OK
Rm:4 = M_0t;
Rn:4 = N_0t;
old_Q:1 = $(Q_FLAG);
$(Q_FLAG) = ((0x80000000 & Rn)!=0);
tmp2:4 = Rm;
Rn = Rn << 1;
Rn = Rn | zext($(T_FLAG));
tmp0:4 = Rn;
tmp1:1 = 0;
if (old_Q == 0) && ($(M_FLAG) == 0) goto <section_1>;
if (old_Q == 0) && ($(M_FLAG) == 1) goto <section_2>;
if (old_Q == 1) && ($(M_FLAG) == 0) goto <section_3>;
# if (old_Q == 1) && ($(M_FLAG) == 1) ...
Rn = Rn - tmp2;
tmp1 = Rn > tmp0;
if ($(Q_FLAG) == 0) goto <section_4a>;
# ($(Q_FLAG) == 1)
$(Q_FLAG) = tmp1;
goto <done>;
<section_4a>
$(Q_FLAG) = tmp1 == 0;
goto <done>;
<section_3> # (old_Q == 1) && ($(M_FLAG) == 0)
Rn = Rn + tmp2;
tmp1 = Rn < tmp0;
if ($(Q_FLAG) == 0) goto <section_3a>;
# ($(Q_FLAG) == 1)
$(Q_FLAG) = tmp1 == 0;
goto <done>;
<section_3a>
$(Q_FLAG) = tmp1;
goto <done>;
<section_2> # (old_Q == 0) && ($(M_FLAG) == 1)
Rn = Rn + tmp2;
tmp1 = Rn < tmp0;
if ($(Q_FLAG) == 0) goto <section_2a>;
# ($(Q_FLAG) == 1)
$(Q_FLAG) = tmp1;
goto <done>;
<section_2a>
$(Q_FLAG) = tmp1 == 0;
goto <done>;
<section_1> # (old_Q == 0) && ($(M_FLAG) == 0)
Rn = Rn - tmp2;
tmp1 = Rn > tmp0;
if ($(Q_FLAG) == 0) goto <section_1a>;
# ($(Q_FLAG) == 1)
$(Q_FLAG) = tmp1 == 0;
goto <done>;
<section_1a>
$(Q_FLAG) = tmp1;
<done>
$(T_FLAG) = $(Q_FLAG) == $(M_FLAG);
N_0t = Rn;
# DIV1_WITH_GOTOs_WORKS_OK
# TODO: the following is currently broken, it should be fixed to eliminate gotos in the code above
@ifdef DIV1_STRAIGHT_CODE # BROKEN
Rm:4 = M_0t;
Rn:4 = N_0t;
old_Q:1 = $(Q_FLAG);
$(Q_FLAG) = ((0x80000000 & Rn)!=0);
tmp2:4 = Rm;
Rn = Rn << 1;
Rn = Rn | zext($(T_FLAG));
tmp0:4 = Rn;
oldQM_10_01_bool:1 = ( ( (old_Q == 1) && ($(M_FLAG) == 0) ) || ( (old_Q == 1) && ($(M_FLAG) == 0) ) );
oldQM_10_01:4 = zext(oldQM_10_01_bool) * 0xffffffff;
oldQM_11_00_bool:1 = ( (old_Q == 1) && ($(M_FLAG) == 1) ) || ( (old_Q == 0) && ($(M_FLAG) == 0) );
oldQM_11_00:4 = zext(oldQM_11_00_bool) * 0xffffffff;
Rn = (oldQM_10_01 & (Rn + tmp2)) | (oldQM_11_00 & (Rn - tmp2));
tmp1:1 = ( (oldQM_11_00 != 0) && (Rn > tmp0) ) | ( (oldQM_10_01 != 0) && (Rn < tmp0) );
QM_10_01:1 = ( ( ($(Q_FLAG) == 1) && ($(M_FLAG) == 0) ) || ( ($(Q_FLAG) == 1) && ($(M_FLAG) == 0) ) ) * 0xff;
QM_11_00:1 = ( ( ($(Q_FLAG) == 1) && ($(M_FLAG) == 1) ) || ( ($(Q_FLAG) == 0) && ($(M_FLAG) == 0) ) ) * 0xff;
$(Q_FLAG) = (QM_10_01 & tmp1) || (QM_11_00 & (tmp1 == 0));
$(T_FLAG) = $(Q_FLAG) == $(M_FLAG);
N_0t = Rn;
@endif # DIV1_STRAIGHT_CODE
}
# Signed Double-Length Multiplication
# pattern 0011nnnnmmmm1101
# text dmuls.l <REG_M>,<REG_N>
# arch arch_sh2_up
:dmuls.l M_0t,N_0t is OP_0=0x3 & OP_1=0xd & M_0t & N_0t {
tempn:4 = N_0t;
tempm:4 = M_0t;
tempn = zext(tempn s> 0)*tempn - zext(tempn s< 0)*tempn;
tempm = zext(tempm s> 0)*tempm - zext(tempm s< 0)*tempm;
fnLmL:4 = zext((N_0t^M_0t) s< 0)*-1;
temp1:4 = tempn;
temp2:4 = tempm;
RnL:4 = temp1 & 0x0000FFFF;
RnH:4 = (temp1 >> 16) & 0x0000FFFF;
RmL:4 = temp2 & 0x0000FFFF;
RmH:4 = (temp2 >> 16) & 0x0000FFFF;
temp0:4 = RmL*RnL;
temp1 = RmH*RnL;
temp2 = RmL*RnH;
temp3:4 = RmH*RnH;
Res2:4 = 0;
Res1:4 = temp1 + temp2;
Res2 = Res2 + 0x00010000*zext(Res1 s< temp1);
temp1 = (Res1 << 16) & 0xFFFF0000;
Res0:4 = temp0 + temp1;
Res2 = Res2 + 1*zext(Res0 s< temp0);
Res2 = Res2 + ((Res1 >> 16) & 0x0000FFFF) + temp3;
if (!(fnLmL s< 0 )) goto <jmp1>;
Res2 = ~Res2;
Res2 = Res2*zext(Res0 != 0) + (Res2 + 1)*zext(Res0 == 0);
Res0 = (Res0*zext((Res0 == 0)) + (1+(~Res0))*zext((Res0 != 0)));
<jmp1>
MACH = Res2;
MACL = Res0;
}
# Unsigned Double-Length Multiplication
# pattern 0011nnnnmmmm0101
# text dmulu.l <REG_M>,<REG_N>
# arch arch_sh2_up
:dmulu.l M_0t,N_0t is OP_0=0x3 & OP_1=0x5 & M_0t & N_0t {
RnL:4 = N_0t & 0x0000FFFF;
RnH:4 = (N_0t >> 16) & 0x0000FFFF;
RmL:4 = M_0t & 0x0000FFFF;
RmH:4 = (M_0t >> 16) & 0x0000FFFF;
temp0:4 = RmL*RnL;
temp1:4 = RmH*RnL;
temp2:4 = RmL*RnH;
temp3:4 = RmH*RnH;
Res2:4 = 0;
Res1:4 = temp1 + temp2;
Res2 = Res2 + zext(Res1<temp1)*0x00010000;
temp1 = (Res1 << 16) & 0xFFFF0000;
Res0:4 = temp0 + temp1;
Res2 = Res2 + zext(Res0<temp1)*1;
Res2 = Res2 + ((Res1 >> 16) & 0x0000FFFF) + temp3;
MACH = Res2;
MACL = Res0;
}
# Decrement and Test
# pattern 0100nnnn00010000
# text dt <REG_N>
# arch arch_sh2_up
:dt N_0t is OP_0=0x4 & N_0t & OP_4=0x10 {
N_0t = N_0t - 1;
$(T_FLAG) = ( N_0t == 0 );
}
# Sign Extension
# pattern 0110nnnnmmmm1110
# text exts.b <REG_M>,<REG_N>
# arch arch_sh_up
:exts.b M_0t,N_0t is OP_0=0x6 & N_0t & M_0t & OP_1=0xe {
N_0t = sext(M_0t:1);
}
# Sign Extension
# pattern 0110nnnnmmmm1111
# text exts.w <REG_M>,<REG_N>
# arch arch_sh_up
:exts.w M_0t,N_0t is OP_0=0x6 & N_0t & M_0t & OP_1=0xf {
N_0t = sext(M_0t:2);
}
# Zero Extension
# pattern 0110nnnnmmmm1100
# text extu.b <REG_M>,<REG_N>
# arch arch_sh_up
:extu.b M_0t,N_0t is OP_0=0x6 & N_0t & M_0t & OP_1=0xc {
N_0t = zext(M_0t:1);
}
# Zero Extension
# pattern 0110nnnnmmmm1101
# text extu.w <REG_M>,<REG_N>
# arch arch_sh_up
:extu.w M_0t,N_0t is OP_0=0x6 & N_0t & M_0t & OP_1=0xd {
N_0t = zext(M_0t:2);
}
# Floating-Point Absolute Value
# pattern 1111nnnn01011101
# text fabs <F_REG_N>
# arch arch_sh2e_up
:fabs FRN_0 is
OP_0=0xf & FRN_0 & DRN_1 & OP_4=0x5d {
if (!( $(FPSCR_PR) == 0 )) goto <doublePrecision>;
FRN_0 = abs(FRN_0);
goto <skip>;
<doublePrecision>
DRN_1 = abs(DRN_1);
<skip>
}
# Floating-Point Addition
# pattern 1111nnnnmmmm0000
# text fadd <F_REG_M>,<F_REG_N>
# arch arch_sh2a_or_sh4_up
:fadd FRM_0,FRN_0 is
OP_0=0xf & FRN_0 & DRN_1 & FRM_0 & DRM_1 & OP_1=0x0 {
if (!( $(FPSCR_PR) == 0 )) goto <doublePrecision>;
FRN_0 = FRN_0 f+ FRM_0;
goto <skip>;
<doublePrecision>
DRN_1 = DRN_1 f+ DRM_1;
<skip>
}
# Floating-Point Comparison
# pattern 1111nnnnmmmm0100
# text fcmp/eq <F_REG_M>,<F_REG_N>
# arch arch_sh2e_up
:fcmp^"/eq" FRM_0t,FRN_0t is
OP_0=0xf & FRN_0t & DRN_1t & FRM_0t & DRM_1t & OP_6 & OP_10 & OP_1=0x4 {
if (!( $(FPSCR_PR) == 0 ) ) && (OP_6:1 == 0) && (OP_10:1 == 0) goto <doublePrecision>;
$(T_FLAG) = ( FRN_0t f== FRM_0t );
goto <skip>;
<doublePrecision>
$(T_FLAG) = ( DRN_1t f== DRM_1t );
<skip>
}
# Floating-Point Comparison
# pattern 1111nnnnmmmm0101
# text fcmp/gt <F_REG_M>,<F_REG_N>
# arch arch_sh2e_up
:fcmp^"/gt" FRM_0t,FRN_0t is
OP_0=0xf & FRM_0t & DRM_1t & FRN_0t & DRN_1t & OP_1=0x5 {
if (!( $(FPSCR_PR) == 0 )) goto <doublePrecision>;
$(T_FLAG) = ( FRN_0t f> FRM_0t );
goto <skip>;
<doublePrecision>
$(T_FLAG) = ( DRN_1t f> DRM_1t );
<skip>
}
# Double-Precision to Single-Precision Conversion
# pattern 1111nnn010111101
# text fcnvds <D_REG_N>,FPUL
# even though reserved to DblPrec, should decode, may not know at the time.
# if this instruction shows up, it is most likely in DblPrec mode but not set
# arch arch_sh2a_or_sh4_up
:fcnvds DRN_1t,FPUL is OP_0=0xf & DRN_1t & OP_5=0x0bd & FPUL {
# note: this instruction is undefined if not running in DblPrec mode.
FPUL = float2float( DRN_1t );
}
# Single-Precision to Double-Precision Conversion
# pattern 1111nnn010101101
# text fcnvsd FPUL,<D_REG_N>
# even though reserved to DblPrec, should decode, may not know at the time.
# if this instruction shows up, it is most likely in DblPrec mode but not set
# arch arch_sh2a_or_sh4_up
:fcnvsd FPUL,DRN_1t is OP_0=0xf & DRN_1t & OP_5=0xad & FPUL {
# note: this instruction is undefined if not running in DblPrec mode.
DRN_1t = float2float( FPUL );
}
# Floating-Point Division
# pattern 1111nnnnmmmm0011
# text fdiv <F_REG_M>,<F_REG_N>
# arch arch_sh2e_up
:fdiv FRM_0t,FRN_0t is
OP_0=0xf & FRN_0t & DRN_1t & FRM_0t & DRM_1t & OP_1=0x3 {
if (!( $(FPSCR_PR) == 0 )) goto <doublePrecision>;
FRN_0t = ( FRN_0t f/ FRM_0t );
goto <skip>;
<doublePrecision>
DRN_1t = ( DRN_1t f/ DRM_1t );
<skip>
}
# Floating-Point Inner Product
# pattern 1111nnmm11101101
# text fipr <V_REG_M>,<V_REG_N>
# even though reserved to DblPrec, should decode, may not know at the time.
# if this instruction shows up, it is most likely in DblPrec mode but not set
# arch arch_sh4_up
:fipr FVM_2t,FVN_2t is OP_0=0xf & FVN_2t & FVM_2t & OP_4=0xed {
# note: this instruction is undefined if not running in SinglePrec mode.
if (!( $(FPSCR_PR) == 0 )) goto <skip>;
# FVn dot FVm
temp1:4 = ( *[register]:4 (&:4 FVN_2t + 0) f* *[register]:4 (&:4 FVM_2t + 0) );
temp1 = temp1 f+ ( *[register]:4 (&:4 FVN_2t + 4) f* *[register]:4 (&:4 FVM_2t + 4) );
temp1 = temp1 f+ ( *[register]:4 (&:4 FVN_2t + 8) f* *[register]:4 (&:4 FVM_2t + 8) );
temp1 = temp1 f+ ( *[register]:4 (&:4 FVN_2t + 12) f* *[register]:4 (&:4 FVM_2t + 12) );
# summation goes to FR[n + 3]
*[register]:4 (&:4 FVN_2t + 12) = temp1;
<skip>
}
# 0.0 Load
# pattern 1111nnnn10001101
# text fldi0 <F_REG_N>
# arch arch_sh2e_up
#
# Note- The manual says this applies only to single float destination regs
#
:fldi0 FRN_0t is OP_0=0xf & DRN_1t & FRN_0t & OP_4=0x8d {
tmp1:4 = 0;
FRN_0t = int2float(tmp1);
}
# 1.0 Load
# pattern 1111nnnn10011101
# text fldi1 <F_REG_N>
# arch arch_sh2e_up
#
# Note- the manual says FPSCR_PR applies only to single float regs, not to doubles.
# Manual also says FPSCR_PR should be 0, but gcc generates code where it's set to 1.
#
:fldi1 FRN_0t is OP_0=0xf & FRN_0t & DRN_1t & OP_4=0x9d {
tmp1:4 = 1;
FRN_0t = int2float(tmp1);
}
# Transfer to System Register
# pattern 1111nnnn00011101
# text flds <F_REG_N>,FPUL
# arch # arch_sh2e_up
# Note: Field usage indicates FR[n], not FR[m].
:flds FRN_0t,FPUL is OP_0=0xf & FRN_0t & OP_4=0x1d & FPUL {
FPUL = FRN_0t;
}
# Integer to Floating-Point Conversion
# pattern 1111nnnn00101101
# text float FPUL,<F_REG_N>
# arch # arch_sh2e_up
:float FPUL,FRN_0t is
OP_0=0xf & OP_6 & FRN_0t & DRN_1t & OP_4=0x2d & FPUL {
# If bit 6 is set this this is an odd FP register number, so need to do single float operation.
# This is not in the manual but this seems to be the correct behavior.
if (!( $(FPSCR_PR) == 0 ) ) && (OP_6:1 == 0x0) goto <doublePrecision>;
FRN_0t = int2float( FPUL );
goto <skip>;
<doublePrecision>
DRN_1t = int2float( FPUL );
<skip>
}
# Floating-Point Multiply and Accumulate
# pattern 1111nnnnmmmm1110
# text fmac FR0,<F_REG_M>,<F_REG_N>
# arch arch_sh2e_up
:fmac FR0_t,FRM_0t,FRN_0t is OP_0=0xf & FRN_0t & FRM_0t & OP_1=0xe & FR0_t {
if (!( $(FPSCR_PR) == 0 )) goto <skip>;
FRN_0t = ( FR0_t f* FRM_0t ) f+ FRN_0t;
<skip>
}
# Floating-Point Transfer #1-4
# pattern 1111nnnnmmmm1100
# text fmov <F_REG_M>,<F_REG_N>
# arch arch_sh2e_up
#
# Note- The manual says all the fmov insns should only look at the FPSCR_SZ flag
# to determine if this is a single or double float move. Ie, don't reference FPSCR_PR.
#
:fmov FRM_0,FRN_0 is
OP_0=0xf & FRN_0 & XDRN & FRM_0 & XDRM & OP_1=0xc {
if (!( $(FPSCR_SZ) == 0 )) goto <doubleWidth>;
FRN_0 = FRM_0;
goto <skip>;
<doubleWidth>
XDRN = XDRM;
<skip>
}
# Floating-Point Transfer #5-6
# pattern 1111nnn0mmmm1000
# text fmov @<REG_M>,<F_REG_N>
# arch arch_sh2e_up
:fmov.s M_0t_at1,FRN_0 is
OP_0=0xf & XDRN & FRN_0 & M_0t_at1 & OP_1=0x8 {
if (!( $(FPSCR_SZ) == 0 )) goto <doubleWidth>;
FRN_0 = *:4 M_0t_at1;
goto <skip>;
<doubleWidth>
XDRN = *:8 M_0t_at1;
<skip>
}
# Floating-Point Transfer #7-8
# pattern 1111nnnnmmmm1010
# text fmov <F_REG_M>,@<REG_N>
# arch arch_sh2e_up
#
# Note- Manual says to ignore FPSCR_PR but FPSCR_SZ must = 0
#
:fmov.s FRM_0,N_0t_at1 is
OP_0=0xf & N_0t_at1 & FRM_0 & XDRM & OP_1=0xa {
if (!( $(FPSCR_SZ) == 0 )) goto <doubleWidth>;
*:4 N_0t_at1 = FRM_0;
goto <skip>;
<doubleWidth>
*:8 N_0t_at1 = XDRM;
<skip>
}
# Floating-Point Transfer #9-10
# pattern 1111nnnnmmmm1001
# text fmov @<REG_M>+,<F_REG_N>
# arch arch_sh2e_up
:fmov.s M_0t_at,FRN_0 is
OP_0=0xf & XDRN & FRN_0 & M_0t_at & OP_1=0x9 {
if (!( $(FPSCR_SZ) == 0 )) goto <doubleWidth>;
FRN_0 = *:4 M_0t_at;
M_0t_at = M_0t_at + 4;
goto <skip>;
<doubleWidth>
XDRN = *:8 M_0t_at;
M_0t_at = M_0t_at + 8;
<skip>
}
# Floating-Point Transfer #11-12
# pattern 1111nnnnmmm01011
# text fmov <F_REG_M>,@-<REG_N>
# arch arch_sh2e_up
:fmov.s FRM_0,N_0t_at_neg is
OP_0=0xf & N_0t_at_neg & XDRM & FRM_0 & OP_1=0xb {
if (!( $(FPSCR_SZ) == 0 )) goto <doubleWidth>;
*:4 N_0t_at_neg = FRM_0;
N_0t_at_neg = N_0t_at_neg - 4;
goto <skip>;
<doubleWidth>
*:8 N_0t_at_neg = XDRM;
N_0t_at_neg = N_0t_at_neg - 8;
<skip>
}
# Floating-Point Transfer #13-14
# pattern 1111nnnnmmmm0110
# text fmov @(R0,<REG_M>),<F_REG_N>
# arch arch_sh2e_up
:fmov.s M_0t_at_with_r0,FRN_0 is
OP_0=0xf & XDRN & FRN_0 & M_0t_at_with_r0 & OP_1=0x6 {
if (!( $(FPSCR_SZ) == 0 )) goto <doubleWidth>;
FRN_0 = *:4 (r0 + M_0t_at_with_r0);
goto <skip>;
<doubleWidth>
XDRN = *:8 (r0 + M_0t_at_with_r0);
<skip>
}
# Floating-Point Transfer #15-16
# pattern 1111nnnnmmmm0111
# text fmov @(R0,<REG_M>),<F_REG_N>
# arch arch_sh2e_up
:fmov FRM_0,N_0t_at_with_r0 is
OP_0=0xf & N_0t_at_with_r0 & XDRM & FRM_0 & OP_1=0x7 {
if (!( $(FPSCR_SZ) == 0 )) goto <doubleWidth>;
*:4 (r0 + N_0t_at_with_r0) = FRM_0;
goto <skip>;
<doubleWidth>
*:8 (r0 + N_0t_at_with_r0) = XDRM;
<skip>
}
# Floating-Point Multiplication
# pattern 1111nnnnmmmm0010
# text fmul <F_REG_M>,<F_REG_N>
# arch arch_sh2e_up
:fmul FRM_0t,FRN_0t is
OP_0=0xf & FRN_0t & DRN_1t & FRM_0t & DRM_1t & OP_1=0x2 {
if (!( $(FPSCR_PR) == 0 )) goto <doublePrecision>;
FRN_0t = FRN_0t f* FRM_0t;
goto <skip>;
<doublePrecision>
DRN_1t = DRN_1t f* DRM_1t;
<skip>
}
# Floating-Point Sign Inversion
# pattern 1111nnnn01001101
# text fneg <F_REG_N>
# arch arch_sh2e_up
:fneg FRN_0t is
OP_0=0xf & FRN_0t & DRN_1t & OP_6 & OP_4=0x4d {
if (!( $(FPSCR_PR) == 0 )) && (OP_6:1 == 0) goto <doublePrecision>;
FRN_0t = f- FRN_0t;
goto <skip>;
<doublePrecision>
DRN_1t = f- DRN_1t;
<skip>
}
# FR Bit Inversion
# pattern 1111101111111101
# text frchg
# arch # arch_sh4_up
:frchg is
OP_3=0xfbfd {
if (!( $(FPSCR_PR) == 0 )) goto <skip>;
$(FPSCR_FR) = !$(FPSCR_FR);
FPSCR = FPSCR ^ 0x00200000;
<skip>
}
# SZ Bit Inversion
# pattern 1111001111111101
# text fschg
# arch arch_sh2a_or_sh4a_up (not in sh4)
:fschg is
OP_3=0xf3fd {
if (!( $(FPSCR_PR) == 0 )) goto <skip>;
FPSCR = FPSCR ^ 0x00100000;
<skip>
}
# PR Bit Inversion
# pattern 1111011111111101
# text fpchg
# arch arch_sh2a_or_sh4_up
:fpchg is
OP_3=0xf7fd {
FPSCR = FPSCR ^ 0x00080000;
}
# Floating-Point Square Root
# pattern 1111nnnn01101101
# text fsqrt <F_REG_N>
# arch # arch_sh2a_or_sh3e_up
:fsqrt FRN_0t is
OP_0=0xf & FRN_0t & DRN_1t & OP_4=0x6d {
if (!( $(FPSCR_PR) == 0 )) goto <doublePrecision>;
FRN_0t = sqrt( FRN_0t );
goto <skip>;
<doublePrecision>
DRN_1t = sqrt( DRN_1t );
<skip>
}
# Transfer from System Register
# pattern 1111nnnn00001101
# text fsts FPUL,<F_REG_N>
# arch arch_sh2e_up
:fsts FPUL,FRN_0t is OP_0=0xf & FRN_0t & OP_4=0xd & FPUL {
FRN_0t = FPUL;
}
# Floating-Point Subtraction
# pattern 1111nnnnmmmm0001
# text fsub <F_REG_M>,<F_REG_N>
# arch arch_sh2e_up
:fsub FRM_0t,FRN_0t is
OP_0=0xf & FRN_0t & DRN_1t & FRM_0t & DRM_1t & OP_1=0x1 {
if (!( $(FPSCR_PR) == 0 )) goto <doublePrecision>;
FRN_0t = FRN_0t f- FRM_0t;
goto <skip>;
<doublePrecision>
DRN_1t = DRN_1t f- DRM_1t;
<skip>
}
# Conversion to Integer
# pattern 1111nnnn00111101
# text ftrc <F_REG_N>,FPUL
# # arch arch_sh2e_up
# Note: Field usage indicates FR[n], not FR[m].
:ftrc FRN_0t,FPUL is
OP_0=0xf & FRN_0t & DRN_1t & OP_4=0x3d & FPUL {
if (!( $(FPSCR_PR) == 0 )) goto <doublePrecision>;
FPUL = trunc( FRN_0t );
goto <skip>;
<doublePrecision>
FPUL = trunc( DRN_1t );
<skip>
}
# Vector Transformation
# pattern 1111nn0111111101
# text ftrv XMTRX_M4,<V_REG_n>
# arch # arch_sh4_up
:ftrv XMTRX_t,FVN_2t is OP_0=0xf & FVN_2t & OP_8=0x1fd & XMTRX_t {
if (!( $(FPSCR_PR) == 0 )) goto <skip>;
temp1:4 = ( xf0 f* *[register]:4 (&:4 FVN_2t + 0) );
temp1 = temp1 f+ ( xf4 f* *[register]:4 (&:4 FVN_2t + 4) );
temp1 = temp1 f+ ( xf8 f* *[register]:4 (&:4 FVN_2t + 8) );
temp1 = temp1 f+ ( xf12 f* *[register]:4 (&:4 FVN_2t + 12) );
temp2:4 = ( xf1 f* *[register]:4 (&:4 FVN_2t + 0) );
temp2 = temp2 f+ ( xf5 f* *[register]:4 (&:4 FVN_2t + 4) );
temp2 = temp2 f+ ( xf9 f* *[register]:4 (&:4 FVN_2t + 8) );
temp2 = temp2 f+ ( xf13 f* *[register]:4 (&:4 FVN_2t + 12) );
temp3:4 = ( xf2 f* *[register]:4 (&:4 FVN_2t + 0) );
temp3 = temp3 f+ ( xf6 f* *[register]:4 (&:4 FVN_2t + 4) );
temp3 = temp3 f+ ( xf10 f* *[register]:4 (&:4 FVN_2t + 8) );
temp3 = temp3 f+ ( xf14 f* *[register]:4 (&:4 FVN_2t + 12) );
temp4:4 = ( xf3 f* *[register]:4 (&:4 FVN_2t + 0) );
temp4 = temp4 f+ ( xf7 f* *[register]:4 (&:4 FVN_2t + 4) );
temp4 = temp4 f+ ( xf11 f* *[register]:4 (&:4 FVN_2t + 8) );
temp4 = temp4 f+ ( xf15 f* *[register]:4 (&:4 FVN_2t + 12) );
# summation goes to FR[n + 0] through FR[n + 3]
*[register]:4 (&:4 FVN_2t + 0) = temp1;
*[register]:4 (&:4 FVN_2t + 4) = temp2;
*[register]:4 (&:4 FVN_2t + 8) = temp3;
*[register]:4 (&:4 FVN_2t + 12) = temp4;
<skip>
}
# Invalidate Instruction Cache block
# pattern 0000nnnn11100011
# text icib @<REG_N>
# arch arch_sh_up
define pcodeop InvalidateCacheBlock;
:icbi N_0t_at1 is OP_0=0x0 & N_0t_at1 & OP_4=0xe3 {
tmp:4 = N_0t_at1;
InvalidateCacheBlock(tmp);
}
# Unconditional Branch
# pattern 0100nnnn00101011
# text jmp @<REG_N>
# arch arch_sh_up
:jmp N_0tjmp is OP_0=0x4 & N_0tjmp & OP_4=0x2b {
PC = N_0tjmp;
tmp:4 = PC;
delayslot(1);
goto [tmp];
}
# Branch to Subroutine Procedure
# pattern 0100nnnn00001011
# text jsr @<REG_N>
# arch arch_sh_up
:jsr N_0tjmp is OP_0=0x4 & N_0tjmp & OP_4=0xb {
PR = inst_next;
PC = N_0tjmp;
tmp:4 = PC;
delayslot(1);
call [tmp];
}
# Load to Control Register
# pattern 0100nnnn00001110
# text ldc <REG_N>,SR
# arch arch_sh_up
:ldc N_0t_sr is OP_0=0x4 & N_0t_sr & OP_4=0xe {
splitSRregister();
SR = (N_0t_sr & 0x700083f3);
}
# Load to Control Register
# pattern 0100nnnn00011110
# text ldc <REG_N>,GBR
# arch arch_sh_up
:ldc N_0t_gbr is OP_0=0x4 & N_0t_gbr & OP_4=0x1e {
GBR = N_0t_gbr;
}
# Load to Control Register
# pattern 0100nnnn00101110
# text ldc <REG_N>,VBR
# arch arch_sh_up
:ldc N_0t_vbr is OP_0=0x4 & N_0t_vbr & OP_4=0x2e {
VBR = N_0t_vbr;
}
# pattern 0100nnnn00111110
# text ldc <REG_N>,SSR
# arch arch_sh3_nommu_up
:ldc N_0t_ssr is OP_0=0x4 & N_0t_ssr & OP_4=0x3e {
SSR = N_0t_ssr;
}
# pattern 0100nnnn01001110
# text ldc <REG_N>,SPC
# arch arch_sh3_nommu_up
:ldc N_0t_spc is OP_0=0x4 & N_0t_spc & OP_4=0x4e {
SPC = N_0t_spc;
}
# pattern 0100nnnn11111010
# text ldc <REG_N>,DBR
# arch arch_sh4_nommu_nofpu_up
:ldc N_0t_dbr is OP_0=0x4 & N_0t_dbr & OP_4=0xfa {
DBR = N_0t_dbr;
}
# pattern 0100nnnn1xxx1110
# text ldc <REG_N>,Rn_BANK
# arch arch_sh3_nommu_up
:ldc N_0t_bank,BANKt is OP_0=0x4 & N_0t_bank & OP_9=0x1 & BANKt & OP_1=0xe {
BANKt = N_0t_bank;
}
# Load to Control Register
# pattern 0100nnnn00000111
# text ldc.l @<REG_N>+,SR
# arch arch_sh_up
:ldc.l N_0t_sr1 is OP_0=0x4 & N_0t_sr1 & OP_4=0x7 {
SR = (*:4 ( N_0t_sr1 )) & 0x700083F3;
splitSRregister();
N_0t_sr1 = N_0t_sr1 + 4;
}
# Load to Control Register
# pattern 0100nnnn00010111
# text ldc.l @<REG_N>+,GBR
# arch arch_sh_up
:ldc.l N_0t_gbr1 is OP_0=0x4 & N_0t_gbr1 & OP_4=0x17 {
GBR = *:4 ( N_0t_gbr1 );
N_0t_gbr1 = N_0t_gbr1 + 4;
}
# Load to Control Register
# pattern 0100nnnn00100111
# text ldc.l @<REG_N>+,VBR
# arch arch_sh_up
:ldc.l N_0t_vbr1 is OP_0=0x4 & N_0t_vbr1 & OP_4=0x27 {
VBR = *:4 ( N_0t_vbr1 );
N_0t_vbr1 = N_0t_vbr1 + 4;
}
# pattern 0100nnnn00110111
# text ldc.l @<REG_N>+,SSR
# arch arch_sh3_nommu_up
:ldc.l N_0t_ssr1 is OP_0=0x4 & N_0t_ssr1 & OP_4=0x37 {
SSR = *:4 ( N_0t_ssr1 );
N_0t_ssr1 = N_0t_ssr1 + 4;
}
# pattern 0100nnnn01000111
# text ldc.l @<REG_N>+,SPC
# arch arch_sh3_nommu_up
:ldc.l N_0t_spc1 is OP_0=0x4 & N_0t_spc1 & OP_4=0x47 {
SPC = *:4 ( N_0t_spc1 );
N_0t_spc1 = N_0t_spc1 + 4;
}
# pattern 0100nnnn11110110
# text ldc.l @<REG_N>+,DBR
# arch arch_sh4_nommu_nofpu_up
:ldc.l N_0t_dbr1 is OP_0=0x4 & N_0t_dbr1 & OP_4=0xf6 {
DBR = *:4 ( N_0t_dbr1 );
N_0t_dbr1 = N_0t_dbr1 + 4;
}
# pattern 0100nnnn1xxx0111
# text ldc.l @<REG_N>+,Rn_BANK
# arch arch_sh3_nommu_up
:ldc.l N_0t_bank1,BANKt is OP_0=0x4 & N_0t_bank1 & OP_9=0x1 & BANKt & OP_1=0x7 {
BANKt = *:4 ( N_0t_bank1 );
N_0t_bank1 = N_0t_bank1 + 4;
}
# Load to FPU System Register
# pattern 0100nnnn01011010
# text lds <REG_N>,FPUL
# arch arch_sh2e_up
:lds N_0t_fpul is OP_0=0x4 & N_0t_fpul & OP_4=0x5a {
FPUL = N_0t_fpul;
}
# Load to FPU System Register
# pattern 0100nnnn01010110
# text lds.l @<REG_M>+,FPUL
# arch arch_sh2e_up
:lds.l N_0t_fpul1 is OP_0=0x4 & N_0t_fpul1 & OP_4=0x56 {
FPUL = *:4 ( N_0t_fpul1 );
N_0t_fpul1 = N_0t_fpul1 + 4;
}
# Load to FPU System Register
# pattern 0100nnnn01101010
# text lds <REG_M>,FPSCR
# arch arch_sh2e_up
# Note: FPSCR context cannot be supported from this instruction; contents of N_0 not known at disassembly time.
:lds N_0t_fpscr is OP_0=0x4 & N_0t_fpscr & OP_4=0x6a {
FPSCR = N_0t_fpscr & 0x003FFFFF;
splitFPSCRregister();
}
# Load to FPU System Register
# pattern 0100nnnn01100110
# text lds.l @<REG_M>+,FPSCR
# arch arch_sh2e_up
# Note: FPSCR context cannot be supported from this instruction; contents of N_0 not known at disassembly time.
:lds.l N_0t_fpscr1 is OP_0=0x4 & N_0t_fpscr1 & OP_4=0x66 {
FPSCR = (*:4 ( N_0t_fpscr1 )) & 0x003FFFFF;
splitFPSCRregister();
N_0t_fpscr1 = N_0t_fpscr1 + 4;
}
# Load to FPU System Register
# pattern 0100nnnn00001010
# text lds <REG_N>,MACH
# arch arch_sh_up
:lds N_0t_mach is OP_0=0x4 & N_0t_mach & OP_4=0xa {
MACH = N_0t_mach;
}
# Load to FPU System Register
# pattern 0100nnnn00011010
# text lds <REG_N>,MACL
# arch arch_sh_up
:lds N_0t_macl is OP_0=0x4 & N_0t_macl & OP_4=0x1a {
MACL = N_0t_macl;
}
# Load to FPU System Register
# pattern 0100nnnn00101010
# text lds <REG_N>,PR
# arch arch_sh_up
:lds N_0t_pr is OP_0=0x4 & N_0t_pr & OP_4=0x2a {
PR = N_0t_pr;
}
# Load to FPU System Register
# pattern 0100nnnn00000110
# text lds.l @<REG_N>+,MACH
# arch arch_sh_up
:lds.l N_0t_mach1 is OP_0=0x4 & N_0t_mach1 & OP_4=0x6 {
MACH = *:4 ( N_0t_mach1 );
N_0t_mach1 = N_0t_mach1 + 4;
}
# Load to FPU System Register
# pattern 0100nnnn00010110
# text lds.l @<REG_N>+,MACL
# arch arch_sh_up
:lds.l N_0t_macl1 is OP_0=0x4 & N_0t_macl1 & OP_4=0x16 {
MACL = *:4 ( N_0t_macl1 );
N_0t_macl1 = N_0t_macl1 + 4;
}
# Load to FPU System Register
# pattern 0100nnnn00100110
# text lds.l @<REG_N>+,PR
# arch arch_sh_up
:lds.l N_0t_pr1 is OP_0=0x4 & N_0t_pr1 & OP_4=0x26 {
PR = *:4 ( N_0t_pr1 );
N_0t_pr1 = N_0t_pr1 + 4;
}
define pcodeop LoadTranslationLookasideBuffer;
# Load to TLB
# pattern 0000000000111000
# text ldtlb
# arch arch_sh3_up
:ldtlb is OP_3=0x38 { LoadTranslationLookasideBuffer(); }
# Double-Precision Multiply-and-Accumulate Operation
# pattern 0000nnnnmmmm1111
# text mac.l @<REG_M>+,@<REG_N>+
# arch arch_sh2_up
define pcodeop mac_lOp;
:mac.l M_0t_at,N_0t_at is OP_0=0x0 & OP_1=0xf & M_0t_at & N_0t_at {
tmpM:4 = *:4 M_0t_at;
tmpN:4 = *:4 N_0t_at;
mac:8 = mac_lOp(tmpN,tmpM,MACH,MACL);
# POSSIBLE THIS WILL WORK WELL ENOUGH
# mac:8 = zext(MACH) << 4 + zext(MACL);
# mac = zext(tmpN) * zext(tmpM) + mac;
# mac = saturate(mac);
MACL = mac:4;
mac = mac >> 32;
MACH = mac:4;
M_0t_at = M_0t_at + 4;
N_0t_at = N_0t_at + 4;
}
# Single-Precision Multiply-and-Accumulate Operation
# pattern 0100nnnnmmmm1111
# text mac.w @<REG_M>+,@<REG_N>+
# arch arch_sh_up
define pcodeop mac_wOp;
:mac.w M_0t_at,N_0t_at is OP_0=0x4 & OP_1=0xf & M_0t_at & N_0t_at {
tmpM:4 = *:2 M_0t_at;
tmpN:4 = *:2 N_0t_at;
mac:8 = mac_wOp(tmpN,tmpM,MACH,MACL);
# POSSIBLE THIS WILL WORK WELL ENOUGH
# mac:8 = zext(MACH) << 4 + zext(MACL);
# mac = zext(tmpN) * zext(tmpM) + mac;
# mac = saturate(mac);
MACL = mac:4;
mac = mac >> 32;
MACH = mac:4;
M_0t_at = M_0t_at + 2;
N_0t_at = N_0t_at + 2;
}
# Data Transfer
# pattern 0110nnnnmmmm0011
# text mov <REG_M>,<REG_N>
# arch arch_sh_up
:mov M_0t,N_0t is OP_0=0x6 & N_0t & M_0t & OP_1=0x3 {
N_0t = M_0t;
}
# Data Transfer
# pattern 0010nnnnmmmm0000
# text mov.b <REG_M>,@<REG_N>
# arch arch_sh_up
:mov.b M_0t,N_0t_at1 is OP_0=0x2 & N_0t_at1 & M_0t & OP_1=0x0 {
*:1 ( N_0t_at1 ) = M_0t:1;
}
# Data Transfer
# pattern 0010nnnnmmmm0001
# text mov.w <REG_M>,@<REG_N>
# arch arch_sh_up
:mov.w M_0t,N_0t_at1 is OP_0=0x2 & N_0t_at1 & M_0t & OP_1=0x1 {
*:2 ( N_0t_at1 ) = M_0t:2;
}
# Data Transfer
# pattern 0010nnnnmmmm0010
# text mov.l <REG_M>,@<REG_N>
# arch arch_sh_up
:mov.l M_0t,N_0t_at1 is OP_0=0x2 & N_0t_at1 & M_0t & OP_1=0x2 {
*:4 ( N_0t_at1 ) = M_0t;
}
# Data Transfer
# pattern 0110nnnnmmmm0000
# text mov.b @<REG_M>,<REG_N>
# arch arch_sh_up
:mov.b M_0t_at1,N_0t is OP_0=0x6 & N_0t & M_0t_at1 & OP_1=0x0 {
N_0t = sext( *:1 ( M_0t_at1 ) );
}
# Data Transfer
# pattern 0110nnnnmmmm0001
# text mov.w @<REG_M>,<REG_N>
# arch arch_sh_up
:mov.w M_0t_at1,N_0t is OP_0=0x6 & N_0t & M_0t_at1 & OP_1=0x1 {
N_0t = sext( *:2 ( M_0t_at1 ) );
}
# Data Transfer
# pattern 0110nnnnmmmm0010
# text mov.l @<REG_M>,<REG_N>
# arch arch_sh_up
:mov.l M_0t_at1,N_0t is OP_0=0x6 & N_0t & M_0t_at1 & OP_1=0x2 {
N_0t = *:4 ( M_0t_at1 );
}
# Data Transfer
# pattern 0010nnnnmmmm0100
# text mov.b <REG_M>,@-<REG_N>
# arch arch_sh_up
:mov.b M_0t,N_0t_at_neg is OP_0=0x2 & N_0t_at_neg & M_0t & OP_1=0x4 {
N_0t_at_neg = N_0t_at_neg - 1;
*:1 ( N_0t_at_neg ) = M_0t:1;
}
# Data Transfer
# pattern 0010nnnnmmmm0101
# text mov.w <REG_M>,@-<REG_N>
# arch arch_sh_up
:mov.w M_0t,N_0t_at_neg is OP_0=0x2 & N_0t_at_neg & M_0t & OP_1=0x5 {
N_0t_at_neg = N_0t_at_neg - 2;
*:2 ( N_0t_at_neg ) = M_0t:2;
}
# Data Transfer
# pattern 0010nnnnmmmm0110
# text mov.l <REG_M>,@-<REG_N>
# arch arch_sh_up
:mov.l M_0t,N_0t_at_neg is OP_0=0x2 & N_0t_at_neg & M_0t & OP_1=0x6 {
N_0t_at_neg = N_0t_at_neg - 4;
*:4 ( N_0t_at_neg ) = M_0t;
}
# Data Transfer
# pattern 0110nnnnmmmm0100
# text mov.b @<REG_M>+,<REG_N>
# arch arch_sh_up
:mov.b M_0t_at,N_0t is OP_0=0x6 & N_0t & M_0t_at & OP_1=0x4 {
N_0t = sext( *:1 ( M_0t_at ) );
M_0t_at = M_0t_at + 1;
}
# Data Transfer
# pattern 0110nnnnmmmm0101
# text mov.w @<REG_M>+,<REG_N>
# arch arch_sh_up
:mov.w M_0t_at,N_0t is OP_0=0x6 & N_0t & M_0t_at & OP_1=0x5 {
N_0t = sext( *:2 ( M_0t_at ) );
M_0t_at = M_0t_at + 2;
}
# Data Transfer
# pattern 0110nnnnmmmm0110
# text mov.l @<REG_M>+,<REG_N>
# arch arch_sh_up
:mov.l M_0t_at,N_0t is OP_0=0x6 & N_0t & M_0t_at & OP_1=0x6 {
N_0t = *:4 ( M_0t_at );
M_0t_at = M_0t_at + 4;
}
# Data Transfer
# pattern 0000nnnnmmmm0100
# text mov.b <REG_M>,@(R0,<REG_N>)
# arch arch_sh_up
:mov.b M_0t,N_0t_at_with_r0 is OP_0=0x0 & N_0t_at_with_r0 & M_0t & OP_1=0x4 {
*:1 ( r0 + N_0t_at_with_r0 ) = M_0t:1;
}
# Data Transfer
# pattern 0000nnnnmmmm0101
# text mov.w <REG_M>,@(R0,<REG_N>)
# arch arch_sh_up
:mov.w M_0t,N_0t_at_with_r0 is OP_0=0x0 & N_0t_at_with_r0 & M_0t & OP_1=0x5 {
*:2 ( r0 + N_0t_at_with_r0 ) = M_0t:2;
}
# Data Transfer
# pattern 0000nnnnmmmm0110
# text mov.l <REG_M>,@(R0,<REG_N>)
# arch arch_sh_up
:mov.l M_0t,N_0t_at_with_r0 is OP_0=0x0 & N_0t_at_with_r0 & M_0t & OP_1=0x6 {
*:4 ( r0 + N_0t_at_with_r0 ) = M_0t;
}
# Data Transfer
# pattern 0000nnnnmmmm1100
# text mov.b @(R0,<REG_M>),<REG_N>
# arch arch_sh_up
:mov.b M_0t_at_with_r0,N_0t is OP_0=0x0 & N_0t & M_0t_at_with_r0 & OP_1=0xc {
N_0t = sext( *:1 ( r0 + M_0t_at_with_r0 ) );
}
# Data Transfer
# pattern 0000nnnnmmmm1101
# text mov.w @(R0,<REG_M>),<REG_N>
# arch arch_sh_up
:mov.w M_0t_at_with_r0,N_0t is OP_0=0x0 & N_0t & M_0t_at_with_r0 & OP_1=0xd {
N_0t = sext( *:2 ( r0 + M_0t_at_with_r0 ) );
}
# Data Transfer
# pattern 0000nnnnmmmm1110
# text mov.l @(R0,<REG_M>),<REG_N>
# arch arch_sh_up
:mov.l M_0t_at_with_r0,N_0t is OP_0=0x0 & N_0t & M_0t_at_with_r0 & OP_1=0xe {
N_0t = *:4 ( r0 + M_0t_at_with_r0 );
}
# Data Transfer
# pattern 1110nnnniiiiiiii
# text mov #<imm>,<REG_N>
# arch arch_sh_up
:mov I_0t,N_0t is OP_0=0xe & N_0t & I_0t {
N_0t = I_0t; # NOTE I_0t already signed extended
}
# Data Transfer
# pattern 1001nnnndddddddd
# text mov.w @(<disp>,PC),<REG_N>
# arch arch_sh_up
:mov.w U_0t_2pc,N_0t is OP_0=0x9 & N_0t & U_0t_2pc {
N_0t = sext( U_0t_2pc ); # NOTE U_0t_2pc units is bytes
}
# Data Transfer
# pattern 1101nnnndddddddd
# text mov.l @(<disp>,PC),<REG_N>
# arch arch_sh_up
:mov.l U_0t_4pc,N_0t is OP_0=0xd & N_0t & U_0t_4pc {
N_0t = U_0t_4pc; # NOTE U_0t_4pc units is bytes
}
# Data Transfer
# pattern 11000100dddddddd
# text mov.b @(<disp>,GBR),R0
# arch arch_sh_up
:mov.b U_0t_gbr_at_1,r0 is OP_2=0xc4 & U_0t_gbr_at_1 & r0 {
r0 = sext( *:1 ( U_0t_gbr_at_1 ) );
}
# Data Transfer
# pattern 11000101dddddddd
# text mov.w @(<disp>,GBR),R0
# arch arch_sh_up
:mov.w U_0t_gbr_at_2,r0 is OP_2=0xc5 & U_0t_gbr_at_2 & r0 {
r0 = sext( *:2 ( U_0t_gbr_at_2 ) ); # NOTE U_0t_gbr_at_2 units is bytes
}
# Data Transfer
# pattern 11000110dddddddd
# text mov.l @(<disp>,GBR),R0
# arch arch_sh_up
:mov.l U_0t_gbr_at_4,r0 is OP_2=0xc6 & U_0t_gbr_at_4 & r0 {
r0 = *:4 ( U_0t_gbr_at_4 ); # NOTE U_0t_gbr_at_4 units is bytes
}
# Data Transfer
# pattern 11000000dddddddd
# text mov.b R0,@(<disp>,GBR)
# arch arch_sh_up
:mov.b r0,U_0t_gbr_at_1 is OP_2=0xc0 & U_0t_gbr_at_1 & r0 {
*:1 ( U_0t_gbr_at_1 ) = r0:1;
}
# Data Transfer
# pattern 11000001dddddddd
# text mov.w R0,@(<disp>,GBR)
# arch arch_sh_up
:mov.w r0,U_0t_gbr_at_2 is OP_2=0xc1 & U_0t_gbr_at_2 & r0 {
*:2 ( U_0t_gbr_at_2 ) = r0:2; # NOTE U_0t_gbr_at_2 units is bytes
}
# Data Transfer
# pattern 11000010dddddddd
# text mov.l R0,@(<disp>,GBR)
# arch arch_sh_up
:mov.l r0, U_0t_gbr_at_4 is OP_2=0xc2 & U_0t_gbr_at_4 & r0 {
*:4 ( U_0t_gbr_at_4 ) = r0; # NOTE U_0t_4_at_gbr_r0_1 units is bytes
}
# Data Transfer
# pattern 10000000mmmmdddd
# text mov.b R0,@(<disp>,<REG_M>)
# arch arch_sh_up
:mov.b r0,U_2t_M0_dispr01 is OP_2=0x80 & M_0t & U_2t_M0_dispr01 & r0 {
*:1 ( U_2t_M0_dispr01 + M_0t ) = r0:1;
}
# Data Transfer
# pattern 10000001mmmmdddd
# text mov.w R0,@(<disp>,<REG_M>)
# arch arch_sh_up
:mov.w r0,U_2t_M0_dispr02 is OP_2=0x81 & M_0t & U_2t_M0_dispr02 & r0 {
*:2 ( U_2t_M0_dispr02 + M_0t ) = r0:2; # NOTE U_2t_M0_dispr02 units is bytes
}
# Data Transfer
# pattern 0001nnnnmmmmdddd
# text mov.l <REG_M>,@(<disp>,<REG_N>)
# arch arch_sh_up
:mov.l M_0t,U_2t_N0_dispr04 is OP_0=0x1 & M_0t & N_0t & U_2t_N0_dispr04 {
*:4 ( U_2t_N0_dispr04 + N_0t ) = M_0t; # NOTE U_2t_N0_dispr04 units is bytes
}
# Data Transfer
# pattern 10000100mmmmdddd
# text mov.b @(<disp>,<REG_M>),R0
# arch arch_sh_up
:mov.b U_2t_M0_dispr01,r0 is OP_2=0x84 & M_0t & U_2t_M0_dispr01 & r0 {
r0 = sext( *:1 ( U_2t_M0_dispr01 + M_0t ) );
}
# Data Transfer
# pattern 10000101mmmmdddd
# text mov.w @(<disp>,<REG_M>),R0
# arch arch_sh_up
:mov.w U_2t_M0_dispr02,r0 is OP_2=0x85 & U_2t_M0_dispr02 & M_0t & r0 {
r0 = sext( *:2 ( U_2t_M0_dispr02 + M_0t ) ); # NOTE U_2t_M0_dispr02 units is bytes
}
# Data Transfer
# pattern 0101nnnnmmmmdddd
# text mov.l @(<disp>,<REG_M>),<REG_N>
# arch arch_sh_up
:mov.l U_2t_M0_dispr04,N_0t is OP_0=0x5 & N_0t & M_0t & U_2t_M0_dispr04 {
N_0t = *:4 ( U_2t_M0_dispr04 + M_0t ); # NOTE U_2t_M0_dispr04 units is bytes
}
# Effective Address Transfer
# pattern 11000111iiiiiiii
# text mova @(<disp>,PC),R0
# arch arch_sh_up
:mova U_0t_4pc,r0 is OP_2=0xc7 & U_0t_4pc & r0 {
r0 = &U_0t_4pc; # NOTE U_0t_4pc units is bytes
}
# MOVe with Cache block Allocation
# pattern 0000nnnn11000011
# text movca.l R0,@<REG_N>
# arch arch_sh4_nommu_nofpu_up
:movca.l N_0txx is OP_0=0x0 & N_0txx & OP_4=0xc3 {
*:4 ( N_0txx ) = r0; # NOTE ignore cache issues
}
# T Bit Transfer
# pattern 0000nnnn00101001
# text movt <REG_N>
# arch
:movt N_0t is OP_0=0x0 & N_0t & OP_4=0x29 {
N_0t = zext($(T_FLAG));
}
# Double-Precision Multiplication
# pattern 0000nnnnmmmm0111
# text mul.l <REG_M>,<REG_N>
# arch
:mul.l M_0t,N_0t is OP_0=0x0 & N_0t & M_0t & OP_1=0x7 {
MACL = N_0t * M_0t;
}
# Signed Multiplication
# pattern 0010nnnnmmmm1111
# text muls.w <REG_M>,<REG_N>
# arch
:muls.w M_0t,N_0t is OP_0=0x2 & N_0t & M_0t & OP_1=0xf {
MACL = sext(N_0t:2) * sext(M_0t:2);
}
# Unsigned Multiplication
# pattern 0010nnnnmmmm1110
# text mulu.w <REG_M>,<REG_N>
# arch
:mulu.w M_0t,N_0t is OP_0=0x2 & N_0t & M_0t & OP_1=0xe {
MACL = zext(N_0t:2) * zext(M_0t:2);
}
# Sign Inversion
# pattern 0110nnnnmmmm1011
# text neg <REG_M>,<REG_N>
# arch
:neg M_0t,N_0t is OP_0=0x6 & N_0t & M_0t & OP_1=0xb {
N_0t = -M_0t;
}
# Sign Inversion with Borrow
# pattern 0110nnnnmmmm1010
# text negc <REG_M>,<REG_N>
# arch
:negc M_0t,N_0t is OP_0=0x6 & N_0t & M_0t & OP_1=0xa {
temp:4 = -M_0t;
N_0t = temp - zext($(T_FLAG));
$(T_FLAG) = ( 0 != temp );
if ( temp >= N_0t ) goto <skip>;
$(T_FLAG) = 1;
<skip>
}
# No Operation
# pattern 0000000000001001
# text nop
# arch
:nop is OP_3=0x9 { } # Empty on purpose
# Bit Inversion
# pattern 0110nnnnmmmm0111
# text not <REG_M>,<REG_N>
# arch
:not M_0t,N_0t is OP_0=0x6 & N_0t & M_0t & OP_1=0x7 {
N_0t = ~M_0t;
}
define pcodeop CacheBlockInvalidate;
# Operand Cache Block Invalidate
# pattern 0000nnnn10010011
# text ocbi @<REG_N>
# arch
:ocbi N_0t_at1 is OP_0=0x0 & N_0t_at1 & OP_4=0x93 { CacheBlockInvalidate(N_0t_at1); }
define pcodeop CacheBlockPurge;
# Cache Block Purge
# pattern 0000nnnn10100011
# text ocbp @<REG_N>
# arch
:ocbp N_0t_at1 is OP_0=0x0 & N_0t_at1 & OP_4=0xa3 { CacheBlockPurge(N_0t_at1); }
define pcodeop CacheBlockWriteBack;
# TODO ocbwb
# Cache Block Write-Back
# pattern 0000nnnn10110011
# text ocbwb @<REG_N>
# arch
:ocbwb N_0t_at1 is OP_0=0x0 & N_0t_at1 & OP_4=0xb3 { CacheBlockWriteBack(N_0t_at1); }
# Logical OR
# pattern 0010nnnnmmmm1011
# text or <REG_M>,<REG_N>
# arch
:or M_0t,N_0t is OP_0=0x2 & N_0t & M_0t & OP_1=0xb {
N_0t = N_0t | M_0t;
}
# Logical OR
# pattern 11001011iiiiiiii
# text or #<imm>,R0
# arch
:or U_0t_r0 is OP_2=0xcb & U_0t_r0 {
r0 = r0 | U_0t_r0;
}
# Logical OR
# pattern 11001111iiiiiiii
# text or.b #<imm>,@(R0,GBR)
# arch
:or.b U_0t1 is OP_2=0xcf & U_0t1 {
*:1 (GBR + r0) = ( *:1 (GBR + r0) ) | U_0t1;
}
# Prefetch to Data Cache
# pattern 0000nnnn10000011
# text pref @<REG_N>
# arch
:pref N_0tjmp is OP_0=0x0 & N_0tjmp & OP_4=0x83 { } # Empty on purpose
# One-Bit Left Rotation through T Bit
# pattern 0100nnnn00100100
# text rotcl <REG_N>
# arch
:rotcl N_0t is OP_0=0x4 & N_0t & OP_4=0x24 {
temp:1 = ( (N_0t & 0x80000000) != 0 );
N_0t = (N_0t << 1) | zext($(T_FLAG));
$(T_FLAG) = temp;
}
# One-Bit Right Rotation through T Bit
# pattern 0100nnnn00100101
# text rotcr <REG_N>
# arch
:rotcr N_0t is OP_0=0x4 & N_0t & OP_4=0x25 {
temp:1 = ( (N_0t & 0x00000001) != 0 );
N_0t = ( N_0t >> 1 ) | ( zext($(T_FLAG)) << 31 );
$(T_FLAG) = temp;
}
# One-Bit Left Rotation
# pattern 0100nnnn00000100
# text rotl <REG_N>
# arch
:rotl N_0t is OP_0=0x4 & N_0t & OP_4=0x4 {
$(T_FLAG) = ( (N_0t & 0x80000000) != 0 );
N_0t = (N_0t << 1) | zext($(T_FLAG));
}
# One-Bit Right Rotation
# pattern 0100nnnn00000101
# text rotr <REG_N>
# arch
:rotr N_0t is OP_0=0x4 & N_0t & OP_4=0x5 {
$(T_FLAG) = ( (N_0t & 0x00000001) != 0 );
N_0t = ( N_0t >> 1 ) | ( zext($(T_FLAG)) << 31 );
}
# Return from Exception Handling
# pattern 0000000000101011
# text rte
# arch
:rte is OP_3=0x2b {
SR = SSR;
splitSRregister();
PC = SPC;
delayslot(1);
return [PC];
}
# Return from Subroutine Procedure
# pattern 0000000000001011
# text rts
# arch
:rts is OP_3=0xb {
PC = PR;
delayslot(1);
return [PC];
}
# S Bit Setting
# pattern 0000000001011000
# text sets
# arch
:sets is OP_3=0x58 {
$(S_FLAG) = 1;
}
# T Bit Setting
# pattern 0000000000011000
# text sett
# arch
:sett is OP_3=0x18 {
$(T_FLAG) = 1;
}
# Note: this constructor follows the description on page 393 precisely, though simpler,
# it should produce identical results to the pseudo-code above
:shad M_0t,N_0t is OP_0=0x4 & N_0t & M_0t & OP_1=0xc {
if ( M_0t s< 0 ) goto <shiftRight>;
N_0t = N_0t << ( M_0t & 0x1f );
goto <skip>;
<shiftRight>
N_0t = N_0t s>> ( ( ~M_0t & 0x1f ) + 1 );
<skip>
}
# One-Bit Left Arithmetic Shift
# pattern 0100nnnn00100000
# text shal <REG_N>
# arch
:shal N_0t is OP_0=0x4 & N_0t & OP_4=0x20 {
$(T_FLAG) = ( ( N_0t & 0x80000000 ) != 0 );
N_0t = N_0t << 1;
}
# One-Bit Right Arithmetic Shift
# pattern 0100nnnn00100001
# text shar <REG_N>
# arch
:shar N_0t is OP_0=0x4 & N_0t & OP_4=0x21 {
$(T_FLAG) = ( ( N_0t & 0x00000001 ) != 0 );
N_0t = N_0t s>> 1;
}
# Note: this constructor follows the description on page 397 precisely, though simpler,
# it should produce identical results to the pseudo-code above
:shld M_0t,N_0t is OP_0=0x4 & N_0t & M_0t & OP_1=0xd {
if ( M_0t s< 0 ) goto <shiftRight>;
N_0t = N_0t << ( M_0t & 0x1f );
goto <skip>;
<shiftRight>
N_0t = N_0t >> ( ( ~M_0t & 0x1f ) + 1 );
<skip>
}
# n-Bit Left Logical Shift
# One-Bit Left Logical Shift
# pattern 0100nnnn00000000
# text shll <REG_N>
# arch
:shll N_0t is OP_0=0x4 & N_0t & OP_4=0x0 {
$(T_FLAG) = ( ( N_0t & 0x80000000 ) != 0 );
N_0t = N_0t << 1;
}
# n-Bit Left Logical Shift
# pattern 0100nnnn00001000
# text shll2 <REG_N>
# arch
:shll2 N_0t is OP_0=0x4 & N_0t & OP_4=0x8 {
N_0t = ( N_0t << 2 );
}
# n-Bit Left Logical Shift
# pattern 0100nnnn00011000
# text shll8 <REG_N>
# arch
:shll8 N_0t is OP_0=0x4 & N_0t & OP_4=0x18 {
N_0t = ( N_0t << 8 );
}
# pattern 0100nnnn00101000
# text shll16 <REG_N>
# arch
:shll16 N_0t is OP_0=0x4 & N_0t & OP_4=0x28 {
N_0t = ( N_0t << 16 );
}
# One-Bit Right Logical Shift
# pattern 0100nnnn00000001
# text shlr <REG_N>
# arch
:shlr N_0t is OP_0=0x4 & N_0t & OP_4=0x1 {
$(T_FLAG) = ( ( N_0t & 0x00000001 ) != 0 );
N_0t = N_0t >> 1;
}
# n-Bit Left Logical Shift
# pattern 0100nnnn00001001
# text shlr2 <REG_N>
# arch
:shlr2 N_0t is OP_0=0x4 & N_0t & OP_4=0x9 {
N_0t = N_0t >> 2;
}
# n-Bit Left Logical Shift
# pattern 0100nnnn00011001
# text shlr8 <REG_N>
# arch
:shlr8 N_0t is OP_0=0x4 & N_0t & OP_4=0x19 {
N_0t = N_0t >> 8;
}
# n-Bit Left Logical Shift
# pattern 0100nnnn00101001
# text shlr16 <REG_N>
# arch
:shlr16 N_0t is OP_0=0x4 & N_0t & OP_4=0x29 {
N_0t = N_0t >> 16;
}
# Transition to Power-Down Mode
# pattern 0000000000011011
# text sleep
# arch
:sleep is OP_3=0x1b { } # empty on purpose
# Store from Control Register
# pattern 0000nnnn00000010
# text stc SR,<REG_N>
# arch arch_sh_up
:stc sr_N_0t is OP_0=0x0 & sr_N_0t & OP_4=0x2 {
genSRregister();
sr_N_0t = SR;
}
# Store from Control Register
# pattern 0000nnnn00010010
# text stc GBR,<REG_N>
# arch
:stc gbr_N_0t is OP_0=0x0 & gbr_N_0t & OP_4=0x12 {
gbr_N_0t = GBR;
}
# Store from Control Register
# pattern 0000nnnn00100010
# text stc VBR,<REG_N>
# arch arch_sh_up
:stc vbr_N_0t is OP_0=0x0 & vbr_N_0t & OP_4=0x22 {
vbr_N_0t = VBR;
}
# pattern 0000nnnn00110010
# text stc SSR,<REG_N>
# arch arch_sh3_nommu_up
:stc ssr_N_0t is OP_0=0x0 & ssr_N_0t & OP_4=0x32 {
ssr_N_0t = SSR;
}
# pattern 0000nnnn01000010
# text stc SPC,<REG_N>
# arch arch_sh3_nommu_up
#
:stc spc_N_0t is OP_0=0x0 & spc_N_0t & OP_4=0x42 {
spc_N_0t = SPC;
}
# pattern 0000nnnn00111010
# text stc SGR,<REG_N>
# arch arch_sh4_nommu_nofpu_up
:stc sgr_N_0t is OP_0=0x0 & sgr_N_0t & OP_4=0x3a {
sgr_N_0t = SGR;
}
# pattern 0000nnnn11111010
# text stc DBR,<REG_N>
# arch arch_sh4_nommu_nofpu_up
:stc dbr_N_0t is OP_0=0x0 & dbr_N_0t & OP_4=0xfa {
dbr_N_0t = DBR;
}
# pattern 0000nnnn1xxx0010
# text stc Rn_BANK,<REG_N>
# arch arch_sh3_nommu_up
:stc BANKt,N_0t_bank is OP_0=0x0 & N_0t_bank & OP_9=0x1 & BANKt & OP_1=0x2 {
N_0t_bank = BANKt;
}
# Store from Control Register
# pattern 0100nnnn00000011
# text stc.l SR,@-<REG_N>
# arch arch_sh_up
:stc.l sr_t,N_0t_at_neg is OP_0=0x4 & N_0t_at_neg & OP_4=0x3 & sr_t {
N_0t_at_neg = N_0t_at_neg - 4;
genSRregister();
*:4 ( N_0t_at_neg ) = SR;
}
# Store from Control Register
# pattern 0100nnnn00010011
# text stc.l GBR,@-<REG_N>
# arch arch_sh_up
:stc.l gbr_t,N_0t_at_neg is OP_0=0x4 & N_0t_at_neg & OP_4=0x13 & gbr_t {
N_0t_at_neg = N_0t_at_neg - 4;
*:4 ( N_0t_at_neg ) = GBR;
}
# Store from Control Register
# pattern 0100nnnn00100011
# text stc.l VBR,@-<REG_N>
# arch arch_sh_up
:stc.l vbr_t,N_0t_at_neg is OP_0=0x4 & N_0t_at_neg & OP_4=0x23 & vbr_t {
N_0t_at_neg = N_0t_at_neg - 4;
*:4 ( N_0t_at_neg ) = VBR;
}
# pattern 0100nnnn00110011
# text stc.l SSR,@-<REG_N>
# arch arch_sh3_nommu_up
:stc.l ssr_t,N_0t_at_neg is OP_0=0x4 & N_0t_at_neg & OP_4=0x33 & ssr_t {
N_0t_at_neg = N_0t_at_neg - 4;
*:4 ( N_0t_at_neg ) = SSR;
}
# pattern 0100nnnn01000011
# text stc.l SPC,@-<REG_N>
# arch arch_sh3_nommu_up
:stc.l spc_t,N_0t_at_neg is OP_0=0x4 & N_0t_at_neg & OP_4=0x43 & spc_t {
N_0t_at_neg = N_0t_at_neg - 4;
*:4 ( N_0t_at_neg ) = SPC;
}
# pattern 0100nnnn00110010
# text stc.l SGR,@-<REG_N>
# arch arch_sh4_nommu_nofpu_up
:stc.l sgr_t,N_0t_at_neg is OP_0=0x4 & N_0t_at_neg & OP_4=0x32 & sgr_t {
N_0t_at_neg = N_0t_at_neg - 4;
*:4 ( N_0t_at_neg ) = SGR;
}
# pattern 0100nnnn11110010
# text stc.l DBR,@-<REG_N>
# arch arch_sh4_nommu_nofpu_up
:stc.l dbr_t,N_0t_at_neg is OP_0=0x4 & N_0t_at_neg & OP_4=0xf2 & dbr_t {
N_0t_at_neg = N_0t_at_neg - 4;
*:4 ( N_0t_at_neg ) = DBR;
}
# pattern 0100nnnn1xxx0011
# text stc.l Rn_BANK,@-<REG_N>
# arch arch_sh3_nommu_up
:stc.l BANKt,N_0t_at_neg is OP_0=0x4 & N_0t_at_neg & OP_9=0x1 & BANKt & OP_1=0x3 {
N_0t_at_neg = N_0t_at_neg - 4;
*:4 ( N_0t_at_neg ) = BANKt;
}
# Store from System Register
# pattern 0000nnnn00001010
# text sts MACH,<REG_N>
# arch arch_sh_up
:sts mach_N_0t is OP_0=0x0 & mach_N_0t & OP_4=0xa {
mach_N_0t = MACH;
}
# Store from System Register
# pattern 0000nnnn00011010
# text sts MACL,<REG_N>
# arch arch_sh_up
:sts macl_N_0t is OP_0=0x0 & macl_N_0t & OP_4=0x1a {
macl_N_0t = MACL;
}
# Store from System Register
# pattern 0000nnnn00101010
# text sts PR,<REG_N>
# arch arch_sh_up
:sts pr_N_0t is OP_0=0x0 & pr_N_0t & OP_4=0x2a {
pr_N_0t = PR;
}
# Store from Control Register
# pattern 0100nnnn00000010
# text sts.l MACH,@-<REG_N>
# arch arch_sh_up
:sts.l mach_t,N_0t_at_neg is OP_0=0x4 & N_0t_at_neg & OP_4=0x2 & mach_t {
N_0t_at_neg = N_0t_at_neg - 4;
*:4 ( N_0t_at_neg ) = MACH;
}
# Store from Control Register
# pattern 0100nnnn00010010
# text sts.l MACL,@-<REG_N>
# arch arch_sh_up
:sts.l macl_t,N_0t_at_neg is OP_0=0x4 & N_0t_at_neg & OP_4=0x12 & macl_t {
N_0t_at_neg = N_0t_at_neg - 4;
*:4 ( N_0t_at_neg ) = MACL;
}
# Store from Control Register
# pattern 0100nnnn00100010
# text sts.l PR,@-<REG_N>
# arch arch_sh_up
:sts.l PR,N_0t_at_neg is OP_0=0x4 & N_0t_at_neg & OP_4=0x22 & PR {
N_0t_at_neg = N_0t_at_neg - 4;
*:4 ( N_0t_at_neg ) = PR;
}
# Store from System Register
# pattern 0000nnnn01011010
# text sts FPUL,<REG_N>
# arch arch_sh2e_up
:sts fpul_N_0t is OP_0=0x0 & fpul_N_0t & OP_4=0x5a {
fpul_N_0t = FPUL;
}
# Store from System Register
# pattern 0000nnnn01101010
# text sts FPSCR,<REG_N>
# arch arch_sh2e_up
:sts fpscr_N_0t is OP_0=0x0 & fpscr_N_0t & OP_4=0x6a {
genFPSCRregister();
fpscr_N_0t = FPSCR;
}
# Store from Control Register
# pattern 0100nnnn01010010
# text sts.l FPUL,@-<REG_N>
# arch arch_sh2e_up
:sts.l fpul_t,N_0t_at_neg is OP_0=0x4 & N_0t_at_neg & OP_4=0x52 & fpul_t {
N_0t_at_neg = N_0t_at_neg - 4;
*:4 ( N_0t_at_neg ) = FPUL;
}
# Store from Control Register
# pattern 0100nnnn01100010
# text sts.l FPSCR,@-<REG_N>
# arch arch_sh2e_up
:sts.l fpscr_t,N_0t_at_neg is OP_0=0x4 & N_0t_at_neg & OP_4=0x62 & fpscr_t {
N_0t_at_neg = N_0t_at_neg - 4;
genFPSCRregister();
*:4 ( N_0t_at_neg ) = FPSCR;
}
# Binary Subtraction
# pattern 0011nnnnmmmm1000
# text sub <REG_M>,<REG_N>
# arch arch_sh_up
:sub M_0t,N_0t is OP_0=0x3 & N_0t & M_0t & OP_1=0x8 {
N_0t = N_0t - M_0t;
}
# Binary Subtraction with Borrow
# pattern 0011nnnnmmmm1010
# text subc <REG_M>,<REG_N>
# arch arch_sh_up
:subc M_0t,N_0t is OP_0=0x3 & N_0t & M_0t & OP_1=0xa {
tmp1:4 = N_0t - M_0t;
tmp0:4 = N_0t;
N_0t = tmp1 - zext($(T_FLAG));
$(T_FLAG) = ( tmp0 < tmp1 );
if ( tmp1 >= N_0t ) goto <skip>;
$(T_FLAG) = 1;
<skip>
}
# Binary Subtraction with Underflow Check
# pattern 0011nnnnmmmm1011
# text subv <REG_M>,<REG_N>
# arch arch_sh_up
:subv M_0t,N_0t is OP_0=0x3 & N_0t & M_0t & OP_1=0xb {
local dest = ( N_0t s< 0 );
local src = ( M_0t s< 0 );
src = src + dest;
N_0t = N_0t - M_0t;
local ans = ( N_0t s< 0 );
ans = ans + dest;
$(T_FLAG) = ( (src == 1) && (ans == 1) );
}
# Upper-/Lower-Half Swap
# pattern 0110nnnnmmmm1000
# text swap.b <REG_M>,<REG_N>
# arch arch_sh_up
:swap.b M_0t,N_0t is OP_0=0x6 & N_0t & M_0t & OP_1=0x8 {
N_0t = ( M_0t & 0xFFFF0000 ) |
( ( M_0t & 0x000000FF ) << 8 ) |
( ( M_0t & 0x0000FF00 ) >> 8 );
}
# Upper-/Lower-Half Swap
# pattern 0110nnnnmmmm1001
# text swap.w <REG_M>,<REG_N>
# arch arch_sh_up
:swap.w M_0t,N_0t is OP_0=0x6 & N_0t & M_0t & OP_1=0x9 {
N_0t = ( M_0t << 16 ) | ( M_0t >> 16 );
}
# Synchronize Data Operation
# pattern 0000000010101011
# text synco
# arch arch_sh4a_up
define pcodeop SynchronizeDataOperation;
:synco is OP_3=0x00ab {
SynchronizeDataOperation();
}
# Memory Test and Bit Setting
# pattern 0100nnnn00011011
# text tas.b @<REG_N>
# arch arch_sh_up
:tas.b N_0t_at1 is OP_0=0x4 & N_0t_at1 & OP_4=0x1b {
temp:1 = *:1 ( N_0t_at1 );
$(T_FLAG) = ( temp == 0 );
temp = temp | 0x80;
*:1 ( N_0t_at1 ) = temp;
}
define pcodeop TrapAlways;
# Trap Exception Handling
# pattern 11000011iiiiiiii
# text trapa #<imm>
# arch arch_sh_up
:trapa U_0t is OP_2=0xc3 & U_0t { TrapAlways(U_0t); }
# AND Operation T Bit Setting
# pattern 0010nnnnmmmm1000
# text tst <REG_M>,<REG_N>
# arch arch_sh_up
:tst M_0t,N_0t is OP_0=0x2 & N_0t & M_0t & OP_1=0x8 {
$(T_FLAG) = ( (N_0t & M_0t) == 0 );
}
# AND Operation T Bit Setting
# pattern 11001000iiiiiiii
# text tst #<imm>,R0
# arch arch_sh_up
:tst U_0t_r0 is OP_2=0xc8 & U_0t_r0 {
$(T_FLAG) = ( ( r0 & U_0t_r0 ) == 0 );
}
# AND Operation T Bit Setting
# pattern 11001100iiiiiiii
# text tst.b #<imm>,@(R0,GBR)
# arch arch_sh_up
:tst.b U_0t1 is OP_2=0xcc & U_0t1 {
$(T_FLAG) = ( ( (*:1 ( GBR + r0 )) & U_0t1 ) == 0 );
}
# pattern 0010nnnnmmmm1010
# text xor <REG_M>,<REG_N>
# arch arch_sh_up
:xor M_0t,N_0t is OP_0=0x2 & N_0t & M_0t & OP_1=0xa {
N_0t = N_0t ^ M_0t;
}
# Exclusive Logical OR
# pattern 11001010iiiiiiii
# text xor #<imm>,R0
# arch arch_sh_up
:xor U_0t_r0 is OP_2=0xca & U_0t_r0 {
r0 = r0 ^ U_0t_r0;
}
# Exclusive Logical OR
# pattern 11001110iiiiiiii
# text xor.b #<imm>,@(R0,GBR)
# arch arch_sh_up
:xor.b U_0t1 is OP_2=0xce & U_0t1 {
*:1 (GBR + r0) = ( *:1 (GBR + r0) ) ^ U_0t1;
}
# Middle Extraction from Linked Registers
# pattern 0010nnnnmmmm1101
# text xtrct <REG_M>,<REG_N>
# arch arch_sh_up
:xtrct M_0t,N_0t is OP_0=0x2 & N_0t & M_0t & OP_1=0xd {
N_0t = (M_0t << 16) | (N_0t >> 16);
}