use crate::isa::csr::{
MISA_DEFAULT_RV64IMAFDC, MISA_EXT_A, MISA_EXT_C, MISA_EXT_D, MISA_EXT_F, MISA_EXT_I,
MISA_EXT_M, MISA_EXT_S, MISA_EXT_U, MISA_EXT_V, MISA_XLEN_64,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Misa(u64);
impl Misa {
#[must_use]
pub const fn rv64imafdc(with_v: bool) -> Self {
if with_v {
Self(MISA_DEFAULT_RV64IMAFDC | MISA_EXT_V)
} else {
Self(MISA_DEFAULT_RV64IMAFDC)
}
}
#[must_use]
pub const fn bits(self) -> u64 {
self.0
}
#[must_use]
pub const fn has_v(self) -> bool {
self.0 & MISA_EXT_V != 0
}
#[must_use]
pub const fn has_s(self) -> bool {
self.0 & MISA_EXT_S != 0
}
#[must_use]
pub fn isa_string(self) -> String {
let mut isa = String::from("rv64");
for (letter, bit) in ISA_LETTERS {
if self.0 & bit != 0 {
isa.push(letter);
}
}
isa
}
}
impl std::str::FromStr for Misa {
type Err = IsaStringError;
fn from_str(isa: &str) -> Result<Self, Self::Err> {
let upper = isa.to_ascii_uppercase();
let Some(extensions) = upper.strip_prefix("RV64") else {
return Err(IsaStringError::NotRv64(isa.to_string()));
};
let mut bits = MISA_XLEN_64 | MISA_EXT_S | MISA_EXT_U;
for ext in extensions.chars() {
bits |= match ext {
'G' => MISA_EXT_I | MISA_EXT_M | MISA_EXT_A | MISA_EXT_F | MISA_EXT_D,
'I' => MISA_EXT_I,
'M' => MISA_EXT_M,
'A' => MISA_EXT_A,
'F' => MISA_EXT_F,
'D' => MISA_EXT_D,
'C' => MISA_EXT_C,
'V' => MISA_EXT_V,
other => return Err(IsaStringError::Unsupported(isa.to_string(), other)),
};
}
if bits & MISA_EXT_I == 0 {
return Err(IsaStringError::NoBase(isa.to_string()));
}
if bits & MISA_EXT_D != 0 && bits & MISA_EXT_F == 0 {
return Err(IsaStringError::DWithoutF(isa.to_string()));
}
Ok(Self(bits))
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum IsaStringError {
NotRv64(String),
NoBase(String),
Unsupported(String, char),
DWithoutF(String),
}
impl std::fmt::Display for IsaStringError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NotRv64(isa) => write!(f, "ISA string {isa:?} does not start with RV64"),
Self::NoBase(isa) => write!(f, "ISA string {isa:?} has no I base"),
Self::Unsupported(isa, ext) => {
write!(f, "ISA string {isa:?} names unsupported extension {ext:?}")
}
Self::DWithoutF(isa) => write!(f, "ISA string {isa:?} has D without F"),
}
}
}
impl std::error::Error for IsaStringError {}
const ISA_LETTERS: [(char, u64); 7] = [
('i', MISA_EXT_I),
('m', MISA_EXT_M),
('a', MISA_EXT_A),
('f', MISA_EXT_F),
('d', MISA_EXT_D),
('c', MISA_EXT_C),
('v', MISA_EXT_V),
];