
#TODO  these names are madeup. do real ones exist?
#TODO  go through and use these instead of numbers
@define HFLEN 2
@define SFLEN 4
@define DFLEN 8
@define QFLEN 16

@define HXLEN 2
@define WXLEN 4
@define DXLEN 8
@define QXLEN 16


define pcodeop unimp;
define pcodeop trap;
define pcodeop ebreak;
define pcodeop ecall;
define pcodeop fence;
define pcodeop fence.i;


# possible tokens:  r0711 r1519 r2024 r2731 cr0206 cr0711 cd0711
rs1: r1519 is r1519  { export r1519; }
rs1: zero is zero & op1519=0 { export 0:$(XLEN); }

rs2: r2024 is r2024 { export r2024; }
rs2: zero is zero & op2024=0 { export 0:$(XLEN); }

rs3: r2731 is r2731 { export r2731; }
rs3: zero is zero & op2731=0 { export 0:$(XLEN); }

rd: r0711 is r0711 { export r0711; }
rd: zero is r0711 & zero & op0711=0 { local tempZero:$(XLEN) = 0; export tempZero; }
rdDst: r0711 is r0711 { export r0711; }


rs1W: r1519 is r1519 { local tmp:$(WXLEN) = r1519:$(WXLEN); export tmp; }
rs1W: zero is r1519 & zero & op1519=0 { export 0:$(WXLEN); }

rs2W: r2024 is r2024 { local tmp:$(WXLEN) = r2024:$(WXLEN); export tmp; }
rs2W: zero is r2024 & zero & op2024=0 { export 0:$(WXLEN); }

#TODO  dest may be bad, might need an assign macro
rdW: r0711 is r0711 { local tmp:$(WXLEN) = r0711:$(WXLEN); export tmp; }
rdW: zero is r0711 & zero & op0711=0 { export 0:$(WXLEN); }



#TODO  does this need to be in an if/endif
@if ADDRSIZE == "64"
rs1L: r1519 is r1519 { local tmp:8 = r1519:8; export tmp; }
rs1L: zero is r1519 & zero & op1519=0 { export 0:8; }

rs2L: r2024 is r2024 { local tmp:8 = r2024:8; export tmp; }
rs2L: zero is r2024 & zero & op2024=0 { export 0:8; }

#TODO  dest may be bad, might need an assign macro
rdL: r0711 is r0711 { export r0711; }
rdL: zero is r0711 & zero & op0711=0 { export 0:8; }
@endif


#TODO  eh not sure if this is usable
#      would only make sense to use this if the float operation
#      tables for frd,frs1,frs2 could be different sizes or
#      if the cast could use this export, but they have to export
#      the same size and you cant 'local tmp:fmt'
# # 32-bit single-precision  $(SFLEN)
# fmt: ".s" is op2526=0 { export $(SFLEN):1; }
# # 64-bit double-precision  $(DFLEN)
# fmt: ".d" is op2526=1 { export $(DFLEN):1; }
# # 16-bit half-precision  $(HFLEN)
# fmt: ".h" is op2526=2 { export $(HFLEN):1; }
# # 128-bit quad-precision  $(QFLEN)
# fmt: ".q" is op2526=3 { export $(QFLEN):1; }


frd:  fr0711 is fr0711 { export fr0711; }
frs1: fr1519 is fr1519 { export fr1519; }
frs2: fr2024 is fr2024 { export fr2024; }
frs3: fr2731 is fr2731 { export fr2731; }

#TODO  dest may be bad, might need an assign macro
#frdS:  fr0711 is fr0711 { local tmp = fr0711:$(SFLEN); export tmp; }
frs1S: fr1519 is fr1519 { local tmp = fr1519:$(SFLEN); export tmp; }
frs2S: fr2024 is fr2024 { local tmp = fr2024:$(SFLEN); export tmp; }
frs3S: fr2731 is fr2731 { local tmp = fr2731:$(SFLEN); export tmp; }

