|
1 | 1 | //! misa register |
2 | 2 |
|
3 | | -use core::num::NonZeroUsize; |
4 | | - |
5 | | -/// misa register |
6 | | -#[derive(Clone, Copy, Debug)] |
7 | | -pub struct Misa { |
8 | | - bits: NonZeroUsize, |
| 3 | +#[cfg(target_arch = "riscv32")] |
| 4 | +read_only_csr! { |
| 5 | + /// `misa` register |
| 6 | + Misa: 0x301, |
| 7 | + mask: 0xc3ff_ffff, |
| 8 | + sentinel: 0, |
9 | 9 | } |
10 | 10 |
|
11 | | -/// Base integer ISA width |
12 | | -#[derive(Copy, Clone, Debug, Eq, PartialEq)] |
13 | | -pub enum XLEN { |
14 | | - XLEN32 = 1, |
15 | | - XLEN64 = 2, |
16 | | - XLEN128 = 3, |
| 11 | +#[cfg(not(target_arch = "riscv32"))] |
| 12 | +read_only_csr! { |
| 13 | + /// `misa` register |
| 14 | + Misa: 0x301, |
| 15 | + mask: 0xc000_0000_03ff_ffff, |
| 16 | + sentinel: 0, |
17 | 17 | } |
18 | 18 |
|
19 | | -impl XLEN { |
20 | | - /// Converts a number into an ISA width |
21 | | - pub(crate) fn from(value: u8) -> Self { |
22 | | - match value { |
23 | | - 1 => XLEN::XLEN32, |
24 | | - 2 => XLEN::XLEN64, |
25 | | - 3 => XLEN::XLEN128, |
26 | | - _ => unreachable!(), |
27 | | - } |
| 19 | +csr_field_enum! { |
| 20 | + /// Base integer ISA width |
| 21 | + XLEN { |
| 22 | + default: XLEN32, |
| 23 | + XLEN32 = 1, |
| 24 | + XLEN64 = 2, |
| 25 | + XLEN128 = 3, |
28 | 26 | } |
29 | 27 | } |
30 | 28 |
|
31 | | -impl Misa { |
32 | | - /// Returns the contents of the register as raw bits |
33 | | - #[inline] |
34 | | - pub fn bits(&self) -> usize { |
35 | | - self.bits.get() |
36 | | - } |
| 29 | +#[cfg(target_arch = "riscv32")] |
| 30 | +read_only_csr_field! { |
| 31 | + Misa, |
| 32 | + /// Effective xlen in M-mode (i.e., `MXLEN`). |
| 33 | + mxl, |
| 34 | + XLEN: [30:31], |
| 35 | +} |
37 | 36 |
|
| 37 | +#[cfg(not(target_arch = "riscv32"))] |
| 38 | +read_only_csr_field! { |
| 39 | + Misa, |
38 | 40 | /// Effective xlen in M-mode (i.e., `MXLEN`). |
39 | | - #[inline] |
40 | | - pub fn mxl(&self) -> XLEN { |
41 | | - let value = (self.bits() >> (usize::BITS - 2)) as u8; |
42 | | - XLEN::from(value) |
43 | | - } |
| 41 | + mxl, |
| 42 | + XLEN: [62:63], |
| 43 | +} |
44 | 44 |
|
| 45 | +impl Misa { |
45 | 46 | /// Returns true when a given extension is implemented. |
46 | 47 | /// |
47 | 48 | /// # Example |
48 | 49 | /// |
49 | 50 | /// ```no_run |
50 | | - /// let misa = unsafe { riscv::register::misa::read() }.unwrap(); |
| 51 | + /// let misa = unsafe { riscv::register::misa::try_read() }.unwrap(); |
51 | 52 | /// assert!(misa.has_extension('A')); // panics if atomic extension is not implemented |
52 | 53 | /// ``` |
53 | 54 | #[inline] |
54 | 55 | pub fn has_extension(&self, extension: char) -> bool { |
55 | | - let bit = extension as u8 - 65; |
| 56 | + let bit = ext_char_to_bit(extension); |
56 | 57 | if bit > 25 { |
57 | 58 | return false; |
58 | 59 | } |
59 | 60 | self.bits() & (1 << bit) == (1 << bit) |
60 | 61 | } |
61 | 62 | } |
62 | 63 |
|
63 | | -read_csr!(0x301); |
64 | | - |
65 | | -/// Reads the CSR |
66 | 64 | #[inline] |
67 | | -pub fn read() -> Option<Misa> { |
68 | | - let r = unsafe { _read() }; |
69 | | - // When misa is hardwired to zero it means that the misa csr |
70 | | - // isn't implemented. |
71 | | - NonZeroUsize::new(r).map(|bits| Misa { bits }) |
| 65 | +const fn ext_char_to_bit(extension: char) -> u8 { |
| 66 | + (extension as u8).saturating_sub(b'A') |
| 67 | +} |
| 68 | + |
| 69 | +#[cfg(test)] |
| 70 | +mod tests { |
| 71 | + use super::*; |
| 72 | + use crate::result::Error; |
| 73 | + |
| 74 | + #[test] |
| 75 | + fn test_misa() { |
| 76 | + (1..=3) |
| 77 | + .zip([XLEN::XLEN32, XLEN::XLEN64, XLEN::XLEN128]) |
| 78 | + .for_each(|(raw, exp_xlen)| { |
| 79 | + assert_eq!(XLEN::try_from(raw), Ok(exp_xlen)); |
| 80 | + assert_eq!(usize::from(exp_xlen), raw); |
| 81 | + |
| 82 | + let misa = Misa::from_bits(raw << (usize::BITS - 2)); |
| 83 | + assert_eq!(misa.try_mxl(), Ok(exp_xlen)); |
| 84 | + assert_eq!(misa.mxl(), exp_xlen); |
| 85 | + }); |
| 86 | + |
| 87 | + (0..62).map(|b| 1 << b).for_each(|invalid_mxl| { |
| 88 | + assert_eq!( |
| 89 | + Misa::from_bits(invalid_mxl).try_mxl(), |
| 90 | + Err(Error::InvalidVariant(0)) |
| 91 | + ); |
| 92 | + }); |
| 93 | + |
| 94 | + ('A'..='Z').for_each(|ext| { |
| 95 | + assert!(!Misa::from_bits(0).has_extension(ext)); |
| 96 | + assert!(Misa::from_bits(1 << ext_char_to_bit(ext)).has_extension(ext)); |
| 97 | + }); |
| 98 | + } |
72 | 99 | } |
0 commit comments