diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 0b382665..4a32c68e 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Write utilities for `mcycle`, `minstret` - Add `senvcfg` CSR - Add `scontext` CSR +- Add `mtinst` CSR ### Changed diff --git a/riscv/src/register.rs b/riscv/src/register.rs index 4a56e1e0..1848145f 100644 --- a/riscv/src/register.rs +++ b/riscv/src/register.rs @@ -88,6 +88,7 @@ pub mod mcause; pub mod mepc; pub mod mip; pub mod mscratch; +pub mod mtinst; pub mod mtval; // Machine Protection and Translation diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index b97dace1..c9b6254f 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -1007,13 +1007,13 @@ macro_rules! test_csr_field { // test a single bit field ($reg:ident, $field:ident) => {{ $crate::paste! { - assert!(!$reg.$field()); + let val = $reg.$field(); - $reg.[](true); - assert!($reg.$field()); + $reg.[](!val); + assert_eq!($reg.$field(), !val); - $reg.[](false); - assert!(!$reg.$field()); + $reg.[](val); + assert_eq!($reg.$field(), val); } }}; @@ -1049,4 +1049,24 @@ macro_rules! test_csr_field { assert_eq!($reg.[](), Ok($var)); } }}; + + // test a multi-bit bitfield + ($reg:ident, $field:ident: [$start:expr, $end:expr], $reset:expr) => {{ + let bits = $reg.bits(); + + let shift = $end - $start + 1; + let mask = (1usize << shift) - 1; + + let exp_val = (bits >> $start) & mask; + + $crate::paste! { + assert_eq!($reg.$field(), exp_val); + + $reg.[]($reset); + assert_eq!($reg.$field(), $reset); + + $reg.[](exp_val); + assert_eq!($reg.$field(), exp_val); + } + }}; } diff --git a/riscv/src/register/mtinst.rs b/riscv/src/register/mtinst.rs new file mode 100644 index 00000000..ea3276d2 --- /dev/null +++ b/riscv/src/register/mtinst.rs @@ -0,0 +1,91 @@ +//! mtinst register. + +const MASK: usize = usize::MAX; + +read_write_csr! { + /// mtinst register + Mtinst: 0x34a, + mask: MASK, +} + +read_write_csr_field! { + Mtinst, + /// Trapped instruction `opcode` field. + opcode: [0:6], +} + +read_write_csr_field! { + Mtinst, + /// Trapped instruction `rd` field for load instructions. + rd: [7:11], +} + +read_write_csr_field! { + Mtinst, + /// Trapped instruction `funct3` field. + funct3: [12:14], +} + +read_write_csr_field! { + Mtinst, + /// Trapped instruction `address offset` field. + address_offset: [15:19], +} + +read_write_csr_field! { + Mtinst, + /// Trapped instruction `rs2` field for store instructions. + rs2: [20:24], +} + +read_write_csr_field! { + Mtinst, + /// Trapped instruction `rl` field for atomic instructions. + rl: 25, +} + +read_write_csr_field! { + Mtinst, + /// Trapped instruction `aq` field for atomic instructions. + aq: 26, +} + +read_write_csr_field! { + Mtinst, + /// Trapped instruction `funct5` field for atomic instructions. + funct5: [27:31], +} + +read_write_csr_field! { + Mtinst, + /// Trapped instruction `funct7` field for virtual machine instructions. + funct7: [25:31], +} + +set!(0x34a); +clear!(0x34a); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_mtinst() { + (1..=usize::BITS) + .map(|r| ((1u128 << r) - 1) as usize) + .for_each(|bits| { + let reset = 0; + let mut mtinst = Mtinst::from_bits(bits); + + test_csr_field!(mtinst, opcode: [0, 6], reset); + test_csr_field!(mtinst, rd: [7, 11], reset); + test_csr_field!(mtinst, funct3: [12, 14], reset); + test_csr_field!(mtinst, address_offset: [15, 19], reset); + test_csr_field!(mtinst, rs2: [20, 24], reset); + test_csr_field!(mtinst, rl); + test_csr_field!(mtinst, aq); + test_csr_field!(mtinst, funct5: [27, 31], reset); + test_csr_field!(mtinst, funct7: [25, 31], reset); + }); + } +}