Skip to main content

probe_rs/
core.rs

1use crate::{
2    CoreType, Endian, InstructionSet, MemoryInterface, Target,
3    architecture::{
4        arm::sequences::{ArmDebugSequence, DefaultArmSequence},
5        riscv::sequences::{DefaultRiscvSequence, RiscvDebugSequence},
6        xtensa::sequences::{DefaultXtensaSequence, XtensaDebugSequence},
7    },
8    config::DebugSequence,
9    error::{BreakpointError, Error},
10    memory::CoreMemoryInterface,
11};
12pub use probe_rs_target::{Architecture, CoreAccessOptions};
13use probe_rs_target::{
14    ArmCoreAccessOptions, MemoryRegion, RiscvCoreAccessOptions, XtensaCoreAccessOptions,
15};
16use std::{sync::Arc, time::Duration};
17
18pub mod core_state;
19pub mod core_status;
20#[cfg(feature = "coredump")]
21pub mod dump;
22pub mod memory_mapped_registers;
23pub mod registers;
24
25pub use core_state::*;
26pub use core_status::*;
27pub use memory_mapped_registers::MemoryMappedRegister;
28pub use registers::*;
29
30/// An struct for storing the current state of a core.
31#[derive(Debug, Clone)]
32pub struct CoreInformation {
33    /// The current Program Counter.
34    pub pc: u64,
35}
36
37/// A generic interface to control a MCU core.
38pub trait CoreInterface: MemoryInterface {
39    /// Wait until the core is halted. If the core does not halt on its own,
40    /// a [`DebugProbeError::Timeout`](crate::probe::DebugProbeError::Timeout) error will be returned.
41    fn wait_for_core_halted(&mut self, timeout: Duration) -> Result<(), Error>;
42
43    /// Check if the core is halted. If the core does not halt on its own,
44    /// a [`DebugProbeError::Timeout`](crate::probe::DebugProbeError::Timeout) error will be returned.
45    fn core_halted(&mut self) -> Result<bool, Error>;
46
47    /// Returns the current status of the core.
48    fn status(&mut self) -> Result<CoreStatus, Error>;
49
50    /// Try to halt the core. This function ensures the core is actually halted, and
51    /// returns a [`DebugProbeError::Timeout`](crate::probe::DebugProbeError::Timeout) otherwise.
52    fn halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error>;
53
54    /// Continue to execute instructions.
55    fn run(&mut self) -> Result<(), Error>;
56
57    /// Reset the core, and then continue to execute instructions. If the core
58    /// should be halted after reset, use the [`reset_and_halt`] function.
59    ///
60    /// [`reset_and_halt`]: Core::reset_and_halt
61    fn reset(&mut self) -> Result<(), Error>;
62
63    /// Reset the core, and then immediately halt. To continue execution after
64    /// reset, use the [`reset`] function.
65    ///
66    /// [`reset`]: Core::reset
67    fn reset_and_halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error>;
68
69    /// Steps one instruction and then enters halted state again.
70    fn step(&mut self) -> Result<CoreInformation, Error>;
71
72    /// Read the value of a core register.
73    fn read_core_reg(&mut self, address: RegisterId) -> Result<RegisterValue, Error>;
74
75    /// Write the value of a core register.
76    fn write_core_reg(&mut self, address: RegisterId, value: RegisterValue) -> Result<(), Error>;
77
78    /// Returns all the available breakpoint units of the core.
79    fn available_breakpoint_units(&mut self) -> Result<u32, Error>;
80
81    /// Read the hardware breakpoints from FpComp registers, and adds them to the Result Vector.
82    /// A value of None in any position of the Vector indicates that the position is unset/available.
83    /// We intentionally return all breakpoints, irrespective of whether they are enabled or not.
84    fn hw_breakpoints(&mut self) -> Result<Vec<Option<u64>>, Error>;
85
86    /// Enables breakpoints on this core. If a breakpoint is set, it will halt as soon as it is hit.
87    fn enable_breakpoints(&mut self, state: bool) -> Result<(), Error>;
88
89    /// Sets a breakpoint at `addr`. It does so by using unit `bp_unit_index`.
90    fn set_hw_breakpoint(&mut self, unit_index: usize, addr: u64) -> Result<(), Error>;
91
92    /// Clears the breakpoint configured in unit `unit_index`.
93    fn clear_hw_breakpoint(&mut self, unit_index: usize) -> Result<(), Error>;
94
95    /// Returns a list of all the registers of this core.
96    fn registers(&self) -> &'static CoreRegisters;
97
98    /// Returns the program counter register.
99    fn program_counter(&self) -> &'static CoreRegister;
100
101    /// Returns the frame pointer register.
102    fn frame_pointer(&self) -> &'static CoreRegister;
103
104    /// Returns the stack pointer register.
105    fn stack_pointer(&self) -> &'static CoreRegister;
106
107    /// Returns the return address register, a.k.a. link register.
108    fn return_address(&self) -> &'static CoreRegister;
109
110    /// Returns `true` if hardware breakpoints are enabled, `false` otherwise.
111    fn hw_breakpoints_enabled(&self) -> bool;
112
113    /// Get the `Architecture` of the Core.
114    fn architecture(&self) -> Architecture;
115
116    /// Get the `CoreType` of the Core
117    fn core_type(&self) -> CoreType;
118
119    /// Determine the instruction set the core is operating in
120    /// This must be queried while halted as this is a runtime
121    /// decision for some core types
122    fn instruction_set(&mut self) -> Result<InstructionSet, Error>;
123
124    /// Return which endianness the core is currently in. Some cores
125    /// allow for changing the endianness.
126    fn endianness(&mut self) -> Result<Endian, Error> {
127        // Return little endian, since that is the most common mode by far.
128        Ok(Endian::Little)
129    }
130
131    /// Determine if an FPU is present.
132    /// This must be queried while halted as this is a runtime
133    /// decision for some core types.
134    fn fpu_support(&mut self) -> Result<bool, Error>;
135
136    /// Determine the number of floating point registers.
137    /// This must be queried while halted as this is a runtime
138    /// decision for some core types.
139    fn floating_point_register_count(&mut self) -> Result<usize, Error>;
140
141    /// Set the reset catch setting.
142    ///
143    /// This configures the core to halt after a reset.
144    ///
145    /// use `reset_catch_clear` to clear the setting again.
146    fn reset_catch_set(&mut self) -> Result<(), Error>;
147
148    /// Clear the reset catch setting.
149    ///
150    /// This will reset the changes done by `reset_catch_set`.
151    fn reset_catch_clear(&mut self) -> Result<(), Error>;
152
153    /// Called when we stop debugging a core.
154    fn debug_core_stop(&mut self) -> Result<(), Error>;
155
156    /// Enables vector catching for the given `condition`
157    fn enable_vector_catch(&mut self, _condition: VectorCatchCondition) -> Result<(), Error> {
158        Err(Error::NotImplemented("vector catch"))
159    }
160
161    /// Disables vector catching for the given `condition`
162    fn disable_vector_catch(&mut self, _condition: VectorCatchCondition) -> Result<(), Error> {
163        Err(Error::NotImplemented("vector catch"))
164    }
165
166    /// Check if the integer size is 64-bit
167    fn is_64_bit(&self) -> bool {
168        false
169    }
170
171    /// Spill registers into memory.
172    fn spill_registers(&mut self) -> Result<(), Error> {
173        // For most architectures, this is not necessary. Use cases include processors
174        // that have a windowed register file, where the whole register file is not visible at once.
175        Ok(())
176    }
177}
178
179/// Generic core handle representing a physical core on an MCU.
180///
181/// This should be considered as a temporary view of the core which locks the debug probe driver to as single consumer by borrowing it.
182///
183/// As soon as you did your atomic task (e.g. halt the core, read the core state and all other debug relevant info) you should drop this object,
184/// to allow potential other shareholders of the session struct to grab a core handle too.
185pub struct Core<'probe> {
186    id: usize,
187    name: &'probe str,
188    target: &'probe Target,
189
190    inner: Box<dyn CoreInterface + 'probe>,
191}
192
193impl CoreMemoryInterface for Core<'_> {
194    type ErrorType = Error;
195
196    fn memory(&self) -> &dyn MemoryInterface<Self::ErrorType> {
197        self.inner.as_ref()
198    }
199
200    fn memory_mut(&mut self) -> &mut dyn MemoryInterface<Self::ErrorType> {
201        self.inner.as_mut()
202    }
203}
204
205impl<'probe> Core<'probe> {
206    /// Borrow the boxed CoreInterface mutable.
207    pub fn inner_mut(&mut self) -> &mut Box<dyn CoreInterface + 'probe> {
208        &mut self.inner
209    }
210
211    /// Create a new [`Core`].
212    pub(crate) fn new(
213        id: usize,
214        name: &'probe str,
215        target: &'probe Target,
216        core: impl CoreInterface + 'probe,
217    ) -> Core<'probe> {
218        Self {
219            id,
220            name,
221            target,
222            inner: Box::new(core),
223        }
224    }
225
226    /// Returns the memory regions associated with this core.
227    pub fn memory_regions(&self) -> impl Iterator<Item = &MemoryRegion> {
228        self.target
229            .memory_map
230            .iter()
231            .filter(|r| r.cores().iter().any(|m| m == self.name))
232    }
233
234    /// Returns the target descriptor of the current `Session`.
235    pub fn target(&self) -> &Target {
236        self.target
237    }
238
239    /// Creates a new [`CoreState`]
240    pub(crate) fn create_state(
241        id: usize,
242        options: CoreAccessOptions,
243        target: &Target,
244        core_type: CoreType,
245    ) -> CombinedCoreState {
246        CombinedCoreState {
247            id,
248            core_state: CoreState::new(ResolvedCoreOptions::new(target, options)),
249            specific_state: SpecificCoreState::from_core_type(core_type),
250        }
251    }
252
253    /// Returns the ID of this core.
254    pub fn id(&self) -> usize {
255        self.id
256    }
257
258    /// Wait until the core is halted. If the core does not halt on its own,
259    /// a [`DebugProbeError::Timeout`](crate::probe::DebugProbeError::Timeout) error will be returned.
260    #[tracing::instrument(skip(self))]
261    pub fn wait_for_core_halted(&mut self, timeout: Duration) -> Result<(), Error> {
262        self.inner.wait_for_core_halted(timeout)
263    }
264
265    /// Check if the core is halted. If the core does not halt on its own,
266    /// a [`DebugProbeError::Timeout`](crate::probe::DebugProbeError::Timeout) error will be returned.
267    pub fn core_halted(&mut self) -> Result<bool, Error> {
268        self.inner.core_halted()
269    }
270
271    /// Try to halt the core. This function ensures the core is actually halted, and
272    /// returns a [`DebugProbeError::Timeout`](crate::probe::DebugProbeError::Timeout) otherwise.
273    #[tracing::instrument(skip(self))]
274    pub fn halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error> {
275        self.inner.halt(timeout)
276    }
277
278    /// Continue to execute instructions.
279    #[tracing::instrument(skip(self))]
280    pub fn run(&mut self) -> Result<(), Error> {
281        self.inner.run()
282    }
283
284    /// Reset the core, and then continue to execute instructions. If the core
285    /// should be halted after reset, use the [`reset_and_halt`] function.
286    ///
287    /// [`reset_and_halt`]: Core::reset_and_halt
288    #[tracing::instrument(skip(self))]
289    pub fn reset(&mut self) -> Result<(), Error> {
290        self.inner.reset()
291    }
292
293    /// Reset the core, and then immediately halt. To continue execution after
294    /// reset, use the [`reset`] function.
295    ///
296    /// [`reset`]: Core::reset
297    #[tracing::instrument(skip(self))]
298    pub fn reset_and_halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error> {
299        self.inner.reset_and_halt(timeout)
300    }
301
302    /// Steps one instruction and then enters halted state again.
303    #[tracing::instrument(skip(self))]
304    pub fn step(&mut self) -> Result<CoreInformation, Error> {
305        self.inner.step()
306    }
307
308    /// Returns the current status of the core.
309    #[tracing::instrument(level = "trace", skip(self))]
310    pub fn status(&mut self) -> Result<CoreStatus, Error> {
311        self.inner.status()
312    }
313
314    /// Read the value of a core register.
315    ///
316    /// # Remarks
317    ///
318    /// `T` can be an unsigned integer type, such as [u32] or [u64], or
319    /// it can be [RegisterValue] to allow the caller to support arbitrary
320    /// length registers.
321    ///
322    /// To add support to convert to a custom type implement [`TryInto<CustomType>`]
323    /// for [RegisterValue].
324    ///
325    /// # Errors
326    ///
327    /// If `T` isn't large enough to hold the register value an error will be raised.
328    #[tracing::instrument(skip(self, address), fields(address))]
329    pub fn read_core_reg<T>(&mut self, address: impl Into<RegisterId>) -> Result<T, Error>
330    where
331        RegisterValue: TryInto<T>,
332        Result<T, <RegisterValue as TryInto<T>>::Error>: RegisterValueResultExt<T>,
333    {
334        let address = address.into();
335
336        tracing::Span::current().record("address", format!("{address:?}"));
337
338        let value = self.inner.read_core_reg(address)?;
339
340        value.try_into().into_crate_error()
341    }
342
343    /// Write the value of a core register.
344    ///
345    /// # Errors
346    ///
347    /// If T is too large to write to the target register an error will be raised.
348    #[tracing::instrument(skip(self, address, value))]
349    pub fn write_core_reg<T>(
350        &mut self,
351        address: impl Into<RegisterId>,
352        value: T,
353    ) -> Result<(), Error>
354    where
355        T: Into<RegisterValue>,
356    {
357        let address = address.into();
358
359        self.inner.write_core_reg(address, value.into())
360    }
361
362    /// Returns all the available breakpoint units of the core.
363    pub fn available_breakpoint_units(&mut self) -> Result<u32, Error> {
364        self.inner.available_breakpoint_units()
365    }
366
367    /// Enables breakpoints on this core. If a breakpoint is set, it will halt as soon as it is hit.
368    fn enable_breakpoints(&mut self, state: bool) -> Result<(), Error> {
369        self.inner.enable_breakpoints(state)
370    }
371
372    /// Returns a list of all the registers of this core.
373    pub fn registers(&self) -> &'static CoreRegisters {
374        self.inner.registers()
375    }
376
377    /// Returns the program counter register.
378    pub fn program_counter(&self) -> &'static CoreRegister {
379        self.inner.program_counter()
380    }
381
382    /// Returns the frame pointer register.
383    pub fn frame_pointer(&self) -> &'static CoreRegister {
384        self.inner.frame_pointer()
385    }
386
387    /// Returns the stack pointer register.
388    pub fn stack_pointer(&self) -> &'static CoreRegister {
389        self.inner.stack_pointer()
390    }
391
392    /// Returns the return address register, a.k.a. link register.
393    pub fn return_address(&self) -> &'static CoreRegister {
394        self.inner.return_address()
395    }
396
397    /// Set a hardware breakpoint
398    ///
399    /// This function will try to set a hardware breakpoint at `address`.
400    ///
401    /// The amount of hardware breakpoints which are supported is chip specific,
402    /// and can be queried using the `get_available_breakpoint_units` function.
403    #[tracing::instrument(skip(self))]
404    pub fn set_hw_breakpoint(&mut self, address: u64) -> Result<(), Error> {
405        if !self.inner.hw_breakpoints_enabled() {
406            self.enable_breakpoints(true)?;
407        }
408
409        // If there is a breakpoint set already, return its bp_unit_index, else find the next free index.
410        let breakpoints = self.inner.hw_breakpoints()?;
411        let breakpoint_comparator_index =
412            match breakpoints.iter().position(|&bp| bp == Some(address)) {
413                Some(breakpoint_comparator_index) => breakpoint_comparator_index,
414                None => breakpoints
415                    .iter()
416                    .position(|bp| bp.is_none())
417                    .ok_or_else(|| Error::Other("No available hardware breakpoints".to_string()))?,
418            };
419
420        tracing::debug!(
421            "Trying to set HW breakpoint #{} with comparator address  {:#08x}",
422            breakpoint_comparator_index,
423            address
424        );
425
426        // Actually set the breakpoint. Even if it has been set, set it again so it will be active.
427        self.inner
428            .set_hw_breakpoint(breakpoint_comparator_index, address)
429    }
430
431    /// Set a hardware breakpoint
432    ///
433    /// This function will try to set a given hardware breakpoint unit to `address`.
434    ///
435    /// The amount of hardware breakpoints which are supported is chip specific,
436    /// and can be queried using the `get_available_breakpoint_units` function.
437    #[tracing::instrument(skip(self))]
438    pub fn set_hw_breakpoint_unit(&mut self, unit_index: usize, addr: u64) -> Result<(), Error> {
439        if !self.inner.hw_breakpoints_enabled() {
440            self.enable_breakpoints(true)?;
441        }
442
443        tracing::debug!(
444            "Trying to set HW breakpoint #{} with comparator address  {:#08x}",
445            unit_index,
446            addr
447        );
448
449        self.inner.set_hw_breakpoint(unit_index, addr)
450    }
451
452    /// Set a hardware breakpoint
453    ///
454    /// This function will try to clear a hardware breakpoint at `address` if there exists a breakpoint at that address.
455    #[tracing::instrument(skip(self))]
456    pub fn clear_hw_breakpoint(&mut self, address: u64) -> Result<(), Error> {
457        let bp_position = self
458            .inner
459            .hw_breakpoints()?
460            .iter()
461            .position(|bp| *bp == Some(address));
462
463        tracing::debug!(
464            "Will clear HW breakpoint    #{} with comparator address    {:#08x}",
465            bp_position.unwrap_or(usize::MAX),
466            address
467        );
468
469        match bp_position {
470            Some(bp_position) => {
471                self.inner.clear_hw_breakpoint(bp_position)?;
472                Ok(())
473            }
474            None => Err(Error::BreakpointOperation(BreakpointError::NotFound(
475                address,
476            ))),
477        }
478    }
479
480    /// Clear all hardware breakpoints
481    ///
482    /// This function will clear all HW breakpoints which are configured on the target,
483    /// regardless if they are set by probe-rs, AND regardless if they are enabled or not.
484    /// Also used as a helper function in [`Session::drop`](crate::session::Session).
485    #[tracing::instrument(skip(self))]
486    pub fn clear_all_hw_breakpoints(&mut self) -> Result<(), Error> {
487        for breakpoint in (self.inner.hw_breakpoints()?).into_iter().flatten() {
488            self.clear_hw_breakpoint(breakpoint)?
489        }
490        Ok(())
491    }
492
493    /// Returns the architecture of the core.
494    pub fn architecture(&self) -> Architecture {
495        self.inner.architecture()
496    }
497
498    /// Returns the core type of the core
499    pub fn core_type(&self) -> CoreType {
500        self.inner.core_type()
501    }
502
503    /// Determine the instruction set the core is operating in
504    /// This must be queried while halted as this is a runtime
505    /// decision for some core types
506    pub fn instruction_set(&mut self) -> Result<InstructionSet, Error> {
507        self.inner.instruction_set()
508    }
509
510    /// Determine if an FPU is present.
511    /// This must be queried while halted as this is a runtime
512    /// decision for some core types.
513    pub fn fpu_support(&mut self) -> Result<bool, Error> {
514        self.inner.fpu_support()
515    }
516
517    /// Determine the number of floating point registers.
518    /// This must be queried while halted as this is a runtime decision for some core types.
519    pub fn floating_point_register_count(&mut self) -> Result<usize, Error> {
520        self.inner.floating_point_register_count()
521    }
522
523    pub(crate) fn reset_catch_set(&mut self) -> Result<(), Error> {
524        self.inner.reset_catch_set()
525    }
526
527    pub(crate) fn reset_catch_clear(&mut self) -> Result<(), Error> {
528        self.inner.reset_catch_clear()
529    }
530
531    pub(crate) fn debug_core_stop(&mut self) -> Result<(), Error> {
532        self.inner.debug_core_stop()
533    }
534
535    /// Enables vector catching for the given `condition`
536    pub fn enable_vector_catch(&mut self, condition: VectorCatchCondition) -> Result<(), Error> {
537        self.inner.enable_vector_catch(condition)
538    }
539
540    /// Disables vector catching for the given `condition`
541    pub fn disable_vector_catch(&mut self, condition: VectorCatchCondition) -> Result<(), Error> {
542        self.inner.disable_vector_catch(condition)
543    }
544
545    /// Check if the integer size is 64-bit
546    pub fn is_64_bit(&self) -> bool {
547        self.inner.is_64_bit()
548    }
549
550    /// Spill registers into memory.
551    pub fn spill_registers(&mut self) -> Result<(), Error> {
552        self.inner.spill_registers()
553    }
554}
555
556impl CoreInterface for Core<'_> {
557    fn wait_for_core_halted(&mut self, timeout: Duration) -> Result<(), Error> {
558        self.wait_for_core_halted(timeout)
559    }
560
561    fn core_halted(&mut self) -> Result<bool, Error> {
562        self.core_halted()
563    }
564
565    fn status(&mut self) -> Result<CoreStatus, Error> {
566        self.status()
567    }
568
569    fn halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error> {
570        self.halt(timeout)
571    }
572
573    fn run(&mut self) -> Result<(), Error> {
574        self.run()
575    }
576
577    fn reset(&mut self) -> Result<(), Error> {
578        self.reset()
579    }
580
581    fn reset_and_halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error> {
582        self.reset_and_halt(timeout)
583    }
584
585    fn step(&mut self) -> Result<CoreInformation, Error> {
586        self.step()
587    }
588
589    fn read_core_reg(&mut self, address: RegisterId) -> Result<RegisterValue, Error> {
590        self.read_core_reg(address)
591    }
592
593    fn write_core_reg(&mut self, address: RegisterId, value: RegisterValue) -> Result<(), Error> {
594        self.write_core_reg(address, value)
595    }
596
597    fn available_breakpoint_units(&mut self) -> Result<u32, Error> {
598        self.available_breakpoint_units()
599    }
600
601    fn hw_breakpoints(&mut self) -> Result<Vec<Option<u64>>, Error> {
602        self.inner.hw_breakpoints()
603    }
604
605    fn enable_breakpoints(&mut self, state: bool) -> Result<(), Error> {
606        self.enable_breakpoints(state)
607    }
608
609    fn set_hw_breakpoint(&mut self, unit_index: usize, addr: u64) -> Result<(), Error> {
610        self.set_hw_breakpoint_unit(unit_index, addr)
611    }
612
613    fn clear_hw_breakpoint(&mut self, unit_index: usize) -> Result<(), Error> {
614        self.inner.clear_hw_breakpoint(unit_index)?;
615        Ok(())
616    }
617
618    fn registers(&self) -> &'static CoreRegisters {
619        self.registers()
620    }
621
622    fn program_counter(&self) -> &'static CoreRegister {
623        self.program_counter()
624    }
625
626    fn frame_pointer(&self) -> &'static CoreRegister {
627        self.frame_pointer()
628    }
629
630    fn stack_pointer(&self) -> &'static CoreRegister {
631        self.stack_pointer()
632    }
633
634    fn return_address(&self) -> &'static CoreRegister {
635        self.return_address()
636    }
637
638    fn hw_breakpoints_enabled(&self) -> bool {
639        self.inner.hw_breakpoints_enabled()
640    }
641
642    fn architecture(&self) -> Architecture {
643        self.architecture()
644    }
645
646    fn core_type(&self) -> CoreType {
647        self.core_type()
648    }
649
650    /// Returns the endianness of the current operating mode
651    /// of the core.
652    fn endianness(&mut self) -> Result<Endian, Error> {
653        self.inner.endianness()
654    }
655
656    fn instruction_set(&mut self) -> Result<InstructionSet, Error> {
657        self.instruction_set()
658    }
659
660    fn fpu_support(&mut self) -> Result<bool, Error> {
661        self.fpu_support()
662    }
663
664    fn floating_point_register_count(&mut self) -> Result<usize, crate::error::Error> {
665        self.floating_point_register_count()
666    }
667
668    fn reset_catch_set(&mut self) -> Result<(), Error> {
669        self.reset_catch_set()
670    }
671
672    fn reset_catch_clear(&mut self) -> Result<(), Error> {
673        self.reset_catch_clear()
674    }
675
676    fn debug_core_stop(&mut self) -> Result<(), Error> {
677        self.debug_core_stop()
678    }
679
680    fn is_64_bit(&self) -> bool {
681        self.is_64_bit()
682    }
683
684    fn spill_registers(&mut self) -> Result<(), Error> {
685        self.spill_registers()
686    }
687}
688
689pub enum ResolvedCoreOptions {
690    Arm {
691        sequence: Arc<dyn ArmDebugSequence>,
692        options: ArmCoreAccessOptions,
693    },
694    Riscv {
695        sequence: Arc<dyn RiscvDebugSequence>,
696        options: RiscvCoreAccessOptions,
697    },
698    Xtensa {
699        sequence: Arc<dyn XtensaDebugSequence>,
700        options: XtensaCoreAccessOptions,
701    },
702}
703
704impl ResolvedCoreOptions {
705    fn new(target: &Target, options: CoreAccessOptions) -> Self {
706        // When the target's debug_sequence doesn't match this core's architecture (e.g.
707        // RP235x_riscv where the vendor returns Arm(Rp235x) for the family), use the default
708        // sequence for this core's architecture so attach still works.
709        match options {
710            CoreAccessOptions::Arm(options) => {
711                let sequence = match &target.debug_sequence {
712                    DebugSequence::Arm(s) => s.clone(),
713                    _ => DefaultArmSequence::create(),
714                };
715                Self::Arm { sequence, options }
716            }
717            CoreAccessOptions::Riscv(options) => {
718                let sequence = match &target.debug_sequence {
719                    DebugSequence::Riscv(s) => s.clone(),
720                    _ => DefaultRiscvSequence::create(),
721                };
722                Self::Riscv { sequence, options }
723            }
724            CoreAccessOptions::Xtensa(options) => {
725                let sequence = match &target.debug_sequence {
726                    DebugSequence::Xtensa(s) => s.clone(),
727                    _ => DefaultXtensaSequence::create(),
728                };
729                Self::Xtensa { sequence, options }
730            }
731        }
732    }
733
734    fn jtag_tap_index(&self) -> usize {
735        match self {
736            Self::Arm { options, .. } => options.jtag_tap.unwrap_or(0),
737            Self::Riscv { options, .. } => options.jtag_tap.unwrap_or(0),
738            Self::Xtensa { options, .. } => options.jtag_tap.unwrap_or(0),
739        }
740    }
741}
742
743impl std::fmt::Debug for ResolvedCoreOptions {
744    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
745        match self {
746            Self::Arm { options, .. } => f
747                .debug_struct("Arm")
748                .field("sequence", &"<ArmDebugSequence>")
749                .field("options", options)
750                .finish(),
751            Self::Riscv { options, .. } => f
752                .debug_struct("Riscv")
753                .field("sequence", &"<RiscvDebugSequence>")
754                .field("options", options)
755                .finish(),
756            Self::Xtensa { options, .. } => f
757                .debug_struct("Xtensa")
758                .field("sequence", &"<XtensaDebugSequence>")
759                .field("options", options)
760                .finish(),
761        }
762    }
763}