@if ((FPSIZE == "64") || (FPSIZE == "128"))
#TODO  dest may be bad, might need an assign macro
#frdD:  fr0711 is fr0711 { local tmp = fr0711:$(DFLEN); export tmp; }
frs1D: fr1519 is fr1519 { local tmp = fr1519:$(DFLEN); export tmp; }
frs2D: fr2024 is fr2024 { local tmp = fr2024:$(DFLEN); export tmp; }
frs3D: fr2731 is fr2731 { local tmp = fr2731:$(DFLEN); export tmp; }
@endif

macro fassignS(dest, src) {
@if FPSIZE == "32"
	dest = src;
@else
	dest = zext(src);
@endif
}


macro assignW(dest, src) {
@if ADDRSIZE == "32"
	dest = src;
@else
	dest = sext(src);
@endif
}

macro zassignW(dest, src) {
@if ADDRSIZE == "32"
	dest = src;
@else
	dest = zext(src);
@endif
}

macro zassignD(dest, src) {
@if ADDRSIZE == "128"
	dest = zext(src);
@else
	dest = src;
@endif
}

macro assignD(dest, src) {
@if ADDRSIZE == "128"
	dest = sext(src);
@else
	dest = src;
@endif
}


immI: sop2031 is sop2031 { local tmp:$(XLEN) = sop2031; export tmp; }

immS: imm is op0711 & sop2531 [ imm = (sop2531 << 5) | op0711; ] { local tmp:$(XLEN) = imm; export tmp; }

# used for goto
immSB: reloc is op0707 & op0811 & op2530 & sop3131 [ reloc = inst_start + ((sop3131 << 12) | (op2530 << 5) | (op0811 << 1) | (op0707 << 11)); ] { export *[ram]:$(XLEN) reloc; }
#immSB: reloc is op0707 & op0811 & op2530 & sop3131 [ reloc = inst_start + ((sop3131 << 12) | (op2530 << 5) | (op0811 << 1) | (op0707 << 11)); ] { export reloc; }

immU: op1231 is op1231 & sop1231 { local tmp:$(XLEN) = sop1231 << 12; export tmp; }

# used for goto
immUJ: reloc is op1219 & op2020 & op2130 & sop3131 [ reloc = inst_start + ((sop3131 << 20) | (op2130 << 1) | (op2020 << 11) | (op1219 << 12)); ] { export *[ram]:$(XLEN) reloc; }

@if ADDRSIZE == "32"
shamt6: op2024 is op2024 & op2525=0 { local tmp:$(XLEN) = op2024; export tmp; }
@else
shamt5: op2024 is op2024 { local tmp:$(XLEN) = op2024; export tmp; }
shamt6: imm is op2024 & op2525 [ imm = (op2525 << 5) | op2024; ] { local tmp:$(XLEN) = imm; export tmp; }
@endif

FRM: "rne" is op1214=0 { local tmp:1 = 0; export tmp; }
FRM: "rtz" is op1214=1 { local tmp:1 = 1; export tmp; }
FRM: "rdn" is op1214=2 { local tmp:1 = 2; export tmp; }
FRM: "rup" is op1214=3 { local tmp:1 = 3; export tmp; }
FRM: "rmm" is op1214=4 { local tmp:1 = 4; export tmp; }
# 5  Invalid.  Reserved for future use
# 6  Invalid.  Reserved for future use
FRM: "dyn" is op1214=7 { local tmp:1 = 7; export tmp; }

# used to specify additional memory ordering constraints
aqrl: ""      is op2526=0 { export 0:$(XLEN); }
aqrl: ".rl"   is op2526=1 { export 1:$(XLEN); }
aqrl: ".aq"   is op2526=2 { export 2:$(XLEN); }
aqrl: ".aqrl" is op2526=3 { export 3:$(XLEN); }



crs1: cr0711 is cr0711 { export cr0711; }
crs1: zero is cr0711 & zero & cop0711=0 { export 0:$(XLEN); }

crd: cd0711 is cd0711 { export cd0711; }
crd: zero is zero & cop0711=0 { export 0:$(XLEN); }

crs2: cr0206 is cr0206 { export cr0206; }
crs2: zero is cr0206 & zero & cop0206=0 { export 0:$(XLEN); }

