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