1#![allow(dead_code)]
2#![allow(non_snake_case)]
3
4use std::collections::HashMap;
5use std::fmt::Binary;
6use std::fmt::Display;
7use std::fmt::Debug;
8
9use crate::fmt::addr::Addr;
10
11
12#[derive(Debug, Clone)]
14pub struct ExceptionFrame {
15 r0: u32,
18 r1: u32,
19 r2: u32,
20 r3: u32,
21 r12: u32,
23 lr: Addr<u32>,
25 pc: Addr<u32>,
28
29 psr: PSR,
37
38 cfsr: CFSR,
42
43 hfsr: HSFR,
45
46 mmfar: Addr<u32>,
51
52 bfar: Addr<u32>,
59
60 rcccsr: u32,
62}
63
64
65pub const SCB_CPACR_FPU_MASK: u32 = 0b11_11 << 20;
66pub const SCB_CPACR_FPU_ENABLE: u32 = 0b01_01 << 20;
67pub const SCB_CPACR_FPU_USER: u32 = 0b10_10 << 20;
68
69impl ExceptionFrame {
70 pub fn ufsr(&self) -> UFSR { self.cfsr.ufsr() }
71 pub fn bfsr(&self) -> BFSR { self.cfsr.bfsr() }
72 pub fn mmfsr(&self) -> MMFSR { self.cfsr.mmfsr() }
73}
74
75
76impl ExceptionFrame {
77 pub fn new_from(values: &HashMap<String, Addr<u32>>) -> Result<Self, &'static str> {
78 Ok(Self { r0: values.get("r0").ok_or("no r0")?.value(),
79 r1: values.get("r1").ok_or("no r1")?.value(),
80 r2: values.get("r2").ok_or("no r2")?.value(),
81 r3: values.get("r3").ok_or("no r3")?.value(),
82 r12: values.get("r12").ok_or("no r12")?.value(),
83 lr: values.get("lr").ok_or("no lr")?.to_owned(),
84 pc: values.get("pc").ok_or("no pc")?.to_owned(),
85 psr: values.get("psr").ok_or("no psr")?.value().into(),
86 cfsr: values.get("cfsr").ok_or("no cfsr")?.value().into(),
87 hfsr: values.get("hfsr").ok_or("no hfsr")?.value().into(),
88 mmfar: values.get("mmfar").ok_or("no mmfar")?.to_owned(),
89 bfar: values.get("bfar").ok_or("no bfar")?.to_owned(),
90 rcccsr: values.get("rcccsr").ok_or("no rcccsr")?.value().into() })
91 }
92}
93
94
95macro_rules! bit {
96 ($mask:literal, $name:ident.$field:ident, $doc:literal) => {
97 impl $name {
98 bit! {$mask, $field, $doc}
99 }
100 };
101 ($mask:literal, $name:ident) => {
102 pub fn $name(&self) -> bool { self.0 & $mask != 0 }
103
104 paste::paste! {
105 pub const [<DOC_ $name>]: &'static str = stringify!($name);
106 }
107 };
108 ($mask:literal, $name:ident, $doc:literal) => {
109 #[doc = $doc]
110 pub fn $name(&self) -> bool { self.0 & $mask != 0 }
111
112 paste::paste! {
113 pub const [<DOC_ $name>]: &'static str = $doc;
114 }
115 };
116
117 ($name:ident, $mask:literal) => {
118 bit!($mask, $name)
119 };
120 ($name:ident, $mask:literal, $doc:literal) => {
121 bit!($mask, $name, $doc)
122 };
123}
124
125
126macro_rules! impl_fmt {
127 ($name:ident) => {
128 impl Display for $name {
129 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { Display::fmt(&self.0, f) }
130 }
131 impl Binary for $name {
132 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { Binary::fmt(&self.0, f) }
133 }
134 };
135
136 ($name:ident, $($next:ident),+) => {
137 impl_fmt!($name);
138 impl_fmt!($($next),+);
139 }
140 }
141
142
143macro_rules! impl_from {
144 ($name:ident<u8>) => {
145 impl_from! {impl $name<u8>}
146 impl_from! {impl $name<i8>}
147 };
148 ($name:ident<u16>) => {
149 impl_from! {impl $name<u16>}
150 impl_from! {impl $name<i16>}
151 impl_from! {$name<u8>}
152 };
153 ($name:ident<u32>) => {
154 impl_from! {impl $name<u32>}
155 impl_from! {impl $name<i32>}
156 impl_from! {$name<u16>}
157 };
158 ($name:ident<u64>) => {
159 impl_from! {impl $name<u64>}
160 impl_from! {impl $name<i64>}
161 impl_from! {$name<u32>}
162 };
163 ($name:ident) => {
164 impl_from! {$name<u32>}
165 };
166
167 (impl $name:ident<$t:ty>) => {
168 impl From<$t> for $name {
169 fn from(value: $t) -> Self { Self(value as _) }
170 }
171 };
172}
173
174macro_rules! impl_try_from {
175 ($name:ident<u8>) => {
176 impl_try_from! {impl $name<u8, u16>}
177 impl_try_from! {impl $name<u8, u32>}
178 impl_try_from! {impl $name<u8, u64>}
179 };
180 ($name:ident<u16>) => {
181 impl_try_from! {impl $name<u8, u32>}
182 impl_try_from! {impl $name<u8, u64>}
183 };
184 ($name:ident<u32>) => {
185 impl_try_from! {impl $name<u8, u64>}
186 };
187 ($name:ident<u64>) => {};
188 ($name:ident) => {
189 impl_try_from! {$name<u32>}
190 };
191
192 (impl $name:ident<$t:ty, $th:ty>) => {
193 impl TryFrom<$th> for $name
194 where $t: TryFrom<$th>,
195 Self: From<$t>
196 {
197 type Error = <$t as TryFrom<$th>>::Error;
198 fn try_from(value: $th) -> Result<Self, Self::Error> {
199 let value: $t = value.try_into()?;
200 Ok(Self::from(value))
201 }
202 }
203 };
204}
205
206macro_rules! impl_to {
207 ($name:ident<u8>) => {
208 impl_to! {impl $name<u8>}
209 impl_to! {impl $name<i8>}
210 impl_to! {$name<u16>}
211 };
212 ($name:ident<u16>) => {
213 impl_to! {impl $name<u16>}
214 impl_to! {impl $name<i16>}
215 impl_to! {$name<u32>}
216 };
217 ($name:ident<u32>) => {
218 impl_to! {impl $name<u32>}
219 impl_to! {impl $name<i32>}
220 impl_to! {$name<u64>}
221 };
222 ($name:ident<u64>) => {
223 impl_to! {impl $name<u64>}
224 impl_to! {impl $name<i64>}
225 };
226 ($name:ident) => {
227 impl_to! {$name<u32>}
228 };
229
230 (impl $name:ident<$t:ty>) => {
231 impl From<$name> for $t {
232 fn from(value: $name) -> Self { value.0 as _ }
233 }
234 };
235}
236
237macro_rules! impl_convert {
238 ($name:ident<u8>) => {
239 impl_to! {$name<u8>}
240 impl_from! {$name<u8>}
241 impl_try_from! {$name<u8>}
242 };
243 ($name:ident<u16>) => {
244 impl_to! {$name<u16>}
245 impl_from! {$name<u16>}
246 impl_try_from! {$name<u16>}
247 };
248 ($name:ident<u32>) => {
249 impl_to! {$name<u32>}
250 impl_from! {$name<u32>}
251 impl_try_from! {$name<u32>}
252 };
253 ($name:ident<u64>) => {
254 impl_to! {$name<u64>}
255 impl_from! {$name<u64>}
256 impl_try_from! {$name<u64>}
257 };
258 ($name:ident) => {
259 impl_convert! {$name<u32>}
260 };
261}
262
263macro_rules! impl_reg {
264 ($name:ident) => {
265 impl_reg!{$name<u32>}
266 };
267 ($name:ident<$t:ty>) => {
268 impl_fmt!{$name}
269 };
270
271 ($name:ident$(<$t:ty>)?, $($next:ident$(<$tn:ty>)?),+) => {
272 impl_reg!($name$(<$t>)?);
273 impl_reg!($($next$(<$tn>)?),+);
274 }
275 }
276
277impl_reg! {PSR, IPSR<u16>, APSR<u16>, EPSR, CFSR, UFSR<u16>, BFSR<u8>, MMFSR<u8>, HSFR}
278impl_convert! { PSR }
279impl_convert! { IPSR<u16> }
280impl_convert! { APSR<u16> }
281impl_convert! { EPSR }
282impl_convert! { CFSR }
283impl_convert! { UFSR<u16> }
284impl_convert! { BFSR<u8> }
285impl_convert! { MMFSR<u8> }
286impl_convert! { HSFR }
287
288#[derive(Clone, Copy, PartialEq, Eq)]
298pub struct PSR(u32);
299
300impl PSR {
301 pub fn apsr(&self) -> APSR { APSR(((self.0 & 0b11111000_00000111_00000000_00000000) >> 16) as u16) }
302 pub fn ipsr(&self) -> IPSR { IPSR((self.0 & 0b00000000_00000000_00000001_11111111) as u16) }
303 pub fn epsr(&self) -> EPSR { EPSR(self.0 & 0b00000111_00000000_11111100_00000000) }
304}
305
306impl Debug for PSR {
307 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
308 f.debug_struct("PSR")
309 .field("APSR", &self.apsr())
310 .field("IPSR", &self.ipsr())
311 .field("EPSR", &self.epsr())
312 .finish()
313 }
314}
315
316
317#[derive(Clone, Copy, PartialEq, Eq)]
319pub struct APSR(u16);
320bit! {0b1000_0000_00000000, APSR.N, r#"Negative"#}
321bit! {0b0100_0000_00000000, APSR.Z, r#"Zero"#}
322bit! {0b0010_0000_00000000, APSR.C, r#"Carry or borrow"#}
323bit! {0b0001_0000_00000000, APSR.V, r#"Overflow"#}
324bit! {0b0000_1000_00000000, APSR.Q, r#"DSP overflow and saturation"#}
325bit! {0b0000_0000_00000111, APSR.GE, r#"Greater than or Equals"#}
326impl Debug for APSR {
327 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
328 f.debug_struct("APSR")
329 .field("N", &self.N())
330 .field("Z", &self.Z())
331 .field("C", &self.C())
332 .field("V", &self.V())
333 .field("Q", &self.Q())
334 .field("GE", &self.GE())
335 .finish()
336 }
337}
338impl RegTags for APSR {
339 fn is_empty(&self) -> bool { self.0 == 0 }
340
341 fn tags(&self) -> impl IntoIterator<Item = (&str, &str)> {
342 if !self.is_empty() {
343 [
344 self.N().then_some(("N", Self::DOC_N)),
345 self.Z().then_some(("Z", Self::DOC_Z)),
346 self.C().then_some(("C", Self::DOC_C)),
347 self.V().then_some(("V", Self::DOC_V)),
348 self.Q().then_some(("Q", Self::DOC_Q)),
349 self.GE().then_some(("GE", Self::DOC_GE)),
350 ].into_iter()
351 .flatten()
352 } else {
353 <[_; 6]>::default().into_iter().flatten()
354 }
355 }
356}
357
358#[derive(Clone, Copy, PartialEq, Eq)]
360pub struct IPSR(u16);
361bit! {0b0000_0000_00000001, IPSR.TM, r#"Thread mode"#}
362bit! {0b0000_0000_00000100, IPSR.NMI, r#"NMI"#}
363bit! {0b0000_0000_00001000, IPSR.HF, r#"HardFault"#}
364bit! {0b0000_0000_00010000, IPSR.MM, r#"MemManage"#}
365bit! {0b0000_0000_00100000, IPSR.BF, r#"BusFault"#}
366bit! {0b0000_0000_01000000, IPSR.UF, r#"UsageFault"#}
367impl Debug for IPSR {
368 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
369 f.debug_struct("IPSR")
370 .field("TM", &self.TM())
371 .field("NMI", &self.NMI())
372 .field("HF", &self.HF())
373 .field("MM", &self.MM())
374 .field("BF", &self.BF())
375 .field("UF", &self.UF())
376 .finish()
377 }
378}
379impl RegTags for IPSR {
380 fn is_empty(&self) -> bool { self.0 == 0 }
381
382 fn tags(&self) -> impl IntoIterator<Item = (&str, &str)> {
383 if !self.is_empty() {
384 [
385 self.TM().then_some(("TM", Self::DOC_TM)),
386 self.NMI().then_some(("NMI", Self::DOC_NMI)),
387 self.HF().then_some(("HF", Self::DOC_HF)),
388 self.MM().then_some(("MM", Self::DOC_MM)),
389 self.BF().then_some(("BF", Self::DOC_BF)),
390 self.UF().then_some(("UF", Self::DOC_UF)),
391 ].into_iter()
392 .flatten()
393 } else {
394 <[_; 6]>::default().into_iter().flatten()
395 }
396 }
397}
398
399#[derive(Clone, Copy, PartialEq, Eq)]
401pub struct EPSR(u32);
402bit! {0b00000110_00000000_00001100_00000000, EPSR.IS_NOT_ICI, r#"Interruptible-continuable instruction bits."#}
403bit! {0b00000000_00000000_11110000_00000000, EPSR.ICI, r#"Interruptible-continuable instruction bits."#}
404bit! {0b00000110_00000000_11111100_00000000, EPSR.IT, r#"If-Then block. Indicates the execution state bits of the IT instruction"#}
405bit! {0b00000001_00000000_00000000_00000000, EPSR.T, r#"Thumb state"#}
406impl Debug for EPSR {
407 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
408 f.debug_struct("EPSR")
409 .field("IS_NOT_ICI", &self.IS_NOT_ICI())
410 .field("ICI", &self.ICI())
411 .field("IT", &self.IT())
412 .field("T", &self.T())
413 .finish()
414 }
415}
416impl RegTags for EPSR {
417 fn is_empty(&self) -> bool { self.0 == 0 }
418
419 fn tags(&self) -> impl IntoIterator<Item = (&str, &str)> {
420 if !self.is_empty() {
421 [
422 self.IS_NOT_ICI().then_some(("IS_NOT_ICI", Self::DOC_IS_NOT_ICI)),
423 self.ICI().then_some(("ICI", Self::DOC_ICI)),
424 self.IT().then_some(("IT", Self::DOC_IT)),
425 self.T().then_some(("T", Self::DOC_T)),
426 ].into_iter()
427 .flatten()
428 } else {
429 <[_; 4]>::default().into_iter().flatten()
430 }
431 }
432}
433
434
435#[derive(Clone, Copy, PartialEq, Eq)]
439pub struct HSFR(u32);
440impl HSFR {
441 bit! {0b00000000_00000000_00000000_00000010, VECTTBL, r#"Bus Fault on vector table read."#}
444 bit! {0b01000000_00000000_00000000_00000000, FORCED, r#"Forced Hard Fault."#}
445 bit! {0b10000000_00000000_00000000_00000000, DEBUGEVT, r#"Reserved for Debug use."#}
446}
447impl Debug for HSFR {
448 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
449 f.debug_struct("HSFR")
450 .field("VECTTBL", &self.VECTTBL())
451 .field("FORCED", &self.FORCED())
452 .field("DEBUGEVT", &self.DEBUGEVT())
453 .finish()
454 }
455}
456impl RegTags for HSFR {
457 fn is_empty(&self) -> bool { self.0 == 0 }
458
459 fn tags(&self) -> impl IntoIterator<Item = (&str, &str)> {
460 if !self.is_empty() {
461 [
462 self.VECTTBL().then_some(("VECTTBL", Self::DOC_VECTTBL)),
463 self.FORCED().then_some(("FORCED", Self::DOC_FORCED)),
464 self.DEBUGEVT().then_some(("DEBUGEVT", Self::DOC_DEBUGEVT)),
465 ].into_iter()
466 .flatten()
467 } else {
468 <[_; 3]>::default().into_iter().flatten()
469 }
470 }
471}
472
473
474#[derive(Clone, Copy, PartialEq, Eq)]
478pub struct CFSR(u32);
479
480impl CFSR {
481 pub fn ufsr(&self) -> UFSR { UFSR(((self.0 & 0b11111111_11111111_00000000_00000000) >> 16) as u16) }
482 pub fn bfsr(&self) -> BFSR { BFSR(((self.0 & 0b00000000_00000000_11111111_00000000) >> 8) as u8) }
483 pub fn mmfsr(&self) -> MMFSR { MMFSR(self.0 as u8) }
484}
485
486impl Debug for CFSR {
487 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
488 f.debug_struct("CFSR")
489 .field("UFSR", &self.ufsr())
490 .field("BFSR", &self.bfsr())
491 .field("MMFSR", &self.mmfsr())
492 .finish()
493 }
494}
495
496
497#[derive(Clone, Copy, PartialEq, Eq)]
499pub struct UFSR(u16);
500impl UFSR {
501 bit! {0b0000_0000_0000_0001, UNDEFINSTR, r#"Undefined instruction."#}
502 bit! {0b0000_0000_0000_0010, INVSTATE, r#"Invalid state."#}
503 bit! {0b0000_0000_0000_0100, INVPC, r#"Invalid `PC` load UsageFault, caused by an invalid `EXC_RETURN` value."#}
504 bit! {0b0000_0000_0000_1000, NOCP, r#"No coprocessor."#}
505 bit! {0b0000_0001_0000_0000, UNALIGNED, r#"Unaligned access UsageFault."#}
506 bit! {0b0010_0000, DIVBYZERO, r#"Divide by zero UsageFault."#}
507}
508
509
510impl RegTags for UFSR {
511 fn is_empty(&self) -> bool { self.0 == 0 }
512
513 fn tags(&self) -> impl IntoIterator<Item = (&str, &str)> {
514 if self.is_empty() {
515 return [None, None, None, None, None, None].into_iter().flatten();
516 }
517
518 [
519 self.UNDEFINSTR().then_some(("UNDEFINSTR", Self::DOC_UNDEFINSTR)),
520 self.INVSTATE().then_some(("INVSTATE", Self::DOC_INVSTATE)),
521 self.INVPC().then_some(("INVPC", Self::DOC_INVPC)),
522 self.NOCP().then_some(("NOCP", Self::DOC_NOCP)),
523 self.UNALIGNED().then_some(("UNALIGNED", Self::DOC_UNALIGNED)),
524 self.DIVBYZERO().then_some(("DIVBYZERO", Self::DOC_DIVBYZERO)),
525 ].into_iter()
526 .flatten()
527 }
528}
529
530impl Debug for UFSR {
531 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
532 f.debug_struct("UFSR")
533 .field("UNDEFINSTR", &self.UNDEFINSTR())
534 .field("INVSTATE", &self.INVSTATE())
535 .field("INVPC", &self.INVPC())
536 .field("NOCP", &self.NOCP())
537 .field("UNALIGNED", &self.UNALIGNED())
538 .field("DIVBYZERO", &self.DIVBYZERO())
539 .finish()
540 }
541}
542
543
544#[derive(Clone, Copy, PartialEq, Eq)]
547pub struct BFSR(u8);
548impl BFSR {
549 bit! {0b0000_0001, IBUSERR, r#"Instruction bus error. Records whether a BusFault on an instruction prefetch has occurred."#}
550 bit! {0b0000_0010, PRECISERR, r#"Precise data bus error."#}
551 bit! {0b0000_0100, IMPRECISERR, r#"Imprecise data bus error."#}
552 bit! {0b0000_1000, UNSTKERR, r#"BusFault on unstacking for a return from exception."#}
553 bit! {0b0001_0000, STKERR, r#"BusFault on stacking for exception entry."#}
554 bit! {0b0010_0000, LSPERR, r#"BusFault during floating point lazy state preservation (only when FPU present)."#}
555 bit! {0b1000_0000, BFARVALID, r#"BusFault Address Register valid flag. BFAR holds a valid fault address."#}
556}
557impl Debug for BFSR {
558 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
559 f.debug_struct("BFSR")
560 .field("IBUSERR", &self.IBUSERR())
561 .field("PRECISERR", &self.PRECISERR())
562 .field("IMPRECISERR", &self.IMPRECISERR())
563 .field("UNSTKERR", &self.UNSTKERR())
564 .field("STKERR", &self.STKERR())
565 .field("LSPERR", &self.LSPERR())
566 .field("BFARVALID", &self.BFARVALID())
567 .finish()
568 }
569}
570impl RegTags for BFSR {
571 fn is_empty(&self) -> bool { self.0 == 0 }
572
573 fn tags(&self) -> impl IntoIterator<Item = (&str, &str)> {
574 if !self.is_empty() {
575 [
576 self.IBUSERR().then_some(("IBUSERR", Self::DOC_IBUSERR)),
577 self.PRECISERR().then_some(("PRECISERR", Self::DOC_PRECISERR)),
578 self.IMPRECISERR()
579 .then_some(("IMPRECISERR", Self::DOC_IMPRECISERR)),
580 self.UNSTKERR().then_some(("UNSTKERR", Self::DOC_UNSTKERR)),
581 self.STKERR().then_some(("STKERR", Self::DOC_STKERR)),
582 self.LSPERR().then_some(("LSPERR", Self::DOC_LSPERR)),
583 ].into_iter()
584 .flatten()
585 } else {
586 <[_; 6]>::default().into_iter().flatten()
587 }
588 }
589}
590
591
592#[derive(Clone, Copy, PartialEq, Eq)]
595pub struct MMFSR(u8);
596impl Debug for MMFSR {
597 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
598 f.debug_struct("MMFSR")
599 .field("IACCVIOL", &self.IACCVIOL())
600 .field("DACCVIOL", &self.DACCVIOL())
601 .field("MUNSTKERR", &self.MUNSTKERR())
602 .field("MSTKERR", &self.MSTKERR())
603 .field("MLSPERR", &self.MLSPERR())
604 .field("MMARVALID", &self.MMARVALID())
605 .finish()
606 }
607}
608impl MMFSR {
609 bit! {0b0000_0001, IACCVIOL, r#"Instruction access violation.
620 The processor attempted an instruction fetch from a location that does not permit execution.
621 Faulting instruction: see `PC`.
622 "#}
623
624 bit! {0b0000_0010, DACCVIOL, r#"Data access violation.
630 The processor attempted a load or store at a location that does not permit the operation.
631 Faulting instruction: see `PC`.
632 Address of the attempted access: see `MMFAR`.
633 "#}
634
635 bit! {0b0000_1000, MUNSTKERR, r#"MemManage fault on unstacking for a return from exception.
645 Fault address - see MMFAR.
646 Potential reasons:
647 - Stack pointer is corrupted
648 - MPU region for the stack changed during execution of the exception handler
649 "#}
650
651
652 bit! {0b0001_0000, MSTKERR, r#"
653 MemManage fault on stacking for exception entry.
654
655 The SP is still adjusted but the values in the context area on the stack might be incorrect. The
656 processor has not written a fault address to the MMFAR. Potential reasons:
657 - Stack pointer is corrupted or not initialized
658 - Stack is reaching a region not defined by the MPU as read/write memory.
659 "#}
660
661 bit! {0b0010_0000, MLSPERR, r#"MemManage fault during floating point lazy state preservation (only Cortex-M4 with FPU)."#}
662 bit! {0b1000_0000, MMARVALID, r#"MemManage Fault Address Register (MMFAR) valid flag. SCB->MMFAR holds a valid fault address."#}
663}
664
665impl RegTags for MMFSR {
666 fn is_empty(&self) -> bool { self.0 == 0 }
667
668 fn tags(&self) -> impl IntoIterator<Item = (&str, &str)> {
669 if self.is_empty() {
670 return [None, None, None, None, None].into_iter().flatten();
671 }
672
673 [
674 self.IACCVIOL().then_some(("IACCVIOL", Self::DOC_IACCVIOL)),
675 self.DACCVIOL().then_some(("DACCVIOL", Self::DOC_DACCVIOL)),
676 self.MUNSTKERR().then_some(("MUNSTKERR", Self::DOC_MUNSTKERR)),
677 self.MSTKERR().then_some(("MSTKERR", Self::DOC_MSTKERR)),
678 self.MLSPERR().then_some(("MLSPERR", Self::DOC_MLSPERR)),
679 ].into_iter()
680 .flatten()
681 }
682}
683
684
685pub trait RegTags {
686 fn is_empty(&self) -> bool;
688
689 fn tags(&self) -> impl IntoIterator<Item = (&str, &str)>;
691}
692
693
694pub enum FaultKind {
695 VECTTBL,
698 FORCED,
700 DEBUGEVT,
702
703 IACCVIOL,
706 DACCVIOL,
708 MSTKERR,
710 MUNSTKERR,
712 MLSPERR,
714
715 STKERR,
718 UNSTKERR,
720 IBUSERR,
722 LSPERR,
724 PRECISERR,
726 IMPRECISERR,
728
729 UNDEFINSTR,
732 INVSTATE,
734 INVPC,
736 NOCPC,
738 UNALIGNED,
740 STKOF,
742 DIVBYZERO,
744}
745
746
747#[derive(Clone, Copy, Debug, PartialEq, Eq)]
748pub enum FpuAccessMode {
749 Disabled,
751 Enabled,
753 Privileged,
755}
756
757
758#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Hash)]
760pub enum VectActive {
761 ThreadMode,
763
764 Exception(Exception),
766
767 Interrupt {
769 irqn: u16,
771 },
772}
773
774impl VectActive {
775 #[inline]
777 pub fn from(vect_active: u16) -> Option<Self> {
778 Some(match vect_active {
779 0 => VectActive::ThreadMode,
780 2 => VectActive::Exception(Exception::NonMaskableInt),
781 3 => VectActive::Exception(Exception::HardFault),
782 4 => VectActive::Exception(Exception::MemoryManagement),
783 5 => VectActive::Exception(Exception::BusFault),
784 6 => VectActive::Exception(Exception::UsageFault),
785 7 => VectActive::Exception(Exception::SecureFault),
786 11 => VectActive::Exception(Exception::SVCall),
787 12 => VectActive::Exception(Exception::DebugMonitor),
788 14 => VectActive::Exception(Exception::PendSV),
789 15 => VectActive::Exception(Exception::SysTick),
790 irqn if (16..512).contains(&irqn) => VectActive::Interrupt { irqn: irqn - 16 },
791 _ => return None,
792 })
793 }
794}
795
796
797#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Hash)]
799pub enum Exception {
800 NonMaskableInt,
802
803 HardFault,
805
806 MemoryManagement,
808
809 BusFault,
811
812 UsageFault,
814
815 SecureFault,
817
818 SVCall,
820
821 DebugMonitor,
823
824 PendSV,
826
827 SysTick,
829}
830
831
832#[cfg(test)]
833mod tests {
834 use super::*;
835
836
837 #[test]
838 fn test_mmfsr_daccviol() {
839 let reg = ExceptionFrame { r0: 0x00000004,
840 r1: 0x00000008,
841 r2: 0x00000008,
842 r3: 0x00000008,
843 r12: 0x00000008,
844 lr: 0x6000d2e7.into(),
845 pc: 0x6000d5e8.into(),
846 psr: 0x010f0000.into(),
847 cfsr: 0x00000082.into(),
848 hfsr: 0x00000000.into(),
849 mmfar: 0x00000004.into(),
850 bfar: 0x00000004.into(),
851 rcccsr: 0x00000000 };
852 let mmfsr = reg.mmfsr();
853 assert!(mmfsr.DACCVIOL());
854 assert!(mmfsr.MMARVALID());
855 }
856
857 #[test]
858 fn test_mmfsr_daccviol__() {
859 let reg = ExceptionFrame { r0: 0x00000004,
860 r1: 0x00000008,
861 r2: 0x00000008,
862 r3: 0x00000008,
863 r12: 0x00000008,
864 lr: 0x6000d2e7.into(),
865 pc: 0x6000d5e8.into(),
866 psr: 0x010f0000.into(),
867 cfsr: 0x00000082.into(),
868 hfsr: 0x00000000.into(),
869 mmfar: 0x00000004.into(),
870 bfar: 0x00000004.into(),
871 rcccsr: 0x00000000 };
872 let mmfsr = reg.mmfsr();
873 assert!(mmfsr.DACCVIOL());
874 assert!(mmfsr.MMARVALID());
875 }
876}