12: Add some S-Mode CSRs r=dvc94ch a=wangrunji0408
Add these S-Mode CSRs:
- `sstatus`
- `stvec`
- `sie`
- `sip`
- `scause`
- `stval`
- `sscratch`
- `sepc`
- `satp`
as well as:
- `time`
- `timeh`
and S-Mode instructions:
- `sfence.vma`
Most of the code have been tested in the [RustOS](https://github.com/wangrunji0408/RustOS) project.
14: Remove ecall and *ret instructions from riscv::asm r=dvc94ch a=Disasm
* *ret instructions should not be used directly in Rust code, they should be used in handlers, written in asm ([example](273f0d4f70/src/lib.rs (L294-L340)
)).
* ecall instruction should be wrapped into something like syscall(), which should be declared in another platform-specific crate.
Co-authored-by: WangRunji <wangrunji0408@163.com>
Co-authored-by: Vadim Kaushan <admin@disasm.info>
This commit is contained in:
commit
8bffbd7291
|
@ -10,6 +10,7 @@ license = "ISC"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bare-metal = "0.2.0"
|
bare-metal = "0.2.0"
|
||||||
|
bit_field = "0.9.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
inline-asm = []
|
inline-asm = []
|
16
src/asm.rs
16
src/asm.rs
|
@ -16,9 +16,17 @@ macro_rules! instruction {
|
||||||
|
|
||||||
|
|
||||||
/// Priviledged ISA Instructions
|
/// Priviledged ISA Instructions
|
||||||
instruction!(ecall, "ecall");
|
|
||||||
instruction!(ebreak, "ebreak");
|
instruction!(ebreak, "ebreak");
|
||||||
instruction!(uret, "uret");
|
|
||||||
instruction!(sret, "sret");
|
|
||||||
instruction!(mret, "mret");
|
|
||||||
instruction!(wfi, "wfi");
|
instruction!(wfi, "wfi");
|
||||||
|
instruction!(sfence_vma_all, "sfence.vma");
|
||||||
|
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||||
|
pub unsafe fn sfence_vma(asid: usize, addr: usize) {
|
||||||
|
asm!("sfence.vma $0, $1" :: "r"(asid), "r"(addr) :: "volatile");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
|
||||||
|
pub fn sfence_vma(_asid: usize, _addr: usize) {}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#![feature(const_fn)]
|
#![feature(const_fn)]
|
||||||
|
|
||||||
extern crate bare_metal;
|
extern crate bare_metal;
|
||||||
|
extern crate bit_field;
|
||||||
|
|
||||||
pub mod asm;
|
pub mod asm;
|
||||||
pub mod interrupt;
|
pub mod interrupt;
|
||||||
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
macro_rules! read_csr {
|
||||||
|
($csr_number:expr) => {
|
||||||
|
/// Reads the CSR
|
||||||
|
#[inline]
|
||||||
|
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||||
|
unsafe fn _read() -> usize {
|
||||||
|
let r: usize;
|
||||||
|
asm!("csrrs $0, $1, x0" : "=r"(r) : "i"($csr_number) :: "volatile");
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
|
||||||
|
unsafe fn _read() -> usize {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! read_csr_as {
|
||||||
|
($register:ident, $csr_number:expr) => {
|
||||||
|
read_csr!($csr_number);
|
||||||
|
|
||||||
|
/// Reads the CSR
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> $register {
|
||||||
|
$register { bits: unsafe{ _read() } }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! read_csr_as_usize {
|
||||||
|
($csr_number:expr) => {
|
||||||
|
read_csr!($csr_number);
|
||||||
|
|
||||||
|
/// Reads the CSR
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> usize {
|
||||||
|
unsafe{ _read() }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! write_csr {
|
||||||
|
($csr_number:expr) => {
|
||||||
|
/// Writes the CSR
|
||||||
|
#[inline]
|
||||||
|
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||||
|
unsafe fn _write(bits: usize) {
|
||||||
|
asm!("csrrw x0, $1, $0" :: "r"(bits), "i"($csr_number) :: "volatile");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
|
||||||
|
unsafe fn _write(_bits: usize) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! write_csr_as_usize {
|
||||||
|
($csr_number:expr) => {
|
||||||
|
write_csr!($csr_number);
|
||||||
|
|
||||||
|
/// Writes the CSR
|
||||||
|
#[inline]
|
||||||
|
pub fn write(bits: usize) {
|
||||||
|
unsafe{ _write(bits) }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! set {
|
||||||
|
($csr_number:expr) => {
|
||||||
|
/// Set the CSR
|
||||||
|
#[inline]
|
||||||
|
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||||
|
unsafe fn _set(bits: usize) {
|
||||||
|
asm!("csrrs x0, $1, $0" :: "r"(bits), "i"($csr_number) :: "volatile");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
|
||||||
|
unsafe fn _set(_bits: usize) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! clear {
|
||||||
|
($csr_number:expr) => {
|
||||||
|
/// Clear the CSR
|
||||||
|
#[inline]
|
||||||
|
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||||
|
unsafe fn _clear(bits: usize) {
|
||||||
|
asm!("csrrc x0, $1, $0" :: "r"(bits), "i"($csr_number) :: "volatile");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
|
||||||
|
unsafe fn _clear(_bits: usize) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! set_csr {
|
||||||
|
($set_field:ident, $e:expr) => {
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn $set_field() {
|
||||||
|
_set($e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! clear_csr {
|
||||||
|
($clear_field:ident, $e:expr) => {
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn $clear_field() {
|
||||||
|
_clear($e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! set_clear_csr {
|
||||||
|
($set_field:ident, $clear_field:ident, $e:expr) => {
|
||||||
|
set_csr!($set_field, $e);
|
||||||
|
clear_csr!($clear_field, $e);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,9 @@
|
||||||
//! - minstreth
|
//! - minstreth
|
||||||
//! - mhpmcounter[3-31]h
|
//! - mhpmcounter[3-31]h
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod macros;
|
||||||
|
|
||||||
pub mod mcause;
|
pub mod mcause;
|
||||||
pub mod mcycle;
|
pub mod mcycle;
|
||||||
pub mod mcycleh;
|
pub mod mcycleh;
|
||||||
|
@ -22,3 +25,16 @@ pub mod misa;
|
||||||
pub mod mstatus;
|
pub mod mstatus;
|
||||||
pub mod mtvec;
|
pub mod mtvec;
|
||||||
pub mod mvendorid;
|
pub mod mvendorid;
|
||||||
|
|
||||||
|
pub mod sstatus;
|
||||||
|
pub mod stvec;
|
||||||
|
pub mod sie;
|
||||||
|
pub mod sip;
|
||||||
|
pub mod scause;
|
||||||
|
pub mod stval;
|
||||||
|
pub mod satp;
|
||||||
|
pub mod sscratch;
|
||||||
|
pub mod sepc;
|
||||||
|
|
||||||
|
pub mod time;
|
||||||
|
pub mod timeh;
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
//! satp register
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||||
|
use bit_field::BitField;
|
||||||
|
|
||||||
|
/// satp register
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Satp {
|
||||||
|
bits: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Satp {
|
||||||
|
/// Returns the contents of the register as raw bits
|
||||||
|
#[inline]
|
||||||
|
pub fn bits(&self) -> usize {
|
||||||
|
self.bits
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Current address-translation scheme
|
||||||
|
#[inline]
|
||||||
|
#[cfg(target_arch = "riscv32")]
|
||||||
|
pub fn mode(&self) -> Mode {
|
||||||
|
match self.bits.get_bit(31) {
|
||||||
|
false => Mode::Bare,
|
||||||
|
true => Mode::Sv32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Current address-translation scheme
|
||||||
|
#[inline]
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub fn mode(&self) -> Mode {
|
||||||
|
match self.bits.get_bits(60..64) {
|
||||||
|
0 => Mode::Bare,
|
||||||
|
8 => Mode::Sv39,
|
||||||
|
9 => Mode::Sv48,
|
||||||
|
10 => Mode::Sv57,
|
||||||
|
11 => Mode::Sv64,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Address space identifier
|
||||||
|
#[inline]
|
||||||
|
#[cfg(target_arch = "riscv32")]
|
||||||
|
pub fn asid(&self) -> usize {
|
||||||
|
self.bits.get_bits(22..31)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Address space identifier
|
||||||
|
#[inline]
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub fn asid(&self) -> usize {
|
||||||
|
self.bits.get_bits(44..60)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Physical page number
|
||||||
|
#[inline]
|
||||||
|
#[cfg(target_arch = "riscv32")]
|
||||||
|
pub fn ppn(&self) -> usize {
|
||||||
|
self.bits.get_bits(0..22)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Physical page number
|
||||||
|
#[inline]
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub fn ppn(&self) -> usize {
|
||||||
|
self.bits.get_bits(0..44)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv32")]
|
||||||
|
pub enum Mode {
|
||||||
|
Bare = 0,
|
||||||
|
Sv32 = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub enum Mode {
|
||||||
|
Bare = 0,
|
||||||
|
Sv39 = 8,
|
||||||
|
Sv48 = 9,
|
||||||
|
Sv57 = 10,
|
||||||
|
Sv64 = 11,
|
||||||
|
}
|
||||||
|
|
||||||
|
read_csr_as!(Satp, 0x180);
|
||||||
|
write_csr!(0x180);
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg(target_arch = "riscv32")]
|
||||||
|
pub unsafe fn set(mode: Mode, asid: usize, ppn: usize) {
|
||||||
|
let mut bits = 0usize;
|
||||||
|
bits.set_bits(31..32, mode as usize);
|
||||||
|
bits.set_bits(22..31, asid);
|
||||||
|
bits.set_bits(0..22, ppn);
|
||||||
|
_write(bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub unsafe fn set(mode: Mode, asid: usize, ppn: usize) {
|
||||||
|
let mut bits = 0usize;
|
||||||
|
bits.set_bits(60..64, mode as usize);
|
||||||
|
bits.set_bits(44..60, asid);
|
||||||
|
bits.set_bits(0..44, ppn);
|
||||||
|
_write(bits);
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
//! scause register
|
||||||
|
|
||||||
|
use bit_field::BitField;
|
||||||
|
use core::mem::size_of;
|
||||||
|
|
||||||
|
/// scause register
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct Scause {
|
||||||
|
bits: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trap Cause
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum Trap {
|
||||||
|
Interrupt(Interrupt),
|
||||||
|
Exception(Exception),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Interrupt
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum Interrupt {
|
||||||
|
UserSoft,
|
||||||
|
SupervisorSoft,
|
||||||
|
UserTimer,
|
||||||
|
SupervisorTimer,
|
||||||
|
UserExternal,
|
||||||
|
SupervisorExternal,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Exception
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
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]
|
||||||
|
pub fn bits(&self) -> usize {
|
||||||
|
self.bits
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the code field
|
||||||
|
pub fn code(&self) -> usize {
|
||||||
|
let bit = 1 << (size_of::<usize>() * 8 - 1);
|
||||||
|
self.bits & !bit
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 {
|
||||||
|
self.bits.get_bit(size_of::<usize>() * 8 - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is trap cause an exception.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_exception(&self) -> bool {
|
||||||
|
!self.is_interrupt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
read_csr_as!(Scause, 0x142);
|
|
@ -0,0 +1,4 @@
|
||||||
|
//! sepc register
|
||||||
|
|
||||||
|
read_csr_as_usize!(0x141);
|
||||||
|
write_csr_as_usize!(0x141);
|
|
@ -0,0 +1,70 @@
|
||||||
|
//! sie register
|
||||||
|
|
||||||
|
use bit_field::BitField;
|
||||||
|
|
||||||
|
/// sie register
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Sie {
|
||||||
|
bits: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sie {
|
||||||
|
/// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor Software Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn ssoft(&self) -> bool {
|
||||||
|
self.bits.get_bit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// User Timer Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn utimer(&self) -> bool {
|
||||||
|
self.bits.get_bit(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor Timer Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn stimer(&self) -> bool {
|
||||||
|
self.bits.get_bit(5)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// User External Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn uext(&self) -> bool {
|
||||||
|
self.bits.get_bit(8)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor External Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn sext(&self) -> bool {
|
||||||
|
self.bits.get_bit(9)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
read_csr_as!(Sie, 0x104);
|
||||||
|
set!(0x104);
|
||||||
|
clear!(0x104);
|
||||||
|
|
||||||
|
/// User Software Interrupt Enable
|
||||||
|
set_clear_csr!(set_usoft, clear_usoft, 1 << 0);
|
||||||
|
/// Supervisor Software Interrupt Enable
|
||||||
|
set_clear_csr!(set_ssoft, clear_ssoft, 1 << 1);
|
||||||
|
/// User Timer Interrupt Enable
|
||||||
|
set_clear_csr!(set_utimer, clear_utimer, 1 << 4);
|
||||||
|
/// Supervisor Timer Interrupt Enable
|
||||||
|
set_clear_csr!(set_stimer, clear_stimer, 1 << 5);
|
||||||
|
/// User External Interrupt Enable
|
||||||
|
set_clear_csr!(set_uext, clear_uext, 1 << 8);
|
||||||
|
/// Supervisor External Interrupt Enable
|
||||||
|
set_clear_csr!(set_sext, clear_sext, 1 << 9);
|
|
@ -0,0 +1,55 @@
|
||||||
|
//! sip register
|
||||||
|
|
||||||
|
use bit_field::BitField;
|
||||||
|
|
||||||
|
/// sip register
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Sip {
|
||||||
|
bits: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sip {
|
||||||
|
/// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor Software Interrupt Pending
|
||||||
|
#[inline]
|
||||||
|
pub fn ssoft(&self) -> bool {
|
||||||
|
self.bits.get_bit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// User Timer Interrupt Pending
|
||||||
|
#[inline]
|
||||||
|
pub fn utimer(&self) -> bool {
|
||||||
|
self.bits.get_bit(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor Timer Interrupt Pending
|
||||||
|
#[inline]
|
||||||
|
pub fn stimer(&self) -> bool {
|
||||||
|
self.bits.get_bit(5)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// User External Interrupt Pending
|
||||||
|
#[inline]
|
||||||
|
pub fn uext(&self) -> bool {
|
||||||
|
self.bits.get_bit(8)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor External Interrupt Pending
|
||||||
|
#[inline]
|
||||||
|
pub fn sext(&self) -> bool {
|
||||||
|
self.bits.get_bit(9)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
read_csr_as!(Sip, 0x144);
|
|
@ -0,0 +1,4 @@
|
||||||
|
//! sscratch register
|
||||||
|
|
||||||
|
read_csr_as_usize!(0x140);
|
||||||
|
write_csr_as_usize!(0x140);
|
|
@ -0,0 +1,136 @@
|
||||||
|
//! sstatus register
|
||||||
|
|
||||||
|
use bit_field::BitField;
|
||||||
|
use core::mem::size_of;
|
||||||
|
|
||||||
|
/// Supervisor Status Register
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Sstatus {
|
||||||
|
bits: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor Previous Privilege Mode
|
||||||
|
#[derive(Eq, PartialEq)]
|
||||||
|
pub enum SPP {
|
||||||
|
Supervisor = 1,
|
||||||
|
User = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Floating-point unit Status
|
||||||
|
#[derive(Eq, PartialEq)]
|
||||||
|
pub enum FS {
|
||||||
|
Off = 0,
|
||||||
|
Initial = 1,
|
||||||
|
Clean = 2,
|
||||||
|
Dirty = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sstatus {
|
||||||
|
/// User Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn uie(&self) -> bool {
|
||||||
|
self.bits.get_bit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn sie(&self) -> bool {
|
||||||
|
self.bits.get_bit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// User Previous Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn upie(&self) -> bool {
|
||||||
|
self.bits.get_bit(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor Previous Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn spie(&self) -> bool {
|
||||||
|
self.bits.get_bit(5)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor Previous Privilege Mode
|
||||||
|
#[inline]
|
||||||
|
pub fn spp(&self) -> SPP {
|
||||||
|
match self.bits.get_bit(8) {
|
||||||
|
true => SPP::Supervisor,
|
||||||
|
false => SPP::User,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The status of the floating-point unit
|
||||||
|
#[inline]
|
||||||
|
pub fn fs(&self) -> FS {
|
||||||
|
match self.bits.get_bits(13..15) {
|
||||||
|
0 => FS::Off,
|
||||||
|
1 => FS::Initial,
|
||||||
|
2 => FS::Clean,
|
||||||
|
3 => FS::Dirty,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The status of additional user-mode extensions
|
||||||
|
/// and associated state
|
||||||
|
#[inline]
|
||||||
|
pub fn xs(&self) -> FS {
|
||||||
|
match self.bits.get_bits(15..17) {
|
||||||
|
0 => FS::Off,
|
||||||
|
1 => FS::Initial,
|
||||||
|
2 => FS::Clean,
|
||||||
|
3 => FS::Dirty,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Permit Supervisor User Memory access
|
||||||
|
#[inline]
|
||||||
|
pub fn sum(&self) -> bool {
|
||||||
|
self.bits.get_bit(18)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make eXecutable Readable
|
||||||
|
#[inline]
|
||||||
|
pub fn mxr(&self) -> bool {
|
||||||
|
self.bits.get_bit(19)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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!(Sstatus, 0x100);
|
||||||
|
set!(0x100);
|
||||||
|
clear!(0x100);
|
||||||
|
|
||||||
|
/// User Interrupt Enable
|
||||||
|
set_clear_csr!(set_uie, clear_uie, 1 << 0);
|
||||||
|
/// Supervisor Interrupt Enable
|
||||||
|
set_clear_csr!(set_sie, clear_sie, 1 << 1);
|
||||||
|
/// User Previous Interrupt Enable
|
||||||
|
set_csr!(set_upie, 1 << 4);
|
||||||
|
/// Supervisor Previous Interrupt Enable
|
||||||
|
set_csr!(set_spie, 1 << 5);
|
||||||
|
/// Make eXecutable Readable
|
||||||
|
set_clear_csr!(set_mxr, clear_mxr, 1 << 19);
|
||||||
|
/// Permit Supervisor User Memory access
|
||||||
|
set_clear_csr!(set_sum, clear_sum, 1 << 18);
|
||||||
|
|
||||||
|
/// Supervisor Previous Privilege Mode
|
||||||
|
#[inline]
|
||||||
|
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||||
|
pub unsafe fn set_spp(spp: SPP) {
|
||||||
|
_set((spp as usize) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The status of the floating-point unit
|
||||||
|
#[inline]
|
||||||
|
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||||
|
pub unsafe fn set_fs(fs: FS) {
|
||||||
|
_set((fs as usize) << 13);
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
//! stval register
|
||||||
|
|
||||||
|
read_csr_as_usize!(0x143);
|
|
@ -0,0 +1,45 @@
|
||||||
|
//! stvec register
|
||||||
|
|
||||||
|
/// stvec register
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Stvec {
|
||||||
|
bits: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trap mode
|
||||||
|
pub enum TrapMode {
|
||||||
|
Direct = 0,
|
||||||
|
Vectored = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stvec {
|
||||||
|
/// 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!(Stvec, 0x105);
|
||||||
|
write_csr!(0x105);
|
||||||
|
|
||||||
|
/// Writes the CSR
|
||||||
|
#[inline]
|
||||||
|
#[cfg_attr(not(any(target_arch = "riscv32", target_arch = "riscv64")), allow(unused_variables))]
|
||||||
|
pub unsafe fn write(addr: usize, mode: TrapMode) {
|
||||||
|
_write(addr + mode as usize);
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
//! time register
|
||||||
|
|
||||||
|
read_csr_as_usize!(0xC01);
|
|
@ -0,0 +1,18 @@
|
||||||
|
//! timeh register
|
||||||
|
|
||||||
|
/// Reads the CSR
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> usize {
|
||||||
|
match () {
|
||||||
|
#[cfg(target_arch = "riscv32")]
|
||||||
|
() => {
|
||||||
|
let r: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!("csrrs $0, 0xC81, x0" : "=r"(r) ::: "volatile");
|
||||||
|
}
|
||||||
|
r
|
||||||
|
}
|
||||||
|
#[cfg(not(target_arch = "riscv32"))]
|
||||||
|
() => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue