use crate::isa::data::Fin;
use crate::isa::decode::{fp, gp};
use crate::isa::rv32::RV32Instr;
use crate::isa::rv64::RV64Instr;
use crate::isa::typed::{Imm32, Instr, Rd, Reg, Rs1, Rs2, Shamt};
use crate::isa::untyped16::Bytecode16;
use crate::rv32;
use crate::rv64;
macro_rules! hint {
() => {Instr::NOP};
}
macro_rules! reserved {
() => {return None};
}
macro_rules! nzimm_is_0 {
($untyped:expr) => {$untyped.ci().imm_b5() == 0 && $untyped.ci().imm_b1() == 0};
}
macro_rules! nzimm_not_0 {
($untyped:expr) => {!nzimm_is_0!($untyped)};
}
macro_rules! rd_is {
($untyped:expr, $n:expr) => {$untyped.ci().rd() == $n};
}
macro_rules! rd_is_0 {
($untyped:expr) => {rd_is!($untyped, 0)};
}
macro_rules! arith {
($type:ident, $opcode:ident, $untyped:expr) => {{
let ca = $untyped.ca();
let rd = Rd(gp_3(ca.rd_or_rs1()));
let rs2 = Rs2(gp_3(ca.rs2()));
$type!($opcode, rd, Rs1(rd.0), rs2)
}};
}
impl Instr {
pub fn try_from_compressed(untyped: Bytecode16) -> Option<Instr> {
let repr = untyped.repr();
match (repr, repr & 0b11) {
(0, _) => None,
(_, 0) => decode_untyped(untyped),
(_, 1) => decode_untyped(untyped),
(_, 2) => decode_untyped(untyped),
_ => None,
}
}
pub fn decode16(i: u16) -> Option<Instr> {
Instr::try_from_compressed(Bytecode16 { repr: i })
}
}
fn decode_untyped(untyped: Bytecode16) -> Option<Instr> {
let inst = untyped.repr();
let instr = match untyped.opcode() {
0b00 => match untyped.funct3() {
0b000 if untyped.ciw().imm_b8() == 0 => reserved!(),
0b000 => {
let ciw = untyped.ciw();
let rd = Rd(gp_3(ciw.rd()));
let nzuimm = ((inst >> 1) & 0x3c0) | ((inst >> 7) & 0x30) | ((inst >> 2) & 0x8) | ((inst >> 4) & 0x4); rv32!(ADDI, rd, Rs1(Reg::X(Fin::new(2))), Imm32::from(nzuimm as u32))
}
0b001 => {
let cl = untyped.cl();
let rd = Rd(fp_3(cl.rd()));
let rs1 = Rs1(gp_3(cl.rs1()));
let offset = ((inst << 1) & 0xc0) | ((inst >> 7) & 0x38);
rv32!(FLD, rd, rs1, Imm32::from(offset as u32))
}
0b010 => {
let cl = untyped.cl();
let rd = Rd(gp_3(cl.rd()));
let rs1 = Rs1(gp_3(cl.rs1()));
let offset = ((inst << 1) & 0x40) | ((inst >> 7) & 0x38) | ((inst >> 4) & 0x4);
rv32!(LW, rd, rs1, Imm32::from(offset as u32))
}
0b011 => {
let cl = untyped.cl();
let rd = Rd(gp_3(cl.rd()));
let rs1 = Rs1(gp_3(cl.rs1()));
let offset = ((inst << 1) & 0xc0) | ((inst >> 7) & 0x38);
rv64!(LD, rd, rs1, Imm32::from(offset as u32))
}
0b100 => reserved!(),
0b101 => {
let cs = untyped.cs();
let rs1 = Rs1(gp_3(cs.rs1()));
let rs2 = Rs2(fp_3(cs.rs2()));
let offset = ((inst << 1) & 0xc0) | ((inst >> 7) & 0x38);
rv32!(FSD, rs1, rs2, Imm32::from(offset as u32))
}
0b110 => {
let cs = untyped.cs();
let rs1 = Rs1(gp_3(cs.rs1()));
let rs2 = Rs2(gp_3(cs.rs2()));
let offset = ((inst << 1) & 0x40) | ((inst >> 7) & 0x38) | ((inst >> 4) & 0x4);
rv32!(SW, rs1, rs2, Imm32::from(offset as u32))
}
0b111 => {
let cs = untyped.cs();
let rs1 = Rs1(gp_3(cs.rs1()));
let rs2 = Rs2(gp_3(cs.rs2()));
let offset = ((inst << 1) & 0xc0) | ((inst >> 7) & 0x38);
rv64!(SD, rs1, rs2, Imm32::from(offset as u32))
}
_ => return None,
},
0b01 => match untyped.funct3() {
0b000 if rd_is_0!(untyped) && nzimm_not_0!(untyped) => hint!(),
0b000 if rd_is_0!(untyped) => Instr::NOP,
0b000 if nzimm_is_0!(untyped) => hint!(),
0b000 => {
let ci = untyped.ci();
let rd = Rd(gp(ci.rd()));
let imm = ((inst >> 7) & 0x20) | ((inst >> 2) & 0x1f);
let imm = match (imm & 0x20) == 0 {
true => imm as u32,
false => (0xc0 | imm) as i8 as i32 as u32,
};
rv32!(ADDI, rd, Rs1(rd.0), Imm32::from(imm))
}
0b001 if rd_is_0!(untyped) => reserved!(),
0b001 => {
let ci = untyped.ci();
let rd = Rd(gp(ci.rd()));
let imm = ((inst >> 7) & 0x20) | ((inst >> 2) & 0x1f);
let imm = match (imm & 0x20) == 0 {
true => imm as u32,
false => (0xc0 | imm) as i8 as i32 as u32,
};
rv64!(ADDIW, rd, Rs1(rd.0), Imm32::from(imm))
}
0b010 => {
let ci = untyped.ci();
let rd = Rd(gp(ci.rd()));
let imm = ((inst >> 7) & 0x20) | ((inst >> 2) & 0x1f);
let imm = match (imm & 0x20) == 0 {
true => imm as u32,
false => (0xc0 | imm) as i8 as i32 as u32,
};
rv32!(ADDI, rd, Rs1(Reg::ZERO), Imm32::from(imm))
}
0b011 if rd_is!(untyped, 2) && nzimm_is_0!(untyped) => reserved!(),
0b011 if rd_is!(untyped, 2) => {
let nzimm = ((inst >> 3) & 0x200) | ((inst >> 2) & 0x10) | ((inst << 1) & 0x40) | ((inst << 4) & 0x180) | ((inst << 3) & 0x20); let nzimm = match (nzimm & 0x200) == 0 {
true => nzimm as u32,
false => (0xfc00 | nzimm) as i16 as i32 as u32,
};
rv32!(ADDI, Rd(Reg::X(Fin::new(2))), Rs1(Reg::X(Fin::new(2))), Imm32::from(nzimm))
}
0b011 if nzimm_is_0!(untyped) => reserved!(),
0b011 if rd_is_0!(untyped) => hint!(),
0b011 => {
let ci = untyped.ci();
let rd = Rd(gp(ci.rd()));
let imm = (((inst as u32) << 5) & 0x20000) | (((inst as u32) << 10) & 0x1f000);
let imm = match (imm & 0x20000) == 0 {
true => imm,
false => (0xfffc0000 | imm) as i32 as u32,
};
rv32!(LUI, rd, Imm32::from(imm >> 12))
}
0b100 => match untyped.cbi().funct2() {
0b00 if nzimm_is_0!(untyped) => hint!(),
0b00 => {
let cbi = untyped.cbi();
let rd = Rd(gp_3(cbi.rd_or_rs1()));
let shamt = ((inst >> 7) & 0x20) | ((inst >> 2) & 0x1f);
rv64!(SRLI, rd, Rs1(rd.0), Shamt(shamt as u8))
}
0b01 if nzimm_is_0!(untyped) => hint!(),
0b01 => {
let cbi = untyped.cbi();
let rd = Rd(gp_3(cbi.rd_or_rs1()));
let shamt = ((inst >> 7) & 0x20) | ((inst >> 2) & 0x1f);
rv64!(SRAI, rd, Rs1(rd.0), Shamt(shamt as u8))
}
0b10 => {
let cbi = untyped.cbi();
let rd = Rd(gp_3(cbi.rd_or_rs1()));
let imm = ((inst >> 7) & 0x20) | ((inst >> 2) & 0x1f);
let imm = match (imm & 0x20) == 0 {
true => imm as u32,
false => (0xc0 | imm) as i8 as i32 as u32,
};
rv32!(ANDI, rd, Rs1(rd.0), Imm32::from(imm))
}
0b11 => match (untyped.ca().funct6(), untyped.ca().funct2()) {
(0b100_0_11, 0b00) => arith!(rv32, SUB, untyped),
(0b100_0_11, 0b01) => arith!(rv32, XOR, untyped),
(0b100_0_11, 0b10) => arith!(rv32, OR, untyped),
(0b100_0_11, 0b11) => arith!(rv32, AND, untyped),
(0b100_1_11, 0b00) => arith!(rv64, SUBW, untyped),
(0b100_1_11, 0b01) => arith!(rv64, ADDW, untyped),
(0b100_1_11, 0b10) => reserved!(),
(0b100_1_11, 0b11) => reserved!(),
_ => return None,
},
_ => return None,
},
0b101 => {
let offset = ((inst >> 1) & 0x800) | ((inst << 2) & 0x400) | ((inst >> 1) & 0x300) | ((inst << 1) & 0x80) | ((inst >> 1) & 0x40) | ((inst << 3) & 0x20) | ((inst >> 7) & 0x10) | ((inst >> 2) & 0xe); let offset = match (offset & 0x800) == 0 {
true => offset as u32,
false => (0xf000 | offset) as i16 as i32 as u32,
};
rv32!(JAL, Rd(Reg::ZERO), Imm32::from(offset >> 1))
}
0b110 => {
let cb = untyped.cb();
let rs1 = Rs1(gp_3(cb.rd_or_rs1()));
let offset = ((inst >> 4) & 0x100) | ((inst << 1) & 0xc0) | ((inst << 3) & 0x20) | ((inst >> 7) & 0x18) | ((inst >> 2) & 0x6); let offset = match (offset & 0x100) == 0 {
true => offset as u32,
false => (0xfe00 | offset) as i16 as i32 as u32,
};
rv32!(BEQ, rs1, Rs2(Reg::ZERO), Imm32::from(offset >> 1))
}
0b111 => {
let cb = untyped.cb();
let rs1 = Rs1(gp_3(cb.rd_or_rs1()));
let offset = ((inst >> 4) & 0x100) | ((inst << 1) & 0xc0) | ((inst << 3) & 0x20) | ((inst >> 7) & 0x18) | ((inst >> 2) & 0x6); let offset = match (offset & 0x100) == 0 {
true => offset as u32,
false => (0xfe00 | offset) as i16 as i32 as u32,
};
rv32!(BNE, rs1, Rs2(Reg::ZERO), Imm32::from(offset >> 1))
}
_ => return None,
},
0b10 => match untyped.funct3() {
0b000 if rd_is_0!(untyped) => hint!(),
0b000 if nzimm_is_0!(untyped) => hint!(),
0b000 => {
let ci = untyped.ci();
let rd = Rd(gp(ci.rd()));
let shamt = ((inst >> 7) & 0x20) | ((inst >> 2) & 0x1f);
rv64!(SLLI, rd, Rs1(rd.0), Shamt(shamt as u8))
}
0b001 => {
let ci = untyped.ci();
let rd = Rd(fp(ci.rd()));
let offset = ((inst << 4) & 0x1c0) | ((inst >> 7) & 0x20) | ((inst >> 2) & 0x18); rv32!(FLD, rd, Rs1(Reg::X(Fin::new(2))), Imm32::from(offset as u32))
}
0b010 if rd_is_0!(untyped) => reserved!(),
0b010 => {
let ci = untyped.ci();
let rd = Rd(gp(ci.rd()));
let offset = ((inst << 4) & 0xc0) | ((inst >> 7) & 0x20) | ((inst >> 2) & 0x1c); rv32!(LW, rd, Rs1(Reg::X(Fin::new(2))), Imm32::from(offset as u32))
}
0b011 if rd_is_0!(untyped) => reserved!(),
0b011 => {
let ci = untyped.ci();
let rd = Rd(gp(ci.rd()));
let offset = ((inst << 4) & 0x1c0) | ((inst >> 7) & 0x20) | ((inst >> 2) & 0x18); rv64!(LD, rd, Rs1(Reg::X(Fin::new(2))), Imm32::from(offset as u32))
}
0b100 if nzimm_is_0!(untyped) && rd_is_0!(untyped) => reserved!(),
0b100 if nzimm_is_0!(untyped) => {
let cr = untyped.cr();
let rs1 = Rs1(gp(cr.rd_or_rs1()));
rv32!(JALR, Rd(Reg::ZERO), rs1, Imm32::from(0))
}
0b100 if untyped.ci().imm_b1() == 0 && untyped.ci().imm_b5() != 0 && rd_is_0!(untyped) => hint!(),
0b100 if untyped.ci().imm_b1() == 0 && untyped.ci().imm_b5() != 0 => {
let cr = untyped.cr();
let rd = Rd(gp(cr.rd_or_rs1()));
let rs2 = Rs2(gp(cr.rs2()));
rv32!(ADD, rd, Rs1(Reg::ZERO), rs2)
}
0b100 if untyped.repr() == 0b100_1_00000_00000_10 => rv32!(EBREAK),
0b100 if untyped.ci().imm_b1() == 1 && untyped.ci().imm_b5() == 0 => {
let cr = untyped.cr();
let rs1 = Rs1(gp(cr.rd_or_rs1()));
rv32!(JALR, Rd(Reg::X(Fin::new(1))), rs1, Imm32::from(0))
}
0b100 if untyped.ci().imm_b1() == 1 => {
let cr = untyped.cr();
let rd = Rd(gp(cr.rd_or_rs1()));
let rs2 = Rs2(gp(cr.rs2()));
rv32!(ADD, rd, Rs1(rd.0), rs2)
}
0b101 => {
let css = untyped.css();
let rs2 = Rs2(fp(css.rs2()));
let offset = ((inst >> 1) & 0x1c0) | ((inst >> 7) & 0x38); rv32!(FSD, Rs1(Reg::X(Fin::new(2))), rs2, Imm32::from(offset as u32))
}
0b110 => {
let css = untyped.css();
let rs2 = Rs2(gp(css.rs2()));
let offset = ((inst >> 1) & 0xc0) | ((inst >> 7) & 0x3c); rv32!(SW, Rs1(Reg::X(Fin::new(2))), rs2, Imm32::from(offset as u32))
}
0b111 => {
let css = untyped.css();
let rs2 = Rs2(gp(css.rs2()));
let offset = ((inst >> 1) & 0x1c0) | ((inst >> 7) & 0x38); rv64!(SD, Rs1(Reg::X(Fin::new(2))), rs2, Imm32::from(offset as u32))
}
_ => return None,
},
_ => return None,
};
Some(instr)
}
fn fp_3(reg: u8) -> Reg {
let encoding = reg as u8;
match encoding {
0b000 => Reg::F(Fin::new(8)),
0b001 => Reg::F(Fin::new(9)),
0b010 => Reg::F(Fin::new(10)),
0b011 => Reg::F(Fin::new(11)),
0b100 => Reg::F(Fin::new(12)),
0b101 => Reg::F(Fin::new(13)),
0b110 => Reg::F(Fin::new(14)),
0b111 => Reg::F(Fin::new(15)),
_ => panic!("Inaccessible register encoding: {:b}", encoding),
}
}
fn gp_3(reg: u8) -> Reg {
let encoding = reg as u8;
match encoding {
0b000 => Reg::X(Fin::new(8)),
0b001 => Reg::X(Fin::new(9)),
0b010 => Reg::X(Fin::new(10)),
0b011 => Reg::X(Fin::new(11)),
0b100 => Reg::X(Fin::new(12)),
0b101 => Reg::X(Fin::new(13)),
0b110 => Reg::X(Fin::new(14)),
0b111 => Reg::X(Fin::new(15)),
_ => panic!("Inaccessible register encoding: {:b}", encoding),
}
}