add user trap setup and handling registers

This commit is contained in:
Ales Katona 2019-08-27 09:40:47 -06:00
parent 4094a32f43
commit 2180ef44d5
No known key found for this signature in database
GPG Key ID: 08C459E2D8ABB7E8
13 changed files with 298 additions and 91 deletions

View File

@ -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

View File

@ -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::<usize>() * 8 - 1)
}
}

View File

@ -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]

View File

@ -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]

View File

@ -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 {

60
src/register/ucause.rs Normal file
View File

@ -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);

4
src/register/uepc.rs Normal file
View File

@ -0,0 +1,4 @@
//! uepc register
read_csr_as_usize!(0x041, __read_mepc);
write_csr_as_usize!(0x041, __write_mepc);

49
src/register/uie.rs Normal file
View File

@ -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);

37
src/register/uip.rs Normal file
View File

@ -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);

4
src/register/uscratch.rs Normal file
View File

@ -0,0 +1,4 @@
//! uscratch register
read_csr_as_usize!(0x040, __read_mscratch);
write_csr_as_usize!(0x040, __write_mscratch);

76
src/register/ustatus.rs Normal file
View File

@ -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 `f0f31`.
#[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::<usize>() * 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);

3
src/register/utval.rs Normal file
View File

@ -0,0 +1,3 @@
//! utval register
read_csr_as_usize!(0x043, __read_mtval);

40
src/register/utvec.rs Normal file
View File

@ -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);
}