Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

riscv: define mtvec CSR with macro helpers #252

Merged
merged 5 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions riscv/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Use CSR helper macros to define `mip` register
- Use CSR helper macros to define `mstatus` register
- Use CSR helper macros to define `mstatush` register
- Use CSR helper macros to define `mtvec` register

## [v0.12.1] - 2024-10-20

Expand Down
1 change: 1 addition & 0 deletions riscv/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#![no_std]
#![allow(clippy::missing_safety_doc)]
#![allow(clippy::eq_op)]
#![allow(clippy::identity_op)]

pub use paste::paste;

Expand Down
2 changes: 1 addition & 1 deletion riscv/src/register/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ macro_rules! clear_pmp {
macro_rules! csr {
($(#[$doc:meta])*
$ty:ident,
$mask:literal) => {
$mask:expr) => {
#[repr(C)]
$(#[$doc])*
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
Expand Down
111 changes: 82 additions & 29 deletions riscv/src/register/mtvec.rs
Original file line number Diff line number Diff line change
@@ -1,50 +1,103 @@
//! mtvec register

/// mtvec register
#[derive(Clone, Copy, Debug)]
pub struct Mtvec {
bits: usize,
use crate::result::{Error, Result};

const MASK: usize = usize::MAX;
const TRAP_MASK: usize = 0b11;

read_write_csr! {
/// mtvec register
Mtvec: 0x305,
mask: MASK,
}

csr_field_enum! {
/// Trap mode
TrapMode {
default: Direct,
Direct = 0,
Vectored = 1,
}
}

/// Trap mode
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum TrapMode {
Direct = 0,
Vectored = 1,
read_write_csr_field! {
Mtvec,
/// Accesses the trap-vector mode.
trap_mode,
TrapMode: [0:1],
}

impl Mtvec {
/// Returns the contents of the register as raw bits
/// Returns the trap-vector base-address
#[inline]
pub fn bits(&self) -> usize {
self.bits
pub const fn address(&self) -> usize {
self.bits & !TRAP_MASK
}

/// Returns the trap-vector base-address
/// Sets the trap-vector base-address.
///
/// # Note
///
/// Panics if the address is not aligned to 4-bytes.
#[inline]
pub fn address(&self) -> usize {
self.bits - (self.bits & 0b11)
pub fn set_address(&mut self, address: usize) {
self.try_set_address(address).unwrap();
}

/// Returns the trap-vector mode
/// Attempts to set the trap-vector base-address.
///
/// # Note
///
/// Returns an error if the address is not aligned to 4-bytes.
#[inline]
pub fn trap_mode(&self) -> Option<TrapMode> {
let mode = self.bits & 0b11;
match mode {
0 => Some(TrapMode::Direct),
1 => Some(TrapMode::Vectored),
_ => None,
pub fn try_set_address(&mut self, address: usize) -> Result<()> {
// check for four-byte alignment
if (address & TRAP_MASK) != 0 {
Err(Error::InvalidFieldVariant {
field: "mtvec::address",
value: address,
})
} else {
self.bits = address | (self.bits & TRAP_MASK);
Ok(())
}
}
}

read_csr_as!(Mtvec, 0x305);
#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_mtvec() {
let mut m = Mtvec::from_bits(0);

(1..=usize::BITS)
.map(|r| (((1u128 << r) - 1) as usize) & !TRAP_MASK)
.for_each(|address| {
m.set_address(address);
assert_eq!(m.address(), address);

write_csr!(0x305);
assert_eq!(m.try_set_address(address), Ok(()));
assert_eq!(m.address(), address);
});

/// Writes the CSR
#[inline]
pub unsafe fn write(addr: usize, mode: TrapMode) {
let bits = addr + mode as usize;
_write(bits);
(1..=usize::BITS)
.filter_map(|r| match ((1u128 << r) - 1) as usize {
addr if (addr & TRAP_MASK) != 0 => Some(addr),
_ => None,
})
.for_each(|address| {
assert_eq!(
m.try_set_address(address),
Err(Error::InvalidFieldVariant {
field: "mtvec::address",
value: address,
})
);
});

test_csr_field!(m, trap_mode: TrapMode::Direct);
test_csr_field!(m, trap_mode: TrapMode::Vectored);
}
}
4 changes: 2 additions & 2 deletions riscv/src/register/satp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl Satp {
#[inline]
#[cfg(target_pointer_width = "64")]
pub fn asid(&self) -> usize {
self.bits >> 44 & 0xFFFF // bits 44-59
(self.bits >> 44) & 0xFFFF // bits 44-59
}

/// Physical page number
Expand Down Expand Up @@ -203,7 +203,7 @@ pub unsafe fn try_set(mode: Mode, asid: usize, ppn: usize) -> Result<()> {
bitmask: 0xFFF_FFFF_FFFF,
})
} else {
let bits = (mode as usize) << 60 | (asid << 44) | ppn;
let bits = ((mode as usize) << 60) | (asid << 44) | ppn;
_try_write(bits)
}
}
Loading