use crate::{types::*, Instruction};
use thiserror::Error;
pub const INSTRUCTION_SIZE: usize = 4;
pub const WORD_SIZE: usize = 8;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Error)]
pub enum DecodingError {
#[error(
"Instruction's opcode is reserved for custom extentions and thus can't be decoded further"
)]
Custom,
#[error("Instruction's opcode is reserved for future standard extentions")]
Reserved,
#[error("Instruction bit pattern not defined in current specification")]
Unknown,
#[error("More bits from the instruction are required to fully decode it")]
Truncated,
#[error("Instruction type is well defined but is not part of RISC-U")]
Unimplemented,
}
type DecodingResult = Result<Instruction, DecodingError>;
pub fn instruction_length(i: u16) -> usize {
if i & 0b11 != 0b11 {
2
} else if i & 0b11100 != 0b11100 {
4
} else if i & 0b111111 == 0b011111 {
6
} else if i & 0b1111111 == 0b011111 {
8
} else {
10 + 2 * ((i >> 12) & 0b111) as usize
}
}
pub fn decode(i: u32) -> DecodingResult {
match i & 0b11 {
0b11 => match (i >> 2) & 0b11111 {
0b00000 => decode_load(i),
0b00001 => Err(DecodingError::Unimplemented), 0b00010 => Err(DecodingError::Custom),
0b00011 => Err(DecodingError::Unknown), 0b00100 => decode_op_imm(i),
0b00101 => Err(DecodingError::Unknown), 0b00110 => Err(DecodingError::Unknown), 0b00111 => Err(DecodingError::Reserved),
0b01000 => decode_store(i),
0b01001 => Err(DecodingError::Unimplemented), 0b01010 => Err(DecodingError::Custom),
0b01011 => Err(DecodingError::Unimplemented), 0b01100 => decode_op(i),
0b01101 => Ok(Instruction::Lui(UType(i))),
0b01110 => Err(DecodingError::Unknown), 0b01111 => Err(DecodingError::Reserved),
0b10000 => Err(DecodingError::Unimplemented), 0b10001 => Err(DecodingError::Unimplemented), 0b10010 => Err(DecodingError::Unimplemented), 0b10011 => Err(DecodingError::Unimplemented), 0b10100 => Err(DecodingError::Unimplemented), 0b10101 => Err(DecodingError::Reserved),
0b10110 => Err(DecodingError::Custom),
0b10111 => Err(DecodingError::Reserved),
0b11000 => decode_branch(i),
0b11001 => Ok(Instruction::Jalr(IType(i))),
0b11010 => Err(DecodingError::Reserved),
0b11011 => Ok(Instruction::Jal(JType(i))),
0b11100 => decode_system(i),
0b11101 => Err(DecodingError::Reserved),
0b11110 => Err(DecodingError::Custom),
0b11111 => Err(DecodingError::Reserved), _ => unreachable!(),
},
_ => Err(DecodingError::Unknown), }
}
#[inline(always)]
fn decode_load(i: u32) -> DecodingResult {
match (i >> 12) & 0b111 {
0b011 => Ok(Instruction::Ld(IType(i))),
0b111 => Err(DecodingError::Reserved),
_ => Err(DecodingError::Unknown),
}
}
#[inline(always)]
fn decode_op_imm(i: u32) -> DecodingResult {
match (i >> 12) & 0b111 {
0b000 => Ok(Instruction::Addi(IType(i))),
_ => Err(DecodingError::Unknown),
}
}
#[inline(always)]
fn decode_store(i: u32) -> DecodingResult {
match (i >> 12) & 0b111 {
0b011 => Ok(Instruction::Sd(SType(i))),
_ => Err(DecodingError::Unknown),
}
}
#[inline(always)]
fn decode_op(i: u32) -> DecodingResult {
match (i >> 25, (i >> 12) & 0b111) {
(0b0000000, 0b000) => Ok(Instruction::Add(RType(i))),
(0b0100000, 0b000) => Ok(Instruction::Sub(RType(i))),
(0b0000000, 0b011) => Ok(Instruction::Sltu(RType(i))),
(0b0000001, 0b000) => Ok(Instruction::Mul(RType(i))),
(0b0000001, 0b101) => Ok(Instruction::Divu(RType(i))),
(0b0000001, 0b111) => Ok(Instruction::Remu(RType(i))),
_ => Err(DecodingError::Unknown),
}
}
fn decode_branch(i: u32) -> DecodingResult {
match (i >> 12) & 0b111 {
0b000 => Ok(Instruction::Beq(BType(i))),
_ => Err(DecodingError::Unknown),
}
}
fn decode_system(i: u32) -> DecodingResult {
match i {
0b0000_0000_0000_0000_0000_0000_0111_0011 => Ok(Instruction::Ecall(IType(i))),
_ => Err(DecodingError::Unknown),
}
}
#[cfg(test)]
mod tests {
use super::*;
use Instruction::*;
#[test]
fn decoding() {
assert_eq!(decode(0x00001a37).unwrap(), Lui(UType(0x00001a37))); assert_eq!(decode(0x800002b7).unwrap(), Lui(UType(0x800002b7))); assert_eq!(decode(0x212120b7).unwrap(), Lui(UType(0x212120b7))); assert_eq!(decode(0xfe1ff06f).unwrap(), Jal(JType(0xfe1ff06f))); assert_eq!(decode(0x0000006f).unwrap(), Jal(JType(0x0000006f))); assert_eq!(decode(0xf89ff06f).unwrap(), Jal(JType(0xf89ff06f))); assert_eq!(decode(0x00008067).unwrap(), Jalr(IType(0x00008067))); assert_eq!(decode(0x00008067).unwrap(), Jalr(IType(0x00008067))); assert_eq!(decode(0x000f0067).unwrap(), Jalr(IType(0x000f0067))); }
#[test]
fn load() {
assert_eq!(decode(0x01853683).unwrap(), Ld(IType(0x01853683))); assert_eq!(decode(0x02013c03).unwrap(), Ld(IType(0x02013c03))); assert_eq!(decode(0x0007b703).unwrap(), Ld(IType(0x0007b703))); }
#[test]
fn op_imm() {
assert_eq!(decode(0x00200793).unwrap(), Addi(IType(0x00200793))); assert_eq!(decode(0x00000013).unwrap(), Addi(IType(0x00000013))); assert_eq!(decode(0x00000013).unwrap(), Addi(IType(0x00000013))); }
#[test]
fn store() {
assert_eq!(decode(0x0b613823).unwrap(), Sd(SType(0x0b613823))); assert_eq!(decode(0x09213823).unwrap(), Sd(SType(0x09213823))); assert_eq!(decode(0x00f6b423).unwrap(), Sd(SType(0x00f6b423))); }
#[test]
fn op() {
assert_eq!(decode(0x00c58633).unwrap(), Add(RType(0x00c58633))); assert_eq!(decode(0x00d506b3).unwrap(), Add(RType(0x00d506b3))); assert_eq!(decode(0x00a70533).unwrap(), Add(RType(0x00a70533))); assert_eq!(decode(0x40b50533).unwrap(), Sub(RType(0x40b50533))); assert_eq!(decode(0x40e78533).unwrap(), Sub(RType(0x40e78533))); assert_eq!(decode(0x41060633).unwrap(), Sub(RType(0x41060633))); assert_eq!(decode(0x0020bf33).unwrap(), Sltu(RType(0x0020bf33))); assert_eq!(decode(0x0020bf33).unwrap(), Sltu(RType(0x0020bf33))); assert_eq!(decode(0x000030b3).unwrap(), Sltu(RType(0x000030b3))); assert_eq!(decode(0x021080b3).unwrap(), Mul(RType(0x021080b3))); assert_eq!(decode(0x02208f33).unwrap(), Mul(RType(0x02208f33))); assert_eq!(decode(0x02208133).unwrap(), Mul(RType(0x02208133))); assert_eq!(decode(0x0220df33).unwrap(), Divu(RType(0x0220df33))); assert_eq!(decode(0x0220df33).unwrap(), Divu(RType(0x0220df33))); assert_eq!(decode(0x0220df33).unwrap(), Divu(RType(0x0220df33))); assert_eq!(decode(0x0220ff33).unwrap(), Remu(RType(0x0220ff33))); assert_eq!(decode(0x0220ff33).unwrap(), Remu(RType(0x0220ff33))); assert_eq!(decode(0x0220ff33).unwrap(), Remu(RType(0x0220ff33))); }
#[test]
fn branch() {
assert_eq!(decode(0x10e78463).unwrap(), Beq(BType(0x10e78463))); assert_eq!(decode(0x00050a63).unwrap(), Beq(BType(0x00050a63))); assert_eq!(decode(0x1b5a0463).unwrap(), Beq(BType(0x1b5a0463))); }
#[test]
fn system() {
assert_eq!(decode(0x00000073).unwrap(), Instruction::new_ecall()); }
}