use crate::register::{SysReg, SysRegRead, SysRegWrite};
use arbitrary_int::{u2, u25, u3, u4, u6};
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
pub struct Hsr {
#[bits(26..=31, rw)]
ec: Option<ExceptionClass>,
#[bit(25, rw)]
il: InstructionLength,
#[bits(0..=24, rw)]
iss: u25,
}
impl Hsr {
pub fn get_iss(&self) -> Option<Iss> {
if let Ok(ec) = self.ec() {
Some(ec.decode_iss(self.iss()))
} else {
None
}
}
}
#[bitbybit::bitenum(u6, exhaustive = false)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, PartialEq, Eq)]
pub enum ExceptionClass {
Unknown = 0b00_0000,
TrappedWfiWfe = 0b00_0001,
TrappedCp15McrMrc = 0b00_0011,
TrappedCp15McrrMrrc = 0b00_0100,
TrappedCp14McrMrc = 0b00_0101,
TrappedLdcStc = 0b00_0110,
TrappedFpu = 0b00_0111,
TrappedVmrs = 0b00_1000,
TrappedCp14McrrMrrc = 0b00_1100,
IllegalAArch32Eret = 0b00_1110,
Svc = 0b01_0001,
Hvc = 0b01_0010,
Smc = 0b01_0011,
PrefetchAbortFromLower = 0b10_0000,
PrefetchAbortFromCurrent = 0b10_0001,
PcAlignment = 0b10_0010,
DataAbortFromLower = 0b10_0100,
DataAbortFromCurrent = 0b10_0101,
}
#[derive(Debug, Clone)]
pub enum Iss {
Unknown(IssUnknown),
TrappedWfiWfe(IssTrappedWfiWfe),
TrappedCp15McrMrc(IssTrappedMcrMrc),
TrappedCp15McrrMrrc(IssTrappedMcrrMrrc),
TrappedCp14McrMrc(IssTrappedMcrMrc),
TrappedLdcStc(IssTrappedLdcStc),
TrappedFpu(IssTrappedFpu),
TrappedVmrs(IssTrappedVmrs),
TrappedCp14McrrMrrc(IssTrappedMcrrMrrc),
IllegalAArch32Eret,
Svc(IssCall),
Hvc(IssCall),
Smc(IssSmc),
PrefetchAbortFromLower(IssPrefetchAbort),
PrefetchAbortFromCurrent(IssPrefetchAbort),
PcAlignment,
DataAbortFromLower(IssDataAbort),
DataAbortFromCurrent(IssDataAbort),
}
impl ExceptionClass {
pub fn decode_iss(&self, iss: u25) -> Iss {
match self {
ExceptionClass::Unknown => Iss::Unknown(IssUnknown(iss.value())),
ExceptionClass::TrappedWfiWfe => {
Iss::TrappedWfiWfe(IssTrappedWfiWfe::new_with_raw_value(iss))
}
ExceptionClass::TrappedCp15McrMrc => {
Iss::TrappedCp15McrMrc(IssTrappedMcrMrc::new_with_raw_value(iss))
}
ExceptionClass::TrappedCp15McrrMrrc => {
Iss::TrappedCp15McrrMrrc(IssTrappedMcrrMrrc::new_with_raw_value(iss))
}
ExceptionClass::TrappedCp14McrMrc => {
Iss::TrappedCp14McrMrc(IssTrappedMcrMrc::new_with_raw_value(iss))
}
ExceptionClass::TrappedLdcStc => {
Iss::TrappedLdcStc(IssTrappedLdcStc::new_with_raw_value(iss))
}
ExceptionClass::TrappedFpu => Iss::TrappedFpu(IssTrappedFpu::new_with_raw_value(iss)),
ExceptionClass::TrappedVmrs => Iss::TrappedVmrs(IssTrappedVmrs(iss.value())),
ExceptionClass::TrappedCp14McrrMrrc => {
Iss::TrappedCp14McrrMrrc(IssTrappedMcrrMrrc::new_with_raw_value(iss))
}
ExceptionClass::IllegalAArch32Eret => Iss::IllegalAArch32Eret,
ExceptionClass::Svc => Iss::Svc(IssCall::new_with_raw_value(iss)),
ExceptionClass::Hvc => Iss::Hvc(IssCall::new_with_raw_value(iss)),
ExceptionClass::Smc => Iss::Smc(IssSmc(iss.value())),
ExceptionClass::PrefetchAbortFromLower => {
Iss::PrefetchAbortFromLower(IssPrefetchAbort::new_with_raw_value(iss))
}
ExceptionClass::PrefetchAbortFromCurrent => {
Iss::PrefetchAbortFromCurrent(IssPrefetchAbort::new_with_raw_value(iss))
}
ExceptionClass::PcAlignment => Iss::PcAlignment,
ExceptionClass::DataAbortFromLower => {
Iss::DataAbortFromLower(IssDataAbort::new_with_raw_value(iss))
}
ExceptionClass::DataAbortFromCurrent => {
Iss::DataAbortFromCurrent(IssDataAbort::new_with_raw_value(iss))
}
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct IssUnknown(pub u32);
#[bitbybit::bitfield(u25, debug, defmt_bitfields(feature = "defmt"))]
pub struct IssTrappedWfiWfe {
#[bit(24, r)]
cv: bool,
#[bits(20..=23, r)]
cc: u4,
#[bit(0, r)]
ti: bool,
}
#[bitbybit::bitfield(u25, debug, defmt_bitfields(feature = "defmt"))]
pub struct IssTrappedMcrMrc {
#[bit(24, r)]
cv: bool,
#[bits(20..=23, r)]
cc: u4,
#[bits(17..=19, r)]
opc2: u3,
#[bits(14..=16, r)]
opc1: u3,
#[bits(10..=13, r)]
crn: u4,
#[bits(5..=8, r)]
rt: u4,
#[bits(1..=4, r)]
crm: u4,
#[bit(0, r)]
is_read: bool,
}
#[bitbybit::bitfield(u25, debug, defmt_bitfields(feature = "defmt"))]
pub struct IssTrappedMcrrMrrc {
#[bit(24, r)]
cv: bool,
#[bits(20..=23, r)]
cc: u4,
#[bits(16..=19, r)]
opc2: u4,
#[bits(10..=13, r)]
rt2: u4,
#[bits(5..=8, r)]
rt: u4,
#[bits(1..=4, r)]
crm: u4,
#[bit(0, r)]
is_read: bool,
}
#[bitbybit::bitfield(u25, debug, defmt_bitfields(feature = "defmt"))]
pub struct IssTrappedLdcStc {
#[bit(24, r)]
cv: bool,
#[bits(20..=23, r)]
cc: u4,
#[bits(12..=19, r)]
imm8: u8,
#[bits(5..=8, r)]
rn: u4,
#[bit(4, r)]
offset: bool,
#[bits(1..=3, r)]
am: u3,
#[bit(0, r)]
is_read: bool,
}
#[bitbybit::bitfield(u25, debug, defmt_bitfields(feature = "defmt"))]
pub struct IssTrappedFpu {
#[bit(24, r)]
cv: bool,
#[bits(20..=23, r)]
cc: u4,
#[bit(5, r)]
ta: bool,
#[bits(0..=3, r)]
coproc: u4,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct IssTrappedVmrs(pub u32);
#[bitbybit::bitfield(u25, debug, defmt_bitfields(feature = "defmt"))]
pub struct IssCall {
#[bits(0..=15, r)]
imm16: u16,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct IssSmc(pub u32);
#[bitbybit::bitfield(u25, debug, defmt_bitfields(feature = "defmt"))]
pub struct IssPrefetchAbort {
#[bit(10, r)]
fnv: bool,
#[bit(9, r)]
ea: bool,
#[bits(0..=5, r)]
ifsc: u6,
}
#[bitbybit::bitfield(u25, debug, defmt_bitfields(feature = "defmt"))]
pub struct IssDataAbort {
#[bit(24, r)]
isv: bool,
#[bits(22..=23, r)]
sas: u2,
#[bit(21, r)]
sae: bool,
#[bits(16..=19, r)]
srt: u4,
#[bit(14, r)]
ar: bool,
#[bit(10, r)]
fnv: bool,
#[bit(9, r)]
ea: bool,
#[bit(8, r)]
cm: bool,
#[bit(6, r)]
wnr: bool,
#[bits(0..=5, r)]
dfsc: u6,
}
#[bitbybit::bitenum(u1, exhaustive = true)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, PartialEq, Eq)]
pub enum InstructionLength {
SixteenBit = 0b0,
ThirtyTwoBit = 0b1,
}
impl SysReg for Hsr {
const CP: u32 = 15;
const CRN: u32 = 5;
const OP1: u32 = 4;
const CRM: u32 = 2;
const OP2: u32 = 0;
}
impl crate::register::SysRegRead for Hsr {}
impl Hsr {
#[inline]
pub fn read() -> Hsr {
Self::new_with_raw_value(<Self as SysRegRead>::read_raw())
}
}
impl crate::register::SysRegWrite for Hsr {}
impl Hsr {
#[inline]
pub unsafe fn write(value: Self) {
unsafe {
<Self as SysRegWrite>::write_raw(value.raw_value());
}
}
}