Skip to main content

probe_rs/architecture/arm/core/
armv8m.rs

1//! Register types and the core interface for armv8-M
2
3use super::{
4    CortexMState, Dfsr,
5    cortex_m::{IdPfr1, Mvfr0},
6    registers::armv8m::{
7        V8M_BASE_SEC_FP_REGISTERS, V8M_BASE_SEC_REGISTERS, V8M_MAIN_FP_REGISTERS,
8        V8M_MAIN_REGISTERS, V8M_MAIN_SEC_FP_REGISTERS, V8M_MAIN_SEC_REGISTERS,
9    },
10    registers::cortex_m::{
11        CORTEX_M_CORE_REGISTERS, CORTEX_M_WITH_FP_CORE_REGISTERS, FP, PC, RA, SP,
12    },
13};
14use crate::{
15    Architecture, BreakpointCause, CoreInformation, CoreInterface, CoreRegister, CoreStatus,
16    CoreType, HaltReason, InstructionSet, MemoryInterface, MemoryMappedRegister,
17    architecture::arm::{
18        ArmError, core::registers::cortex_m::XPSR, memory::ArmMemoryInterface,
19        sequences::ArmDebugSequence,
20    },
21    core::{CoreRegisters, RegisterId, RegisterValue, VectorCatchCondition},
22    error::Error,
23    memory::{CoreMemoryInterface, valid_32bit_address},
24};
25use bitfield::bitfield;
26use std::{
27    mem::size_of,
28    sync::Arc,
29    time::{Duration, Instant},
30};
31
32/// The state of a core that can be used to persist core state across calls to multiple different cores.
33pub struct Armv8m<'probe> {
34    memory: Box<dyn ArmMemoryInterface + 'probe>,
35
36    state: &'probe mut CortexMState,
37
38    /// True if the core implements the security extension.
39    security: bool,
40
41    sequence: Arc<dyn ArmDebugSequence>,
42}
43
44impl<'probe> Armv8m<'probe> {
45    pub(crate) fn new(
46        mut memory: Box<dyn ArmMemoryInterface + 'probe>,
47        state: &'probe mut CortexMState,
48        sequence: Arc<dyn ArmDebugSequence>,
49    ) -> Result<Self, Error> {
50        if !state.initialized() {
51            // determine current state
52            let dhcsr = Dhcsr(memory.read_word_32(Dhcsr::get_mmio_address())?);
53
54            tracing::debug!("State when connecting: {:x?}", dhcsr);
55
56            let core_state = if dhcsr.s_sleep() {
57                CoreStatus::Sleeping
58            } else if dhcsr.s_halt() {
59                let dfsr = Dfsr(memory.read_word_32(Dfsr::get_mmio_address())?);
60
61                let reason = dfsr.halt_reason();
62
63                tracing::debug!("Core was halted when connecting, reason: {:?}", reason);
64
65                CoreStatus::Halted(reason)
66            } else {
67                CoreStatus::Running
68            };
69
70            // Clear DFSR register. The bits in the register are sticky,
71            // so we clear them here to ensure that that none are set.
72            let dfsr_clear = Dfsr::clear_all();
73
74            memory.write_word_32(Dfsr::get_mmio_address(), dfsr_clear.into())?;
75
76            state.current_state = core_state;
77            state.fp_present = Mvfr0(memory.read_word_32(Mvfr0::get_mmio_address())?).fp_present();
78
79            state.initialize();
80        }
81
82        // TODO is this stupid?
83        let idpfr1 = IdPfr1(memory.read_word_32(IdPfr1::get_mmio_address())?);
84        let security = idpfr1.security_present();
85
86        Ok(Self {
87            memory,
88            state,
89            security,
90            sequence,
91        })
92    }
93
94    fn set_core_status(&mut self, new_status: CoreStatus) {
95        super::update_core_status(&mut self.memory, &mut self.state.current_state, new_status);
96    }
97
98    fn wait_for_status(
99        &mut self,
100        timeout: Duration,
101        predicate: impl Fn(CoreStatus) -> bool,
102    ) -> Result<(), Error> {
103        let start = Instant::now();
104
105        while !predicate(self.status()?) {
106            if start.elapsed() >= timeout {
107                return Err(Error::Arm(ArmError::Timeout));
108            }
109            // Wait a bit before polling again.
110            std::thread::sleep(Duration::from_millis(1));
111        }
112
113        Ok(())
114    }
115}
116
117impl CoreInterface for Armv8m<'_> {
118    fn wait_for_core_halted(&mut self, timeout: Duration) -> Result<(), Error> {
119        // Wait until halted state is active again.
120        self.wait_for_status(timeout, |s| s.is_halted())
121    }
122
123    fn core_halted(&mut self) -> Result<bool, Error> {
124        // Wait until halted state is active again.
125        Ok(self.status()?.is_halted())
126    }
127
128    fn status(&mut self) -> Result<crate::core::CoreStatus, Error> {
129        let dhcsr = Dhcsr(self.memory.read_word_32(Dhcsr::get_mmio_address())?);
130
131        if dhcsr.s_lockup() {
132            tracing::debug!(
133                "The core is in locked up status as a result of an unrecoverable exception"
134            );
135
136            self.state.clear_pending_step();
137            self.set_core_status(CoreStatus::LockedUp);
138
139            return Ok(CoreStatus::LockedUp);
140        }
141
142        if dhcsr.s_sleep() {
143            // Check if we assumed the core to be halted
144            if self.state.current_state.is_halted() {
145                tracing::warn!("Expected core to be halted, but core is running");
146            }
147
148            self.set_core_status(CoreStatus::Sleeping);
149
150            return Ok(CoreStatus::Sleeping);
151        }
152
153        // TODO: Handle lockup
154
155        if dhcsr.s_halt() {
156            let dfsr = Dfsr(self.memory.read_word_32(Dfsr::get_mmio_address())?);
157
158            let mut reason = dfsr.halt_reason();
159            reason = self.state.resolve_halt_reason(reason);
160
161            // Clear bits from Dfsr register
162            self.memory
163                .write_word_32(Dfsr::get_mmio_address(), Dfsr::clear_all().into())?;
164
165            // If the core was halted before, we cannot read the halt reason from the chip,
166            // because we clear it directly after reading.
167            if self.state.current_state.is_halted() {
168                // There shouldn't be any bits set, otherwise it means
169                // that the reason for the halt has changed. No bits set
170                // means that we have an unknown HaltReason.
171                if reason == HaltReason::Unknown {
172                    tracing::debug!("Cached halt reason: {:?}", self.state.current_state);
173                    return Ok(self.state.current_state);
174                }
175
176                tracing::debug!(
177                    "Reason for halt has changed, old reason was {:?}, new reason is {:?}",
178                    &self.state.current_state,
179                    &reason
180                );
181            }
182
183            // Set the status so any semihosting operations will know we're halted
184            self.set_core_status(CoreStatus::Halted(reason));
185
186            if let HaltReason::Breakpoint(_) = reason {
187                self.state.semihosting_command = super::cortex_m::check_for_semihosting(
188                    self.state.semihosting_command.take(),
189                    self,
190                )?;
191                if let Some(command) = self.state.semihosting_command {
192                    reason = HaltReason::Breakpoint(BreakpointCause::Semihosting(command));
193                }
194
195                // Set it again if it's changed
196                self.set_core_status(CoreStatus::Halted(reason));
197            }
198
199            return Ok(CoreStatus::Halted(reason));
200        }
201
202        // Core is neither halted nor sleeping, so we assume it is running.
203        if self.state.current_state.is_halted() {
204            tracing::warn!("Core is running, but we expected it to be halted");
205        }
206
207        self.set_core_status(CoreStatus::Running);
208
209        Ok(CoreStatus::Running)
210    }
211
212    fn halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error> {
213        self.state.clear_pending_step();
214
215        let mut value = Dhcsr(0);
216        value.set_c_halt(true);
217        value.set_c_debugen(true);
218        value.enable_write();
219
220        self.memory
221            .write_word_32(Dhcsr::get_mmio_address(), value.into())?;
222
223        self.wait_for_core_halted(timeout)?;
224
225        // Update core status
226        let _ = self.status()?;
227
228        // try to read the program counter
229        let pc_value = self.read_core_reg(self.program_counter().into())?;
230
231        // get pc
232        Ok(CoreInformation {
233            pc: pc_value.try_into()?,
234        })
235    }
236    fn run(&mut self) -> Result<(), Error> {
237        // Before we run, we always perform a single instruction step, to account for possible breakpoints that might get us stuck on the current instruction.
238        self.step()?;
239        self.state.clear_pending_step();
240
241        let mut value = Dhcsr(0);
242        value.set_c_halt(false);
243        value.set_c_debugen(true);
244        value.enable_write();
245
246        self.memory
247            .write_word_32(Dhcsr::get_mmio_address(), value.into())?;
248        self.memory.flush()?;
249
250        // We assume that the core is running now
251        self.set_core_status(CoreStatus::Running);
252
253        Ok(())
254    }
255
256    fn reset(&mut self) -> Result<(), Error> {
257        self.state.semihosting_command = None;
258        self.state.clear_pending_step();
259
260        self.sequence
261            .reset_system(&mut *self.memory, crate::CoreType::Armv8m, None)?;
262        // Invalidate cached state: chip reset clears FP_CTRL and core status
263        self.set_core_status(CoreStatus::Unknown);
264        self.state.hw_breakpoints_enabled = false;
265        Ok(())
266    }
267
268    fn reset_and_halt(&mut self, _timeout: Duration) -> Result<CoreInformation, Error> {
269        // Set the vc_corereset bit in the DEMCR register.
270        // This will halt the core after reset.
271        self.reset_catch_set()?;
272        self.state.clear_pending_step();
273
274        self.sequence
275            .reset_system(&mut *self.memory, crate::CoreType::Armv8m, None)?;
276
277        // Invalidate cached state: chip reset clears FP_CTRL and core status
278        self.set_core_status(CoreStatus::Unknown);
279        self.state.hw_breakpoints_enabled = false;
280
281        // Some processors may not enter the halt state immediately after clearing the reset state.
282        // Particularly: on PSOC 6, vector catch takes effect after the core's boot ROM finishes
283        // executing, when jumping to the reset vector of the user application.
284        match self.wait_for_core_halted(Duration::from_millis(100)) {
285            Ok(()) => (),
286            Err(Error::Arm(ArmError::Timeout)) if self.status()? == CoreStatus::Sleeping => {
287                // On PSOC 6, if no application is loaded in flash, or if this core is waiting for
288                // another core to boot it, the boot ROM sleeps and vector catch is not triggered.
289                tracing::warn!(
290                    "reset_and_halt timed out and core is sleeping; assuming core is quiescent"
291                );
292                self.halt(Duration::from_millis(100))?;
293            }
294            Err(e) => return Err(e),
295        }
296
297        const XPSR_THUMB: u32 = 1 << 24;
298
299        let xpsr_value: u32 = self.read_core_reg(XPSR.id())?.try_into()?;
300        if xpsr_value & XPSR_THUMB == 0 {
301            self.write_core_reg(XPSR.id(), (xpsr_value | XPSR_THUMB).into())?;
302        }
303
304        self.reset_catch_clear()?;
305
306        // try to read the program counter
307        let pc_value = self.read_core_reg(self.program_counter().into())?;
308
309        // get pc
310        Ok(CoreInformation {
311            pc: pc_value.try_into()?,
312        })
313    }
314
315    fn step(&mut self) -> Result<CoreInformation, Error> {
316        // First check if we stopped on a breakpoint, because this requires special handling before we can continue.
317        let breakpoint_at_pc = if matches!(
318            self.state.current_state,
319            CoreStatus::Halted(HaltReason::Breakpoint(_))
320        ) {
321            let pc_before_step = self.read_core_reg(self.program_counter().into())?;
322            self.enable_breakpoints(false)?;
323            Some(pc_before_step)
324        } else {
325            None
326        };
327
328        let mut value = Dhcsr(0);
329        // Leave halted state.
330        // Step one instruction.
331        self.state.begin_step();
332        value.set_c_step(true);
333        value.set_c_halt(false);
334        value.set_c_debugen(true);
335        value.set_c_maskints(true);
336        value.enable_write();
337
338        self.memory
339            .write_word_32(Dhcsr::get_mmio_address(), value.into())?;
340        self.memory.flush()?;
341
342        // The single-step might put the core in lockup state. Lockup isn't considered "halted"
343        // so we can't use `wait_for_core_halted` here.
344        // So we wait for halted OR lockup, and if we entered lockup we halt.
345        if let Err(err) = self.wait_for_status(Duration::from_millis(100), |s| {
346            matches!(s, CoreStatus::Halted(_) | CoreStatus::LockedUp)
347        }) {
348            self.state.clear_pending_step();
349            return Err(err);
350        }
351        if self.status()? == CoreStatus::LockedUp {
352            self.halt(Duration::from_millis(100))?;
353        }
354
355        // Try to read the new program counter.
356        let mut pc_after_step = self.read_core_reg(self.program_counter().into())?;
357
358        // Re-enable breakpoints before we continue.
359        if let Some(pc_before_step) = breakpoint_at_pc {
360            // If we were stopped on a software breakpoint, then we need to manually advance the PC, or else we will be stuck here forever.
361            if pc_before_step == pc_after_step
362                && !self
363                    .hw_breakpoints()?
364                    .contains(&pc_before_step.try_into().ok())
365            {
366                tracing::debug!(
367                    "Encountered a breakpoint instruction @ {}. We need to manually advance the program counter to the next instruction.",
368                    pc_after_step
369                );
370                // Advance the program counter by the architecture specific byte size of the BKPT instruction.
371                pc_after_step.increment_address(2)?;
372                self.write_core_reg(self.program_counter().into(), pc_after_step)?;
373            }
374            self.enable_breakpoints(true)?;
375        }
376
377        self.state.semihosting_command = None;
378
379        Ok(CoreInformation {
380            pc: pc_after_step.try_into()?,
381        })
382    }
383
384    fn read_core_reg(&mut self, address: RegisterId) -> Result<RegisterValue, Error> {
385        if self.state.current_state.is_halted() {
386            let value = super::cortex_m::read_core_reg(&mut *self.memory, address)?;
387            Ok(value.into())
388        } else {
389            Err(Error::Arm(ArmError::CoreNotHalted))
390        }
391    }
392
393    fn write_core_reg(&mut self, address: RegisterId, value: RegisterValue) -> Result<(), Error> {
394        if self.state.current_state.is_halted() {
395            super::cortex_m::write_core_reg(&mut *self.memory, address, value.try_into()?)?;
396
397            Ok(())
398        } else {
399            Err(Error::Arm(ArmError::CoreNotHalted))
400        }
401    }
402
403    fn available_breakpoint_units(&mut self) -> Result<u32, Error> {
404        let raw_val = self.memory.read_word_32(FpCtrl::get_mmio_address())?;
405
406        let reg = FpCtrl::from(raw_val);
407
408        Ok(reg.num_code())
409    }
410
411    /// See docs on the [`CoreInterface::hw_breakpoints`] trait
412    fn hw_breakpoints(&mut self) -> Result<Vec<Option<u64>>, Error> {
413        let mut breakpoints = vec![];
414        let num_hw_breakpoints = self.available_breakpoint_units()? as usize;
415        for bp_unit_index in 0..num_hw_breakpoints {
416            let reg_addr = FpCompN::get_mmio_address() + (bp_unit_index * size_of::<u32>()) as u64;
417            // The raw breakpoint address as read from memory
418            let register_value = self.memory.read_word_32(reg_addr)?;
419            // The breakpoint address after it has been adjusted for FpRev 1 or 2
420            if FpCompN::from(register_value).enable() {
421                let breakpoint = FpCompN::from(register_value).bp_addr() << 1;
422                breakpoints.push(Some(breakpoint as u64));
423            } else {
424                breakpoints.push(None);
425            }
426        }
427        Ok(breakpoints)
428    }
429
430    fn enable_breakpoints(&mut self, state: bool) -> Result<(), Error> {
431        let mut val = FpCtrl::from(0);
432        val.set_key(true);
433        val.set_enable(state);
434
435        self.memory
436            .write_word_32(FpCtrl::get_mmio_address(), val.into())?;
437        self.memory.flush()?;
438
439        self.state.hw_breakpoints_enabled = state;
440
441        Ok(())
442    }
443
444    fn set_hw_breakpoint(&mut self, bp_unit_index: usize, addr: u64) -> Result<(), Error> {
445        let addr = valid_32bit_address(addr)?;
446
447        let mut val = FpCompN::from(0);
448
449        // clear bits which cannot be set and shift into position
450        let comp_val = (addr & 0xff_ff_ff_fe) >> 1;
451
452        val.set_bp_addr(comp_val);
453        val.set_enable(true);
454
455        let reg_addr = FpCompN::get_mmio_address() + (bp_unit_index * size_of::<u32>()) as u64;
456
457        self.memory.write_word_32(reg_addr, val.into())?;
458
459        Ok(())
460    }
461
462    fn clear_hw_breakpoint(&mut self, bp_unit_index: usize) -> Result<(), Error> {
463        let mut val = FpCompN::from(0);
464        val.set_enable(false);
465        val.set_bp_addr(0);
466
467        let reg_addr = FpCompN::get_mmio_address() + (bp_unit_index * size_of::<u32>()) as u64;
468
469        self.memory.write_word_32(reg_addr, val.into())?;
470
471        Ok(())
472    }
473
474    fn registers(&self) -> &'static CoreRegisters {
475        let main = true; // TODO m33 is mainline, no one has m23 (baseline) yet
476        let security = self.security;
477        let fp = self.state.fp_present;
478
479        match (main, security, fp) {
480            (true, true, true) => &V8M_MAIN_SEC_FP_REGISTERS,
481            (true, true, false) => &V8M_MAIN_SEC_REGISTERS,
482            (true, false, true) => &V8M_MAIN_FP_REGISTERS,
483            (true, false, false) => &V8M_MAIN_REGISTERS,
484            (false, true, true) => &V8M_BASE_SEC_FP_REGISTERS,
485            (false, true, false) => &V8M_BASE_SEC_REGISTERS,
486            (false, false, true) => &CORTEX_M_WITH_FP_CORE_REGISTERS,
487            (false, false, false) => &CORTEX_M_CORE_REGISTERS,
488        }
489    }
490
491    fn program_counter(&self) -> &'static CoreRegister {
492        &PC
493    }
494
495    fn frame_pointer(&self) -> &'static CoreRegister {
496        &FP
497    }
498
499    fn stack_pointer(&self) -> &'static CoreRegister {
500        &SP
501    }
502
503    fn return_address(&self) -> &'static CoreRegister {
504        &RA
505    }
506
507    fn hw_breakpoints_enabled(&self) -> bool {
508        self.state.hw_breakpoints_enabled
509    }
510
511    fn architecture(&self) -> Architecture {
512        Architecture::Arm
513    }
514
515    fn core_type(&self) -> CoreType {
516        CoreType::Armv8m
517    }
518
519    fn instruction_set(&mut self) -> Result<InstructionSet, Error> {
520        Ok(InstructionSet::Thumb2)
521    }
522
523    fn fpu_support(&mut self) -> Result<bool, Error> {
524        Ok(self.state.fp_present)
525    }
526
527    fn floating_point_register_count(&mut self) -> Result<usize, Error> {
528        Ok(32)
529    }
530
531    #[tracing::instrument(skip(self))]
532    fn reset_catch_set(&mut self) -> Result<(), Error> {
533        self.sequence
534            .reset_catch_set(&mut *self.memory, CoreType::Armv8m, None)?;
535
536        Ok(())
537    }
538
539    #[tracing::instrument(skip(self))]
540    fn reset_catch_clear(&mut self) -> Result<(), Error> {
541        self.sequence
542            .reset_catch_clear(&mut *self.memory, CoreType::Armv8m, None)?;
543
544        Ok(())
545    }
546
547    #[tracing::instrument(skip(self))]
548    fn debug_core_stop(&mut self) -> Result<(), Error> {
549        self.sequence
550            .debug_core_stop(&mut *self.memory, CoreType::Armv8m)?;
551
552        Ok(())
553    }
554
555    #[tracing::instrument(skip(self))]
556    fn enable_vector_catch(&mut self, condition: VectorCatchCondition) -> Result<(), Error> {
557        let mut dhcsr = Dhcsr(self.memory.read_word_32(Dhcsr::get_mmio_address())?);
558        dhcsr.set_c_debugen(true);
559        self.memory
560            .write_word_32(Dhcsr::get_mmio_address(), dhcsr.into())?;
561
562        let mut demcr = Demcr(self.memory.read_word_32(Demcr::get_mmio_address())?);
563        let idpfr1 = IdPfr1(self.memory.read_word_32(IdPfr1::get_mmio_address())?);
564        match condition {
565            VectorCatchCondition::HardFault => demcr.set_vc_harderr(true),
566            VectorCatchCondition::CoreReset => demcr.set_vc_corereset(true),
567            VectorCatchCondition::SecureFault => {
568                if !idpfr1.security_present() {
569                    return Err(Error::Arm(ArmError::ExtensionRequired(&["Security"])));
570                }
571                demcr.set_vc_sferr(true);
572            }
573            VectorCatchCondition::All => {
574                demcr.set_vc_harderr(true);
575                demcr.set_vc_corereset(true);
576                if idpfr1.security_present() {
577                    demcr.set_vc_sferr(true);
578                }
579            }
580            VectorCatchCondition::Svc | VectorCatchCondition::Hlt => {
581                return Err(Error::NotImplemented("vector catch condition Svc/Hlt"));
582            }
583        };
584
585        self.memory
586            .write_word_32(Demcr::get_mmio_address(), demcr.into())?;
587        Ok(())
588    }
589
590    fn disable_vector_catch(&mut self, condition: VectorCatchCondition) -> Result<(), Error> {
591        let mut demcr = Demcr(self.memory.read_word_32(Demcr::get_mmio_address())?);
592        let idpfr1 = IdPfr1(self.memory.read_word_32(IdPfr1::get_mmio_address())?);
593        match condition {
594            VectorCatchCondition::HardFault => demcr.set_vc_harderr(false),
595            VectorCatchCondition::CoreReset => demcr.set_vc_corereset(false),
596            VectorCatchCondition::SecureFault => {
597                if !idpfr1.security_present() {
598                    return Err(Error::Arm(ArmError::ExtensionRequired(&["Security"])));
599                }
600                demcr.set_vc_sferr(false);
601            }
602            VectorCatchCondition::All => {
603                demcr.set_vc_harderr(false);
604                demcr.set_vc_corereset(false);
605                if idpfr1.security_present() {
606                    demcr.set_vc_sferr(false);
607                }
608            }
609            VectorCatchCondition::Svc | VectorCatchCondition::Hlt => {
610                return Err(Error::NotImplemented("vector catch condition Svc/Hlt"));
611            }
612        };
613
614        self.memory
615            .write_word_32(Demcr::get_mmio_address(), demcr.into())?;
616        Ok(())
617    }
618}
619
620impl CoreMemoryInterface for Armv8m<'_> {
621    type ErrorType = ArmError;
622
623    fn memory(&self) -> &dyn MemoryInterface<Self::ErrorType> {
624        self.memory.as_ref()
625    }
626    fn memory_mut(&mut self) -> &mut dyn MemoryInterface<Self::ErrorType> {
627        self.memory.as_mut()
628    }
629}
630
631bitfield! {
632    /// Debug Halting Control and Status Register, DHCSR (see armv8-M Architecture Reference Manual D1.2.38)
633    ///
634    /// To write this register successfully, you need to set the debug key via [`Dhcsr::enable_write`] first!
635    #[derive(Copy, Clone)]
636    pub struct Dhcsr(u32);
637    impl Debug;
638    /// Restart sticky status. Indicates the PE has processed a request to clear DHCSR.C_HALT to 0. That is, either
639    /// a write to DHCSR that clears DHCSR.C_HALT from 1 to 0, or an External Restart Request.
640    ///
641    /// The possible values of this bit are:
642    ///
643    /// `0`: PE has not left Debug state since the last read of DHCSR.\
644    /// `1`: PE has left Debug state since the last read of DHCSR.
645    ///
646    /// If the PE is not halted when `C_HALT` is cleared to zero, it is UNPREDICTABLE whether this bit is set to `1`. If
647    /// `DHCSR.C_DEBUGEN == 0` this bit reads as an UNKNOWN value.
648    ///
649    /// This bit clears to zero when read.
650    ///
651    /// **Note**
652    ///
653    /// If the request to clear C_HALT is made simultaneously with a request to set C_HALT, for example
654    /// a restart request and external debug request occur together, then the
655    pub s_restart_st, _ : 26;
656    ///  Indicates whether the processor has been reset since the last read of DHCSR:
657    ///
658    /// `0`: No reset since last DHCSR read.\
659    /// `1`: At least one reset since last DHCSR read.
660    ///
661    /// This is a sticky bit, that clears to `0` on a read of DHCSR.
662    pub s_reset_st, _: 25;
663    /// When not in Debug state, indicates whether the processor has completed
664    /// the execution of an instruction since the last read of DHCSR:
665    ///
666    /// `0`: No instruction has completed since last DHCSR read.\
667    /// `1`: At least one instructions has completed since last DHCSR read.
668    ///
669    /// This is a sticky bit, that clears to `0` on a read of DHCSR.
670    ///
671    /// This bit is UNKNOWN:
672    ///
673    /// - after a Local reset, but is set to `1` as soon as the processor completes
674    /// execution of an instruction.
675    /// - when S_LOCKUP is set to `1`.
676    /// - when S_HALT is set to `1`.
677    ///
678    /// When the processor is not in Debug state, a debugger can check this bit to
679    /// determine if the processor is stalled on a load, store or fetch access.
680    pub s_retire_st, _: 24;
681    /// Floating-point registers Debuggable.
682    /// Indicates that FPSCR, VPR, and the Floating-point registers are RAZ/WI in the current PE state when accessed via DCRSR. This reflects !CanDebugAccessFP().
683    /// The possible values of this bit are:
684    ///
685    /// `0`: Floating-point registers accessible.\
686    /// `1`: Floating-point registers are RAZ/WI.
687    ///
688    /// If version Armv8.1-M of the architecture is not implemented, this bit is RES0
689    pub s_fpd, _: 23;
690    /// Secure unprivileged halting debug enabled. Indicates whether Secure unprivileged-only halting debug is allowed or active.
691    /// The possible values of this bit are:
692    ///
693    /// `0`: Secure invasive halting debug prohibited or not restricted to an unprivileged mode.\
694    /// `1`: Unprivileged Secure invasive halting debug enabled.
695    ///
696    /// If the PE is in Non-debug state, this bit reflects the value of `UnprivHaltingDebugAllowed(TRUE) && !SecureHaltingDebugAllowed()`.
697    ///
698    /// The value of this bit does not change whilst the PE remains in Debug state.
699    ///
700    /// If the Security Extension is not implemented, this bit is RES0.
701    /// If version Armv8.1 of the architecture and UDE are not implemented, this bit is RES0.
702    pub s_suide, _: 22;
703    /// Non-secure unprivileged halting debug enabled. Indicates whether Non-secure unprivileged-only halting debug is allowed or active.
704    ///
705    /// The possible values of this bit are:
706    ///
707    /// `0`: Non-secure invasive halting debug prohibited or not restricted to an unprivileged mode.\
708    /// `1`: Unprivileged Non-secure invasive halting debug enabled.
709    ///
710    /// If the PE is in Non-debug state, this bit reflects the value of `UnprivHaltingDebugAllowed(FALSE) &&
711    /// !HaltingDebugAllowed()`.
712    ///
713    /// The value of this bit does not change whilst the PE remains in Debug state.
714    /// If version Armv8.1 of the architecture and UDE are not implemented, this bit is RES0
715    pub s_nsuide, _: 21;
716    /// Secure debug enabled. Indicates whether Secure invasive debug is allowed.
717    /// The possible values of this bit are:
718    ///
719    /// `0`: Secure invasive debug prohibited.\
720    /// `1`: Secure invasive debug allowed.
721    ///
722    /// If the PE is in Non-debug state, this bit reflects the value of SecureHaltingDebugAllowed() or UnprivHaltingDebugAllowed(TRUE).
723    ///
724    /// The value of this bit does not change while the PE remains in Debug state.
725    ///
726    /// If the Security Extension is not implemented, this bit is RES0.
727    pub s_sde, _: 20;
728    /// Indicates whether the processor is locked up because of an unrecoverable
729    /// exception:
730    ///
731    /// `0` Not locked up.\
732    /// `1` Locked up.
733    /// See Unrecoverable exception cases on page B1-206 for more
734    /// information.
735    ///
736    /// This bit can only read as `1` when accessed by a remote debugger using the
737    /// DAP. The value of `1` indicates that the processor is running but locked up.
738    /// The bit clears to `0` when the processor enters Debug state.
739    pub s_lockup, _: 19;
740    /// Indicates whether the processor is sleeping:
741    ///
742    /// `0` Not sleeping.
743    /// `1` Sleeping.
744    ///
745    /// The debugger must set the DHCSR.C_HALT bit to `1` to gain control, or
746    /// wait for an interrupt or other wakeup event to wakeup the system
747    pub s_sleep, _: 18;
748    /// Indicates whether the processor is in Debug state:
749    ///
750    /// `0`: Not in Debug state.\
751    /// `1`: In Debug state.
752    pub s_halt, _: 17;
753    /// A handshake flag for transfers through the DCRDR:
754    ///
755    /// - Writing to DCRSR clears the bit to `0`.\
756    /// - Completion of the DCRDR transfer then sets the bit to `1`.
757    ///
758    /// For more information about DCRDR transfers see Debug Core Register
759    /// Data Register, DCRDR on page C1-292.
760    ///
761    /// `0`: There has been a write to the DCRDR, but the transfer is not complete.\
762    /// `1` The transfer to or from the DCRDR is complete.
763    ///
764    /// This bit is only valid when the processor is in Debug state, otherwise the
765    /// bit is UNKNOWN.
766    pub s_regrdy, _: 16;
767    /// Halt on PMU overflow control. Request entry to Debug state when a PMU counter overflows.
768    ///
769    /// The possible values of this bit are:
770    ///
771    /// `0`: No action.\
772    /// `1`: If C_DEBUGEN is set to `1`, then when a PMU counter is configured to generate an interrupt overflows,
773    /// the PE sets DHCSR.C_HALT to `1` and DFSR.PMU to `1`.
774    ///
775    /// PMU_OVSSET and PMU_OVSCLR indicate which counter or counters triggered the halt.
776    ///
777    /// If the Main Extension is not implemented, this bit is RES0.
778    ///
779    /// If version Armv8.1 of the architecture and PMU are not implemented, this bit is RES0.
780    ///
781    /// This bit resets to zero on a Cold reset.
782    pub c_pmov, set_c_pmov: 6;
783    /// Allow imprecise entry to Debug state. The actions on writing to this bit are:
784    ///
785    /// `0`: No action.\
786    /// `1`: Allow imprecise entry to Debug state, for example by forcing any stalled load
787    /// or store instruction to complete.
788    ///
789    /// Setting this bit to `1` allows a debugger to request imprecise entry to Debug state.
790    ///
791    /// The effect of setting this bit to `1` is UNPREDICTABLE unless the DHCSR write also sets
792    /// C_DEBUGEN and C_HALT to `1`. This means that if the processor is not already in Debug
793    /// state it enters Debug state when the stalled instruction completes.
794    ///
795    /// Writing `1` to this bit makes the state of the memory system UNPREDICTABLE. Therefore, if a
796    /// debugger writes `1` to this bit it must reset the processor before leaving Debug state.
797    ///
798    /// **Note**
799    ///
800    /// - A debugger can write to the DHCSR to clear this bit to `0`. However, this does not
801    /// remove the UNPREDICTABLE state of the memory system caused by setting C_SNAPSTALL to `1`.
802    /// - The architecture does not guarantee that setting this bit to 1 will force entry to Debug
803    /// state.
804    /// - Arm strongly recommends that a value of `1` is never written to C_SNAPSTALL when
805    /// the processor is in Debug state.
806    ///
807    /// A power-on reset sets this bit to `0`.
808    pub c_snapstall, set_c_snapstall: 5;
809    /// When debug is enabled, the debugger can write to this bit to mask
810    /// PendSV, SysTick and external configurable interrupts:
811    ///
812    /// `0`: Do not mask.\
813    /// `1` Mask PendSV, SysTick and external configurable interrupts.
814    /// The effect of any attempt to change the value of this bit is UNPREDICTABLE
815    /// unless both:
816    /// - before the write to DHCSR, the value of the C_HALT bit is `1`.
817    /// - the write to the DHCSR that changes the C_MASKINTS bit also
818    /// writes `1` to the C_HALT bit.
819    ///
820    /// This means that a single write to DHCSR cannot set the C_HALT to `0` and
821    /// change the value of the C_MASKINTS bit.
822    ///
823    /// The bit does not affect NMI. When DHCSR.C_DEBUGEN is set to `0`, the
824    /// value of this bit is UNKNOWN.
825    ///
826    /// For more information about the use of this bit see Table C1-9 on
827    /// page C1-282.
828    ///
829    /// This bit is UNKNOWN after a power-on reset.
830    pub c_maskints, set_c_maskints: 3;
831    /// Processor step bit. The effects of writes to this bit are:
832    ///
833    /// `0`: Single-stepping disabled.\
834    /// `1`: Single-stepping enabled.
835    ///
836    /// For more information about the use of this bit see Table C1-9 on page C1-282.
837    ///
838    /// This bit is UNKNOWN after a power-on reset.
839    pub c_step, set_c_step: 2;
840    /// Processor halt bit. The effects of writes to this bit are:
841    ///
842    /// `0`: Request a halted processor to run.\
843    /// `1`: Request a running processor to halt.
844    ///
845    /// Table C1-9 on page C1-282 shows the effect of writes to this bit when the
846    /// processor is in Debug state.
847    ///
848    /// This bit is 0 after a System reset
849    pub c_halt, set_c_halt: 1;
850    /// Halting debug enable bit:
851    /// `0`: Halting debug disabled.\
852    /// `1`: Halting debug enabled.
853    ///
854    /// If a debugger writes to DHCSR to change the value of this bit from `0` to
855    /// `1`, it must also write 0 to the C_MASKINTS bit, otherwise behavior is UNPREDICTABLE.
856    ///
857    /// This bit can only be written from the DAP. Access to the DHCSR from
858    /// software running on the processor is IMPLEMENTATION DEFINED.
859    ///
860    /// However, writes to this bit from software running on the processor are ignored.
861    ///
862    /// This bit is `0` after a power-on reset.
863    pub c_debugen, set_c_debugen: 0;
864}
865
866impl Dhcsr {
867    /// This function sets the bit to enable writes to this register.
868    pub fn enable_write(&mut self) {
869        self.0 &= !(0xffff << 16);
870        self.0 |= 0xa05f << 16;
871    }
872}
873
874impl From<u32> for Dhcsr {
875    fn from(value: u32) -> Self {
876        Self(value)
877    }
878}
879
880impl From<Dhcsr> for u32 {
881    fn from(value: Dhcsr) -> Self {
882        value.0
883    }
884}
885
886impl MemoryMappedRegister<u32> for Dhcsr {
887    const ADDRESS_OFFSET: u64 = 0xE000_EDF0;
888    const NAME: &'static str = "DHCSR";
889}
890
891bitfield! {
892    /// Application Interrupt and Reset Control Register, AIRCR (see armv8-M Architecture Reference Manual D1.2.3)
893    ///
894    /// [`Aircr::vectkey`] must be called before this register can effectively be written!
895    #[derive(Copy, Clone)]
896    pub struct Aircr(u32);
897    impl Debug;
898    /// Vector Key. The value `0x05FA` must be written to this register, otherwise
899    /// the register write is UNPREDICTABLE.
900    get_vectkeystat, set_vectkey: 31,16;
901    /// Indicates the memory system data endianness:
902    ///
903    /// `0`: little endian.\
904    /// `1` big endian.
905    ///
906    /// See Endian support on page A3-44 for more information.
907    pub endianness, set_endianness: 15;
908    /// Priority grouping, indicates the binary point position.
909    /// For information about the use of this field see Priority grouping on page B1-527.
910    ///
911    /// This field resets to `0b000`.
912    pub prigroup, set_prigroup: 10,8;
913    /// System reset request Secure only. The value of this bit defines whether the SYSRESETREQ bit is functional for Non-secure use.
914    /// This bit is not banked between Security states.
915    /// The possible values of this bit are:
916    ///
917    /// `0`: SYSRESETREQ functionality is available to both Security states.\
918    /// `1`: SYSRESETREQ functionality is only available to Secure state.
919    ///
920    /// This bit is RAZ/WI from Non-secure state.
921    /// This bit resets to zero on a Warm reset
922    pub sysresetreqs, set_sysresetreqs: 3;
923    ///  System Reset Request:
924    ///
925    /// `0` do not request a reset.\
926    /// `1` request reset.
927    ///
928    /// Writing 1 to this bit asserts a signal to request a reset by the external
929    /// system. The system components that are reset by this request are
930    /// IMPLEMENTATION DEFINED. A Local reset is required as part of a system
931    /// reset request.
932    ///
933    /// A Local reset clears this bit to `0`.
934    ///
935    /// See Reset management on page B1-208 for more information
936    pub sysresetreq, set_sysresetreq: 2;
937    /// Clears all active state information for fixed and configurable exceptions:
938    ///
939    /// `0`: do not clear state information.\
940    /// `1`: clear state information.
941    ///
942    /// The effect of writing a `1` to this bit if the processor is not halted in Debug
943    /// state is UNPREDICTABLE.
944    pub vectclractive, set_vectclractive: 1;
945    /// Writing `1` to this bit causes a local system reset, see Reset management on page B1-559 for
946    /// more information. This bit self-clears.
947    ///
948    /// The effect of writing a `1` to this bit if the processor is not halted in Debug state is
949    /// UNPREDICTABLE.
950    ///
951    /// When the processor is halted in Debug state, if a write to the register writes a `1` to both
952    /// VECTRESET and SYSRESETREQ, the behavior is UNPREDICTABLE.
953    ///
954    /// This bit is write only.
955    pub vectreset, set_vectreset: 0;
956}
957
958impl From<u32> for Aircr {
959    fn from(value: u32) -> Self {
960        Self(value)
961    }
962}
963
964impl From<Aircr> for u32 {
965    fn from(value: Aircr) -> Self {
966        value.0
967    }
968}
969
970impl Aircr {
971    /// Must be called before writing the register.
972    pub fn vectkey(&mut self) {
973        self.set_vectkey(0x05FA);
974    }
975
976    /// Verifies that the vector key is correct (see [`Aircr::vectkey`])
977    pub fn vectkeystat(&self) -> bool {
978        self.get_vectkeystat() == 0xFA05
979    }
980}
981
982impl MemoryMappedRegister<u32> for Aircr {
983    const ADDRESS_OFFSET: u64 = 0xE000_ED0C;
984    const NAME: &'static str = "AIRCR";
985}
986
987/// Debug Core Register Data Register, DCRDR (see armv8-M Architecture Reference Manual D1.2.32)
988#[derive(Debug, Copy, Clone)]
989pub struct Dcrdr(u32);
990
991impl From<u32> for Dcrdr {
992    fn from(value: u32) -> Self {
993        Self(value)
994    }
995}
996
997impl From<Dcrdr> for u32 {
998    fn from(value: Dcrdr) -> Self {
999        value.0
1000    }
1001}
1002
1003impl MemoryMappedRegister<u32> for Dcrdr {
1004    const ADDRESS_OFFSET: u64 = 0xE000_EDF8;
1005    const NAME: &'static str = "DCRDR";
1006}
1007
1008bitfield! {
1009    /// /// Debug Exception and Monitor Control Register, DEMCR (see armv8-M Architecture Reference Manual D1.2.36)
1010    #[derive(Copy, Clone)]
1011    pub struct Demcr(u32);
1012    impl Debug;
1013    /// Global enable for DWT, PMU and ITM features
1014    pub trcena, set_trcena: 24;
1015    /// Monitor pending request key. Writes to the mon_pend and mon_en fields
1016    /// request are ignored unless `monprkey` is set to zero concurrently.
1017    pub monprkey, set_monprkey: 23;
1018    /// Unprivileged monitor enable.
1019    pub umon_en, set_umon_en: 21;
1020    /// Secure DebugMonitor enable
1021    pub sdme, set_sdme: 20;
1022    /// DebugMonitor semaphore bit
1023    pub mon_req, set_mon_req: 19;
1024    /// Step the processor?
1025    pub mon_step, set_mon_step: 18;
1026    /// Sets or clears the pending state of the DebugMonitor exception
1027    pub mon_pend, set_mon_pend: 17;
1028    /// Enable the DebugMonitor exception
1029    pub mon_en, set_mon_en: 16;
1030    /// Enable halting debug on a SecureFault exception
1031    pub vc_sferr, set_vc_sferr: 11;
1032    /// Enable halting debug trap on a HardFault exception
1033    pub vc_harderr, set_vc_harderr: 10;
1034    /// Enable halting debug trap on a fault occurring during exception entry
1035    /// or exception return
1036    pub vc_interr, set_vc_interr: 9;
1037    /// Enable halting debug trap on a BusFault exception
1038    pub vc_buserr, set_vc_buserr: 8;
1039    /// Enable halting debug trap on a UsageFault exception caused by a state
1040    /// information error, for example an Undefined Instruction exception
1041    pub vc_staterr, set_vc_staterr: 7;
1042    /// Enable halting debug trap on a UsageFault exception caused by a
1043    /// checking error, for example an alignment check error
1044    pub vc_chkerr, set_vc_chkerr: 6;
1045    /// Enable halting debug trap on a UsageFault caused by an access to a
1046    /// Coprocessor
1047    pub vc_nocperr, set_vc_nocperr: 5;
1048    /// Enable halting debug trap on a MemManage exception.
1049    pub vc_mmerr, set_vc_mmerr: 4;
1050    /// Enable Reset Vector Catch
1051    pub vc_corereset, set_vc_corereset: 0;
1052}
1053
1054impl From<u32> for Demcr {
1055    fn from(value: u32) -> Self {
1056        Self(value)
1057    }
1058}
1059
1060impl From<Demcr> for u32 {
1061    fn from(value: Demcr) -> Self {
1062        value.0
1063    }
1064}
1065
1066impl MemoryMappedRegister<u32> for Demcr {
1067    const ADDRESS_OFFSET: u64 = 0xe000_edfc;
1068    const NAME: &'static str = "DEMCR";
1069}
1070
1071bitfield! {
1072    /// Flash Patch Control Register, FP_CTRL (see armv8-M Architecture Reference Manual D1.2.108)
1073    #[derive(Copy,Clone)]
1074    pub struct FpCtrl(u32);
1075    impl Debug;
1076    /// Flash Patch breakpoint architecture revision:
1077    /// 0000 Flash Patch breakpoint version 1.
1078    /// 0001 Flash Patch breakpoint version 2. Supports breakpoints on any location in the 4GB address range.
1079    pub rev, _: 31, 28;
1080    num_code_1, _: 14, 12;
1081    /// The number of literal address comparators supported, starting from NUM_CODE upwards.
1082    /// UNK/SBZP if Flash Patch is not implemented. Flash Patch is not implemented if `FP_REMAP[29]` is 0.
1083    /// If this field is zero, the implementation does not support literal comparators.
1084    pub num_lit, _: 11, 8;
1085    num_code_0, _: 7, 4;
1086    /// On any write to FP_CTRL, this bit must be 1. A write to the register with this bit set to zero
1087    /// is ignored. The Flash Patch Breakpoint unit ignores the write unless this bit is 1.
1088    pub _, set_key: 1;
1089    /// Enable bit for the FPB:
1090    /// 0 Flash Patch breakpoint disabled.
1091    /// 1 Flash Patch breakpoint enabled.
1092    /// A power-on reset clears this bit to 0.
1093    pub enable, set_enable: 0;
1094}
1095
1096impl FpCtrl {
1097    /// The number of instruction address comparators.
1098    /// If NUM_CODE is zero, the implementation does not support any instruction address comparators.
1099    pub fn num_code(&self) -> u32 {
1100        (self.num_code_1() << 4) | self.num_code_0()
1101    }
1102}
1103
1104impl MemoryMappedRegister<u32> for FpCtrl {
1105    const ADDRESS_OFFSET: u64 = 0xE000_2000;
1106    const NAME: &'static str = "FP_CTRL";
1107}
1108
1109impl From<u32> for FpCtrl {
1110    fn from(value: u32) -> Self {
1111        FpCtrl(value)
1112    }
1113}
1114
1115impl From<FpCtrl> for u32 {
1116    fn from(value: FpCtrl) -> Self {
1117        value.0
1118    }
1119}
1120
1121bitfield! {
1122    /// FP_COMPn, Flash Patch Comparator Register, n = 0 - 125 (see armv8-M Architecture Reference Manual D1.2.107)
1123    #[derive(Copy,Clone)]
1124    pub struct FpCompN(u32);
1125    impl Debug;
1126    /// BPADDR, `bits[31:1]` Breakpoint address. Specifies bits`[31:1]` of the breakpoint instruction address.
1127    /// If BE == 0, this field is Reserved, UNK/SBZP.
1128    /// The reset value of this field is UNKNOWN.
1129    pub bp_addr, set_bp_addr: 31, 1;
1130    /// Enable bit for breakpoint:
1131    /// 0 Breakpoint disabled.
1132    /// 1 Breakpoint enabled.
1133    /// The reset value of this bit is UNKNOWN.
1134    pub enable, set_enable: 0;
1135}
1136
1137impl MemoryMappedRegister<u32> for FpCompN {
1138    const ADDRESS_OFFSET: u64 = 0xE000_2008;
1139    const NAME: &'static str = "FP_COMPn";
1140}
1141
1142impl From<u32> for FpCompN {
1143    fn from(value: u32) -> Self {
1144        FpCompN(value)
1145    }
1146}
1147
1148impl From<FpCompN> for u32 {
1149    fn from(value: FpCompN) -> Self {
1150        value.0
1151    }
1152}