use bit_field::BitField;
use core::mem::size_of;
#[derive(Clone, Copy)]
pub struct Scause {
bits: usize,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Trap {
Interrupt(Interrupt),
Exception(Exception),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Interrupt {
UserSoft,
SupervisorSoft,
UserTimer,
SupervisorTimer,
UserExternal,
SupervisorExternal,
Unknown,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Exception {
InstructionMisaligned,
InstructionFault,
IllegalInstruction,
Breakpoint,
LoadFault,
StoreMisaligned,
StoreFault,
UserEnvCall,
InstructionPageFault,
LoadPageFault,
StorePageFault,
Unknown,
}
impl Interrupt {
#[inline]
pub fn from(nr: usize) -> Self {
match nr {
0 => Interrupt::UserSoft,
1 => Interrupt::SupervisorSoft,
4 => Interrupt::UserTimer,
5 => Interrupt::SupervisorTimer,
8 => Interrupt::UserExternal,
9 => Interrupt::SupervisorExternal,
_ => Interrupt::Unknown,
}
}
}
impl Exception {
#[inline]
pub fn from(nr: usize) -> Self {
match nr {
0 => Exception::InstructionMisaligned,
1 => Exception::InstructionFault,
2 => Exception::IllegalInstruction,
3 => Exception::Breakpoint,
5 => Exception::LoadFault,
6 => Exception::StoreMisaligned,
7 => Exception::StoreFault,
8 => Exception::UserEnvCall,
12 => Exception::InstructionPageFault,
13 => Exception::LoadPageFault,
15 => Exception::StorePageFault,
_ => Exception::Unknown,
}
}
}
impl Scause {
#[inline]
pub fn bits(&self) -> usize {
self.bits
}
#[inline]
pub fn code(&self) -> usize {
let bit = 1 << (size_of::<usize>() * 8 - 1);
self.bits & !bit
}
#[inline]
pub fn cause(&self) -> Trap {
if self.is_interrupt() {
Trap::Interrupt(Interrupt::from(self.code()))
} else {
Trap::Exception(Exception::from(self.code()))
}
}
#[inline]
pub fn is_interrupt(&self) -> bool {
self.bits.get_bit(size_of::<usize>() * 8 - 1)
}
#[inline]
pub fn is_exception(&self) -> bool {
!self.is_interrupt()
}
}
read_csr_as!(Scause, 0x142);
write_csr!(0x142);
#[inline]
pub unsafe fn write(bits: usize) {
_write(bits)
}
#[inline]
pub unsafe fn set(cause: Trap) {
let bits = match cause {
Trap::Interrupt(i) => {
(match i {
Interrupt::UserSoft => 0,
Interrupt::SupervisorSoft => 1,
Interrupt::UserTimer => 4,
Interrupt::SupervisorTimer => 5,
Interrupt::UserExternal => 8,
Interrupt::SupervisorExternal => 9,
Interrupt::Unknown => panic!("unknown interrupt"),
} | (1 << (size_of::<usize>() * 8 - 1)))
} Trap::Exception(e) => match e {
Exception::InstructionMisaligned => 0,
Exception::InstructionFault => 1,
Exception::IllegalInstruction => 2,
Exception::Breakpoint => 3,
Exception::LoadFault => 5,
Exception::StoreMisaligned => 6,
Exception::StoreFault => 7,
Exception::UserEnvCall => 8,
Exception::InstructionPageFault => 12,
Exception::LoadPageFault => 13,
Exception::StorePageFault => 15,
Exception::Unknown => panic!("unknown exception"),
}, };
_write(bits);
}