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