New api.
This commit is contained in:
parent
179df42984
commit
7db0e71060
|
@ -9,5 +9,4 @@ keywords = ["riscv", "register", "peripheral"]
|
||||||
license = "ISC"
|
license = "ISC"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bare-metal = "^0.1.1"
|
bare-metal = "0.1.1"
|
||||||
volatile-register = "^0.2.0"
|
|
79
README.md
79
README.md
|
@ -2,6 +2,85 @@
|
||||||
|
|
||||||
> Low level access to RISCV processors
|
> Low level access to RISCV processors
|
||||||
|
|
||||||
|
## Implemented Peripherals
|
||||||
|
- [ ] plic
|
||||||
|
- [ ] clint
|
||||||
|
|
||||||
|
## Implemented privileged ASM instructions
|
||||||
|
- [x] ecall
|
||||||
|
- [x] ebreak
|
||||||
|
- [x] uret
|
||||||
|
- [x] sret
|
||||||
|
- [x] mret
|
||||||
|
- [x] wfi
|
||||||
|
- [ ] sfence.vma
|
||||||
|
|
||||||
|
## Implemented CSR's
|
||||||
|
|
||||||
|
### User mode
|
||||||
|
- [ ] ustatus
|
||||||
|
- [ ] uie
|
||||||
|
- [ ] utvec
|
||||||
|
- [ ] uscratch
|
||||||
|
- [ ] uepc
|
||||||
|
- [ ] ucause
|
||||||
|
- [ ] utval
|
||||||
|
- [ ] uip
|
||||||
|
- [ ] fflags
|
||||||
|
- [ ] frm
|
||||||
|
- [ ] fcsr
|
||||||
|
- [ ] cycle
|
||||||
|
- [ ] time
|
||||||
|
- [ ] instret
|
||||||
|
- [ ] hpmcounter[3-31]
|
||||||
|
- [ ] cycleh
|
||||||
|
- [ ] timeh
|
||||||
|
- [ ] instreth
|
||||||
|
- [ ] hpmcounter[3-31]h
|
||||||
|
|
||||||
|
### Supervisor mode
|
||||||
|
- [ ] sstatus
|
||||||
|
- [ ] sedeleg
|
||||||
|
- [ ] sideleg
|
||||||
|
- [ ] sie
|
||||||
|
- [ ] stvec
|
||||||
|
- [ ] scounteren
|
||||||
|
- [ ] sscratch
|
||||||
|
- [ ] sepc
|
||||||
|
- [ ] scause
|
||||||
|
- [ ] stval
|
||||||
|
- [ ] sip
|
||||||
|
- [ ] satp
|
||||||
|
|
||||||
|
### Machine mode
|
||||||
|
- [x] mvendorid
|
||||||
|
- [ ] marchid
|
||||||
|
- [ ] mimpid
|
||||||
|
- [ ] mhartid
|
||||||
|
- [x] mstatus
|
||||||
|
- [x] misa
|
||||||
|
- [ ] medeleg
|
||||||
|
- [ ] mideleg
|
||||||
|
- [x] mie
|
||||||
|
- [x] mtvec
|
||||||
|
- [ ] mcounteren
|
||||||
|
- [ ] mscratch
|
||||||
|
- [ ] mepc
|
||||||
|
- [x] mcause
|
||||||
|
- [ ] mtval
|
||||||
|
- [x] mip
|
||||||
|
- [ ] pmpcfg[0-3]
|
||||||
|
- [ ] pmpaddr[0-15]
|
||||||
|
- [x] mcycle
|
||||||
|
- [x] minstret
|
||||||
|
- [ ] mhpmcounter[3-31]
|
||||||
|
- [x] mcycleh
|
||||||
|
- [x] minstreth
|
||||||
|
- [ ] mhpmcounter[3-31]h
|
||||||
|
- [ ] mhpmevent[3-31]
|
||||||
|
- [ ] tselect
|
||||||
|
- [ ] tdata[1-3]
|
||||||
|
|
||||||
# License
|
# License
|
||||||
Copyright 2017 David Craven
|
Copyright 2017 David Craven
|
||||||
|
|
||||||
|
|
10
src/asm.rs
10
src/asm.rs
|
@ -17,16 +17,10 @@ macro_rules! instruction {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// User Level ISA instructions
|
/// Priviledged ISA Instructions
|
||||||
instruction!(nop, "addi zero, zero, 0");
|
|
||||||
instruction!(ecall, "ecall");
|
instruction!(ecall, "ecall");
|
||||||
instruction!(ebreak, "ebreak");
|
instruction!(ebreak, "ebreak");
|
||||||
instruction!(fence, "fence iorw, iorw");
|
|
||||||
instruction!(fencei, "fence.i");
|
|
||||||
|
|
||||||
/// Priviledged ISA Instructions
|
|
||||||
instruction!(wfi, "wfi");
|
|
||||||
instruction!(uret, "uret");
|
instruction!(uret, "uret");
|
||||||
instruction!(sret, "sret");
|
instruction!(sret, "sret");
|
||||||
instruction!(mret, "mret");
|
instruction!(mret, "mret");
|
||||||
instruction!(sfencevma, "sfence.vma");
|
instruction!(wfi, "wfi");
|
||||||
|
|
606
src/csr.rs
606
src/csr.rs
|
@ -1,606 +0,0 @@
|
||||||
//! Functions for accessing Control and Status Registers
|
|
||||||
|
|
||||||
#[cfg(target_arch = "riscv")]
|
|
||||||
macro_rules! csr_asm {
|
|
||||||
($op:ident, $csr:expr, $value:expr) => (
|
|
||||||
{
|
|
||||||
let res: usize;
|
|
||||||
unsafe {
|
|
||||||
asm!(concat!(stringify!($op), " $0, ", stringify!($csr), ", $1")
|
|
||||||
: "=r"(res)
|
|
||||||
: "r"($value)
|
|
||||||
:
|
|
||||||
: "volatile");
|
|
||||||
}
|
|
||||||
res
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "riscv"))]
|
|
||||||
macro_rules! csr_asm {
|
|
||||||
($op:ident, $csr:expr, $value:expr) => {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! r {
|
|
||||||
($MOD:ident, $TYPE:ident, $CSR:expr) => (
|
|
||||||
pub struct R {
|
|
||||||
bits: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl super::$TYPE {
|
|
||||||
#[inline]
|
|
||||||
pub fn read(&self) -> R {
|
|
||||||
R { bits: csr_asm!(csrrs, $CSR, 0) as u32 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl R {
|
|
||||||
#[inline]
|
|
||||||
pub fn bits(&self) -> u32 {
|
|
||||||
self.bits
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! w {
|
|
||||||
($MOD:ident, $TYPE:ident, $CSR:expr) => (
|
|
||||||
macro_rules! func {
|
|
||||||
($fnname:ident, $csrop:ident) => (
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn $fnname<F>(&self, f: F)
|
|
||||||
where
|
|
||||||
F: FnOnce(&mut W) -> &mut W,
|
|
||||||
{
|
|
||||||
let mut w = W { bits: 0 };
|
|
||||||
f(&mut w);
|
|
||||||
csr_asm!($csrop, $CSR, w.bits as usize);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct W {
|
|
||||||
bits: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl super::$TYPE {
|
|
||||||
func!(write, csrrw);
|
|
||||||
func!(set, csrrs);
|
|
||||||
func!(clear, csrrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl W {
|
|
||||||
#[inline]
|
|
||||||
pub fn bits(&mut self, value: u32) -> &mut W {
|
|
||||||
self.bits = value;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
pub fn set_bits(&mut self, value: u32) -> &mut W {
|
|
||||||
self.bits |= value;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
pub fn clear_bits(&mut self, value: u32) -> &mut W {
|
|
||||||
self.bits &= !value;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! rw {
|
|
||||||
($MOD:ident, $TYPE:ident, $CSR:expr) => (
|
|
||||||
r!($MOD, $TYPE, $CSR);
|
|
||||||
w!($MOD, $TYPE, $CSR);
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! csr {
|
|
||||||
($MOD:ident, $TYPE:ident, $CSR:expr, $MACRO:ident) => (
|
|
||||||
pub struct $TYPE {}
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
pub const $MOD: $TYPE = $TYPE {};
|
|
||||||
|
|
||||||
pub mod $MOD {
|
|
||||||
$MACRO!($MOD, $TYPE, $CSR);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// User Trap Setup
|
|
||||||
csr!(ustatus, USTATUS, 0x000, rw);
|
|
||||||
csr!(uie, UIE, 0x004, rw);
|
|
||||||
csr!(utvec, UTVEC, 0x005, rw);
|
|
||||||
/// User Trap Handling
|
|
||||||
csr!(uscratch, USCRATCH, 0x040, rw);
|
|
||||||
csr!(uepc, UEPC, 0x041, rw);
|
|
||||||
csr!(ucause, UCAUSE, 0x042, rw);
|
|
||||||
csr!(utval, UTVAL, 0x043, rw);
|
|
||||||
csr!(uip, UIP, 0x044, r);
|
|
||||||
/// User Floating-Point CSRs
|
|
||||||
csr!(fflags, FFLAGS, 0x001, rw);
|
|
||||||
csr!(frm, FRM, 0x002, rw);
|
|
||||||
csr!(fcsr, FCSR, 0x003, rw);
|
|
||||||
/// User Counter/Timers
|
|
||||||
csr!(cycle, CYCLE, 0xC00, rw);
|
|
||||||
csr!(time, TIME, 0xC01, rw);
|
|
||||||
csr!(instret, INSTRET, 0xC02, rw);
|
|
||||||
// TODO: hpmcounter3 - hpmcounter31
|
|
||||||
csr!(cycleh, CYCLEH, 0xC80, rw);
|
|
||||||
csr!(timeh, TIMEH, 0xC81, rw);
|
|
||||||
csr!(instreth, INSTRETH, 0xC82, rw);
|
|
||||||
// TODO: hpmcounter3h - hpmcounter31h
|
|
||||||
|
|
||||||
/// Supervisor Trap Setup
|
|
||||||
csr!(sstatus, SSTATUS, 0x100, rw);
|
|
||||||
csr!(sedeleg, SEDELEG, 0x102, rw);
|
|
||||||
csr!(sideleg, SIDELEG, 0x103, rw);
|
|
||||||
csr!(sie, SIE, 0x104, rw);
|
|
||||||
csr!(stvec, STVEC, 0x105, rw);
|
|
||||||
csr!(scounteren, SCOUNTEREN, 0x106, rw);
|
|
||||||
/// Supervisor Trap Handling
|
|
||||||
csr!(sscratch, SSCRATCH, 0x140, rw);
|
|
||||||
csr!(sepc, SEPC, 0x141, rw);
|
|
||||||
csr!(scause, SCAUSE, 0x142, rw);
|
|
||||||
csr!(stval, STVAL, 0x143, rw);
|
|
||||||
csr!(sip, SIP, 0x144, r);
|
|
||||||
/// Supervisor Protection and Translation
|
|
||||||
csr!(satp, SATP, 0x180, rw);
|
|
||||||
|
|
||||||
/// Machine Information Registers
|
|
||||||
csr!(mvendorid, MVENDORID, 0xF11, r);
|
|
||||||
csr!(marchid, MARCHID, 0xF12, r);
|
|
||||||
csr!(mimpid, MIMPID, 0xF13, r);
|
|
||||||
csr!(mhartid, MHARTID, 0xF14, r);
|
|
||||||
/// Machine Trap Setup
|
|
||||||
csr!(mstatus, MSTATUS, 0x300, rw);
|
|
||||||
csr!(misa, MISA, 0x301, r);
|
|
||||||
csr!(medeleg, MEDELEG, 0x302, rw);
|
|
||||||
csr!(mideleg, MIDELEG, 0x303, rw);
|
|
||||||
csr!(mie, MIE, 0x304, rw);
|
|
||||||
csr!(mtvec, MTVEC, 0x305, rw);
|
|
||||||
csr!(mcounteren, MCOUNTEREN, 0x306, rw);
|
|
||||||
/// Machine Trap Handling
|
|
||||||
csr!(mscratch, MSCRATCH, 0x340, rw);
|
|
||||||
csr!(mepc, MEPC, 0x341, rw);
|
|
||||||
csr!(mcause, MCAUSE, 0x342, r);
|
|
||||||
csr!(mtval, MTVAL, 0x343, rw);
|
|
||||||
csr!(mip, MIP, 0x344, r);
|
|
||||||
/// Machine Protection and Translation
|
|
||||||
csr!(pmpcfg0, PMPCFG0, 0x3A0, rw);
|
|
||||||
csr!(pmpcfg1, PMPCFG1, 0x3A1, rw);
|
|
||||||
csr!(pmpcfg2, PMPCFG2, 0x3A2, rw);
|
|
||||||
csr!(pmpcfg3, PMPCFG3, 0x3A3, rw);
|
|
||||||
// TODO pmpaddr0 - pmpaddr15
|
|
||||||
|
|
||||||
/// Machine Counter/Timers
|
|
||||||
csr!(mcycle, MCYCLE, 0xB00, rw);
|
|
||||||
csr!(minstret, MINSTRET, 0xB02, rw);
|
|
||||||
// TODO mhpmcounter3 .. mhpmcounter31
|
|
||||||
csr!(mcycleh, MCYCLEH, 0xB80, rw);
|
|
||||||
csr!(minstreth, MINSTRETH, 0xB82, rw);
|
|
||||||
// TODO mhpmcounter3h .. mhpmcounter31h
|
|
||||||
/// Machine Counter Setup
|
|
||||||
// TODO mhpmevent3 .. mhpmevent31
|
|
||||||
|
|
||||||
/// Debug/Trace Registers (shared with Debug Mode)
|
|
||||||
csr!(tselect, TSELECT, 0x7A0, rw);
|
|
||||||
csr!(tdata1, TDATA1, 0x7A1, rw);
|
|
||||||
csr!(tdata2, TDATA2, 0x7A2, rw);
|
|
||||||
csr!(tdata3, TDATA3, 0x7A3, rw);
|
|
||||||
/// Debug Mode Registers
|
|
||||||
csr!(dcsr, DCSR, 0x7B0, rw);
|
|
||||||
csr!(dpc, DPC, 0x7B1, rw);
|
|
||||||
csr!(dscratch, DSCRATCH, 0x7B2, rw);
|
|
||||||
|
|
||||||
/// Machine Cause CSR (mcause) is ReadOnly.
|
|
||||||
/// Trap Cause
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub enum Trap {
|
|
||||||
Interrupt(Interrupt),
|
|
||||||
Exception(Exception),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Interrupt
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub enum Interrupt {
|
|
||||||
UserSoft,
|
|
||||||
SupervisorSoft,
|
|
||||||
MachineSoft,
|
|
||||||
UserTimer,
|
|
||||||
SupervisorTimer,
|
|
||||||
MachineTimer,
|
|
||||||
UserExternal,
|
|
||||||
SupervisorExternal,
|
|
||||||
MachineExternal,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Interrupt {
|
|
||||||
pub fn from(nr: u32) -> 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,
|
|
||||||
_ => unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Exception
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub enum Exception {
|
|
||||||
InstructionMisaligned,
|
|
||||||
InstructionFault,
|
|
||||||
IllegalInstruction,
|
|
||||||
Breakpoint,
|
|
||||||
LoadMisaligned,
|
|
||||||
LoadFault,
|
|
||||||
StoreMisaligned,
|
|
||||||
StoreFault,
|
|
||||||
UserEnvCall,
|
|
||||||
SupervisorEnvCall,
|
|
||||||
MachineEnvCall,
|
|
||||||
InstructionPageFault,
|
|
||||||
LoadPageFault,
|
|
||||||
StorePageFault,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Exception {
|
|
||||||
pub fn from(nr: u32) -> 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,
|
|
||||||
_ => unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl mcause::R {
|
|
||||||
#[inline]
|
|
||||||
/// Trap Cause
|
|
||||||
pub fn cause(&self) -> Trap {
|
|
||||||
let bits = self.bits();
|
|
||||||
let code = bits & !(1 << 31);
|
|
||||||
match bits & (1 << 31) == 1 << 31 {
|
|
||||||
true => Trap::Interrupt(Interrupt::from(code)),
|
|
||||||
false => Trap::Exception(Exception::from(code)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Is trap cause an interrupt.
|
|
||||||
pub fn is_interrupt(&self) -> bool {
|
|
||||||
match self.cause() {
|
|
||||||
Trap::Interrupt(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Is trap cause an exception.
|
|
||||||
pub fn is_exception(&self) -> bool {
|
|
||||||
match self.cause() {
|
|
||||||
Trap::Exception(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Machine Status CSR is ReadWrite
|
|
||||||
// TODO: Virtualization, Memory Privilege and Extension Context Fields
|
|
||||||
|
|
||||||
/// Machine Previous Privilege Mode
|
|
||||||
pub enum MPP {
|
|
||||||
Machine = 3,
|
|
||||||
Supervisor = 1,
|
|
||||||
User = 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Supervisor Previous Privilege Mode
|
|
||||||
pub enum SPP {
|
|
||||||
Supervisor = 1,
|
|
||||||
User = 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl mstatus::R {
|
|
||||||
#[inline]
|
|
||||||
/// User Interrupt Enable
|
|
||||||
pub fn uie(&self) -> bool {
|
|
||||||
self.bits() & (1 << 0) == 1 << 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Supervisor Interrupt Enable
|
|
||||||
pub fn sie(&self) -> bool {
|
|
||||||
self.bits() & (1 << 1) == 1 << 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Machine Interrupt Enable
|
|
||||||
pub fn mie(&self) -> bool {
|
|
||||||
self.bits() & (1 << 3) == 1 << 3
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// User Previous Interrupt Enable
|
|
||||||
pub fn upie(&self) -> bool {
|
|
||||||
self.bits() & (1 << 4) == 1 << 4
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Supervisor Previous Interrupt Enable
|
|
||||||
pub fn spie(&self) -> bool {
|
|
||||||
self.bits() & (1 << 5) == 1 << 5
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// User Previous Interrupt Enable
|
|
||||||
pub fn mpie(&self) -> bool {
|
|
||||||
self.bits() & (1 << 7) == 1 << 7
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Supervisor Previous Privilege Mode
|
|
||||||
pub fn spp(&self) -> SPP {
|
|
||||||
match self.bits() & (1 << 8) == (1 << 8) {
|
|
||||||
true => SPP::Supervisor,
|
|
||||||
false => SPP::User,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Machine Previous Privilege Mode
|
|
||||||
pub fn mpp(&self) -> MPP {
|
|
||||||
match (self.bits() & (0b11 << 11)) >> 11 {
|
|
||||||
0b00 => MPP::User,
|
|
||||||
0b01 => MPP::Supervisor,
|
|
||||||
0b11 => MPP::Machine,
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl mstatus::W {
|
|
||||||
#[inline]
|
|
||||||
/// User Interrupt Enable
|
|
||||||
pub fn uie(&mut self) -> &mut mstatus::W {
|
|
||||||
self.set_bits(1 << 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Supervisor Interrupt Enable
|
|
||||||
pub fn sie(&mut self) -> &mut mstatus::W {
|
|
||||||
self.set_bits(1 << 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Machine Interrupt Enable
|
|
||||||
pub fn mie(&mut self) -> &mut mstatus::W {
|
|
||||||
self.set_bits(1 << 3)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// User Previous Interrupt Enable
|
|
||||||
pub fn upie(&mut self) -> &mut mstatus::W {
|
|
||||||
self.set_bits(1 << 4)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// User Previous Interrupt Enable
|
|
||||||
pub fn spie(&mut self) -> &mut mstatus::W {
|
|
||||||
self.set_bits(1 << 5)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// User Previous Interrupt Enable
|
|
||||||
pub fn mpie(&mut self) -> &mut mstatus::W {
|
|
||||||
self.set_bits(1 << 7)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Supervisor Previous Privilege Mode
|
|
||||||
pub fn spp(&mut self, value: SPP) -> &mut mstatus::W {
|
|
||||||
self.set_bits((value as u32) << 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Machine Previous Privilege Mode
|
|
||||||
pub fn mpp(&mut self, value: MPP) -> &mut mstatus::W {
|
|
||||||
self.set_bits((value as u32) << 11)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Machine Interrupt Enable CSR (mie) is ReadWrite.
|
|
||||||
impl mie::R {
|
|
||||||
#[inline]
|
|
||||||
/// User Software Interrupt Enable
|
|
||||||
pub fn usoft(&self) -> bool {
|
|
||||||
self.bits() & (1 << 0) == 1 << 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Supervisor Software Interrupt Enable
|
|
||||||
pub fn ssoft(&self) -> bool {
|
|
||||||
self.bits() & (1 << 1) == 1 << 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Machine Software Interrupt Enable
|
|
||||||
pub fn msoft(&self) -> bool {
|
|
||||||
self.bits() & (1 << 3) == 1 << 3
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// User Timer Interrupt Enable
|
|
||||||
pub fn utimer(&self) -> bool {
|
|
||||||
self.bits() & (1 << 4) == 1 << 4
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Supervisor Timer Interrupt Enable
|
|
||||||
pub fn stimer(&self) -> bool {
|
|
||||||
self.bits() & (1 << 5) == 1 << 5
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Machine Timer Interrupt Enable
|
|
||||||
pub fn mtimer(&self) -> bool {
|
|
||||||
self.bits() & (1 << 7) == 1 << 7
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// User External Interrupt Enable
|
|
||||||
pub fn uext(&self) -> bool {
|
|
||||||
self.bits() & (1 << 8) == 1 << 8
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Supervisor External Interrupt Enable
|
|
||||||
pub fn sext(&self) -> bool {
|
|
||||||
self.bits() & (1 << 9) == 1 << 9
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Machine External Interrupt Enable
|
|
||||||
pub fn mext(&self) -> bool {
|
|
||||||
self.bits() & (1 << 11) == 1 << 11
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl mie::W {
|
|
||||||
#[inline]
|
|
||||||
/// User Software Interrupt Enable
|
|
||||||
pub fn usoft(&mut self) -> &mut mie::W {
|
|
||||||
self.set_bits(1 << 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Supervisor Software Interrupt Enable
|
|
||||||
pub fn ssoft(&mut self) -> &mut mie::W {
|
|
||||||
self.set_bits(1 << 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Machine Software Interrupt Enable
|
|
||||||
pub fn msoft(&mut self) -> &mut mie::W {
|
|
||||||
self.set_bits(1 << 3)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// User Timer Interrupt Enable
|
|
||||||
pub fn utimer(&mut self) -> &mut mie::W {
|
|
||||||
self.set_bits(1 << 4)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Supervisor Timer Interrupt Enable
|
|
||||||
pub fn stimer(&mut self) -> &mut mie::W {
|
|
||||||
self.set_bits(1 << 5)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Machine Timer Interrupt Enable
|
|
||||||
pub fn mtimer(&mut self) -> &mut mie::W {
|
|
||||||
self.set_bits(1 << 7)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// User External Interrupt Enable
|
|
||||||
pub fn uext(&mut self) -> &mut mie::W {
|
|
||||||
self.set_bits(1 << 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Supervisor External Interrupt Enable
|
|
||||||
pub fn sext(&mut self) -> &mut mie::W {
|
|
||||||
self.set_bits(1 << 9)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Machine External Interrupt Enable
|
|
||||||
pub fn mext(&mut self) -> &mut mie::W {
|
|
||||||
self.set_bits(1 << 11)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Machine Interrupt Pending CSR (mip) is ReadOnly.
|
|
||||||
impl mip::R {
|
|
||||||
#[inline]
|
|
||||||
/// User Software Interrupt Enable
|
|
||||||
pub fn usoft(&self) -> bool {
|
|
||||||
self.bits() & (1 << 0) == 1 << 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Supervisor Software Interrupt Enable
|
|
||||||
pub fn ssoft(&self) -> bool {
|
|
||||||
self.bits() & (1 << 1) == 1 << 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Machine Software Interrupt Enable
|
|
||||||
pub fn msoft(&self) -> bool {
|
|
||||||
self.bits() & (1 << 3) == 1 << 3
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// User Timer Interrupt Enable
|
|
||||||
pub fn utimer(&self) -> bool {
|
|
||||||
self.bits() & (1 << 4) == 1 << 4
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Supervisor Timer Interrupt Enable
|
|
||||||
pub fn stimer(&self) -> bool {
|
|
||||||
self.bits() & (1 << 5) == 1 << 5
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Machine Timer Interrupt Enable
|
|
||||||
pub fn mtimer(&self) -> bool {
|
|
||||||
self.bits() & (1 << 7) == 1 << 7
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// User External Interrupt Enable
|
|
||||||
pub fn uext(&self) -> bool {
|
|
||||||
self.bits() & (1 << 8) == 1 << 8
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Supervisor External Interrupt Enable
|
|
||||||
pub fn sext(&self) -> bool {
|
|
||||||
self.bits() & (1 << 9) == 1 << 9
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Machine External Interrupt Enable
|
|
||||||
pub fn mext(&self) -> bool {
|
|
||||||
self.bits() & (1 << 11) == 1 << 11
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,13 +2,14 @@
|
||||||
|
|
||||||
// NOTE: Adapted from cortex-m/src/interrupt.rs
|
// NOTE: Adapted from cortex-m/src/interrupt.rs
|
||||||
pub use bare_metal::{CriticalSection, Mutex, Nr};
|
pub use bare_metal::{CriticalSection, Mutex, Nr};
|
||||||
|
use register::mstatus;
|
||||||
|
|
||||||
/// Disables all interrupts
|
/// Disables all interrupts
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn disable() {
|
pub unsafe fn disable() {
|
||||||
match () {
|
match () {
|
||||||
#[cfg(target_arch = "riscv")]
|
#[cfg(target_arch = "riscv")]
|
||||||
() => ::csr::mstatus.clear(|w| w.mie()),
|
() => mstatus::clear_mie(),
|
||||||
#[cfg(not(target_arch = "riscv"))]
|
#[cfg(not(target_arch = "riscv"))]
|
||||||
() => {}
|
() => {}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +24,7 @@ pub fn disable() {
|
||||||
pub unsafe fn enable() {
|
pub unsafe fn enable() {
|
||||||
match () {
|
match () {
|
||||||
#[cfg(target_arch = "riscv")]
|
#[cfg(target_arch = "riscv")]
|
||||||
() => ::csr::mstatus.set(|w| w.mie()),
|
() => mstatus::set_mie(),
|
||||||
#[cfg(not(target_arch = "riscv"))]
|
#[cfg(not(target_arch = "riscv"))]
|
||||||
() => {}
|
() => {}
|
||||||
}
|
}
|
||||||
|
@ -36,17 +37,17 @@ pub fn free<F, R>(f: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&CriticalSection) -> R,
|
F: FnOnce(&CriticalSection) -> R,
|
||||||
{
|
{
|
||||||
let mstatus = ::csr::mstatus.read();
|
let mstatus = mstatus::read();
|
||||||
|
|
||||||
// disable interrupts
|
// disable interrupts
|
||||||
disable();
|
unsafe { disable(); }
|
||||||
|
|
||||||
let r = f(unsafe { &CriticalSection::new() });
|
let r = f(unsafe { &CriticalSection::new() });
|
||||||
|
|
||||||
// If the interrupts were active before our `disable` call, then re-enable
|
// If the interrupts were active before our `disable` call, then re-enable
|
||||||
// them. Otherwise, keep them disabled
|
// them. Otherwise, keep them disabled
|
||||||
if mstatus.mie() {
|
if mstatus.mie() {
|
||||||
unsafe { enable() }
|
unsafe { enable(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
r
|
r
|
||||||
|
|
|
@ -14,5 +14,5 @@
|
||||||
extern crate bare_metal;
|
extern crate bare_metal;
|
||||||
|
|
||||||
pub mod asm;
|
pub mod asm;
|
||||||
pub mod csr;
|
|
||||||
pub mod interrupt;
|
pub mod interrupt;
|
||||||
|
pub mod register;
|
||||||
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
//! mcause register
|
||||||
|
|
||||||
|
/// mcause register
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Mcause {
|
||||||
|
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,
|
||||||
|
MachineSoft,
|
||||||
|
UserTimer,
|
||||||
|
SupervisorTimer,
|
||||||
|
MachineTimer,
|
||||||
|
UserExternal,
|
||||||
|
SupervisorExternal,
|
||||||
|
MachineExternal,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Exception
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads the CSR
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> Mcause {
|
||||||
|
match () {
|
||||||
|
#[cfg(target_arch = "riscv")]
|
||||||
|
() => {
|
||||||
|
let r: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!("csrrs $0, 0x342, x0" : "=r"(r) ::: "volatile");
|
||||||
|
}
|
||||||
|
Mcause { bits: r }
|
||||||
|
}
|
||||||
|
#[cfg(not(target_arch = "riscv"))]
|
||||||
|
() => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
//! mcycle register
|
||||||
|
|
||||||
|
/// Reads the CSR
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> usize {
|
||||||
|
match () {
|
||||||
|
#[cfg(target_arch = "riscv")]
|
||||||
|
() => {
|
||||||
|
let r: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!("csrrs $0, 0xB00, x0" : "=r"(r) ::: "volatile");
|
||||||
|
}
|
||||||
|
r
|
||||||
|
}
|
||||||
|
#[cfg(not(target_arch = "riscv"))]
|
||||||
|
() => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
//! mcycleh register
|
||||||
|
|
||||||
|
/// Reads the CSR
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> usize {
|
||||||
|
match () {
|
||||||
|
#[cfg(all(target_arch = "riscv", target_pointer_width = "32"))]
|
||||||
|
() => {
|
||||||
|
let r: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!("csrrs $0, 0xB80, x0" : "=r"(r) ::: "volatile");
|
||||||
|
}
|
||||||
|
r
|
||||||
|
}
|
||||||
|
#[cfg(any(not(target_arch = "riscv"), not(target_pointer_width = "32")))]
|
||||||
|
() => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
//! mie register
|
||||||
|
|
||||||
|
/// 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 & (1 << 0) == 1 << 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor Software Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn ssoft(&self) -> bool {
|
||||||
|
self.bits & (1 << 1) == 1 << 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Machine Software Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn msoft(&self) -> bool {
|
||||||
|
self.bits & (1 << 3) == 1 << 3
|
||||||
|
}
|
||||||
|
|
||||||
|
/// User Timer Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn utimer(&self) -> bool {
|
||||||
|
self.bits & (1 << 4) == 1 << 4
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor Timer Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn stimer(&self) -> bool {
|
||||||
|
self.bits & (1 << 5) == 1 << 5
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Machine Timer Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn mtimer(&self) -> bool {
|
||||||
|
self.bits & (1 << 7) == 1 << 7
|
||||||
|
}
|
||||||
|
|
||||||
|
/// User External Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn uext(&self) -> bool {
|
||||||
|
self.bits & (1 << 8) == 1 << 8
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor External Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn sext(&self) -> bool {
|
||||||
|
self.bits & (1 << 9) == 1 << 9
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Machine External Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn mext(&self) -> bool {
|
||||||
|
self.bits & (1 << 11) == 1 << 11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads the CSR
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> Mie {
|
||||||
|
match () {
|
||||||
|
#[cfg(target_arch = "riscv")]
|
||||||
|
() => {
|
||||||
|
let r: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!("csrrs $0, 0x304, x0" : "=r"(r) ::: "volatile");
|
||||||
|
}
|
||||||
|
Mie { bits: r }
|
||||||
|
}
|
||||||
|
#[cfg(not(target_arch = "riscv"))]
|
||||||
|
() => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the CSR
|
||||||
|
#[cfg_attr(not(target_arch = "riscv"), allow(unused_variables))]
|
||||||
|
#[inline]
|
||||||
|
unsafe fn set(bits: usize) {
|
||||||
|
match () {
|
||||||
|
#[cfg(target_arch = "riscv")]
|
||||||
|
() => asm!("csrrs x0, 0x304, $0" :: "r"(bits) :: "volatile"),
|
||||||
|
#[cfg(not(target_arch = "riscv"))]
|
||||||
|
() => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears the CSR
|
||||||
|
#[cfg_attr(not(target_arch = "riscv"), allow(unused_variables))]
|
||||||
|
#[inline]
|
||||||
|
unsafe fn clear(bits: usize) {
|
||||||
|
match () {
|
||||||
|
#[cfg(target_arch = "riscv")]
|
||||||
|
() => asm!("csrrc x0, 0x304, $0" :: "r"(bits) :: "volatile"),
|
||||||
|
#[cfg(not(target_arch = "riscv"))]
|
||||||
|
() => 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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);
|
||||||
|
/// Machine Software Interrupt Enable
|
||||||
|
set_clear_csr!(set_msoft, clear_msoft, 1 << 3);
|
||||||
|
/// 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);
|
||||||
|
/// Machine Timer Interrupt Enable
|
||||||
|
set_clear_csr!(set_mtimer, clear_mtimer, 1 << 7);
|
||||||
|
/// 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);
|
||||||
|
/// Machine External Interrupt Enable
|
||||||
|
set_clear_csr!(set_mext, clear_mext, 1 << 11);
|
|
@ -0,0 +1,18 @@
|
||||||
|
//! minstret register
|
||||||
|
|
||||||
|
/// Reads the CSR
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> usize {
|
||||||
|
match () {
|
||||||
|
#[cfg(target_arch = "riscv")]
|
||||||
|
() => {
|
||||||
|
let r: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!("csrrs $0, 0xB02, x0" : "=r"(r) ::: "volatile");
|
||||||
|
}
|
||||||
|
r
|
||||||
|
}
|
||||||
|
#[cfg(not(target_arch = "riscv"))]
|
||||||
|
() => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
//! minstreth register
|
||||||
|
|
||||||
|
/// Reads the CSR
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> usize {
|
||||||
|
match () {
|
||||||
|
#[cfg(all(target_arch = "riscv", target_pointer_width = "32"))]
|
||||||
|
() => {
|
||||||
|
let r: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!("csrrs $0, 0xB82, x0" : "=r"(r) ::: "volatile");
|
||||||
|
}
|
||||||
|
r
|
||||||
|
},
|
||||||
|
#[cfg(any(not(target_arch = "riscv"), not(target_pointer_width = "32")))]
|
||||||
|
() => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
//! mip register
|
||||||
|
|
||||||
|
/// 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 & (1 << 0) == 1 << 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor Software Interrupt Pending
|
||||||
|
#[inline]
|
||||||
|
pub fn ssoft(&self) -> bool {
|
||||||
|
self.bits & (1 << 1) == 1 << 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Machine Software Interrupt Pending
|
||||||
|
#[inline]
|
||||||
|
pub fn msoft(&self) -> bool {
|
||||||
|
self.bits & (1 << 3) == 1 << 3
|
||||||
|
}
|
||||||
|
|
||||||
|
/// User Timer Interrupt Pending
|
||||||
|
#[inline]
|
||||||
|
pub fn utimer(&self) -> bool {
|
||||||
|
self.bits & (1 << 4) == 1 << 4
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor Timer Interrupt Pending
|
||||||
|
#[inline]
|
||||||
|
pub fn stimer(&self) -> bool {
|
||||||
|
self.bits & (1 << 5) == 1 << 5
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Machine Timer Interrupt Pending
|
||||||
|
#[inline]
|
||||||
|
pub fn mtimer(&self) -> bool {
|
||||||
|
self.bits & (1 << 7) == 1 << 7
|
||||||
|
}
|
||||||
|
|
||||||
|
/// User External Interrupt Pending
|
||||||
|
#[inline]
|
||||||
|
pub fn uext(&self) -> bool {
|
||||||
|
self.bits & (1 << 8) == 1 << 8
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor External Interrupt Pending
|
||||||
|
#[inline]
|
||||||
|
pub fn sext(&self) -> bool {
|
||||||
|
self.bits & (1 << 9) == 1 << 9
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Machine External Interrupt Pending
|
||||||
|
#[inline]
|
||||||
|
pub fn mext(&self) -> bool {
|
||||||
|
self.bits & (1 << 11) == 1 << 11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads the CSR
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> Mip {
|
||||||
|
match () {
|
||||||
|
#[cfg(target_arch = "riscv")]
|
||||||
|
() => {
|
||||||
|
let r: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!("csrrs $0, 0x344, x0" : "=r"(r) ::: "volatile");
|
||||||
|
}
|
||||||
|
Mip { bits: r }
|
||||||
|
}
|
||||||
|
#[cfg(not(target_arch = "riscv"))]
|
||||||
|
() => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
//! misa register
|
||||||
|
|
||||||
|
/// misa register
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Misa {
|
||||||
|
bits: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Machine XLEN
|
||||||
|
pub enum MXL {
|
||||||
|
XLEN32,
|
||||||
|
XLEN64,
|
||||||
|
XLEN128,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Misa {
|
||||||
|
/// Returns the contents of the register as raw bits
|
||||||
|
pub fn bits(&self) -> usize {
|
||||||
|
self.bits
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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_widht = "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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads the CSR
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> Option<Misa> {
|
||||||
|
match () {
|
||||||
|
#[cfg(target_arch = "riscv")]
|
||||||
|
() => {
|
||||||
|
let r: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!("csrrs $0, 0x301, x0" : "=r"(r) ::: "volatile");
|
||||||
|
}
|
||||||
|
// When misa is hardwired to zero it means that the misa csr
|
||||||
|
// isn't implemented.
|
||||||
|
if r == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Misa { bits: r })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
#[cfg(not(target_arch = "riscv"))]
|
||||||
|
() => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
//! RISCV 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
|
||||||
|
|
||||||
|
pub mod mcause;
|
||||||
|
pub mod mcycle;
|
||||||
|
pub mod mcycleh;
|
||||||
|
pub mod mie;
|
||||||
|
pub mod mip;
|
||||||
|
pub mod minstret;
|
||||||
|
pub mod minstreth;
|
||||||
|
pub mod misa;
|
||||||
|
pub mod mstatus;
|
||||||
|
pub mod mtvec;
|
||||||
|
pub mod mvendorid;
|
|
@ -0,0 +1,169 @@
|
||||||
|
//! mstatus register
|
||||||
|
// TODO: Virtualization, Memory Privilege and Extension Context Fields
|
||||||
|
|
||||||
|
/// mstatus register
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Mstatus {
|
||||||
|
bits: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Machine Previous Privilege Mode
|
||||||
|
pub enum MPP {
|
||||||
|
Machine = 3,
|
||||||
|
Supervisor = 1,
|
||||||
|
User = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor Previous Privilege Mode
|
||||||
|
pub enum SPP {
|
||||||
|
Supervisor = 1,
|
||||||
|
User = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mstatus {
|
||||||
|
/// User Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn uie(&self) -> bool {
|
||||||
|
self.bits & (1 << 0) == 1 << 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn sie(&self) -> bool {
|
||||||
|
self.bits & (1 << 1) == 1 << 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Machine Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn mie(&self) -> bool {
|
||||||
|
self.bits & (1 << 3) == 1 << 3
|
||||||
|
}
|
||||||
|
|
||||||
|
/// User Previous Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn upie(&self) -> bool {
|
||||||
|
self.bits & (1 << 4) == 1 << 4
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor Previous Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn spie(&self) -> bool {
|
||||||
|
self.bits & (1 << 5) == 1 << 5
|
||||||
|
}
|
||||||
|
|
||||||
|
/// User Previous Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub fn mpie(&self) -> bool {
|
||||||
|
self.bits & (1 << 7) == 1 << 7
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supervisor Previous Privilege Mode
|
||||||
|
#[inline]
|
||||||
|
pub fn spp(&self) -> SPP {
|
||||||
|
match self.bits & (1 << 8) == (1 << 8) {
|
||||||
|
true => SPP::Supervisor,
|
||||||
|
false => SPP::User,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Machine Previous Privilege Mode
|
||||||
|
#[inline]
|
||||||
|
pub fn mpp(&self) -> MPP {
|
||||||
|
match (self.bits & (0b11 << 11)) >> 11 {
|
||||||
|
0b00 => MPP::User,
|
||||||
|
0b01 => MPP::Supervisor,
|
||||||
|
0b11 => MPP::Machine,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Reads the CSR
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> Mstatus {
|
||||||
|
match () {
|
||||||
|
#[cfg(target_arch = "riscv")]
|
||||||
|
() => {
|
||||||
|
let r: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!("csrrs $0, 0x300, x0" : "=r"(r) ::: "volatile");
|
||||||
|
}
|
||||||
|
Mstatus { bits: r }
|
||||||
|
}
|
||||||
|
#[cfg(not(target_arch = "riscv"))]
|
||||||
|
() => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the CSR
|
||||||
|
#[cfg_attr(not(target_arch = "riscv"), allow(unused_variables))]
|
||||||
|
#[inline]
|
||||||
|
unsafe fn set(bits: usize) {
|
||||||
|
match () {
|
||||||
|
#[cfg(target_arch = "riscv")]
|
||||||
|
() => asm!("csrrs x0, 0x305, $0" :: "r"(bits) :: "volatile"),
|
||||||
|
#[cfg(not(target_arch = "riscv"))]
|
||||||
|
() => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears the CSR
|
||||||
|
#[cfg_attr(not(target_arch = "riscv"), allow(unused_variables))]
|
||||||
|
#[inline]
|
||||||
|
unsafe fn clear(bits: usize) {
|
||||||
|
match () {
|
||||||
|
#[cfg(target_arch = "riscv")]
|
||||||
|
() => asm!("csrrc x0, 0x305, $0" :: "r"(bits) :: "volatile"),
|
||||||
|
#[cfg(not(target_arch = "riscv"))]
|
||||||
|
() => 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// User Interrupt Enable
|
||||||
|
set_clear_csr!(set_uie, clear_uie, 1 << 0);
|
||||||
|
/// Supervisor Interrupt Enable
|
||||||
|
set_clear_csr!(set_sie, clear_sie, 1 << 1);
|
||||||
|
/// Machine Interrupt Enable
|
||||||
|
set_clear_csr!(set_mie, clear_mie, 1 << 3);
|
||||||
|
/// User Previous Interrupt Enable
|
||||||
|
set_csr!(set_upie, 1 << 4);
|
||||||
|
/// Supervisor Previous Interrupt Enable
|
||||||
|
set_csr!(set_spie, 1 << 5);
|
||||||
|
/// Machine Previous Interrupt Enable
|
||||||
|
set_csr!(set_mpie, 1 << 7);
|
||||||
|
/// Supervisor Previous Privilege Mode
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn set_spp(spp: SPP) {
|
||||||
|
set((spp as usize) << 8);
|
||||||
|
}
|
||||||
|
/// Machine Previous Privilege Mode
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn set_mpp(mpp: MPP) {
|
||||||
|
set((mpp as usize) << 11);
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
//! mtvec register
|
||||||
|
|
||||||
|
/// mtvec register
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Mtvec {
|
||||||
|
bits: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trap mode
|
||||||
|
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!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads the CSR
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> Mtvec {
|
||||||
|
match () {
|
||||||
|
#[cfg(target_arch = "riscv")]
|
||||||
|
() => {
|
||||||
|
let r: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!("csrrs $0, 0x305, x0" : "=r"(r) ::: "volatile");
|
||||||
|
}
|
||||||
|
Mtvec { bits: r }
|
||||||
|
}
|
||||||
|
#[cfg(not(target_arch = "riscv"))]
|
||||||
|
() => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes the CSR
|
||||||
|
#[cfg_attr(not(target_arch = "riscv"), allow(unused_variables))]
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn write(addr: usize, mode: TrapMode) {
|
||||||
|
let bits = addr + mode as usize;
|
||||||
|
match () {
|
||||||
|
#[cfg(target_arch = "riscv")]
|
||||||
|
() => asm!("csrrw x0, 0x305, $0" :: "r"(bits) :: "volatile"),
|
||||||
|
#[cfg(not(target_arch = "riscv"))]
|
||||||
|
() => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
//! mvendorid register
|
||||||
|
|
||||||
|
/// mvendorid register
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Mvendorid {
|
||||||
|
bits: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mvendorid {
|
||||||
|
/// Returns the contents of the register as raw bits
|
||||||
|
pub fn bits(&self) -> usize {
|
||||||
|
self.bits
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the JEDEC manufacturer ID
|
||||||
|
pub fn jedec_manufacturer(&self) -> usize {
|
||||||
|
self.bits >> 7
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads the CSR
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> Option<Mvendorid> {
|
||||||
|
match () {
|
||||||
|
#[cfg(target_arch = "riscv")]
|
||||||
|
() => {
|
||||||
|
let r: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!("csrrs $0, 0xF11, x0" : "=r"(r) ::: "volatile");
|
||||||
|
}
|
||||||
|
// When mvendorid is hardwired to zero it means that the mvendorid
|
||||||
|
// csr isn't implemented.
|
||||||
|
if r == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Mvendorid { bits: r })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(target_arch = "riscv"))]
|
||||||
|
() => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue