add user trap setup and handling registers
This commit is contained in:
parent
4094a32f43
commit
2180ef44d5
@ -13,11 +13,18 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
// TODO: User Trap Setup
|
// User Trap Setup
|
||||||
|
// TODO: sedeleg, sideleg
|
||||||
|
pub mod ustatus;
|
||||||
// TODO: User Trap Handling
|
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
|
// User Floating-Point CSRs
|
||||||
// TODO: frm, fflags
|
// TODO: frm, fflags
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// TODO: Virtualization, Memory Privilege and Extension Context Fields
|
// TODO: Virtualization, Memory Privilege and Extension Context Fields
|
||||||
|
|
||||||
use bit_field::BitField;
|
use bit_field::BitField;
|
||||||
|
use core::mem::size_of;
|
||||||
|
|
||||||
/// mstatus register
|
/// mstatus register
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
@ -80,7 +81,7 @@ impl Mstatus {
|
|||||||
self.bits.get_bit(5)
|
self.bits.get_bit(5)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// User Previous Interrupt Enable
|
/// Machine Previous Interrupt Enable
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mpie(&self) -> bool {
|
pub fn mpie(&self) -> bool {
|
||||||
self.bits.get_bit(7)
|
self.bits.get_bit(7)
|
||||||
@ -134,6 +135,13 @@ impl Mstatus {
|
|||||||
_ => unreachable!(),
|
_ => 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,82 +3,14 @@
|
|||||||
use bit_field::BitField;
|
use bit_field::BitField;
|
||||||
use core::mem::size_of;
|
use core::mem::size_of;
|
||||||
|
|
||||||
|
pub use crate::register::mcause::{Interrupt, Exception, Trap};
|
||||||
|
|
||||||
/// scause register
|
/// scause register
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Scause {
|
pub struct Scause {
|
||||||
bits: usize,
|
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 {
|
impl Scause {
|
||||||
/// Returns the contents of the register as raw bits
|
/// Returns the contents of the register as raw bits
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use bit_field::BitField;
|
use bit_field::BitField;
|
||||||
use core::mem::size_of;
|
use core::mem::size_of;
|
||||||
|
pub use super::mstatus::FS;
|
||||||
|
|
||||||
/// Supervisor Status Register
|
/// Supervisor Status Register
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
@ -16,15 +17,6 @@ pub enum SPP {
|
|||||||
User = 0,
|
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 {
|
impl Sstatus {
|
||||||
/// User Interrupt Enable
|
/// User Interrupt Enable
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1,18 +1,13 @@
|
|||||||
//! stvec register
|
//! stvec register
|
||||||
|
|
||||||
|
pub use crate::register::mtvec::TrapMode;
|
||||||
|
|
||||||
/// stvec register
|
/// stvec register
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Stvec {
|
pub struct Stvec {
|
||||||
bits: usize,
|
bits: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trap mode
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub enum TrapMode {
|
|
||||||
Direct = 0,
|
|
||||||
Vectored = 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Stvec {
|
impl Stvec {
|
||||||
/// Returns the contents of the register as raw bits
|
/// Returns the contents of the register as raw bits
|
||||||
pub fn bits(&self) -> usize {
|
pub fn bits(&self) -> usize {
|
||||||
|
60
src/register/ucause.rs
Normal file
60
src/register/ucause.rs
Normal 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
4
src/register/uepc.rs
Normal 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
49
src/register/uie.rs
Normal 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
37
src/register/uip.rs
Normal 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
4
src/register/uscratch.rs
Normal 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
76
src/register/ustatus.rs
Normal 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 `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::<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
3
src/register/utval.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
//! utval register
|
||||||
|
|
||||||
|
read_csr_as_usize!(0x043, __read_mtval);
|
40
src/register/utvec.rs
Normal file
40
src/register/utvec.rs
Normal 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);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user