-
Notifications
You must be signed in to change notification settings - Fork 166
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #244 from rmsyn/riscv/misa-csr-macro
riscv: define misa using CSR macros
- Loading branch information
Showing
8 changed files
with
73 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,72 +1,99 @@ | ||
//! misa register | ||
use core::num::NonZeroUsize; | ||
|
||
/// misa register | ||
#[derive(Clone, Copy, Debug)] | ||
pub struct Misa { | ||
bits: NonZeroUsize, | ||
#[cfg(target_arch = "riscv32")] | ||
read_only_csr! { | ||
/// `misa` register | ||
Misa: 0x301, | ||
mask: 0xc3ff_ffff, | ||
sentinel: 0, | ||
} | ||
|
||
/// Base integer ISA width | ||
#[derive(Copy, Clone, Debug, Eq, PartialEq)] | ||
pub enum XLEN { | ||
XLEN32 = 1, | ||
XLEN64 = 2, | ||
XLEN128 = 3, | ||
#[cfg(not(target_arch = "riscv32"))] | ||
read_only_csr! { | ||
/// `misa` register | ||
Misa: 0x301, | ||
mask: 0xc000_0000_03ff_ffff, | ||
sentinel: 0, | ||
} | ||
|
||
impl XLEN { | ||
/// Converts a number into an ISA width | ||
pub(crate) fn from(value: u8) -> Self { | ||
match value { | ||
1 => XLEN::XLEN32, | ||
2 => XLEN::XLEN64, | ||
3 => XLEN::XLEN128, | ||
_ => unreachable!(), | ||
} | ||
csr_field_enum! { | ||
/// Base integer ISA width | ||
XLEN { | ||
default: XLEN32, | ||
XLEN32 = 1, | ||
XLEN64 = 2, | ||
XLEN128 = 3, | ||
} | ||
} | ||
|
||
impl Misa { | ||
/// Returns the contents of the register as raw bits | ||
#[inline] | ||
pub fn bits(&self) -> usize { | ||
self.bits.get() | ||
} | ||
#[cfg(target_arch = "riscv32")] | ||
read_only_csr_field! { | ||
Misa, | ||
/// Effective xlen in M-mode (i.e., `MXLEN`). | ||
mxl, | ||
XLEN: [30:31], | ||
} | ||
|
||
#[cfg(not(target_arch = "riscv32"))] | ||
read_only_csr_field! { | ||
Misa, | ||
/// Effective xlen in M-mode (i.e., `MXLEN`). | ||
#[inline] | ||
pub fn mxl(&self) -> XLEN { | ||
let value = (self.bits() >> (usize::BITS - 2)) as u8; | ||
XLEN::from(value) | ||
} | ||
mxl, | ||
XLEN: [62:63], | ||
} | ||
|
||
impl Misa { | ||
/// Returns true when a given extension is implemented. | ||
/// | ||
/// # Example | ||
/// | ||
/// ```no_run | ||
/// let misa = unsafe { riscv::register::misa::read() }.unwrap(); | ||
/// let misa = unsafe { riscv::register::misa::try_read() }.unwrap(); | ||
/// assert!(misa.has_extension('A')); // panics if atomic extension is not implemented | ||
/// ``` | ||
#[inline] | ||
pub fn has_extension(&self, extension: char) -> bool { | ||
let bit = extension as u8 - 65; | ||
let bit = ext_char_to_bit(extension); | ||
if bit > 25 { | ||
return false; | ||
} | ||
self.bits() & (1 << bit) == (1 << bit) | ||
} | ||
} | ||
|
||
read_csr!(0x301); | ||
|
||
/// Reads the CSR | ||
#[inline] | ||
pub fn read() -> Option<Misa> { | ||
let r = unsafe { _read() }; | ||
// When misa is hardwired to zero it means that the misa csr | ||
// isn't implemented. | ||
NonZeroUsize::new(r).map(|bits| Misa { bits }) | ||
const fn ext_char_to_bit(extension: char) -> u8 { | ||
(extension as u8).saturating_sub(b'A') | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use crate::result::Error; | ||
|
||
#[test] | ||
fn test_misa() { | ||
(1..=3) | ||
.zip([XLEN::XLEN32, XLEN::XLEN64, XLEN::XLEN128]) | ||
.for_each(|(raw, exp_xlen)| { | ||
assert_eq!(XLEN::try_from(raw), Ok(exp_xlen)); | ||
assert_eq!(usize::from(exp_xlen), raw); | ||
|
||
let misa = Misa::from_bits(raw << (usize::BITS - 2)); | ||
assert_eq!(misa.try_mxl(), Ok(exp_xlen)); | ||
assert_eq!(misa.mxl(), exp_xlen); | ||
}); | ||
|
||
(0..62).map(|b| 1 << b).for_each(|invalid_mxl| { | ||
assert_eq!( | ||
Misa::from_bits(invalid_mxl).try_mxl(), | ||
Err(Error::InvalidVariant(0)) | ||
); | ||
}); | ||
|
||
('A'..='Z').for_each(|ext| { | ||
assert!(!Misa::from_bits(0).has_extension(ext)); | ||
assert!(Misa::from_bits(1 << ext_char_to_bit(ext)).has_extension(ext)); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters