initial commit

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
2019-12-18 09:59:00 +08:00
commit 79114aa65a
80 changed files with 4021 additions and 0 deletions

77
xous-riscv/src/asm.rs Normal file
View File

@ -0,0 +1,77 @@
//! Assembly instructions
macro_rules! instruction {
($(#[$attr:meta])*, $fnname:ident, $asm:expr, $asm_fn:ident) => (
$(#[$attr])*
#[inline]
pub unsafe fn $fnname() {
match () {
#[cfg(all(riscv, feature = "inline-asm"))]
() => asm!($asm :::: "volatile"),
#[cfg(all(riscv, not(feature = "inline-asm")))]
() => {
extern "C" {
fn $asm_fn();
}
$asm_fn();
}
#[cfg(not(riscv))]
() => unimplemented!(),
}
}
)
}
instruction!(
/// `EBREAK` instruction wrapper
///
/// Generates a breakpoint exception.
, ebreak, "ebreak", __ebreak);
instruction!(
/// `WFI` instruction wrapper
///
/// Provides a hint to the implementation that the current hart can be stalled until an interrupt might need servicing.
/// The WFI instruction is just a hint, and a legal implementation is to implement WFI as a NOP.
, wfi, "wfi", __wfi);
instruction!(
/// `SFENCE.VMA` instruction wrapper (all address spaces and page table levels)
///
/// Synchronizes updates to in-memory memory-management data structures with current execution.
/// Instruction execution causes implicit reads and writes to these data structures; however, these implicit references
/// are ordinarily not ordered with respect to loads and stores in the instruction stream.
/// Executing an `SFENCE.VMA` instruction guarantees that any stores in the instruction stream prior to the
/// `SFENCE.VMA` are ordered before all implicit references subsequent to the `SFENCE.VMA`.
, sfence_vma_all, "sfence.vma", __sfence_vma_all);
/// `SFENCE.VMA` instruction wrapper
///
/// Synchronizes updates to in-memory memory-management data structures with current execution.
/// Instruction execution causes implicit reads and writes to these data structures; however, these implicit references
/// are ordinarily not ordered with respect to loads and stores in the instruction stream.
/// Executing an `SFENCE.VMA` instruction guarantees that any stores in the instruction stream prior to the
/// `SFENCE.VMA` are ordered before all implicit references subsequent to the `SFENCE.VMA`.
#[inline]
#[allow(unused_variables)]
pub unsafe fn sfence_vma(asid: usize, addr: usize) {
match () {
#[cfg(all(riscv, feature = "inline-asm"))]
() => asm!("sfence.vma $0, $1" :: "r"(asid), "r"(addr) :: "volatile"),
#[cfg(all(riscv, not(feature = "inline-asm")))]
() => {
extern "C" {
fn __sfence_vma(asid: usize, addr: usize);
}
__sfence_vma(asid, addr);
}
#[cfg(not(riscv))]
() => unimplemented!(),
}
}

View File

@ -0,0 +1,54 @@
//! Interrupts
// NOTE: Adapted from cortex-m/src/interrupt.rs
pub use bare_metal::{CriticalSection, Mutex, Nr};
use register::mstatus;
/// Disables all interrupts
#[inline]
pub unsafe fn disable() {
match () {
#[cfg(riscv)]
() => mstatus::clear_mie(),
#[cfg(not(riscv))]
() => unimplemented!(),
}
}
/// Enables all the interrupts
///
/// # Safety
///
/// - Do not call this function inside an `interrupt::free` critical section
#[inline]
pub unsafe fn enable() {
match () {
#[cfg(riscv)]
() => mstatus::set_mie(),
#[cfg(not(riscv))]
() => unimplemented!(),
}
}
/// Execute closure `f` in an interrupt-free context.
///
/// This as also known as a "critical section".
pub fn free<F, R>(f: F) -> R
where
F: FnOnce(&CriticalSection) -> R,
{
let mstatus = mstatus::read();
// disable interrupts
unsafe { disable(); }
let r = f(unsafe { &CriticalSection::new() });
// If the interrupts were active before our `disable` call, then re-enable
// them. Otherwise, keep them disabled
if mstatus.mie() {
unsafe { enable(); }
}
r
}

27
xous-riscv/src/lib.rs Normal file
View File

@ -0,0 +1,27 @@
//! Low level access to RISC-V processors
//!
//! # Minimum Supported Rust Version (MSRV)
//!
//! This crate is guaranteed to compile on stable Rust 1.30 and up. It *might*
//! compile with older versions but that may change in any new patch release.
//! Note that `riscv64imac-unknown-none-elf` and `riscv64gc-unknown-none-elf` targets
//! are not supported on stable yet.
//!
//! # Features
//!
//! This crate provides:
//!
//! - Access to core registers like `mstatus` or `mcause`.
//! - Interrupt manipulation mechanisms.
//! - Wrappers around assembly instructions like `WFI`.
#![no_std]
#![deny(warnings)]
#![cfg_attr(feature = "inline-asm", feature(asm))]
extern crate bare_metal;
extern crate bit_field;
pub mod asm;
pub mod interrupt;
pub mod register;

View File

@ -0,0 +1,132 @@
//! Floating-point control and status register
use bit_field::BitField;
/// Floating-point control and status register
#[derive(Clone, Copy, Debug)]
pub struct FCSR {
bits: u32,
}
/// Accrued Exception Flags
#[derive(Clone, Copy, Debug)]
pub struct Flags(u32);
/// Accrued Exception Flag
#[derive(Clone, Copy, Debug)]
pub enum Flag {
/// Inexact
NX = 0b00001,
/// Underflow
UF = 0b00010,
/// Overflow
OF = 0b00100,
/// Divide by Zero
DZ = 0b01000,
/// Invalid Operation
NV = 0b10000,
}
impl Flags {
/// Inexact
#[inline]
pub fn nx(&self) -> bool {
self.0.get_bit(0)
}
/// Underflow
#[inline]
pub fn uf(&self) -> bool {
self.0.get_bit(1)
}
/// Overflow
#[inline]
pub fn of(&self) -> bool {
self.0.get_bit(2)
}
/// Divide by Zero
#[inline]
pub fn dz(&self) -> bool {
self.0.get_bit(3)
}
/// Invalid Operation
#[inline]
pub fn nv(&self) -> bool {
self.0.get_bit(4)
}
}
/// Rounding Mode
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RoundingMode {
RoundToNearestEven = 0b000,
RoundTowardsZero = 0b001,
RoundDown = 0b010,
RoundUp = 0b011,
RoundToNearestMaxMagnitude = 0b100,
Invalid = 0b111,
}
impl FCSR {
/// Returns the contents of the register as raw bits
pub fn bits(&self) -> u32 {
self.bits
}
/// Accrued Exception Flags
#[inline]
pub fn fflags(&self) -> Flags {
Flags(self.bits.get_bits(0..5))
}
/// Rounding Mode
#[inline]
pub fn frm(&self) -> RoundingMode {
match self.bits.get_bits(5..8) {
0b000 => RoundingMode::RoundToNearestEven,
0b001 => RoundingMode::RoundTowardsZero,
0b010 => RoundingMode::RoundDown,
0b011 => RoundingMode::RoundUp,
0b100 => RoundingMode::RoundToNearestMaxMagnitude,
_ => RoundingMode::Invalid,
}
}
}
read_csr!(0x003, __read_fcsr);
write_csr!(0x003, __write_fcsr);
clear!(0x003, __clear_fcsr);
/// Reads the CSR
#[inline]
pub fn read() -> FCSR {
FCSR { bits: unsafe{ _read() as u32 } }
}
/// Writes the CSR
#[inline]
pub unsafe fn set_rounding_mode(frm: RoundingMode) {
let old = read();
let bits = ((frm as u32) << 5) | old.fflags().0;
_write(bits as usize);
}
/// Resets `fflags` field bits
#[inline]
pub unsafe fn clear_flags() {
let mask = 0b11111;
_clear(mask);
}
/// Resets `fflags` field bit
#[inline]
pub unsafe fn clear_flag(flag: Flag) {
_clear(flag as usize);
}

View File

@ -0,0 +1,82 @@
macro_rules! reg {
(
$addr:expr, $csrl:ident, $csrh:ident, $readf:ident, $writef:ident
) => {
/// Performance-monitoring counter
pub mod $csrl {
read_csr_as_usize!($addr, $readf);
read_composite_csr!(super::$csrh::read(), read());
}
}
}
macro_rules! regh {
(
$addr:expr, $csrh:ident, $readf:ident, $writef:ident
) => {
/// Upper 32 bits of performance-monitoring counter (RV32I only)
pub mod $csrh {
read_csr_as_usize_rv32!($addr, $readf);
}
}
}
reg!(0xC03, hpmcounter3, hpmcounter3h, __read_hpmcounter3, __write_hpmcounter3);
reg!(0xC04, hpmcounter4, hpmcounter4h, __read_hpmcounter4, __write_hpmcounter4);
reg!(0xC05, hpmcounter5, hpmcounter5h, __read_hpmcounter5, __write_hpmcounter5);
reg!(0xC06, hpmcounter6, hpmcounter6h, __read_hpmcounter6, __write_hpmcounter6);
reg!(0xC07, hpmcounter7, hpmcounter7h, __read_hpmcounter7, __write_hpmcounter7);
reg!(0xC08, hpmcounter8, hpmcounter8h, __read_hpmcounter8, __write_hpmcounter8);
reg!(0xC09, hpmcounter9, hpmcounter9h, __read_hpmcounter9, __write_hpmcounter9);
reg!(0xC0A, hpmcounter10, hpmcounter10h, __read_hpmcounter10, __write_hpmcounter10);
reg!(0xC0B, hpmcounter11, hpmcounter11h, __read_hpmcounter11, __write_hpmcounter11);
reg!(0xC0C, hpmcounter12, hpmcounter12h, __read_hpmcounter12, __write_hpmcounter12);
reg!(0xC0D, hpmcounter13, hpmcounter13h, __read_hpmcounter13, __write_hpmcounter13);
reg!(0xC0E, hpmcounter14, hpmcounter14h, __read_hpmcounter14, __write_hpmcounter14);
reg!(0xC0F, hpmcounter15, hpmcounter15h, __read_hpmcounter15, __write_hpmcounter15);
reg!(0xC10, hpmcounter16, hpmcounter16h, __read_hpmcounter16, __write_hpmcounter16);
reg!(0xC11, hpmcounter17, hpmcounter17h, __read_hpmcounter17, __write_hpmcounter17);
reg!(0xC12, hpmcounter18, hpmcounter18h, __read_hpmcounter18, __write_hpmcounter18);
reg!(0xC13, hpmcounter19, hpmcounter19h, __read_hpmcounter19, __write_hpmcounter19);
reg!(0xC14, hpmcounter20, hpmcounter20h, __read_hpmcounter20, __write_hpmcounter20);
reg!(0xC15, hpmcounter21, hpmcounter21h, __read_hpmcounter21, __write_hpmcounter21);
reg!(0xC16, hpmcounter22, hpmcounter22h, __read_hpmcounter22, __write_hpmcounter22);
reg!(0xC17, hpmcounter23, hpmcounter23h, __read_hpmcounter23, __write_hpmcounter23);
reg!(0xC18, hpmcounter24, hpmcounter24h, __read_hpmcounter24, __write_hpmcounter24);
reg!(0xC19, hpmcounter25, hpmcounter25h, __read_hpmcounter25, __write_hpmcounter25);
reg!(0xC1A, hpmcounter26, hpmcounter26h, __read_hpmcounter26, __write_hpmcounter26);
reg!(0xC1B, hpmcounter27, hpmcounter27h, __read_hpmcounter27, __write_hpmcounter27);
reg!(0xC1C, hpmcounter28, hpmcounter28h, __read_hpmcounter28, __write_hpmcounter28);
reg!(0xC1D, hpmcounter29, hpmcounter29h, __read_hpmcounter29, __write_hpmcounter29);
reg!(0xC1E, hpmcounter30, hpmcounter30h, __read_hpmcounter30, __write_hpmcounter30);
reg!(0xC1F, hpmcounter31, hpmcounter31h, __read_hpmcounter31, __write_hpmcounter31);
regh!(0xC83, hpmcounter3h, __read_hpmcounter3h, __write_hpmcounter3h);
regh!(0xC84, hpmcounter4h, __read_hpmcounter4h, __write_hpmcounter4h);
regh!(0xC85, hpmcounter5h, __read_hpmcounter5h, __write_hpmcounter5h);
regh!(0xC86, hpmcounter6h, __read_hpmcounter6h, __write_hpmcounter6h);
regh!(0xC87, hpmcounter7h, __read_hpmcounter7h, __write_hpmcounter7h);
regh!(0xC88, hpmcounter8h, __read_hpmcounter8h, __write_hpmcounter8h);
regh!(0xC89, hpmcounter9h, __read_hpmcounter9h, __write_hpmcounter9h);
regh!(0xC8A, hpmcounter10h, __read_hpmcounter10h, __write_hpmcounter10h);
regh!(0xC8B, hpmcounter11h, __read_hpmcounter11h, __write_hpmcounter11h);
regh!(0xC8C, hpmcounter12h, __read_hpmcounter12h, __write_hpmcounter12h);
regh!(0xC8D, hpmcounter13h, __read_hpmcounter13h, __write_hpmcounter13h);
regh!(0xC8E, hpmcounter14h, __read_hpmcounter14h, __write_hpmcounter14h);
regh!(0xC8F, hpmcounter15h, __read_hpmcounter15h, __write_hpmcounter15h);
regh!(0xC90, hpmcounter16h, __read_hpmcounter16h, __write_hpmcounter16h);
regh!(0xC91, hpmcounter17h, __read_hpmcounter17h, __write_hpmcounter17h);
regh!(0xC92, hpmcounter18h, __read_hpmcounter18h, __write_hpmcounter18h);
regh!(0xC93, hpmcounter19h, __read_hpmcounter19h, __write_hpmcounter19h);
regh!(0xC94, hpmcounter20h, __read_hpmcounter20h, __write_hpmcounter20h);
regh!(0xC95, hpmcounter21h, __read_hpmcounter21h, __write_hpmcounter21h);
regh!(0xC96, hpmcounter22h, __read_hpmcounter22h, __write_hpmcounter22h);
regh!(0xC97, hpmcounter23h, __read_hpmcounter23h, __write_hpmcounter23h);
regh!(0xC98, hpmcounter24h, __read_hpmcounter24h, __write_hpmcounter24h);
regh!(0xC99, hpmcounter25h, __read_hpmcounter25h, __write_hpmcounter25h);
regh!(0xC9A, hpmcounter26h, __read_hpmcounter26h, __write_hpmcounter26h);
regh!(0xC9B, hpmcounter27h, __read_hpmcounter27h, __write_hpmcounter27h);
regh!(0xC9C, hpmcounter28h, __read_hpmcounter28h, __write_hpmcounter28h);
regh!(0xC9D, hpmcounter29h, __read_hpmcounter29h, __write_hpmcounter29h);
regh!(0xC9E, hpmcounter30h, __read_hpmcounter30h, __write_hpmcounter30h);
regh!(0xC9F, hpmcounter31h, __read_hpmcounter31h, __write_hpmcounter31h);

View File

@ -0,0 +1,270 @@
macro_rules! read_csr {
($csr_number:expr, $asm_fn: ident) => {
/// Reads the CSR
#[inline]
unsafe fn _read() -> usize {
match () {
#[cfg(all(riscv, feature = "inline-asm"))]
() => {
let r: usize;
asm!("csrrs $0, $1, x0" : "=r"(r) : "i"($csr_number) :: "volatile");
r
}
#[cfg(all(riscv, not(feature = "inline-asm")))]
() => {
extern "C" {
fn $asm_fn() -> usize;
}
$asm_fn()
}
#[cfg(not(riscv))]
() => unimplemented!(),
}
}
};
}
macro_rules! read_csr_rv32 {
($csr_number:expr, $asm_fn: ident) => {
/// Reads the CSR
#[inline]
unsafe fn _read() -> usize {
match () {
#[cfg(all(riscv32, feature = "inline-asm"))]
() => {
let r: usize;
asm!("csrrs $0, $1, x0" : "=r"(r) : "i"($csr_number) :: "volatile");
r
}
#[cfg(all(riscv32, not(feature = "inline-asm")))]
() => {
extern "C" {
fn $asm_fn() -> usize;
}
$asm_fn()
}
#[cfg(not(riscv32))]
() => unimplemented!(),
}
}
};
}
macro_rules! read_csr_as {
($register:ident, $csr_number:expr, $asm_fn: ident) => {
read_csr!($csr_number, $asm_fn);
/// Reads the CSR
#[inline]
pub fn read() -> $register {
$register { bits: unsafe{ _read() } }
}
};
}
macro_rules! read_csr_as_usize {
($csr_number:expr, $asm_fn: ident) => {
read_csr!($csr_number, $asm_fn);
/// Reads the CSR
#[inline]
pub fn read() -> usize {
unsafe{ _read() }
}
};
}
macro_rules! read_csr_as_usize_rv32 {
($csr_number:expr, $asm_fn: ident) => {
read_csr_rv32!($csr_number, $asm_fn);
/// Reads the CSR
#[inline]
pub fn read() -> usize {
unsafe{ _read() }
}
};
}
macro_rules! write_csr {
($csr_number:expr, $asm_fn: ident) => {
/// Writes the CSR
#[inline]
#[allow(unused_variables)]
unsafe fn _write(bits: usize) {
match () {
#[cfg(all(riscv, feature = "inline-asm"))]
() => asm!("csrrw x0, $1, $0" :: "r"(bits), "i"($csr_number) :: "volatile"),
#[cfg(all(riscv, not(feature = "inline-asm")))]
() => {
extern "C" {
fn $asm_fn(bits: usize);
}
$asm_fn(bits);
}
#[cfg(not(riscv))]
() => unimplemented!(),
}
}
};
}
macro_rules! write_csr_rv32 {
($csr_number:expr, $asm_fn: ident) => {
/// Writes the CSR
#[inline]
#[allow(unused_variables)]
unsafe fn _write(bits: usize) {
match () {
#[cfg(all(riscv32, feature = "inline-asm"))]
() => asm!("csrrw x0, $1, $0" :: "r"(bits), "i"($csr_number) :: "volatile"),
#[cfg(all(riscv32, not(feature = "inline-asm")))]
() => {
extern "C" {
fn $asm_fn(bits: usize);
}
$asm_fn(bits);
}
#[cfg(not(riscv32))]
() => unimplemented!(),
}
}
};
}
macro_rules! write_csr_as_usize {
($csr_number:expr, $asm_fn: ident) => {
write_csr!($csr_number, $asm_fn);
/// Writes the CSR
#[inline]
pub fn write(bits: usize) {
unsafe{ _write(bits) }
}
};
}
macro_rules! write_csr_as_usize_rv32 {
($csr_number:expr, $asm_fn: ident) => {
write_csr_rv32!($csr_number, $asm_fn);
/// Writes the CSR
#[inline]
pub fn write(bits: usize) {
unsafe{ _write(bits) }
}
};
}
macro_rules! set {
($csr_number:expr, $asm_fn: ident) => {
/// Set the CSR
#[inline]
#[allow(unused_variables)]
unsafe fn _set(bits: usize) {
match () {
#[cfg(all(riscv, feature = "inline-asm"))]
() => asm!("csrrs x0, $1, $0" :: "r"(bits), "i"($csr_number) :: "volatile"),
#[cfg(all(riscv, not(feature = "inline-asm")))]
() => {
extern "C" {
fn $asm_fn(bits: usize);
}
$asm_fn(bits);
}
#[cfg(not(riscv))]
() => unimplemented!(),
}
}
};
}
macro_rules! clear {
($csr_number:expr, $asm_fn: ident) => {
/// Clear the CSR
#[inline]
#[allow(unused_variables)]
unsafe fn _clear(bits: usize) {
match () {
#[cfg(all(riscv, feature = "inline-asm"))]
() => asm!("csrrc x0, $1, $0" :: "r"(bits), "i"($csr_number) :: "volatile"),
#[cfg(all(riscv, not(feature = "inline-asm")))]
() => {
extern "C" {
fn $asm_fn(bits: usize);
}
$asm_fn(bits);
}
#[cfg(not(riscv))]
() => unimplemented!(),
}
}
};
}
macro_rules! set_csr {
($(#[$attr:meta])*, $set_field:ident, $e:expr) => {
$(#[$attr])*
#[inline]
pub unsafe fn $set_field() {
_set($e);
}
}
}
macro_rules! clear_csr {
($(#[$attr:meta])*, $clear_field:ident, $e:expr) => {
$(#[$attr])*
#[inline]
pub unsafe fn $clear_field() {
_clear($e);
}
}
}
macro_rules! set_clear_csr {
($(#[$attr:meta])*, $set_field:ident, $clear_field:ident, $e:expr) => {
set_csr!($(#[$attr])*, $set_field, $e);
clear_csr!($(#[$attr])*, $clear_field, $e);
}
}
macro_rules! read_composite_csr {
($hi:expr, $lo:expr) => {
/// Reads the CSR as a 64-bit value
#[inline]
pub fn read64() -> u64 {
match () {
#[cfg(riscv32)]
() => loop {
let hi = $hi;
let lo = $lo;
if hi == $hi {
return ((hi as u64) << 32) | lo as u64;
}
},
#[cfg(not(riscv32))]
() => $lo as u64,
}
}
}
}

View File

@ -0,0 +1,27 @@
//! marchid register
use core::num::NonZeroUsize;
/// marchid register
#[derive(Clone, Copy, Debug)]
pub struct Marchid {
bits: NonZeroUsize,
}
impl Marchid {
/// Returns the contents of the register as raw bits
pub fn bits(&self) -> usize {
self.bits.get()
}
}
read_csr!(0xF11, __read_marchid);
/// Reads the CSR
#[inline]
pub fn read() -> Option<Marchid> {
let r = unsafe{ _read() };
// When marchid is hardwired to zero it means that the marchid
// csr isn't implemented.
NonZeroUsize::new(r).map(|bits| Marchid { bits })
}

View File

@ -0,0 +1,139 @@
//! mcause register
/// mcause register
#[derive(Clone, Copy, Debug)]
pub struct Mcause {
bits: usize,
}
/// Trap Cause
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Trap {
Interrupt(Interrupt),
Exception(Exception),
}
/// Interrupt
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Interrupt {
UserSoft,
SupervisorSoft,
MachineSoft,
UserTimer,
SupervisorTimer,
MachineTimer,
UserExternal,
SupervisorExternal,
MachineExternal,
Unknown,
}
/// Exception
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Exception {
InstructionMisaligned,
InstructionFault,
IllegalInstruction,
Breakpoint,
LoadMisaligned,
LoadFault,
StoreMisaligned,
StoreFault,
UserEnvCall,
SupervisorEnvCall,
MachineEnvCall,
InstructionPageFault,
LoadPageFault,
StorePageFault,
Unknown,
}
impl Interrupt {
pub fn from(nr: usize) -> Self {
match nr {
0 => Interrupt::UserSoft,
1 => Interrupt::SupervisorSoft,
3 => Interrupt::MachineSoft,
4 => Interrupt::UserTimer,
5 => Interrupt::SupervisorTimer,
7 => Interrupt::MachineTimer,
8 => Interrupt::UserExternal,
9 => Interrupt::SupervisorExternal,
11 => Interrupt::MachineExternal,
_ => Interrupt::Unknown,
}
}
}
impl Exception {
pub fn from(nr: usize) -> Self {
match nr {
0 => Exception::InstructionMisaligned,
1 => Exception::InstructionFault,
2 => Exception::IllegalInstruction,
3 => Exception::Breakpoint,
4 => Exception::LoadMisaligned,
5 => Exception::LoadFault,
6 => Exception::StoreMisaligned,
7 => Exception::StoreFault,
8 => Exception::UserEnvCall,
9 => Exception::SupervisorEnvCall,
11 => Exception::MachineEnvCall,
12 => Exception::InstructionPageFault,
13 => Exception::LoadPageFault,
15 => Exception::StorePageFault,
_ => Exception::Unknown,
}
}
}
impl Mcause {
/// 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!(Mcause, 0x342, __read_mcause);

View File

@ -0,0 +1,4 @@
//! mcycle register
read_csr_as_usize!(0xB00, __read_mcycle);
read_composite_csr!(super::mcycleh::read(), read());

View File

@ -0,0 +1,3 @@
//! mcycleh register
read_csr_as_usize_rv32!(0xB80, __read_mcycleh);

View File

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

View File

@ -0,0 +1,3 @@
//! mhartid register
read_csr_as_usize!(0xf14, __read_mhartid);

View File

@ -0,0 +1,84 @@
macro_rules! reg {
(
$addr:expr, $csrl:ident, $csrh:ident, $readf:ident, $writef:ident
) => {
/// Machine performance-monitoring counter
pub mod $csrl {
read_csr_as_usize!($addr, $readf);
write_csr_as_usize!($addr, $writef);
read_composite_csr!(super::$csrh::read(), read());
}
}
}
macro_rules! regh {
(
$addr:expr, $csrh:ident, $readf:ident, $writef:ident
) => {
/// Upper 32 bits of machine performance-monitoring counter (RV32I only)
pub mod $csrh {
read_csr_as_usize_rv32!($addr, $readf);
write_csr_as_usize_rv32!($addr, $writef);
}
}
}
reg!(0xB03, mhpmcounter3, mhpmcounter3h, __read_mhpmcounter3, __write_mhpmcounter3);
reg!(0xB04, mhpmcounter4, mhpmcounter4h, __read_mhpmcounter4, __write_mhpmcounter4);
reg!(0xB05, mhpmcounter5, mhpmcounter5h, __read_mhpmcounter5, __write_mhpmcounter5);
reg!(0xB06, mhpmcounter6, mhpmcounter6h, __read_mhpmcounter6, __write_mhpmcounter6);
reg!(0xB07, mhpmcounter7, mhpmcounter7h, __read_mhpmcounter7, __write_mhpmcounter7);
reg!(0xB08, mhpmcounter8, mhpmcounter8h, __read_mhpmcounter8, __write_mhpmcounter8);
reg!(0xB09, mhpmcounter9, mhpmcounter9h, __read_mhpmcounter9, __write_mhpmcounter9);
reg!(0xB0A, mhpmcounter10, mhpmcounter10h, __read_mhpmcounter10, __write_mhpmcounter10);
reg!(0xB0B, mhpmcounter11, mhpmcounter11h, __read_mhpmcounter11, __write_mhpmcounter11);
reg!(0xB0C, mhpmcounter12, mhpmcounter12h, __read_mhpmcounter12, __write_mhpmcounter12);
reg!(0xB0D, mhpmcounter13, mhpmcounter13h, __read_mhpmcounter13, __write_mhpmcounter13);
reg!(0xB0E, mhpmcounter14, mhpmcounter14h, __read_mhpmcounter14, __write_mhpmcounter14);
reg!(0xB0F, mhpmcounter15, mhpmcounter15h, __read_mhpmcounter15, __write_mhpmcounter15);
reg!(0xB10, mhpmcounter16, mhpmcounter16h, __read_mhpmcounter16, __write_mhpmcounter16);
reg!(0xB11, mhpmcounter17, mhpmcounter17h, __read_mhpmcounter17, __write_mhpmcounter17);
reg!(0xB12, mhpmcounter18, mhpmcounter18h, __read_mhpmcounter18, __write_mhpmcounter18);
reg!(0xB13, mhpmcounter19, mhpmcounter19h, __read_mhpmcounter19, __write_mhpmcounter19);
reg!(0xB14, mhpmcounter20, mhpmcounter20h, __read_mhpmcounter20, __write_mhpmcounter20);
reg!(0xB15, mhpmcounter21, mhpmcounter21h, __read_mhpmcounter21, __write_mhpmcounter21);
reg!(0xB16, mhpmcounter22, mhpmcounter22h, __read_mhpmcounter22, __write_mhpmcounter22);
reg!(0xB17, mhpmcounter23, mhpmcounter23h, __read_mhpmcounter23, __write_mhpmcounter23);
reg!(0xB18, mhpmcounter24, mhpmcounter24h, __read_mhpmcounter24, __write_mhpmcounter24);
reg!(0xB19, mhpmcounter25, mhpmcounter25h, __read_mhpmcounter25, __write_mhpmcounter25);
reg!(0xB1A, mhpmcounter26, mhpmcounter26h, __read_mhpmcounter26, __write_mhpmcounter26);
reg!(0xB1B, mhpmcounter27, mhpmcounter27h, __read_mhpmcounter27, __write_mhpmcounter27);
reg!(0xB1C, mhpmcounter28, mhpmcounter28h, __read_mhpmcounter28, __write_mhpmcounter28);
reg!(0xB1D, mhpmcounter29, mhpmcounter29h, __read_mhpmcounter29, __write_mhpmcounter29);
reg!(0xB1E, mhpmcounter30, mhpmcounter30h, __read_mhpmcounter30, __write_mhpmcounter30);
reg!(0xB1F, mhpmcounter31, mhpmcounter31h, __read_mhpmcounter31, __write_mhpmcounter31);
regh!(0xB83, mhpmcounter3h, __read_mhpmcounter3h, __write_mhpmcounter3h);
regh!(0xB84, mhpmcounter4h, __read_mhpmcounter4h, __write_mhpmcounter4h);
regh!(0xB85, mhpmcounter5h, __read_mhpmcounter5h, __write_mhpmcounter5h);
regh!(0xB86, mhpmcounter6h, __read_mhpmcounter6h, __write_mhpmcounter6h);
regh!(0xB87, mhpmcounter7h, __read_mhpmcounter7h, __write_mhpmcounter7h);
regh!(0xB88, mhpmcounter8h, __read_mhpmcounter8h, __write_mhpmcounter8h);
regh!(0xB89, mhpmcounter9h, __read_mhpmcounter9h, __write_mhpmcounter9h);
regh!(0xB8A, mhpmcounter10h, __read_mhpmcounter10h, __write_mhpmcounter10h);
regh!(0xB8B, mhpmcounter11h, __read_mhpmcounter11h, __write_mhpmcounter11h);
regh!(0xB8C, mhpmcounter12h, __read_mhpmcounter12h, __write_mhpmcounter12h);
regh!(0xB8D, mhpmcounter13h, __read_mhpmcounter13h, __write_mhpmcounter13h);
regh!(0xB8E, mhpmcounter14h, __read_mhpmcounter14h, __write_mhpmcounter14h);
regh!(0xB8F, mhpmcounter15h, __read_mhpmcounter15h, __write_mhpmcounter15h);
regh!(0xB90, mhpmcounter16h, __read_mhpmcounter16h, __write_mhpmcounter16h);
regh!(0xB91, mhpmcounter17h, __read_mhpmcounter17h, __write_mhpmcounter17h);
regh!(0xB92, mhpmcounter18h, __read_mhpmcounter18h, __write_mhpmcounter18h);
regh!(0xB93, mhpmcounter19h, __read_mhpmcounter19h, __write_mhpmcounter19h);
regh!(0xB94, mhpmcounter20h, __read_mhpmcounter20h, __write_mhpmcounter20h);
regh!(0xB95, mhpmcounter21h, __read_mhpmcounter21h, __write_mhpmcounter21h);
regh!(0xB96, mhpmcounter22h, __read_mhpmcounter22h, __write_mhpmcounter22h);
regh!(0xB97, mhpmcounter23h, __read_mhpmcounter23h, __write_mhpmcounter23h);
regh!(0xB98, mhpmcounter24h, __read_mhpmcounter24h, __write_mhpmcounter24h);
regh!(0xB99, mhpmcounter25h, __read_mhpmcounter25h, __write_mhpmcounter25h);
regh!(0xB9A, mhpmcounter26h, __read_mhpmcounter26h, __write_mhpmcounter26h);
regh!(0xB9B, mhpmcounter27h, __read_mhpmcounter27h, __write_mhpmcounter27h);
regh!(0xB9C, mhpmcounter28h, __read_mhpmcounter28h, __write_mhpmcounter28h);
regh!(0xB9D, mhpmcounter29h, __read_mhpmcounter29h, __write_mhpmcounter29h);
regh!(0xB9E, mhpmcounter30h, __read_mhpmcounter30h, __write_mhpmcounter30h);
regh!(0xB9F, mhpmcounter31h, __read_mhpmcounter31h, __write_mhpmcounter31h);

View File

@ -0,0 +1,41 @@
macro_rules! reg {
(
$addr:expr, $csr:ident, $readf:ident, $writef:ident
) => {
/// Machine performance-monitoring event selector
pub mod $csr {
read_csr_as_usize!($addr, $readf);
write_csr_as_usize!($addr, $writef);
}
}
}
reg!(0x323, mhpmevent3, __read_mhpmevent3, __write_mhpmevent3);
reg!(0x324, mhpmevent4, __read_mhpmevent4, __write_mhpmevent4);
reg!(0x325, mhpmevent5, __read_mhpmevent5, __write_mhpmevent5);
reg!(0x326, mhpmevent6, __read_mhpmevent6, __write_mhpmevent6);
reg!(0x327, mhpmevent7, __read_mhpmevent7, __write_mhpmevent7);
reg!(0x328, mhpmevent8, __read_mhpmevent8, __write_mhpmevent8);
reg!(0x329, mhpmevent9, __read_mhpmevent9, __write_mhpmevent9);
reg!(0x32A, mhpmevent10, __read_mhpmevent10, __write_mhpmevent10);
reg!(0x32B, mhpmevent11, __read_mhpmevent11, __write_mhpmevent11);
reg!(0x32C, mhpmevent12, __read_mhpmevent12, __write_mhpmevent12);
reg!(0x32D, mhpmevent13, __read_mhpmevent13, __write_mhpmevent13);
reg!(0x32E, mhpmevent14, __read_mhpmevent14, __write_mhpmevent14);
reg!(0x32F, mhpmevent15, __read_mhpmevent15, __write_mhpmevent15);
reg!(0x330, mhpmevent16, __read_mhpmevent16, __write_mhpmevent16);
reg!(0x331, mhpmevent17, __read_mhpmevent17, __write_mhpmevent17);
reg!(0x332, mhpmevent18, __read_mhpmevent18, __write_mhpmevent18);
reg!(0x333, mhpmevent19, __read_mhpmevent19, __write_mhpmevent19);
reg!(0x334, mhpmevent20, __read_mhpmevent20, __write_mhpmevent20);
reg!(0x335, mhpmevent21, __read_mhpmevent21, __write_mhpmevent21);
reg!(0x336, mhpmevent22, __read_mhpmevent22, __write_mhpmevent22);
reg!(0x337, mhpmevent23, __read_mhpmevent23, __write_mhpmevent23);
reg!(0x338, mhpmevent24, __read_mhpmevent24, __write_mhpmevent24);
reg!(0x339, mhpmevent25, __read_mhpmevent25, __write_mhpmevent25);
reg!(0x33A, mhpmevent26, __read_mhpmevent26, __write_mhpmevent26);
reg!(0x33B, mhpmevent27, __read_mhpmevent27, __write_mhpmevent27);
reg!(0x33C, mhpmevent28, __read_mhpmevent28, __write_mhpmevent28);
reg!(0x33D, mhpmevent29, __read_mhpmevent29, __write_mhpmevent29);
reg!(0x33E, mhpmevent30, __read_mhpmevent30, __write_mhpmevent30);
reg!(0x33F, mhpmevent31, __read_mhpmevent31, __write_mhpmevent31);

View File

@ -0,0 +1,103 @@
//! mie register
use bit_field::BitField;
/// mie register
#[derive(Clone, Copy, Debug)]
pub struct Mie {
bits: usize,
}
impl Mie {
/// 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)
}
/// Machine Software Interrupt Enable
#[inline]
pub fn msoft(&self) -> bool {
self.bits.get_bit(3)
}
/// 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)
}
/// Machine Timer Interrupt Enable
#[inline]
pub fn mtimer(&self) -> bool {
self.bits.get_bit(7)
}
/// 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)
}
/// Machine External Interrupt Enable
#[inline]
pub fn mext(&self) -> bool {
self.bits.get_bit(11)
}
}
read_csr_as!(Mie, 0x304, __read_mie);
set!(0x304, __set_mie);
clear!(0x304, __clear_mie);
set_clear_csr!(
/// User Software Interrupt Enable
, set_usoft, clear_usoft, 1 << 0);
set_clear_csr!(
/// Supervisor Software Interrupt Enable
, set_ssoft, clear_ssoft, 1 << 1);
set_clear_csr!(
/// Machine Software Interrupt Enable
, set_msoft, clear_msoft, 1 << 3);
set_clear_csr!(
/// User Timer Interrupt Enable
, set_utimer, clear_utimer, 1 << 4);
set_clear_csr!(
/// Supervisor Timer Interrupt Enable
, set_stimer, clear_stimer, 1 << 5);
set_clear_csr!(
/// Machine Timer Interrupt Enable
, set_mtimer, clear_mtimer, 1 << 7);
set_clear_csr!(
/// User External Interrupt Enable
, set_uext, clear_uext, 1 << 8);
set_clear_csr!(
/// Supervisor External Interrupt Enable
, set_sext, clear_sext, 1 << 9);
set_clear_csr!(
/// Machine External Interrupt Enable
, set_mext, clear_mext, 1 << 11);

View File

@ -0,0 +1,27 @@
//! mimpid register
use core::num::NonZeroUsize;
/// mimpid register
#[derive(Clone, Copy, Debug)]
pub struct Mimpid {
bits: NonZeroUsize,
}
impl Mimpid {
/// Returns the contents of the register as raw bits
pub fn bits(&self) -> usize {
self.bits.get()
}
}
read_csr!(0xF11, __read_mimpid);
/// Reads the CSR
#[inline]
pub fn read() -> Option<Mimpid> {
let r = unsafe{ _read() };
// When mimpid is hardwired to zero it means that the mimpid
// csr isn't implemented.
NonZeroUsize::new(r).map(|bits| Mimpid { bits })
}

View File

@ -0,0 +1,4 @@
//! minstret register
read_csr_as_usize!(0xB02, __read_minstret);
read_composite_csr!(super::minstreth::read(), read());

View File

@ -0,0 +1,3 @@
//! minstreth register
read_csr_as_usize_rv32!(0xB82, __read_minstreth);

View File

@ -0,0 +1,73 @@
//! mip register
use bit_field::BitField;
/// mip register
#[derive(Clone, Copy, Debug)]
pub struct Mip {
bits: usize,
}
impl Mip {
/// 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)
}
/// Machine Software Interrupt Pending
#[inline]
pub fn msoft(&self) -> bool {
self.bits.get_bit(3)
}
/// 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)
}
/// Machine Timer Interrupt Pending
#[inline]
pub fn mtimer(&self) -> bool {
self.bits.get_bit(7)
}
/// 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)
}
/// Machine External Interrupt Pending
#[inline]
pub fn mext(&self) -> bool {
self.bits.get_bit(11)
}
}
read_csr_as!(Mip, 0x344, __read_mip);

View File

@ -0,0 +1,60 @@
//! misa register
use core::num::NonZeroUsize;
/// misa register
#[derive(Clone, Copy, Debug)]
pub struct Misa {
bits: NonZeroUsize,
}
/// Machine XLEN
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum MXL {
XLEN32,
XLEN64,
XLEN128,
}
impl Misa {
/// Returns the contents of the register as raw bits
pub fn bits(&self) -> usize {
self.bits.get()
}
/// Returns the machine xlen.
pub fn mxl(&self) -> MXL {
let value = match () {
#[cfg(target_pointer_width = "32")]
() => (self.bits() >> 30) as u8,
#[cfg(target_pointer_width = "64")]
() => (self.bits() >> 62) as u8,
};
match value {
1 => MXL::XLEN32,
2 => MXL::XLEN64,
3 => MXL::XLEN128,
_ => unreachable!(),
}
}
/// Returns true when the atomic extension is implemented.
pub fn has_extension(&self, extension: char) -> bool {
let bit = extension as u8 - 65;
if bit > 25 {
return false;
}
self.bits() & (1 << bit) == (1 << bit)
}
}
read_csr!(0x301, __read_misa);
/// Reads the CSR
#[inline]
pub fn read() -> Option<Misa> {
let r = unsafe{ _read() };
// When misa is hardwired to zero it means that the misa csr
// isn't implemented.
NonZeroUsize::new(r).map(|bits| Misa { bits })
}

View File

@ -0,0 +1,109 @@
//! RISC-V CSR's
//!
//! The following registers are not available on 64-bit implementations.
//!
//! - cycleh
//! - timeh
//! - instreth
//! - hpmcounter[3-31]h
//! - mcycleh
//! - minstreth
//! - mhpmcounter[3-31]h
#[macro_use]
mod macros;
// User Trap Setup
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
pub mod fcsr;
// User Counter/Timers
// TODO: cycle[h], instret[h]
pub mod time;
mod hpmcounterx;
pub use self::hpmcounterx::*;
pub mod timeh;
// Supervisor Trap Setup
// TODO: sedeleg, sideleg
pub mod sstatus;
pub mod sie;
pub mod stvec;
// TODO: scounteren
// Supervisor Trap Handling
pub mod sscratch;
pub mod sepc;
pub mod scause;
pub mod stval;
pub mod sip;
// Supervisor Protection and Translation
pub mod satp;
// Machine Information Registers
pub mod mvendorid;
pub mod marchid;
pub mod mimpid;
pub mod mhartid;
// Machine Trap Setup
pub mod mstatus;
pub mod misa;
// TODO: medeleg, mideleg
pub mod mie;
pub mod mtvec;
// TODO: mcounteren
// Machine Trap Handling
pub mod mscratch;
pub mod mepc;
pub mod mcause;
pub mod mtval;
pub mod mip;
// Machine Protection and Translation
mod pmpcfgx;
pub use self::pmpcfgx::*;
mod pmpaddrx;
pub use self::pmpaddrx::*;
// Machine Counter/Timers
pub mod mcycle;
pub mod minstret;
mod mhpmcounterx;
pub use self::mhpmcounterx::*;
pub mod mcycleh;
pub mod minstreth;
// Machine Counter Setup
mod mhpmeventx;
pub use self::mhpmeventx::*;
// TODO: Debug/Trace Registers (shared with Debug Mode)
// TODO: Debug Mode Registers

View File

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

View File

@ -0,0 +1,200 @@
//! mstatus register
// TODO: Virtualization, Memory Privilege and Extension Context Fields
use bit_field::BitField;
use core::mem::size_of;
/// mstatus register
#[derive(Clone, Copy, Debug)]
pub struct Mstatus {
bits: usize,
}
/// Additional extension state
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum XS {
/// All off
AllOff = 0,
/// None dirty or clean, some on
NoneDirtyOrClean = 1,
/// None dirty, some clean
NoneDirtySomeClean = 2,
/// Some dirty
SomeDirty = 3,
}
/// Floating-point extension state
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum FS {
Off = 0,
Initial = 1,
Clean = 2,
Dirty = 3,
}
/// Machine Previous Privilege Mode
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum MPP {
Machine = 3,
Supervisor = 1,
User = 0,
}
/// Supervisor Previous Privilege Mode
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum SPP {
Supervisor = 1,
User = 0,
}
impl Mstatus {
/// 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)
}
/// Machine Interrupt Enable
#[inline]
pub fn mie(&self) -> bool {
self.bits.get_bit(3)
}
/// 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)
}
/// Machine Previous Interrupt Enable
#[inline]
pub fn mpie(&self) -> bool {
self.bits.get_bit(7)
}
/// Supervisor Previous Privilege Mode
#[inline]
pub fn spp(&self) -> SPP {
match self.bits.get_bit(8) {
true => SPP::Supervisor,
false => SPP::User,
}
}
/// Machine Previous Privilege Mode
#[inline]
pub fn mpp(&self) -> MPP {
match self.bits.get_bits(11..13) {
0b00 => MPP::User,
0b01 => MPP::Supervisor,
0b11 => MPP::Machine,
_ => unreachable!(),
}
}
/// 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!(Mstatus, 0x300, __read_mstatus);
write_csr!(0x300, __write_mstatus);
set!(0x300, __set_mstatus);
clear!(0x300, __clear_mstatus);
set_clear_csr!(
/// User Interrupt Enable
, set_uie, clear_uie, 1 << 0);
set_clear_csr!(
/// Supervisor Interrupt Enable
, set_sie, clear_sie, 1 << 1);
set_clear_csr!(
/// Machine Interrupt Enable
, set_mie, clear_mie, 1 << 3);
set_csr!(
/// User Previous Interrupt Enable
, set_upie, 1 << 4);
set_csr!(
/// Supervisor Previous Interrupt Enable
, set_spie, 1 << 5);
set_csr!(
/// Machine Previous Interrupt Enable
, set_mpie, 1 << 7);
/// Supervisor Previous Privilege Mode
#[inline]
pub unsafe fn set_spp(spp: SPP) {
match spp {
SPP::Supervisor => _set(1 << 8),
SPP::User => _clear(1 << 8),
}
}
/// Machine Previous Privilege Mode
#[inline]
pub unsafe fn set_mpp(mpp: MPP) {
let mut value = _read();
value.set_bits(11..13, mpp as usize);
_write(value);
}
/// Floating-point extension state
#[inline]
pub unsafe fn set_fs(fs: FS) {
let mut value = _read();
value.set_bits(13..15, fs as usize);
_write(value);
}

View File

@ -0,0 +1,3 @@
//! mtval register
read_csr_as_usize!(0x343, __read_mtval);

View File

@ -0,0 +1,47 @@
//! mtvec register
/// mtvec register
#[derive(Clone, Copy, Debug)]
pub struct Mtvec {
bits: usize,
}
/// Trap mode
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum TrapMode {
Direct = 0,
Vectored = 1,
}
impl Mtvec {
/// 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!(Mtvec, 0x305, __read_mtvec);
write_csr!(0x305, __write_mtvec);
/// Writes the CSR
#[inline]
pub unsafe fn write(addr: usize, mode: TrapMode) {
let bits = addr + mode as usize;
_write(bits);
}

View File

@ -0,0 +1,32 @@
//! mvendorid register
use core::num::NonZeroUsize;
/// mvendorid register
#[derive(Clone, Copy, Debug)]
pub struct Mvendorid {
bits: NonZeroUsize,
}
impl Mvendorid {
/// Returns the contents of the register as raw bits
pub fn bits(&self) -> usize {
self.bits.get()
}
/// Returns the JEDEC manufacturer ID
pub fn jedec_manufacturer(&self) -> usize {
self.bits() >> 7
}
}
read_csr!(0xF11, __read_mvendorid);
/// Reads the CSR
#[inline]
pub fn read() -> Option<Mvendorid> {
let r = unsafe{ _read() };
// When mvendorid is hardwired to zero it means that the mvendorid
// csr isn't implemented.
NonZeroUsize::new(r).map(|bits| Mvendorid { bits })
}

View File

@ -0,0 +1,28 @@
macro_rules! reg {
(
$addr:expr, $csr:ident, $readf:ident, $writef:ident
) => {
/// Physical memory protection address register
pub mod $csr {
read_csr_as_usize!($addr, $readf);
write_csr_as_usize!($addr, $writef);
}
}
}
reg!(0x3B0, pmpaddr0, __read_pmpaddr0, __write_pmpaddr0);
reg!(0x3B1, pmpaddr1, __read_pmpaddr1, __write_pmpaddr1);
reg!(0x3B2, pmpaddr2, __read_pmpaddr2, __write_pmpaddr2);
reg!(0x3B3, pmpaddr3, __read_pmpaddr3, __write_pmpaddr3);
reg!(0x3B4, pmpaddr4, __read_pmpaddr4, __write_pmpaddr4);
reg!(0x3B5, pmpaddr5, __read_pmpaddr5, __write_pmpaddr5);
reg!(0x3B6, pmpaddr6, __read_pmpaddr6, __write_pmpaddr6);
reg!(0x3B7, pmpaddr7, __read_pmpaddr7, __write_pmpaddr7);
reg!(0x3B8, pmpaddr8, __read_pmpaddr8, __write_pmpaddr8);
reg!(0x3B9, pmpaddr9, __read_pmpaddr9, __write_pmpaddr9);
reg!(0x3BA, pmpaddr10, __read_pmpaddr10, __write_pmpaddr10);
reg!(0x3BB, pmpaddr11, __read_pmpaddr11, __write_pmpaddr11);
reg!(0x3BC, pmpaddr12, __read_pmpaddr12, __write_pmpaddr12);
reg!(0x3BD, pmpaddr13, __read_pmpaddr13, __write_pmpaddr13);
reg!(0x3BE, pmpaddr14, __read_pmpaddr14, __write_pmpaddr14);
reg!(0x3BF, pmpaddr15, __read_pmpaddr15, __write_pmpaddr15);

View File

@ -0,0 +1,23 @@
/// Physical memory protection configuration
pub mod pmpcfg0 {
read_csr_as_usize!(0x3A0, __read_pmpcfg0);
write_csr_as_usize!(0x3A0, __write_pmpcfg0);
}
/// Physical memory protection configuration, RV32 only
pub mod pmpcfg1 {
read_csr_as_usize_rv32!(0x3A1, __read_pmpcfg1);
write_csr_as_usize_rv32!(0x3A1, __write_pmpcfg1);
}
/// Physical memory protection configuration
pub mod pmpcfg2 {
read_csr_as_usize!(0x3A2, __read_pmpcfg2);
write_csr_as_usize!(0x3A2, __write_pmpcfg2);
}
/// Physical memory protection configuration, RV32 only
pub mod pmpcfg3 {
read_csr_as_usize_rv32!(0x3A3, __read_pmpcfg3);
write_csr_as_usize_rv32!(0x3A3, __write_pmpcfg3);
}

View File

@ -0,0 +1,110 @@
//! satp register
#[cfg(riscv)]
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(riscv32)]
pub fn mode(&self) -> Mode {
match self.bits.get_bit(31) {
false => Mode::Bare,
true => Mode::Sv32,
}
}
/// Current address-translation scheme
#[inline]
#[cfg(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(riscv32)]
pub fn asid(&self) -> usize {
self.bits.get_bits(22..31)
}
/// Address space identifier
#[inline]
#[cfg(riscv64)]
pub fn asid(&self) -> usize {
self.bits.get_bits(44..60)
}
/// Physical page number
#[inline]
#[cfg(riscv32)]
pub fn ppn(&self) -> usize {
self.bits.get_bits(0..22)
}
/// Physical page number
#[inline]
#[cfg(riscv64)]
pub fn ppn(&self) -> usize {
self.bits.get_bits(0..44)
}
}
#[cfg(riscv32)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Mode {
Bare = 0,
Sv32 = 1,
}
#[cfg(riscv64)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Mode {
Bare = 0,
Sv39 = 8,
Sv48 = 9,
Sv57 = 10,
Sv64 = 11,
}
read_csr_as!(Satp, 0x180, __read_satp);
write_csr!(0x180, __write_satp);
#[inline]
#[cfg(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(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);
}

View File

@ -0,0 +1,117 @@
//! 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, 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]
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, __read_scause);