cfrs1: cfr0711 is cfr0711 { export cfr0711; }

cfrd: cfr0711 is cfr0711 { export cfr0711; }

cfrs2: cfr0206 is cfr0206 { export cfr0206; }

#ATTN  Not doing tables for the RVC registers since there is no
#      zero register to worry about



cimmI: imm is scop1212 & cop0206 [ imm = (scop1212 << 5) | (cop0206); ] { local tmp:$(XLEN) = imm; export tmp; }

# used for goto
cbimm: reloc is scop1212 & cop1011 & cop0506 & cop0304 & cop0202 [ reloc = inst_start + ((scop1212 << 8) | (cop0506 << 6) | (cop0202 << 5) | (cop1011 << 3) | (cop0304 << 1)); ] { export *[ram]:$(XLEN) reloc; }
#cbimm: reloc is scop1212 & cop1011 & cop0506 & cop0304 & cop0202 [ reloc = inst_start + ((scop1212 << 8) | (cop0506 << 6) | (cop0202 << 5) | (cop1011 << 3) | (cop0304 << 1)); ] { export reloc; }

# used for goto
cjimm: reloc is scop1212 & cop1111 & cop0910 & cop0808 & cop0707 & cop0606 & cop0305 & cop0202 [ reloc = inst_start + ((scop1212 << 11) | (cop1111 << 4) | (cop0910 << 8) | (cop0808 << 10) | (cop0707 << 6) | (cop0606 << 7) | (cop0305 << 1) | (cop0202 << 5)); ] { export *[ram]:$(XLEN) reloc; }


nzuimm5: is cop0606=1 | cop0505=1 | cop0404=1 | cop0303 = 1 | cop0202=1 {}
nzuimm6: is cop1212=1 | cop0606=1 | cop0505=1 | cop0404=1 | cop0303 = 1 | cop0202=1 {}

@if ADDRSIZE == "32"
c6imm: uimm is cop1212=0 & cop0206 & nzuimm5 [ uimm = (cop0206 + 0); ] { local tmp:$(XLEN) = uimm; export tmp; }
@elif ADDRSIZE == "64"
c6imm: uimm is cop1212 & cop0206 & nzuimm6 [ uimm = (cop1212 << 5) | (cop0206); ] { local tmp:$(XLEN) = uimm; export tmp; }
@elif ADDRSIZE == "128"
c6imm: uimm is cop1212 & cop0206 [ uimm = (cop1212 << 5) | (cop0206); ] { local tmp:$(XLEN) = uimm + (64 * (uimm == 0)); export tmp; }
@endif

cbigimm: uimm is cop1212 & scop1212 & cop0206 & nzuimm6 [ uimm = (cop1212 << 5) | (cop0206); ] { local tmp:$(XLEN) = (scop1212 << 17) | (cop0206 << 12); export tmp; }

nzcaddi4: is cop1212=1 | cop1111=1 | cop1010=1 | cop0909=1 | cop0808=1 | cop0707=1 | cop0606=1 | cop0505=1 {}

caddi4spnimm: uimm is nzcaddi4 & cop1112 & cop0710 & cop0606 & cop0505 [ uimm = (cop0710 << 6) | (cop1112 << 4) | (cop0505 << 3) | (cop0606 << 2); ] { local tmp:$(XLEN) = uimm; export tmp; }

caddi16spimm: imm is scop1212 & cop0606 & cop0505 & cop0304 & cop0202 & nzuimm6 [ imm = (scop1212 << 9) | (cop0304 << 7) | (cop0505 << 6) | (cop0202 << 5) | (cop0606 << 4); ] { local tmp:$(XLEN) = imm; export tmp; }


clwimm: uimm is cop1012 & cop0606 & cop0505 [ uimm = (cop1012 << 3) | (cop0606 << 2) | (cop0505 << 6); ] { local tmp:$(XLEN) = uimm; export tmp; }

clwspimm: uimm is cop1212 & cop0406 & cop0203 [ uimm = (cop1212 << 5) | (cop0406 << 2) | (cop0203 << 6); ] { local tmp:$(XLEN) = uimm; export tmp; }

