diff --git a/Cargo.toml b/Cargo.toml index 18296c9..0bea202 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "raki" -version = "1.2.0" +version = "1.3.0" edition = "2021" authors = ["Norimasa Takana "] repository = "https://github.com/Alignof/raki" diff --git a/src/decode.rs b/src/decode.rs index 9c2348b..7c05a47 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -3,6 +3,17 @@ mod inst_16; mod inst_32; +mod a_extension; +mod base_i; +mod c_extension; +mod m_extension; +mod priv_extension; +mod zicboz_extension; +mod zicfiss_extension; +mod zicntr_extension; +mod zicsr_extension; +mod zifencei_extension; + use crate::instruction::{Instruction, Opcode, OpcodeKind}; use crate::{Extensions, Isa}; diff --git a/src/decode/a_extension.rs b/src/decode/a_extension.rs new file mode 100644 index 0000000..2ac786b --- /dev/null +++ b/src/decode/a_extension.rs @@ -0,0 +1,215 @@ +pub mod bit_32 { + use super::super::{only_rv64, DecodeUtil, DecodingError}; + use crate::instruction::a_extension::AOpcode; + use crate::Isa; + + pub fn parse_opcode(inst: u32, isa: Isa) -> Result { + let opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); + let funct3: u8 = u8::try_from(inst.slice(14, 12)).unwrap(); + let funct7: u8 = u8::try_from(inst.slice(31, 27)).unwrap(); + + match opmap { + 0b010_1111 => match funct3 { + 0b010 => match funct7 { + 0b00010 => Ok(AOpcode::LR_W), + 0b00011 => Ok(AOpcode::SC_W), + 0b00001 => Ok(AOpcode::AMOSWAP_W), + 0b00000 => Ok(AOpcode::AMOADD_W), + 0b00100 => Ok(AOpcode::AMOXOR_W), + 0b01100 => Ok(AOpcode::AMOAND_W), + 0b01000 => Ok(AOpcode::AMOOR_W), + 0b10000 => Ok(AOpcode::AMOMIN_W), + 0b10100 => Ok(AOpcode::AMOMAX_W), + 0b11000 => Ok(AOpcode::AMOMINU_W), + 0b11100 => Ok(AOpcode::AMOMAXU_W), + _ => Err(DecodingError::InvalidFunct7), + }, + 0b011 => match funct7 { + 0b00010 => only_rv64(AOpcode::LR_D, isa), + 0b00011 => only_rv64(AOpcode::SC_D, isa), + 0b00001 => only_rv64(AOpcode::AMOSWAP_D, isa), + 0b00000 => only_rv64(AOpcode::AMOADD_D, isa), + 0b00100 => only_rv64(AOpcode::AMOXOR_D, isa), + 0b01100 => only_rv64(AOpcode::AMOAND_D, isa), + 0b01000 => only_rv64(AOpcode::AMOOR_D, isa), + 0b10000 => only_rv64(AOpcode::AMOMIN_D, isa), + 0b10100 => only_rv64(AOpcode::AMOMAX_D, isa), + 0b11000 => only_rv64(AOpcode::AMOMINU_D, isa), + 0b11100 => only_rv64(AOpcode::AMOMAXU_D, isa), + _ => Err(DecodingError::InvalidFunct7), + }, + _ => Err(DecodingError::InvalidFunct3), + }, + _ => Err(DecodingError::InvalidOpcode), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rd(inst: u32, opkind: &AOpcode) -> Option { + let rd: usize = inst.slice(11, 7) as usize; + + match opkind { + AOpcode::LR_W + | AOpcode::SC_W + | AOpcode::AMOSWAP_W + | AOpcode::AMOADD_W + | AOpcode::AMOXOR_W + | AOpcode::AMOAND_W + | AOpcode::AMOOR_W + | AOpcode::AMOMIN_W + | AOpcode::AMOMAX_W + | AOpcode::AMOMINU_W + | AOpcode::AMOMAXU_W + | AOpcode::LR_D + | AOpcode::SC_D + | AOpcode::AMOSWAP_D + | AOpcode::AMOADD_D + | AOpcode::AMOXOR_D + | AOpcode::AMOAND_D + | AOpcode::AMOOR_D + | AOpcode::AMOMIN_D + | AOpcode::AMOMAX_D + | AOpcode::AMOMINU_D + | AOpcode::AMOMAXU_D => Some(rd), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rs1(inst: u32, opkind: &AOpcode) -> Option { + let rs1: usize = inst.slice(19, 15) as usize; + + match opkind { + AOpcode::LR_W + | AOpcode::SC_W + | AOpcode::AMOSWAP_W + | AOpcode::AMOADD_W + | AOpcode::AMOXOR_W + | AOpcode::AMOAND_W + | AOpcode::AMOOR_W + | AOpcode::AMOMIN_W + | AOpcode::AMOMAX_W + | AOpcode::AMOMINU_W + | AOpcode::AMOMAXU_W + | AOpcode::LR_D + | AOpcode::SC_D + | AOpcode::AMOSWAP_D + | AOpcode::AMOADD_D + | AOpcode::AMOXOR_D + | AOpcode::AMOAND_D + | AOpcode::AMOOR_D + | AOpcode::AMOMIN_D + | AOpcode::AMOMAX_D + | AOpcode::AMOMINU_D + | AOpcode::AMOMAXU_D => Some(rs1), + } + } + + pub fn parse_rs2(inst: u32, opkind: &AOpcode) -> Option { + let rs2: usize = inst.slice(24, 20) as usize; + + match opkind { + AOpcode::SC_W + | AOpcode::AMOSWAP_W + | AOpcode::AMOADD_W + | AOpcode::AMOXOR_W + | AOpcode::AMOAND_W + | AOpcode::AMOOR_W + | AOpcode::AMOMIN_W + | AOpcode::AMOMAX_W + | AOpcode::AMOMINU_W + | AOpcode::AMOMAXU_W + | AOpcode::SC_D + | AOpcode::AMOSWAP_D + | AOpcode::AMOADD_D + | AOpcode::AMOXOR_D + | AOpcode::AMOAND_D + | AOpcode::AMOOR_D + | AOpcode::AMOMIN_D + | AOpcode::AMOMAX_D + | AOpcode::AMOMINU_D + | AOpcode::AMOMAXU_D => Some(rs2), + _ => None, + } + } + + #[allow(non_snake_case)] + #[allow(clippy::unnecessary_wraps, clippy::cast_possible_wrap)] + pub fn parse_imm(inst: u32, opkind: &AOpcode) -> Option { + let aq_and_rl = || inst.slice(26, 25) as i32; + + match opkind { + AOpcode::LR_W + | AOpcode::SC_W + | AOpcode::AMOSWAP_W + | AOpcode::AMOADD_W + | AOpcode::AMOXOR_W + | AOpcode::AMOAND_W + | AOpcode::AMOOR_W + | AOpcode::AMOMIN_W + | AOpcode::AMOMAX_W + | AOpcode::AMOMINU_W + | AOpcode::AMOMAXU_W + | AOpcode::LR_D + | AOpcode::SC_D + | AOpcode::AMOSWAP_D + | AOpcode::AMOADD_D + | AOpcode::AMOXOR_D + | AOpcode::AMOAND_D + | AOpcode::AMOOR_D + | AOpcode::AMOMIN_D + | AOpcode::AMOMAX_D + | AOpcode::AMOMINU_D + | AOpcode::AMOMAXU_D => Some(aq_and_rl()), + } + } +} + +#[cfg(test)] +#[allow(unused_variables)] +mod test_a { + #[test] + #[allow(overflowing_literals)] + fn a_decode_test() { + use crate::instruction::a_extension::AOpcode; + use crate::{Decode, Isa, OpcodeKind}; + + let test_32 = |inst_32: u32, + op: OpcodeKind, + rd: Option, + rs1: Option, + rs2: Option, + imm: Option| { + let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap(); + assert!(matches!(&op_32, op)); + assert_eq!(inst_32.parse_rd(&op_32).unwrap(), rd); + assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), rs1); + assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), rs2); + assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), imm); + }; + + test_32( + 0x04d7_27af, + OpcodeKind::A(AOpcode::AMOADD_W), + Some(15), + Some(14), + Some(13), + Some(2), + ); + test_32( + 0x1007b62f, + OpcodeKind::A(AOpcode::LR_D), + Some(12), + Some(15), + None, + Some(0), + ); + test_32( + 0x60f6302f, + OpcodeKind::A(AOpcode::AMOAND_D), + Some(0), + Some(12), + Some(15), + Some(0), + ); + } +} diff --git a/src/decode/base_i.rs b/src/decode/base_i.rs new file mode 100644 index 0000000..eb6ffd4 --- /dev/null +++ b/src/decode/base_i.rs @@ -0,0 +1,476 @@ +pub mod bit_32 { + use super::super::{only_rv64, DecodeUtil, DecodingError}; + use crate::instruction::base_i::BaseIOpcode; + use crate::Isa; + + #[allow(clippy::too_many_lines)] + pub fn parse_opcode(inst: u32, isa: Isa) -> Result { + let opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); + let funct3: u8 = u8::try_from(inst.slice(14, 12)).unwrap(); + let funct5: u8 = u8::try_from(inst.slice(24, 20)).unwrap(); + let funct6: u8 = u8::try_from(inst.slice(31, 26)).unwrap(); + let funct7: u8 = u8::try_from(inst.slice(31, 25)).unwrap(); + + match opmap { + 0b011_0111 => Ok(BaseIOpcode::LUI), + 0b001_0111 => Ok(BaseIOpcode::AUIPC), + 0b110_1111 => Ok(BaseIOpcode::JAL), + 0b110_0111 => Ok(BaseIOpcode::JALR), + 0b110_0011 => match funct3 { + 0b000 => Ok(BaseIOpcode::BEQ), + 0b001 => Ok(BaseIOpcode::BNE), + 0b100 => Ok(BaseIOpcode::BLT), + 0b101 => Ok(BaseIOpcode::BGE), + 0b110 => Ok(BaseIOpcode::BLTU), + 0b111 => Ok(BaseIOpcode::BGEU), + _ => Err(DecodingError::InvalidFunct3), + }, + 0b000_0011 => match funct3 { + 0b000 => Ok(BaseIOpcode::LB), + 0b001 => Ok(BaseIOpcode::LH), + 0b010 => Ok(BaseIOpcode::LW), + 0b011 => only_rv64(BaseIOpcode::LD, isa), + 0b100 => Ok(BaseIOpcode::LBU), + 0b101 => Ok(BaseIOpcode::LHU), + 0b110 => only_rv64(BaseIOpcode::LWU, isa), + _ => Err(DecodingError::InvalidFunct3), + }, + 0b010_0011 => match funct3 { + 0b000 => Ok(BaseIOpcode::SB), + 0b001 => Ok(BaseIOpcode::SH), + 0b010 => Ok(BaseIOpcode::SW), + 0b011 => only_rv64(BaseIOpcode::SD, isa), + _ => Err(DecodingError::InvalidFunct3), + }, + 0b001_0011 => match funct3 { + 0b000 => Ok(BaseIOpcode::ADDI), + 0b001 => match isa { + Isa::Rv32 => match funct7 { + 0b000_0000 => Ok(BaseIOpcode::SLLI), + _ => Err(DecodingError::InvalidFunct7), + }, + Isa::Rv64 => match funct6 { + 0b00_0000 => Ok(BaseIOpcode::SLLI), + _ => Err(DecodingError::InvalidFunct6), + }, + }, + 0b010 => Ok(BaseIOpcode::SLTI), + 0b011 => Ok(BaseIOpcode::SLTIU), + 0b100 => Ok(BaseIOpcode::XORI), + 0b101 => match isa { + Isa::Rv32 => match funct7 { + 0b000_0000 => Ok(BaseIOpcode::SRLI), + 0b010_0000 => Ok(BaseIOpcode::SRAI), + _ => Err(DecodingError::InvalidFunct7), + }, + Isa::Rv64 => match funct6 { + 0b00_0000 => Ok(BaseIOpcode::SRLI), + 0b01_0000 => Ok(BaseIOpcode::SRAI), + _ => Err(DecodingError::InvalidFunct6), + }, + }, + 0b110 => Ok(BaseIOpcode::ORI), + 0b111 => Ok(BaseIOpcode::ANDI), + _ => Err(DecodingError::InvalidFunct3), + }, + 0b011_0011 => match funct3 { + 0b000 => match funct7 { + 0b000_0000 => Ok(BaseIOpcode::ADD), + 0b010_0000 => Ok(BaseIOpcode::SUB), + _ => Err(DecodingError::InvalidFunct7), + }, + 0b001 => Ok(BaseIOpcode::SLL), + 0b010 => Ok(BaseIOpcode::SLT), + 0b011 => Ok(BaseIOpcode::SLTU), + 0b100 => Ok(BaseIOpcode::XOR), + 0b101 => match funct7 { + 0b000_0000 => Ok(BaseIOpcode::SRL), + 0b010_0000 => Ok(BaseIOpcode::SRA), + _ => Err(DecodingError::InvalidFunct7), + }, + 0b110 => Ok(BaseIOpcode::OR), + 0b111 => Ok(BaseIOpcode::AND), + _ => Err(DecodingError::InvalidFunct3), + }, + 0b111_0011 => match funct3 { + 0b000 => match funct7 { + 0b000_0000 => match funct5 { + 0b00000 => Ok(BaseIOpcode::ECALL), + 0b00001 => Ok(BaseIOpcode::EBREAK), + _ => Err(DecodingError::InvalidFunct5), + }, + _ => Err(DecodingError::InvalidFunct7), + }, + _ => Err(DecodingError::InvalidFunct3), + }, + 0b001_1011 => match funct3 { + 0b000 => only_rv64(BaseIOpcode::ADDIW, isa), + 0b001 => only_rv64(BaseIOpcode::SLLIW, isa), + 0b101 => match funct7 { + 0b000_0000 => only_rv64(BaseIOpcode::SRLIW, isa), + 0b010_0000 => only_rv64(BaseIOpcode::SRAIW, isa), + _ => Err(DecodingError::InvalidFunct7), + }, + _ => Err(DecodingError::InvalidFunct3), + }, + 0b011_1011 => match funct3 { + 0b000 => match funct7 { + 0b000_0000 => only_rv64(BaseIOpcode::ADDW, isa), + 0b010_0000 => only_rv64(BaseIOpcode::SUBW, isa), + _ => Err(DecodingError::InvalidFunct7), + }, + 0b001 => only_rv64(BaseIOpcode::SLLW, isa), + 0b101 => match funct7 { + 0b000_0000 => only_rv64(BaseIOpcode::SRLW, isa), + 0b010_0000 => only_rv64(BaseIOpcode::SRAW, isa), + _ => Err(DecodingError::InvalidFunct7), + }, + _ => Err(DecodingError::InvalidFunct3), + }, + _ => Err(DecodingError::InvalidOpcode), + } + } + + pub fn parse_rd(inst: u32, opkind: &BaseIOpcode) -> Option { + let rd: usize = inst.slice(11, 7) as usize; + + // B(EQ|NE|LT|GE|LTU|GEU), S(B|H|W), ECALL, EBREAK + match opkind { + BaseIOpcode::LUI + | BaseIOpcode::AUIPC + | BaseIOpcode::JAL + | BaseIOpcode::JALR + | BaseIOpcode::LB + | BaseIOpcode::LH + | BaseIOpcode::LW + | BaseIOpcode::LBU + | BaseIOpcode::LHU + | BaseIOpcode::ADDI + | BaseIOpcode::SLTI + | BaseIOpcode::SLTIU + | BaseIOpcode::XORI + | BaseIOpcode::ORI + | BaseIOpcode::ANDI + | BaseIOpcode::SLLI + | BaseIOpcode::SRLI + | BaseIOpcode::SRAI + | BaseIOpcode::ADD + | BaseIOpcode::SUB + | BaseIOpcode::SLL + | BaseIOpcode::SLT + | BaseIOpcode::SLTU + | BaseIOpcode::XOR + | BaseIOpcode::SRL + | BaseIOpcode::SRA + | BaseIOpcode::OR + | BaseIOpcode::AND + | BaseIOpcode::LWU + | BaseIOpcode::LD + | BaseIOpcode::ADDIW + | BaseIOpcode::SLLIW + | BaseIOpcode::SRLIW + | BaseIOpcode::SRAIW + | BaseIOpcode::ADDW + | BaseIOpcode::SUBW + | BaseIOpcode::SLLW + | BaseIOpcode::SRLW + | BaseIOpcode::SRAW => Some(rd), + _ => None, + } + } + + pub fn parse_rs1(inst: u32, opkind: &BaseIOpcode) -> Option { + let rs1: usize = inst.slice(19, 15) as usize; + + // LUI, AUIPC, JAL, FENCE, ECALL, EBREAK + match opkind { + BaseIOpcode::JALR + | BaseIOpcode::BEQ + | BaseIOpcode::BNE + | BaseIOpcode::BLT + | BaseIOpcode::BGE + | BaseIOpcode::BLTU + | BaseIOpcode::BGEU + | BaseIOpcode::LB + | BaseIOpcode::LH + | BaseIOpcode::LW + | BaseIOpcode::LBU + | BaseIOpcode::LHU + | BaseIOpcode::SB + | BaseIOpcode::SH + | BaseIOpcode::SW + | BaseIOpcode::ADDI + | BaseIOpcode::SLTI + | BaseIOpcode::SLTIU + | BaseIOpcode::XORI + | BaseIOpcode::ORI + | BaseIOpcode::ANDI + | BaseIOpcode::SLLI + | BaseIOpcode::SRLI + | BaseIOpcode::SRAI + | BaseIOpcode::ADD + | BaseIOpcode::SUB + | BaseIOpcode::SLL + | BaseIOpcode::SLT + | BaseIOpcode::SLTU + | BaseIOpcode::XOR + | BaseIOpcode::SRL + | BaseIOpcode::SRA + | BaseIOpcode::OR + | BaseIOpcode::AND + | BaseIOpcode::LWU + | BaseIOpcode::LD + | BaseIOpcode::SD + | BaseIOpcode::ADDIW + | BaseIOpcode::SLLIW + | BaseIOpcode::SRLIW + | BaseIOpcode::SRAIW + | BaseIOpcode::ADDW + | BaseIOpcode::SUBW + | BaseIOpcode::SLLW + | BaseIOpcode::SRLW + | BaseIOpcode::SRAW => Some(rs1), + _ => None, + } + } + + pub fn parse_rs2(inst: u32, opkind: &BaseIOpcode) -> Option { + let rs2: usize = inst.slice(24, 20) as usize; + + // LUI, AUIPC, JAL, JALR L(B|H|W|BU|HU), + // ADDI, SLTI, SLTIU, XORI, ORI, ANDI, SLLI, + // FENCE, ECALL, EBREAK + match opkind { + BaseIOpcode::BEQ + | BaseIOpcode::BNE + | BaseIOpcode::BLT + | BaseIOpcode::BGE + | BaseIOpcode::BLTU + | BaseIOpcode::BGEU + | BaseIOpcode::SB + | BaseIOpcode::SH + | BaseIOpcode::SW + | BaseIOpcode::ADD + | BaseIOpcode::SUB + | BaseIOpcode::SLL + | BaseIOpcode::SLT + | BaseIOpcode::SLTU + | BaseIOpcode::XOR + | BaseIOpcode::SRL + | BaseIOpcode::SRA + | BaseIOpcode::OR + | BaseIOpcode::AND + | BaseIOpcode::SD + | BaseIOpcode::ADDW + | BaseIOpcode::SUBW + | BaseIOpcode::SLLW + | BaseIOpcode::SRLW + | BaseIOpcode::SRAW => Some(rs2), + _ => None, + } + } + + #[allow(clippy::cast_possible_wrap)] + #[allow(non_snake_case)] + pub fn parse_imm(inst: u32, opkind: &BaseIOpcode, isa: Isa) -> Option { + let U_type = || (inst.slice(31, 12) << 12) as i32; + let I_type = || { + let imm32 = inst.slice(31, 20) as i32; + inst.to_signed_nbit(imm32, 12) + }; + let S_type = || { + let imm32 = (inst.slice(11, 7).set(&[4, 3, 2, 1, 0]) + | inst.slice(31, 25).set(&[11, 10, 9, 8, 7, 6, 5])) as i32; + inst.to_signed_nbit(imm32, 12) + }; + let B_type = || { + let imm32 = (inst.slice(11, 7).set(&[4, 3, 2, 1, 11]) + | inst.slice(31, 25).set(&[12, 10, 9, 8, 7, 6, 5])) as i32; + inst.to_signed_nbit(imm32, 13) + }; + let J_type = || { + let imm32 = inst.slice(31, 12).set(&[ + 20, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 11, 19, 18, 17, 16, 15, 14, 13, 12, + ]) as i32; + inst.to_signed_nbit(imm32, 21) + }; + let shamt5 = || inst.slice(24, 20); // shamt = SHift AMounT + let shamt6 = || inst.slice(25, 20); + + match opkind { + // u-type + BaseIOpcode::LUI | BaseIOpcode::AUIPC => Some(U_type()), + // j-type + BaseIOpcode::JAL => Some(J_type()), + // b-type + BaseIOpcode::BEQ + | BaseIOpcode::BNE + | BaseIOpcode::BLT + | BaseIOpcode::BGE + | BaseIOpcode::BLTU + | BaseIOpcode::BGEU => Some(B_type()), + // i-type + BaseIOpcode::JALR + | BaseIOpcode::LB + | BaseIOpcode::LH + | BaseIOpcode::LW + | BaseIOpcode::LBU + | BaseIOpcode::LHU + | BaseIOpcode::ADDI + | BaseIOpcode::SLTI + | BaseIOpcode::SLTIU + | BaseIOpcode::XORI + | BaseIOpcode::ORI + | BaseIOpcode::ANDI + | BaseIOpcode::LWU + | BaseIOpcode::ADDIW + | BaseIOpcode::LD => Some(I_type()), + // s-type + BaseIOpcode::SD | BaseIOpcode::SB | BaseIOpcode::SH | BaseIOpcode::SW => Some(S_type()), + BaseIOpcode::SRAI | BaseIOpcode::SLLI | BaseIOpcode::SRLI => match isa { + Isa::Rv32 => Some(shamt5() as i32), // shamt + Isa::Rv64 => Some(shamt6() as i32), + }, + BaseIOpcode::SLLIW | BaseIOpcode::SRLIW | BaseIOpcode::SRAIW => Some(shamt5() as i32), + _ => None, + } + } +} + +#[cfg(test)] +#[allow(unused_variables)] +mod test_basei { + #[test] + #[allow(overflowing_literals)] + fn basei_decode_test() { + use crate::instruction::base_i::BaseIOpcode; + use crate::{Decode, Isa, OpcodeKind}; + + let test_32 = |inst_32: u32, + op: OpcodeKind, + rd: Option, + rs1: Option, + rs2: Option, + imm: Option| { + let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap(); + assert!(matches!(&op_32, op)); + assert_eq!(inst_32.parse_rd(&op_32).unwrap(), rd); + assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), rs1); + assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), rs2); + assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), imm); + }; + + test_32( + 0b1000_0000_0000_0000_0000_0000_1011_0111, + OpcodeKind::BaseI(BaseIOpcode::LUI), + Some(1), + None, + None, + Some(0x8000_0000), + ); + test_32( + 0b0000_0000_0000_0000_0000_0010_1001_0111, + OpcodeKind::BaseI(BaseIOpcode::AUIPC), + Some(5), + None, + None, + Some(0), + ); + test_32( + 0b1111_1111_1001_1111_1111_0000_0110_1111, + OpcodeKind::BaseI(BaseIOpcode::JAL), + Some(0), + None, + None, + Some(-8), + ); + test_32( + 0b1111_1110_0010_0000_1000_1110_1010_0011, + OpcodeKind::BaseI(BaseIOpcode::SB), + None, + Some(1), + Some(2), + Some(-3), + ); + test_32( + 0b1110_1110_1100_0010_1000_0010_1001_0011, + OpcodeKind::BaseI(BaseIOpcode::ADDI), + Some(5), + Some(5), + None, + Some(-276), + ); + test_32( + 0b0000_0000_0000_0000_0000_0000_0111_0011, + OpcodeKind::BaseI(BaseIOpcode::ECALL), + None, + None, + None, + None, + ); + test_32( + 0b0000_0000_0000_0101_0100_1100_0110_0011, + OpcodeKind::BaseI(BaseIOpcode::BLT), + None, + Some(10), + Some(0), + Some(24), + ); + test_32( + 0x0010_0513, + OpcodeKind::BaseI(BaseIOpcode::ADDI), + Some(10), + Some(0), + None, + Some(1), + ); + test_32( + 0x4170_04b3, + OpcodeKind::BaseI(BaseIOpcode::SUB), + Some(9), + Some(0), + Some(23), + None, + ); + test_32( + 0x3307_3983, + OpcodeKind::BaseI(BaseIOpcode::LD), + Some(19), + Some(14), + None, + Some(816), + ); + test_32( + 0x10ec_eb63, + OpcodeKind::BaseI(BaseIOpcode::BLTU), + None, + Some(25), + Some(14), + Some(278), + ); + test_32( + 0x31e1_60ef, + OpcodeKind::BaseI(BaseIOpcode::JAL), + Some(1), + None, + None, + Some(90910), + ); + test_32( + 0x0019_4913, + OpcodeKind::BaseI(BaseIOpcode::XORI), + Some(18), + Some(18), + None, + Some(1), + ); + test_32( + 0x00a9_3933, + OpcodeKind::BaseI(BaseIOpcode::SLTU), + Some(18), + Some(18), + Some(10), + None, + ); + } +} diff --git a/src/decode/c_extension.rs b/src/decode/c_extension.rs new file mode 100644 index 0000000..4735ca6 --- /dev/null +++ b/src/decode/c_extension.rs @@ -0,0 +1,384 @@ +pub mod bit_16 { + use super::super::{only_rv64, DecodeUtil, DecodingError}; + use crate::instruction::c_extension::COpcode; + use crate::Isa; + + fn quadrant0(_inst: u16, opmap: u8, isa: Isa) -> Result { + match opmap { + 0b000 => Ok(COpcode::ADDI4SPN), + 0b010 => Ok(COpcode::LW), + 0b011 => only_rv64(COpcode::LD, isa), + 0b110 => Ok(COpcode::SW), + 0b111 => only_rv64(COpcode::SD, isa), + _ => Err(DecodingError::InvalidOpcode), + } + } + + fn quadrant1(inst: u16, opmap: u8, isa: Isa) -> Result { + let sr_flag: u8 = u8::try_from(inst.slice(11, 10)).unwrap(); + let lo_flag: u8 = u8::try_from(inst.slice(6, 5)).unwrap(); + let mi_flag: u8 = u8::try_from(inst.slice(11, 7)).unwrap(); + let bit_12: u8 = u8::try_from(inst.slice(12, 12)).unwrap(); + + match opmap { + 0b000 => match mi_flag { + 0b00000 => Ok(COpcode::NOP), + _ => Ok(COpcode::ADDI), + }, + 0b001 => match isa { + Isa::Rv32 => Ok(COpcode::JAL), + Isa::Rv64 => Ok(COpcode::ADDIW), + }, + 0b010 => Ok(COpcode::LI), + 0b011 => match mi_flag { + 0b00010 => Ok(COpcode::ADDI16SP), + _ => Ok(COpcode::LUI), + }, + 0b100 => match sr_flag { + 0b00 => Ok(COpcode::SRLI), + 0b01 => Ok(COpcode::SRAI), + 0b10 => Ok(COpcode::ANDI), + 0b11 => match bit_12 { + 0b0 => match lo_flag { + 0b00 => Ok(COpcode::SUB), + 0b01 => Ok(COpcode::XOR), + 0b10 => Ok(COpcode::OR), + 0b11 => Ok(COpcode::AND), + _ => Err(DecodingError::InvalidOpcode), + }, + 0b1 => match lo_flag { + 0b00 => only_rv64(COpcode::SUBW, isa), + 0b01 => only_rv64(COpcode::ADDW, isa), + _ => Err(DecodingError::InvalidOpcode), + }, + _ => unreachable!(), + }, + _ => Err(DecodingError::InvalidOpcode), + }, + 0b101 => Ok(COpcode::J), + 0b110 => Ok(COpcode::BEQZ), + 0b111 => Ok(COpcode::BNEZ), + _ => Err(DecodingError::InvalidOpcode), + } + } + + fn quadrant2(inst: u16, opmap: u8, isa: Isa) -> Result { + let lo_flag: u8 = u8::try_from(inst.slice(6, 2)).unwrap(); + let mi_flag: u8 = u8::try_from(inst.slice(11, 7)).unwrap(); + let hi_flag: u8 = u8::try_from(inst.slice(12, 12)).unwrap(); + + match opmap { + 0b000 => Ok(COpcode::SLLI), + 0b010 => Ok(COpcode::LWSP), + 0b011 => only_rv64(COpcode::LDSP, isa), + 0b100 => match hi_flag { + 0b0 => match lo_flag { + 0b0 => Ok(COpcode::JR), + _ => Ok(COpcode::MV), + }, + 0b1 => match mi_flag { + 0b0 => Ok(COpcode::EBREAK), + _ => match lo_flag { + 0b0 => Ok(COpcode::JALR), + _ => Ok(COpcode::ADD), + }, + }, + _ => Err(DecodingError::InvalidOpcode), + }, + 0b110 => Ok(COpcode::SWSP), + 0b111 => only_rv64(COpcode::SDSP, isa), + _ => Err(DecodingError::InvalidOpcode), + } + } + + pub fn parse_opcode(inst: u16, isa: Isa) -> Result { + let opmap: u8 = u8::try_from(inst.slice(15, 13)).unwrap(); + let quadrant: u8 = u8::try_from(inst.slice(1, 0)).unwrap(); + + if inst == 0b0000_0000_0000_0000 { + return Err(DecodingError::InvalidOpcode); + } + + match quadrant { + 0b00 => quadrant0(inst, opmap, isa), + 0b01 => quadrant1(inst, opmap, isa), + 0b10 => quadrant2(inst, opmap, isa), + _ => Err(DecodingError::InvalidOpcode), + } + } + + pub fn parse_rd(inst: u16, opkind: &COpcode) -> Option { + // see riscv-spec-20191213.pdf, page 100, Table 16.2 + let q0_rd: usize = (inst.slice(4, 2) + 8) as usize; + let q1_rd: usize = (inst.slice(9, 7) + 8) as usize; + let q1_wide_rd: usize = inst.slice(11, 7) as usize; + let q2_rd: usize = inst.slice(11, 7) as usize; + + match opkind { + // Quadrant 0 + COpcode::ADDI4SPN | COpcode::LW | COpcode::LD => Some(q0_rd), + // Quadrant 1 + COpcode::SRLI + | COpcode::SRAI + | COpcode::ANDI + | COpcode::SUB + | COpcode::XOR + | COpcode::OR + | COpcode::AND + | COpcode::ADDW + | COpcode::SUBW => Some(q1_rd), + COpcode::LI | COpcode::LUI | COpcode::ADDI | COpcode::ADDIW | COpcode::ADDI16SP => { + Some(q1_wide_rd) + } + // Quadrant 2 + COpcode::SLLI | COpcode::LWSP | COpcode::LDSP | COpcode::MV | COpcode::ADD => { + Some(q2_rd) + } + _ => None, + } + } + + pub fn parse_rs1(inst: u16, opkind: &COpcode) -> Option { + // see riscv-spec-20191213.pdf, page 100, Table 16.2 + let q0_rs1: usize = (inst.slice(9, 7) + 8) as usize; + let q1_rs1: usize = (inst.slice(9, 7) + 8) as usize; + let q1_addi_rs1: usize = inst.slice(11, 7) as usize; + let q2_rs1: usize = inst.slice(11, 7) as usize; + + match opkind { + // Quadrant 0 + COpcode::LW | COpcode::LD | COpcode::SW | COpcode::SD => Some(q0_rs1), + // Quadrant 1 + COpcode::ADDI | COpcode::ADDIW | COpcode::ADDI16SP => Some(q1_addi_rs1), + COpcode::SRLI + | COpcode::SRAI + | COpcode::ANDI + | COpcode::SUB + | COpcode::XOR + | COpcode::OR + | COpcode::AND + | COpcode::BEQZ + | COpcode::BNEZ + | COpcode::SUBW + | COpcode::ADDW => Some(q1_rs1), + // Quadrant 2 + COpcode::SLLI | COpcode::JR | COpcode::JALR | COpcode::ADD => Some(q2_rs1), + _ => None, + } + } + + pub fn parse_rs2(inst: u16, opkind: &COpcode) -> Option { + // see riscv-spec-20191213.pdf, page 100, Table 16.2 + let q0_rs2: usize = (inst.slice(4, 2) + 8) as usize; + let q1_rs2: usize = (inst.slice(4, 2) + 8) as usize; + let q2_rs2: usize = inst.slice(6, 2) as usize; + + match opkind { + // Quadrant 0 + COpcode::SW | COpcode::SD => Some(q0_rs2), + // Quadrant 1 + COpcode::SUB + | COpcode::XOR + | COpcode::OR + | COpcode::AND + | COpcode::SUBW + | COpcode::ADDW => Some(q1_rs2), + // Quadrant 2 + COpcode::JR + | COpcode::JALR + | COpcode::MV + | COpcode::ADD + | COpcode::SWSP + | COpcode::SDSP => Some(q2_rs2), + _ => None, + } + } + + #[allow(clippy::cast_possible_wrap)] + #[allow(clippy::similar_names)] + pub fn parse_imm(inst: u16, opkind: &COpcode) -> Option { + let q0_uimm = || (inst.slice(12, 10).set(&[5, 4, 3]) | inst.slice(6, 5).set(&[2, 6])); + let q0_uimm_64 = || (inst.slice(12, 10).set(&[5, 4, 3]) | inst.slice(6, 5).set(&[7, 6])); + let q0_nzuimm = || inst.slice(12, 5).set(&[5, 4, 9, 8, 7, 6, 2, 3]); + let q1_nzuimm = || (inst.slice(6, 2).set(&[4, 3, 2, 1, 0]) | inst.slice(12, 12).set(&[5])); + let q1_nzimm = || { + let imm16 = + (inst.slice(6, 2).set(&[4, 3, 2, 1, 0]) | inst.slice(12, 12).set(&[5])) as i32; + inst.to_signed_nbit(imm16, 6) + }; + let q1_imm = || { + let imm16 = + (inst.slice(6, 2).set(&[4, 3, 2, 1, 0]) | inst.slice(12, 12).set(&[5])) as i32; + inst.to_signed_nbit(imm16, 6) + }; + let q1_j_imm = || { + let imm16 = inst.slice(12, 2).set(&[11, 4, 9, 8, 10, 6, 7, 3, 2, 1, 5]) as i32; + inst.to_signed_nbit(imm16, 12) + }; + let q1_b_imm = || { + let imm16 = (inst.slice(6, 2).set(&[7, 6, 2, 1, 5]) + | inst.slice(12, 10).set(&[8, 4, 3])) as i32; + inst.to_signed_nbit(imm16, 9) + }; + let q1_16sp_nzimm = || { + let imm16 = + (inst.slice(6, 2).set(&[4, 6, 8, 7, 5]) | inst.slice(12, 12).set(&[9])) as i32; + inst.to_signed_nbit(imm16, 10) + }; + let q1_lui_imm = || { + let imm16 = (inst.slice(6, 2).set(&[16, 15, 14, 13, 12]) + | inst.slice(12, 12).set(&[17])) as i32; + inst.to_signed_nbit(imm16, 18) + }; + let q2_imm = + || (inst.slice(6, 2).set(&[4, 3, 2, 1, 0]) | inst.slice(12, 12).set(&[5])) as i32; + let q2_lwsp_imm = + || (inst.slice(6, 2).set(&[4, 3, 2, 7, 6]) | inst.slice(12, 12).set(&[5])) as i32; + let q2_ldsp_imm = + || (inst.slice(6, 2).set(&[4, 3, 8, 7, 6]) | inst.slice(12, 12).set(&[5])) as i32; + let q2_swsp_imm = || inst.slice(12, 7).set(&[5, 4, 3, 2, 7, 6]) as i32; + let q2_sdsp_imm = || inst.slice(12, 7).set(&[5, 4, 3, 8, 7, 6]) as i32; + + match opkind { + // Quadrant0 + COpcode::ADDI4SPN => Some(q0_nzuimm() as i32), + COpcode::LW | COpcode::SW => Some(q0_uimm() as i32), + COpcode::LD | COpcode::SD => Some(q0_uimm_64() as i32), + // Quadrant1 + COpcode::ADDIW | COpcode::LI | COpcode::ANDI => Some(q1_imm()), + COpcode::NOP | COpcode::ADDI => Some(q1_nzimm()), + COpcode::SRLI | COpcode::SRAI => Some(q1_nzuimm() as i32), + COpcode::JAL | COpcode::J => Some(q1_j_imm()), + COpcode::BEQZ | COpcode::BNEZ => Some(q1_b_imm()), + COpcode::LUI => Some(q1_lui_imm()), + COpcode::ADDI16SP => Some(q1_16sp_nzimm()), + // Quadrant2 + COpcode::SLLI => Some(q2_imm()), + COpcode::LWSP => Some(q2_lwsp_imm()), + COpcode::LDSP => Some(q2_ldsp_imm()), + COpcode::SWSP => Some(q2_swsp_imm()), + COpcode::SDSP => Some(q2_sdsp_imm()), + _ => None, + } + } +} + +#[cfg(test)] +#[allow(unused_variables)] +mod test_c { + #[test] + fn c_decode_test() { + use crate::instruction::c_extension::COpcode; + use crate::{Decode, Isa, OpcodeKind}; + let test_16 = |inst_16: u16, + op: OpcodeKind, + rd: Option, + rs1: Option, + rs2: Option, + imm: Option| { + let op_16 = inst_16.parse_opcode(Isa::Rv64).unwrap(); + assert!(matches!(&op_16, op)); + assert_eq!(inst_16.parse_rd(&op_16).unwrap(), rd); + assert_eq!(inst_16.parse_rs1(&op_16).unwrap(), rs1); + assert_eq!(inst_16.parse_rs2(&op_16).unwrap(), rs2); + assert_eq!(inst_16.parse_imm(&op_16, Isa::Rv64).unwrap(), imm); + }; + + test_16( + 0b0000_0000_0000_0001, + OpcodeKind::C(COpcode::NOP), + None, + None, + None, + Some(0), + ); + test_16( + 0b0110_0011_1000_0001, + OpcodeKind::C(COpcode::LUI), + Some(7), + None, + None, + Some(0), + ); + test_16( + 0b1000_0010_1100_0001, + OpcodeKind::C(COpcode::SRAI), + Some(13), + Some(13), + None, + Some(16), + ); + test_16( + 0x4521, + OpcodeKind::C(COpcode::LI), + Some(10), + None, + None, + Some(8), + ); + test_16( + 0xb5e5, + OpcodeKind::C(COpcode::J), + None, + None, + None, + Some(-280), + ); + test_16( + 0x6105, + OpcodeKind::C(COpcode::ADDI), + Some(2), + Some(2), + None, + Some(32), + ); + test_16( + 0x8082, + OpcodeKind::C(COpcode::JR), + None, + Some(1), + Some(0), + None, + ); + test_16( + 0xe29d, + OpcodeKind::C(COpcode::BNEZ), + None, + Some(13), + None, + Some(38), + ); + test_16( + 0xc05c, + OpcodeKind::C(COpcode::SW), + None, + Some(8), + Some(15), + Some(4), + ); + test_16( + 0x9002, + OpcodeKind::C(COpcode::EBREAK), + None, + None, + None, + None, + ); + test_16( + 0x880a, + OpcodeKind::C(COpcode::MV), + Some(16), + None, + Some(2), + None, + ); + test_16( + 0x8585, + OpcodeKind::C(COpcode::SRAI), + Some(11), + Some(11), + None, + Some(1), + ); + } +} diff --git a/src/decode/inst_16.rs b/src/decode/inst_16.rs index 55f3516..55f009b 100644 --- a/src/decode/inst_16.rs +++ b/src/decode/inst_16.rs @@ -1,8 +1,6 @@ -#[allow(non_snake_case)] -mod c_extension; -mod zicfiss_extension; - +use super::{c_extension, zicfiss_extension}; use super::{Decode, DecodeUtil, DecodingError}; + use crate::instruction::{InstFormat, Instruction, OpcodeKind}; use crate::{Extensions, Isa}; @@ -34,42 +32,42 @@ impl Decode for u16 { let extension = self.parse_extension(); match extension { - Ok(Extensions::C) => Ok(OpcodeKind::C(c_extension::parse_opcode(self, isa)?)), - Ok(Extensions::Zicfiss) => Ok(OpcodeKind::Zicfiss(zicfiss_extension::parse_opcode( - self, isa, - )?)), + Ok(Extensions::C) => Ok(OpcodeKind::C(c_extension::bit_16::parse_opcode(self, isa)?)), + Ok(Extensions::Zicfiss) => Ok(OpcodeKind::Zicfiss( + zicfiss_extension::bit_16::parse_opcode(self, isa)?, + )), _ => Err(DecodingError::Not16BitInst), } } fn parse_rd(self, opkind: &OpcodeKind) -> Result, DecodingError> { match opkind { - OpcodeKind::C(opc) => Ok(c_extension::parse_rd(self, opc)), - OpcodeKind::Zicfiss(opc) => Ok(zicfiss_extension::parse_rd(self, opc)), + OpcodeKind::C(opc) => Ok(c_extension::bit_16::parse_rd(self, opc)), + OpcodeKind::Zicfiss(opc) => Ok(zicfiss_extension::bit_16::parse_rd(self, opc)), _ => Err(DecodingError::Not16BitInst), } } fn parse_rs1(self, opkind: &OpcodeKind) -> Result, DecodingError> { match opkind { - OpcodeKind::C(opc) => Ok(c_extension::parse_rs1(self, opc)), - OpcodeKind::Zicfiss(opc) => Ok(zicfiss_extension::parse_rs1(self, opc)), + OpcodeKind::C(opc) => Ok(c_extension::bit_16::parse_rs1(self, opc)), + OpcodeKind::Zicfiss(opc) => Ok(zicfiss_extension::bit_16::parse_rs1(self, opc)), _ => Err(DecodingError::Not16BitInst), } } fn parse_rs2(self, opkind: &OpcodeKind) -> Result, DecodingError> { match opkind { - OpcodeKind::C(opc) => Ok(c_extension::parse_rs2(self, opc)), - OpcodeKind::Zicfiss(opc) => Ok(zicfiss_extension::parse_rs2(self, opc)), + OpcodeKind::C(opc) => Ok(c_extension::bit_16::parse_rs2(self, opc)), + OpcodeKind::Zicfiss(opc) => Ok(zicfiss_extension::bit_16::parse_rs2(self, opc)), _ => Err(DecodingError::Not16BitInst), } } fn parse_imm(self, opkind: &OpcodeKind, _isa: Isa) -> Result, DecodingError> { match opkind { - OpcodeKind::C(opc) => Ok(c_extension::parse_imm(self, opc)), - OpcodeKind::Zicfiss(opc) => Ok(zicfiss_extension::parse_imm(self, opc)), + OpcodeKind::C(opc) => Ok(c_extension::bit_16::parse_imm(self, opc)), + OpcodeKind::Zicfiss(opc) => Ok(zicfiss_extension::bit_16::parse_imm(self, opc)), _ => Err(DecodingError::Not16BitInst), } } diff --git a/src/decode/inst_16/c_extension.rs b/src/decode/inst_16/c_extension.rs deleted file mode 100644 index 769726c..0000000 --- a/src/decode/inst_16/c_extension.rs +++ /dev/null @@ -1,376 +0,0 @@ -use super::super::{only_rv64, DecodeUtil, DecodingError}; -use crate::instruction::c_extension::COpcode; -use crate::Isa; - -fn quadrant0(_inst: u16, opmap: u8, isa: Isa) -> Result { - match opmap { - 0b000 => Ok(COpcode::ADDI4SPN), - 0b010 => Ok(COpcode::LW), - 0b011 => only_rv64(COpcode::LD, isa), - 0b110 => Ok(COpcode::SW), - 0b111 => only_rv64(COpcode::SD, isa), - _ => Err(DecodingError::InvalidOpcode), - } -} - -fn quadrant1(inst: u16, opmap: u8, isa: Isa) -> Result { - let sr_flag: u8 = u8::try_from(inst.slice(11, 10)).unwrap(); - let lo_flag: u8 = u8::try_from(inst.slice(6, 5)).unwrap(); - let mi_flag: u8 = u8::try_from(inst.slice(11, 7)).unwrap(); - let bit_12: u8 = u8::try_from(inst.slice(12, 12)).unwrap(); - - match opmap { - 0b000 => match mi_flag { - 0b00000 => Ok(COpcode::NOP), - _ => Ok(COpcode::ADDI), - }, - 0b001 => match isa { - Isa::Rv32 => Ok(COpcode::JAL), - Isa::Rv64 => Ok(COpcode::ADDIW), - }, - 0b010 => Ok(COpcode::LI), - 0b011 => match mi_flag { - 0b00010 => Ok(COpcode::ADDI16SP), - _ => Ok(COpcode::LUI), - }, - 0b100 => match sr_flag { - 0b00 => Ok(COpcode::SRLI), - 0b01 => Ok(COpcode::SRAI), - 0b10 => Ok(COpcode::ANDI), - 0b11 => match bit_12 { - 0b0 => match lo_flag { - 0b00 => Ok(COpcode::SUB), - 0b01 => Ok(COpcode::XOR), - 0b10 => Ok(COpcode::OR), - 0b11 => Ok(COpcode::AND), - _ => Err(DecodingError::InvalidOpcode), - }, - 0b1 => match lo_flag { - 0b00 => only_rv64(COpcode::SUBW, isa), - 0b01 => only_rv64(COpcode::ADDW, isa), - _ => Err(DecodingError::InvalidOpcode), - }, - _ => unreachable!(), - }, - _ => Err(DecodingError::InvalidOpcode), - }, - 0b101 => Ok(COpcode::J), - 0b110 => Ok(COpcode::BEQZ), - 0b111 => Ok(COpcode::BNEZ), - _ => Err(DecodingError::InvalidOpcode), - } -} - -fn quadrant2(inst: u16, opmap: u8, isa: Isa) -> Result { - let lo_flag: u8 = u8::try_from(inst.slice(6, 2)).unwrap(); - let mi_flag: u8 = u8::try_from(inst.slice(11, 7)).unwrap(); - let hi_flag: u8 = u8::try_from(inst.slice(12, 12)).unwrap(); - - match opmap { - 0b000 => Ok(COpcode::SLLI), - 0b010 => Ok(COpcode::LWSP), - 0b011 => only_rv64(COpcode::LDSP, isa), - 0b100 => match hi_flag { - 0b0 => match lo_flag { - 0b0 => Ok(COpcode::JR), - _ => Ok(COpcode::MV), - }, - 0b1 => match mi_flag { - 0b0 => Ok(COpcode::EBREAK), - _ => match lo_flag { - 0b0 => Ok(COpcode::JALR), - _ => Ok(COpcode::ADD), - }, - }, - _ => Err(DecodingError::InvalidOpcode), - }, - 0b110 => Ok(COpcode::SWSP), - 0b111 => only_rv64(COpcode::SDSP, isa), - _ => Err(DecodingError::InvalidOpcode), - } -} - -pub fn parse_opcode(inst: u16, isa: Isa) -> Result { - let opmap: u8 = u8::try_from(inst.slice(15, 13)).unwrap(); - let quadrant: u8 = u8::try_from(inst.slice(1, 0)).unwrap(); - - if inst == 0b0000_0000_0000_0000 { - return Err(DecodingError::InvalidOpcode); - } - - match quadrant { - 0b00 => quadrant0(inst, opmap, isa), - 0b01 => quadrant1(inst, opmap, isa), - 0b10 => quadrant2(inst, opmap, isa), - _ => Err(DecodingError::InvalidOpcode), - } -} - -pub fn parse_rd(inst: u16, opkind: &COpcode) -> Option { - // see riscv-spec-20191213.pdf, page 100, Table 16.2 - let q0_rd: usize = (inst.slice(4, 2) + 8) as usize; - let q1_rd: usize = (inst.slice(9, 7) + 8) as usize; - let q1_wide_rd: usize = inst.slice(11, 7) as usize; - let q2_rd: usize = inst.slice(11, 7) as usize; - - match opkind { - // Quadrant 0 - COpcode::ADDI4SPN | COpcode::LW | COpcode::LD => Some(q0_rd), - // Quadrant 1 - COpcode::SRLI - | COpcode::SRAI - | COpcode::ANDI - | COpcode::SUB - | COpcode::XOR - | COpcode::OR - | COpcode::AND - | COpcode::ADDW - | COpcode::SUBW => Some(q1_rd), - COpcode::LI | COpcode::LUI | COpcode::ADDI | COpcode::ADDIW | COpcode::ADDI16SP => { - Some(q1_wide_rd) - } - // Quadrant 2 - COpcode::SLLI | COpcode::LWSP | COpcode::LDSP | COpcode::MV | COpcode::ADD => Some(q2_rd), - _ => None, - } -} - -pub fn parse_rs1(inst: u16, opkind: &COpcode) -> Option { - // see riscv-spec-20191213.pdf, page 100, Table 16.2 - let q0_rs1: usize = (inst.slice(9, 7) + 8) as usize; - let q1_rs1: usize = (inst.slice(9, 7) + 8) as usize; - let q1_addi_rs1: usize = inst.slice(11, 7) as usize; - let q2_rs1: usize = inst.slice(11, 7) as usize; - - match opkind { - // Quadrant 0 - COpcode::LW | COpcode::LD | COpcode::SW | COpcode::SD => Some(q0_rs1), - // Quadrant 1 - COpcode::ADDI | COpcode::ADDIW | COpcode::ADDI16SP => Some(q1_addi_rs1), - COpcode::SRLI - | COpcode::SRAI - | COpcode::ANDI - | COpcode::SUB - | COpcode::XOR - | COpcode::OR - | COpcode::AND - | COpcode::BEQZ - | COpcode::BNEZ - | COpcode::SUBW - | COpcode::ADDW => Some(q1_rs1), - // Quadrant 2 - COpcode::SLLI | COpcode::JR | COpcode::JALR | COpcode::ADD => Some(q2_rs1), - _ => None, - } -} - -pub fn parse_rs2(inst: u16, opkind: &COpcode) -> Option { - // see riscv-spec-20191213.pdf, page 100, Table 16.2 - let q0_rs2: usize = (inst.slice(4, 2) + 8) as usize; - let q1_rs2: usize = (inst.slice(4, 2) + 8) as usize; - let q2_rs2: usize = inst.slice(6, 2) as usize; - - match opkind { - // Quadrant 0 - COpcode::SW | COpcode::SD => Some(q0_rs2), - // Quadrant 1 - COpcode::SUB - | COpcode::XOR - | COpcode::OR - | COpcode::AND - | COpcode::SUBW - | COpcode::ADDW => Some(q1_rs2), - // Quadrant 2 - COpcode::JR - | COpcode::JALR - | COpcode::MV - | COpcode::ADD - | COpcode::SWSP - | COpcode::SDSP => Some(q2_rs2), - _ => None, - } -} - -#[allow(clippy::cast_possible_wrap)] -#[allow(clippy::similar_names)] -pub fn parse_imm(inst: u16, opkind: &COpcode) -> Option { - let q0_uimm = || (inst.slice(12, 10).set(&[5, 4, 3]) | inst.slice(6, 5).set(&[2, 6])); - let q0_uimm_64 = || (inst.slice(12, 10).set(&[5, 4, 3]) | inst.slice(6, 5).set(&[7, 6])); - let q0_nzuimm = || inst.slice(12, 5).set(&[5, 4, 9, 8, 7, 6, 2, 3]); - let q1_nzuimm = || (inst.slice(6, 2).set(&[4, 3, 2, 1, 0]) | inst.slice(12, 12).set(&[5])); - let q1_nzimm = || { - let imm16 = (inst.slice(6, 2).set(&[4, 3, 2, 1, 0]) | inst.slice(12, 12).set(&[5])) as i32; - inst.to_signed_nbit(imm16, 6) - }; - let q1_imm = || { - let imm16 = (inst.slice(6, 2).set(&[4, 3, 2, 1, 0]) | inst.slice(12, 12).set(&[5])) as i32; - inst.to_signed_nbit(imm16, 6) - }; - let q1_j_imm = || { - let imm16 = inst.slice(12, 2).set(&[11, 4, 9, 8, 10, 6, 7, 3, 2, 1, 5]) as i32; - inst.to_signed_nbit(imm16, 12) - }; - let q1_b_imm = || { - let imm16 = - (inst.slice(6, 2).set(&[7, 6, 2, 1, 5]) | inst.slice(12, 10).set(&[8, 4, 3])) as i32; - inst.to_signed_nbit(imm16, 9) - }; - let q1_16sp_nzimm = || { - let imm16 = (inst.slice(6, 2).set(&[4, 6, 8, 7, 5]) | inst.slice(12, 12).set(&[9])) as i32; - inst.to_signed_nbit(imm16, 10) - }; - let q1_lui_imm = || { - let imm16 = - (inst.slice(6, 2).set(&[16, 15, 14, 13, 12]) | inst.slice(12, 12).set(&[17])) as i32; - inst.to_signed_nbit(imm16, 18) - }; - let q2_imm = || (inst.slice(6, 2).set(&[4, 3, 2, 1, 0]) | inst.slice(12, 12).set(&[5])) as i32; - let q2_lwsp_imm = - || (inst.slice(6, 2).set(&[4, 3, 2, 7, 6]) | inst.slice(12, 12).set(&[5])) as i32; - let q2_ldsp_imm = - || (inst.slice(6, 2).set(&[4, 3, 8, 7, 6]) | inst.slice(12, 12).set(&[5])) as i32; - let q2_swsp_imm = || inst.slice(12, 7).set(&[5, 4, 3, 2, 7, 6]) as i32; - let q2_sdsp_imm = || inst.slice(12, 7).set(&[5, 4, 3, 8, 7, 6]) as i32; - - match opkind { - // Quadrant0 - COpcode::ADDI4SPN => Some(q0_nzuimm() as i32), - COpcode::LW | COpcode::SW => Some(q0_uimm() as i32), - COpcode::LD | COpcode::SD => Some(q0_uimm_64() as i32), - // Quadrant1 - COpcode::ADDIW | COpcode::LI | COpcode::ANDI => Some(q1_imm()), - COpcode::NOP | COpcode::ADDI => Some(q1_nzimm()), - COpcode::SRLI | COpcode::SRAI => Some(q1_nzuimm() as i32), - COpcode::JAL | COpcode::J => Some(q1_j_imm()), - COpcode::BEQZ | COpcode::BNEZ => Some(q1_b_imm()), - COpcode::LUI => Some(q1_lui_imm()), - COpcode::ADDI16SP => Some(q1_16sp_nzimm()), - // Quadrant2 - COpcode::SLLI => Some(q2_imm()), - COpcode::LWSP => Some(q2_lwsp_imm()), - COpcode::LDSP => Some(q2_ldsp_imm()), - COpcode::SWSP => Some(q2_swsp_imm()), - COpcode::SDSP => Some(q2_sdsp_imm()), - _ => None, - } -} - -#[cfg(test)] -#[allow(unused_variables)] -mod test_c { - #[test] - fn c_decode_test() { - use super::*; - use crate::{Decode, Isa, OpcodeKind}; - let test_16 = |inst_16: u16, - op: OpcodeKind, - rd: Option, - rs1: Option, - rs2: Option, - imm: Option| { - let op_16 = inst_16.parse_opcode(Isa::Rv64).unwrap(); - assert!(matches!(&op_16, op)); - assert_eq!(inst_16.parse_rd(&op_16).unwrap(), rd); - assert_eq!(inst_16.parse_rs1(&op_16).unwrap(), rs1); - assert_eq!(inst_16.parse_rs2(&op_16).unwrap(), rs2); - assert_eq!(inst_16.parse_imm(&op_16, Isa::Rv64).unwrap(), imm); - }; - - test_16( - 0b0000_0000_0000_0001, - OpcodeKind::C(COpcode::NOP), - None, - None, - None, - Some(0), - ); - test_16( - 0b0110_0011_1000_0001, - OpcodeKind::C(COpcode::LUI), - Some(7), - None, - None, - Some(0), - ); - test_16( - 0b1000_0010_1100_0001, - OpcodeKind::C(COpcode::SRAI), - Some(13), - Some(13), - None, - Some(16), - ); - test_16( - 0x4521, - OpcodeKind::C(COpcode::LI), - Some(10), - None, - None, - Some(8), - ); - test_16( - 0xb5e5, - OpcodeKind::C(COpcode::J), - None, - None, - None, - Some(-280), - ); - test_16( - 0x6105, - OpcodeKind::C(COpcode::ADDI), - Some(2), - Some(2), - None, - Some(32), - ); - test_16( - 0x8082, - OpcodeKind::C(COpcode::JR), - None, - Some(1), - Some(0), - None, - ); - test_16( - 0xe29d, - OpcodeKind::C(COpcode::BNEZ), - None, - Some(13), - None, - Some(38), - ); - test_16( - 0xc05c, - OpcodeKind::C(COpcode::SW), - None, - Some(8), - Some(15), - Some(4), - ); - test_16( - 0x9002, - OpcodeKind::C(COpcode::EBREAK), - None, - None, - None, - None, - ); - test_16( - 0x880a, - OpcodeKind::C(COpcode::MV), - Some(16), - None, - Some(2), - None, - ); - test_16( - 0x8585, - OpcodeKind::C(COpcode::SRAI), - Some(11), - Some(11), - None, - Some(1), - ); - } -} diff --git a/src/decode/inst_16/zicfiss_extension.rs b/src/decode/inst_16/zicfiss_extension.rs deleted file mode 100644 index 7432d09..0000000 --- a/src/decode/inst_16/zicfiss_extension.rs +++ /dev/null @@ -1,77 +0,0 @@ -use super::super::DecodingError; -use crate::instruction::zicfiss_extension::ZicfissOpcode; -use crate::Isa; - -pub fn parse_opcode(inst: u16, _isa: Isa) -> Result { - match inst { - 0b0110_0000_1000_0001 => Ok(ZicfissOpcode::C_SSPUSH), - 0b0110_0010_1000_0001 => Ok(ZicfissOpcode::C_SSPOPCHK), - _ => Err(DecodingError::InvalidOpcode), - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rd(_inst: u16, opkind: &ZicfissOpcode) -> Option { - match opkind { - ZicfissOpcode::C_SSPUSH => Some(1), - ZicfissOpcode::C_SSPOPCHK => Some(5), - _ => unreachable!(), - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rs1(_inst: u16, _opkind: &ZicfissOpcode) -> Option { - None -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rs2(_inst: u16, _opkind: &ZicfissOpcode) -> Option { - None -} - -#[allow(clippy::cast_possible_wrap, clippy::unnecessary_wraps)] -pub fn parse_imm(_inst: u16, _opkind: &ZicfissOpcode) -> Option { - None -} - -#[cfg(test)] -#[allow(unused_variables)] -mod test_zicfiss { - #[test] - #[allow(overflowing_literals)] - fn zicfiss_16() { - use super::*; - use crate::{Decode, Isa, OpcodeKind}; - let test_16 = |inst_16: u16, - op: OpcodeKind, - rd: Option, - rs1: Option, - rs2: Option, - imm: Option| { - let op_16 = inst_16.parse_opcode(Isa::Rv64).unwrap(); - assert!(matches!(&op_16, op)); - assert_eq!(inst_16.parse_rd(&op_16).unwrap(), rd); - assert_eq!(inst_16.parse_rs1(&op_16).unwrap(), rs1); - assert_eq!(inst_16.parse_rs2(&op_16).unwrap(), rs2); - assert_eq!(inst_16.parse_imm(&op_16, Isa::Rv64).unwrap(), imm); - }; - - test_16( - 0x6081, - OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPUSH), - Some(1), - None, - None, - None, - ); - - test_16( - 0x6281, - OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPOPCHK), - Some(5), - None, - None, - None, - ); - } -} diff --git a/src/decode/inst_32.rs b/src/decode/inst_32.rs index ee1bf3e..8719f95 100644 --- a/src/decode/inst_32.rs +++ b/src/decode/inst_32.rs @@ -1,12 +1,7 @@ -mod a_extension; -mod base_i; -mod m_extension; -mod priv_extension; -mod zicfiss_extension; -mod zicntr_extension; -mod zicsr_extension; -mod zifencei_extension; - +use super::{ + a_extension, base_i, m_extension, priv_extension, zicboz_extension, zicfiss_extension, + zicntr_extension, zicsr_extension, zifencei_extension, +}; use super::{Decode, DecodeUtil, DecodingError}; use crate::instruction::{InstFormat, Instruction, OpcodeKind}; use crate::{Extensions, Isa}; @@ -36,18 +31,29 @@ impl Decode for u32 { let extension = self.parse_extension(); match extension { - Ok(Extensions::BaseI) => Ok(OpcodeKind::BaseI(base_i::parse_opcode(self, isa)?)), - Ok(Extensions::M) => Ok(OpcodeKind::M(m_extension::parse_opcode(self, isa)?)), - Ok(Extensions::A) => Ok(OpcodeKind::A(a_extension::parse_opcode(self, isa)?)), - Ok(Extensions::Zifencei) => Ok(OpcodeKind::Zifencei(zifencei_extension::parse_opcode( + Ok(Extensions::BaseI) => { + Ok(OpcodeKind::BaseI(base_i::bit_32::parse_opcode(self, isa)?)) + } + Ok(Extensions::M) => Ok(OpcodeKind::M(m_extension::bit_32::parse_opcode(self, isa)?)), + Ok(Extensions::A) => Ok(OpcodeKind::A(a_extension::bit_32::parse_opcode(self, isa)?)), + Ok(Extensions::Zifencei) => Ok(OpcodeKind::Zifencei( + zifencei_extension::bit_32::parse_opcode(self)?, + )), + Ok(Extensions::Zicsr) => Ok(OpcodeKind::Zicsr(zicsr_extension::bit_32::parse_opcode( + self, + )?)), + Ok(Extensions::Zicfiss) => Ok(OpcodeKind::Zicfiss( + zicfiss_extension::bit_32::parse_opcode(self)?, + )), + Ok(Extensions::Zicntr) => Ok(OpcodeKind::Zicntr( + zicntr_extension::bit_32::parse_opcode(self)?, + )), + Ok(Extensions::Zicboz) => Ok(OpcodeKind::Zicboz( + zicboz_extension::bit_32::parse_opcode(self)?, + )), + Ok(Extensions::Priv) => Ok(OpcodeKind::Priv(priv_extension::bit_32::parse_opcode( self, )?)), - Ok(Extensions::Zicsr) => Ok(OpcodeKind::Zicsr(zicsr_extension::parse_opcode(self)?)), - Ok(Extensions::Zicfiss) => { - Ok(OpcodeKind::Zicfiss(zicfiss_extension::parse_opcode(self)?)) - } - Ok(Extensions::Zicntr) => Ok(OpcodeKind::Zicntr(zicntr_extension::parse_opcode(self)?)), - Ok(Extensions::Priv) => Ok(OpcodeKind::Priv(priv_extension::parse_opcode(self)?)), Ok(Extensions::C) => Err(DecodingError::Not32BitInst), Err(decoding_err) => Err(decoding_err), } @@ -55,56 +61,60 @@ impl Decode for u32 { fn parse_rd(self, opkind: &OpcodeKind) -> Result, DecodingError> { match opkind { - OpcodeKind::BaseI(opc) => Ok(base_i::parse_rd(self, opc)), - OpcodeKind::M(opc) => Ok(m_extension::parse_rd(self, opc)), - OpcodeKind::A(opc) => Ok(a_extension::parse_rd(self, opc)), - OpcodeKind::Zifencei(opc) => Ok(zifencei_extension::parse_rd(self, opc)), - OpcodeKind::Zicsr(opc) => Ok(zicsr_extension::parse_rd(self, opc)), - OpcodeKind::Zicfiss(opc) => Ok(zicfiss_extension::parse_rd(self, opc)), - OpcodeKind::Zicntr(opc) => Ok(zicntr_extension::parse_rd(self, opc)), - OpcodeKind::Priv(opc) => Ok(priv_extension::parse_rd(self, opc)), + OpcodeKind::BaseI(opc) => Ok(base_i::bit_32::parse_rd(self, opc)), + OpcodeKind::M(opc) => Ok(m_extension::bit_32::parse_rd(self, opc)), + OpcodeKind::A(opc) => Ok(a_extension::bit_32::parse_rd(self, opc)), + OpcodeKind::Zifencei(opc) => Ok(zifencei_extension::bit_32::parse_rd(self, opc)), + OpcodeKind::Zicsr(opc) => Ok(zicsr_extension::bit_32::parse_rd(self, opc)), + OpcodeKind::Zicfiss(opc) => Ok(zicfiss_extension::bit_32::parse_rd(self, opc)), + OpcodeKind::Zicntr(opc) => Ok(zicntr_extension::bit_32::parse_rd(self, opc)), + OpcodeKind::Zicboz(opc) => Ok(zicboz_extension::bit_32::parse_rd(self, opc)), + OpcodeKind::Priv(opc) => Ok(priv_extension::bit_32::parse_rd(self, opc)), OpcodeKind::C(_) => Err(DecodingError::Not32BitInst), } } fn parse_rs1(self, opkind: &OpcodeKind) -> Result, DecodingError> { match opkind { - OpcodeKind::BaseI(opc) => Ok(base_i::parse_rs1(self, opc)), - OpcodeKind::M(opc) => Ok(m_extension::parse_rs1(self, opc)), - OpcodeKind::A(opc) => Ok(a_extension::parse_rs1(self, opc)), - OpcodeKind::Zifencei(opc) => Ok(zifencei_extension::parse_rs1(self, opc)), - OpcodeKind::Zicsr(opc) => Ok(zicsr_extension::parse_rs1(self, opc)), - OpcodeKind::Zicfiss(opc) => Ok(zicfiss_extension::parse_rs1(self, opc)), - OpcodeKind::Zicntr(opc) => Ok(zicntr_extension::parse_rs1(self, opc)), - OpcodeKind::Priv(opc) => Ok(priv_extension::parse_rs1(self, opc)), + OpcodeKind::BaseI(opc) => Ok(base_i::bit_32::parse_rs1(self, opc)), + OpcodeKind::M(opc) => Ok(m_extension::bit_32::parse_rs1(self, opc)), + OpcodeKind::A(opc) => Ok(a_extension::bit_32::parse_rs1(self, opc)), + OpcodeKind::Zifencei(opc) => Ok(zifencei_extension::bit_32::parse_rs1(self, opc)), + OpcodeKind::Zicsr(opc) => Ok(zicsr_extension::bit_32::parse_rs1(self, opc)), + OpcodeKind::Zicfiss(opc) => Ok(zicfiss_extension::bit_32::parse_rs1(self, opc)), + OpcodeKind::Zicntr(opc) => Ok(zicntr_extension::bit_32::parse_rs1(self, opc)), + OpcodeKind::Zicboz(opc) => Ok(zicboz_extension::bit_32::parse_rs1(self, opc)), + OpcodeKind::Priv(opc) => Ok(priv_extension::bit_32::parse_rs1(self, opc)), OpcodeKind::C(_) => Err(DecodingError::Not32BitInst), } } fn parse_rs2(self, opkind: &OpcodeKind) -> Result, DecodingError> { match opkind { - OpcodeKind::BaseI(opc) => Ok(base_i::parse_rs2(self, opc)), - OpcodeKind::M(opc) => Ok(m_extension::parse_rs2(self, opc)), - OpcodeKind::A(opc) => Ok(a_extension::parse_rs2(self, opc)), - OpcodeKind::Zifencei(opc) => Ok(zifencei_extension::parse_rs2(self, opc)), - OpcodeKind::Zicsr(opc) => Ok(zicsr_extension::parse_rs2(self, opc)), - OpcodeKind::Zicfiss(opc) => Ok(zicfiss_extension::parse_rs2(self, opc)), - OpcodeKind::Zicntr(opc) => Ok(zicntr_extension::parse_rs2(self, opc)), - OpcodeKind::Priv(opc) => Ok(priv_extension::parse_rs2(self, opc)), + OpcodeKind::BaseI(opc) => Ok(base_i::bit_32::parse_rs2(self, opc)), + OpcodeKind::M(opc) => Ok(m_extension::bit_32::parse_rs2(self, opc)), + OpcodeKind::A(opc) => Ok(a_extension::bit_32::parse_rs2(self, opc)), + OpcodeKind::Zifencei(opc) => Ok(zifencei_extension::bit_32::parse_rs2(self, opc)), + OpcodeKind::Zicsr(opc) => Ok(zicsr_extension::bit_32::parse_rs2(self, opc)), + OpcodeKind::Zicfiss(opc) => Ok(zicfiss_extension::bit_32::parse_rs2(self, opc)), + OpcodeKind::Zicntr(opc) => Ok(zicntr_extension::bit_32::parse_rs2(self, opc)), + OpcodeKind::Zicboz(opc) => Ok(zicboz_extension::bit_32::parse_rs2(self, opc)), + OpcodeKind::Priv(opc) => Ok(priv_extension::bit_32::parse_rs2(self, opc)), OpcodeKind::C(_) => Err(DecodingError::Not32BitInst), } } fn parse_imm(self, opkind: &OpcodeKind, isa: Isa) -> Result, DecodingError> { match opkind { - OpcodeKind::BaseI(opc) => Ok(base_i::parse_imm(self, opc, isa)), - OpcodeKind::M(opc) => Ok(m_extension::parse_imm(self, opc)), - OpcodeKind::A(opc) => Ok(a_extension::parse_imm(self, opc)), - OpcodeKind::Zifencei(opc) => Ok(zifencei_extension::parse_imm(self, opc)), - OpcodeKind::Zicsr(opc) => Ok(zicsr_extension::parse_imm(self, opc)), - OpcodeKind::Zicfiss(opc) => Ok(zicfiss_extension::parse_imm(self, opc)), - OpcodeKind::Zicntr(opc) => Ok(zicntr_extension::parse_imm(self, opc)), - OpcodeKind::Priv(opc) => Ok(priv_extension::parse_imm(self, opc)), + OpcodeKind::BaseI(opc) => Ok(base_i::bit_32::parse_imm(self, opc, isa)), + OpcodeKind::M(opc) => Ok(m_extension::bit_32::parse_imm(self, opc)), + OpcodeKind::A(opc) => Ok(a_extension::bit_32::parse_imm(self, opc)), + OpcodeKind::Zifencei(opc) => Ok(zifencei_extension::bit_32::parse_imm(self, opc)), + OpcodeKind::Zicsr(opc) => Ok(zicsr_extension::bit_32::parse_imm(self, opc)), + OpcodeKind::Zicfiss(opc) => Ok(zicfiss_extension::bit_32::parse_imm(self, opc)), + OpcodeKind::Zicntr(opc) => Ok(zicntr_extension::bit_32::parse_imm(self, opc)), + OpcodeKind::Zicboz(opc) => Ok(zicboz_extension::bit_32::parse_imm(self, opc)), + OpcodeKind::Priv(opc) => Ok(priv_extension::bit_32::parse_imm(self, opc)), OpcodeKind::C(_) => Err(DecodingError::Not32BitInst), } } @@ -124,7 +134,11 @@ impl DecodeUtil for u32 { let csr: u16 = u16::try_from(self.slice(31, 20)).unwrap(); match opmap { - 0b000_1111 => Ok(Extensions::Zifencei), + 0b000_1111 => match funct3 { + 0b000 => Ok(Extensions::Zifencei), + 0b010 => Ok(Extensions::Zicboz), + _ => Err(DecodingError::UnknownExtension), + }, 0b010_1111 => match funct5 { 0b00000 | 0b00001 | 0b00010 | 0b00011 | 0b00100 | 0b01000 | 0b01100 | 0b10000 | 0b10100 | 0b11000 | 0b11100 => Ok(Extensions::A), diff --git a/src/decode/inst_32/a_extension.rs b/src/decode/inst_32/a_extension.rs deleted file mode 100644 index 0032eba..0000000 --- a/src/decode/inst_32/a_extension.rs +++ /dev/null @@ -1,213 +0,0 @@ -use super::super::{only_rv64, DecodeUtil, DecodingError}; -use crate::instruction::a_extension::AOpcode; -use crate::Isa; - -pub fn parse_opcode(inst: u32, isa: Isa) -> Result { - let opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); - let funct3: u8 = u8::try_from(inst.slice(14, 12)).unwrap(); - let funct7: u8 = u8::try_from(inst.slice(31, 27)).unwrap(); - - match opmap { - 0b010_1111 => match funct3 { - 0b010 => match funct7 { - 0b00010 => Ok(AOpcode::LR_W), - 0b00011 => Ok(AOpcode::SC_W), - 0b00001 => Ok(AOpcode::AMOSWAP_W), - 0b00000 => Ok(AOpcode::AMOADD_W), - 0b00100 => Ok(AOpcode::AMOXOR_W), - 0b01100 => Ok(AOpcode::AMOAND_W), - 0b01000 => Ok(AOpcode::AMOOR_W), - 0b10000 => Ok(AOpcode::AMOMIN_W), - 0b10100 => Ok(AOpcode::AMOMAX_W), - 0b11000 => Ok(AOpcode::AMOMINU_W), - 0b11100 => Ok(AOpcode::AMOMAXU_W), - _ => Err(DecodingError::InvalidFunct7), - }, - 0b011 => match funct7 { - 0b00010 => only_rv64(AOpcode::LR_D, isa), - 0b00011 => only_rv64(AOpcode::SC_D, isa), - 0b00001 => only_rv64(AOpcode::AMOSWAP_D, isa), - 0b00000 => only_rv64(AOpcode::AMOADD_D, isa), - 0b00100 => only_rv64(AOpcode::AMOXOR_D, isa), - 0b01100 => only_rv64(AOpcode::AMOAND_D, isa), - 0b01000 => only_rv64(AOpcode::AMOOR_D, isa), - 0b10000 => only_rv64(AOpcode::AMOMIN_D, isa), - 0b10100 => only_rv64(AOpcode::AMOMAX_D, isa), - 0b11000 => only_rv64(AOpcode::AMOMINU_D, isa), - 0b11100 => only_rv64(AOpcode::AMOMAXU_D, isa), - _ => Err(DecodingError::InvalidFunct7), - }, - _ => Err(DecodingError::InvalidFunct3), - }, - _ => Err(DecodingError::InvalidOpcode), - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rd(inst: u32, opkind: &AOpcode) -> Option { - let rd: usize = inst.slice(11, 7) as usize; - - match opkind { - AOpcode::LR_W - | AOpcode::SC_W - | AOpcode::AMOSWAP_W - | AOpcode::AMOADD_W - | AOpcode::AMOXOR_W - | AOpcode::AMOAND_W - | AOpcode::AMOOR_W - | AOpcode::AMOMIN_W - | AOpcode::AMOMAX_W - | AOpcode::AMOMINU_W - | AOpcode::AMOMAXU_W - | AOpcode::LR_D - | AOpcode::SC_D - | AOpcode::AMOSWAP_D - | AOpcode::AMOADD_D - | AOpcode::AMOXOR_D - | AOpcode::AMOAND_D - | AOpcode::AMOOR_D - | AOpcode::AMOMIN_D - | AOpcode::AMOMAX_D - | AOpcode::AMOMINU_D - | AOpcode::AMOMAXU_D => Some(rd), - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rs1(inst: u32, opkind: &AOpcode) -> Option { - let rs1: usize = inst.slice(19, 15) as usize; - - match opkind { - AOpcode::LR_W - | AOpcode::SC_W - | AOpcode::AMOSWAP_W - | AOpcode::AMOADD_W - | AOpcode::AMOXOR_W - | AOpcode::AMOAND_W - | AOpcode::AMOOR_W - | AOpcode::AMOMIN_W - | AOpcode::AMOMAX_W - | AOpcode::AMOMINU_W - | AOpcode::AMOMAXU_W - | AOpcode::LR_D - | AOpcode::SC_D - | AOpcode::AMOSWAP_D - | AOpcode::AMOADD_D - | AOpcode::AMOXOR_D - | AOpcode::AMOAND_D - | AOpcode::AMOOR_D - | AOpcode::AMOMIN_D - | AOpcode::AMOMAX_D - | AOpcode::AMOMINU_D - | AOpcode::AMOMAXU_D => Some(rs1), - } -} - -pub fn parse_rs2(inst: u32, opkind: &AOpcode) -> Option { - let rs2: usize = inst.slice(24, 20) as usize; - - match opkind { - AOpcode::SC_W - | AOpcode::AMOSWAP_W - | AOpcode::AMOADD_W - | AOpcode::AMOXOR_W - | AOpcode::AMOAND_W - | AOpcode::AMOOR_W - | AOpcode::AMOMIN_W - | AOpcode::AMOMAX_W - | AOpcode::AMOMINU_W - | AOpcode::AMOMAXU_W - | AOpcode::SC_D - | AOpcode::AMOSWAP_D - | AOpcode::AMOADD_D - | AOpcode::AMOXOR_D - | AOpcode::AMOAND_D - | AOpcode::AMOOR_D - | AOpcode::AMOMIN_D - | AOpcode::AMOMAX_D - | AOpcode::AMOMINU_D - | AOpcode::AMOMAXU_D => Some(rs2), - _ => None, - } -} - -#[allow(non_snake_case)] -#[allow(clippy::unnecessary_wraps, clippy::cast_possible_wrap)] -pub fn parse_imm(inst: u32, opkind: &AOpcode) -> Option { - let aq_and_rl = || inst.slice(26, 25) as i32; - - match opkind { - AOpcode::LR_W - | AOpcode::SC_W - | AOpcode::AMOSWAP_W - | AOpcode::AMOADD_W - | AOpcode::AMOXOR_W - | AOpcode::AMOAND_W - | AOpcode::AMOOR_W - | AOpcode::AMOMIN_W - | AOpcode::AMOMAX_W - | AOpcode::AMOMINU_W - | AOpcode::AMOMAXU_W - | AOpcode::LR_D - | AOpcode::SC_D - | AOpcode::AMOSWAP_D - | AOpcode::AMOADD_D - | AOpcode::AMOXOR_D - | AOpcode::AMOAND_D - | AOpcode::AMOOR_D - | AOpcode::AMOMIN_D - | AOpcode::AMOMAX_D - | AOpcode::AMOMINU_D - | AOpcode::AMOMAXU_D => Some(aq_and_rl()), - } -} - -#[cfg(test)] -#[allow(unused_variables)] -mod test_a { - #[test] - #[allow(overflowing_literals)] - fn a_decode_test() { - use super::*; - use crate::{Decode, Isa, OpcodeKind}; - - let test_32 = |inst_32: u32, - op: OpcodeKind, - rd: Option, - rs1: Option, - rs2: Option, - imm: Option| { - let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap(); - assert!(matches!(&op_32, op)); - assert_eq!(inst_32.parse_rd(&op_32).unwrap(), rd); - assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), rs1); - assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), rs2); - assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), imm); - }; - - test_32( - 0x04d7_27af, - OpcodeKind::A(AOpcode::AMOADD_W), - Some(15), - Some(14), - Some(13), - Some(2), - ); - test_32( - 0x1007b62f, - OpcodeKind::A(AOpcode::LR_D), - Some(12), - Some(15), - None, - Some(0), - ); - test_32( - 0x60f6302f, - OpcodeKind::A(AOpcode::AMOAND_D), - Some(0), - Some(12), - Some(15), - Some(0), - ); - } -} diff --git a/src/decode/inst_32/base_i.rs b/src/decode/inst_32/base_i.rs deleted file mode 100644 index e3b9eb6..0000000 --- a/src/decode/inst_32/base_i.rs +++ /dev/null @@ -1,474 +0,0 @@ -use super::super::{only_rv64, DecodeUtil, DecodingError}; -use crate::instruction::base_i::BaseIOpcode; -use crate::Isa; - -#[allow(clippy::too_many_lines)] -pub fn parse_opcode(inst: u32, isa: Isa) -> Result { - let opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); - let funct3: u8 = u8::try_from(inst.slice(14, 12)).unwrap(); - let funct5: u8 = u8::try_from(inst.slice(24, 20)).unwrap(); - let funct6: u8 = u8::try_from(inst.slice(31, 26)).unwrap(); - let funct7: u8 = u8::try_from(inst.slice(31, 25)).unwrap(); - - match opmap { - 0b011_0111 => Ok(BaseIOpcode::LUI), - 0b001_0111 => Ok(BaseIOpcode::AUIPC), - 0b110_1111 => Ok(BaseIOpcode::JAL), - 0b110_0111 => Ok(BaseIOpcode::JALR), - 0b110_0011 => match funct3 { - 0b000 => Ok(BaseIOpcode::BEQ), - 0b001 => Ok(BaseIOpcode::BNE), - 0b100 => Ok(BaseIOpcode::BLT), - 0b101 => Ok(BaseIOpcode::BGE), - 0b110 => Ok(BaseIOpcode::BLTU), - 0b111 => Ok(BaseIOpcode::BGEU), - _ => Err(DecodingError::InvalidFunct3), - }, - 0b000_0011 => match funct3 { - 0b000 => Ok(BaseIOpcode::LB), - 0b001 => Ok(BaseIOpcode::LH), - 0b010 => Ok(BaseIOpcode::LW), - 0b011 => only_rv64(BaseIOpcode::LD, isa), - 0b100 => Ok(BaseIOpcode::LBU), - 0b101 => Ok(BaseIOpcode::LHU), - 0b110 => only_rv64(BaseIOpcode::LWU, isa), - _ => Err(DecodingError::InvalidFunct3), - }, - 0b010_0011 => match funct3 { - 0b000 => Ok(BaseIOpcode::SB), - 0b001 => Ok(BaseIOpcode::SH), - 0b010 => Ok(BaseIOpcode::SW), - 0b011 => only_rv64(BaseIOpcode::SD, isa), - _ => Err(DecodingError::InvalidFunct3), - }, - 0b001_0011 => match funct3 { - 0b000 => Ok(BaseIOpcode::ADDI), - 0b001 => match isa { - Isa::Rv32 => match funct7 { - 0b000_0000 => Ok(BaseIOpcode::SLLI), - _ => Err(DecodingError::InvalidFunct7), - }, - Isa::Rv64 => match funct6 { - 0b00_0000 => Ok(BaseIOpcode::SLLI), - _ => Err(DecodingError::InvalidFunct6), - }, - }, - 0b010 => Ok(BaseIOpcode::SLTI), - 0b011 => Ok(BaseIOpcode::SLTIU), - 0b100 => Ok(BaseIOpcode::XORI), - 0b101 => match isa { - Isa::Rv32 => match funct7 { - 0b000_0000 => Ok(BaseIOpcode::SRLI), - 0b010_0000 => Ok(BaseIOpcode::SRAI), - _ => Err(DecodingError::InvalidFunct7), - }, - Isa::Rv64 => match funct6 { - 0b00_0000 => Ok(BaseIOpcode::SRLI), - 0b01_0000 => Ok(BaseIOpcode::SRAI), - _ => Err(DecodingError::InvalidFunct6), - }, - }, - 0b110 => Ok(BaseIOpcode::ORI), - 0b111 => Ok(BaseIOpcode::ANDI), - _ => Err(DecodingError::InvalidFunct3), - }, - 0b011_0011 => match funct3 { - 0b000 => match funct7 { - 0b000_0000 => Ok(BaseIOpcode::ADD), - 0b010_0000 => Ok(BaseIOpcode::SUB), - _ => Err(DecodingError::InvalidFunct7), - }, - 0b001 => Ok(BaseIOpcode::SLL), - 0b010 => Ok(BaseIOpcode::SLT), - 0b011 => Ok(BaseIOpcode::SLTU), - 0b100 => Ok(BaseIOpcode::XOR), - 0b101 => match funct7 { - 0b000_0000 => Ok(BaseIOpcode::SRL), - 0b010_0000 => Ok(BaseIOpcode::SRA), - _ => Err(DecodingError::InvalidFunct7), - }, - 0b110 => Ok(BaseIOpcode::OR), - 0b111 => Ok(BaseIOpcode::AND), - _ => Err(DecodingError::InvalidFunct3), - }, - 0b111_0011 => match funct3 { - 0b000 => match funct7 { - 0b000_0000 => match funct5 { - 0b00000 => Ok(BaseIOpcode::ECALL), - 0b00001 => Ok(BaseIOpcode::EBREAK), - _ => Err(DecodingError::InvalidFunct5), - }, - _ => Err(DecodingError::InvalidFunct7), - }, - _ => Err(DecodingError::InvalidFunct3), - }, - 0b001_1011 => match funct3 { - 0b000 => only_rv64(BaseIOpcode::ADDIW, isa), - 0b001 => only_rv64(BaseIOpcode::SLLIW, isa), - 0b101 => match funct7 { - 0b000_0000 => only_rv64(BaseIOpcode::SRLIW, isa), - 0b010_0000 => only_rv64(BaseIOpcode::SRAIW, isa), - _ => Err(DecodingError::InvalidFunct7), - }, - _ => Err(DecodingError::InvalidFunct3), - }, - 0b011_1011 => match funct3 { - 0b000 => match funct7 { - 0b000_0000 => only_rv64(BaseIOpcode::ADDW, isa), - 0b010_0000 => only_rv64(BaseIOpcode::SUBW, isa), - _ => Err(DecodingError::InvalidFunct7), - }, - 0b001 => only_rv64(BaseIOpcode::SLLW, isa), - 0b101 => match funct7 { - 0b000_0000 => only_rv64(BaseIOpcode::SRLW, isa), - 0b010_0000 => only_rv64(BaseIOpcode::SRAW, isa), - _ => Err(DecodingError::InvalidFunct7), - }, - _ => Err(DecodingError::InvalidFunct3), - }, - _ => Err(DecodingError::InvalidOpcode), - } -} - -pub fn parse_rd(inst: u32, opkind: &BaseIOpcode) -> Option { - let rd: usize = inst.slice(11, 7) as usize; - - // B(EQ|NE|LT|GE|LTU|GEU), S(B|H|W), ECALL, EBREAK - match opkind { - BaseIOpcode::LUI - | BaseIOpcode::AUIPC - | BaseIOpcode::JAL - | BaseIOpcode::JALR - | BaseIOpcode::LB - | BaseIOpcode::LH - | BaseIOpcode::LW - | BaseIOpcode::LBU - | BaseIOpcode::LHU - | BaseIOpcode::ADDI - | BaseIOpcode::SLTI - | BaseIOpcode::SLTIU - | BaseIOpcode::XORI - | BaseIOpcode::ORI - | BaseIOpcode::ANDI - | BaseIOpcode::SLLI - | BaseIOpcode::SRLI - | BaseIOpcode::SRAI - | BaseIOpcode::ADD - | BaseIOpcode::SUB - | BaseIOpcode::SLL - | BaseIOpcode::SLT - | BaseIOpcode::SLTU - | BaseIOpcode::XOR - | BaseIOpcode::SRL - | BaseIOpcode::SRA - | BaseIOpcode::OR - | BaseIOpcode::AND - | BaseIOpcode::LWU - | BaseIOpcode::LD - | BaseIOpcode::ADDIW - | BaseIOpcode::SLLIW - | BaseIOpcode::SRLIW - | BaseIOpcode::SRAIW - | BaseIOpcode::ADDW - | BaseIOpcode::SUBW - | BaseIOpcode::SLLW - | BaseIOpcode::SRLW - | BaseIOpcode::SRAW => Some(rd), - _ => None, - } -} - -pub fn parse_rs1(inst: u32, opkind: &BaseIOpcode) -> Option { - let rs1: usize = inst.slice(19, 15) as usize; - - // LUI, AUIPC, JAL, FENCE, ECALL, EBREAK - match opkind { - BaseIOpcode::JALR - | BaseIOpcode::BEQ - | BaseIOpcode::BNE - | BaseIOpcode::BLT - | BaseIOpcode::BGE - | BaseIOpcode::BLTU - | BaseIOpcode::BGEU - | BaseIOpcode::LB - | BaseIOpcode::LH - | BaseIOpcode::LW - | BaseIOpcode::LBU - | BaseIOpcode::LHU - | BaseIOpcode::SB - | BaseIOpcode::SH - | BaseIOpcode::SW - | BaseIOpcode::ADDI - | BaseIOpcode::SLTI - | BaseIOpcode::SLTIU - | BaseIOpcode::XORI - | BaseIOpcode::ORI - | BaseIOpcode::ANDI - | BaseIOpcode::SLLI - | BaseIOpcode::SRLI - | BaseIOpcode::SRAI - | BaseIOpcode::ADD - | BaseIOpcode::SUB - | BaseIOpcode::SLL - | BaseIOpcode::SLT - | BaseIOpcode::SLTU - | BaseIOpcode::XOR - | BaseIOpcode::SRL - | BaseIOpcode::SRA - | BaseIOpcode::OR - | BaseIOpcode::AND - | BaseIOpcode::LWU - | BaseIOpcode::LD - | BaseIOpcode::SD - | BaseIOpcode::ADDIW - | BaseIOpcode::SLLIW - | BaseIOpcode::SRLIW - | BaseIOpcode::SRAIW - | BaseIOpcode::ADDW - | BaseIOpcode::SUBW - | BaseIOpcode::SLLW - | BaseIOpcode::SRLW - | BaseIOpcode::SRAW => Some(rs1), - _ => None, - } -} - -pub fn parse_rs2(inst: u32, opkind: &BaseIOpcode) -> Option { - let rs2: usize = inst.slice(24, 20) as usize; - - // LUI, AUIPC, JAL, JALR L(B|H|W|BU|HU), - // ADDI, SLTI, SLTIU, XORI, ORI, ANDI, SLLI, - // FENCE, ECALL, EBREAK - match opkind { - BaseIOpcode::BEQ - | BaseIOpcode::BNE - | BaseIOpcode::BLT - | BaseIOpcode::BGE - | BaseIOpcode::BLTU - | BaseIOpcode::BGEU - | BaseIOpcode::SB - | BaseIOpcode::SH - | BaseIOpcode::SW - | BaseIOpcode::ADD - | BaseIOpcode::SUB - | BaseIOpcode::SLL - | BaseIOpcode::SLT - | BaseIOpcode::SLTU - | BaseIOpcode::XOR - | BaseIOpcode::SRL - | BaseIOpcode::SRA - | BaseIOpcode::OR - | BaseIOpcode::AND - | BaseIOpcode::SD - | BaseIOpcode::ADDW - | BaseIOpcode::SUBW - | BaseIOpcode::SLLW - | BaseIOpcode::SRLW - | BaseIOpcode::SRAW => Some(rs2), - _ => None, - } -} - -#[allow(clippy::cast_possible_wrap)] -#[allow(non_snake_case)] -pub fn parse_imm(inst: u32, opkind: &BaseIOpcode, isa: Isa) -> Option { - let U_type = || (inst.slice(31, 12) << 12) as i32; - let I_type = || { - let imm32 = inst.slice(31, 20) as i32; - inst.to_signed_nbit(imm32, 12) - }; - let S_type = || { - let imm32 = (inst.slice(11, 7).set(&[4, 3, 2, 1, 0]) - | inst.slice(31, 25).set(&[11, 10, 9, 8, 7, 6, 5])) as i32; - inst.to_signed_nbit(imm32, 12) - }; - let B_type = || { - let imm32 = (inst.slice(11, 7).set(&[4, 3, 2, 1, 11]) - | inst.slice(31, 25).set(&[12, 10, 9, 8, 7, 6, 5])) as i32; - inst.to_signed_nbit(imm32, 13) - }; - let J_type = || { - let imm32 = inst.slice(31, 12).set(&[ - 20, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 11, 19, 18, 17, 16, 15, 14, 13, 12, - ]) as i32; - inst.to_signed_nbit(imm32, 21) - }; - let shamt5 = || inst.slice(24, 20); // shamt = SHift AMounT - let shamt6 = || inst.slice(25, 20); - - match opkind { - // u-type - BaseIOpcode::LUI | BaseIOpcode::AUIPC => Some(U_type()), - // j-type - BaseIOpcode::JAL => Some(J_type()), - // b-type - BaseIOpcode::BEQ - | BaseIOpcode::BNE - | BaseIOpcode::BLT - | BaseIOpcode::BGE - | BaseIOpcode::BLTU - | BaseIOpcode::BGEU => Some(B_type()), - // i-type - BaseIOpcode::JALR - | BaseIOpcode::LB - | BaseIOpcode::LH - | BaseIOpcode::LW - | BaseIOpcode::LBU - | BaseIOpcode::LHU - | BaseIOpcode::ADDI - | BaseIOpcode::SLTI - | BaseIOpcode::SLTIU - | BaseIOpcode::XORI - | BaseIOpcode::ORI - | BaseIOpcode::ANDI - | BaseIOpcode::LWU - | BaseIOpcode::ADDIW - | BaseIOpcode::LD => Some(I_type()), - // s-type - BaseIOpcode::SD | BaseIOpcode::SB | BaseIOpcode::SH | BaseIOpcode::SW => Some(S_type()), - BaseIOpcode::SRAI | BaseIOpcode::SLLI | BaseIOpcode::SRLI => match isa { - Isa::Rv32 => Some(shamt5() as i32), // shamt - Isa::Rv64 => Some(shamt6() as i32), - }, - BaseIOpcode::SLLIW | BaseIOpcode::SRLIW | BaseIOpcode::SRAIW => Some(shamt5() as i32), - _ => None, - } -} - -#[cfg(test)] -#[allow(unused_variables)] -mod test_basei { - #[test] - #[allow(overflowing_literals)] - fn basei_decode_test() { - use super::*; - use crate::{Decode, Isa, OpcodeKind}; - - let test_32 = |inst_32: u32, - op: OpcodeKind, - rd: Option, - rs1: Option, - rs2: Option, - imm: Option| { - let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap(); - assert!(matches!(&op_32, op)); - assert_eq!(inst_32.parse_rd(&op_32).unwrap(), rd); - assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), rs1); - assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), rs2); - assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), imm); - }; - - test_32( - 0b1000_0000_0000_0000_0000_0000_1011_0111, - OpcodeKind::BaseI(BaseIOpcode::LUI), - Some(1), - None, - None, - Some(0x8000_0000), - ); - test_32( - 0b0000_0000_0000_0000_0000_0010_1001_0111, - OpcodeKind::BaseI(BaseIOpcode::AUIPC), - Some(5), - None, - None, - Some(0), - ); - test_32( - 0b1111_1111_1001_1111_1111_0000_0110_1111, - OpcodeKind::BaseI(BaseIOpcode::JAL), - Some(0), - None, - None, - Some(-8), - ); - test_32( - 0b1111_1110_0010_0000_1000_1110_1010_0011, - OpcodeKind::BaseI(BaseIOpcode::SB), - None, - Some(1), - Some(2), - Some(-3), - ); - test_32( - 0b1110_1110_1100_0010_1000_0010_1001_0011, - OpcodeKind::BaseI(BaseIOpcode::ADDI), - Some(5), - Some(5), - None, - Some(-276), - ); - test_32( - 0b0000_0000_0000_0000_0000_0000_0111_0011, - OpcodeKind::BaseI(BaseIOpcode::ECALL), - None, - None, - None, - None, - ); - test_32( - 0b0000_0000_0000_0101_0100_1100_0110_0011, - OpcodeKind::BaseI(BaseIOpcode::BLT), - None, - Some(10), - Some(0), - Some(24), - ); - test_32( - 0x0010_0513, - OpcodeKind::BaseI(BaseIOpcode::ADDI), - Some(10), - Some(0), - None, - Some(1), - ); - test_32( - 0x4170_04b3, - OpcodeKind::BaseI(BaseIOpcode::SUB), - Some(9), - Some(0), - Some(23), - None, - ); - test_32( - 0x3307_3983, - OpcodeKind::BaseI(BaseIOpcode::LD), - Some(19), - Some(14), - None, - Some(816), - ); - test_32( - 0x10ec_eb63, - OpcodeKind::BaseI(BaseIOpcode::BLTU), - None, - Some(25), - Some(14), - Some(278), - ); - test_32( - 0x31e1_60ef, - OpcodeKind::BaseI(BaseIOpcode::JAL), - Some(1), - None, - None, - Some(90910), - ); - test_32( - 0x0019_4913, - OpcodeKind::BaseI(BaseIOpcode::XORI), - Some(18), - Some(18), - None, - Some(1), - ); - test_32( - 0x00a9_3933, - OpcodeKind::BaseI(BaseIOpcode::SLTU), - Some(18), - Some(18), - Some(10), - None, - ); - } -} diff --git a/src/decode/inst_32/m_extension.rs b/src/decode/inst_32/m_extension.rs deleted file mode 100644 index 4d7f1c0..0000000 --- a/src/decode/inst_32/m_extension.rs +++ /dev/null @@ -1,149 +0,0 @@ -use super::super::{only_rv64, DecodeUtil, DecodingError}; -use crate::instruction::m_extension::MOpcode; -use crate::Isa; - -pub fn parse_opcode(inst: u32, isa: Isa) -> Result { - let opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); - let funct3: u8 = u8::try_from(inst.slice(14, 12)).unwrap(); - - match opmap { - 0b011_0011 => match funct3 { - 0b000 => Ok(MOpcode::MUL), - 0b001 => Ok(MOpcode::MULH), - 0b010 => Ok(MOpcode::MULHSU), - 0b011 => Ok(MOpcode::MULHU), - 0b100 => Ok(MOpcode::DIV), - 0b101 => Ok(MOpcode::DIVU), - 0b110 => Ok(MOpcode::REM), - 0b111 => Ok(MOpcode::REMU), - _ => Err(DecodingError::InvalidFunct3), - }, - 0b011_1011 => match funct3 { - 0b000 => only_rv64(MOpcode::MULW, isa), - 0b100 => only_rv64(MOpcode::DIVW, isa), - 0b101 => only_rv64(MOpcode::DIVUW, isa), - 0b110 => only_rv64(MOpcode::REMW, isa), - 0b111 => only_rv64(MOpcode::REMUW, isa), - _ => Err(DecodingError::InvalidFunct3), - }, - _ => Err(DecodingError::InvalidOpcode), - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rd(inst: u32, opkind: &MOpcode) -> Option { - let rd: usize = inst.slice(11, 7) as usize; - - match opkind { - MOpcode::MUL - | MOpcode::MULH - | MOpcode::MULHSU - | MOpcode::MULHU - | MOpcode::DIV - | MOpcode::DIVU - | MOpcode::REM - | MOpcode::REMU - | MOpcode::MULW - | MOpcode::DIVW - | MOpcode::DIVUW - | MOpcode::REMW - | MOpcode::REMUW => Some(rd), - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rs1(inst: u32, opkind: &MOpcode) -> Option { - let rs1: usize = inst.slice(19, 15) as usize; - - match opkind { - MOpcode::MUL - | MOpcode::MULH - | MOpcode::MULHSU - | MOpcode::MULHU - | MOpcode::DIV - | MOpcode::DIVU - | MOpcode::REM - | MOpcode::REMU - | MOpcode::MULW - | MOpcode::DIVW - | MOpcode::DIVUW - | MOpcode::REMW - | MOpcode::REMUW => Some(rs1), - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rs2(inst: u32, opkind: &MOpcode) -> Option { - let rs2: usize = inst.slice(24, 20) as usize; - - match opkind { - MOpcode::MUL - | MOpcode::MULH - | MOpcode::MULHSU - | MOpcode::MULHU - | MOpcode::DIV - | MOpcode::DIVU - | MOpcode::REM - | MOpcode::REMU - | MOpcode::MULW - | MOpcode::DIVW - | MOpcode::DIVUW - | MOpcode::REMW - | MOpcode::REMUW => Some(rs2), - } -} - -#[allow(non_snake_case)] -pub fn parse_imm(_inst: u32, _opkind: &MOpcode) -> Option { - None -} - -#[cfg(test)] -#[allow(unused_variables)] -mod test_m { - #[test] - #[allow(overflowing_literals)] - fn m_decode_test() { - use super::*; - use crate::{Decode, Isa, OpcodeKind}; - - let test_32 = |inst_32: u32, - op: OpcodeKind, - rd: Option, - rs1: Option, - rs2: Option, - imm: Option| { - let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap(); - assert!(matches!(&op_32, op)); - assert_eq!(inst_32.parse_rd(&op_32).unwrap(), rd); - assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), rs1); - assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), rs2); - assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), imm); - }; - - test_32( - 0x02d706b3, - OpcodeKind::M(MOpcode::MUL), - Some(13), - Some(14), - Some(13), - None, - ); - test_32( - 0x0289_7933, - OpcodeKind::M(MOpcode::REMU), - Some(18), - Some(18), - Some(8), - None, - ); - test_32( - 0x0289_5933, - OpcodeKind::M(MOpcode::DIVU), - Some(18), - Some(18), - Some(8), - None, - ); - } -} diff --git a/src/decode/inst_32/priv_extension.rs b/src/decode/inst_32/priv_extension.rs deleted file mode 100644 index 1d76949..0000000 --- a/src/decode/inst_32/priv_extension.rs +++ /dev/null @@ -1,88 +0,0 @@ -use super::super::{DecodeUtil, DecodingError}; -use crate::instruction::priv_extension::PrivOpcode; - -pub fn parse_opcode(inst: u32) -> Result { - let _opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); - let _funct3: u8 = u8::try_from(inst.slice(14, 12)).unwrap(); - let funct7: u8 = u8::try_from(inst.slice(31, 25)).unwrap(); - - match inst { - 0b0001_0000_0010_0000_0000_0000_0111_0011 => Ok(PrivOpcode::SRET), - 0b0011_0000_0010_0000_0000_0000_0111_0011 => Ok(PrivOpcode::MRET), - 0b0001_0000_0101_0000_0000_0000_0111_0011 => Ok(PrivOpcode::WFI), - _ => match funct7 { - 0b000_1001 => Ok(PrivOpcode::SFENCE_VMA), - _ => Err(DecodingError::InvalidFunct7), - }, - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rd(_inst: u32, _opkind: &PrivOpcode) -> Option { - None -} - -pub fn parse_rs1(inst: u32, opkind: &PrivOpcode) -> Option { - let rs1: usize = inst.slice(19, 15) as usize; - - match opkind { - PrivOpcode::SFENCE_VMA => Some(rs1), - _ => None, - } -} - -pub fn parse_rs2(inst: u32, opkind: &PrivOpcode) -> Option { - let rs2: usize = inst.slice(24, 20) as usize; - - match opkind { - PrivOpcode::SFENCE_VMA => Some(rs2), - _ => None, - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_imm(_inst: u32, _opkind: &PrivOpcode) -> Option { - None -} - -#[cfg(test)] -#[allow(unused_variables)] -mod test_priv { - #[test] - #[allow(overflowing_literals)] - fn priv_decode_test() { - use super::*; - use crate::{Decode, Isa, OpcodeKind}; - - let test_32 = |inst_32: u32, - op: OpcodeKind, - rd: Option, - rs1: Option, - rs2: Option, - imm: Option| { - let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap(); - assert!(matches!(&op_32, op)); - assert_eq!(inst_32.parse_rd(&op_32).unwrap(), rd); - assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), rs1); - assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), rs2); - assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), imm); - }; - - test_32( - 0x10200073, - OpcodeKind::Priv(PrivOpcode::SRET), - None, - None, - None, - None, - ); - test_32( - 0x10500073, - OpcodeKind::Priv(PrivOpcode::WFI), - None, - None, - None, - None, - ); - } -} diff --git a/src/decode/inst_32/zicfiss_extension.rs b/src/decode/inst_32/zicfiss_extension.rs deleted file mode 100644 index 6d118ea..0000000 --- a/src/decode/inst_32/zicfiss_extension.rs +++ /dev/null @@ -1,164 +0,0 @@ -use super::super::{DecodeUtil, DecodingError}; -use crate::instruction::zicfiss_extension::ZicfissOpcode; - -pub fn parse_opcode(inst: u32) -> Result { - let opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); - let funct3: u8 = u8::try_from(inst.slice(14, 12)).unwrap(); - let rs1: u8 = u8::try_from(inst.slice(19, 15)).unwrap(); - let funct7_rs2: u16 = u16::try_from(inst.slice(31, 20)).unwrap(); - - match opmap { - 0b111_0011 => match funct3 { - 0b100 => match funct7_rs2 { - 0b1100_1110_0001 | 0b1100_1110_0101 => Ok(ZicfissOpcode::SSPUSH), - 0b1100_1101_1100 => match rs1 { - 0b0_0000 => Ok(ZicfissOpcode::SSRDP), - _ => Ok(ZicfissOpcode::SSPOPCHK), - }, - _ => Err(DecodingError::InvalidOpcode), - }, - _ => Err(DecodingError::InvalidFunct3), - }, - 0b010_1111 => match funct3 { - 0b010 => Ok(ZicfissOpcode::SSAMOSWAP_W), - 0b011 => Ok(ZicfissOpcode::SSAMOSWAP_D), - _ => Err(DecodingError::InvalidFunct3), - }, - _ => Err(DecodingError::InvalidOpcode), - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rd(inst: u32, opkind: &ZicfissOpcode) -> Option { - let rd: usize = inst.slice(11, 7) as usize; - match opkind { - ZicfissOpcode::SSPUSH | ZicfissOpcode::SSPOPCHK => Some(0), - ZicfissOpcode::SSRDP | ZicfissOpcode::SSAMOSWAP_W | ZicfissOpcode::SSAMOSWAP_D => Some(rd), - ZicfissOpcode::C_SSPUSH | ZicfissOpcode::C_SSPOPCHK => unreachable!(), - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rs1(inst: u32, opkind: &ZicfissOpcode) -> Option { - let rs1: usize = inst.slice(19, 15) as usize; - match opkind { - ZicfissOpcode::SSPUSH => Some(0), - ZicfissOpcode::SSPOPCHK | ZicfissOpcode::SSAMOSWAP_W | ZicfissOpcode::SSAMOSWAP_D => { - Some(rs1) - } - ZicfissOpcode::SSRDP => None, - ZicfissOpcode::C_SSPUSH | ZicfissOpcode::C_SSPOPCHK => unreachable!(), - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rs2(inst: u32, opkind: &ZicfissOpcode) -> Option { - let rs2: usize = inst.slice(24, 20) as usize; - match opkind { - ZicfissOpcode::SSPUSH | ZicfissOpcode::SSAMOSWAP_W | ZicfissOpcode::SSAMOSWAP_D => { - Some(rs2) - } - ZicfissOpcode::SSPOPCHK | ZicfissOpcode::SSRDP => None, - ZicfissOpcode::C_SSPUSH | ZicfissOpcode::C_SSPOPCHK => unreachable!(), - } -} - -#[allow(clippy::cast_possible_wrap, clippy::unnecessary_wraps)] -pub fn parse_imm(_inst: u32, opkind: &ZicfissOpcode) -> Option { - match opkind { - ZicfissOpcode::SSPUSH - | ZicfissOpcode::SSPOPCHK - | ZicfissOpcode::SSRDP - | ZicfissOpcode::SSAMOSWAP_W - | ZicfissOpcode::SSAMOSWAP_D => None, - ZicfissOpcode::C_SSPUSH | ZicfissOpcode::C_SSPOPCHK => unreachable!(), - } -} - -#[cfg(test)] -#[allow(unused_variables)] -mod test_zicfiss { - #[test] - #[allow(overflowing_literals)] - fn zicfiss_32bit_decode_test() { - use super::*; - use crate::{Decode, Isa, OpcodeKind}; - - let test_32 = |inst_32: u32, - expected_op: OpcodeKind, - expected_rd: Option, - expected_rs1: Option, - expected_rs2: Option, - expected_imm: Option| { - let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap(); - assert_eq!(op_32, expected_op); - assert_eq!(inst_32.parse_rd(&op_32).unwrap(), expected_rd); - assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), expected_rs1); - assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), expected_rs2); - assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), expected_imm); - }; - - test_32( - 0b1100_1110_0101_0000_0100_0000_0111_0011, - OpcodeKind::Zicfiss(ZicfissOpcode::SSPUSH), - Some(0), - Some(0), - Some(5), - None, - ); - - test_32( - 0b1100_1110_0001_0000_0100_0000_0111_0011, - OpcodeKind::Zicfiss(ZicfissOpcode::SSPUSH), - Some(0), - Some(0), - Some(1), - None, - ); - - test_32( - 0b1100_1101_1100_0000_1100_0000_0111_0011, - OpcodeKind::Zicfiss(ZicfissOpcode::SSPOPCHK), - Some(0), - Some(1), - None, - None, - ); - - test_32( - 0b1100_1101_1100_0010_1100_0000_0111_0011, - OpcodeKind::Zicfiss(ZicfissOpcode::SSPOPCHK), - Some(0), - Some(5), - None, - None, - ); - - test_32( - 0b0100_1000_1100_0010_1010_0001_1010_1111, - OpcodeKind::Zicfiss(ZicfissOpcode::SSAMOSWAP_W), - Some(3), - Some(5), - Some(12), - None, - ); - - test_32( - 0b0100_1000_1100_0111_0011_0001_1010_1111, - OpcodeKind::Zicfiss(ZicfissOpcode::SSAMOSWAP_D), - Some(3), - Some(14), - Some(12), - None, - ); - - test_32( - 0xcdc0c073, - OpcodeKind::Zicfiss(ZicfissOpcode::SSPOPCHK), - Some(0), - Some(1), - None, - None, - ); - } -} diff --git a/src/decode/inst_32/zicntr_extension.rs b/src/decode/inst_32/zicntr_extension.rs deleted file mode 100644 index 1fbd18c..0000000 --- a/src/decode/inst_32/zicntr_extension.rs +++ /dev/null @@ -1,107 +0,0 @@ -use super::super::{DecodeUtil, DecodingError}; -use crate::instruction::zicntr_extension::ZicntrOpcode; - -pub fn parse_opcode(inst: u32) -> Result { - let opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); - let funct3: u8 = u8::try_from(inst.slice(14, 12)).unwrap(); - let csr_num: u16 = u16::try_from(inst.slice(31, 20)).unwrap(); - - match opmap { - 0b111_0011 => match funct3 { - 0b010 => match csr_num { - 0xc00 => Ok(ZicntrOpcode::RDCYCLE), - 0xc01 => Ok(ZicntrOpcode::RDTIME), - 0xc02 => Ok(ZicntrOpcode::RDINSTRET), - 0xc80 => Ok(ZicntrOpcode::RDCYCLE_H), - 0xc81 => Ok(ZicntrOpcode::RDTIME_H), - 0xc82 => Ok(ZicntrOpcode::RDINSTRET_H), - _ => Err(DecodingError::InvalidOpcode), - }, - _ => Err(DecodingError::InvalidFunct3), - }, - _ => Err(DecodingError::InvalidOpcode), - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rd(inst: u32, opkind: &ZicntrOpcode) -> Option { - let rd: usize = inst.slice(11, 7) as usize; - match opkind { - ZicntrOpcode::RDCYCLE - | ZicntrOpcode::RDTIME - | ZicntrOpcode::RDINSTRET - | ZicntrOpcode::RDCYCLE_H - | ZicntrOpcode::RDTIME_H - | ZicntrOpcode::RDINSTRET_H => Some(rd), - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rs1(_inst: u32, opkind: &ZicntrOpcode) -> Option { - match opkind { - ZicntrOpcode::RDCYCLE - | ZicntrOpcode::RDTIME - | ZicntrOpcode::RDINSTRET - | ZicntrOpcode::RDCYCLE_H - | ZicntrOpcode::RDTIME_H - | ZicntrOpcode::RDINSTRET_H => None, - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rs2(_inst: u32, opkind: &ZicntrOpcode) -> Option { - match opkind { - ZicntrOpcode::RDCYCLE - | ZicntrOpcode::RDTIME - | ZicntrOpcode::RDINSTRET - | ZicntrOpcode::RDCYCLE_H - | ZicntrOpcode::RDTIME_H - | ZicntrOpcode::RDINSTRET_H => None, - } -} - -#[allow(clippy::cast_possible_wrap, clippy::unnecessary_wraps)] -pub fn parse_imm(_inst: u32, opkind: &ZicntrOpcode) -> Option { - match opkind { - ZicntrOpcode::RDCYCLE - | ZicntrOpcode::RDTIME - | ZicntrOpcode::RDINSTRET - | ZicntrOpcode::RDCYCLE_H - | ZicntrOpcode::RDTIME_H - | ZicntrOpcode::RDINSTRET_H => None, - } -} - -#[cfg(test)] -#[allow(unused_variables)] -mod test_zicntr { - #[test] - #[allow(overflowing_literals)] - fn zicntr_decode_test() { - use super::*; - use crate::{Decode, Isa, OpcodeKind}; - - let test_32 = |inst_32: u32, - op: OpcodeKind, - rd: Option, - rs1: Option, - rs2: Option, - imm: Option| { - let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap(); - assert!(matches!(&op_32, op)); - assert_eq!(inst_32.parse_rd(&op_32).unwrap(), rd); - assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), rs1); - assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), rs2); - assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), imm); - }; - - test_32( - 0b1100_0000_0001_0000_0010_0111_1111_0011, - OpcodeKind::Zicntr(ZicntrOpcode::RDTIME), - Some(15), - None, - None, - None, - ) - } -} diff --git a/src/decode/inst_32/zicsr_extension.rs b/src/decode/inst_32/zicsr_extension.rs deleted file mode 100644 index adf183b..0000000 --- a/src/decode/inst_32/zicsr_extension.rs +++ /dev/null @@ -1,117 +0,0 @@ -use super::super::{DecodeUtil, DecodingError}; -use crate::instruction::zicsr_extension::ZicsrOpcode; - -pub fn parse_opcode(inst: u32) -> Result { - let opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); - let funct3: u8 = u8::try_from(inst.slice(14, 12)).unwrap(); - - match opmap { - 0b111_0011 => match funct3 { - 0b001 => Ok(ZicsrOpcode::CSRRW), - 0b010 => Ok(ZicsrOpcode::CSRRS), - 0b011 => Ok(ZicsrOpcode::CSRRC), - 0b101 => Ok(ZicsrOpcode::CSRRWI), - 0b110 => Ok(ZicsrOpcode::CSRRSI), - 0b111 => Ok(ZicsrOpcode::CSRRCI), - _ => Err(DecodingError::InvalidFunct3), - }, - _ => Err(DecodingError::InvalidOpcode), - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rd(inst: u32, opkind: &ZicsrOpcode) -> Option { - let rd: usize = inst.slice(11, 7) as usize; - - match opkind { - ZicsrOpcode::CSRRW - | ZicsrOpcode::CSRRS - | ZicsrOpcode::CSRRC - | ZicsrOpcode::CSRRWI - | ZicsrOpcode::CSRRSI - | ZicsrOpcode::CSRRCI => Some(rd), - } -} - -pub fn parse_rs1(inst: u32, opkind: &ZicsrOpcode) -> Option { - let rs1: usize = inst.slice(19, 15) as usize; - - // LUI, AUIPC, JAL, FENCE, ECALL, EBREAK - match opkind { - ZicsrOpcode::CSRRW | ZicsrOpcode::CSRRS | ZicsrOpcode::CSRRC => Some(rs1), - _ => None, - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rs2(inst: u32, opkind: &ZicsrOpcode) -> Option { - let csr: usize = inst.slice(31, 20) as usize; - - match opkind { - ZicsrOpcode::CSRRW - | ZicsrOpcode::CSRRS - | ZicsrOpcode::CSRRC - | ZicsrOpcode::CSRRWI - | ZicsrOpcode::CSRRSI - | ZicsrOpcode::CSRRCI => Some(csr), - } -} - -#[allow(clippy::cast_possible_wrap)] -pub fn parse_imm(inst: u32, opkind: &ZicsrOpcode) -> Option { - let uimm: u32 = inst.slice(19, 15); - match opkind { - ZicsrOpcode::CSRRWI | ZicsrOpcode::CSRRSI | ZicsrOpcode::CSRRCI => Some(uimm as i32), - _ => None, - } -} - -#[cfg(test)] -#[allow(unused_variables)] -mod test_zicsr { - #[test] - #[allow(overflowing_literals)] - fn zicsr_decode_test() { - use super::*; - use crate::{Decode, Isa, OpcodeKind}; - - let test_32 = |inst_32: u32, - op: OpcodeKind, - rd: Option, - rs1: Option, - rs2: Option, - imm: Option| { - let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap(); - assert!(matches!(&op_32, op)); - assert_eq!(inst_32.parse_rd(&op_32).unwrap(), rd); - assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), rs1); - assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), rs2); - assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), imm); - }; - - test_32( - 0b0001_0000_0000_1000_0011_0000_0111_0011, - OpcodeKind::Zicsr(ZicsrOpcode::CSRRC), - Some(0), // rd - Some(16), // rs1 - Some(0x100), // csr - None, - ); - test_32( - 0b0001_0000_0000_1000_0010_0000_0111_0011, - OpcodeKind::Zicsr(ZicsrOpcode::CSRRS), - Some(0), // rd - Some(16), // rs1 - Some(0x100), // csr - None, - ); - test_32( - 0b0001_0000_0000_0001_0110_0000_0111_0011, - OpcodeKind::Zicsr(ZicsrOpcode::CSRRSI), - Some(0), // rd - None, // rs1 - Some(0x100), // csr - Some(2), // imm - ); - } -} diff --git a/src/decode/inst_32/zifencei_extension.rs b/src/decode/inst_32/zifencei_extension.rs deleted file mode 100644 index 0a5faa0..0000000 --- a/src/decode/inst_32/zifencei_extension.rs +++ /dev/null @@ -1,78 +0,0 @@ -use super::super::{DecodeUtil, DecodingError}; -use crate::instruction::zifencei_extension::ZifenceiOpcode; - -pub fn parse_opcode(inst: u32) -> Result { - let opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); - - match opmap { - 0b000_1111 => Ok(ZifenceiOpcode::FENCE), - _ => Err(DecodingError::InvalidOpcode), - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rd(inst: u32, opkind: &ZifenceiOpcode) -> Option { - let rd: usize = inst.slice(11, 7) as usize; - - match opkind { - ZifenceiOpcode::FENCE => Some(rd), - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rs1(inst: u32, opkind: &ZifenceiOpcode) -> Option { - let rs1: usize = inst.slice(19, 15) as usize; - - match opkind { - ZifenceiOpcode::FENCE => Some(rs1), - } -} - -#[allow(clippy::unnecessary_wraps)] -pub fn parse_rs2(_inst: u32, opkind: &ZifenceiOpcode) -> Option { - match opkind { - ZifenceiOpcode::FENCE => None, - } -} - -#[allow(clippy::cast_possible_wrap, clippy::unnecessary_wraps)] -pub fn parse_imm(inst: u32, opkind: &ZifenceiOpcode) -> Option { - let fm_pred_succ: u32 = inst.slice(31, 20); - match opkind { - ZifenceiOpcode::FENCE => Some(fm_pred_succ as i32), - } -} - -#[cfg(test)] -#[allow(unused_variables)] -mod test_zifenci { - #[test] - #[allow(overflowing_literals)] - fn zifenci_decode_test() { - use super::*; - use crate::{Decode, Isa, OpcodeKind}; - - let test_32 = |inst_32: u32, - op: OpcodeKind, - rd: Option, - rs1: Option, - rs2: Option, - imm: Option| { - let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap(); - assert!(matches!(&op_32, op)); - assert_eq!(inst_32.parse_rd(&op_32).unwrap(), rd); - assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), rs1); - assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), rs2); - assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), imm); - }; - - test_32( - 0b0000_0011_0011_0000_0000_0000_0000_1111, - OpcodeKind::Zifencei(ZifenceiOpcode::FENCE), - Some(0), - Some(0), - None, - Some(0b0011_0011), - ) - } -} diff --git a/src/decode/m_extension.rs b/src/decode/m_extension.rs new file mode 100644 index 0000000..5a90809 --- /dev/null +++ b/src/decode/m_extension.rs @@ -0,0 +1,151 @@ +pub mod bit_32 { + use super::super::{only_rv64, DecodeUtil, DecodingError}; + use crate::instruction::m_extension::MOpcode; + use crate::Isa; + + pub fn parse_opcode(inst: u32, isa: Isa) -> Result { + let opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); + let funct3: u8 = u8::try_from(inst.slice(14, 12)).unwrap(); + + match opmap { + 0b011_0011 => match funct3 { + 0b000 => Ok(MOpcode::MUL), + 0b001 => Ok(MOpcode::MULH), + 0b010 => Ok(MOpcode::MULHSU), + 0b011 => Ok(MOpcode::MULHU), + 0b100 => Ok(MOpcode::DIV), + 0b101 => Ok(MOpcode::DIVU), + 0b110 => Ok(MOpcode::REM), + 0b111 => Ok(MOpcode::REMU), + _ => Err(DecodingError::InvalidFunct3), + }, + 0b011_1011 => match funct3 { + 0b000 => only_rv64(MOpcode::MULW, isa), + 0b100 => only_rv64(MOpcode::DIVW, isa), + 0b101 => only_rv64(MOpcode::DIVUW, isa), + 0b110 => only_rv64(MOpcode::REMW, isa), + 0b111 => only_rv64(MOpcode::REMUW, isa), + _ => Err(DecodingError::InvalidFunct3), + }, + _ => Err(DecodingError::InvalidOpcode), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rd(inst: u32, opkind: &MOpcode) -> Option { + let rd: usize = inst.slice(11, 7) as usize; + + match opkind { + MOpcode::MUL + | MOpcode::MULH + | MOpcode::MULHSU + | MOpcode::MULHU + | MOpcode::DIV + | MOpcode::DIVU + | MOpcode::REM + | MOpcode::REMU + | MOpcode::MULW + | MOpcode::DIVW + | MOpcode::DIVUW + | MOpcode::REMW + | MOpcode::REMUW => Some(rd), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rs1(inst: u32, opkind: &MOpcode) -> Option { + let rs1: usize = inst.slice(19, 15) as usize; + + match opkind { + MOpcode::MUL + | MOpcode::MULH + | MOpcode::MULHSU + | MOpcode::MULHU + | MOpcode::DIV + | MOpcode::DIVU + | MOpcode::REM + | MOpcode::REMU + | MOpcode::MULW + | MOpcode::DIVW + | MOpcode::DIVUW + | MOpcode::REMW + | MOpcode::REMUW => Some(rs1), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rs2(inst: u32, opkind: &MOpcode) -> Option { + let rs2: usize = inst.slice(24, 20) as usize; + + match opkind { + MOpcode::MUL + | MOpcode::MULH + | MOpcode::MULHSU + | MOpcode::MULHU + | MOpcode::DIV + | MOpcode::DIVU + | MOpcode::REM + | MOpcode::REMU + | MOpcode::MULW + | MOpcode::DIVW + | MOpcode::DIVUW + | MOpcode::REMW + | MOpcode::REMUW => Some(rs2), + } + } + + #[allow(non_snake_case)] + pub fn parse_imm(_inst: u32, _opkind: &MOpcode) -> Option { + None + } +} + +#[cfg(test)] +#[allow(unused_variables)] +mod test_m { + #[test] + #[allow(overflowing_literals)] + fn m_decode_test() { + use crate::instruction::m_extension::MOpcode; + use crate::{Decode, Isa, OpcodeKind}; + + let test_32 = |inst_32: u32, + op: OpcodeKind, + rd: Option, + rs1: Option, + rs2: Option, + imm: Option| { + let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap(); + assert!(matches!(&op_32, op)); + assert_eq!(inst_32.parse_rd(&op_32).unwrap(), rd); + assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), rs1); + assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), rs2); + assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), imm); + }; + + test_32( + 0x02d706b3, + OpcodeKind::M(MOpcode::MUL), + Some(13), + Some(14), + Some(13), + None, + ); + test_32( + 0x0289_7933, + OpcodeKind::M(MOpcode::REMU), + Some(18), + Some(18), + Some(8), + None, + ); + test_32( + 0x0289_5933, + OpcodeKind::M(MOpcode::DIVU), + Some(18), + Some(18), + Some(8), + None, + ); + } +} diff --git a/src/decode/priv_extension.rs b/src/decode/priv_extension.rs new file mode 100644 index 0000000..b06fc24 --- /dev/null +++ b/src/decode/priv_extension.rs @@ -0,0 +1,90 @@ +pub mod bit_32 { + use super::super::{DecodeUtil, DecodingError}; + use crate::instruction::priv_extension::PrivOpcode; + + pub fn parse_opcode(inst: u32) -> Result { + let _opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); + let _funct3: u8 = u8::try_from(inst.slice(14, 12)).unwrap(); + let funct7: u8 = u8::try_from(inst.slice(31, 25)).unwrap(); + + match inst { + 0b0001_0000_0010_0000_0000_0000_0111_0011 => Ok(PrivOpcode::SRET), + 0b0011_0000_0010_0000_0000_0000_0111_0011 => Ok(PrivOpcode::MRET), + 0b0001_0000_0101_0000_0000_0000_0111_0011 => Ok(PrivOpcode::WFI), + _ => match funct7 { + 0b000_1001 => Ok(PrivOpcode::SFENCE_VMA), + _ => Err(DecodingError::InvalidFunct7), + }, + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rd(_inst: u32, _opkind: &PrivOpcode) -> Option { + None + } + + pub fn parse_rs1(inst: u32, opkind: &PrivOpcode) -> Option { + let rs1: usize = inst.slice(19, 15) as usize; + + match opkind { + PrivOpcode::SFENCE_VMA => Some(rs1), + _ => None, + } + } + + pub fn parse_rs2(inst: u32, opkind: &PrivOpcode) -> Option { + let rs2: usize = inst.slice(24, 20) as usize; + + match opkind { + PrivOpcode::SFENCE_VMA => Some(rs2), + _ => None, + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_imm(_inst: u32, _opkind: &PrivOpcode) -> Option { + None + } +} + +#[cfg(test)] +#[allow(unused_variables)] +mod test_priv { + #[test] + #[allow(overflowing_literals)] + fn priv_decode_test() { + use crate::instruction::priv_extension::PrivOpcode; + use crate::{Decode, Isa, OpcodeKind}; + + let test_32 = |inst_32: u32, + op: OpcodeKind, + rd: Option, + rs1: Option, + rs2: Option, + imm: Option| { + let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap(); + assert!(matches!(&op_32, op)); + assert_eq!(inst_32.parse_rd(&op_32).unwrap(), rd); + assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), rs1); + assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), rs2); + assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), imm); + }; + + test_32( + 0x10200073, + OpcodeKind::Priv(PrivOpcode::SRET), + None, + None, + None, + None, + ); + test_32( + 0x10500073, + OpcodeKind::Priv(PrivOpcode::WFI), + None, + None, + None, + None, + ); + } +} diff --git a/src/decode/zicboz_extension.rs b/src/decode/zicboz_extension.rs new file mode 100644 index 0000000..8f115f3 --- /dev/null +++ b/src/decode/zicboz_extension.rs @@ -0,0 +1,91 @@ +pub mod bit_32 { + use super::super::{DecodeUtil, DecodingError}; + use crate::instruction::zicboz_extension::ZicbozOpcode; + + pub fn parse_opcode(inst: u32) -> Result { + let opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); + let funct3: u8 = u8::try_from(inst.slice(14, 12)).unwrap(); + let field_11_7: u8 = u8::try_from(inst.slice(11, 7)).unwrap(); + let cbo_num: u16 = u16::try_from(inst.slice(31, 20)).unwrap(); + + match opmap { + 0b000_1111 => match funct3 { + 0b010 => match cbo_num { + 0b100 => match field_11_7 { + 0x0 => Ok(ZicbozOpcode::CBO_ZERO), + _ => Err(DecodingError::InvalidOpcode), + }, + _ => Err(DecodingError::InvalidOpcode), + }, + _ => Err(DecodingError::InvalidFunct3), + }, + _ => Err(DecodingError::InvalidOpcode), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rd(_inst: u32, _opkind: &ZicbozOpcode) -> Option { + None + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rs1(inst: u32, opkind: &ZicbozOpcode) -> Option { + let rs1: u8 = u8::try_from(inst.slice(19, 15)).unwrap(); + match opkind { + ZicbozOpcode::CBO_ZERO => Some(rs1.into()), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rs2(_inst: u32, _opkind: &ZicbozOpcode) -> Option { + None + } + + #[allow(clippy::cast_possible_wrap, clippy::unnecessary_wraps)] + pub fn parse_imm(_inst: u32, _opkind: &ZicbozOpcode) -> Option { + None + } +} + +#[cfg(test)] +#[allow(unused_variables)] +mod test_zicboz { + #[test] + #[allow(overflowing_literals)] + fn zicboz_decode_test() { + use crate::instruction::zicboz_extension::ZicbozOpcode; + use crate::{Decode, Isa, OpcodeKind}; + + let test_32 = |inst_32: u32, + op: OpcodeKind, + rd: Option, + rs1: Option, + rs2: Option, + imm: Option| { + let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap(); + assert!(matches!(&op_32, op)); + assert_eq!(inst_32.parse_rd(&op_32).unwrap(), rd); + assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), rs1); + assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), rs2); + assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), imm); + }; + + test_32( + 0b0000_0000_0100_1010_1010_0000_0000_1111, + OpcodeKind::Zicboz(ZicbozOpcode::CBO_ZERO), + None, + Some(21), + None, + None, + ); + + test_32( + 0b0000_0000_0100_1000_0010_0000_0000_1111, + OpcodeKind::Zicboz(ZicbozOpcode::CBO_ZERO), + None, + Some(16), + None, + None, + ); + } +} diff --git a/src/decode/zicfiss_extension.rs b/src/decode/zicfiss_extension.rs new file mode 100644 index 0000000..63bc513 --- /dev/null +++ b/src/decode/zicfiss_extension.rs @@ -0,0 +1,244 @@ +pub mod bit_32 { + use super::super::{DecodeUtil, DecodingError}; + use crate::instruction::zicfiss_extension::ZicfissOpcode; + + pub fn parse_opcode(inst: u32) -> Result { + let opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); + let funct3: u8 = u8::try_from(inst.slice(14, 12)).unwrap(); + let rs1: u8 = u8::try_from(inst.slice(19, 15)).unwrap(); + let funct7_rs2: u16 = u16::try_from(inst.slice(31, 20)).unwrap(); + + match opmap { + 0b111_0011 => match funct3 { + 0b100 => match funct7_rs2 { + 0b1100_1110_0001 | 0b1100_1110_0101 => Ok(ZicfissOpcode::SSPUSH), + 0b1100_1101_1100 => match rs1 { + 0b0_0000 => Ok(ZicfissOpcode::SSRDP), + _ => Ok(ZicfissOpcode::SSPOPCHK), + }, + _ => Err(DecodingError::InvalidOpcode), + }, + _ => Err(DecodingError::InvalidFunct3), + }, + 0b010_1111 => match funct3 { + 0b010 => Ok(ZicfissOpcode::SSAMOSWAP_W), + 0b011 => Ok(ZicfissOpcode::SSAMOSWAP_D), + _ => Err(DecodingError::InvalidFunct3), + }, + _ => Err(DecodingError::InvalidOpcode), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rd(inst: u32, opkind: &ZicfissOpcode) -> Option { + let rd: usize = inst.slice(11, 7) as usize; + match opkind { + ZicfissOpcode::SSPUSH | ZicfissOpcode::SSPOPCHK => Some(0), + ZicfissOpcode::SSRDP | ZicfissOpcode::SSAMOSWAP_W | ZicfissOpcode::SSAMOSWAP_D => { + Some(rd) + } + ZicfissOpcode::C_SSPUSH | ZicfissOpcode::C_SSPOPCHK => unreachable!(), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rs1(inst: u32, opkind: &ZicfissOpcode) -> Option { + let rs1: usize = inst.slice(19, 15) as usize; + match opkind { + ZicfissOpcode::SSPUSH => Some(0), + ZicfissOpcode::SSPOPCHK | ZicfissOpcode::SSAMOSWAP_W | ZicfissOpcode::SSAMOSWAP_D => { + Some(rs1) + } + ZicfissOpcode::SSRDP => None, + ZicfissOpcode::C_SSPUSH | ZicfissOpcode::C_SSPOPCHK => unreachable!(), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rs2(inst: u32, opkind: &ZicfissOpcode) -> Option { + let rs2: usize = inst.slice(24, 20) as usize; + match opkind { + ZicfissOpcode::SSPUSH | ZicfissOpcode::SSAMOSWAP_W | ZicfissOpcode::SSAMOSWAP_D => { + Some(rs2) + } + ZicfissOpcode::SSPOPCHK | ZicfissOpcode::SSRDP => None, + ZicfissOpcode::C_SSPUSH | ZicfissOpcode::C_SSPOPCHK => unreachable!(), + } + } + + #[allow(clippy::cast_possible_wrap, clippy::unnecessary_wraps)] + pub fn parse_imm(_inst: u32, opkind: &ZicfissOpcode) -> Option { + match opkind { + ZicfissOpcode::SSPUSH + | ZicfissOpcode::SSPOPCHK + | ZicfissOpcode::SSRDP + | ZicfissOpcode::SSAMOSWAP_W + | ZicfissOpcode::SSAMOSWAP_D => None, + ZicfissOpcode::C_SSPUSH | ZicfissOpcode::C_SSPOPCHK => unreachable!(), + } + } +} + +pub mod bit_16 { + use super::super::DecodingError; + use crate::instruction::zicfiss_extension::ZicfissOpcode; + use crate::Isa; + + pub fn parse_opcode(inst: u16, _isa: Isa) -> Result { + match inst { + 0b0110_0000_1000_0001 => Ok(ZicfissOpcode::C_SSPUSH), + 0b0110_0010_1000_0001 => Ok(ZicfissOpcode::C_SSPOPCHK), + _ => Err(DecodingError::InvalidOpcode), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rd(_inst: u16, opkind: &ZicfissOpcode) -> Option { + match opkind { + ZicfissOpcode::C_SSPUSH => Some(1), + ZicfissOpcode::C_SSPOPCHK => Some(5), + _ => unreachable!(), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rs1(_inst: u16, _opkind: &ZicfissOpcode) -> Option { + None + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rs2(_inst: u16, _opkind: &ZicfissOpcode) -> Option { + None + } + + #[allow(clippy::cast_possible_wrap, clippy::unnecessary_wraps)] + pub fn parse_imm(_inst: u16, _opkind: &ZicfissOpcode) -> Option { + None + } +} + +#[cfg(test)] +#[allow(unused_variables)] +mod test_zicfiss { + #[test] + #[allow(overflowing_literals)] + fn zicfiss_32bit_decode_test() { + use crate::instruction::zicfiss_extension::ZicfissOpcode; + use crate::{Decode, Isa, OpcodeKind}; + + let test_32 = |inst_32: u32, + expected_op: OpcodeKind, + expected_rd: Option, + expected_rs1: Option, + expected_rs2: Option, + expected_imm: Option| { + let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap(); + assert_eq!(op_32, expected_op); + assert_eq!(inst_32.parse_rd(&op_32).unwrap(), expected_rd); + assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), expected_rs1); + assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), expected_rs2); + assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), expected_imm); + }; + + test_32( + 0b1100_1110_0101_0000_0100_0000_0111_0011, + OpcodeKind::Zicfiss(ZicfissOpcode::SSPUSH), + Some(0), + Some(0), + Some(5), + None, + ); + + test_32( + 0b1100_1110_0001_0000_0100_0000_0111_0011, + OpcodeKind::Zicfiss(ZicfissOpcode::SSPUSH), + Some(0), + Some(0), + Some(1), + None, + ); + + test_32( + 0b1100_1101_1100_0000_1100_0000_0111_0011, + OpcodeKind::Zicfiss(ZicfissOpcode::SSPOPCHK), + Some(0), + Some(1), + None, + None, + ); + + test_32( + 0b1100_1101_1100_0010_1100_0000_0111_0011, + OpcodeKind::Zicfiss(ZicfissOpcode::SSPOPCHK), + Some(0), + Some(5), + None, + None, + ); + + test_32( + 0b0100_1000_1100_0010_1010_0001_1010_1111, + OpcodeKind::Zicfiss(ZicfissOpcode::SSAMOSWAP_W), + Some(3), + Some(5), + Some(12), + None, + ); + + test_32( + 0b0100_1000_1100_0111_0011_0001_1010_1111, + OpcodeKind::Zicfiss(ZicfissOpcode::SSAMOSWAP_D), + Some(3), + Some(14), + Some(12), + None, + ); + + test_32( + 0xcdc0c073, + OpcodeKind::Zicfiss(ZicfissOpcode::SSPOPCHK), + Some(0), + Some(1), + None, + None, + ); + } + + #[test] + #[allow(overflowing_literals)] + fn zicfiss_16() { + use crate::instruction::zicfiss_extension::ZicfissOpcode; + use crate::{Decode, Isa, OpcodeKind}; + let test_16 = |inst_16: u16, + op: OpcodeKind, + rd: Option, + rs1: Option, + rs2: Option, + imm: Option| { + let op_16 = inst_16.parse_opcode(Isa::Rv64).unwrap(); + assert!(matches!(&op_16, op)); + assert_eq!(inst_16.parse_rd(&op_16).unwrap(), rd); + assert_eq!(inst_16.parse_rs1(&op_16).unwrap(), rs1); + assert_eq!(inst_16.parse_rs2(&op_16).unwrap(), rs2); + assert_eq!(inst_16.parse_imm(&op_16, Isa::Rv64).unwrap(), imm); + }; + + test_16( + 0x6081, + OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPUSH), + Some(1), + None, + None, + None, + ); + + test_16( + 0x6281, + OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPOPCHK), + Some(5), + None, + None, + None, + ); + } +} diff --git a/src/decode/zicntr_extension.rs b/src/decode/zicntr_extension.rs new file mode 100644 index 0000000..dde7840 --- /dev/null +++ b/src/decode/zicntr_extension.rs @@ -0,0 +1,109 @@ +pub mod bit_32 { + use super::super::{DecodeUtil, DecodingError}; + use crate::instruction::zicntr_extension::ZicntrOpcode; + + pub fn parse_opcode(inst: u32) -> Result { + let opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); + let funct3: u8 = u8::try_from(inst.slice(14, 12)).unwrap(); + let csr_num: u16 = u16::try_from(inst.slice(31, 20)).unwrap(); + + match opmap { + 0b111_0011 => match funct3 { + 0b010 => match csr_num { + 0xc00 => Ok(ZicntrOpcode::RDCYCLE), + 0xc01 => Ok(ZicntrOpcode::RDTIME), + 0xc02 => Ok(ZicntrOpcode::RDINSTRET), + 0xc80 => Ok(ZicntrOpcode::RDCYCLE_H), + 0xc81 => Ok(ZicntrOpcode::RDTIME_H), + 0xc82 => Ok(ZicntrOpcode::RDINSTRET_H), + _ => Err(DecodingError::InvalidOpcode), + }, + _ => Err(DecodingError::InvalidFunct3), + }, + _ => Err(DecodingError::InvalidOpcode), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rd(inst: u32, opkind: &ZicntrOpcode) -> Option { + let rd: usize = inst.slice(11, 7) as usize; + match opkind { + ZicntrOpcode::RDCYCLE + | ZicntrOpcode::RDTIME + | ZicntrOpcode::RDINSTRET + | ZicntrOpcode::RDCYCLE_H + | ZicntrOpcode::RDTIME_H + | ZicntrOpcode::RDINSTRET_H => Some(rd), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rs1(_inst: u32, opkind: &ZicntrOpcode) -> Option { + match opkind { + ZicntrOpcode::RDCYCLE + | ZicntrOpcode::RDTIME + | ZicntrOpcode::RDINSTRET + | ZicntrOpcode::RDCYCLE_H + | ZicntrOpcode::RDTIME_H + | ZicntrOpcode::RDINSTRET_H => None, + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rs2(_inst: u32, opkind: &ZicntrOpcode) -> Option { + match opkind { + ZicntrOpcode::RDCYCLE + | ZicntrOpcode::RDTIME + | ZicntrOpcode::RDINSTRET + | ZicntrOpcode::RDCYCLE_H + | ZicntrOpcode::RDTIME_H + | ZicntrOpcode::RDINSTRET_H => None, + } + } + + #[allow(clippy::cast_possible_wrap, clippy::unnecessary_wraps)] + pub fn parse_imm(_inst: u32, opkind: &ZicntrOpcode) -> Option { + match opkind { + ZicntrOpcode::RDCYCLE + | ZicntrOpcode::RDTIME + | ZicntrOpcode::RDINSTRET + | ZicntrOpcode::RDCYCLE_H + | ZicntrOpcode::RDTIME_H + | ZicntrOpcode::RDINSTRET_H => None, + } + } +} + +#[cfg(test)] +#[allow(unused_variables)] +mod test_zicntr { + #[test] + #[allow(overflowing_literals)] + fn zicntr_decode_test() { + use crate::instruction::zicntr_extension::ZicntrOpcode; + use crate::{Decode, Isa, OpcodeKind}; + + let test_32 = |inst_32: u32, + op: OpcodeKind, + rd: Option, + rs1: Option, + rs2: Option, + imm: Option| { + let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap(); + assert!(matches!(&op_32, op)); + assert_eq!(inst_32.parse_rd(&op_32).unwrap(), rd); + assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), rs1); + assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), rs2); + assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), imm); + }; + + test_32( + 0b1100_0000_0001_0000_0010_0111_1111_0011, + OpcodeKind::Zicntr(ZicntrOpcode::RDTIME), + Some(15), + None, + None, + None, + ); + } +} diff --git a/src/decode/zicsr_extension.rs b/src/decode/zicsr_extension.rs new file mode 100644 index 0000000..aa6ff6a --- /dev/null +++ b/src/decode/zicsr_extension.rs @@ -0,0 +1,119 @@ +pub mod bit_32 { + use super::super::{DecodeUtil, DecodingError}; + use crate::instruction::zicsr_extension::ZicsrOpcode; + + pub fn parse_opcode(inst: u32) -> Result { + let opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); + let funct3: u8 = u8::try_from(inst.slice(14, 12)).unwrap(); + + match opmap { + 0b111_0011 => match funct3 { + 0b001 => Ok(ZicsrOpcode::CSRRW), + 0b010 => Ok(ZicsrOpcode::CSRRS), + 0b011 => Ok(ZicsrOpcode::CSRRC), + 0b101 => Ok(ZicsrOpcode::CSRRWI), + 0b110 => Ok(ZicsrOpcode::CSRRSI), + 0b111 => Ok(ZicsrOpcode::CSRRCI), + _ => Err(DecodingError::InvalidFunct3), + }, + _ => Err(DecodingError::InvalidOpcode), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rd(inst: u32, opkind: &ZicsrOpcode) -> Option { + let rd: usize = inst.slice(11, 7) as usize; + + match opkind { + ZicsrOpcode::CSRRW + | ZicsrOpcode::CSRRS + | ZicsrOpcode::CSRRC + | ZicsrOpcode::CSRRWI + | ZicsrOpcode::CSRRSI + | ZicsrOpcode::CSRRCI => Some(rd), + } + } + + pub fn parse_rs1(inst: u32, opkind: &ZicsrOpcode) -> Option { + let rs1: usize = inst.slice(19, 15) as usize; + + // LUI, AUIPC, JAL, FENCE, ECALL, EBREAK + match opkind { + ZicsrOpcode::CSRRW | ZicsrOpcode::CSRRS | ZicsrOpcode::CSRRC => Some(rs1), + _ => None, + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rs2(inst: u32, opkind: &ZicsrOpcode) -> Option { + let csr: usize = inst.slice(31, 20) as usize; + + match opkind { + ZicsrOpcode::CSRRW + | ZicsrOpcode::CSRRS + | ZicsrOpcode::CSRRC + | ZicsrOpcode::CSRRWI + | ZicsrOpcode::CSRRSI + | ZicsrOpcode::CSRRCI => Some(csr), + } + } + + #[allow(clippy::cast_possible_wrap)] + pub fn parse_imm(inst: u32, opkind: &ZicsrOpcode) -> Option { + let uimm: u32 = inst.slice(19, 15); + match opkind { + ZicsrOpcode::CSRRWI | ZicsrOpcode::CSRRSI | ZicsrOpcode::CSRRCI => Some(uimm as i32), + _ => None, + } + } +} + +#[cfg(test)] +#[allow(unused_variables)] +mod test_zicsr { + #[test] + #[allow(overflowing_literals)] + fn zicsr_decode_test() { + use crate::instruction::zicsr_extension::ZicsrOpcode; + use crate::{Decode, Isa, OpcodeKind}; + + let test_32 = |inst_32: u32, + op: OpcodeKind, + rd: Option, + rs1: Option, + rs2: Option, + imm: Option| { + let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap(); + assert!(matches!(&op_32, op)); + assert_eq!(inst_32.parse_rd(&op_32).unwrap(), rd); + assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), rs1); + assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), rs2); + assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), imm); + }; + + test_32( + 0b0001_0000_0000_1000_0011_0000_0111_0011, + OpcodeKind::Zicsr(ZicsrOpcode::CSRRC), + Some(0), // rd + Some(16), // rs1 + Some(0x100), // csr + None, + ); + test_32( + 0b0001_0000_0000_1000_0010_0000_0111_0011, + OpcodeKind::Zicsr(ZicsrOpcode::CSRRS), + Some(0), // rd + Some(16), // rs1 + Some(0x100), // csr + None, + ); + test_32( + 0b0001_0000_0000_0001_0110_0000_0111_0011, + OpcodeKind::Zicsr(ZicsrOpcode::CSRRSI), + Some(0), // rd + None, // rs1 + Some(0x100), // csr + Some(2), // imm + ); + } +} diff --git a/src/decode/zifencei_extension.rs b/src/decode/zifencei_extension.rs new file mode 100644 index 0000000..3569c83 --- /dev/null +++ b/src/decode/zifencei_extension.rs @@ -0,0 +1,80 @@ +pub mod bit_32 { + use super::super::{DecodeUtil, DecodingError}; + use crate::instruction::zifencei_extension::ZifenceiOpcode; + + pub fn parse_opcode(inst: u32) -> Result { + let opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); + + match opmap { + 0b000_1111 => Ok(ZifenceiOpcode::FENCE), + _ => Err(DecodingError::InvalidOpcode), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rd(inst: u32, opkind: &ZifenceiOpcode) -> Option { + let rd: usize = inst.slice(11, 7) as usize; + + match opkind { + ZifenceiOpcode::FENCE => Some(rd), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rs1(inst: u32, opkind: &ZifenceiOpcode) -> Option { + let rs1: usize = inst.slice(19, 15) as usize; + + match opkind { + ZifenceiOpcode::FENCE => Some(rs1), + } + } + + #[allow(clippy::unnecessary_wraps)] + pub fn parse_rs2(_inst: u32, opkind: &ZifenceiOpcode) -> Option { + match opkind { + ZifenceiOpcode::FENCE => None, + } + } + + #[allow(clippy::cast_possible_wrap, clippy::unnecessary_wraps)] + pub fn parse_imm(inst: u32, opkind: &ZifenceiOpcode) -> Option { + let fm_pred_succ: u32 = inst.slice(31, 20); + match opkind { + ZifenceiOpcode::FENCE => Some(fm_pred_succ as i32), + } + } +} + +#[cfg(test)] +#[allow(unused_variables)] +mod test_zifenci { + #[test] + #[allow(overflowing_literals)] + fn zifenci_decode_test() { + use crate::instruction::zifencei_extension::ZifenceiOpcode; + use crate::{Decode, Isa, OpcodeKind}; + + let test_32 = |inst_32: u32, + op: OpcodeKind, + rd: Option, + rs1: Option, + rs2: Option, + imm: Option| { + let op_32 = inst_32.parse_opcode(Isa::Rv64).unwrap(); + assert!(matches!(&op_32, op)); + assert_eq!(inst_32.parse_rd(&op_32).unwrap(), rd); + assert_eq!(inst_32.parse_rs1(&op_32).unwrap(), rs1); + assert_eq!(inst_32.parse_rs2(&op_32).unwrap(), rs2); + assert_eq!(inst_32.parse_imm(&op_32, Isa::Rv64).unwrap(), imm); + }; + + test_32( + 0b0000_0011_0011_0000_0000_0000_0000_1111, + OpcodeKind::Zifencei(ZifenceiOpcode::FENCE), + Some(0), + Some(0), + None, + Some(0b0011_0011), + ); + } +} diff --git a/src/instruction.rs b/src/instruction.rs index a0d7a37..e96591b 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -5,6 +5,7 @@ pub mod base_i; pub mod c_extension; pub mod m_extension; pub mod priv_extension; +pub mod zicboz_extension; pub mod zicfiss_extension; pub mod zicntr_extension; pub mod zicsr_extension; @@ -17,6 +18,7 @@ use base_i::BaseIOpcode; use c_extension::COpcode; use m_extension::MOpcode; use priv_extension::PrivOpcode; +use zicboz_extension::ZicbozOpcode; use zicfiss_extension::ZicfissOpcode; use zicntr_extension::ZicntrOpcode; use zicsr_extension::ZicsrOpcode; @@ -446,6 +448,8 @@ pub enum OpcodeKind { C(COpcode), /// Instruction-Fetch Fence, Zifencei(ZifenceiOpcode), + /// Cache-Block Zero Instructions + Zicboz(ZicbozOpcode), /// Control and Status Register Instructions Zicsr(ZicsrOpcode), /// CFI Shadow Stack @@ -464,6 +468,7 @@ impl Display for OpcodeKind { Self::A(opc) => write!(f, "{opc}"), Self::C(opc) => write!(f, "{opc}"), Self::Zifencei(opc) => write!(f, "{opc}"), + Self::Zicboz(opc) => write!(f, "{opc}"), Self::Zicsr(opc) => write!(f, "{opc}"), Self::Zicfiss(opc) => write!(f, "{opc}"), Self::Zicntr(opc) => write!(f, "{opc}"), @@ -481,6 +486,7 @@ impl OpcodeKind { Self::A(opc) => opc.get_format(), Self::C(opc) => opc.get_format(), Self::Zifencei(opc) => opc.get_format(), + Self::Zicboz(opc) => opc.get_format(), Self::Zicsr(opc) => opc.get_format(), Self::Zicfiss(opc) => opc.get_format(), Self::Zicntr(opc) => opc.get_format(), diff --git a/src/instruction/zicboz_extension.rs b/src/instruction/zicboz_extension.rs new file mode 100644 index 0000000..0b2b405 --- /dev/null +++ b/src/instruction/zicboz_extension.rs @@ -0,0 +1,29 @@ +//! Zicboz extension Instruction. +//! +//! The RISC-V Instruction Set Manual Volume I p.108 19.7.4 cbo.zero + +use super::{InstFormat, Opcode}; +use core::fmt::{self, Display, Formatter}; + +/// Insturctions in Zicboz Extension. +#[allow(non_camel_case_types, clippy::upper_case_acronyms)] +#[derive(Debug, PartialEq)] +pub enum ZicbozOpcode { + CBO_ZERO, +} + +impl Display for ZicbozOpcode { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + ZicbozOpcode::CBO_ZERO => write!(f, "cbo.zero"), + } + } +} + +impl Opcode for ZicbozOpcode { + fn get_format(&self) -> InstFormat { + match self { + ZicbozOpcode::CBO_ZERO => InstFormat::OnlyRs1, + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 62c9f00..ecf4e7a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,6 +60,8 @@ enum Extensions { C, /// Instruction-Fetch Fence Zifencei, + /// Cache-Block Zero Instructions + Zicboz, /// Control and Status Register Instructions Zicsr, /// Shadow Stack @@ -137,7 +139,7 @@ mod tests { .unwrap() .opc, OpcodeKind::BaseI(BaseIOpcode::JAL), - ) + ); } #[test] @@ -165,6 +167,6 @@ mod tests { .unwrap() .opc, OpcodeKind::BaseI(BaseIOpcode::JAL), - ) + ); } }