View File

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

View File

@ -0,0 +1,76 @@
//! 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, __read_sie);
set!(0x104, __set_sie);
clear!(0x104, __clear_sie);
set_clear_csr!(
/// User Software Interrupt Enable
, set_usoft, clear_usoft, 1 << 0);
set_clear_csr!(
/// Supervisor Software Interrupt Enable
, set_ssoft, clear_ssoft, 1 << 1);
set_clear_csr!(
/// User Timer Interrupt Enable
, set_utimer, clear_utimer, 1 << 4);
set_clear_csr!(
/// Supervisor Timer Interrupt Enable
, set_stimer, clear_stimer, 1 << 5);
set_clear_csr!(
/// User External Interrupt Enable
, set_uext, clear_uext, 1 << 8);
set_clear_csr!(
/// Supervisor External Interrupt Enable
, set_sext, clear_sext, 1 << 9);

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, __read_sip);

View File

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

View File

@ -0,0 +1,140 @@
//! sstatus register
use bit_field::BitField;
use core::mem::size_of;
pub use super::mstatus::FS;
/// Supervisor Status Register
#[derive(Clone, Copy, Debug)]
pub struct Sstatus {
bits: usize,
}
/// Supervisor Previous Privilege Mode
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum SPP {
Supervisor = 1,
User = 0,
}
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, __read_sstatus);
write_csr!(0x100, __write_sstatus);
set!(0x100, __set_sstatus);
clear!(0x100, __clear_sstatus);
set_clear_csr!(
/// User Interrupt Enable
, set_uie, clear_uie, 1 << 0);
set_clear_csr!(
/// Supervisor Interrupt Enable
, set_sie, clear_sie, 1 << 1);
set_csr!(
/// User Previous Interrupt Enable
, set_upie, 1 << 4);
set_csr!(
/// Supervisor Previous Interrupt Enable
, set_spie, 1 << 5);
set_clear_csr!(
/// Make eXecutable Readable
, set_mxr, clear_mxr, 1 << 19);
set_clear_csr!(
/// Permit Supervisor User Memory access
, set_sum, clear_sum, 1 << 18);
/// Supervisor Previous Privilege Mode
#[inline]
#[cfg(riscv)]
pub unsafe fn set_spp(spp: SPP) {
match spp {
SPP::Supervisor => _set(1 << 8),
SPP::User => _clear(1 << 8),
}
}
/// The status of the floating-point unit
#[inline]
#[cfg(riscv)]
pub unsafe fn set_fs(fs: FS) {
let mut value = _read();
value.set_bits(13..15, fs as usize);
_write(value);
}

