ghidra/Ghidra/Processors/SuperH/data/languages/superh.sinc
2019-06-23 17:58:32 -04:00

1411 lines
31 KiB
Plaintext

# All assembly defintions taken from: http://www.shared-ptr.com/sh_insns.html
define endian=big;
define alignment=2;
define space ram type=ram_space size=4 wordsize=1 default;
define space register type=register_space size=4;
define register offset=0 size=4
[r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15];
define register offset=0x100 size=4 [sr gbr vbr mach macl pr pc];
# SR Flags
@define T_FLAG "sr[0,1]"
@define S_FLAG "sr[1,1]"
@define I0_FLAG "sr[4,1]"
@define I1_FLAG "sr[5,1]"
@define I2_FLAG "sr[6,1]"
@define I3_FLAG "sr[7,1]"
@define Q_FLAG "sr[8,1]"
@define M_FLAG "sr[9,1]"
define token instr(16)
disp_00_03 = (0, 3)
sdisp_00_03 = (0, 3) signed
disp_00_07 = (0, 7)
sdisp_00_07 = (0, 7) signed
disp_00_11 = (0, 11)
sdisp_00_11 = (0, 11) signed
imm_00_07 = (0, 7)
simm_00_07 = (0, 7) signed
opcode_00_03 = (0, 3)
opcode_00_07 = (0, 7)
opcode_00_15 = (0, 15)
opcode_04_07 = (4, 7)
opcode_08_11 = (8, 11)
opcode_08_15 = (8, 15)
opcode_12_15 = (12, 15)
rm_04_07 = (4, 7)
rm_08_11 = (8, 11)
rn_04_07 = (4, 7)
rn_08_11 = (8, 11)
;
attach variables [ rm_04_07 rm_08_11 rn_04_07 rn_08_11 ] [
r0 r1 r2 r3 r4 r5 r6 r7
r8 r9 r10 r11 r12 r13 r14 r15
];
# helpers for branch
target00_07: target is sdisp_00_07 [ target = (sdisp_00_07 << 1) + inst_start + 4; ] {
export *:4 target;
}
target00_11: target is sdisp_00_11 [ target = (sdisp_00_11 << 1) + inst_start + 4; ] {
export *:4 target;
}
#
# Data Transfer Instructions
#
:mov rm_04_07, rn_08_11 is opcode_12_15=0b0110 & rn_08_11 & rm_04_07 & opcode_00_03=0b0011
{
rn_08_11 = rm_04_07;
}
:mov simm_00_07,rn_08_11 is opcode_12_15=0b1110 & rn_08_11 & simm_00_07
{
rn_08_11 = simm_00_07;
}
:mova @(disp,pc),r0 is r0 & pc & opcode_08_15=0b11000111 & disp_00_07 [disp = (disp_00_07 << 2); ]
{
local temp:4 = inst_start;
r0 = disp + (temp & 0xFFFFFFFC) + 4;
}
:mov.w @(target,pc),rn_08_11 is pc & opcode_12_15=0b1001 & rn_08_11 & disp_00_07 [ target = (disp_00_07 << 1) + 4; ]
{
local temp:4 = inst_start;
rn_08_11 = sext(*:2 (temp + target));
}
:mov.l @(disp,pc),rn_08_11 is pc & opcode_12_15=0b1101 & rn_08_11 & disp_00_07 [disp = (disp_00_07 << 2) + 4; ]
{
local temp:4 = inst_start;
rn_08_11 = *:4 ((temp & 0xFFFFFFFC) + disp);
}
:mov.b @rm_04_07,rn_08_11 is opcode_12_15=0b0110 & rn_08_11 & rm_04_07 & opcode_00_03=0b0000
{
rn_08_11 = sext(*:1 rm_04_07);
}
:mov.w @rm_04_07,rn_08_11 is opcode_12_15=0b0110 & rn_08_11 & rm_04_07 & opcode_00_03=0b0001
{
rn_08_11 = sext(*:2 rm_04_07);
}
:mov.l @rm_04_07,rn_08_11 is opcode_12_15=0b0110 & rn_08_11 & rm_04_07 & opcode_00_03=0b0010
{
rn_08_11 = *:4 rm_04_07;
}
:mov.b rm_04_07,@rn_08_11 is opcode_12_15=0b0010 & rn_08_11 & rm_04_07 & opcode_00_03=0b0000
{
*:1 rn_08_11 = rm_04_07:1;
}
:mov.w rm_04_07,@rn_08_11 is opcode_12_15=0b0010 & rn_08_11 & rm_04_07 & opcode_00_03=0b0001
{
*:2 rn_08_11 = rm_04_07:2;
}
:mov.l rm_04_07,@rn_08_11 is opcode_12_15=0b0010 & rn_08_11 & rm_04_07 & opcode_00_03=0b0010
{
*:4 rn_08_11 = rm_04_07;
}
:mov.b @rm_04_07+,rn_08_11 is opcode_12_15=0b0110 & rn_08_11 & rm_04_07 & opcode_00_03=0b0100 & opcode_04_07 & opcode_08_11
{
rn_08_11 = sext(*:1 rm_04_07);
local m:4 = opcode_04_07;
local n:4 = opcode_08_11;
# Check n != m
if(m == n) goto <END>;
rm_04_07 = rm_04_07 + 1;
<END>
}
:mov.w @rm_04_07+,rn_08_11 is opcode_12_15=0b0110 & rn_08_11 & rm_04_07 & opcode_00_03=0b0101 & opcode_04_07 & opcode_08_11
{
rn_08_11 = sext(*:2 rm_04_07);
local m:4 = opcode_04_07;
local n:4 = opcode_08_11;
# Check n != m
if(m == n) goto <END>;
rm_04_07 = rm_04_07 + 2;
<END>
}
:mov.l @rm_04_07+,rn_08_11 is opcode_12_15=0b0110 & rn_08_11 & rm_04_07 & opcode_00_03=0b0110 & opcode_04_07 & opcode_08_11
{
rn_08_11 = *:4 rm_04_07;
local m:4 = opcode_04_07;
local n:4 = opcode_08_11;
# Check n != m
if(m == n) goto <END>;
rm_04_07 = rm_04_07 + 4;
<END>
}
:mov.b rm_04_07,@-rn_08_11 is opcode_12_15=0b0010 & rn_08_11 & rm_04_07 & opcode_00_03=0b0100
{
rn_08_11 = rn_08_11 -1;
*:1 rn_08_11 = rm_04_07;
}
:mov.w rm_04_07,@-rn_08_11 is opcode_12_15=0b0010 & rn_08_11 & rm_04_07 & opcode_00_03=0b0101
{
rn_08_11 = rn_08_11 -2;
*:2 rn_08_11 = rm_04_07;
}
:mov.l rm_04_07,@-rn_08_11 is opcode_12_15=0b0010 & rn_08_11 & rm_04_07 & opcode_00_03=0b0110
{
rn_08_11 = rn_08_11 -4;
*:4 rn_08_11 = rm_04_07;
}
:mov.b @(disp_00_03,rm_04_07),r0 is r0 & opcode_08_15=0b10000100 & rm_04_07 & disp_00_03
{
r0 = sext(*:1 (disp_00_03 + rm_04_07));
}
:mov.w @(disp,rm_04_07),r0 is r0 & opcode_08_15=0b10000101 & rm_04_07 & disp_00_03 [ disp = disp_00_03 << 1; ]
{
r0 = sext(*:2 (disp + rm_04_07));
}
:mov.l @(disp,rm_04_07),rn_08_11 is opcode_12_15=0b0101 & rn_08_11 & rm_04_07 & disp_00_03 [ disp = disp_00_03 << 2; ]
{
rn_08_11 = *:4 (disp + rm_04_07);
}
:mov.b r0,@(disp_00_03,rn_04_07) is r0 & opcode_08_15=0b10000000 & rn_04_07 & disp_00_03
{
*:1 (rn_04_07 + disp_00_03) = r0:1;
}
:mov.w r0,@(disp,rn_04_07) is r0 & opcode_08_15=0b10000001 & rn_04_07 & disp_00_03 [ disp = disp_00_03 << 1; ]
{
*:2 (rn_04_07 + disp) = r0:2;
}
:mov.l rm_04_07,@(disp,rn_08_11) is opcode_12_15=0b0001 & rn_08_11 & rm_04_07 & disp_00_03 [ disp = disp_00_03 << 2; ]
{
*:4 (rn_08_11 + disp) = rm_04_07;
}
:mov.b @(r0,rm_04_07),rn_08_11 is r0 & opcode_12_15=0b0000 & rn_08_11 & rm_04_07 & opcode_00_03=0b1100
{
rn_08_11 = sext(*:1 (rm_04_07 + r0));
}
:mov.w @(r0,rm_04_07),rn_08_11 is r0 & opcode_12_15=0b0000 & rn_08_11 & rm_04_07 & opcode_00_03=0b1101
{
rn_08_11 = sext(*:2 (rm_04_07 + r0));
}
:mov.l @(r0,rm_04_07),rn_08_11 is r0 & opcode_12_15=0b0000 & rn_08_11 & rm_04_07 & opcode_00_03=0b1110
{
rn_08_11 = *:4 (rm_04_07 + r0);
}
:mov.b rm_04_07,@(r0,rn_08_11) is r0 & opcode_12_15=0b0000 & rn_08_11 & rm_04_07 & opcode_00_03=0b0100
{
*:1 (rn_08_11 + r0) = rm_04_07;
}
:mov.w rm_04_07,@(r0,rn_08_11) is r0 & opcode_12_15=0b0000 & rn_08_11 & rm_04_07 & opcode_00_03=0b0101
{
*:2 (rn_08_11 + r0) = rm_04_07;
}
:mov.l rm_04_07,@(r0,rn_08_11) is r0 & opcode_12_15=0b0000 & rn_08_11 & rm_04_07 & opcode_00_03=0b0110
{
*:4 (rn_08_11 + r0) = rm_04_07;
}
:mov.b @(disp_00_07,gbr),r0 is gbr & r0 & opcode_08_15=0b11000100 & disp_00_07
{
r0 = sext(*:1 (gbr + disp_00_07));
}
:mov.w @(disp,gbr),r0 is gbr & r0 & opcode_08_15=0b11000101 & disp_00_07 [disp = (disp_00_07 << 1); ]
{
r0 = sext(*:2 (gbr + disp));
}
:mov.l @(disp,gbr),r0 is gbr & r0 & opcode_08_15=0b11000110 & disp_00_07 [disp = (disp_00_07 << 2); ]
{
r0 = *:4 (gbr + disp);
}
:mov.b r0,@(disp_00_07,gbr) is r0 & gbr & opcode_08_15=0b11000000 & disp_00_07
{
*:1 (gbr + disp_00_07) = r0;
}
:mov.w r0,@(disp,gbr) is r0 & gbr & opcode_08_15=0b11000001 & disp_00_07 [disp = (disp_00_07 << 1); ]
{
*:2 (gbr + disp) = r0;
}
:mov.l r0,@(disp,gbr) is r0 & gbr & opcode_08_15=0b11000010 & disp_00_07 [disp = (disp_00_07 << 2); ]
{
*:4 (gbr + disp) = r0;
}
:movt rn_08_11 is opcode_12_15=0b0000 & rn_08_11 & opcode_00_07=0b00101001
{
rn_08_11 = zext($(T_FLAG));
}
:swap.b rm_04_07,rn_08_11 is opcode_12_15=0b0110 & rn_08_11 & rm_04_07 & opcode_00_03=0b1000
{
local temp0;
local temp1;
temp0 = rm_04_07 & 0xFFFF0000;
temp1 = (rm_04_07 & 0x000000FF) << 8;
rn_08_11 = (rm_04_07 & 0x0000FF00) >> 8;
rn_08_11 = rn_08_11 | temp1 | temp0;
}
:swap.w rm_04_07,rn_08_11 is opcode_12_15=0b0110 & rn_08_11 & rm_04_07 & opcode_00_03=0b1001
{
local temp;
temp = (rm_04_07 >> 16) & 0x0000FFFF;
rn_08_11 = rm_04_07 << 16;
rn_08_11 = rn_08_11 | temp;
}
:xtrct rm_04_07,rn_08_11 is opcode_12_15=0b0010 & rn_08_11 & rm_04_07 & opcode_00_03=0b1101
{
local high;
local low;
high = (rm_04_07 << 16) & 0xFFFF0000;
low = (rn_08_11 >> 16) & 0x0000FFFF;
rn_08_11 = high | low;
}
#
# Arithmetic Operation Instructions
#
:add rm_04_07,rn_08_11 is opcode_12_15=0b0011 & rn_08_11 & rm_04_07 & opcode_00_03=0b1100
{
rn_08_11 = rn_08_11 + rm_04_07;
}
:add imm_00_07,rn_08_11 is opcode_12_15=0b0111 & rn_08_11 & imm_00_07
{
rn_08_11 = rn_08_11 + sext(imm_00_07:1);
}
:addc rm_04_07,rn_08_11 is opcode_12_15=0b0011 & rn_08_11 & rm_04_07 & opcode_00_03=0b1110
{
local temp0;
local temp1;
temp1 = rn_08_11 + rm_04_07;
temp0 = temp1;
rn_08_11 = temp1 + zext($(T_FLAG));
$(T_FLAG) = (temp0 > temp1) | (temp1 > rn_08_11);
}
:addv rm_04_07,rn_08_11 is opcode_12_15=0b0011 & rn_08_11 & rm_04_07 & opcode_00_03=0b1111
{
local dest:1;
local src:1;
local ans:1;
dest = (rn_08_11 s< 0);
src = (rm_04_07 s< 0);
src = src + dest;
rn_08_11 = rn_08_11 + rm_04_07;
ans = (rn_08_11 s< 0);
ans = ans + dest;
$(T_FLAG) = (src == 0 || src == 2) && (ans == 1);
}
:cmp"/eq" imm_00_07,r0 is r0 & opcode_08_15=0b10001000 & imm_00_07
{
local temp:4 = sext(imm_00_07:1);
$(T_FLAG) = (r0 == temp);
}
:cmp"/eq" rm_04_07,rn_08_11 is opcode_12_15=0b0011 & rn_08_11 & rm_04_07 & opcode_00_03=0b0000
{
$(T_FLAG) = (rn_08_11 == rm_04_07);
}
:cmp"/hs" rm_04_07,rn_08_11 is opcode_12_15=0b0011 & rn_08_11 & rm_04_07 & opcode_00_03=0b0010
{
$(T_FLAG) = (rn_08_11 >= rm_04_07);
}
:cmp"/ge" rm_04_07,rn_08_11 is opcode_12_15=0b0011 & rn_08_11 & rm_04_07 & opcode_00_03=0b0011
{
$(T_FLAG) = (rn_08_11 s>= rm_04_07);
}
:cmp"/hi" rm_04_07,rn_08_11 is opcode_12_15=0b0011 & rn_08_11 & rm_04_07 & opcode_00_03=0b0110
{
$(T_FLAG) = (rn_08_11 > rm_04_07);
}
:cmp"/gt" rm_04_07,rn_08_11 is opcode_12_15=0b0011 & rn_08_11 & rm_04_07 & opcode_00_03=0b0111
{
$(T_FLAG) = (rn_08_11 s> rm_04_07);
}
:cmp"/pl" rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00010101
{
$(T_FLAG) = (rn_08_11 s> 0);
}
:cmp"/pz" rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00010001
{
$(T_FLAG) = (rn_08_11 s>= 0);
}
:cmp"/str" rm_04_07,rn_08_11 is opcode_12_15=0b0010 & rn_08_11 & rm_04_07 & opcode_00_03=0b1100
{
local temp:4;
local HH:4;
local HL:4;
local LH:4;
local LL:4;
temp = rn_08_11 ^ rm_04_07;
HH = (temp & 0xFF000000) >> 24;
HL = (temp & 0x00FF0000) >> 16;
LH = (temp & 0x0000FF00) >> 8;
LL = (temp & 0x000000FF);
$(T_FLAG) = (HH != 0) && (HL != 0) && (LH != 0) && (LL != 0);
}
:div0s rm_04_07,rn_08_11 is opcode_12_15=0b0010 & rn_08_11 & rm_04_07 & opcode_00_03=0b0111
{
$(Q_FLAG) = !((rn_08_11 & 0x80000000) == 0);
$(M_FLAG) = !((rm_04_07 & 0x80000000) == 0);
$(T_FLAG) = !($(M_FLAG) == $(Q_FLAG));
}
:div0u is opcode_00_15=0b0000000000011001
{
$(M_FLAG) = 0;
$(Q_FLAG) = 0;
$(T_FLAG) = 0;
}
:div1 rm_04_07,rn_08_11 is opcode_12_15=0b0011 & rn_08_11 & rm_04_07 & opcode_00_03=0b0100
{
local tmp0:4;
local tmp1:1;
local tmp2:4;
local old_q:1;
old_q = $(Q_FLAG);
$(Q_FLAG) = (0x80000000 & rn_08_11) != 0;
tmp2 = rm_04_07;
rn_08_11 = rn_08_11 << 1;
rn_08_11 = rn_08_11 | zext($(T_FLAG));
# BUGBUG: cleaner way to do this??
if(old_q == 0 && $(M_FLAG) == 0 && $(Q_FLAG) == 0) goto <OQ0_M0_Q0>;
if(old_q == 0 && $(M_FLAG) == 0 && $(Q_FLAG) == 1) goto <OQ0_M0_Q1>;
if(old_q == 0 && $(M_FLAG) == 1 && $(Q_FLAG) == 0) goto <OQ0_M1_Q0>;
if(old_q == 0 && $(M_FLAG) == 1 && $(Q_FLAG) == 1) goto <OQ0_M1_Q1>;
if(old_q == 1 && $(M_FLAG) == 0 && $(Q_FLAG) == 0) goto <OQ1_M0_Q0>;
if(old_q == 1 && $(M_FLAG) == 0 && $(Q_FLAG) == 1) goto <OQ1_M0_Q1>;
if(old_q == 1 && $(M_FLAG) == 1 && $(Q_FLAG) == 0) goto <OQ1_M1_Q0>;
if(old_q == 1 && $(M_FLAG) == 1 && $(Q_FLAG) == 1) goto <OQ1_M1_Q1>;
<OQ0_M0_Q0>
tmp0 = rn_08_11;
rn_08_11 = rn_08_11 - tmp2;
tmp1 = rn_08_11 > tmp0;
$(Q_FLAG) = tmp1;
goto <SET_FLAG>;
<OQ0_M0_Q1>
tmp0 = rn_08_11;
rn_08_11 = rn_08_11 - tmp2;
tmp1 = rn_08_11 > tmp0;
$(Q_FLAG) = tmp1 == 0;
goto <SET_FLAG>;
<OQ0_M1_Q0>
tmp0 = rn_08_11;
rn_08_11 = rn_08_11 + tmp2;
tmp1 = rn_08_11 < tmp0;
$(Q_FLAG) = tmp1 == 0;
goto <SET_FLAG>;
<OQ0_M1_Q1>
tmp0 = rn_08_11;
rn_08_11 = rn_08_11 + tmp2;
tmp1 = rn_08_11 < tmp0;
$(Q_FLAG) = tmp1;
goto <SET_FLAG>;
<OQ1_M0_Q0>
tmp0 = rn_08_11;
rn_08_11 = rn_08_11 + tmp2;
tmp1 = rn_08_11 < tmp0;
$(Q_FLAG) = tmp1;
goto <SET_FLAG>;
<OQ1_M0_Q1>
tmp0 = rn_08_11;
rn_08_11 = rn_08_11 + tmp2;
tmp1 = rn_08_11 < tmp0;
$(Q_FLAG) = tmp1;
goto <SET_FLAG>;
<OQ1_M1_Q0>
tmp0 = rn_08_11;
rn_08_11 = rn_08_11 - tmp2;
tmp1 = rn_08_11 > tmp0;
$(Q_FLAG) = tmp1 == 0;
goto <SET_FLAG>;
<OQ1_M1_Q1>
tmp0 = rn_08_11;
rn_08_11 = rn_08_11 - tmp2;
tmp1 = rn_08_11 > tmp0;
$(Q_FLAG) = tmp1;
goto <SET_FLAG>;
<SET_FLAG>
$(T_FLAG) = $(Q_FLAG) == $(M_FLAG);
}
@if SH_VERSION == "2"
:dmuls.l rm_04_07,rn_08_11 is opcode_12_15=0b0011 & rn_08_11 & rm_04_07 & opcode_00_03=0b1101
{
local a:8 = sext(rn_08_11);
local b:8 = sext(rm_04_07);
local result:8 = a * b;
mach = result(4);
macl = result:4;
}
:dmulu.l rm_04_07,rn_08_11 is opcode_12_15=0b0011 & rn_08_11 & rm_04_07 & opcode_00_03=0b0101
{
local a:8 = zext(rn_08_11);
local b:8 = zext(rm_04_07);
local result:8 = a * b;
mach = result(4);
macl = result:4;
}
:dt rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00010000
{
rn_08_11 = rn_08_11 - 1;
$(T_FLAG) = (rn_08_11 == 0);
}
@endif
:exts.b rm_04_07,rn_08_11 is opcode_12_15=0b0110 & rn_08_11 & rm_04_07 & opcode_00_03=0b1110
{
rn_08_11 = rm_04_07;
if((rm_04_07 & 0x00000080) == 0) goto <UNSIGNED>;
rn_08_11 = rn_08_11 | 0xFFFFFF00;
goto <END>;
<UNSIGNED>
rn_08_11 = rn_08_11 & 0x000000FF;
<END>
}
:exts.w rm_04_07,rn_08_11 is opcode_12_15=0b0110 & rn_08_11 & rm_04_07 & opcode_00_03=0b1111
{
rn_08_11 = rm_04_07;
if((rm_04_07 & 0x00008000) == 0) goto <UNSIGNED>;
rn_08_11 = rn_08_11 | 0xFFFF0000;
goto <END>;
<UNSIGNED>
rn_08_11 = rn_08_11 & 0x0000FFFF;
<END>
}
:extu.b rm_04_07,rn_08_11 is opcode_12_15=0b0110 & rn_08_11 & rm_04_07 & opcode_00_03=0b1100
{
rn_08_11 = rm_04_07 & 0x000000FF;
}
:extu.w rm_04_07,rn_08_11 is opcode_12_15=0b0110 & rn_08_11 & rm_04_07 & opcode_00_03=0b1101
{
rn_08_11 = rm_04_07 & 0x0000FFFF;
}
@if SH_VERSION == "2"
:mac.l @rm_04_07+,@rn_08_11+ is opcode_12_15=0b0000 & rn_08_11 & rm_04_07 & opcode_00_03=0b1111
{
# BUGBUG: review this instruction
local RnL;
local RnH;
local RmL;
local RmH;
local Res0;
local Res1:4;
local Res2:4;
local temp0;
local temp1:4;
local temp2:4;
local temp3;
local tempm:4;
local tempn:4;
local fnLmL:4;
tempn = *:4 rn_08_11;
rn_08_11 = rn_08_11 + 4;
tempm = *:4 rm_04_07;
rm_04_07 = rm_04_07 + 4;
if((tempn ^ tempm) s<0) goto <NEG>;
fnLmL = 0;
goto <END>;
<NEG>
fnLmL = -1;
if( tempn s>= 0) goto <SKIP_TEMPN>;
tempn = 0 - tempn;
<SKIP_TEMPN>
if( tempm s>= 0) goto <SKIP_TEMPM>;
tempm = 0 - tempm;
<SKIP_TEMPM>
temp1 = tempn;
temp2 = tempm;
RnL = temp1 & 0x0000FFFF;
RnH = (temp1 >> 16) & 0x0000FFFF;
RmL = temp2 & 0x0000FFFF;
RmH = (temp2 >> 16) & 0x0000FFFF;
temp0 = RmL * RnL;
temp1 = RmH * RnL;
temp2 = RmL * RnH;
temp3 = RmH * RnH;
Res2 = 0;
Res1 = temp1 + temp2;
if(Res2 >= temp1) goto <SKIP_RES2_ADD>;
Res2 = Res2 + 0x00010000;
<SKIP_RES2_ADD>
temp1 = (Res1 << 16) & 0xFFFF0000;
Res0 = temp0 + temp1;
Res2 = Res2 + zext(Res0 < temp0);
Res2 = Res2 + ((Res1 >> 16) & 0x0000FFFF) + temp3;
if(fnLmL s>= 0) goto <CHECK_S>;
Res2 = ~Res2;
if(Res0 == 0) goto <RES0_0>;
Res0 = (~Res0) + 1;
goto <CHECK_S>;
<RES0_0>
Res2 = Res2 + 1;
<CHECK_S>
if($(S_FLAG) != 1) goto <S_0>;
Res0 = macl + Res0;
Res2 = Res2 + zext(macl > Res0);
Res2 = Res2 + (mach & 0x0000FFFF);
if((Res2 s>= 0) || Res2 >= 0xFFFF8000) goto <SKIP_1>;
Res2 = 0xFFFF8000;
Res0 = 0x00000000;
<SKIP_1>
if((Res2 s<= 0) || Res2 <= 0x00007FFF) goto <SKIP_2>;
Res2 = 0x00007FFF;
Res0 = 0xFFFFFFFF;
<SKIP_2>
mach = (Res2 & 0x0000FFFF) | (mach & 0xFFFF0000);
macl = Res0;
goto <END>;
<S_0>
Res0 = macl + Res0;
Res2 = Res2 + zext(macl > Res0);
Res2 = Res2 + mach;
mach = Res2;
macl = Res0;
<END>
}
@endif
:mac.w @rm_04_07+,@rn_08_11+ is opcode_12_15=0b0100 & rn_08_11 & rm_04_07 & opcode_00_03=0b1111
{
# BUGBUG: review this instruction
local tempm:4;
local tempn:4;
local dest;
local src:4;
local ans;
local templ:4;
tempn = *:2 rn_08_11;
rn_08_11 = rn_08_11 + 2;
tempm = *:2 rm_04_07;
rm_04_07 = rm_04_07 + 2;
templ = macl;
tempm = sext(tempn:2) * sext(tempm:2);
dest = (macl s< 0);
if(tempm s< 0) goto <ELSE>;
src = 0;
tempn = 0;
goto <ENDIF>;
<ELSE>
src = 1;
tempn = 0xFFFFFFFF;
<ENDIF>
src = src + zext(dest);
macl = macl + tempm;
ans = (macl s< 0);
ans = ans + dest;
# if (S == 1)
if($(S_FLAG) != 1) goto <S_0>;
if(ans != 1) goto <END>;
@if SH_VERSION == "1"
if(src != 0 && src != 2) goto <SKIP_BIT>;
mach = mach | 0x00000001;
<SKIP_BIT>
@endif
if(src == 0) goto <SRC_0>;
if(src == 2) goto <SRC_2>;
goto <END>;
<SRC_0>
macl = 0x7FFFFFFF;
goto <END>;
<SRC_2>
macl = 0x80000000;
goto <END>;
# if (S != 1)
<S_0>
mach = mach + tempn;
if(templ s<= macl) goto <SKIP_INC>;
macl = macl + 1;
<SKIP_INC>
@if SH_VERSION == "1"
if((mach & 0x00000200) == 0) goto <ZERO_EXTEND>;
mach = mach | 0xFFFFFC00;
goto <END>;
<ZERO_EXTEND>
mach = mach & 0x000003FF;
@endif
<END>
}
@if SH_VERSION == "2"
:mul.l rm_04_07,rn_08_11 is opcode_12_15=0b0000 & rn_08_11 & rm_04_07 & opcode_00_03=0b0111
{
macl = rn_08_11 * rm_04_07;
}
@endif
:muls.w rm_04_07,rn_08_11 is opcode_12_15=0b0010 & rn_08_11 & rm_04_07 & opcode_00_03=0b1111
{
macl = sext(rn_08_11:2 & 0xFFFF) * sext(rm_04_07:2 & 0xFFFF);
}
:mulu.w rm_04_07,rn_08_11 is opcode_12_15=0b0010 & rn_08_11 & rm_04_07 & opcode_00_03=0b1110
{
macl = (rn_08_11 & 0xFFFF) * (rm_04_07 & 0xFFFF);
}
:neg rm_04_07,rn_08_11 is opcode_12_15=0b0110 & rn_08_11 & rm_04_07 & opcode_00_03=0b1011
{
rn_08_11 = 0 - rm_04_07;
}
:negc rm_04_07,rn_08_11 is opcode_12_15=0b0110 & rn_08_11 & rm_04_07 & opcode_00_03=0b1010
{
local temp;
temp = 0 - rm_04_07;
rn_08_11 = temp - zext($(T_FLAG));
# BUGBUG: should temp be signed or unsigned??
# Documentation says if(0 < temp) not 0 != temp
$(T_FLAG) = (0 != temp) || (temp < rn_08_11);
}
:sub rm_04_07,rn_08_11 is opcode_12_15=0b0011 & rn_08_11 & rm_04_07 & opcode_00_03=0b1000
{
rn_08_11 = rn_08_11 - rm_04_07;
}
:subc rm_04_07,rn_08_11 is opcode_12_15=0b0011 & rn_08_11 & rm_04_07 & opcode_00_03=0b1010
{
local temp0;
local temp1;
temp1 = rn_08_11 - rm_04_07;
temp0 = rn_08_11;
rn_08_11 = temp1 - zext($(T_FLAG));
$(T_FLAG) = (temp0 < temp1 || temp1 < rn_08_11);
}
:subv rm_04_07,rn_08_11 is opcode_12_15=0b0011 & rn_08_11 & rm_04_07 & opcode_00_03=0b1011
{
local dest;
local src;
local ans;
dest = !(rn_08_11 s>= 0);
src = !(rm_04_07 s>= 0);
src = src + dest;
rn_08_11 = rn_08_11 - rm_04_07;
ans = (rn_08_11 s>= 0);
ans = ans + dest;
$(T_FLAG) = (src == 1) && (ans == 1);
}
#
# Logic Operation Instructions
#
:and rm_04_07,rn_08_11 is opcode_12_15=0b0010 & rn_08_11 & rm_04_07 & opcode_00_03=0b1001
{
rn_08_11 = rn_08_11 & rm_04_07;
}
:and imm_00_07,r0 is r0 & opcode_08_15=0b11001001 & imm_00_07
{
r0 = (r0 & imm_00_07) & 0x000000FF;
}
:and.b imm_00_07,@(r0,gbr) is r0 & gbr & opcode_08_15=0b11001101 & imm_00_07
{
local temp = *:1 (gbr + r0);
temp = (temp & imm_00_07) & 0x000000FF;
*:1 (gbr + r0) = temp;
}
:not rm_04_07,rn_08_11 is opcode_12_15=0b0110 & rn_08_11 & rm_04_07 & opcode_00_03=0b0111
{
rn_08_11 = ~rm_04_07;
}
:or rm_04_07,rn_08_11 is opcode_12_15=0b0010 & rn_08_11 & rm_04_07 & opcode_00_03=0b1011
{
rn_08_11 = rn_08_11 | rm_04_07;
}
:or imm_00_07,r0 is r0 & opcode_08_15=0b11001011 & imm_00_07
{
r0 = r0 | imm_00_07:4;
}
:or.b imm_00_07,@(r0,gbr) is r0 & gbr & opcode_08_15=0b11001111 & imm_00_07
{
local temp = *:1 (gbr + r0);
temp = (temp & imm_00_07) | 0x000000FF;
*:1 (gbr + r0) = temp;
}
:tas.b @rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00011011
{
local temp = *:1 rn_08_11;
$(T_FLAG) = (temp == 0);
temp = temp | 0x80;
*:1 rn_08_11 = temp;
}
:tst rm_04_07,rn_08_11 is opcode_12_15=0b0010 & rn_08_11 & rm_04_07 & opcode_00_03=0b1000
{
$(T_FLAG) = ((rm_04_07 & rm_04_07) == 0);
}
:tst imm_00_07,r0 is r0 & opcode_08_15=0b11001000 & imm_00_07
{
local temp = r0 & (imm_00_07 & 0x000000FF);
$(T_FLAG) = (temp == 0);
}
:tst.b imm_00_07,@(r0,gbr) is r0 & gbr & opcode_08_15=0b11001100 & imm_00_07
{
local temp = *:1 (gbr + r0);
temp = temp & (imm_00_07 & 0x000000FF);
$(T_FLAG) = (temp == 0);
}
:xor rm_04_07,rn_08_11 is opcode_12_15=0b0010 & rn_08_11 & rm_04_07 & opcode_00_03=0b1010
{
rn_08_11 = rn_08_11 ^ rm_04_07;
}
:xor imm_00_07,r0 is r0 & opcode_08_15=0b11001010 & imm_00_07
{
r0 = r0 ^ (imm_00_07 & 0x000000FF);
}
:xor.b imm_00_07,@(r0,gbr) is r0 & gbr & opcode_08_15=0b11001110 & imm_00_07
{
local temp = *:1 (gbr + r0);
temp = temp & (imm_00_07 & 0x000000FF);
*:1 (gbr + r0) = temp;
}
#
#Shift Instructions
#
:rotcl rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00100100
{
local temp:1;
temp = ((rn_08_11 & 0x80000000) != 0);
rn_08_11 = (rn_08_11 << 1) & 0xFFFFFFFE;
if($(T_FLAG) == 0) goto <SKIP_BIT>;
rn_08_11 = rn_08_11 | 0x1;
<SKIP_BIT>
$(T_FLAG) = temp;
}
:rotcr rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00100101
{
local temp:1;
temp = !((rn_08_11 & 1) == 0);
rn_08_11 = (rn_08_11 >> 1) & 0x7FFFFFFF;
if($(T_FLAG) == 0) goto <SKIP_BIT>;
rn_08_11 = rn_08_11 | 0x80000000;
<SKIP_BIT>
$(T_FLAG) = temp;
}
:rotl rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00000100
{
$(T_FLAG) = ((rn_08_11 & 0x80000000) != 0);
if($(T_FLAG) == 1) goto <SIGN_EXTEND>;
rn_08_11 = rn_08_11 & 0xFFFFFFFE;
goto <END>;
<SIGN_EXTEND>
rn_08_11 = rn_08_11 | 0x00000001;
<END>
}
:rotr rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00000101
{
$(T_FLAG) = ((rn_08_11 & 0x1) != 0);
if($(T_FLAG) == 1) goto <SIGN_EXTEND>;
rn_08_11 = rn_08_11 & 0x7FFFFFFF;
goto <END>;
<SIGN_EXTEND>
rn_08_11 = rn_08_11 | 0x80000000;
<END>
}
:shal rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00100000
{
# clear or set T
$(T_FLAG) = ((rn_08_11 & 0x80000000) != 0);
rn_08_11 = rn_08_11 << 1;
}
:shar rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00100001
{
$(T_FLAG) = ((rn_08_11 & 1) == 1);
rn_08_11 = rn_08_11 >> 1;
if((rn_08_11 & 0x80000000) != 1) goto <SIGN_EXTEND>;
rn_08_11 = rn_08_11 & 0x7FFFFFFF;
goto <END>;
<SIGN_EXTEND>
rn_08_11 = rn_08_11 | 0x80000000;
<END>
}
:shll rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00000000
{
# clear or set T
$(T_FLAG) = ((rn_08_11 & 0x80000000) != 0);
rn_08_11 = rn_08_11 << 1;
}
:shll2 rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00001000
{
rn_08_11 = rn_08_11 << 2;
}
:shll8 rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00011000
{
rn_08_11 = rn_08_11 << 8;
}
:shll16 rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00101000
{
rn_08_11 = rn_08_11 << 16;
}
:shlr rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00000001
{
# clear or set T
$(T_FLAG) = (rn_08_11 & 1) == 1;
rn_08_11 = rn_08_11 >> 1;
rn_08_11 = rn_08_11 & 0x7FFFFFFF;
}
:shlr2 rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00001001
{
rn_08_11 = rn_08_11 >> 2;
rn_08_11 = rn_08_11 & 0x3FFFFFFF;
}
:shlr8 rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00011001
{
rn_08_11 = rn_08_11 >> 8;
rn_08_11 = rn_08_11 & 0x00FFFFFF;
}
:shlr16 rn_08_11 is opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00101001
{
rn_08_11 = rn_08_11 >> 16;
rn_08_11 = rn_08_11 & 0x0000FFFF;
}
#
# Branch Instructions
#
:bf target00_07 is opcode_08_15=0b10001011 & target00_07
{
if ($(T_FLAG) == 0) goto target00_07;
}
@if SH_VERSION == "2"
:bf"/s" target00_07 is opcode_08_15=0b10001111 & target00_07
{
delayslot(1);
if ($(T_FLAG)==0) goto target00_07;
}
@endif
:bt target00_07 is opcode_08_15=0b10001001 & target00_07
{
if ($(T_FLAG) == 1) goto target00_07;
}
@if SH_VERSION == "2"
:bt"/s" target00_07 is opcode_08_15=0b10001101 & target00_07
{
delayslot(1);
if ($(T_FLAG)==1) goto target00_07;
}
@endif
:bra target00_11 is opcode_12_15=0b1010 & target00_11
{
delayslot(1);
goto target00_11;
}
@if SH_VERSION == "2"
:braf rm_08_11 is opcode_12_15=0b0000 & rm_08_11 & opcode_00_07=0b00100011
{
local temp:4 = inst_start + 4 + rm_08_11;
delayslot(1);
goto [temp];
}
@endif
:bsr target00_11 is opcode_12_15=0b1011 & target00_11
{
pr = inst_start + 4;
delayslot(1);
call target00_11;
}
@if SH_VERSION == "2"
:bsrf rm_08_11 is opcode_12_15=0b0000 & rm_08_11 & opcode_00_07=0b00000011
{
pr = inst_start + 4;
delayslot(1);
call [rm_08_11];
}
@endif
:jmp @rm_08_11 is opcode_12_15=0b0100 & rm_08_11 & opcode_00_07=0b00101011
{
delayslot(1);
goto [rm_08_11];
}
:jsr @rm_08_11 is opcode_12_15=0b0100 & rm_08_11 & opcode_00_07=0b00001011
{
pr = inst_start + 4;
delayslot(1);
call [rm_08_11];
}
:rts is opcode_00_15=0b0000000000001011
{
delayslot(1);
return [pr];
}
#
# System Control Instructions
#
:clrmac is opcode_00_15=0b0000000000101000
{
mach = 0;
macl = 0;
}
:clrt is opcode_00_15=0b0000000000001000
{
$(T_FLAG) = 0;
}
:ldc rm_08_11,sr is sr & opcode_12_15=0b0100 & rm_08_11 & opcode_00_07=0b00001110
{
sr = rm_08_11 & 0x0FFF0FFF;
}
:ldc.l @rm_08_11+,sr is sr & opcode_12_15=0b0100 & rm_08_11 & opcode_00_07=0b00000111
{
sr = *rm_08_11 & 0x0FFF0FFF;
rm_08_11 = rm_08_11 + 4;
}
:ldc rm_08_11,gbr is gbr & opcode_12_15=0b0100 & rm_08_11 & opcode_00_07=0b00011110
{
gbr = rm_08_11;
}
:ldc.l @rm_08_11+,gbr is gbr & opcode_12_15=0b0100 & rm_08_11 & opcode_00_07=0b00010111
{
gbr = *rm_08_11;
rm_08_11 = rm_08_11 + 4;
}
:ldc rm_08_11,vbr is vbr & opcode_12_15=0b0100 & rm_08_11 & opcode_00_07=0b00101110
{
vbr = rm_08_11;
}
:ldc.l @rm_08_11+,vbr is vbr & opcode_12_15=0b0100 & rm_08_11 & opcode_00_07=0b00100111
{
vbr = *rm_08_11;
rm_08_11 = rm_08_11 + 4;
}
:lds rm_08_11,mach is mach & opcode_12_15=0b0100 & rm_08_11 & opcode_00_07=0b00001010
{
mach = rm_08_11;
@if SH_VERSION == "1"
if((mach & 0x00000200) == 0) goto <ZERO_EXTEND>;
# sign extend
mach = mach | 0xFFFFFC00;
goto <END>;
<ZERO_EXTEND>
mach = mach & 0x000003FF;
<END>
@endif
}
:lds.l @rm_08_11+,mach is mach & opcode_12_15=0b0100 & rm_08_11 & opcode_00_07=0b00000110
{
mach = *rm_08_11;
@if SH_VERSION == "1"
if((mach & 0x00000200) == 0) goto <ZERO_EXTEND>;
# sign extend
mach = mach | 0xFFFFFC00;
goto <END>;
<ZERO_EXTEND>
mach = mach & 0x000003FF;
<END>
@endif
rm_08_11 = rm_08_11 + 4;
}
:lds rm_08_11,macl is macl & opcode_12_15=0b0100 & rm_08_11 & opcode_00_07=0b00011010
{
macl = rm_08_11;
}
:lds.l @rm_08_11+,macl is macl & opcode_12_15=0b0100 & rm_08_11 & opcode_00_07=0b00010110
{
macl = *rm_08_11;
rm_08_11 = rm_08_11 + 4;
}
:lds rm_08_11,pr is pr & opcode_12_15=0b0100 & rm_08_11 & opcode_00_07=0b00101010
{
pr = rm_08_11;
}
:lds.l @rm_08_11+,pr is pr & opcode_12_15=0b0100 & rm_08_11 & opcode_00_07=0b00100110
{
pr = *rm_08_11;
rm_08_11 = rm_08_11 + 4;
}
:nop is opcode_00_15=0b0000000000001001
{
# BUGBUG: intentional nop
r0 = r0; # do this to suppress warning
}
:rte is opcode_00_15=0b0000000000101011
{
_pc:4 = *r15;
r15 = r15 + 4;
_sr:4 = *r15 & 0x000063F3;
r15 = r15 + 4;
delayslot(1);
pc = _pc;
sr = _sr;
goto [pc];
}
:sett is opcode_00_15=0b0000000000011000
{
$(T_FLAG) = 1;
}
:sleep is opcode_00_15=0b0000000000011011
{
# BUGBUG: call sleep();
r0 = r0;
}
:stc sr,rn_08_11 is sr & opcode_12_15=0b0000 & rn_08_11 & opcode_00_07=0b00000010
{
rn_08_11 = sr;
}
:stc.l sr,@-rn_08_11 is sr & opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00000011
{
rn_08_11 = rn_08_11 -4;
*rn_08_11 = sr;
}
:stc gbr,rn_08_11 is gbr & opcode_12_15=0b0000 & rn_08_11 & opcode_00_07=0b00010010
{
rn_08_11 = gbr;
}
:stc.l gbr,@-rn_08_11 is gbr & opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00010011
{
rn_08_11 = rn_08_11 -4;
*rn_08_11 = gbr;
}
:stc vbr,rn_08_11 is vbr & opcode_12_15=0b0000 & rn_08_11 & opcode_00_07=0b00100010
{
rn_08_11 = vbr;
}
:stc.l vbr,@-rn_08_11 is vbr & opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00100011
{
rn_08_11 = rn_08_11 -4;
*rn_08_11 = vbr;
}
:sts mach,rn_08_11 is mach & opcode_12_15=0b0000 & rn_08_11 & opcode_00_07=0b00001010
{
rn_08_11 = mach;
@if SH_VERSION == "1"
if((rn_08_11 & 0x00000200) == 0) goto <ZERO_EXTEND>;
# sign extend
rn_08_11 = rn_08_11 | 0xFFFFFC00;
goto <END>;
<ZERO_EXTEND>
rn_08_11 = rn_08_11 & 0x000003FF;
<END>
@endif
}
:sts.l mach,@-rn_08_11 is mach & opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00000010
{
rn_08_11 = rn_08_11 - 4;
local temp = mach;
@if SH_VERSION == "1"
if((temp & 0x00000200) == 0) goto <ZERO_EXTEND>;
# sign extend
temp = temp | 0xFFFFFC00;
goto <END>;
<ZERO_EXTEND>
temp = temp & 0x000003FF;
<END>
@endif
*rn_08_11 = temp;
}
:sts macl,rn_08_11 is macl & opcode_12_15=0b0000 & rn_08_11 & opcode_00_07=0b00011010
{
rn_08_11 = macl;
}
:sts.l macl,@-rn_08_11 is macl & opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00010010
{
rn_08_11 = rn_08_11 -4;
*rn_08_11 = macl;
}
:sts pr,rn_08_11 is pr & opcode_12_15=0b0000 & rn_08_11 & opcode_00_07=0b00101010
{
rn_08_11 = pr;
}
:sts.l pr,@-rn_08_11 is pr & opcode_12_15=0b0100 & rn_08_11 & opcode_00_07=0b00100010
{
rn_08_11 = rn_08_11 -4;
*rn_08_11 = pr;
}
:trapa imm_00_07 is opcode_08_15=0b11000011 & imm_00_07
{
r15 = r15 -4;
*r15 = sr;
r15 = r15- 4;
*r15 = pc + 2;
pc = *(vbr + (imm_00_07 * 4));
goto [pc];
}