ghidra/Ghidra/Processors/Sparc/data/languages/SparcV9.sinc

1259 lines
61 KiB
Plaintext

# SLA specification file for SPARC/64
define endian=big;
define alignment=4;
define space ram type=ram_space size=$(SIZE) default;
define space register type=register_space size=4;
define register offset=0 size=$(SIZE) [
g0 g1 g2 g3 g4 g5 g6 g7
o0 o1 o2 o3 o4 o5 sp o7
l0 l1 l2 l3 l4 l5 l6 l7
i0 i1 i2 i3 i4 i5 fp i7
];
# these are save locations for implementing register windows
#
define register offset=0x500 size=$(SIZE) [
s_l0 s_l1 s_l2 s_l3 s_l4 s_l5 s_l6 s_l7
s_i0 s_i1 s_i2 s_i3 s_i4 s_i5 s_fp s_i7
];
define register offset=0x1000 size=$(SIZE) [ PC nPC ASR TICK Y CCR FPRS PCR PIC GSR SOFTINT_SET SOFTINT_CLR SOFTINT TICK_CMPR STICK STICK_CMPR ];
define register offset=0x1100 size=$(SIZE) [
asr7 asr8 asr9 asr10 asr11 asr12 asr13 asr14 asr15
asr16 asr17 asr18 asr19 asr20 asr21 asr22 asr23
asr24 asr25 asr26 asr27 asr28 asr29 asr30 asr31
];
define register offset=0x3000 size=1 [ x_nf x_zf x_vf x_cf i_nf i_zf i_vf i_cf ];
define register offset=0x4000 size=1 [ ASI _ _ _ _ _ _ _ fprs _ _ _ _ _ _ _ ];
define register offset=0x4000 size=$(SIZE) [ ASIext fprsext ];
define register offset=0x5000 size=2 [ fsr ];
define register offset=0x5002 size=1 [ fcc0 fcc1 fcc2 fcc3 ];
define register offset=0x5010 size=1 [ didrestore ];
define register offset=0x5020 size=1 [ DECOMPILE_MODE ]; # Fake register
define register offset=0x5000 size=$(SIZE) [
TPC1 TPC2 TPC3 TPC4
TNPC1 TNPC2 TNPC3 TNPC4
TSTATE1 TSTATE2 TSTATE3 TSTATE4
TT1 TT2 TT3 TT4
TCK TBA PSTATE TL
PIL CWP CANSAVE CANRESTORE CLEANWIN
OTHERWIN WSTATE FQ VER GL
];
define register offset=0x6000 size=$(SIZE) [
HPSTATE1 HPSTATE2 HPSTATE3 HPSTATE4
HTSTATE1 HTSTATE2 HTSTATE3 HTSTATE4
RESV2_1 RESV2_2 RESV2_3 RESV2_4
HINTP1 HINTP2 HINTP3 HINTP4
RESV4_1 RESV4_2 RESV4_3 RESV4_4
HTBA1 HTBA2 HTBA3 HTBA4
HVER1 HVER2 HVER3 HVER4
# TODO: actually RESV 6 - 29 registers...
RESV30_1 RESV30_2 RESV30_3 RESV30_4
HSTICK_CMPR1 HSTICK_CMPR2 HSTICK_CMPR3 HSTICK_CMPR4
];
# A window is 24 registers (96 or 192 bytes), most processors have 7 or 8. (g0->g7,o0->o7,l0->o7,i0->i7)
# When the window is overflowed the data must be purged to some backup memory, via user
# supplied function attached to a signal handler.
# When the window is underflowed the data must be read from some backup memory, via user
# supplied function attached to a signal handler.
# There are 2 basic strategies we figured for this.
# One, create a bank of register space and read and write to it in a way that simulates
# how the sparc would really work, but the symbolic names become indexes.
# Two, save and restore logic does all the work.
# window index is ((CWP+1)%NWINDOWS)
# CWP is an index from 0 to N of the windows.
# Size of CWP is implementation dependent (must be > 5 bits).
# inputs i0 i1 i2 i3 i4 i5 fp i7
# locals l0 l1 l2 l3 l4 l5 l6 l7
# output o0 o1 o2 o3 o4 o5 sp o7
# fp w016 w036 w126 w236 w316 w336 w416 w436 w516 w536
# sp w036 w126 w236 w316 w336 w416 w436 w616 w536
# i7 w017 w037 w127 w217 w237 w327 w417
# o7 w037 w127 w217 w237 w327 w417
define register offset=0x7000 size=$(SIZE) [
w010 w011 w012 w013 w014 w015 w016 w017
w020 w021 w022 w023 w024 w025 w026 w027
w030 w031 w032 w033 w034 w035 w036 w037
w110 w111 w112 w113 w114 w115 w116 w117
w120 w121 w122 w123 w124 w125 w126 w127
w130 w131 w132 w133 w134 w135 w136 w137
w210 w211 w212 w213 w214 w215 w216 w217
w220 w221 w222 w223 w224 w225 w226 w227
w230 w231 w232 w233 w234 w235 w236 w237
w310 w311 w312 w313 w314 w315 w316 w317
w320 w321 w322 w323 w324 w325 w326 w327
w330 w331 w332 w333 w334 w335 w336 w337
w410 w411 w412 w413 w414 w415 w416 w417
w420 w421 w422 w423 w424 w425 w426 w427
w430 w431 w432 w433 w434 w435 w436 w437
w510 w511 w512 w513 w514 w515 w516 w517
w520 w521 w522 w523 w524 w525 w526 w527
w530 w531 w532 w533 w534 w535 w536 w537
w610 w611 w612 w613 w614 w615 w616 w617
w620 w621 w622 w623 w624 w625 w626 w627
w630 w631 w632 w633 w634 w635 w636 w637
w710 w711 w712 w713 w714 w715 w716 w717
w720 w721 w722 w723 w724 w725 w726 w727
w730 w731 w732 w733 w734 w735 w736 w737
];
# Floating-point registers
define register offset=0x2000 size=4 [
fs0 fs1 fs2 fs3 fs4 fs5 fs6 fs7
fs8 fs9 fs10 fs11 fs12 fs13 fs14 fs15
fs16 fs17 fs18 fs19 fs20 fs21 fs22 fs23
fs24 fs25 fs26 fs27 fs28 fs29 fs30 fs31
];
define register offset=0x2000 size=8 [
fd0 fd2 fd4 fd6 fd8 fd10 fd12 fd14
fd16 fd18 fd20 fd22 fd24 fd26 fd28 fd30
fd32 fd34 fd36 fd38 fd40 fd42 fd44 fd46
fd48 fd50 fd52 fd54 fd56 fd58 fd60 fd62
];
define register offset=0x2000 size=16 [
fq0 fq4 fq8 fq12 fq16 fq20 fq24 fq28
fq32 fq36 fq40 fq44 fq48 fq52 fq56 fq60
];
define pcodeop segment;
define pcodeop popc;
define pcodeop sw_trap;
define pcodeop reset;
define token instr(32)
op = (30,31)
disp30 = ( 0,29) signed
udisp22 = ( 0,21)
disp22 = ( 0,21) signed
disp19 = ( 0,18) signed
d16lo = ( 0,13)
d16hi = (20,21) signed
op2 = (22,24)
a = (29,29)
fpc = (27,29)
cond = (25,28)
cond4 = (14,17)
rcond2 = (25,27)
cc0 = (20,20)
cc1 = (21,21)
fccn = (20,21)
fccn2 = (25,26)
cc0_3 = (25,25)
cc1_3 = (26,26)
cc0_4 = (11,11)
cc1_4 = (12,12)
fccn_4 = (11,12)
cc2_4 = (18,18)
p = (19,19)
rd = (25,29)
rd_d = (25,29)
rd_zero = (25,29)
fsrd = (25,29)
fdrd = (25,29)
fqrd = (25,29)
prd = (25,29)
op3 = (19,24)
rs1 = (14,18)
rs1_zero = (14,18)
rs1_3 = (14,18)
prs1 = (14,18)
fsrs1 = (14,18)
fdrs1 = (14,18)
fqrs1 = (14,18)
i = (13,13)
x = (12,12)
rcond3 = (10,12)
rs2 = ( 0, 4)
rs2_zero = ( 0, 4)
fsrs2 = ( 0, 4)
fdrs2 = ( 0, 4)
fqrs2 = ( 0, 4)
shcnt32 = ( 0, 4)
shcnt64 = ( 0, 5)
simm13 = ( 0,12) signed
simm11 = ( 0,10) signed
simm10 = ( 0, 9) signed
imm_asi = ( 5,12)
cmask = ( 4, 6)
mmask = ( 0, 3)
opf = ( 5,13)
opf5 = ( 5, 9)
opf6 = ( 5,10)
opf_cc = (11,13)
opf_low = ( 5,10)
fcn = (25,29)
swtrap = ( 0, 6)
bit28 = (28,28)
const22 = ( 0,21)
bit13 = (13,13)
bit18 = (18,18)
;
attach variables [ rd rs1 rs2 ] [ g0 g1 g2 g3 g4 g5 g6 g7
o0 o1 o2 o3 o4 o5 sp o7
l0 l1 l2 l3 l4 l5 l6 l7
i0 i1 i2 i3 i4 i5 fp i7 ];
@if SIZE=="4"
# The ldd, ldda, std, and stda insns access a pair of regs
define register offset=0 size=8 [
g0_1 g2_3 g4_5 g6_7
o0_1 o2_3 o4_5 sp_7
l0_1 l2_3 l4_5 l6_7
i0_1 i2_3 i4_5 fp_7
];
attach variables [ rd_d ] [
g0_1 _ g2_3 _ g4_5 _ g6_7 _
o0_1 _ o2_3 _ o4_5 _ sp_7 _
l0_1 _ l2_3 _ l4_5 _ l6_7 _
i0_1 _ i2_3 _ i4_5 _ fp_7 _
];
@endif
attach variables [ fccn fccn2 fccn_4 ] [ fcc0 fcc1 fcc2 fcc3 ];
attach variables [ rs1_3 ] [ Y _ CCR _ TICK PC _ asr7
asr8 asr9 asr10 asr11 asr12 asr13 asr14 asr15
PCR PIC asr18 GSR SOFTINT_SET SOFTINT_CLR SOFTINT TICK_CMPR
STICK STICK_CMPR asr26 asr27 asr28 asr29 asr30 asr31 ];
#attach names [ rd rs1 rs2 ] [ "%g0" "%g1" "%g2" "%g3" "%g4" "%g5" "%g6" "%g7"
# "%o0" "%o1" "%o2" "%o3" "%o4" "%o5" "%sp" "%o7"
# "%l0" "%l1" "%l2" "%l3" "%l4" "%l5" "%l6" "%l7"
# "%i0" "%i1" "%i2" "%i3" "%i4" "%i5" "%fp" "%i7" ];
# Window register table accessors ===================================
@define NUMREGWINS 8
@define REGWINSZ 16
@define LOCALOFF 8
@define OUTOFF 16
# copy oN to iN
# CWP++
macro save() {
if (DECOMPILE_MODE) goto <skip_rotate>;
# Save inputs
*[register]:$(SIZE) (&w010 + (CWP:4*$(REGWINSZ)+0)*$(SIZE)) = i0;
*[register]:$(SIZE) (&w010 + (CWP:4*$(REGWINSZ)+1)*$(SIZE)) = i1;
*[register]:$(SIZE) (&w010 + (CWP:4*$(REGWINSZ)+2)*$(SIZE)) = i2;
*[register]:$(SIZE) (&w010 + (CWP:4*$(REGWINSZ)+3)*$(SIZE)) = i3;
*[register]:$(SIZE) (&w010 + (CWP:4*$(REGWINSZ)+4)*$(SIZE)) = i4;
*[register]:$(SIZE) (&w010 + (CWP:4*$(REGWINSZ)+5)*$(SIZE)) = i5;
*[register]:$(SIZE) (&w010 + (CWP:4*$(REGWINSZ)+6)*$(SIZE)) = fp;
*[register]:$(SIZE) (&w010 + (CWP:4*$(REGWINSZ)+7)*$(SIZE)) = i7;
# Save local
*[register]:$(SIZE) (&w010 + (CWP:4*$(REGWINSZ)+0+$(LOCALOFF))*$(SIZE)) = l0;
*[register]:$(SIZE) (&w010 + (CWP:4*$(REGWINSZ)+1+$(LOCALOFF))*$(SIZE)) = l1;
*[register]:$(SIZE) (&w010 + (CWP:4*$(REGWINSZ)+2+$(LOCALOFF))*$(SIZE)) = l3;
*[register]:$(SIZE) (&w010 + (CWP:4*$(REGWINSZ)+3+$(LOCALOFF))*$(SIZE)) = l3;
*[register]:$(SIZE) (&w010 + (CWP:4*$(REGWINSZ)+4+$(LOCALOFF))*$(SIZE)) = l4;
*[register]:$(SIZE) (&w010 + (CWP:4*$(REGWINSZ)+5+$(LOCALOFF))*$(SIZE)) = l5;
*[register]:$(SIZE) (&w010 + (CWP:4*$(REGWINSZ)+6+$(LOCALOFF))*$(SIZE)) = l6;
*[register]:$(SIZE) (&w010 + (CWP:4*$(REGWINSZ)+7+$(LOCALOFF))*$(SIZE)) = l7;
<skip_rotate>
# what was outputs become inputs
i0 = o0;
i1 = o1;
i2 = o2;
i3 = o3;
i4 = o4;
i5 = o5;
fp = sp;
i7 = o7;
# zero out locals
l0 = 0;
l1 = 0;
l2 = 0;
l3 = 0;
l4 = 0;
l5 = 0;
l6 = 0;
l7 = 0;
CWP = CWP + 1;
}
# copy iN ot oN
# CWP--
macro restore() {
CWP = CWP - 1;
# inputs once again become outputs
o0 = i0; # API return value
o1 = i1;
o2 = i2;
o3 = i3;
o4 = i4;
o5 = i5;
sp = fp;
o7 = i7; # address of CALLer address
if (DECOMPILE_MODE) goto <skip_rotate>;
# restore original inputs
i0 = *[register]:$(SIZE) ((&w010) + ((CWP:4*$(REGWINSZ)+0)*$(SIZE)));
i1 = *[register]:$(SIZE) ((&w010) + ((CWP:4*$(REGWINSZ)+1)*$(SIZE)));
i2 = *[register]:$(SIZE) ((&w010) + ((CWP:4*$(REGWINSZ)+2)*$(SIZE)));
i3 = *[register]:$(SIZE) ((&w010) + ((CWP:4*$(REGWINSZ)+3)*$(SIZE)));
i4 = *[register]:$(SIZE) ((&w010) + ((CWP:4*$(REGWINSZ)+4)*$(SIZE)));
i5 = *[register]:$(SIZE) ((&w010) + ((CWP:4*$(REGWINSZ)+5)*$(SIZE)));
fp = *[register]:$(SIZE) ((&w010) + ((CWP:4*$(REGWINSZ)+6)*$(SIZE)));
i7 = *[register]:$(SIZE) ((&w010) + ((CWP:4*$(REGWINSZ)+7)*$(SIZE))); # address of CALLer address
# restore original locals
l0 = *[register]:$(SIZE) ((&w010) + ((CWP:4*$(REGWINSZ)+0+$(LOCALOFF))*$(SIZE)));
l1 = *[register]:$(SIZE) ((&w010) + ((CWP:4*$(REGWINSZ)+1+$(LOCALOFF))*$(SIZE)));
l2 = *[register]:$(SIZE) ((&w010) + ((CWP:4*$(REGWINSZ)+2+$(LOCALOFF))*$(SIZE)));
l3 = *[register]:$(SIZE) ((&w010) + ((CWP:4*$(REGWINSZ)+3+$(LOCALOFF))*$(SIZE)));
l4 = *[register]:$(SIZE) ((&w010) + ((CWP:4*$(REGWINSZ)+4+$(LOCALOFF))*$(SIZE)));
l5 = *[register]:$(SIZE) ((&w010) + ((CWP:4*$(REGWINSZ)+5+$(LOCALOFF))*$(SIZE)));
l6 = *[register]:$(SIZE) ((&w010) + ((CWP:4*$(REGWINSZ)+6+$(LOCALOFF))*$(SIZE)));
l7 = *[register]:$(SIZE) ((&w010) + ((CWP:4*$(REGWINSZ)+6+$(LOCALOFF))*$(SIZE)));
<skip_rotate>
}
RS1: rs1 is rs1 & rs1_zero=0 { export 0:$(SIZE); }
RS1: rs1 is rs1 { export rs1; }
RS2: rs2 is rs2 & rs2_zero=0 { export 0:$(SIZE); }
RS2: rs2 is rs2 { export rs2; }
RD: rd is rd & rd_zero=0 { export 0:$(SIZE); }
RD: rd is rd & rd_zero { export rd; }
regorimm: RS2 is i=0 & RS2 { export RS2; }
regorimm: simm13 is i=1 & simm13 { export *[const]:$(SIZE) simm13; }
regorimm10: RS2 is i=0 & RS2 { export RS2; }
regorimm10: simm10 is i=1 & simm10 { export *[const]:$(SIZE) simm10; }
regorimm11: RS2 is i=0 & RS2 { export RS2; }
regorimm11: simm11 is i=1 & simm11 { export *[const]:$(SIZE) simm11; }
reg_or_shcnt: RS2 is i=0 & RS2 & rs2=0 { export 0:1; }
reg_or_shcnt: RS2 is i=0 & x=0 & RS2 { tmp:1=RS2:1; tmp = tmp & 0x1f; export tmp; }
reg_or_shcnt: RS2 is i=0 & x=1 & RS2 { tmp:1=RS2:1; tmp = tmp & 0x3f; export tmp; }
reg_or_shcnt: shcnt32 is i=1 & x=0 & shcnt32 { export *[const]:1 shcnt32; }
reg_or_shcnt: shcnt64 is i=1 & x=1 & shcnt64 { export *[const]:1 shcnt64; }
ea: [regorimm] is rs1=0 & regorimm { export regorimm; } # special case g0=zero
ea: [RS1+regorimm] is RS1 & regorimm { local tmp = RS1+regorimm; export tmp; }
ea: [RS1] is RS1 & i=1 & simm13=0x0 { export RS1; } #special case when adding zero
retea: [regorimm] is rs1=0 & regorimm { export regorimm; }
retea: [RS1+regorimm] is RS1 & regorimm { local tmp = RS1+regorimm; export tmp; }
retea: [RS1] is RS1 & i=1 & simm13=0x0 { export RS1; } #special case when adding zero
retea: is rs1 & rs1_zero=31 & i=1 & simm13=0x8 { local tmp = rs1 + 0x8; export tmp; } # typical return from CALL instruction (suppress display)
ea_alt: [RS1+RS2] imm_asi is i=0 & RS1 & RS2 & imm_asi { local tmp1:1 = imm_asi; local tmp = RS1+RS2+segment(tmp1); export tmp; }
ea_alt: [RS1+simm13] %ASI is i=1 & RS1 & simm13 & ASI { local tmp = RS1+simm13+segment(ASI); export tmp; }
ea_alt: [RS1] %ASI is i=1 & RS1 & simm13=0x0 & ASI { local tmp = RS1+segment(ASI); export tmp; } #special case when adding zero
macro addflags(op1,op2) {
x_cf = carry(op1,op2);
x_vf = scarry(op1,op2);
local tmp1 = op1:4;
local tmp2 = op2:4;
i_cf = carry(tmp1,tmp2);
i_vf = scarry(tmp1,tmp2);
}
macro taddflags(op1,op2) {
addflags(op1,op2);
i_vf = i_vf || ((op1 & 0x3) != 0) || ((op2 & 0x3) != 0);
}
macro addflags32(op1,op2) {
i_cf = carry(op1,op2);
i_vf = scarry(op1,op2);
}
macro logicflags() {
x_cf = 0;
x_vf = 0;
i_cf = 0;
i_vf = 0;
}
macro subflags(op1,op2) {
x_cf = op1 < op2;
x_vf = sborrow(op1,op2);
local tmp1 = op1:4;
local tmp2 = op2:4;
i_cf = tmp1 < tmp2;
i_vf = sborrow(tmp1,tmp2);
}
macro zeroflags(op1) {
x_zf = (op1 == 0);
x_nf = (op1 s< 0);
local tmp1 = op1:4;
i_zf = (tmp1 == 0);
i_nf = (tmp1 s< 0);
}
macro packflags(ccr) {
ccr = zext((x_nf << 7) | (x_zf << 6) | (x_vf << 5) | (x_cf << 4) | (i_nf << 3) | (i_zf << 2) | (i_vf << 1) | (i_cf << 0));
}
macro unpackflags(ccr) {
x_nf = (ccr & 0x80)!=0;
x_zf = (ccr & 0x40)!=0;
x_vf = (ccr & 0x20)!=0;
x_cf = (ccr & 0x10)!=0;
i_nf = (ccr & 0x8)!=0;
i_zf = (ccr & 0x4)!=0;
i_vf = (ccr & 0x2)!=0;
i_cf = (ccr & 0x1)!=0;
}
# ---------------
:add RS1,regorimm,rd is op=2 & rd & op3=0x0 & RS1 & regorimm {rd = RS1 + regorimm;}
:addcc RS1,regorimm,rd is op=2 & rd & op3=0x10 & RS1 & regorimm {addflags(RS1,regorimm);
rd = RS1 + regorimm;
zeroflags(rd);
}
:addc RS1,regorimm,rd is op=2 & rd & op3=0x8 & RS1 & regorimm {rd = RS1 + regorimm + zext(i_cf);}
:addccc RS1,regorimm,rd is op=2 & rd & op3=0x18 & RS1 & regorimm {addflags(RS1,regorimm);
rd = RS1 + regorimm + zext(i_cf);
zeroflags(rd);
}
#-----------------------
:and RS1,regorimm,rd is op=2 & rd & op3=0x1 & RS1 & regorimm {rd = RS1 & regorimm;}
:andcc RS1,regorimm,rd is op=2 & rd & op3=0x11 & RS1 & regorimm {logicflags();
rd = RS1 & regorimm;
zeroflags(rd);
}
:andn RS1,regorimm,rd is op=2 & rd & op3=0x5 & RS1 & regorimm {rd = RS1 & ~regorimm;}
:andncc RS1,regorimm,rd is op=2 & rd & op3=0x15 & RS1 & regorimm {logicflags();
rd = RS1 & ~regorimm;
zeroflags(rd);
}
:or RS1,regorimm,rd is op=2 & rd & op3=0x2 & RS1 & regorimm {rd = RS1 | regorimm;}
:orcc RS1,regorimm,rd is op=2 & rd & op3=0x12 & RS1 & regorimm {logicflags();
rd = RS1 | regorimm;
zeroflags(rd);
}
:orn RS1,regorimm,rd is op=2 & rd & op3=0x6 & RS1 & regorimm {rd = RS1 | ~regorimm;}
:orncc RS1,regorimm,rd is op=2 & rd & op3=0x16 & RS1 & regorimm {logicflags();
rd = RS1 | ~regorimm;
zeroflags(rd);
}
:xor RS1,regorimm,rd is op=2 & rd & op3=0x3 & RS1 & regorimm {rd = RS1 ^ regorimm;}
:xorcc RS1,regorimm,rd is op=2 & rd & op3=0x13 & RS1 & regorimm {logicflags();
rd = RS1 ^ regorimm;
zeroflags(rd);
}
:xnor RS1,regorimm,rd is op=2 & rd & op3=0x7 & RS1 & regorimm {rd = RS1 ^ ~regorimm;}
:xnorcc RS1,regorimm,rd is op=2 & rd & op3=0x17 & RS1 & regorimm {logicflags();
rd = RS1 ^ ~regorimm;
zeroflags(rd);
}
# ---------------
:ldsb ea,rd is op=3 & rd & op3=0x09 & ea { rd = sext(*:1 ea); }
:ldsh ea,rd is op=3 & rd & op3=0x0A & ea { rd = sext(*:2 ea); }
:ldsw ea,rd is op=3 & rd & op3=0x08 & ea { rd = sext(*:4 ea); }
:ldub ea,rd is op=3 & rd & op3=0x01 & ea { rd = zext(*:1 ea); }
:lduh ea,rd is op=3 & rd & op3=0x02 & ea { rd = zext(*:2 ea); }
:lduw ea,rd is op=3 & rd & op3=0x00 & ea { rd = zext(*:4 ea); }
:ldx ea,rd is op=3 & rd & op3=0x0b & ea { rd = *:$(SIZE) ea; }
@if SIZE=="8"
:ldd ea,rd is op=3 & rd & op3=0x03 & ea { rd = *:$(SIZE) ea; }
@else
:ldd ea,rd is op=3 & rd & rd_d & op3=0x03 & ea { rd_d = *:8 ea; }
@endif
:ldsba ea_alt,rd is op=3 & rd & op3=0x19 & ea_alt { rd = sext(*:1 ea_alt); }
:ldsha ea_alt,rd is op=3 & rd & op3=0x1a & ea_alt { rd = sext(*:2 ea_alt); }
:ldswa ea_alt,rd is op=3 & rd & op3=0x18 & ea_alt { rd = sext(*:4 ea_alt); }
:lduba ea_alt,rd is op=3 & rd & op3=0x11 & ea_alt { rd = zext(*:1 ea_alt); }
:lduha ea_alt,rd is op=3 & rd & op3=0x12 & ea_alt { rd = zext(*:2 ea_alt); }
:lduwa ea_alt,rd is op=3 & rd & op3=0x10 & ea_alt { rd = zext(*:4 ea_alt); }
:ldxa ea_alt,rd is op=3 & rd & op3=0x1b & ea_alt { rd = *:$(SIZE) ea_alt; }
:ldda ea_alt,rd is op=3 & rd & op3=0x13 & ea_alt { rd = *:$(SIZE) ea_alt; }
#-----------------
:stb RD,ea is op=3 & RD & op3=0x05 & ea { *ea = RD:1; }
:sth RD,ea is op=3 & RD & op3=0x06 & ea { *ea = RD:2; }
:stw RD,ea is op=3 & RD & op3=0x04 & ea { *ea = RD:4; }
@if SIZE=="8"
:stx RD,ea is op=3 & RD & op3=0x0e & ea { *ea = RD; }
:std RD,ea is op=3 & RD & op3=0x07 & ea { *ea = RD; }
@else
# size = 4, but this extended store instruction needs to write 8 bytes
:stx RD,ea is op=3 & RD & rd_d & op3=0x0e & ea { *ea = rd_d; }
:std RD,ea is op=3 & RD & rd_d & op3=0x07 & ea { *ea = rd_d; }
@endif
:clrx ea is op=3 & rd=0 & op3=0x0e & ea { *ea = 0:8; }
:clrd ea is op=3 & rd=0 & op3=0x07 & ea { *ea = 0:8; }
:stba RD,ea_alt is op=3 & RD & op3=0x15 & ea_alt { *ea_alt = RD:1; }
:stha RD,ea_alt is op=3 & RD & op3=0x16 & ea_alt { *ea_alt = RD:2; }
:stwa RD,ea_alt is op=3 & RD & op3=0x14 & ea_alt { *ea_alt = RD:4; }
:stxa RD,ea_alt is op=3 & RD & op3=0x1e & ea_alt { *ea_alt = RD; }
:stda RD,ea_alt is op=3 & RD & op3=0x17 & ea_alt { *ea_alt = RD; }
# ---------------
:sub RS1,regorimm,rd is op=2 & rd & op3=0x4 & RS1 & regorimm {rd = RS1 - regorimm;}
:subcc RS1,regorimm,rd is op=2 & rd & op3=0x14 & RS1 & regorimm {subflags(RS1,regorimm);
rd = RS1 - regorimm;
zeroflags(rd);
}
:subc RS1,regorimm,rd is op=2 & rd & op3=0xc & RS1 & regorimm {rd = RS1 - regorimm - zext(i_cf);}
:subccc RS1,regorimm,rd is op=2 & rd & op3=0x1c & RS1 & regorimm {subflags(RS1,regorimm);
rd = RS1 - regorimm - zext(i_cf);
zeroflags(rd);
}
# ---------------
:nop is op=0x0 & rd=0x0 & op2=0x4 & disp22=0x0 { }
# ---------------COMPARES
:cmp RS1,regorimm is op=0x2 & rd=0x0 & op3=0x14 & RS1 & regorimm {subflags(RS1,regorimm);
local tmp = RS1 - regorimm;
zeroflags(tmp);
}
# ---------------MOVES
:mov regorimm,rd is op=2 & rd & op3=0x2 & rs1=0 & regorimm {rd = regorimm;}
# This will not work until the rs1 field in a token can be used without being
# part of the display portion below
RCOND: "z" is rcond3=1 & RS1 { tmp:1 = (RS1 == 0); export tmp; }
RCOND: "lez" is rcond3=2 & RS1 { tmp:1 = (RS1 s<= 0); export tmp; }
RCOND: "lz" is rcond3=3 & RS1 { tmp:1 = (RS1 s< 0); export tmp; }
RCOND: "nz" is rcond3=5 & RS1 { tmp:1 = (RS1 != 0); export tmp; }
RCOND: "gz" is rcond3=6 & RS1 { tmp:1 = (RS1 s> 0); export tmp; }
RCOND: "gez" is rcond3=7 & RS1 { tmp:1 = (RS1 s>= 0); export tmp; }
:movr^RCOND RS1,regorimm10,rd is op=0x2 & rd & op3=0x2f & RCOND & regorimm10 & RS1 {
if !RCOND goto <movrend>;
rd = regorimm10;
<movrend>
}
#:movrz RS1,regorimm10,rd is op=0x2 & rd & op3=0x2f & RS1 & rcond3=1 & regorimm10 { if (RS1 == 0) goto inst_next; rd = regorimm10; }
#:movrlez RS1,regorimm10,rd is op=0x2 & rd & op3=0x2f & RS1 & rcond3=2 & regorimm10 { if (RS1 s<= 0) goto inst_next; rd = regorimm10; }
#:movrlz RS1,regorimm10,rd is op=0x2 & rd & op3=0x2f & RS1 & rcond3=3 & regorimm10 { if (RS1 s< 0) goto inst_next; rd = regorimm10; }
#:movrnz RS1,regorimm10,rd is op=0x2 & rd & op3=0x2f & RS1 & rcond3=5 & regorimm10 { if (RS1 != 0) goto inst_next; rd = regorimm10; }
#:movrgz RS1,regorimm10,rd is op=0x2 & rd & op3=0x2f & RS1 & rcond3=6 & regorimm10 { if (RS1 s> 0) goto inst_next; rd = regorimm10; }
#:movrgez RS1,regorimm10,rd is op=0x2 & rd & op3=0x2f & RS1 & rcond3=7 & regorimm10 { if (RS1 s>= 0) goto inst_next; rd = regorimm10; }
m_icc: "a" is cond4=0x8 { tmp:1=1; export tmp; }
m_icc: "n" is cond4=0x0 { tmp:1=0; export tmp; }
m_icc: "ne" is cond4=0x9 { tmp:1=!i_zf; export tmp; }
m_icc: "e" is cond4=0x1 { tmp:1=i_zf; export tmp; }
m_icc: "g" is cond4=0xa { tmp:1=!(i_zf || (i_nf ^^ i_vf)); export tmp; }
m_icc: "le" is cond4=0x2 { tmp:1=(i_zf || (i_nf ^^ i_vf)); export tmp; }
m_icc: "ge" is cond4=0xb { tmp:1=!(i_nf ^^ i_vf); export tmp; }
m_icc: "l" is cond4=0x3 { tmp:1=(i_nf ^^ i_vf); export tmp; }
m_icc: "gu" is cond4=0xc { tmp:1=!(i_cf || i_zf); export tmp; }
m_icc: "leu" is cond4=0x4 { tmp:1=(i_cf || i_zf); export tmp; }
m_icc: "cc" is cond4=0xd { tmp:1=!(i_cf); export tmp; }
m_icc: "cs" is cond4=0x5 { export i_cf; }
m_icc: "pos" is cond4=0xe { tmp:1=!(i_nf); export tmp; }
m_icc: "neg" is cond4=0x6 { export i_nf; }
m_icc: "vc" is cond4=0xf { tmp:1=!(i_vf); export tmp; }
m_icc: "vs" is cond4=0x7 { export i_vf; }
m_xcc: "a" is cond4=0x8 { tmp:1=1; export tmp; }
m_xcc: "n" is cond4=0x0 { tmp:1=0; export tmp; }
m_xcc: "ne" is cond4=0x9 { tmp:1=!x_zf; export tmp; }
m_xcc: "e" is cond4=0x1 { tmp:1=x_zf; export tmp; }
m_xcc: "g" is cond4=0xa { tmp:1=!(x_zf || (x_nf ^^ x_vf)); export tmp; }
m_xcc: "le" is cond4=0x2 { tmp:1=(x_zf || (x_nf ^^ x_vf)); export tmp; }
m_xcc: "ge" is cond4=0xb { tmp:1=!(x_nf ^^ x_vf); export tmp; }
m_xcc: "l" is cond4=0x3 { tmp:1=(x_nf ^^ x_vf); export tmp; }
m_xcc: "gu" is cond4=0xc { tmp:1=!(x_cf || x_zf); export tmp; }
m_xcc: "leu" is cond4=0x4 { tmp:1=(x_cf || x_zf); export tmp; }
m_xcc: "cc" is cond4=0xd { tmp:1=!(x_cf); export tmp; }
m_xcc: "cs" is cond4=0x5 { export x_cf; }
m_xcc: "pos" is cond4=0xe { tmp:1=!(x_nf); export tmp; }
m_xcc: "neg" is cond4=0x6 { export x_nf; }
m_xcc: "vc" is cond4=0xf { tmp:1=!(x_vf); export tmp; }
m_xcc: "vs" is cond4=0x7 { export x_vf; }
m_cc:m_icc is cc2_4=1 & cc1_4=0 & cc0_4=0 & m_icc { export m_icc; }
m_cc:m_xcc is cc2_4=1 & cc1_4=1 & cc0_4=0 & m_xcc { export m_xcc; }
MICC: "%icc" is cc2_4=1 &cc1_4=0 { }
MICC: "%xcc" is cc2_4=1 &cc1_4=1 { }
:mov^m_cc MICC,regorimm11,rd is op=0x2 & rd & op3=0x2c & m_cc & MICC & regorimm11 {
if (!m_cc) goto <movend>;
rd = regorimm11;
<movend>
}
# ---------------BRANCHES
icc: "a" is cond=0x8 { tmp:1=1; export tmp; }
icc: "ne" is cond=0x9 { tmp:1=!i_zf; export tmp; }
icc: "e" is cond=0x1 { tmp:1=i_zf; export tmp; }
icc: "g" is cond=0xa { tmp:1=!(i_zf || (i_nf ^^ i_vf)); export tmp; }
icc: "le" is cond=0x2 { tmp:1=(i_zf || (i_nf ^^ i_vf)); export tmp; }
icc: "ge" is cond=0xb { tmp:1=!(i_nf ^^ i_vf); export tmp; }
icc: "l" is cond=0x3 { tmp:1=(i_nf ^^ i_vf); export tmp; }
icc: "gu" is cond=0xc { tmp:1=!(i_cf || i_zf); export tmp; }
icc: "leu" is cond=0x4 { tmp:1=(i_cf || i_zf); export tmp; }
icc: "cc" is cond=0xd { tmp:1=!(i_cf); export tmp; }
icc: "cs" is cond=0x5 { export i_cf; }
icc: "pos" is cond=0xe { tmp:1=!(i_nf); export tmp; }
icc: "neg" is cond=0x6 { export i_nf; }
icc: "vc" is cond=0xf { tmp:1=!(i_vf); export tmp; }
icc: "vs" is cond=0x7 { export i_vf; }
xcc: "a" is cond=0x8 { tmp:1=1; export tmp; }
xcc: "ne" is cond=0x9 { tmp:1=!x_zf; export tmp; }
xcc: "e" is cond=0x1 { tmp:1=x_zf; export tmp; }
xcc: "g" is cond=0xa { tmp:1=!(x_zf || (x_nf ^^ x_vf)); export tmp; }
xcc: "le" is cond=0x2 { tmp:1=(x_zf || (x_nf ^^ x_vf)); export tmp; }
xcc: "ge" is cond=0xb { tmp:1=!(x_nf ^^ x_vf); export tmp; }
xcc: "l" is cond=0x3 { tmp:1=(x_nf ^^ x_vf); export tmp; }
xcc: "gu" is cond=0xc { tmp:1=!(x_cf || x_zf); export tmp; }
xcc: "leu" is cond=0x4 { tmp:1=(x_cf || x_zf); export tmp; }
xcc: "cc" is cond=0xd { tmp:1=!(x_cf); export tmp; }
xcc: "cs" is cond=0x5 { export x_cf; }
xcc: "pos" is cond=0xe { tmp:1=!(x_nf); export tmp; }
xcc: "neg" is cond=0x6 { export x_nf; }
xcc: "vc" is cond=0xf { tmp:1=!(x_vf); export tmp; }
xcc: "vs" is cond=0x7 { export x_vf; }
cc: icc is cc1=0 & cc0=0 & icc { export icc; }
cc: xcc is cc1=1 & cc0=0 & xcc { export xcc; }
d16off: reloc is d16hi & d16lo [reloc = inst_start+4*((d16hi<<14) | d16lo);] { export *:$(SIZE) reloc; }
predict: ",pt" is p=1 { }
predict: ",pn" is p=0 { }
:brz^predict RS1,d16off is op=0 & a=0 & bit28=0 & rcond2=0x1 & op2=0x3 & RS1 & d16off & predict { delayslot(1); if (RS1 == 0) goto d16off;}
:brlez^predict RS1,d16off is op=0 & a=0 & bit28=0 & rcond2=0x2 & op2=0x3 & RS1 & d16off & predict { delayslot(1); if (RS1 s<= 0) goto d16off;}
:brlz^predict RS1,d16off is op=0 & a=0 & bit28=0 & rcond2=0x3 & op2=0x3 & RS1 & d16off & predict { delayslot(1); if (RS1 s< 0) goto d16off;}
:brnz^predict RS1,d16off is op=0 & a=0 & bit28=0 & rcond2=0x5 & op2=0x3 & RS1 & d16off & predict { delayslot(1); if (RS1 != 0) goto d16off;}
:brgz^predict RS1,d16off is op=0 & a=0 & bit28=0 & rcond2=0x6 & op2=0x3 & RS1 & d16off & predict { delayslot(1); if (RS1 s> 0) goto d16off;}
:brgez^predict RS1,d16off is op=0 & a=0 & bit28=0 & rcond2=0x7 & op2=0x3 & RS1 & d16off & predict { delayslot(1); if (RS1 s>= 0) goto d16off;}
:brz^",a"^predict RS1,d16off is op=0 & a=1 & bit28=0 & rcond2=0x1 & op2=0x3 & RS1 & d16off & predict { if (RS1 != 0) goto inst_next; delayslot(1); goto d16off;}
:brlez^",a"^predict RS1,d16off is op=0 & a=1 & bit28=0 & rcond2=0x2 & op2=0x3 & RS1 & d16off & predict { if (RS1 s> 0) goto inst_next; delayslot(1); goto d16off;}
:brlz^",a"^predict RS1,d16off is op=0 & a=1 & bit28=0 & rcond2=0x3 & op2=0x3 & RS1 & d16off & predict { if (RS1 s>= 0) goto inst_next; delayslot(1); goto d16off;}
:brnz^",a"^predict RS1,d16off is op=0 & a=1 & bit28=0 & rcond2=0x5 & op2=0x3 & RS1 & d16off & predict { if (RS1 == 0) goto inst_next; delayslot(1); goto d16off;}
:brgz^",a"^predict RS1,d16off is op=0 & a=1 & bit28=0 & rcond2=0x6 & op2=0x3 & RS1 & d16off & predict { if (RS1 s<= 0) goto inst_next; delayslot(1); goto d16off;}
:brgez^",a"^predict RS1,d16off is op=0 & a=1 & bit28=0 & rcond2=0x7 & op2=0x3 & RS1 & d16off & predict { if (RS1 s< 0) goto inst_next; delayslot(1); goto d16off;}
BCC: "%icc" is cc0=0 & cc1=0 { }
BCC: "%xcc" is cc0=0 & cc1=1 { }
reloff: reloc is disp22 [reloc=inst_start+(4*disp22);] { export *:$(SIZE) reloc; }
reloff64: reloc is disp19 [reloc=inst_start+(4*disp19);] { export *:$(SIZE) reloc; }
skip: reloc is epsilon [reloc=inst_start+8;] { export *:$(SIZE) reloc; }
:ba reloff is op=0x0 & op2=0x2 & a=0x0 & cond=0x8 & reloff { delayslot(1); goto reloff; }
:"ba,a" reloff is op=0x0 & op2=0x2 & a=0x1 & cond=0x8 & reloff { goto reloff; }
:bn reloff is op=0x0 & op2=0x2 & a=0x0 & cond=0x0 & reloff { }
:"bn,a" reloff,skip is op=0x0 & op2=0x2 & a=0x1 & cond=0x0 & reloff & skip { goto skip; }
:b^icc reloff is op=0x0 & op2=0x2 & a=0x0 & icc & reloff { delayslot(1); if (icc) goto reloff; }
:b^icc^",a" reloff is op=0x0 & op2=0x2 & a=0x1 & icc & reloff { if (!icc) goto inst_next; delayslot(1); goto reloff; }
:bpa^predict reloff64 is op=0x0 & op2=0x1 & a=0x0 & cond=0x8 & reloff64 & predict { delayslot(1); goto reloff64; }
:"bpa,a"^predict reloff64 is op=0x0 & op2=0x1 & a=0x1 & cond=0x8 & reloff64 & predict { goto reloff64; }
:bpn^predict reloff64 is op=0x0 & op2=0x1 & a=0x0 & cond=0x0 & reloff64 & predict { }
:"bpn,a"^predict reloff64,skip is op=0x0 & op2=0x1 & a=0x1 & cond=0x0 & reloff64 & predict & skip { goto skip; }
:bp^cc^predict BCC,reloff64 is op=0x0 & op2=0x1 & a=0x0 & cond & cc & reloff64 & predict & BCC { delayslot(1); if (cc) goto reloff64; }
:bp^cc^",a"^predict BCC,reloff64 is op=0x0 & op2=0x1 & a=0x1 & cond & cc & reloff64 & predict & BCC { if (!cc) goto inst_next; delayslot(1); goto reloff64; }
#:br^cc^predict reloff64 is op=0x0 & a=0x0 & op2=0x3 & cc & reloff64 & predict { delayslot(1); if (cc) goto reloff64; }
#:br^cc^",a"^predict reloff64 is op=0x0 & a=0x1 & op2=0x3 & cc & reloff64 & predict { if (!cc) goto inst_next; delayslot(1); goto reloff64; }
#---------------CALL
callreloff: reloc is disp30 [reloc=inst_start+4*disp30;] { export *:$(SIZE) reloc; }
:call callreloff is op=0x1 & callreloff {
o7=inst_start; didrestore=0; delayslot(1); call callreloff; if (didrestore==0) goto inst_next; return [o7];
}
# changing to jump for PIC call if destination is right below this one.
:call callreloff is op=0x1 & disp30=2 & callreloff {
o7=inst_start; delayslot(1); goto callreloff;
}
#----------------RET
#----------------MULTIPLY AND DIVIDE 64 bit
:mulx RS1,regorimm,rd is op=2 & rd & op3=0x09 & RS1 & regorimm {rd = RS1 * regorimm;}
:sdivx RS1,regorimm,rd is op=2 & rd & op3=0x2d & RS1 & regorimm {rd = RS1 s/ regorimm;}
:udivx RS1,regorimm,rd is op=2 & rd & op3=0x0d & RS1 & regorimm {rd = RS1 / regorimm;}
#----------------MULTIPLY 32 bit
@if SIZE=="8"
:umul RS1,regorimm,rd is op=2 & rd & op3=0x0a & RS1 & regorimm {rd = zext(RS1:4) * zext(regorimm:4); Y=rd>>32;}
:smul RS1,regorimm,rd is op=2 & rd & op3=0x0b & RS1 & regorimm {rd = zext(RS1:4) * zext(regorimm:4); Y=rd>>32;}
:umulcc RS1,regorimm,rd is op=2 & rd & op3=0x1a & RS1 & regorimm {rd = zext(RS1:4) * zext(regorimm:4); Y=rd>>32; zeroflags(rd); logicflags();}
:smulcc RS1,regorimm,rd is op=2 & rd & op3=0x1b & RS1 & regorimm {rd = zext(RS1:4) * zext(regorimm:4); Y=rd>>32; zeroflags(rd); logicflags();}
@else
# size = 4
:umul RS1,regorimm,rd is op=2 & rd & op3=0x0a & RS1 & regorimm {
tmp_RS1:8 = zext(RS1); tmp_regorimm:8 = zext(regorimm);
tmp:8 = tmp_RS1 * tmp_regorimm; rd = tmp:4; tmp2:8 = tmp >> 32; Y = tmp2:4;
}
:smul RS1,regorimm,rd is op=2 & rd & op3=0x0b & RS1 & regorimm {
tmp_RS1:8 = sext(RS1); tmp_regorimm:8 = sext(regorimm);
tmp:8 = tmp_RS1 * tmp_regorimm; rd = tmp:4; tmp2:8 = tmp >> 32; Y = tmp2:4;
}
:umulcc RS1,regorimm,rd is op=2 & rd & op3=0x1a & RS1 & regorimm {rd = zext(RS1:4) * zext(regorimm:4); Y=rd>>32; zeroflags(rd); logicflags();}
:smulcc RS1,regorimm,rd is op=2 & rd & op3=0x1b & RS1 & regorimm {rd = zext(RS1:4) * zext(regorimm:4); Y=rd>>32; zeroflags(rd); logicflags();}
@endif
#----------------MULTIPLY Step
:mulscc RS1,regorimm,rd is op=2 & rd & op3=0x24 & RS1 & regorimm { tmp:4 = RS1:4 >> 1;
ccr:4 = zext(i_nf ^^ i_vf);
ccr = ccr << 31;
tmp = tmp | ccr;
multiplicand:4 = (Y:4 & 0x1) * regorimm:4;
addflags32(tmp, multiplicand);
tmp = tmp + multiplicand;
rd = zext(tmp);
zeroflags(rd);
local tbit = (RS1 & 0x1) << 31;
Y = (Y >> 1) | tbit;
}
#----------------DIVIDE (64-bit / 32-bit)
# NB- Beware, the plus + operator has higher precdence than shift <<
# (These are Java rules. C rules have shift and + at the same level, so left to right)
:udiv RS1,regorimm,rd is op=2 & rd & op3=0x0e & RS1 & regorimm {
numerator:$(SIZE)= (Y << 32) + (RS1 & 0xffffffff);
denom:$(SIZE) = regorimm & 0xffffffff;
rd = numerator / denom;
}
:sdiv RS1,regorimm,rd is op=2 & rd & op3=0x0f & RS1 & regorimm {
numerator:$(SIZE)= (Y << 32) + (RS1 & 0xffffffff);
denom:$(SIZE) = regorimm & 0xffffffff;
rd = numerator s/ denom;
}
:udivcc RS1,regorimm,rd is op=2 & rd & op3=0x1e & RS1 & regorimm {
numerator:$(SIZE)= ( Y << 32) + (RS1 & 0xffffffff);
denom:$(SIZE) = regorimm & 0xffffffff;
rd = numerator / denom;
zeroflags(rd);
i_vf = rd > 0xffffffff;
i_cf = 0;
x_vf = 0;
x_cf = 0;
}
:sdivcc RS1,regorimm,rd is op=2 & rd & op3=0x1f & RS1 & regorimm {
numerator:$(SIZE)= (Y << 32) + (RS1 & 0xffffffff);
denom:$(SIZE) = regorimm & 0xffffffff;
rd = numerator s/ denom;
zeroflags(rd);
i_vf = (rd s>= 0x80000000) || (rd s<= -0x7ffffffff);
i_cf = 0;
x_vf = 0;
x_cf = 0;
}
#---------------SHIFT
:sll RS1,reg_or_shcnt,rd is op=0x2 & rd & op3=0x25 & x=0 & RS1 & reg_or_shcnt { rd=RS1<<reg_or_shcnt; }
:srl RS1,reg_or_shcnt,rd is op=0x2 & rd & op3=0x26 & x=0 & RS1 & reg_or_shcnt { tmp:$(SIZE)=zext(RS1:4); rd=tmp>>reg_or_shcnt; }
:sllx RS1,reg_or_shcnt,rd is op=0x2 & rd & op3=0x25 & x=1 & RS1 & reg_or_shcnt { rd=RS1<<reg_or_shcnt; }
:srlx RS1,reg_or_shcnt,rd is op=0x2 & rd & op3=0x26 & x=1 & RS1 & reg_or_shcnt { rd=RS1>>reg_or_shcnt; }
:sra RS1,reg_or_shcnt,rd is op=0x2 & rd & op3=0x27 & x=0 & RS1 & reg_or_shcnt { tmp:4=RS1:4; rd=sext(tmp s>> reg_or_shcnt); }
:srax RS1,reg_or_shcnt,rd is op=0x2 & rd & op3=0x27 & x=1 & RS1 & reg_or_shcnt { rd=RS1 s>> reg_or_shcnt; }
rreg: "%ASI" is rs1_3=3 & i=0 { tmp:$(SIZE) = zext(ASI); export tmp; }
rreg: "%fprs" is rs1_3=6 & i=0 { tmp:$(SIZE) = zext(fprs); export tmp; }
rreg: "%ccr" is rs1_3=2 & i=0 { tmp:$(SIZE) = zext(CCR); export tmp; }
rreg: PC is rs1_3=5 & PC & i=0 { export inst_start; }
rreg: rs1_3 is rs1_3 & i=0 { export rs1_3; }
#---------------RD special register
:rd rreg,rd is op=0x2 & rd & op3=0x28 & rreg & i=0 { rd = rreg; }
:rd rreg,rd is op=0x2 & rd & op3=0x28 & rs1_3=2 & rreg & i=0 { packflags(rd); }
wrASI: "%ASI" is rd=3 { }
wrFPRS: "%fprs" is rd=6 { }
wrCCR: "%ccr" is rd=2 { }
#---------------WR special register
:wr regorimm,wrASI is op=0x2 & regorimm & op3=0x30 & rd=3 & wrASI { ASI = regorimm:1; }
:wr regorimm,wrFPRS is op=0x2 & regorimm & op3=0x30 & rd=6 & wrFPRS { fprs = regorimm:1; }
:wr regorimm,wrCCR is op=0x2 & regorimm & op3=0x30 & rd=2 & wrCCR { unpackflags(regorimm); }
:wr regorimm,rd is op=0x2 & regorimm & op3=0x30 & rd { rd = regorimm; }
#---------------MISC
sethidisp: "%hi("^hi^")" is udisp22 [hi=udisp22<<10;] { export *[const]:$(SIZE) hi; }
:sethi sethidisp,rd is rd & op=0x0 & op2=0x4 & sethidisp { rd=sethidisp; }
:popc regorimm, rd is op=0x2 & rd & op3=0x2e & rs1=0 & regorimm { rd = popc(regorimm); }
:save RS1,regorimm,rd is op=0x2 & rd & op3=0x3c & RS1 & regorimm { local tmp = RS1 + regorimm; save(); rd = tmp; }
:restore RS1,regorimm,rd is op=0x2 & rd & op3=0x3d & RS1 & regorimm { local tmp = RS1 + regorimm; restore(); didrestore=1; rd = tmp; }
:restore is op=0x2 & rd=0 & op3=0x3d { restore(); didrestore=1; }
:return retea is op=0x2 & op3=0x39 & retea { restore(); delayslot(1); didrestore=1; return [retea]; }
jmplreloff: reloc is rd [reloc=inst_start+8;] { export reloc; }
:jmpl retea,rd is op=0x2 & rd & op3=0x38 & retea & jmplreloff { rd = inst_start; delayslot(1); goto [retea]; }
# special case where link register is loaded with return address
:jmpl retea,rd is op=0x2 & rd & prd=15 & op3=0x38 & retea & jmplreloff { rd = inst_start; delayslot(1); call [retea]; }
:jmpl retea is op=0x2 & rd=0 & op3=0x38 & retea { o7=inst_start; delayslot(1); goto [retea]; }
:ret is op=0x2 & rd=0 & rs1=31 & op3=0x38 & i=1 & simm13=8 & retea { delayslot(1); return [retea]; }
:retl is op=0x2 & rd=0 & rs1=15 & op3=0x38 & i=1 & simm13=8 & retea { delayslot(1); return [retea]; }
casa_ea: [RS1]imm_asi is i=0 & RS1 & imm_asi { local tmp1:1 = imm_asi; local tmp = RS1+segment(tmp1); export tmp; }
casa_ea: [RS1]%ASI is i=1 & RS1 & ASI { local tmp = RS1+segment(ASI); export tmp; }
:casa casa_ea,RS2,rd is op=0x3 & rd & op3=0x3c & casa_ea & RS2 { local tmp:4=rd:4; rd=zext(*:4 casa_ea); if ((RS2 & 0xFFFFFFFF)!=rd) goto <end>; *:4 casa_ea=tmp; <end> }
:casxa casa_ea,RS2,rd is op=0x3 & rd & op3=0x3e & casa_ea & RS2 { local tmp=rd; rd=*:$(SIZE) casa_ea; if (RS2!=rd) goto <end>; *:$(SIZE) casa_ea=tmp; <end> }
:impdef1 is op=0x2 & op3=0x36 unimpl
:impdef2 is op=0x2 & op3=0x37 unimpl
:ldstub ea,rd is op=0x3 & rd & op3=0xd & ea { rd = zext(*:1 ea); *:1 ea = 0xFF; }
:ldstuba ea_alt,rd is op=0x3 & rd & op3=0x1d & ea_alt { rd = zext(*:1 ea_alt); *:1 ea_alt = 0xFF; }
:swap ea,rd is op=0x3 & rd & op3=0xF & ea { tmp:4=rd:4; rd = zext(*:4 ea); *:4 ea = tmp; }
:swapa ea_alt,rd is op=0x3 & rd & op3=0x1F & ea_alt { tmp:4=rd:4; rd = zext(*:4 ea_alt); *:4 ea_alt = tmp; }
:taddcc RS1,regorimm,rd is op=2 & rd & op3=0x20 & RS1 & regorimm {taddflags(RS1,regorimm);
rd = RS1 + regorimm;
zeroflags(rd);
}
:taddcctv RS1,regorimm,rd is op=2 & rd & op3=0x22 & RS1 & regorimm {taddflags(RS1,regorimm);
rd = RS1 + regorimm;
zeroflags(rd);
}
:tsubcc RS1,regorimm,rd is op=2 & rd & op3=0x21 & RS1 & regorimm {taddflags(RS1,regorimm);
rd = RS1 - regorimm;
zeroflags(rd);
}
:tsubcctv RS1,regorimm,rd is op=2 & rd & op3=0x23 & RS1 & regorimm {taddflags(RS1,regorimm);
rd = RS1 - regorimm;
zeroflags(rd);
}
tcc: icc is cc1_4=0 & cc0_4=0 & icc { export icc; }
tcc: xcc is cc1_4=1 & cc0_4=0 & xcc { export xcc; }
TICC: "%icc" is cc1_4=0 &cc0_4=0 { }
TICC: "%xcc" is cc1_4=1 &cc0_4=0 { }
trap: RS1+RS2 is i=0 & RS1 & RS2 { local tmp = ((RS1 + RS2) & 0x7F); export tmp; }
trap: RS1+swtrap is i=1 & RS1 & swtrap { local tmp = ((RS1 + swtrap) & 0x7F); export tmp; }
:t^tcc TICC, trap is op=0x2 & op3=0x3a & tcc & TICC & trap { sw_trap(trap); }
membar_mask: is cmask & mmask { tmp:1 = (cmask << 4) | mmask; export tmp; }
:membar membar_mask is op=0x2 & rd=0 & op3=0x28 & rs1=0xF & i=1 & membar_mask {}
:stbar is op=0x2 & rd=0 & op3=0x28 & rs1=0xF & i=0 {}
:sir simm13 is op=0x2 & rd=0xF & op3=0x30 & rs1=0x0 & i=1 & simm13 { reset(); }
attach variables [ prs1 prd ] [ TPC1 TNPC1 TSTATE1 TT1 TCK TBA PSTATE TL
PIL CWP CANSAVE CANRESTORE CLEANWIN OTHERWIN WSTATE FQ
GL _ _ _ _ _ _ _ _ _ _ _ _ _ _ VER ];
tnpc: "%tnpc" is fcn { local reloc = zext(TL == 1)*&TNPC1 + zext(TL == 2)*&TNPC2 + zext(TL == 3)*&TNPC3 + zext(TL ==4)*&TNPC4; export reloc; }
tpc: "%tpc" is fcn { local reloc = zext(TL == 1)*&TPC1 + zext(TL == 2)*&TPC2 + zext(TL == 3)*&TPC3 + zext(TL ==4)*&TPC4; export reloc; }
tt: "%tt" is fcn { local tmp = zext(TL == 1)* &TT1 + zext(TL == 2)*&TT2 + zext(TL == 3)*&TT3 + zext(TL ==4)*&TT4; export tmp; }
tstate: "%tstate" is fcn { local tmp = zext(TL == 1)* &TSTATE1 + zext(TL == 2)* &TSTATE2 + zext(TL == 3)* &TSTATE3 + zext(TL==4)* &TSTATE4; export tmp; }
# prs1 is same bits as rs1
# prd is same bits as rd
:rdpr prs1,rd is op=0x2 & rd & op3=0x2A & prs1 {rd = prs1; }
:rdpr tpc,rd is op=0x2 & prs1 = 0 & rd & op3=0x2A & tpc { rd = *[register]:$(SIZE) tpc; }
:rdpr tnpc,rd is op=0x2 & prs1 = 1 & rd & op3=0x2A & tnpc {rd = *[register]:$(SIZE) tnpc; }
:rdpr tt,rd is op=0x2 & prs1 = 2 & rd & op3=0x2A & tt { rd = *[register]:$(SIZE) tt; }
:rdpr tstate,rd is op=0x2 & prs1 = 3 & rd & op3=0x2A & tstate {rd = *[register]:$(SIZE) tstate;}
:wrpr RS1,regorimm,prd is op=0x2 & prd & op3=0x32 & RS1 & regorimm {prd = RS1^regorimm; }
:wrpr RS1,regorimm,tpc is op=0x2 & prd = 0 & op3=0x32 & RS1 & regorimm & tpc { *[register]:$(SIZE) tpc = RS1^regorimm; }
:wrpr RS1,regorimm,tnpc is op=0x2 & prd = 1 & op3=0x32 & RS1 & regorimm & tnpc { *[register]:$(SIZE) tnpc = RS1^regorimm; }
:wrpr RS1,regorimm,tstate is op=0x2 & prd = 2 & op3=0x32 & RS1 & regorimm & tstate { *[register]:$(SIZE) tstate = RS1^regorimm; }
:wrpr RS1,regorimm,tt is op=0x2 & prd = 3 & op3=0x32 & RS1 & regorimm & tt { *[register]:$(SIZE) tt = RS1^regorimm; }
hpstate: "%hpstate" is fcn { local reloc = zext(TL == 1)*&HPSTATE1 + zext(TL == 2)*&HPSTATE2 + zext(TL == 3)*&HPSTATE3 + zext(TL ==4)*&HPSTATE4; export reloc; }
htstate: "%htstate" is fcn { local reloc = zext(TL == 1)*&HTSTATE1 + zext(TL == 2)*&HTSTATE2 + zext(TL == 3)*&HTSTATE3 + zext(TL ==4)*&HTSTATE4; export reloc; }
hintp: "%hintp" is fcn { local reloc = zext(TL == 1)*&HINTP1 + zext(TL == 2)*&HINTP2 + zext(TL == 3)*&HINTP3 + zext(TL ==4)*&HINTP4; export reloc; }
htba: "%htba" is fcn { local reloc = zext(TL == 1)*&HTBA1 + zext(TL == 2)*&HTBA2 + zext(TL == 3)*&HTBA3 + zext(TL ==4)*&HTBA4; export reloc; }
hver: "%hver" is fcn { local reloc = zext(TL == 1)*&HVER1 + zext(TL == 2)*&HVER2 + zext(TL == 3)*&HVER3 + zext(TL ==4)*&HVER4; export reloc; }
hsys_tick_cmpr: "%hstick_cmpr" is fcn { local reloc = zext(TL == 1)*&HSTICK_CMPR1 + zext(TL == 2)*&HSTICK_CMPR2 + zext(TL == 3)*&HSTICK_CMPR3 + zext(TL ==4)*&HSTICK_CMPR4; export reloc; }
resv30: "%resv30" is fcn { local reloc = zext(TL == 1)*&RESV30_1 + zext(TL == 2)*&RESV30_2 + zext(TL == 3)*&RESV30_3 + zext(TL ==4)*&RESV30_4; export reloc; }
:rdhpr hpstate,rd is op=0x2 & prs1 = 0 & rd & op3=0x29 & hpstate { rd = *[register]:$(SIZE) hpstate; }
:rdhpr htstate,rd is op=0x2 & prs1 = 1 & rd & op3=0x29 & htstate { rd = *[register]:$(SIZE) htstate; }
:rdhpr hintp,rd is op=0x2 & prs1 = 3 & rd & op3=0x29 & hintp { rd = *[register]:$(SIZE) hintp; }
:rdhpr htba,rd is op=0x2 & prs1 = 5 & rd & op3=0x29 & htba { rd = *[register]:$(SIZE) htba; }
:rdhpr hver,rd is op=0x2 & prs1 = 6 & rd & op3=0x29 & hver { rd = *[register]:$(SIZE) hver; }
:rdhpr hsys_tick_cmpr,rd is op=0x2 & prs1 = 31 & rd & op3=0x29 & hsys_tick_cmpr { rd = *[register]:$(SIZE) hsys_tick_cmpr; }
:rdhpr resv30,rd is op=0x2 & prs1 = 30 & rd & op3=0x29 & resv30 { rd = *[register]:$(SIZE) resv30; }
:wrhpr RS1,regorimm,hpstate is op=0x2 & prd = 0 & op3=0x33 & RS1 & regorimm & hpstate { *[register]:$(SIZE) hpstate = RS1^regorimm; }
:wrhpr RS1,regorimm,htstate is op=0x2 & prd = 1 & op3=0x33 & RS1 & regorimm & htstate { *[register]:$(SIZE) htstate = RS1^regorimm; }
:wrhpr RS1,regorimm,hintp is op=0x2 & prd = 3 & op3=0x33 & RS1 & regorimm & hintp { *[register]:$(SIZE) hintp = RS1^regorimm; }
:wrhpr RS1,regorimm,htba is op=0x2 & prd = 5 & op3=0x33 & RS1 & regorimm & htba { *[register]:$(SIZE) htba = RS1^regorimm; }
:wrhpr RS1,regorimm,hsys_tick_cmpr is op=0x2 & prd = 31 & op3=0x33 & RS1 & regorimm & hsys_tick_cmpr { *[register]:$(SIZE) hsys_tick_cmpr = RS1^regorimm; }
:wrhpr RS1,regorimm,resv30 is op=0x2 & prd = 30 & op3=0x33 & RS1 & regorimm & resv30 { *[register]:$(SIZE) resv30 = RS1^regorimm; }
:done is op = 2 & fcn = 0 & op3 = 0x3e & tnpc {TL=TL-1;return [tnpc]; }
:retry is op = 2 & fcn = 1 & op3 = 0x3e & tpc {TL=TL-1;return [tpc]; }
:flush ea is op = 2 & op3 = 0x3b & ea {}
:flushw is op = 2 & op3 = 0x2b & i = 0 {}
define pcodeop IllegalInstructionTrap;
:illtrap const22 is op = 0 & op3 = 0 & const22 {
IllegalInstructionTrap(const22:4);
tmp:$(SIZE) = 0; # trap - don't fall-thru
return [ tmp ];
}
:prefetch ea,fcn is op=3 & fcn & op3 = 0x2d & ea {}
:prefetcha ea_alt,fcn is op=3 & fcn & op3 = 0x3d & ea_alt {}
:restored is op = 2 & fcn=1 & op3 = 0x31 {}
:saved is op = 2 & fcn = 0 & op3 = 0x31 {}
attach variables [fsrd fsrs1 fsrs2 ] [ fs0 fs1 fs2 fs3 fs4 fs5 fs6 fs7
fs8 fs9 fs10 fs11 fs12 fs13 fs14 fs15
fs16 fs17 fs18 fs19 fs20 fs21 fs22 fs23
fs24 fs25 fs26 fs27 fs28 fs29 fs30 fs31 ];
attach variables [fdrd fdrs1 fdrs2 ] [ fd0 fd32 fd2 fd34 fd4 fd36 fd6 fd38
fd8 fd40 fd10 fd42 fd12 fd44 fd14 fd46
fd16 fd48 fd18 fd50 fd20 fd52 fd22 fd54
fd24 fd56 fd26 fd58 fd28 fd60 fd30 fd62 ];
attach variables [fqrd fqrs1 fqrs2 ] [ fq0 _ fq32 _ fq4 _ fq36 _ fq8 _ fq40 _ fq12 _ fq44
_ fq16 _ fq48 _ fq20 _ fq52 _ fq24 _ fq56 _ fq28 _ fq60 _];
define pcodeop ld;
define pcodeop ldd;
define pcodeop ldq;
define pcodeop ldx;
define pcodeop lda;
define pcodeop ldda;
define pcodeop ldqa;
define pcodeop ld_fsr;
define pcodeop ldx_fsr;
define pcodeop st;
define pcodeop std;
define pcodeop stq;
define pcodeop stx;
define pcodeop st_fsr;
define pcodeop stx_fsr;
define pcodeop sta;
define pcodeop stda;
define pcodeop stqa;
:fabss fsrs2,fsrd is op=0x2 & fsrd & op3=0x34 & opf=0x9 & fsrs2 { fsrd = abs(fsrs2); }
:fabsd fdrs2,fdrd is op=0x2 & fdrd & op3=0x34 & opf=0xa & fdrs2 { fdrd = abs(fdrs2); }
:fabsq fqrs2,fqrd is op=0x2 & fqrd & op3=0x34 & opf=0xb & fqrs2 { fqrd = abs(fqrs2); }
:fadds fsrs1,fsrs2,fsrd is op=0x2 & fsrd & op3=0x34 & fsrs1 & opf=0x41 & fsrs2 { fsrd = fsrs1 f+ fsrs2; }
:faddd fdrs1,fdrs2,fdrd is op=0x2 & fdrd & op3=0x34 & fdrs1 & opf=0x42 & fdrs2 { fdrd = fdrs1 f+ fdrs2; }
:faddq fqrs1,fqrs2,fqrd is op=0x2 & fqrd & op3=0x34 & fqrs1 & opf=0x43 & fqrs2 { fqrd = fqrs1 f+ fqrs2; }
:fdivs fsrs1,fsrs2,fsrd is op=0x2 & fsrd & op3=0x34 & fsrs1 & opf=0x4d & fsrs2 { fsrd = fsrs1 f/ fsrs2; }
:fdivd fdrs1,fdrs2,fdrd is op=0x2 & fdrd & op3=0x34 & fdrs1 & opf=0x4e & fdrs2 { fdrd = fdrs1 f/ fdrs2; }
:fdivq fqrs1,fqrs2,fqrd is op=0x2 & fqrd & op3=0x34 & fqrs1 & opf=0x4f & fqrs2 { fqrd = fqrs1 f/ fqrs2; }
:fdmulq fdrs1,fdrs2,fqrd is op=0x2 & fqrd & op3=0x34 & fdrs1 & opf=0x6e & fdrs2 {
tmp1:16 = float2float(fdrs1);
tmp2:16 = float2float(fdrs2);
fqrd = tmp1 f* tmp2;
}
:fsmuld fsrs1,fsrs2,fdrd is op=0x2 & fdrd & op3=0x34 & fsrs1 & opf=0x69 & fsrs2 {
tmp1:8 = float2float(fsrs1);
tmp2:8 = float2float(fsrs2);
fdrd = tmp1 f* tmp2;
}
:fitos fsrs2,fsrd is op=0x2 & fsrd & op3=0x34 & opf=0xc4 & fsrs2 { fsrd = int2float(fsrs2); }
:fitod fsrs2,fdrd is op=0x2 & fdrd & op3=0x34 & opf=0xc8 & fsrs2 { fdrd = int2float(fsrs2); }
:fitoq fsrs2,fqrd is op=0x2 & fqrd & op3=0x34 & opf=0xcc & fsrs2 { fqrd = int2float(fsrs2); }
:fmovs fsrs2,fsrd is op=0x2 & fsrd & op3=0x34 & opf=0x1 & fsrs2 { fsrd = fsrs2; }
:fmovd fdrs2,fdrd is op=0x2 & fdrd & op3=0x34 & opf=0x2 & fdrs2 { fdrd = fdrs2; }
:fmovq fqrs2,fqrd is op=0x2 & fqrd & op3=0x34 & opf=0x3 & fqrs2 { fqrd = fqrs2; }
:fmuls fsrs1,fsrs2,fsrd is op=0x2 & fsrd & op3=0x34 & fsrs1 & opf=0x49 & fsrs2 { fsrd = fsrs1 f* fsrs2; }
:fmuld fdrs1,fdrs2,fdrd is op=0x2 & fdrd & op3=0x34 & fdrs1 & opf=0x4a & fdrs2 { fdrd = fdrs1 f* fdrs2; }
:fmulq fqrs1,fqrs2,fqrd is op=0x2 & fqrd & op3=0x34 & fqrs1 & opf=0x4b & fqrs2 { fqrd = fqrs1 f* fqrs2; }
:fnegs fsrs2,fsrd is op=0x2 & fsrd & op3=0x34 & opf=0x5 & fsrs2 { fsrd = f- fsrs2; }
:fnegd fdrs2,fdrd is op=0x2 & fdrd & op3=0x34 & opf=0x6 & fdrs2 { fdrd = f- fdrs2; }
:fnegq fqrs2,fqrd is op=0x2 & fqrd & op3=0x34 & opf=0x7 & fqrs2 { fqrd = f- fqrs2; }
:fsubs fsrs1,fsrs2,fsrd is op=0x2 & fsrd & op3=0x34 & fsrs1 & opf=0x45 & fsrs2 { fsrd = fsrs1 f- fsrs2; }
:fsubd fdrs1,fdrs2,fdrd is op=0x2 & fdrd & op3=0x34 & fdrs1 & opf=0x46 & fdrs2 { fdrd = fdrs1 f- fdrs2; }
:fsubq fqrs1,fqrs2,fqrd is op=0x2 & fqrd & op3=0x34 & fqrs1 & opf=0x47 & fqrs2 { fqrd = fqrs1 f- fqrs2; }
:fxtos fdrs2,fsrd is op=0x2 & fsrd & op3=0x34 & opf=0x84 & fdrs2 { fsrd = int2float(fdrs2); }
:fxtod fdrs2,fdrd is op=0x2 & fdrd & op3=0x34 & opf=0x88 & fdrs2 { fdrd = int2float(fdrs2); }
:fxtoq fdrs2,fqrd is op=0x2 & fqrd & op3=0x34 & opf=0x8c & fdrs2 { fqrd = int2float(fdrs2); }
:fstoi fsrs2,fsrd is op=0x2 & fsrd & op3=0x34 & opf=0xd1 & fsrs2 { fsrd = trunc(fsrs2); }
:fdtoi fdrs2,fdrd is op=0x2 & fdrd & op3=0x34 & opf=0xd2 & fdrs2 { fdrd = trunc(fdrs2); }
:fqtoi fqrs2,fqrd is op=0x2 & fqrd & op3=0x34 & opf=0xd3 & fqrs2 { fqrd = trunc(fqrs2); }
:fstox fsrs2,fsrd is op=0x2 & fsrd & op3=0x34 & opf=0x81 & fsrs2 { fsrd = trunc(fsrs2); }
:fdtox fdrs2,fdrd is op=0x2 & fdrd & op3=0x34 & opf=0x82 & fdrs2 { fdrd = trunc(fdrs2); }
:fqtox fqrs2,fqrd is op=0x2 & fqrd & op3=0x34 & opf=0x83 & fqrs2 { fqrd = trunc(fqrs2); }
:fstod fsrs2,fdrd is op=0x2 & fdrd & op3=0x34 & opf=0xc9 & fsrs2 { fdrd = float2float(fsrs2); }
:fstoq fsrs2,fqrd is op=0x2 & fqrd & op3=0x34 & opf=0xcd & fsrs2 { fqrd = float2float(fsrs2); }
:fdtos fdrs2,fsrd is op=0x2 & fsrd & op3=0x34 & opf=0xc6 & fdrs2 { fsrd = float2float(fdrs2); }
:fdtoq fdrs2,fqrd is op=0x2 & fqrd & op3=0x34 & opf=0xce & fdrs2 { fqrd = float2float(fdrs2); }
:fqtos fdrs2,fsrd is op=0x2 & fsrd & op3=0x34 & opf=0xc7 & fdrs2 { fsrd = float2float(fdrs2); }
:fqtod fqrs2,fdrd is op=0x2 & fdrd & op3=0x34 & opf=0xcb & fqrs2 { fdrd = float2float(fqrs2); }
:fsqrts fsrs2,fsrd is op=0x2 & fsrd & op3=0x34 & opf=0x29 & fsrs2 { fsrd = sqrt(fsrs2); }
:fsqrtd fdrs2,fdrd is op=0x2 & fdrd & op3=0x34 & opf=0x2a & fdrs2 { fdrd = sqrt(fdrs2); }
:fsqrtq fqrs2,fqrd is op=0x2 & fqrd & op3=0x34 & opf=0x2b & fqrs2 { fqrd = sqrt(fqrs2); }
:ld ea,fsrd is op=3 & fsrd & op3=0x20 & ea { fsrd = *:4 ea; }
:ldd ea,fdrd is op=3 & fdrd & op3=0x23 & ea { fdrd = *:8 ea; }
:ldq ea,fqrd is op=3 & fqrd & op3=0x22 & ea { fqrd = *:16 ea; }
:ld ea,"%fsr" is op=3 & op3=0x21 & rd=0 & ea { fsr = *:2 ea; }
:ldx ea,"%fsr" is op=3 & op3=0x21 & rd=1 & ea { fsr = *:2 ea; }
:lda ea_alt,fsrd is op=3 & fsrd & op3=0x30 & ea_alt { fsrd = *:4 ea_alt; }
:ldda ea_alt,fdrd is op=3 & fdrd & op3=0x33 & ea_alt { fdrd = *:8 ea_alt; }
:ldqa ea_alt,fqrd is op=3 & fqrd & op3=0x32 & ea_alt { fqrd = *:16 ea_alt; }
:st fsrd,ea is op=3 & fsrd & op3=0x24 & ea { *ea = fsrd:4; }
:std fdrd,ea is op=3 & fdrd & op3=0x27 & ea { *ea = fdrd:8; }
:stq fqrd,ea is op=3 & fqrd & op3=0x26 & ea { *ea = fqrd:16; }
:st "%fsr",ea is op=3 & op3=0x25 & rd=0 & ea { *ea = fsr; }
:stx "%fsr",ea is op=3 & op3=0x25 & rd=1 & ea { *ea = fsr; }
:sta fsrd,ea_alt is op=3 & fsrd & op3=0x34 & ea_alt { *ea_alt = fsrd:4; }
:stda fdrd,ea_alt is op=3 & fdrd & op3=0x37 & ea_alt { *ea_alt = fdrd:8; }
:stqa fqrd,ea_alt is op=3 & fqrd & op3=0x36 & ea_alt { *ea_alt = fqrd:16; }
fcc0_or_fccn: is op2=6 { export fcc0; }
fcc0_or_fccn: is op2=5 & fccn { export fccn; }
fcc: "u" is cond=0x7 & fcc0_or_fccn { tmp:1=(fcc0_or_fccn == 3); export tmp; }
fcc: "g" is cond=0x6 & fcc0_or_fccn { tmp:1=(fcc0_or_fccn == 2); export tmp; }
fcc: "ug" is cond=0x5 & fcc0_or_fccn { tmp:1=(fcc0_or_fccn == 2 || fcc0_or_fccn == 3); export tmp; }
fcc: "l" is cond=0x4 & fcc0_or_fccn { tmp:1=(fcc0_or_fccn == 1); export tmp; }
fcc: "ul" is cond=0x3 & fcc0_or_fccn { tmp:1=(fcc0_or_fccn == 1 || fcc0_or_fccn ==3); export tmp; }
fcc: "lg" is cond=0x2 & fcc0_or_fccn { tmp:1=(fcc0_or_fccn == 1 || fcc0_or_fccn ==2); export tmp; }
fcc: "ne" is cond=0x1 & fcc0_or_fccn { tmp:1=(fcc0_or_fccn == 1 || fcc0_or_fccn == 2 || fcc0_or_fccn ==3); export tmp; }
fcc: "e" is cond=0x9 & fcc0_or_fccn { tmp:1=(fcc0_or_fccn == 0); export tmp; }
fcc: "ue" is cond=0xa & fcc0_or_fccn { tmp:1=(fcc0_or_fccn == 0 || fcc0_or_fccn == 3); export tmp; }
fcc: "ge" is cond=0xb & fcc0_or_fccn { tmp:1=(fcc0_or_fccn == 0 || fcc0_or_fccn == 2); export tmp; }
fcc: "uge" is cond=0xc & fcc0_or_fccn { tmp:1=(fcc0_or_fccn == 0 || fcc0_or_fccn == 2 || fcc0_or_fccn == 3); export tmp; }
fcc: "le" is cond=0xd & fcc0_or_fccn { tmp:1=(fcc0_or_fccn == 0 || fcc0_or_fccn == 1); export tmp; }
fcc: "ule" is cond=0xe & fcc0_or_fccn { tmp:1=(fcc0_or_fccn == 0 || fcc0_or_fccn == 1 || fcc0_or_fccn ==3); export tmp; }
fcc: "o" is cond=0xf & fcc0_or_fccn { tmp:1=(fcc0_or_fccn == 0 || fcc0_or_fccn == 1 || fcc0_or_fccn ==2); export tmp; }
:fba reloff is op=0x0 & op2=0x6 & a=0x0 & cond=0x8 & reloff { delayslot(1); goto reloff; }
:"fba,a" reloff is op=0x0 & op2=0x6 & a=0x1 & cond=0x8 & reloff { goto reloff; }
:fbn reloff is op=0x0 & op2=0x6 & a=0x0 & cond=0x0 & reloff { }
:"fbn,a" reloff,skip is op=0x0 & op2=0x6 & a=0x1 & cond=0x0 & reloff & skip { goto skip; }
:fb^fcc reloff is op=0x0 & op2=0x6 & a=0x0 & fcc & reloff { delayslot(1); if (fcc) goto reloff; }
:fb^fcc^",a" reloff is op=0x0 & op2=0x6 & a=0x1 & fcc & reloff { if (!fcc) goto inst_next; delayslot(1); goto reloff; }
:fb^fcc^predict "%"fccn,reloff64 is op=0x0 & op2=0x5 & a=0x0 & fcc & reloff64 & predict & fccn { delayslot(1); if (fcc) goto reloff64; }
:fb^fcc^",a"^predict "%"^fccn,reloff64 is op=0x0 & op2=0x5 & a=0x1 & fcc & reloff64 & predict & fccn { if (!fcc) goto inst_next; delayslot(1); goto reloff64; }
macro fcmp(f1, f2, fccn) {
# fcc value | relation
# 0 | f1 = f2
# 1 | f1 < f2
# 2 | f1 > f2
# 3 | f1 or f2 NaN
fccn = (1*(f1 f< f2)) + (2*(f1 f> f2)) + (3*(nan(f1) || nan(f2)));
}
:fcmps %fccn2,fsrs1,fsrs2 is op=0x2 & fpc=0 & fccn2 & op3=0x35 & opf=0x51 & fsrs1 & fsrs2 { fcmp(fsrs1, fsrs2, fccn2); }
:fcmpd %fccn2,fdrs1,fdrs2 is op=0x2 & fpc=0 & fccn2 & op3=0x35 & opf=0x52 & fdrs1 & fdrs2 { fcmp(fdrs1, fdrs2, fccn2); }
:fcmpq %fccn2,fqrs1,fqrs2 is op=0x2 & fpc=0 & fccn2 & op3=0x35 & opf=0x53 & fqrs1 & fqrs2 { fcmp(fqrs1, fqrs2, fccn2); }
:fcmpes %fccn2,fsrs1,fsrs2 is op=0x2 & fpc=0 & fccn2 & op3=0x35 & opf=0x55 & fsrs1 & fsrs2 { fcmp(fsrs1, fsrs2, fccn2); }
:fcmped %fccn2,fdrs1,fdrs2 is op=0x2 & fpc=0 & fccn2 & op3=0x35 & opf=0x56 & fdrs1 & fdrs2 { fcmp(fdrs1, fdrs2, fccn2); }
:fcmpeq %fccn2,fqrs1,fqrs2 is op=0x2 & fpc=0 & fccn2 & op3=0x35 & opf=0x57 & fqrs1 & fqrs2 { fcmp(fqrs1, fqrs2, fccn2); }
Z: is opf_cc=4 { export i_zf; }
Z: is opf_cc=6 { export x_zf; }
C: is opf_cc=4 { export i_cf; }
C: is opf_cc=6 { export x_cf; }
N: is opf_cc=4 { export i_nf; }
N: is opf_cc=6 { export x_nf; }
V: is opf_cc=4 { export i_vf; }
V: is opf_cc=6 { export x_vf; }
# floating-point move with integer condition codes
fmicc: "a" is cond4=0x8 { tmp:1=1; export tmp; }
fmicc: "n" is cond4=0x0 { tmp:1=0; export tmp; }
fmicc: "ne" is cond4=0x9 & Z { tmp:1=!Z; export tmp; }
fmicc: "e" is cond4=0x1 & Z { export Z; }
fmicc: "g" is cond4=0xa & Z & N & V { tmp:1=!(Z|(N^V)); export tmp; }
fmicc: "le" is cond4=0x2 & Z & N & V { tmp:1= (Z|(N^V)); export tmp; }
fmicc: "ge" is cond4=0xb & N & V { tmp:1=!(N^V); export tmp; }
fmicc: "l" is cond4=0x3 & N & V { tmp:1= (N^V); export tmp; }
fmicc: "gu" is cond4=0xc & C & Z { tmp:1=!(C|Z); export tmp; }
fmicc: "leu" is cond4=0x4 & C & Z { tmp:1= (C|Z); export tmp; }
fmicc: "cc" is cond4=0xd & C { tmp:1=!C; export tmp; }
fmicc: "cs" is cond4=0x5 & C { tmp:1=C; export tmp; }
fmicc: "pos" is cond4=0xe & N { tmp:1=!N; export tmp; }
fmicc: "neg" is cond4=0x6 & N { tmp:1=N; export tmp; }
fmicc: "vc" is cond4=0xf & V { tmp:1=!V; export tmp; }
fmicc: "vs" is cond4=0x7 & V { tmp:1=V; export tmp; }
# floating-point move with floating-point condition codes
fmfcc: "a" is cond4=0x8 & fccn_4 { tmp:1=(fccn_4 == 0); export tmp; }
fmfcc: "n" is cond4=0x0 & fccn_4 { tmp:1=(fccn_4 == 0); export tmp; }
fmfcc: "u" is cond4=0x7 & fccn_4 { tmp:1=(fccn_4 == 0); export tmp; }
fmfcc: "g" is cond4=0x6 & fccn_4 { tmp:1=(fccn_4 == 2); export tmp; }
fmfcc: "ug" is cond4=0x5 & fccn_4 { tmp:1=(fccn_4 == 2 || fccn_4 == 3); export tmp; }
fmfcc: "l" is cond4=0x4 & fccn_4 { tmp:1=(fccn_4 == 1); export tmp; }
fmfcc: "ul" is cond4=0x3 & fccn_4 { tmp:1=(fccn_4 == 1 || fccn_4 ==3); export tmp; }
fmfcc: "lg" is cond4=0x2 & fccn_4 { tmp:1=(fccn_4 == 1 || fccn_4 ==2); export tmp; }
fmfcc: "ne" is cond4=0x1 & fccn_4 { tmp:1=(fccn_4 == 1 || fccn_4 == 2 || fccn_4 ==3); export tmp; }
fmfcc: "e" is cond4=0x9 & fccn_4 { tmp:1=(fccn_4 == 0); export tmp; }
fmfcc: "ue" is cond4=0xa & fccn_4 { tmp:1=(fccn_4 == 0 || fccn_4 == 3); export tmp; }
fmfcc: "ge" is cond4=0xb & fccn_4 { tmp:1=(fccn_4 == 0 || fccn_4 == 2); export tmp; }
fmfcc: "uge" is cond4=0xc & fccn_4 { tmp:1=(fccn_4 == 0 || fccn_4 == 2 || fccn_4 == 3); export tmp; }
fmfcc: "le" is cond4=0xd & fccn_4 { tmp:1=(fccn_4 == 0 || fccn_4 == 1); export tmp; }
fmfcc: "ule" is cond4=0xe & fccn_4 { tmp:1=(fccn_4 == 0 || fccn_4 == 1 || fccn_4 ==3); export tmp; }
fmfcc: "o" is cond4=0xf & fccn_4 { tmp:1=(fccn_4 == 0 || fccn_4 == 1 || fccn_4 ==2); export tmp; }
fmfcc_or_fmicc: fmfcc is bit18=0 & fmfcc { export fmfcc; }
fmfcc_or_fmicc: fmicc is bit18=1 & fmicc { export fmicc; }
fcc_icc_xcc: "%"^fccn_4 is bit18=0 & fccn_4 { }
fcc_icc_xcc: "%icc" is bit18=1 & opf_cc=4 { }
fcc_icc_xcc: "%xcc" is bit18=1 & opf_cc=6 { }
:fmovs^fmfcc_or_fmicc fcc_icc_xcc,fsrs2,fsrd is op=2 & op3=0x35 & bit18=0 & fmfcc_or_fmicc & fcc_icc_xcc & opf_low=1 & fsrs2 & fsrd
{ if !(fmfcc_or_fmicc) goto <end>; fsrd = fsrs2; <end>}
:fmovd^fmfcc_or_fmicc fcc_icc_xcc,fdrs2,fdrd is op=2 & op3=0x35 & bit18=0 & fmfcc_or_fmicc & fcc_icc_xcc & opf_low=2 & fdrs2 & fdrd
{ if !(fmfcc_or_fmicc) goto <end>; fdrd = fdrs2; <end> }
:fmovq^fmfcc_or_fmicc fcc_icc_xcc,fqrs2,fqrd is op=2 & op3=0x35 & bit18=0 & fmfcc_or_fmicc & fcc_icc_xcc & opf_low=3 & fqrs2 & fqrd
{ if !(fmfcc_or_fmicc) goto <end>; fqrd = fqrs2; <end> }
:movf^fmfcc_or_fmicc fcc_icc_xcc,regorimm11,rd is op=2 & rd & op3=0x2c & bit18=0 & fmfcc_or_fmicc & fcc_icc_xcc & regorimm11
{ if !(fmfcc_or_fmicc) goto <end>; rd = regorimm11; <end> }
fmovrcc: "z" is rcond3=0x1 & RS1 { tmp:1 = (RS1 f== 0); export tmp; }
fmovrcc: "lez" is rcond3=0x2 & RS1 { tmp:1 = (RS1 f<= 0); export tmp; }
fmovrcc: "lz" is rcond3=0x3 & RS1 { tmp:1 = (RS1 f< 0); export tmp; }
fmovrcc: "nz" is rcond3=0x5 & RS1 { tmp:1 = (RS1 f!= 0); export tmp; }
fmovrcc: "gz" is rcond3=0x6 & RS1 { tmp:1 = (RS1 f> 0); export tmp; }
fmovrcc: "gez" is rcond3=0x7 & RS1 { tmp:1 = (RS1 f>= 0); export tmp; }
:fmovrs^fmovrcc RS1,fsrs2,fsrd is op=2 & fsrd & op3=0x35 & bit13=0 & RS1 & fmovrcc & opf_low=0x5 & fsrs2
{ if !(fmovrcc) goto <end>; fsrd = fsrs2; <end> }
:fmovrd^fmovrcc RS1,fdrs2,fdrd is op=2 & fdrd & op3=0x35 & bit13=0 & RS1 & fmovrcc & opf_low=0x6 & fdrs2
{ if !(fmovrcc) goto <end>; fdrd = fdrs2; <end> }
:fmovrq^fmovrcc RS1,fqrs2,fqrd is op=2 & fqrd & op3=0x35 & bit13=0 & RS1 & fmovrcc & opf_low=0x7 & fqrs2
{ if !(fmovrcc) goto <end>; fqrd = fqrs2; <end> }
# Include support for the VIS1 vector instructions
@include "SparcVIS.sinc"