use crate::registers::general_purpose::{RegType, Register};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u16)]
pub enum MCsr {
Mvendorid = 0xF11,
Marchid = 0xF12,
Mimpid = 0xF13,
Mhartid = 0xF14,
Mstatus = 0x300,
Misa = 0x301,
Mie = 0x304,
Mtvec = 0x305,
Mscratch = 0x340,
Mepc = 0x341,
Mcause = 0x342,
Mtval = 0x343,
Mip = 0x344,
}
impl MCsr {
#[inline(always)]
pub const fn from_index(index: u16) -> Option<Self> {
match index {
0xF11 => Some(Self::Mvendorid),
0xF12 => Some(Self::Marchid),
0xF13 => Some(Self::Mimpid),
0xF14 => Some(Self::Mhartid),
0x300 => Some(Self::Mstatus),
0x301 => Some(Self::Misa),
0x304 => Some(Self::Mie),
0x305 => Some(Self::Mtvec),
0x340 => Some(Self::Mscratch),
0x341 => Some(Self::Mepc),
0x342 => Some(Self::Mcause),
0x343 => Some(Self::Mtval),
0x344 => Some(Self::Mip),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum MCauseException {
InstructionAddressMisaligned = 0,
InstructionAccessFault = 1,
IllegalInstruction = 2,
Breakpoint = 3,
LoadAddressMisaligned = 4,
LoadAccessFault = 5,
StoreAddressMisaligned = 6,
StoreAccessFault = 7,
UserEnvironmentCall = 8,
SupervisorEnvironmentCall = 9,
MachineEnvironmentCall = 11,
InstructionPageFault = 12,
LoadPageFault = 13,
StorePageFault = 15,
}
impl MCauseException {
#[inline(always)]
pub const fn from_code(code: u64) -> Option<Self> {
match code {
0 => Some(Self::InstructionAddressMisaligned),
1 => Some(Self::InstructionAccessFault),
2 => Some(Self::IllegalInstruction),
3 => Some(Self::Breakpoint),
4 => Some(Self::LoadAddressMisaligned),
5 => Some(Self::LoadAccessFault),
6 => Some(Self::StoreAddressMisaligned),
7 => Some(Self::StoreAccessFault),
8 => Some(Self::UserEnvironmentCall),
9 => Some(Self::SupervisorEnvironmentCall),
11 => Some(Self::MachineEnvironmentCall),
12 => Some(Self::InstructionPageFault),
13 => Some(Self::LoadPageFault),
15 => Some(Self::StorePageFault),
_ => None,
}
}
#[inline(always)]
pub const fn to_raw<Reg>(self) -> Reg::Type
where
Reg: [const] Register,
{
Reg::Type::from(self as u32)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum MCauseInterrupt {
UserSoftware = 0,
SupervisorSoftware = 1,
MachineSoftware = 3,
UserTimer = 4,
SupervisorTimer = 5,
MachineTimer = 7,
UserExternal = 8,
SupervisorExternal = 9,
MachineExternal = 11,
}
impl MCauseInterrupt {
#[inline(always)]
pub const fn from_code(code: u64) -> Option<Self> {
match code {
0 => Some(Self::UserSoftware),
1 => Some(Self::SupervisorSoftware),
3 => Some(Self::MachineSoftware),
4 => Some(Self::UserTimer),
5 => Some(Self::SupervisorTimer),
7 => Some(Self::MachineTimer),
8 => Some(Self::UserExternal),
9 => Some(Self::SupervisorExternal),
11 => Some(Self::MachineExternal),
_ => None,
}
}
#[inline(always)]
pub const fn to_raw<Reg>(self) -> Reg::Type
where
Reg: [const] Register,
{
Reg::Type::from(self as u32) | (Reg::Type::from(1u8) << (Reg::XLEN - 1))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MCause {
Exception(MCauseException),
Interrupt(MCauseInterrupt),
}
impl From<MCauseException> for MCause {
#[inline(always)]
fn from(cause: MCauseException) -> Self {
Self::Exception(cause)
}
}
impl From<MCauseInterrupt> for MCause {
#[inline(always)]
fn from(cause: MCauseInterrupt) -> Self {
Self::Interrupt(cause)
}
}
impl MCause {
#[inline(always)]
pub const fn from_raw<Reg>(raw: Reg::Type) -> Option<Self>
where
Reg: [const] Register,
{
let raw = raw.as_u64();
let is_interrupt = (raw & (1u64 << (Reg::XLEN - 1))) != 0;
let code = raw & !(1u64 << (Reg::XLEN - 1));
if is_interrupt {
MCauseInterrupt::from_code(code).map(Self::Interrupt)
} else {
MCauseException::from_code(code).map(Self::Exception)
}
}
#[inline(always)]
pub const fn to_raw<Reg>(self) -> Reg::Type
where
Reg: [const] Register,
{
match self {
MCause::Exception(exception) => exception.to_raw::<Reg>(),
MCause::Interrupt(interrupt) => interrupt.to_raw::<Reg>(),
}
}
}