Skip to content

Commit

Permalink
Merge pull request #261 from rmsyn/riscv/scause-csr-macro
Browse files Browse the repository at this point in the history
riscv: define `scause` CSR with macro helpers
  • Loading branch information
romancardenas authored Feb 8, 2025
2 parents c5a8b24 + b2b533e commit b584859
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 25 deletions.
1 change: 1 addition & 0 deletions riscv/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Use CSR helper macros to define `mtvendorid` register
- Use CSR helper macros to define `satp` register
- Use CSR helper macros to define `pmpcfgx` field types
- Use CSR helper macros to define `scause` field types

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

Expand Down
118 changes: 93 additions & 25 deletions riscv/src/register/scause.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,47 @@
pub use crate::interrupt::Trap;
pub use riscv_pac::{CoreInterruptNumber, ExceptionNumber, InterruptNumber}; // re-export useful riscv-pac traits

/// scause register
#[derive(Clone, Copy)]
pub struct Scause {
bits: usize,
read_write_csr! {
/// scause register
Scause: 0x142,
mask: usize::MAX,
}

impl Scause {
/// Returns the contents of the register as raw bits
#[inline]
pub fn bits(&self) -> usize {
self.bits
}
#[cfg(target_arch = "riscv32")]
read_write_csr_field! {
Scause,
/// Returns the type of the trap:
///
/// - `true`: an interrupt caused the trap
/// - `false`: an exception caused the trap
interrupt: 31,
}

#[cfg(not(target_arch = "riscv32"))]
read_write_csr_field! {
Scause,
/// Returns the type of the trap:
///
/// - `true`: an interrupt caused the trap
/// - `false`: an exception caused the trap
interrupt: 63,
}

#[cfg(target_arch = "riscv32")]
read_write_csr_field! {
Scause,
/// Returns the code field
#[inline]
pub fn code(&self) -> usize {
self.bits & !(1 << (usize::BITS as usize - 1))
}
code: [0:30],
}

#[cfg(not(target_arch = "riscv32"))]
read_write_csr_field! {
Scause,
/// Returns the code field
code: [0:62],
}

impl Scause {
/// Returns the trap cause represented by this register.
///
/// # Note
Expand All @@ -40,25 +62,16 @@ impl Scause {
/// Is trap cause an interrupt.
#[inline]
pub fn is_interrupt(&self) -> bool {
self.bits & (1 << (usize::BITS as usize - 1)) != 0
self.interrupt()
}

/// Is trap cause an exception.
#[inline]
pub fn is_exception(&self) -> bool {
!self.is_interrupt()
!self.interrupt()
}
}

read_csr_as!(Scause, 0x142);
write_csr!(0x142);

/// Writes the CSR
#[inline]
pub unsafe fn write(bits: usize) {
_write(bits)
}

/// Set supervisor cause register to corresponding cause.
#[inline]
pub unsafe fn set<I: CoreInterruptNumber, E: ExceptionNumber>(cause: Trap<I, E>) {
Expand All @@ -70,3 +83,58 @@ pub unsafe fn set<I: CoreInterruptNumber, E: ExceptionNumber>(cause: Trap<I, E>)
};
_write(bits);
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_scause() {
let new_code = 0;
(1usize..=usize::BITS as usize)
.map(|r| ((1u128 << r) - 1) as usize)
.for_each(|raw| {
let exp_interrupt = (raw >> (usize::BITS - 1)) != 0;
let exp_code = raw & ((1usize << (usize::BITS - 1)) - 1);
let exp_cause = if exp_interrupt {
Trap::Interrupt(exp_code)
} else {
Trap::Exception(exp_code)
};

let mut scause = Scause::from_bits(raw);

assert_eq!(scause.interrupt(), exp_interrupt);
assert_eq!(scause.is_interrupt(), exp_interrupt);
assert_eq!(scause.is_exception(), !exp_interrupt);

assert_eq!(scause.code(), exp_code);
assert_eq!(scause.cause(), exp_cause);

scause.set_interrupt(!exp_interrupt);

assert_eq!(scause.is_interrupt(), !exp_interrupt);
assert_eq!(scause.is_exception(), exp_interrupt);

scause.set_code(new_code);
let new_cause = if scause.interrupt() {
Trap::Interrupt(new_code)
} else {
Trap::Exception(new_code)
};

assert_eq!(scause.code(), new_code);
assert_eq!(scause.cause(), new_cause);

scause.set_code(exp_code);
let exp_cause = if scause.interrupt() {
Trap::Interrupt(exp_code)
} else {
Trap::Exception(exp_code)
};

assert_eq!(scause.code(), exp_code);
assert_eq!(scause.cause(), exp_cause);
});
}
}

0 comments on commit b584859

Please sign in to comment.