add S-Mode registers

- use macros to simplify CSR ops
- use crate 'bit_field' to make bits operation clear
This commit is contained in:
WangRunji 2018-11-09 22:42:46 +08:00
parent 9dc7b40fdd
commit 8776d30d3b
15 changed files with 711 additions and 0 deletions

View File

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

View File

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

129
src/register/macros.rs Normal file
View File

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

View File

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

108
src/register/satp.rs Normal file
View File

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

118
src/register/scause.rs Normal file
View File

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

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

@ -0,0 +1,4 @@
//! sepc register
read_csr_as_usize!(0x141);
write_csr_as_usize!(0x141);

70
src/register/sie.rs Normal file
View File

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

55
src/register/sip.rs Normal file
View File

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

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

@ -0,0 +1,4 @@
//! sscratch register
read_csr_as_usize!(0x140);
write_csr_as_usize!(0x140);

136
src/register/sstatus.rs Normal file
View File

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

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

@ -0,0 +1,3 @@
//! stval register
read_csr_as_usize!(0x143);

45
src/register/stvec.rs Normal file
View File

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

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

@ -0,0 +1,3 @@
//! time register
read_csr_as_usize!(0xC01);

18
src/register/timeh.rs Normal file
View File

@ -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!(),
}
}