use crate::reg::{Reg, RegVal};
use std::convert::From;
use std::fmt;
#[rustfmt::skip]
#[derive(Debug, Clone, Copy)]
pub enum Instruction {
Beq { rs1: Reg, rs2: Reg, imm: ImmB },
Bne { rs1: Reg, rs2: Reg, imm: ImmB },
Blt { rs1: Reg, rs2: Reg, imm: ImmB },
Bge { rs1: Reg, rs2: Reg, imm: ImmB },
Bltu { rs1: Reg, rs2: Reg, imm: ImmB },
Bgeu { rs1: Reg, rs2: Reg, imm: ImmB },
Jalr { rd: Reg, rs1: Reg, imm: ImmI },
Jal { rd: Reg, imm: ImmJ },
Lui { rd: Reg, imm: ImmU },
Auipc { rd: Reg, imm: ImmU },
Addi { rd: Reg, rs1: Reg, imm: ImmI },
Slti { rd: Reg, rs1: Reg, imm: ImmI },
Sltiu { rd: Reg, rs1: Reg, imm: ImmI },
Xori { rd: Reg, rs1: Reg, imm: ImmI },
Ori { rd: Reg, rs1: Reg, imm: ImmI },
Andi { rd: Reg, rs1: Reg, imm: ImmI },
Slli { rd: Reg, rs1: Reg, shamt: ImmI },
Srli { rd: Reg, rs1: Reg, shamt: ImmI },
Srai { rd: Reg, rs1: Reg, shamt: ImmI },
Add { rd: Reg, rs1: Reg, rs2: Reg },
Sub { rd: Reg, rs1: Reg, rs2: Reg },
Sll { rd: Reg, rs1: Reg, rs2: Reg },
Slt { rd: Reg, rs1: Reg, rs2: Reg },
Sltu { rd: Reg, rs1: Reg, rs2: Reg },
Xor { rd: Reg, rs1: Reg, rs2: Reg },
Srl { rd: Reg, rs1: Reg, rs2: Reg },
Sra { rd: Reg, rs1: Reg, rs2: Reg },
Or { rd: Reg, rs1: Reg, rs2: Reg },
And { rd: Reg, rs1: Reg, rs2: Reg },
Lb { rd: Reg, rs1: Reg, imm: ImmI },
Lh { rd: Reg, rs1: Reg, imm: ImmI },
Lw { rd: Reg, rs1: Reg, imm: ImmI },
Lbu { rd: Reg, rs1: Reg, imm: ImmI },
Lhu { rd: Reg, rs1: Reg, imm: ImmI },
Lwu { rd: Reg, rs1: Reg, imm: ImmI },
Sb { imm: ImmS, rs1: Reg, rs2: Reg },
Sh { imm: ImmS, rs1: Reg, rs2: Reg },
Sw { imm: ImmS, rs1: Reg, rs2: Reg },
Fence { rd: Reg },
FenceI { rd: Reg },
ECall,
EBreak,
}
pub enum OpCode {
Lui,
Auipc,
Op,
OpImm,
Jal,
Jalr,
Branch,
Load,
Store,
MiscMem,
System,
}
#[derive(Debug, Clone, Copy)]
pub struct ImmI(RegVal);
#[derive(Debug, Clone, Copy)]
pub struct ImmS(RegVal);
#[derive(Debug, Clone, Copy)]
pub struct ImmB(RegVal);
#[derive(Debug, Clone, Copy)]
pub struct ImmU(RegVal);
#[derive(Debug, Clone, Copy)]
pub struct ImmJ(RegVal);
#[derive(Debug, Clone)]
pub struct DecodeError;
struct InvalidOpcode(u8);
impl ImmI {
pub fn val(self) -> RegVal {
self.into()
}
}
impl ImmS {
pub fn val(self) -> RegVal {
self.into()
}
}
impl ImmB {
pub fn val(self) -> RegVal {
self.into()
}
}
impl ImmU {
pub fn val(self) -> RegVal {
self.into()
}
}
impl ImmJ {
pub fn val(self) -> RegVal {
self.into()
}
}
impl From<ImmJ> for RegVal {
fn from(imm: ImmJ) -> RegVal {
imm.0
}
}
impl From<ImmU> for RegVal {
fn from(imm: ImmU) -> RegVal {
imm.0
}
}
impl From<ImmI> for RegVal {
fn from(imm: ImmI) -> RegVal {
imm.0
}
}
impl From<ImmB> for RegVal {
fn from(imm: ImmB) -> RegVal {
imm.0
}
}
impl From<ImmS> for RegVal {
fn from(imm: ImmS) -> RegVal {
imm.0
}
}
impl OpCode {
fn name(&self) -> &'static str {
use OpCode::*;
match &self {
Lui => "Lui",
Auipc => "Auipc",
Op => "Op",
OpImm => "OpImm",
Jal => "Jal",
Jalr => "Jalr",
Branch => "Branch",
Load => "Load",
Store => "Store",
MiscMem => "MiscMem",
System => "System",
}
}
}
impl fmt::Display for OpCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<Instruction {}>", self.name())
}
}
impl std::fmt::Display for DecodeError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl fmt::Display for ImmB {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0.to_i32())
}
}
impl fmt::Display for ImmI {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0.to_i32())
}
}
impl fmt::Display for ImmJ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0.to_i32())
}
}
impl fmt::Display for ImmU {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0.to_i32())
}
}
impl fmt::Display for ImmS {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0.to_i32())
}
}
impl fmt::LowerHex for ImmI {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::LowerHex::fmt(&self.0.to_i32(), f)
}
}
impl fmt::LowerHex for ImmJ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::LowerHex::fmt(&self.0.to_i32(), f)
}
}
impl fmt::Display for Instruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.asm())
}
}
impl Instruction {
#[rustfmt::skip]
#[allow(unused_variables)]
fn asm(&self) -> String {
use Instruction::*;
match self {
Beq { rs1 , rs2 , imm } => format!("beq {}, {}, {}", rs1, rs2, imm),
Bne { rs1 , rs2 , imm } => format!("bne {}, {}, {}", rs1, rs2, imm),
Blt { rs1 , rs2 , imm } => format!("blt {}, {}, {}", rs1, rs2, imm),
Bge { rs1 , rs2 , imm } => format!("bge {}, {}, {}", rs1, rs2, imm),
Bltu { rs1 , rs2 , imm } => format!("bltu {}, {}, {}", rs1, rs2, imm),
Bgeu { rs1 , rs2 , imm } => format!("bgeu {}, {}, {}", rs1, rs2, imm),
Jalr { rd , rs1 , imm } => format!("jalr {}, 0x{:08x}({})", rd, imm, rs1),
Jal { rd , imm } => format!("jal {}, 0x{:08x}", rd, imm),
Lui { rd , imm } => format!("lui {}, {}", rd, imm),
Auipc { rd , imm } => format!("auipc {}, {}", rd, imm),
Addi { rd , rs1 , imm } => format!("addi {}, {}, {}", rd, rs1, imm),
Slti { rd , rs1 , imm } => format!("slti {}, {}, {}", rd, rs1, imm),
Sltiu { rd , rs1 , imm } => format!("sltiu {}, {}, {}", rd, rs1, imm),
Xori { rd , rs1 , imm } => format!("xori {}, {}, {}", rd, rs1, imm),
Ori { rd , rs1 , imm } => format!("ori {}, {}, {}", rd, rs1, imm),
Andi { rd , rs1 , imm } => format!("andi {}, {}, {}", rd, rs1, imm),
Slli { rd , rs1 , shamt } => format!("slli {}, {}, {}", rd, rs1, shamt),
Srli { rd , rs1 , shamt } => format!("srli {}, {}, {}", rd, rs1, shamt),
Srai { rd , rs1 , shamt } => format!("srai {}, {}, {}", rd, rs1, shamt),
Add { rd , rs1 , rs2 } => format!("add {}, {}, {}", rd, rs1, rs2),
Sub { rd , rs1 , rs2 } => format!("sub {}, {}, {}", rd, rs1, rs2),
Sll { rd , rs1 , rs2 } => format!("sll {}, {}, {}", rd, rs1, rs2),
Slt { rd , rs1 , rs2 } => format!("slt {}, {}, {}", rd, rs1, rs2),
Sltu { rd , rs1 , rs2 } => format!("sltu {}, {}, {}", rd, rs1, rs2),
Xor { rd , rs1 , rs2 } => format!("xor {}, {}, {}", rd, rs1, rs2),
Srl { rd , rs1 , rs2 } => format!("srl {}, {}, {}", rd, rs1, rs2),
Sra { rd , rs1 , rs2 } => format!("sra {}, {}, {}", rd, rs1, rs2),
Or { rd , rs1 , rs2 } => format!("or {}, {}, {}", rd, rs1, rs2),
And { rd , rs1 , rs2 } => format!("and {}, {}, {}", rd, rs1, rs2),
Lb { rd , rs1 , imm } => format!("lb {}, {}({})", rd, imm, rs1),
Lh { rd , rs1 , imm } => format!("lh {}, {}({})", rd, imm, rs1),
Lw { rd , rs1 , imm } => format!("lw {}, {}({})", rd, imm, rs1),
Lbu { rd , rs1 , imm } => format!("lbu {}, {}({})", rd, imm, rs1),
Lhu { rd , rs1 , imm } => format!("lhu {}, {}({})", rd, imm, rs1),
Lwu { rd , rs1 , imm } => format!("lwu {}, {}({})", rd, imm, rs1),
Sb { imm , rs1 , rs2 } => format!("sb {}, {}({})", rs2, imm, rs1),
Sh { imm , rs1 , rs2 } => format!("sh {}, {}({})", rs2, imm, rs1),
Sw { imm , rs1 , rs2 } => format!("sw {}, {}({})", rs2, imm, rs1),
Fence { rd } => format!("fence"),
FenceI { rd } => format!("fence.i"),
ECall => format!("ecall"),
EBreak => format!("ebreak"),
}
}
}
pub fn decode(instruction: u32) -> Result<Instruction, DecodeError> {
match opcode(instruction) {
Ok(OpCode::Lui) => Ok(decode_lui(instruction)),
Ok(OpCode::Auipc) => Ok(decode_auipc(instruction)),
Ok(OpCode::Op) => decode_op(instruction),
Ok(OpCode::OpImm) => Ok(decode_op_imm(instruction)),
Ok(OpCode::Jalr) => Ok(decode_jalr(instruction)),
Ok(OpCode::Jal) => Ok(decode_jal(instruction)),
Ok(OpCode::Branch) => decode_branch(instruction),
Ok(OpCode::Load) => Ok(decode_load(instruction)),
Ok(OpCode::Store) => decode_store(instruction),
Ok(OpCode::MiscMem) => Ok(decode_misc_mem(instruction)),
Ok(OpCode::System) => Ok(decode_system(instruction)),
Err(InvalidOpcode(_opcode)) => Err(DecodeError),
}
}
fn decode_lui(instruction: u32) -> Instruction {
let rd = rd(instruction);
let imm = imm_u(instruction);
Instruction::Lui { rd, imm }
}
fn decode_auipc(instruction: u32) -> Instruction {
let rd = rd(instruction);
let imm = imm_u(instruction);
Instruction::Auipc { rd, imm }
}
fn decode_op(instruction: u32) -> Result<Instruction, DecodeError> {
let rd = rd(instruction);
let rs1 = rs1(instruction);
let rs2 = rs2(instruction);
match funct3(instruction) {
0b000 => match funct7(instruction) {
0b0000000 => Ok(Instruction::Add { rd, rs1, rs2 }),
0b0100000 => Ok(Instruction::Sub { rd, rs1, rs2 }),
_ => Err(DecodeError), },
0b001 => {
Ok(Instruction::Sll { rd, rs1, rs2 })
}
0b010 => Ok(Instruction::Slt { rd, rs1, rs2 }),
0b011 => Ok(Instruction::Sltu { rd, rs1, rs2 }),
0b100 => Ok(Instruction::Xor { rd, rs1, rs2 }),
0b101 => {
match funct7(instruction) {
0b0000000 => Ok(Instruction::Srl { rd, rs1, rs2 }),
0b0100000 => Ok(Instruction::Sra { rd, rs1, rs2 }),
_ => Err(DecodeError), }
}
0b110 => Ok(Instruction::Or { rd, rs1, rs2 }),
0b111 => Ok(Instruction::And { rd, rs1, rs2 }),
_ => unreachable!(),
}
}
fn decode_op_imm(instruction: u32) -> Instruction {
let rd = rd(instruction);
let rs1 = rs1(instruction);
let imm = imm_i(instruction);
match funct3(instruction) {
0b000 => Instruction::Addi { rd, rs1, imm },
0b001 => {
let ImmI(imm) = imm;
let shamt = ImmI(RegVal::from_u32(0b000_0011_1111 & imm.to_u32()));
Instruction::Slli { rd, rs1, shamt }
}
0b010 => Instruction::Slti { rd, rs1, imm },
0b011 => Instruction::Sltiu { rd, rs1, imm },
0b100 => Instruction::Xori { rd, rs1, imm },
0b101 => {
let ImmI(imm) = imm;
let is_arithmetic = 0b0100_0000_0000 & imm.to_u32() != 0;
let shamt = ImmI(RegVal::from_u32(0b000_0011_1111 & imm.to_u32()));
if is_arithmetic {
Instruction::Srai { rd, rs1, shamt }
} else {
Instruction::Srli { rd, rs1, shamt }
}
}
0b110 => Instruction::Ori { rd, rs1, imm },
0b111 => Instruction::Andi { rd, rs1, imm },
_ => unreachable!(),
}
}
fn decode_jalr(instruction: u32) -> Instruction {
let imm = imm_i(instruction);
let rd = rd(instruction);
let rs1 = rs1(instruction);
assert!(funct3(instruction) == 0);
Instruction::Jalr { rd, rs1, imm }
}
fn decode_jal(instruction: u32) -> Instruction {
let imm = imm_j(instruction);
let rd = rd(instruction);
Instruction::Jal { rd, imm }
}
fn decode_branch(instruction: u32) -> Result<Instruction, DecodeError> {
let rs1 = rs1(instruction);
let rs2 = rs2(instruction);
let imm = imm_b(instruction);
match funct3(instruction) {
0b000 => Ok(Instruction::Beq { rs1, rs2, imm }),
0b001 => Ok(Instruction::Bne { rs1, rs2, imm }),
0b100 => Ok(Instruction::Blt { rs1, rs2, imm }),
0b101 => Ok(Instruction::Bge { rs1, rs2, imm }),
0b110 => Ok(Instruction::Bltu { rs1, rs2, imm }),
0b111 => Ok(Instruction::Bgeu { rs1, rs2, imm }),
_ => Err(DecodeError), }
}
fn decode_load(instruction: u32) -> Instruction {
let rd = rd(instruction);
let rs1 = rs1(instruction);
let imm = imm_i(instruction);
match funct3(instruction) {
0b000 => Instruction::Lb { rd, rs1, imm },
0b001 => Instruction::Lh { rd, rs1, imm },
0b010 => Instruction::Lw { rd, rs1, imm },
0b011 => panic!(format!("Bad funct7 for store: {}", funct3(instruction))),
0b100 => Instruction::Lbu { rd, rs1, imm },
0b101 => Instruction::Lhu { rd, rs1, imm },
0b110 => panic!(format!("Can't lwu in rv32i.")),
0b111 => panic!(format!("Bad funct7 for store: {}", funct3(instruction))),
_ => unreachable!(),
}
}
fn decode_store(instruction: u32) -> Result<Instruction, DecodeError> {
let rs1 = rs1(instruction);
let rs2 = rs2(instruction);
let imm = imm_s(instruction);
match funct3(instruction) {
0b000 => Ok(Instruction::Sb { imm, rs1, rs2 }),
0b001 => Ok(Instruction::Sh { imm, rs1, rs2 }),
0b010 => Ok(Instruction::Sw { imm, rs1, rs2 }),
0b011 => Err(DecodeError), 0b100 => Err(DecodeError), 0b101 => Err(DecodeError), 0b110 => Err(DecodeError), 0b111 => Err(DecodeError), _ => unreachable!(),
}
}
fn decode_misc_mem(_instruction: u32) -> Instruction {
unimplemented!()
}
fn decode_system(instruction: u32) -> Instruction {
let rd = rd(instruction);
let rs1 = rs1(instruction);
assert_eq!(rd, Reg(0));
assert_eq!(rs1, Reg(0));
assert_eq!(funct3(instruction), 0);
match funct12(instruction) {
0 => Instruction::ECall,
1 => Instruction::EBreak,
_ => panic!("Unknown Funct12"),
}
}
fn rd(value: u32) -> Reg {
let reg_num = ((value & 0b00000000_00000000_00001111_10000000) >> 7) as u8;
Reg(reg_num)
}
fn rs1(value: u32) -> Reg {
let reg_num = ((value & 0b00000000_00001111_10000000_00000000) >> 15) as u8;
Reg(reg_num)
}
fn rs2(value: u32) -> Reg {
let reg_num = ((value & 0b00000001_11110000_00000000_00000000) >> 20) as u8;
Reg(reg_num)
}
fn funct3(value: u32) -> u8 {
((value & 0b00000000_00000000_01110000_00000000) >> 12) as u8
}
fn funct7(value: u32) -> u8 {
((value & 0b11111110_00000000_00000000_00000000) >> 25) as u8
}
fn funct12(value: u32) -> u16 {
((value & 0b11111111_11110000_00000000_00000000) >> 20) as u16
}
fn imm_i(value: u32) -> ImmI {
let unsigned_imm = (value & 0b11111111_11110000_00000000_00000000) >> 20;
assert_eq!(unsigned_imm >> 12, 0); let imm = if unsigned_imm & 0b1000_0000_0000 != 0 { unsigned_imm | 0xff_ff_f0_00 } else { unsigned_imm };
ImmI(RegVal::from_u32(imm))
}
fn imm_u(value: u32) -> ImmU {
let imm_bits = value & 0b11111111_11111111_11110000_00000000;
ImmU(RegVal::from_u32(imm_bits))
}
#[rustfmt::skip]
fn imm_s(value: u32) -> ImmS {
let lo = (value & 0b00000000_00000000_00001111_10000000) >> 7;
let hi = (value & 0b11111110_00000000_00000000_00000000) >> 25;
let unsigned_imm = hi << 5 | lo;
assert_eq!(unsigned_imm >> 12, 0); let imm = if unsigned_imm & 0b1000_0000_0000 != 0 {
unsigned_imm | 0xff_ff_f0_00
} else {
unsigned_imm
};
ImmS(RegVal::from_u32(imm))
}
#[rustfmt::skip]
fn imm_j(value: u32) -> ImmJ {
let bit_20 = (value & 0b10000000_00000000_00000000_00000000) >> 31;
let bits_10_to_1 = (value & 0b01111111_11100000_00000000_00000000) >> 21;
let bit_11 = (value & 0b00000000_00010000_00000000_00000000) >> 20;
let bits_19_to_12 = (value & 0b00000000_00001111_11110000_00000000) >> 12;
let imm_bits = (bit_20 << 20) | (bits_19_to_12 << 12) | (bit_11 << 11) | (bits_10_to_1 << 1);
let imm = if imm_bits & 0b00000000_00010000_00000000_00000000 != 0 {
imm_bits | 0b11111111_11110000_00000000_00000000
} else {
imm_bits
};
ImmJ(RegVal::from_u32(imm))
}
#[rustfmt::skip]
fn imm_b(value: u32) -> ImmB {
let bit_12 = (value & 0b10000000_00000000_00000000_00000000) >> 31;
let bits_10_to_5 = (value & 0b01111110_00000000_00000000_00000000) >> 25;
let bits_4_to_1 = (value & 0b00000000_00000000_00001111_00000000) >> 8;
let bit_11 = (value & 0b00000000_00000000_00000000_10000000) >> 7;
let imm_bits = (bit_12 << 12) | (bit_11 << 11) | (bits_10_to_5 << 5) | (bits_4_to_1 << 1);
let imm = if imm_bits & 0b00000000_00010000_00010000_00000000 != 0 {
imm_bits | 0b11111111_11111111_11110000_00000000
} else {
imm_bits
};
ImmB(RegVal::from_u32(imm))
}
fn opcode(value: u32) -> Result<OpCode, InvalidOpcode> {
use OpCode::*;
let opcode_bits = (value & 0b00000000_00000000_00000000_01111111) as u8;
match opcode_bits {
0b0110111 => Ok(Lui),
0b0010111 => Ok(Auipc),
0b0110011 => Ok(Op),
0b0010011 => Ok(OpImm),
0b1100111 => Ok(Jalr),
0b1101111 => Ok(Jal),
0b1100011 => Ok(Branch),
0b0000011 => Ok(Load),
0b0100011 => Ok(Store),
0b0001111 => Ok(MiscMem),
0b1110011 => Ok(System),
b => Err(InvalidOpcode(b)),
}
}