use crate::{
error::Error,
instructions::{
extract_opcode, insts, Instruction, Itype, R4type, R5type, Rtype, Stype, Utype,
},
};
use core::convert::TryFrom;
use core::fmt;
#[derive(Debug, Clone, PartialEq)]
pub enum TaggedInstruction {
Rtype(Rtype),
Itype(Itype),
Stype(Stype),
Utype(Utype),
R4type(R4type),
R5type(R5type),
}
impl fmt::Display for TaggedInstruction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TaggedInstruction::Rtype(i) => i.fmt(f),
TaggedInstruction::Itype(i) => i.fmt(f),
TaggedInstruction::Stype(i) => i.fmt(f),
TaggedInstruction::Utype(i) => i.fmt(f),
TaggedInstruction::R4type(i) => i.fmt(f),
TaggedInstruction::R5type(i) => i.fmt(f),
}
}
}
impl From<Rtype> for TaggedInstruction {
fn from(i: Rtype) -> Self {
TaggedInstruction::Rtype(i)
}
}
impl From<Itype> for TaggedInstruction {
fn from(i: Itype) -> Self {
TaggedInstruction::Itype(i)
}
}
impl From<Stype> for TaggedInstruction {
fn from(i: Stype) -> Self {
TaggedInstruction::Stype(i)
}
}
impl From<Utype> for TaggedInstruction {
fn from(i: Utype) -> Self {
TaggedInstruction::Utype(i)
}
}
impl From<R4type> for TaggedInstruction {
fn from(i: R4type) -> Self {
TaggedInstruction::R4type(i)
}
}
impl From<R5type> for TaggedInstruction {
fn from(i: R5type) -> Self {
TaggedInstruction::R5type(i)
}
}
impl From<TaggedInstruction> for Instruction {
fn from(t: TaggedInstruction) -> Self {
match t {
TaggedInstruction::Rtype(i) => i.0,
TaggedInstruction::Itype(i) => i.0,
TaggedInstruction::Stype(i) => i.0,
TaggedInstruction::Utype(i) => i.0,
TaggedInstruction::R4type(i) => i.0,
TaggedInstruction::R5type(i) => i.0,
}
}
}
impl TryFrom<Instruction> for TaggedInstruction {
type Error = Error;
fn try_from(i: Instruction) -> Result<Self, Self::Error> {
let op = extract_opcode(i);
let tagged_inst = match op {
insts::OP_UNLOADED => Rtype(i).into(),
insts::OP_ECALL => Rtype(i).into(),
insts::OP_EBREAK => Rtype(i).into(),
insts::OP_FENCEI => Rtype(i).into(),
insts::OP_FENCE => Rtype(i).into(),
insts::OP_CUSTOM_TRACE_END => Rtype(i).into(),
insts::OP_SUB => Rtype(i).into(),
insts::OP_SUBW => Rtype(i).into(),
insts::OP_ADD => Rtype(i).into(),
insts::OP_ADDW => Rtype(i).into(),
insts::OP_XOR => Rtype(i).into(),
insts::OP_OR => Rtype(i).into(),
insts::OP_AND => Rtype(i).into(),
insts::OP_SLL => Rtype(i).into(),
insts::OP_SLLW => Rtype(i).into(),
insts::OP_SRL => Rtype(i).into(),
insts::OP_SRLW => Rtype(i).into(),
insts::OP_SRA => Rtype(i).into(),
insts::OP_SRAW => Rtype(i).into(),
insts::OP_SLT => Rtype(i).into(),
insts::OP_SLTU => Rtype(i).into(),
insts::OP_LB_VERSION0 => Itype(i).into(),
insts::OP_LB_VERSION1 => Itype(i).into(),
insts::OP_LH_VERSION0 => Itype(i).into(),
insts::OP_LH_VERSION1 => Itype(i).into(),
insts::OP_LW_VERSION0 => Itype(i).into(),
insts::OP_LW_VERSION1 => Itype(i).into(),
insts::OP_LD_VERSION0 => Itype(i).into(),
insts::OP_LD_VERSION1 => Itype(i).into(),
insts::OP_LBU_VERSION0 => Itype(i).into(),
insts::OP_LBU_VERSION1 => Itype(i).into(),
insts::OP_LHU_VERSION0 => Itype(i).into(),
insts::OP_LHU_VERSION1 => Itype(i).into(),
insts::OP_LWU_VERSION0 => Itype(i).into(),
insts::OP_LWU_VERSION1 => Itype(i).into(),
insts::OP_ADDI => Itype(i).into(),
insts::OP_ADDIW => Itype(i).into(),
insts::OP_XORI => Itype(i).into(),
insts::OP_ORI => Itype(i).into(),
insts::OP_ANDI => Itype(i).into(),
insts::OP_SLTI => Itype(i).into(),
insts::OP_SLTIU => Itype(i).into(),
insts::OP_JALR_VERSION0 => Itype(i).into(),
insts::OP_JALR_VERSION1 => Itype(i).into(),
insts::OP_SLLI => Itype(i).into(),
insts::OP_SRLI => Itype(i).into(),
insts::OP_SRAI => Itype(i).into(),
insts::OP_SLLIW => Itype(i).into(),
insts::OP_SRLIW => Itype(i).into(),
insts::OP_SRAIW => Itype(i).into(),
insts::OP_SB => Stype(i).into(),
insts::OP_SH => Stype(i).into(),
insts::OP_SW => Stype(i).into(),
insts::OP_SD => Stype(i).into(),
insts::OP_BEQ => Stype(i).into(),
insts::OP_BNE => Stype(i).into(),
insts::OP_BLT => Stype(i).into(),
insts::OP_BGE => Stype(i).into(),
insts::OP_BLTU => Stype(i).into(),
insts::OP_BGEU => Stype(i).into(),
insts::OP_LUI => Utype(i).into(),
insts::OP_AUIPC => Utype(i).into(),
insts::OP_JAL => Utype(i).into(),
insts::OP_MUL => Rtype(i).into(),
insts::OP_MULW => Rtype(i).into(),
insts::OP_MULH => Rtype(i).into(),
insts::OP_MULHSU => Rtype(i).into(),
insts::OP_MULHU => Rtype(i).into(),
insts::OP_DIV => Rtype(i).into(),
insts::OP_DIVW => Rtype(i).into(),
insts::OP_DIVU => Rtype(i).into(),
insts::OP_DIVUW => Rtype(i).into(),
insts::OP_REM => Rtype(i).into(),
insts::OP_REMW => Rtype(i).into(),
insts::OP_REMU => Rtype(i).into(),
insts::OP_REMUW => Rtype(i).into(),
insts::OP_LR_W => Rtype(i).into(),
insts::OP_SC_W => Rtype(i).into(),
insts::OP_AMOSWAP_W => Rtype(i).into(),
insts::OP_AMOADD_W => Rtype(i).into(),
insts::OP_AMOXOR_W => Rtype(i).into(),
insts::OP_AMOAND_W => Rtype(i).into(),
insts::OP_AMOOR_W => Rtype(i).into(),
insts::OP_AMOMIN_W => Rtype(i).into(),
insts::OP_AMOMAX_W => Rtype(i).into(),
insts::OP_AMOMINU_W => Rtype(i).into(),
insts::OP_AMOMAXU_W => Rtype(i).into(),
insts::OP_LR_D => Rtype(i).into(),
insts::OP_SC_D => Rtype(i).into(),
insts::OP_AMOSWAP_D => Rtype(i).into(),
insts::OP_AMOADD_D => Rtype(i).into(),
insts::OP_AMOXOR_D => Rtype(i).into(),
insts::OP_AMOAND_D => Rtype(i).into(),
insts::OP_AMOOR_D => Rtype(i).into(),
insts::OP_AMOMIN_D => Rtype(i).into(),
insts::OP_AMOMAX_D => Rtype(i).into(),
insts::OP_AMOMINU_D => Rtype(i).into(),
insts::OP_AMOMAXU_D => Rtype(i).into(),
insts::OP_ADDUW => Rtype(i).into(),
insts::OP_ANDN => Rtype(i).into(),
insts::OP_BCLR => Rtype(i).into(),
insts::OP_BCLRI => Itype(i).into(),
insts::OP_BEXT => Rtype(i).into(),
insts::OP_BEXTI => Itype(i).into(),
insts::OP_BINV => Rtype(i).into(),
insts::OP_BINVI => Itype(i).into(),
insts::OP_BSET => Rtype(i).into(),
insts::OP_BSETI => Itype(i).into(),
insts::OP_CLMUL => Rtype(i).into(),
insts::OP_CLMULH => Rtype(i).into(),
insts::OP_CLMULR => Rtype(i).into(),
insts::OP_CLZ => Rtype(i).into(),
insts::OP_CLZW => Rtype(i).into(),
insts::OP_CPOP => Rtype(i).into(),
insts::OP_CPOPW => Rtype(i).into(),
insts::OP_CTZ => Rtype(i).into(),
insts::OP_CTZW => Rtype(i).into(),
insts::OP_MAX => Rtype(i).into(),
insts::OP_MAXU => Rtype(i).into(),
insts::OP_MIN => Rtype(i).into(),
insts::OP_MINU => Rtype(i).into(),
insts::OP_ORCB => Rtype(i).into(),
insts::OP_ORN => Rtype(i).into(),
insts::OP_REV8 => Rtype(i).into(),
insts::OP_ROL => Rtype(i).into(),
insts::OP_ROLW => Rtype(i).into(),
insts::OP_ROR => Rtype(i).into(),
insts::OP_RORI => Itype(i).into(),
insts::OP_RORIW => Itype(i).into(),
insts::OP_RORW => Rtype(i).into(),
insts::OP_SEXTB => Rtype(i).into(),
insts::OP_SEXTH => Rtype(i).into(),
insts::OP_SH1ADD => Rtype(i).into(),
insts::OP_SH1ADDUW => Rtype(i).into(),
insts::OP_SH2ADD => Rtype(i).into(),
insts::OP_SH2ADDUW => Rtype(i).into(),
insts::OP_SH3ADD => Rtype(i).into(),
insts::OP_SH3ADDUW => Rtype(i).into(),
insts::OP_SLLIUW => Itype(i).into(),
insts::OP_XNOR => Rtype(i).into(),
insts::OP_ZEXTH => Rtype(i).into(),
insts::OP_WIDE_MUL => R4type(i).into(),
insts::OP_WIDE_MULU => R4type(i).into(),
insts::OP_WIDE_MULSU => R4type(i).into(),
insts::OP_WIDE_DIV => R4type(i).into(),
insts::OP_WIDE_DIVU => R4type(i).into(),
insts::OP_FAR_JUMP_REL => Utype(i).into(),
insts::OP_FAR_JUMP_ABS => Utype(i).into(),
insts::OP_ADC => Rtype(i).into(),
insts::OP_SBB => R4type(i).into(),
insts::OP_ADCS => R4type(i).into(),
insts::OP_SBBS => R4type(i).into(),
insts::OP_ADD3A => R5type(i).into(),
insts::OP_ADD3B => R5type(i).into(),
insts::OP_ADD3C => R5type(i).into(),
insts::OP_CUSTOM_LOAD_UIMM => Utype(i).into(),
insts::OP_CUSTOM_LOAD_IMM => Utype(i).into(),
_ => return Err(Error::InvalidOp(op)),
};
Ok(tagged_inst)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::instructions::{blank_instruction, instruction_opcode_name};
#[test]
fn test_all_valid_opcodes_convert_to_tagged_instruction() {
for i in insts::OP_UNLOADED..=insts::OP_CUSTOM_TRACE_END {
let inst = blank_instruction(i);
let result = TaggedInstruction::try_from(inst);
assert!(
result.is_ok(),
"TaggedInstruction does not handle opcode {}({})!",
i,
instruction_opcode_name(i)
);
}
}
}