diff --git a/.gitignore b/.gitignore index 1e7caa9e..b0a1d51d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ Cargo.lock target/ + +.vscode/ diff --git a/CHANGELOG.md b/CHANGELOG.md index a20ba398..782dbd20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,14 +12,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Add generic implementation of a PLIC peripheral - Add `asm::fence()`, a wrapper for implementing a `fence` instruction - Add `asm::fence_i()`, a wrapper for implementing a `fence.i` instruction +- Add `TryFrom` implementation for `mcause::{Interrupt, Exception}` and `scause::{Interrupt, Exception}` ### Changed - CI actions updated. They now use `checkout@v3` and `dtolnay/rust-toolchain`. +- `mcause::{Interrupt, Exception}` and `scause::{Interrupt, Exception}` now implement `From` trait for `usize` ### Fixed - Fix `scause::Exception` missing `LoadMisaligned` +- Fix `scause::Exception` missing `SupervisorEnvCall` +- Removed user-level interrupts from `mcause::Interrupt` and `scause::Interrupt` ## [v0.10.1] - 2023-01-18 diff --git a/src/register/mcause.rs b/src/register/mcause.rs index 705ffff4..efe9e6a7 100644 --- a/src/register/mcause.rs +++ b/src/register/mcause.rs @@ -15,79 +15,100 @@ pub enum Trap { /// Interrupt #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(usize)] pub enum Interrupt { - UserSoft, - SupervisorSoft, - MachineSoft, - UserTimer, - SupervisorTimer, - MachineTimer, - UserExternal, - SupervisorExternal, - MachineExternal, + SupervisorSoft = 1, + MachineSoft = 3, + SupervisorTimer = 5, + MachineTimer = 7, + SupervisorExternal = 9, + MachineExternal = 11, Unknown, } /// Exception #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[repr(usize)] pub enum Exception { - InstructionMisaligned, - InstructionFault, - IllegalInstruction, - Breakpoint, - LoadMisaligned, - LoadFault, - StoreMisaligned, - StoreFault, - UserEnvCall, - SupervisorEnvCall, - MachineEnvCall, - InstructionPageFault, - LoadPageFault, - StorePageFault, + InstructionMisaligned = 0, + InstructionFault = 1, + IllegalInstruction = 2, + Breakpoint = 3, + LoadMisaligned = 4, + LoadFault = 5, + StoreMisaligned = 6, + StoreFault = 7, + UserEnvCall = 8, + SupervisorEnvCall = 9, + MachineEnvCall = 11, + InstructionPageFault = 12, + LoadPageFault = 13, + StorePageFault = 15, Unknown, } -impl Interrupt { +impl From for Interrupt { #[inline] - pub fn from(nr: usize) -> Self { + fn from(nr: usize) -> Self { match nr { - 0 => Interrupt::UserSoft, - 1 => Interrupt::SupervisorSoft, - 3 => Interrupt::MachineSoft, - 4 => Interrupt::UserTimer, - 5 => Interrupt::SupervisorTimer, - 7 => Interrupt::MachineTimer, - 8 => Interrupt::UserExternal, - 9 => Interrupt::SupervisorExternal, - 11 => Interrupt::MachineExternal, - _ => Interrupt::Unknown, + 1 => Self::SupervisorSoft, + 3 => Self::MachineSoft, + 5 => Self::SupervisorTimer, + 7 => Self::MachineTimer, + 9 => Self::SupervisorExternal, + 11 => Self::MachineExternal, + _ => Self::Unknown, } } } -impl Exception { +impl TryFrom for usize { + type Error = Interrupt; + + #[inline] + fn try_from(value: Interrupt) -> Result { + match value { + Interrupt::Unknown => Err(Self::Error::Unknown), + _ => Ok(value as Self), + } + } +} + +impl From for Exception { #[inline] - pub fn from(nr: usize) -> Self { + fn from(nr: usize) -> Self { match nr { - 0 => Exception::InstructionMisaligned, - 1 => Exception::InstructionFault, - 2 => Exception::IllegalInstruction, - 3 => Exception::Breakpoint, - 4 => Exception::LoadMisaligned, - 5 => Exception::LoadFault, - 6 => Exception::StoreMisaligned, - 7 => Exception::StoreFault, - 8 => Exception::UserEnvCall, - 9 => Exception::SupervisorEnvCall, - 11 => Exception::MachineEnvCall, - 12 => Exception::InstructionPageFault, - 13 => Exception::LoadPageFault, - 15 => Exception::StorePageFault, - _ => Exception::Unknown, + 0 => Self::InstructionMisaligned, + 1 => Self::InstructionFault, + 2 => Self::IllegalInstruction, + 3 => Self::Breakpoint, + 4 => Self::LoadMisaligned, + 5 => Self::LoadFault, + 6 => Self::StoreMisaligned, + 7 => Self::StoreFault, + 8 => Self::UserEnvCall, + 9 => Self::SupervisorEnvCall, + 11 => Self::MachineEnvCall, + 12 => Self::InstructionPageFault, + 13 => Self::LoadPageFault, + 15 => Self::StorePageFault, + _ => Self::Unknown, } } } + +impl TryFrom for usize { + type Error = Exception; + + #[inline] + fn try_from(value: Exception) -> Result { + match value { + Exception::Unknown => Err(Self::Error::Unknown), + _ => Ok(value as Self), + } + } +} + impl Mcause { /// Returns the contents of the register as raw bits #[inline] @@ -98,14 +119,7 @@ impl Mcause { /// Returns the code field #[inline] pub fn code(&self) -> usize { - match () { - #[cfg(target_pointer_width = "32")] - () => self.bits & !(1 << 31), - #[cfg(target_pointer_width = "64")] - () => self.bits & !(1 << 63), - #[cfg(target_pointer_width = "128")] - () => self.bits & !(1 << 127), - } + self.bits & !(1 << (usize::BITS as usize - 1)) } /// Trap Cause @@ -121,14 +135,7 @@ impl Mcause { /// Is trap cause an interrupt. #[inline] pub fn is_interrupt(&self) -> bool { - match () { - #[cfg(target_pointer_width = "32")] - () => self.bits & (1 << 31) == 1 << 31, - #[cfg(target_pointer_width = "64")] - () => self.bits & (1 << 63) == 1 << 63, - #[cfg(target_pointer_width = "128")] - () => self.bits & (1 << 127) == 1 << 127, - } + self.bits & (1 << (usize::BITS as usize - 1)) != 0 } /// Is trap cause an exception. diff --git a/src/register/scause.rs b/src/register/scause.rs index 1f6f9a40..79fa1b9e 100644 --- a/src/register/scause.rs +++ b/src/register/scause.rs @@ -1,7 +1,5 @@ //! scause register -use bit_field::BitField; - /// scause register #[derive(Clone, Copy)] pub struct Scause { @@ -17,66 +15,88 @@ pub enum Trap { /// Interrupt #[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(usize)] pub enum Interrupt { - UserSoft, - SupervisorSoft, - UserTimer, - SupervisorTimer, - UserExternal, - SupervisorExternal, + SupervisorSoft = 1, + SupervisorTimer = 5, + SupervisorExternal = 9, Unknown, } /// Exception #[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(usize)] pub enum Exception { - InstructionMisaligned, - InstructionFault, - IllegalInstruction, - Breakpoint, - LoadMisaligned, - LoadFault, - StoreMisaligned, - StoreFault, - UserEnvCall, - InstructionPageFault, - LoadPageFault, - StorePageFault, + InstructionMisaligned = 0, + InstructionFault = 1, + IllegalInstruction = 2, + Breakpoint = 3, + LoadMisaligned = 4, + LoadFault = 5, + StoreMisaligned = 6, + StoreFault = 7, + UserEnvCall = 8, + SupervisorEnvCall = 9, + InstructionPageFault = 12, + LoadPageFault = 13, + StorePageFault = 15, Unknown, } -impl Interrupt { +impl From for Interrupt { #[inline] - pub fn from(nr: usize) -> Self { + 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, + 1 => Self::SupervisorSoft, + 5 => Self::SupervisorTimer, + 9 => Self::SupervisorExternal, + _ => Self::Unknown, + } + } +} + +impl TryFrom for usize { + type Error = Interrupt; + + #[inline] + fn try_from(value: Interrupt) -> Result { + match value { + Interrupt::Unknown => Err(Self::Error::Unknown), + _ => Ok(value as Self), } } } -impl Exception { +impl From for Exception { #[inline] - pub fn from(nr: usize) -> Self { + fn from(nr: usize) -> Self { match nr { - 0 => Exception::InstructionMisaligned, - 1 => Exception::InstructionFault, - 2 => Exception::IllegalInstruction, - 3 => Exception::Breakpoint, - 4 => Exception::LoadMisaligned, - 5 => Exception::LoadFault, - 6 => Exception::StoreMisaligned, - 7 => Exception::StoreFault, - 8 => Exception::UserEnvCall, - 12 => Exception::InstructionPageFault, - 13 => Exception::LoadPageFault, - 15 => Exception::StorePageFault, - _ => Exception::Unknown, + 0 => Self::InstructionMisaligned, + 1 => Self::InstructionFault, + 2 => Self::IllegalInstruction, + 3 => Self::Breakpoint, + 4 => Self::LoadMisaligned, + 5 => Self::LoadFault, + 6 => Self::StoreMisaligned, + 7 => Self::StoreFault, + 8 => Self::UserEnvCall, + 9 => Self::SupervisorEnvCall, + 12 => Self::InstructionPageFault, + 13 => Self::LoadPageFault, + 15 => Self::StorePageFault, + _ => Self::Unknown, + } + } +} + +impl TryFrom for usize { + type Error = Exception; + + #[inline] + fn try_from(value: Exception) -> Result { + match value { + Exception::Unknown => Err(Self::Error::Unknown), + _ => Ok(value as Self), } } } @@ -91,8 +111,7 @@ impl Scause { /// Returns the code field #[inline] pub fn code(&self) -> usize { - let bit = 1 << (usize::BITS as usize - 1); - self.bits & !bit + self.bits & !(1 << (usize::BITS as usize - 1)) } /// Trap Cause @@ -108,7 +127,7 @@ impl Scause { /// Is trap cause an interrupt. #[inline] pub fn is_interrupt(&self) -> bool { - self.bits.get_bit(usize::BITS as usize - 1) + self.bits & (1 << (usize::BITS as usize - 1)) != 0 } /// Is trap cause an exception. @@ -132,31 +151,10 @@ pub unsafe fn write(bits: usize) { 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 << (usize::BITS as usize - 1))) - } // interrupt bit is 1 - Trap::Exception(e) => match e { - Exception::InstructionMisaligned => 0, - Exception::InstructionFault => 1, - Exception::IllegalInstruction => 2, - Exception::Breakpoint => 3, - Exception::LoadMisaligned => 4, - 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"), - }, // interrupt bit is 0 + let i = usize::try_from(i).expect("unknown interrupt"); + i | (1 << (usize::BITS as usize - 1)) // interrupt bit is 1 + } + Trap::Exception(e) => usize::try_from(e).expect("unknown exception"), }; _write(bits); }