use cores::open_core_name;
use err::{CoreNameError, VendorError};
mod cores;
pub mod err;
mod vendors;
static MAX_JEDEC_COMPANY_ID_BANK: u32 = 1 << 25;
static MAX_JEDEC_COMPANY_ID_OFFSET: u8 = (1 << 7) - 2;
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct Manufacturer {
bank: u32,
offset: u8,
name: &'static str,
}
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub enum Vendor {
NonCommercial,
Commercial(Manufacturer),
}
impl Vendor {
#[must_use]
#[deprecated(since = "0.1.2", note = "please use `to_string()` instead")]
pub const fn name(&self) -> &'static str {
match self {
Self::NonCommercial => "Non-Commercial",
Self::Commercial(m) => m.name,
}
}
}
impl TryFrom<u32> for Vendor {
type Error = VendorError;
fn try_from(mvendorid: u32) -> Result<Self, Self::Error> {
if mvendorid == 0 {
return Ok(Self::NonCommercial);
}
let bank = (mvendorid >> 7) + 1;
let offset = (mvendorid << 25 >> 25) as u8;
if offset > MAX_JEDEC_COMPANY_ID_OFFSET {
return Err(VendorError::InvalidOffset(offset));
}
vendors::jedec_company_name(bank, offset)
.map(|name| Manufacturer { bank, offset, name })
.map(Vendor::Commercial)
}
}
macro_rules! try_from_int_impl_for_vendor {
($t:tt) => {
impl TryFrom<$t> for Vendor {
type Error = VendorError;
fn try_from(mvendorid: $t) -> Result<Self, Self::Error> {
match u32::try_from(mvendorid) {
Ok(v) => Vendor::try_from(v),
Err(_) => {
let bank = (mvendorid >> 7 << 7) + 1;
Err(VendorError::InvalidBank(bank as u32))
}
}
}
}
};
}
try_from_int_impl_for_vendor!(u8);
try_from_int_impl_for_vendor!(u16);
try_from_int_impl_for_vendor!(u64);
try_from_int_impl_for_vendor!(u128);
try_from_int_impl_for_vendor!(usize);
try_from_int_impl_for_vendor!(i16);
try_from_int_impl_for_vendor!(i32);
try_from_int_impl_for_vendor!(i64);
try_from_int_impl_for_vendor!(i128);
try_from_int_impl_for_vendor!(isize);
macro_rules! from_vendor_impl_for_int {
($t:tt) => {
impl From<Vendor> for $t {
fn from(value: Vendor) -> Self {
match value {
Vendor::NonCommercial => 0,
Vendor::Commercial(manufacturer) => {
$t::from((manufacturer.bank - 1) << 7) + $t::from(manufacturer.offset)
}
}
}
}
};
}
from_vendor_impl_for_int!(u32);
from_vendor_impl_for_int!(u64);
from_vendor_impl_for_int!(u128);
from_vendor_impl_for_int!(i64);
from_vendor_impl_for_int!(i128);
impl core::fmt::Display for Vendor {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
match self {
Self::NonCommercial => write!(f, "Non-Commercial"),
Self::Commercial(m) => write!(f, "{}", m.name),
}
}
}
pub const fn core_name_rv32(vendor: Vendor, marchid: u32) -> Result<&'static str, CoreNameError> {
if marchid == 0 {
return Err(CoreNameError::ZeroedMarchid(marchid as u64));
}
if marchid >> 31 == 0 {
return open_core_name(marchid as u64);
}
match vendor {
Vendor::NonCommercial => Err(CoreNameError::MismatchedInput(vendor, marchid as u64)),
Vendor::Commercial(..) => {
Err(CoreNameError::NoKnownNamesForVendor(vendor))
}
}
}
pub const fn core_name_rv64(vendor: Vendor, marchid: u64) -> Result<&'static str, CoreNameError> {
if marchid == 0 {
return Err(CoreNameError::ZeroedMarchid(marchid));
}
if marchid >> 63 == 0 {
return open_core_name(marchid);
}
match vendor {
Vendor::NonCommercial => Err(CoreNameError::MismatchedInput(vendor, marchid)),
Vendor::Commercial(..) => {
Err(CoreNameError::NoKnownNamesForVendor(vendor))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn int_to_vendor() {
assert_eq!(Vendor::try_from(0), Ok(Vendor::NonCommercial));
assert_eq!(
Vendor::try_from(1),
Ok(Vendor::Commercial(Manufacturer {
bank: 1,
offset: 1,
name: "AMD",
}))
);
assert_eq!(
Vendor::try_from(0xFF),
Err(VendorError::InvalidOffset(0x7F))
);
assert_eq!(
Vendor::try_from(u32::MAX - 2),
Err(VendorError::UnknownBank(0x2000000))
);
assert_eq!(
Vendor::try_from(u64::MAX - 2),
Err(VendorError::InvalidBank(0xFFFFFF81))
);
}
#[test]
fn vendor_to_int() {
assert_eq!(Vendor::try_from(0).map(u32::from), Ok(0));
assert_eq!(
Vendor::try_from((1 << 7) + 1).map(u32::from),
Ok((1 << 7) + 1)
);
}
#[test]
fn implementer_display() {
assert_eq!(Vendor::NonCommercial.to_string(), "Non-Commercial");
assert_eq!(
Vendor::try_from(1).map(|v| v.to_string()),
Ok("AMD".to_string())
);
}
#[test]
fn core_name_32bit() {
assert_eq!(
core_name_rv32(Vendor::NonCommercial, 0),
Err(CoreNameError::ZeroedMarchid(0)),
);
assert_eq!(
core_name_rv32(Vendor::NonCommercial, 1 << 31),
Err(CoreNameError::MismatchedInput(
Vendor::NonCommercial,
1 << 31
))
);
assert!(matches!(
core_name_rv32(Vendor::try_from(1).unwrap(), 1 << 31),
Err(CoreNameError::NoKnownNamesForVendor(_))
));
assert_eq!(core_name_rv32(Vendor::NonCommercial, 1), Ok("Rocket"));
}
#[test]
fn core_name_64bit() {
assert_eq!(
core_name_rv64(Vendor::NonCommercial, 0),
Err(CoreNameError::ZeroedMarchid(0)),
);
assert_eq!(
core_name_rv64(Vendor::NonCommercial, 1 << 63),
Err(CoreNameError::MismatchedInput(
Vendor::NonCommercial,
1 << 63
))
);
assert!(matches!(
core_name_rv64(Vendor::try_from(1).unwrap(), 1 << 63),
Err(CoreNameError::NoKnownNamesForVendor(_))
));
assert_eq!(core_name_rv64(Vendor::NonCommercial, 1), Ok("Rocket"));
}
}