mod esr;
mod midr;
mod smccc;
use bit_field::BitField;
pub use esr::decode;
pub use midr::decode_midr;
pub use smccc::decode_smccc;
use std::fmt::{self, Debug, Display, Formatter};
use std::num::ParseIntError;
use thiserror::Error;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FieldInfo {
pub name: &'static str,
pub long_name: Option<&'static str>,
pub start: usize,
pub width: usize,
pub value: u64,
pub description: Option<String>,
pub subfields: Vec<FieldInfo>,
}
impl FieldInfo {
fn get(
register: u64,
name: &'static str,
long_name: Option<&'static str>,
start: usize,
end: usize,
) -> Self {
let value = register.get_bits(start..end);
Self {
name,
long_name,
start,
width: end - start,
value,
description: None,
subfields: vec![],
}
}
fn get_bit(
register: u64,
name: &'static str,
long_name: Option<&'static str>,
bit: usize,
) -> Self {
Self::get(register, name, long_name, bit, bit + 1)
}
fn with_description(self, description: String) -> Self {
Self {
description: Some(description),
..self
}
}
fn as_bit(&self) -> bool {
assert!(self.width == 1);
self.value == 1
}
fn describe_bit<F>(self, describer: F) -> Self
where
F: FnOnce(bool) -> &'static str,
{
let bit = self.as_bit();
let description = describer(bit).to_string();
self.with_description(description)
}
fn describe<F>(self, describer: F) -> Result<Self, DecodeError>
where
F: FnOnce(u64) -> Result<&'static str, DecodeError>,
{
let description = describer(self.value)?.to_string();
Ok(self.with_description(description))
}
fn check_res0(self) -> Result<Self, DecodeError> {
if self.value != 0 {
Err(DecodeError::InvalidRes0 { res0: self.value })
} else {
Ok(self)
}
}
pub fn value_string(&self) -> String {
if self.width == 1 {
if self.value == 1 { "true" } else { "false" }.to_string()
} else {
format!("{:#01$x}", self.value, self.width.div_ceil(4) + 2,)
}
}
pub fn value_binary_string(&self) -> String {
format!("{:#01$b}", self.value, self.width + 2)
}
}
impl Display for FieldInfo {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if self.width == 1 {
write!(
f,
"{}: {}",
self.name,
if self.value == 1 { "true" } else { "false" }
)
} else {
write!(
f,
"{}: {} {}",
self.name,
self.value_string(),
self.value_binary_string(),
)
}
}
}
#[derive(Debug, Error)]
pub enum DecodeError {
#[error("Invalid ESR, res0 is {res0:#x}")]
InvalidRes0 { res0: u64 },
#[error("Invalid EC {ec:#x}")]
InvalidEc { ec: u64 },
#[error("Invalid DFSC or IFSC {fsc:#x}")]
InvalidFsc { fsc: u64 },
#[error("Invalid SET {set:#x}")]
InvalidSet { set: u64 },
#[error("Invalid AET {aet:#x}")]
InvalidAet { aet: u64 },
#[error("Invalid AM {am:#x}")]
InvalidAm { am: u64 },
#[error("Invalid ISS {iss:#x} for trapped LD64B or ST64B*")]
InvalidLd64bIss { iss: u64 },
}
pub fn parse_number(s: &str) -> Result<u64, ParseIntError> {
if let Some(hex) = s.strip_prefix("0x") {
u64::from_str_radix(hex, 16)
} else {
s.parse()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_decimal() {
assert_eq!(parse_number("12345"), Ok(12345));
}
#[test]
fn parse_hex() {
assert_eq!(parse_number("0x123abc"), Ok(0x123abc));
}
#[test]
fn parse_invalid() {
assert!(parse_number("123abc").is_err());
}
}