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