From 2180ef44d50266a6f29a0c7552a6db1e6be576eb Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 27 Aug 2019 09:40:47 -0600 Subject: [PATCH] add user trap setup and handling registers --- src/register/mod.rs | 15 +++++--- src/register/mstatus.rs | 10 +++++- src/register/scause.rs | 72 ++----------------------------------- src/register/sstatus.rs | 10 +----- src/register/stvec.rs | 9 ++--- src/register/ucause.rs | 60 +++++++++++++++++++++++++++++++ src/register/uepc.rs | 4 +++ src/register/uie.rs | 49 ++++++++++++++++++++++++++ src/register/uip.rs | 37 +++++++++++++++++++ src/register/uscratch.rs | 4 +++ src/register/ustatus.rs | 76 ++++++++++++++++++++++++++++++++++++++++ src/register/utval.rs | 3 ++ src/register/utvec.rs | 40 +++++++++++++++++++++ 13 files changed, 298 insertions(+), 91 deletions(-) create mode 100644 src/register/ucause.rs create mode 100644 src/register/uepc.rs create mode 100644 src/register/uie.rs create mode 100644 src/register/uip.rs create mode 100644 src/register/uscratch.rs create mode 100644 src/register/ustatus.rs create mode 100644 src/register/utval.rs create mode 100644 src/register/utvec.rs diff --git a/src/register/mod.rs b/src/register/mod.rs index 82fb0a1..35251bc 100644 --- a/src/register/mod.rs +++ b/src/register/mod.rs @@ -13,11 +13,18 @@ #[macro_use] mod macros; -// TODO: User Trap Setup - - -// TODO: User Trap Handling +// User Trap Setup +// TODO: sedeleg, sideleg +pub mod ustatus; +pub mod uie; +pub mod utvec; +// User Trap Handling +pub mod uscratch; +pub mod uepc; +pub mod ucause; +pub mod utval; +pub mod uip; // User Floating-Point CSRs // TODO: frm, fflags diff --git a/src/register/mstatus.rs b/src/register/mstatus.rs index 9693918..6c34c83 100644 --- a/src/register/mstatus.rs +++ b/src/register/mstatus.rs @@ -2,6 +2,7 @@ // TODO: Virtualization, Memory Privilege and Extension Context Fields use bit_field::BitField; +use core::mem::size_of; /// mstatus register #[derive(Clone, Copy, Debug)] @@ -80,7 +81,7 @@ impl Mstatus { self.bits.get_bit(5) } - /// User Previous Interrupt Enable + /// Machine Previous Interrupt Enable #[inline] pub fn mpie(&self) -> bool { self.bits.get_bit(7) @@ -134,6 +135,13 @@ impl Mstatus { _ => unreachable!(), } } + + /// Whether either the FS field or XS field + /// signals the presence of some dirty state + #[inline] + pub fn sd(&self) -> bool { + self.bits.get_bit(size_of::() * 8 - 1) + } } diff --git a/src/register/scause.rs b/src/register/scause.rs index 0172f07..b0a3e40 100644 --- a/src/register/scause.rs +++ b/src/register/scause.rs @@ -3,82 +3,14 @@ use bit_field::BitField; use core::mem::size_of; +pub use crate::register::mcause::{Interrupt, Exception, Trap}; + /// scause register #[derive(Clone, Copy)] pub struct Scause { bits: usize, } -/// Trap Cause -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum Trap { - Interrupt(Interrupt), - Exception(Exception), -} - -/// Interrupt -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum Interrupt { - UserSoft, - SupervisorSoft, - UserTimer, - SupervisorTimer, - UserExternal, - SupervisorExternal, - Unknown, -} - -/// Exception -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum Exception { - InstructionMisaligned, - InstructionFault, - IllegalInstruction, - Breakpoint, - LoadFault, - StoreMisaligned, - StoreFault, - UserEnvCall, - InstructionPageFault, - LoadPageFault, - StorePageFault, - Unknown, -} - -impl Interrupt { - 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 { - 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 { /// Returns the contents of the register as raw bits #[inline] diff --git a/src/register/sstatus.rs b/src/register/sstatus.rs index 550aaf2..68908fc 100644 --- a/src/register/sstatus.rs +++ b/src/register/sstatus.rs @@ -2,6 +2,7 @@ use bit_field::BitField; use core::mem::size_of; +pub use super::mstatus::FS; /// Supervisor Status Register #[derive(Clone, Copy, Debug)] @@ -16,15 +17,6 @@ pub enum SPP { User = 0, } -/// Floating-point unit Status -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum FS { - Off = 0, - Initial = 1, - Clean = 2, - Dirty = 3, -} - impl Sstatus { /// User Interrupt Enable #[inline] diff --git a/src/register/stvec.rs b/src/register/stvec.rs index aab918b..2bbbefa 100644 --- a/src/register/stvec.rs +++ b/src/register/stvec.rs @@ -1,18 +1,13 @@ //! stvec register +pub use crate::register::mtvec::TrapMode; + /// stvec register #[derive(Clone, Copy, Debug)] pub struct Stvec { bits: usize, } -/// Trap mode -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum TrapMode { - Direct = 0, - Vectored = 1, -} - impl Stvec { /// Returns the contents of the register as raw bits pub fn bits(&self) -> usize { diff --git a/src/register/ucause.rs b/src/register/ucause.rs new file mode 100644 index 0000000..33db79c --- /dev/null +++ b/src/register/ucause.rs @@ -0,0 +1,60 @@ +//! ucause register + +pub use crate::register::mcause::{Interrupt, Exception, Trap}; + +/// ucause register +#[derive(Clone, Copy, Debug)] +pub struct Ucause { + bits: usize, +} + +impl Ucause { + /// Returns the contents of the register as raw bits + #[inline] + pub fn bits(&self) -> usize { + self.bits + } + + /// Returns the code field + 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), + } + } + + /// Trap Cause + #[inline] + pub fn cause(&self) -> Trap { + if self.is_interrupt() { + Trap::Interrupt(Interrupt::from(self.code())) + } else { + Trap::Exception(Exception::from(self.code())) + } + } + + /// 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, + } + } + + /// Is trap cause an exception. + #[inline] + pub fn is_exception(&self) -> bool { + !self.is_interrupt() + } +} + +read_csr_as!(Ucause, 0x042, __read_mcause); diff --git a/src/register/uepc.rs b/src/register/uepc.rs new file mode 100644 index 0000000..0a0ba9b --- /dev/null +++ b/src/register/uepc.rs @@ -0,0 +1,4 @@ +//! uepc register + +read_csr_as_usize!(0x041, __read_mepc); +write_csr_as_usize!(0x041, __write_mepc); diff --git a/src/register/uie.rs b/src/register/uie.rs new file mode 100644 index 0000000..75a23f6 --- /dev/null +++ b/src/register/uie.rs @@ -0,0 +1,49 @@ +//! uie register + +use bit_field::BitField; + +/// uie register +#[derive(Clone, Copy, Debug)] +pub struct Uie { + bits: usize, +} + +impl Uie { + /// Returns the contents of the register as raw bits + #[inline] + pub fn bits(&self) -> usize { + self.bits + } + + /// User Software Interrupt Enable + #[inline] + pub fn usoft(&self) -> bool { + self.bits.get_bit(0) + } + + /// User Timer Interrupt Enable + #[inline] + pub fn utimer(&self) -> bool { + self.bits.get_bit(4) + } + + /// User External Interrupt Enable + #[inline] + pub fn uext(&self) -> bool { + self.bits.get_bit(8) + } +} + +read_csr_as!(Uie, 0x004, __read_sie); +set!(0x004, __set_sie); +clear!(0x004, __clear_sie); + +set_clear_csr!( + /// User Software Interrupt Enable + , set_usoft, clear_usoft, 1 << 0); +set_clear_csr!( + /// User Timer Interrupt Enable + , set_utimer, clear_utimer, 1 << 4); +set_clear_csr!( + /// User External Interrupt Enable + , set_uext, clear_uext, 1 << 8); diff --git a/src/register/uip.rs b/src/register/uip.rs new file mode 100644 index 0000000..700292b --- /dev/null +++ b/src/register/uip.rs @@ -0,0 +1,37 @@ +//! uip register + +use bit_field::BitField; + +/// uip register +#[derive(Clone, Copy, Debug)] +pub struct Uip { + bits: usize, +} + +impl Uip { + /// Returns the contents of the register as raw bits + #[inline] + pub fn bits(&self) -> usize { + self.bits + } + + /// User Software Interrupt Pending + #[inline] + pub fn usoft(&self) -> bool { + self.bits.get_bit(0) + } + + /// User Timer Interrupt Pending + #[inline] + pub fn utimer(&self) -> bool { + self.bits.get_bit(4) + } + + /// User External Interrupt Pending + #[inline] + pub fn uext(&self) -> bool { + self.bits.get_bit(8) + } +} + +read_csr_as!(Uip, 0x044, __read_mip); diff --git a/src/register/uscratch.rs b/src/register/uscratch.rs new file mode 100644 index 0000000..32f3e8d --- /dev/null +++ b/src/register/uscratch.rs @@ -0,0 +1,4 @@ +//! uscratch register + +read_csr_as_usize!(0x040, __read_mscratch); +write_csr_as_usize!(0x040, __write_mscratch); diff --git a/src/register/ustatus.rs b/src/register/ustatus.rs new file mode 100644 index 0000000..80a0982 --- /dev/null +++ b/src/register/ustatus.rs @@ -0,0 +1,76 @@ +//! mstatus register +// TODO: Virtualization, Memory Privilege and Extension Context Fields + +use bit_field::BitField; +use core::mem::size_of; +pub use super::mstatus::{XS, FS}; + +/// mstatus register +#[derive(Clone, Copy, Debug)] +pub struct Ustatus { + bits: usize, +} + +impl Ustatus { + /// User Interrupt Enable + #[inline] + pub fn uie(&self) -> bool { + self.bits.get_bit(0) + } + + /// User Previous Interrupt Enable + #[inline] + pub fn upie(&self) -> bool { + self.bits.get_bit(4) + } + + /// Floating-point extension state + /// + /// Encodes the status of the floating-point unit, + /// including the CSR `fcsr` and floating-point data registers `f0–f31`. + #[inline] + pub fn fs(&self) -> FS { + match self.bits.get_bits(13..15) { + 0b00 => FS::Off, + 0b01 => FS::Initial, + 0b10 => FS::Clean, + 0b11 => FS::Dirty, + _ => unreachable!(), + } + } + + /// Additional extension state + /// + /// Encodes the status of additional user-mode extensions and associated state. + #[inline] + pub fn xs(&self) -> XS { + match self.bits.get_bits(15..17) { + 0b00 => XS::AllOff, + 0b01 => XS::NoneDirtyOrClean, + 0b10 => XS::NoneDirtySomeClean, + 0b11 => XS::SomeDirty, + _ => unreachable!(), + } + } + + /// Whether either the FS field or XS field + /// signals the presence of some dirty state + #[inline] + pub fn sd(&self) -> bool { + self.bits.get_bit(size_of::() * 8 - 1) + } +} + + +read_csr_as!(Ustatus, 0x000, __read_ustatus); +write_csr!(0x000, __write_ustatus); +set!(0x000, __set_ustatus); +clear!(0x000, __clear_ustatus); + +set_clear_csr!( + /// User Interrupt Enable + , set_uie, clear_uie, 1 << 0); + +set_csr!( + /// User Previous Interrupt Enable + , set_upie, 1 << 4); diff --git a/src/register/utval.rs b/src/register/utval.rs new file mode 100644 index 0000000..35edac6 --- /dev/null +++ b/src/register/utval.rs @@ -0,0 +1,3 @@ +//! utval register + +read_csr_as_usize!(0x043, __read_mtval); diff --git a/src/register/utvec.rs b/src/register/utvec.rs new file mode 100644 index 0000000..b516e89 --- /dev/null +++ b/src/register/utvec.rs @@ -0,0 +1,40 @@ +//! stvec register + +pub use crate::register::mtvec::TrapMode; + +/// stvec register +#[derive(Clone, Copy, Debug)] +pub struct Utvec { + bits: usize, +} + +impl Utvec { + /// Returns the contents of the register as raw bits + pub fn bits(&self) -> usize { + self.bits + } + + /// Returns the trap-vector base-address + pub fn address(&self) -> usize { + self.bits - (self.bits & 0b11) + } + + /// Returns the trap-vector mode + pub fn trap_mode(&self) -> TrapMode { + let mode = self.bits & 0b11; + match mode { + 0 => TrapMode::Direct, + 1 => TrapMode::Vectored, + _ => unimplemented!() + } + } +} + +read_csr_as!(Utvec, 0x005, __read_stvec); +write_csr!(0x005, __write_stvec); + +/// Writes the CSR +#[inline] +pub unsafe fn write(addr: usize, mode: TrapMode) { + _write(addr + mode as usize); +}