View File

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

View File

@ -0,0 +1,40 @@
//! stvec register
pub use crate::register::mtvec::TrapMode;
/// stvec register
#[derive(Clone, Copy, Debug)]
pub struct Stvec {
bits: usize,
}
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, __read_stvec);
write_csr!(0x105, __write_stvec);
/// Writes the CSR
#[inline]
pub unsafe fn write(addr: usize, mode: TrapMode) {
_write(addr + mode as usize);
}

View File

@ -0,0 +1,4 @@
//! time register
read_csr_as_usize!(0xC01, __read_time);
read_composite_csr!(super::timeh::read(), read());

View File

@ -0,0 +1,3 @@
//! timeh register
read_csr_as_usize_rv32!(0xC81, __read_timeh);

View File

@ -0,0 +1,17 @@
//! ucause register
/// 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
}
}
read_csr_as!(Ucause, 0x042, __read_ucause);

View File

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

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_uie);
set!(0x004, __set_uie);
clear!(0x004, __clear_uie);
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);

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

View File

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

View File

@ -0,0 +1,37 @@
//! ustatus register
// TODO: Virtualization, Memory Privilege and Extension Context Fields
use bit_field::BitField;
/// ustatus 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)
}
}
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);

View File

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

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_utvec);
write_csr!(0x005, __write_utvec);
/// Writes the CSR
#[inline]
pub unsafe fn write(addr: usize, mode: TrapMode) {
_write(addr + mode as usize);
}