use core::fmt;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct TypeR {
pub rd: Register,
pub rs1: Register,
pub rs2: Register,
}
impl From<u32> for TypeR {
fn from(insn: u32) -> Self {
Self {
rd: rd_from(insn),
rs1: rs1_from(insn),
rs2: rs2_from(insn),
}
}
}
impl From<u16> for TypeR {
fn from(insn: u16) -> Self {
let rd = rd_from(insn.into());
Self {
rd,
rs1: rd,
rs2: rs2_from_compressed(insn),
}
}
}
impl fmt::Display for TypeR {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "x{}, x{}, x{}", self.rd, self.rs1, self.rs2)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct TypeI {
pub rd: Register,
pub rs1: Register,
pub imm: i16,
}
impl From<u32> for TypeI {
fn from(insn: u32) -> Self {
let imm = sign_extend_u16((insn >> 20) as u16, 11);
Self {
rd: rd_from(insn),
rs1: rs1_from(insn),
imm,
}
}
}
impl fmt::Display for TypeI {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "x{}, x{}, 0x{:X}", self.rd, self.rs1, self.imm)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct TypeS {
pub rs1: Register,
pub rs2: Register,
pub imm: i16,
}
impl From<u32> for TypeS {
fn from(insn: u32) -> Self {
let imm = ((insn >> 7) & 0x01f) | ((insn >> (25 - 5)) & 0xfe0);
Self {
rs1: rs1_from(insn),
rs2: rs2_from(insn),
imm: sign_extend_u16(imm as u16, 11),
}
}
}
impl fmt::Display for TypeS {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "x{}, x{}, 0x{:X}", self.rs1, self.rs2, self.imm)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct TypeB {
pub rs1: Register,
pub rs2: Register,
pub imm: i16,
}
impl From<u32> for TypeB {
fn from(insn: u32) -> Self {
let imm = ((insn >> 7) & 0x001e)
| ((insn >> (25 - 5)) & 0x07e0)
| ((insn << (11 - 7)) & 0x0800)
| ((insn >> (31 - 12)) & 0x1000);
Self {
rs1: rs1_from(insn),
rs2: rs2_from(insn),
imm: sign_extend_u16(imm as u16, 12),
}
}
}
impl From<u16> for TypeB {
fn from(insn: u16) -> Self {
let imm = ((insn >> (3 - 1)) & 0x006)
| ((insn >> (10 - 3)) & 0x018)
| ((insn << (5 - 2)) & 0x020)
| ((insn << (7 - 6)) & 0x0c0)
| ((insn >> (12 - 8)) & 0x100);
Self {
rs1: rs1c_from(insn),
rs2: 0,
imm: sign_extend_u16(imm, 8),
}
}
}
impl fmt::Display for TypeB {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "x{}, x{}, 0x{:X}", self.rs1, self.rs2, self.imm)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct TypeU {
pub rd: Register,
pub imm: i32,
}
impl From<u32> for TypeU {
fn from(insn: u32) -> Self {
Self {
rd: rd_from(insn),
imm: (insn & 0xfffff000) as i32,
}
}
}
impl From<u16> for TypeU {
fn from(insn: u16) -> Self {
let insn: u32 = insn.into();
let imm = ((insn << (12 - 2)) & 0x0001f000) | ((insn << (17 - 12)) & 0x00020000);
Self {
rd: rd_from(insn),
imm: sign_extend_u32(imm, 17),
}
}
}
impl fmt::Display for TypeU {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let ushifted_imm: u32 = (self.imm as u32) >> 12;
write!(f, "x{}, 0x{:X}", self.rd, ushifted_imm)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct TypeJ {
pub rd: Register,
pub imm: i32,
}
impl From<u32> for TypeJ {
fn from(insn: u32) -> Self {
let imm = ((insn >> (21 - 1)) & 0x0007fe)
| ((insn >> (20 - 11)) & 0x000800)
| (insn & 0x0ff000)
| ((insn >> (31 - 20)) & 0x100000);
Self {
rd: rd_from(insn),
imm: sign_extend_u32(imm, 20),
}
}
}
impl From<u16> for TypeJ {
fn from(insn: u16) -> Self {
let imm = ((insn >> (3 - 1)) & 0x00e)
| ((insn >> (11 - 4)) & 0x010)
| ((insn << (5 - 2)) & 0x020)
| ((insn >> (7 - 6)) & 0x040)
| ((insn << (7 - 6)) & 0x080)
| ((insn >> (9 - 8)) & 0x300)
| ((insn << (10 - 8)) & 0x400)
| ((insn >> (12 - 11)) & 0x800);
Self {
rd: 0,
imm: sign_extend_u32(imm as u32, 11),
}
}
}
impl fmt::Display for TypeJ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "x{}, 0x{:X}", self.rd, self.imm)
}
}
pub type Register = u8;
const fn rd_from(insn: u32) -> u8 {
(insn >> 7) as u8 & REG_MASK
}
const fn rs1_from(insn: u32) -> u8 {
(insn >> 15) as u8 & REG_MASK
}
const fn rs2_from(insn: u32) -> u8 {
(insn >> 20) as u8 & REG_MASK
}
const fn rs2_from_compressed(insn: u16) -> u8 {
(insn >> 2) as u8 & REG_MASK
}
const fn rs1c_from(insn: u16) -> u8 {
((insn >> 7) as u8 & 0x07) | 0x08
}
const fn sign_extend_u16(value: u16, pos: u8) -> i16 {
if (value & (1 << pos)) > 0 {
(value | !((1 << pos) - 1)) as i16
} else {
value as i16
}
}
const fn sign_extend_u32(value: u32, pos: u8) -> i32 {
if (value & (1 << pos)) > 0 {
(value | !((1 << pos) - 1)) as i32
} else {
value as i32
}
}
const REG_MASK: u8 = 0x1f;