cswspimm: uimm is cop0708 & cop0912 [ uimm = (cop0708 << 6) | (cop0912 << 2); ] { local tmp:$(XLEN) = uimm; export tmp; }

cldimm: uimm is cop1012 & cop0506 [ uimm = (cop1012 << 3) | (cop0506 << 6); ] { local tmp:$(XLEN) = uimm; export tmp; }

cldspimm: uimm is cop1212 & cop0506 & cop0204 [ uimm = (cop1212 << 5) | (cop0506 << 3) | (cop0204 << 6); ] { local tmp:$(XLEN) = uimm; export tmp; }

csdspimm: uimm is cop0709 & cop1012 [ uimm = (cop0709 << 6) | (cop1012 << 3); ] { local tmp:$(XLEN) = uimm; export tmp; }

@if ADDRSIZE == "128"
clqimm: uimm is cop1112 & cop1010 & cop0506 [ uimm = (cop1112 << 4) | (cop1010 << 8) | (cop0506 << 6); ] { local tmp:$(XLEN) = uimm; export tmp; }

clqspimm: uimm is cop1212 & cop0606 & cop0205 [ uimm = (cop1212 << 5) | (cop0606 << 4) | (cop0205 << 6); ] { local tmp:$(XLEN) = uimm; export tmp; }

csqspimm: uimm is cop0710 & cop1112 [ uimm = (cop0710 << 6) | (cop1112 << 4); ] { local tmp:$(XLEN) = uimm; export tmp; }
@endif





# SEE riscv-privileged.pdf Section 'CSR Listing' for description
# This implementation aligns with the table breakdown

# csr[11:10] - read/write (00, 01, 10) or read-only (11)
# csr[9:8] - lowest privilege that can access the CSR

# 0x000-0x0ff
with csr: op3031=0 & op2829=0 {
	: csr_0 is csr_0 { export csr_0; } # user, standard read/write
}

# 0x100-0x1ff
with csr: op3031=0 & op2829=1 {
	: csr_1 is csr_1 { export csr_1; } # supervisor, standard read/write
}

# 0x200-0x2ff
with csr: op3031=0 & op2829=2 {
	: csr_2 is csr_2 { export csr_2; } # hypervisor, standard read/write
}

# 0x300-0x3ff
with csr: op3031=0 & op2829=3 {
	: csr_3 is csr_3 { export csr_3; } # machine, standard read/write
}

# 0x400-0x4ff
with csr: op3031=1 & op2829=0 {
	: csr_4 is csr_4 { export csr_4; } # user, standard read/write
}

# 0x500-0x5ff
with csr: op3031=1 & op2829=1 {
	: csr_50 is csr_50 & op2727=0 { export csr_50; } # supervisor, standard read/write
	: csr_58 is csr_58 & op2627=2 { export csr_58; } # supervisor, standard read/write
	: csr_5C is csr_5C & op2627=3 { export csr_5C; } # supervisor, custom read/write
}

# 0x600-0x6ff
with csr: op3031=1 & op2829=2 {
	: csr_60 is csr_60 & op2727=0 { export csr_60; } # hypervisor, standard read/write
	: csr_68 is csr_68 & op2627=2 { export csr_68; } # hypervisor, standard read/write
	: csr_6C is csr_6C & op2627=3 { export csr_6C; } # hypervisor, custom read/write
}

# 0x700-0x7ff
with csr: op3031=1 & op2829=3 {
	: csr_70 is csr_70 & op2727=0   { export csr_70; } # machine, standard read/write
	: csr_78 is csr_78 & op2527=4   { export csr_78; } # machine, standard read/write
	: csr_7A is csr_7A & op2427=0xa { export csr_7A; } # machine, standard read/write debug
	: csr_7B is csr_7B & op2427=0xb { export csr_7B; } # machine, debug-mode-only
	: csr_7C is csr_7C & op2627=3   { export csr_7C; } # machine, custom read/write
}

# 0x800-0x8ff
with csr: op3031=2 & op2829=0 {
	: csr_8 is csr_8 { export csr_8; } # user, custom read/write
}

