probe_rs/
core.rs

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