|
1 | 1 | //! mtvec register
|
2 | 2 |
|
3 |
| -/// mtvec register |
4 |
| -#[derive(Clone, Copy, Debug)] |
5 |
| -pub struct Mtvec { |
6 |
| - bits: usize, |
| 3 | +use crate::result::{Error, Result}; |
| 4 | + |
| 5 | +const MASK: usize = usize::MAX; |
| 6 | +const TRAP_MASK: usize = 0b11; |
| 7 | + |
| 8 | +read_write_csr! { |
| 9 | + /// mtvec register |
| 10 | + Mtvec: 0x305, |
| 11 | + mask: MASK, |
| 12 | +} |
| 13 | + |
| 14 | +csr_field_enum! { |
| 15 | + /// Trap mode |
| 16 | + TrapMode { |
| 17 | + default: Direct, |
| 18 | + Direct = 0, |
| 19 | + Vectored = 1, |
| 20 | + } |
7 | 21 | }
|
8 | 22 |
|
9 |
| -/// Trap mode |
10 |
| -#[derive(Copy, Clone, Debug, Eq, PartialEq)] |
11 |
| -pub enum TrapMode { |
12 |
| - Direct = 0, |
13 |
| - Vectored = 1, |
| 23 | +read_write_csr_field! { |
| 24 | + Mtvec, |
| 25 | + /// Accesses the trap-vector mode. |
| 26 | + trap_mode, |
| 27 | + TrapMode: [0:1], |
14 | 28 | }
|
15 | 29 |
|
16 | 30 | impl Mtvec {
|
17 |
| - /// Returns the contents of the register as raw bits |
| 31 | + /// Returns the trap-vector base-address |
18 | 32 | #[inline]
|
19 |
| - pub fn bits(&self) -> usize { |
20 |
| - self.bits |
| 33 | + pub const fn address(&self) -> usize { |
| 34 | + self.bits & !TRAP_MASK |
21 | 35 | }
|
22 | 36 |
|
23 |
| - /// Returns the trap-vector base-address |
| 37 | + /// Sets the trap-vector base-address. |
| 38 | + /// |
| 39 | + /// # Note |
| 40 | + /// |
| 41 | + /// Panics if the address is not aligned to 4-bytes. |
24 | 42 | #[inline]
|
25 |
| - pub fn address(&self) -> usize { |
26 |
| - self.bits - (self.bits & 0b11) |
| 43 | + pub fn set_address(&mut self, address: usize) { |
| 44 | + self.try_set_address(address).unwrap(); |
27 | 45 | }
|
28 | 46 |
|
29 |
| - /// Returns the trap-vector mode |
| 47 | + /// Attempts to set the trap-vector base-address. |
| 48 | + /// |
| 49 | + /// # Note |
| 50 | + /// |
| 51 | + /// Returns an error if the address is not aligned to 4-bytes. |
30 | 52 | #[inline]
|
31 |
| - pub fn trap_mode(&self) -> Option<TrapMode> { |
32 |
| - let mode = self.bits & 0b11; |
33 |
| - match mode { |
34 |
| - 0 => Some(TrapMode::Direct), |
35 |
| - 1 => Some(TrapMode::Vectored), |
36 |
| - _ => None, |
| 53 | + pub fn try_set_address(&mut self, address: usize) -> Result<()> { |
| 54 | + // check for four-byte alignment |
| 55 | + if (address & TRAP_MASK) != 0 { |
| 56 | + Err(Error::InvalidFieldVariant { |
| 57 | + field: "mtvec::address", |
| 58 | + value: address, |
| 59 | + }) |
| 60 | + } else { |
| 61 | + self.bits = address | (self.bits & TRAP_MASK); |
| 62 | + Ok(()) |
37 | 63 | }
|
38 | 64 | }
|
39 | 65 | }
|
40 | 66 |
|
41 |
| -read_csr_as!(Mtvec, 0x305); |
| 67 | +#[cfg(test)] |
| 68 | +mod tests { |
| 69 | + use super::*; |
| 70 | + |
| 71 | + #[test] |
| 72 | + fn test_mtvec() { |
| 73 | + let mut m = Mtvec::from_bits(0); |
| 74 | + |
| 75 | + (1..=usize::BITS) |
| 76 | + .map(|r| (((1u128 << r) - 1) as usize) & !TRAP_MASK) |
| 77 | + .for_each(|address| { |
| 78 | + m.set_address(address); |
| 79 | + assert_eq!(m.address(), address); |
42 | 80 |
|
43 |
| -write_csr!(0x305); |
| 81 | + assert_eq!(m.try_set_address(address), Ok(())); |
| 82 | + assert_eq!(m.address(), address); |
| 83 | + }); |
44 | 84 |
|
45 |
| -/// Writes the CSR |
46 |
| -#[inline] |
47 |
| -pub unsafe fn write(addr: usize, mode: TrapMode) { |
48 |
| - let bits = addr + mode as usize; |
49 |
| - _write(bits); |
| 85 | + (1..=usize::BITS) |
| 86 | + .filter_map(|r| match ((1u128 << r) - 1) as usize { |
| 87 | + addr if (addr & TRAP_MASK) != 0 => Some(addr), |
| 88 | + _ => None, |
| 89 | + }) |
| 90 | + .for_each(|address| { |
| 91 | + assert_eq!( |
| 92 | + m.try_set_address(address), |
| 93 | + Err(Error::InvalidFieldVariant { |
| 94 | + field: "mtvec::address", |
| 95 | + value: address, |
| 96 | + }) |
| 97 | + ); |
| 98 | + }); |
| 99 | + |
| 100 | + test_csr_field!(m, trap_mode: TrapMode::Direct); |
| 101 | + test_csr_field!(m, trap_mode: TrapMode::Vectored); |
| 102 | + } |
50 | 103 | }
|
0 commit comments