# 0x900-0x9ff
with csr: op3031=2 & op2829=1 {
	: csr_90 is csr_90 & op2727=0 { export csr_90; } # supervisor, standard read/write
	: csr_98 is csr_98 & op2627=2 { export csr_98; } # supervisor, standard read/write
	: csr_9C is csr_9C & op2627=3 { export csr_9C; } # supervisor, custom read/write
}

# 0xa00-0xaff
with csr: op3031=2 & op2829=2 {
	: csr_A0 is csr_A0 & op2727=0 { export csr_A0; } # hypervisor, standard read/write
	: csr_A8 is csr_A8 & op2627=2 { export csr_A8; } # hypervisor, standard read/write
	: csr_AC is csr_AC & op2627=3 { export csr_AC; } # hypervisor, custom read/write
}

# 0xb00-0xbff
with csr: op3031=2 & op2829=3 {
	: csr_B0 is csr_B0 & op2727=0 { export csr_B0; } # machine, standard read/write
	: csr_B8 is csr_B8 & op2627=2 { export csr_B8; } # machine, standard read/write
	: csr_BC is csr_BC & op2627=3 { export csr_BC; } # machine, custom read/write
}

# 0xc00-0xcff
with csr: op3031=3 & op2829=0 {
	: csr_C0 is csr_C0 & op2727=0 { export csr_C0; } # user, standard read-only
	: csr_C8 is csr_C8 & op2627=2 { export csr_C8; } # user, standard read-only
	: csr_CC is csr_CC & op2627=3 { export csr_CC; } # user, custom read-only
}

# 0xd00-0xdff
with csr: op3031=3 & op2829=1 {
	: csr_D0 is csr_D0 & op2727=0 { export csr_D0; } # supervisor, standard read-only
	: csr_D8 is csr_D8 & op2627=2 { export csr_D8; } # supervisor, standard read-only
	: csr_DC is csr_DC & op2627=3 { export csr_DC; } # supervisor, custom read-only
}

# 0xe00-0xeff
with csr: op3031=3 & op2829=2 {
	: csr_E0 is csr_E0 & op2727=0 { export csr_E0; } # hypervisor, standard read-only
	: csr_E8 is csr_E8 & op2627=2 { export csr_E8; } # hypervisor, standard read-only
	: csr_EC is csr_EC & op2627=3 { export csr_EC; } # hypervisor, custom read-only
}

# 0xf00-0xfff
with csr: op3031=3 & op2829=3 {
	: csr_F0 is csr_F0 & op2727=0 { export csr_F0; } # machine, standard read-only
	: csr_F8 is csr_F8 & op2627=2 { export csr_F8; } # machine, standard read-only
	: csr_FC is csr_FC & op2627=3 { export csr_FC; } # machine, custom read-only
}



vm: op2525 is op2525 { local tmp:1 = op2525; export tmp; }

vs1: v1519 is v1519 { export v1519; }
vs2: v2024 is v2024 { export v2024; }
vs3: v0711 is v0711 { export v0711; }
vd:  v0711 is v0711 { export v0711; }

simm5: sop1519 is sop1519 { local tmp:$(XLEN) = sop1519; export tmp; }
# zimm: op1519 is op1519 { local tmp:$(XLEN) = op1519; export tmp; }

nf: op2931 is op2931 { local tmp:$(XLEN) = op2931; export tmp; }

vtypei: op2030 is op2030 { local tmp:$(XLEN) = op2030; export tmp; }


bs: op3031 is op3031 { local tmp:$(XLEN) = op3031; export tmp; }
rcon: op2023 is op2023 { local tmp:$(XLEN) = op2023; export tmp; }

# imm=0 for baseline operation, nonzero values are reserved
shamtw: 0 is op2024=0 { local tmp:$(XLEN) = 0; export tmp; }

imm3u: op2022 is op2022 { local tmp:$(XLEN) = op2022; export tmp; }
imm4u: op2023 is op2023 { local tmp:$(XLEN) = op2023; export tmp; }
imm5u: op2024 is op2024 { local tmp:$(XLEN) = op2024; export tmp; }
