Skip to main content

probe_rs/architecture/riscv/
communication_interface.rs

1//! Debug Module Communication
2//!
3//! This module implements communication with a
4//! Debug Module, as described in the RISC-V debug
5//! specification v0.13 and v1.0.
6
7use crate::architecture::riscv::dtm::DtmAccess;
8use crate::memory::valid_32bit_address;
9use crate::probe::queue::DeferredResultIndex;
10use crate::{
11    Error as ProbeRsError, architecture::riscv::*, config::Target, memory_mapped_bitfield_register,
12};
13use std::any::Any;
14use std::collections::HashMap;
15use std::ops::Range;
16
17/// Some error occurred when working with the RISC-V core.
18#[derive(thiserror::Error, Debug)]
19pub enum RiscvError {
20    /// An error occurred during transport
21    #[error("Error during transport")]
22    DtmOperationFailed,
23    /// DMI operation is in progress
24    #[error("Transport operation in progress")]
25    DtmOperationInProcess,
26    /// An error with operating the debug probe occurred.
27    #[error("Debug Probe Error")]
28    DebugProbe(#[from] DebugProbeError),
29    /// A timeout occurred during DMI access.
30    #[error("Timeout during DMI access.")]
31    Timeout,
32    /// An error occurred during the execution of an abstract command.
33    #[error("Error occurred during execution of an abstract command: {0:?}")]
34    AbstractCommand(AbstractCommandErrorKind),
35    /// The request for reset, resume or halt was not acknowledged.
36    #[error("The core did not acknowledge a request for reset, resume or halt")]
37    RequestNotAcknowledged,
38    /// This debug transport module (DTM) version is currently not supported.
39    #[error("The version '{0}' of the debug transport module (DTM) is currently not supported.")]
40    UnsupportedDebugTransportModuleVersion(u8),
41    /// This version of the debug module is not supported.
42    #[error("The version '{0:?}' of the debug module is currently not supported.")]
43    UnsupportedDebugModuleVersion(DebugModuleVersion),
44    /// The provided csr address was invalid/unsupported
45    #[error("CSR at address '{0:x}' is unsupported.")]
46    UnsupportedCsrAddress(u16),
47    /// The given program buffer register is not supported.
48    #[error("Program buffer register '{0}' is currently not supported.")]
49    UnsupportedProgramBufferRegister(usize),
50    /// The program buffer is too small for the supplied program.
51    #[error(
52        "Program buffer is too small for supplied program. Required: {required}, Actual: {actual}"
53    )]
54    ProgramBufferTooSmall {
55        /// The required size of the program buffer.
56        required: usize,
57        /// The actual size of the program buffer.
58        actual: usize,
59    },
60    /// Memory width larger than 32 bits is not supported yet.
61    #[error("Memory width larger than 32 bits is not supported yet.")]
62    UnsupportedBusAccessWidth(RiscvBusAccess),
63    /// An error during system bus access occurred.
64    #[error("Error using system bus")]
65    SystemBusAccess,
66    /// The given trigger type is not available for the address breakpoint.
67    #[error("Unexpected trigger type {0} for address breakpoint.")]
68    UnexpectedTriggerType(u32),
69    /// The connected target is not a RISC-V device.
70    #[error("Connected target is not a RISC-V device.")]
71    NoRiscvTarget,
72    /// The target does not support halt after reset.
73    #[error("The target does not support halt after reset.")]
74    ResetHaltRequestNotSupported,
75    /// The result index of a batched command is not available.
76    #[error("The requested data is not available due to a previous error.")]
77    BatchedResultNotAvailable,
78    /// The hart is unavailable
79    #[error("The requested hart is unavailable.")]
80    HartUnavailable,
81}
82
83impl From<RiscvError> for ProbeRsError {
84    fn from(err: RiscvError) -> Self {
85        match err {
86            RiscvError::DebugProbe(e) => e.into(),
87            other => ProbeRsError::Riscv(other),
88        }
89    }
90}
91
92/// Errors which can occur while executing an abstract command.
93#[derive(Debug)]
94pub enum AbstractCommandErrorKind {
95    /// An abstract command was executing
96    /// while command, `abstractcs`, or `abstractauto`
97    /// was written, or when one of the `data` or `progbuf`
98    /// registers was read or written. This status is only
99    /// written if `cmderr` contains 0.
100    Busy = 1,
101    /// The requested command is not supported
102    NotSupported = 2,
103    /// An exception occurred while executing the command (e.g. while executing the Program Buffer).
104    Exception = 3,
105    /// The abstract command couldn’t
106    /// execute because the hart wasn’t in the required
107    /// state (running/halted), or unavailable.
108    HaltResume = 4,
109    /// The abstract command failed due to a
110    /// bus error (e.g. alignment, access size, or timeout).
111    Bus = 5,
112    /// A reserved code. Should not occur.
113    _Reserved = 6,
114    /// The command failed for another reason.
115    Other = 7,
116}
117
118impl From<AbstractCommandErrorKind> for RiscvError {
119    fn from(err: AbstractCommandErrorKind) -> Self {
120        RiscvError::AbstractCommand(err)
121    }
122}
123
124impl AbstractCommandErrorKind {
125    fn parse(status: Abstractcs) -> Result<(), Self> {
126        let err = match status.cmderr() {
127            0 => return Ok(()),
128            1 => Self::Busy,
129            2 => Self::NotSupported,
130            3 => Self::Exception,
131            4 => Self::HaltResume,
132            5 => Self::Bus,
133            6 => Self::_Reserved,
134            7 => Self::Other,
135            _ => unreachable!("cmderr is a 3 bit value, values higher than 7 should not occur."),
136        };
137
138        Err(err)
139    }
140}
141
142/// List of all debug module versions.
143///
144/// The version of the debug module can be read from the version field of the `dmstatus`
145/// register.
146#[derive(Debug, Copy, Clone, PartialEq, Eq)]
147pub enum DebugModuleVersion {
148    /// There is no debug module present.
149    NoModule,
150    /// The debug module conforms to the version 0.11 of the RISC-V Debug Specification.
151    Version0_11,
152    /// The debug module conforms to the version 0.13 of the RISC-V Debug Specification.
153    Version0_13,
154    /// The debug module conforms to the version 1.0 of the RISC-V Debug Specification.
155    Version1_0,
156    /// The debug module is present, but does not conform to any available version of the RISC-V Debug Specification.
157    NonConforming,
158    /// Unknown debug module version.
159    Unknown(u8),
160}
161
162impl DebugModuleVersion {
163    fn is_implemented(self) -> bool {
164        matches!(
165            self,
166            DebugModuleVersion::Version0_13 | DebugModuleVersion::Version1_0
167        )
168    }
169}
170
171impl From<u8> for DebugModuleVersion {
172    fn from(raw: u8) -> Self {
173        match raw {
174            0 => Self::NoModule,
175            1 => Self::Version0_11,
176            2 => Self::Version0_13,
177            3 => Self::Version1_0,
178            15 => Self::NonConforming,
179            other => Self::Unknown(other),
180        }
181    }
182}
183
184#[derive(Copy, Clone, Debug)]
185struct CoreRegisterAbstractCmdSupport(u8);
186
187impl CoreRegisterAbstractCmdSupport {
188    const READ: Self = Self(1 << 0);
189    const WRITE: Self = Self(1 << 1);
190    const BOTH: Self = Self(Self::READ.0 | Self::WRITE.0);
191
192    fn supports(&self, o: Self) -> bool {
193        self.0 & o.0 == o.0
194    }
195
196    fn unset(&mut self, o: Self) {
197        self.0 &= !(o.0);
198    }
199}
200
201/// Save stack of a scratch register.
202// TODO: we probably only need an Option, we don't seem to use scratch registers in nested situations.
203#[derive(Debug, Default)]
204struct ScratchState {
205    stack: Vec<u32>,
206}
207
208impl ScratchState {
209    fn push(&mut self, value: u32) {
210        self.stack.push(value);
211    }
212
213    fn pop(&mut self) -> Option<u32> {
214        self.stack.pop()
215    }
216}
217
218/// Describes the method which should be used to access memory.
219#[derive(Default, Debug)]
220pub struct MemoryAccessConfig {
221    has_program_buffer: bool,
222
223    /// Describes, which memory access method should be used for a given access width
224    default_method: HashMap<RiscvBusAccess, MemoryAccessMethod>,
225
226    region_override: HashMap<(Range<u64>, RiscvBusAccess), MemoryAccessMethod>,
227}
228
229impl MemoryAccessConfig {
230    /// Sets the default memory access method for the given access width.
231    pub fn set_default_method(&mut self, access: RiscvBusAccess, method: MemoryAccessMethod) {
232        self.default_method.insert(access, method);
233    }
234
235    /// Sets a memory access method override for the given access size and address range.
236    pub fn set_region_override(
237        &mut self,
238        access: RiscvBusAccess,
239        range: Range<u64>,
240        method: MemoryAccessMethod,
241    ) {
242        self.region_override.insert((range, access), method);
243    }
244
245    /// Returns the default memory access method for the given access width.
246    pub fn default_method(&self, access: RiscvBusAccess) -> MemoryAccessMethod {
247        self.default_method
248            .get(&access)
249            .copied()
250            .unwrap_or(if self.has_program_buffer {
251                MemoryAccessMethod::ProgramBuffer
252            } else {
253                MemoryAccessMethod::AbstractCommand
254            })
255    }
256
257    /// Returns the memory access method for the given address and access width.
258    pub fn method(&self, address: u64, access: RiscvBusAccess) -> MemoryAccessMethod {
259        for ((range, method_access), method) in &self.region_override {
260            if range.contains(&address) && method_access == &access {
261                return *method;
262            }
263        }
264
265        self.default_method(access)
266    }
267
268    /// Returns the memory access method for the given address range and access width.
269    pub fn range_method(
270        &self,
271        address_range: Range<u64>,
272        access: RiscvBusAccess,
273    ) -> MemoryAccessMethod {
274        fn range_overlaps(range: &Range<u64>, address_range: &Range<u64>) -> bool {
275            range.start < address_range.end && address_range.start < range.end
276        }
277
278        let mut max = self.default_method(access);
279
280        for ((range, method_access), method) in &self.region_override {
281            if range_overlaps(range, &address_range) && method_access == &access {
282                max = std::cmp::min(*method, max);
283            }
284        }
285
286        max
287    }
288}
289
290/// A state to carry all the state data across multiple core switches in a session.
291#[derive(Debug)]
292pub struct RiscvCommunicationInterfaceState {
293    /// Debug specification version
294    debug_version: DebugModuleVersion,
295
296    /// Size of the program buffer, in 32-bit words
297    progbuf_size: u8,
298
299    /// Cache for the program buffer.
300    progbuf_cache: [u32; 16],
301
302    /// Implicit `ebreak` instruction is present after the
303    /// the program buffer.
304    implicit_ebreak: bool,
305
306    /// Number of data registers for abstract commands
307    data_register_count: u8,
308
309    /// Number of scratch registers
310    nscratch: u8,
311
312    /// Whether the target supports autoexecuting the program buffer
313    supports_autoexec: bool,
314
315    /// Pointer to the configuration string
316    confstrptr: Option<u128>,
317
318    /// Width of the `hartsel` register
319    hartsellen: u8,
320
321    /// Number of harts
322    num_harts: u32,
323
324    /// describes, if the given register can be read / written with an
325    /// abstract command
326    abstract_cmd_register_info: HashMap<RegisterId, CoreRegisterAbstractCmdSupport>,
327
328    /// First scratch register's state
329    s0: ScratchState,
330
331    /// Second scratch register's state
332    s1: ScratchState,
333
334    /// Bitfield of enabled harts
335    enabled_harts: u32,
336
337    /// The index of the last selected hart
338    last_selected_hart: u32,
339
340    /// Store the value of the `hasresethaltreq` bit of the `dmstatus` register.
341    hasresethaltreq: Option<bool>,
342
343    /// Whether the core is currently halted.
344    is_halted: bool,
345
346    /// The current value of the `dmcontrol` register.
347    current_dmcontrol: Dmcontrol,
348
349    memory_access_config: MemoryAccessConfig,
350
351    sw_breakpoint_debug_enabled: bool,
352
353    /// Whether the connected core is 64-bit (RV64). When true, memory access
354    /// methods will accept 64-bit addresses and CSR access uses 64-bit data registers.
355    pub(super) xlen_64: bool,
356
357    /// When true, `halted_access` will set `dcsr.prv = M` (machine mode) after
358    /// every internal halt and restore the original `prv` before resuming.
359    ///
360    /// Use this on targets (e.g. Nuclei UX600 running Linux) whose ILM/DLM are
361    /// not mapped in the supervisor page table: the program buffer must execute
362    /// at M-privilege so that physical addresses are used directly.
363    pub(crate) force_machine_mode_progbuf: bool,
364}
365
366/// Timeout for RISC-V operations.
367const RISCV_TIMEOUT: Duration = Duration::from_secs(5);
368
369/// RiscV only supports 12bit CSRs. See
370/// [Zicsr](https://riscv.org/wp-content/uploads/2019/06/riscv-spec.pdf#chapter.9) extension
371const RISCV_MAX_CSR_ADDR: u16 = 0xFFF;
372
373impl RiscvCommunicationInterfaceState {
374    /// Create a new interface state.
375    pub fn new() -> Self {
376        RiscvCommunicationInterfaceState {
377            // Set to the minimum here, will be set to the correct value below
378            progbuf_size: 0,
379            progbuf_cache: [0u32; 16],
380
381            debug_version: DebugModuleVersion::NonConforming,
382
383            // Assume the implicit ebreak is not present
384            implicit_ebreak: false,
385
386            // Set to the minimum here, will be set to the correct value below
387            data_register_count: 1,
388
389            nscratch: 0,
390
391            supports_autoexec: false,
392
393            confstrptr: None,
394
395            // Assume maximum value, will be determined exactly alter.
396            hartsellen: 20,
397
398            // We assume only a singe hart exists initially
399            num_harts: 1,
400
401            abstract_cmd_register_info: HashMap::new(),
402
403            s0: ScratchState::default(),
404            s1: ScratchState::default(),
405            enabled_harts: 0,
406            last_selected_hart: 0,
407            hasresethaltreq: None,
408            is_halted: false,
409
410            current_dmcontrol: Dmcontrol(0),
411
412            memory_access_config: MemoryAccessConfig::default(),
413
414            sw_breakpoint_debug_enabled: false,
415
416            xlen_64: false,
417            force_machine_mode_progbuf: false,
418        }
419    }
420
421    /// Get the memory access method which should be used for an
422    /// access with the specified width.
423    fn memory_access_method(
424        &mut self,
425        access_width: RiscvBusAccess,
426        address: u64,
427    ) -> MemoryAccessMethod {
428        self.memory_access_config.method(address, access_width)
429    }
430
431    fn memory_range_access_method(
432        &self,
433        width: RiscvBusAccess,
434        address_range: Range<u64>,
435    ) -> MemoryAccessMethod {
436        self.memory_access_config.range_method(address_range, width)
437    }
438}
439
440impl Default for RiscvCommunicationInterfaceState {
441    fn default() -> Self {
442        Self::new()
443    }
444}
445
446/// The combined state of a RISC-V debug module and its transport interface.
447pub struct RiscvDebugInterfaceState {
448    pub(crate) interface_state: RiscvCommunicationInterfaceState,
449    pub(super) dtm_state: Box<dyn Any + Send>,
450}
451
452impl RiscvDebugInterfaceState {
453    pub(crate) fn new(dtm_state: Box<dyn Any + Send>) -> Self {
454        Self {
455            interface_state: RiscvCommunicationInterfaceState::new(),
456            dtm_state,
457        }
458    }
459}
460
461/// A single-use factory for creating RISC-V communication interfaces and their states.
462pub trait RiscvInterfaceBuilder<'probe> {
463    /// Creates a new RISC-V communication interface state object.
464    ///
465    /// The state object needs to be stored separately from the communication interface
466    /// and can be used to restore the state of the interface at a later time.
467    fn create_state(&self) -> RiscvDebugInterfaceState;
468
469    /// Consumes the factory and creates a communication interface
470    /// object initialised with the given state.
471    fn attach<'state>(
472        self: Box<Self>,
473        state: &'state mut RiscvDebugInterfaceState,
474    ) -> Result<RiscvCommunicationInterface<'state>, DebugProbeError>
475    where
476        'probe: 'state;
477
478    /// Consumes the factory and creates a communication interface
479    /// object using a JTAG tunnel initialised with the given state.
480    fn attach_tunneled<'state>(
481        self: Box<Self>,
482        _tunnel_ir_id: u32,
483        _tunnel_ir_width: u32,
484        _state: &'state mut RiscvDebugInterfaceState,
485    ) -> Result<RiscvCommunicationInterface<'state>, DebugProbeError>
486    where
487        'probe: 'state,
488    {
489        Err(DebugProbeError::InterfaceNotAvailable {
490            interface_name: "Tunneled RISC-V",
491        })
492    }
493
494    /// Consumes the factory and creates a communication interface
495    /// object initialised with the given state.
496    ///
497    /// Automatically determines whether to use JTAG tunneling or not from the target.
498    fn attach_auto<'state>(
499        self: Box<Self>,
500        target: &Target,
501        state: &'state mut RiscvDebugInterfaceState,
502    ) -> Result<RiscvCommunicationInterface<'state>, DebugProbeError>
503    where
504        'probe: 'state,
505    {
506        let maybe_tunnel = target.jtag.as_ref().and_then(|j| j.riscv_tunnel.as_ref());
507        if let Some(tunnel) = maybe_tunnel {
508            self.attach_tunneled(tunnel.ir_id, tunnel.ir_width, state)
509        } else {
510            self.attach(state)
511        }
512    }
513}
514
515/// A interface that implements controls for RISC-V cores.
516#[derive(Debug)]
517pub struct RiscvCommunicationInterface<'state> {
518    /// The Debug Transport Module (DTM) is used to
519    /// communicate with the Debug Module on the target chip.
520    dtm: Box<dyn DtmAccess + 'state>,
521    state: &'state mut RiscvCommunicationInterfaceState,
522}
523
524impl<'state> RiscvCommunicationInterface<'state> {
525    /// Creates a new RISC-V communication interface with a given probe driver.
526    pub fn new(
527        dtm: Box<dyn DtmAccess + 'state>,
528        state: &'state mut RiscvCommunicationInterfaceState,
529    ) -> Self {
530        Self { dtm, state }
531    }
532
533    /// Select current hart
534    pub fn select_hart(&mut self, hart: u32) -> Result<(), RiscvError> {
535        if !self.hart_enabled(hart) {
536            return Err(RiscvError::HartUnavailable);
537        }
538
539        if self.state.last_selected_hart == hart {
540            return Ok(());
541        }
542
543        // Since we changed harts, we don't know the state of the Dmcontrol register anymore.
544        let mut control = self.read_dm_register::<Dmcontrol>()?;
545        control.set_dmactive(true);
546        control.set_hartsel(hart);
547        self.schedule_write_dm_register(control)?;
548        self.state.last_selected_hart = hart;
549        Ok(())
550    }
551
552    /// Check if the given hart is enabled
553    pub fn hart_enabled(&self, hart: u32) -> bool {
554        self.state.enabled_harts & (1 << hart) != 0
555    }
556
557    /// Assert the target reset
558    pub fn target_reset_assert(&mut self) -> Result<(), DebugProbeError> {
559        self.dtm.target_reset_assert()
560    }
561
562    /// Deassert the target reset.
563    pub fn target_reset_deassert(&mut self) -> Result<(), DebugProbeError> {
564        self.dtm.target_reset_deassert()
565    }
566
567    /// Read the targets idcode used as hint for chip detection
568    pub fn read_idcode(&mut self) -> Result<Option<u32>, DebugProbeError> {
569        self.dtm.read_idcode()
570    }
571
572    fn save_s0(&mut self) -> Result<bool, RiscvError> {
573        let s0 = self.abstract_cmd_register_read(registers::S0)?;
574
575        self.state.s0.push(s0);
576
577        Ok(true)
578    }
579
580    fn restore_s0(&mut self, saved: bool) -> Result<(), RiscvError> {
581        if saved {
582            let s0 = self.state.s0.pop().unwrap();
583
584            self.abstract_cmd_register_write(registers::S0, s0)?;
585        }
586
587        Ok(())
588    }
589
590    fn save_s1(&mut self) -> Result<bool, RiscvError> {
591        let s1 = self.abstract_cmd_register_read(registers::S1)?;
592
593        self.state.s1.push(s1);
594
595        Ok(true)
596    }
597
598    fn restore_s1(&mut self, saved: bool) -> Result<(), RiscvError> {
599        if saved {
600            let s1 = self.state.s1.pop().unwrap();
601
602            self.abstract_cmd_register_write(registers::S1, s1)?;
603        }
604
605        Ok(())
606    }
607
608    /// Enable the debug module on the target and detect which features
609    /// are supported.
610    pub fn enter_debug_mode(&mut self) -> Result<(), RiscvError> {
611        tracing::debug!("Building RISC-V interface");
612        self.dtm.init()?;
613
614        // Reset error bits from previous connections
615        self.dtm.clear_error_state()?;
616
617        // enable the debug module
618        let mut control = Dmcontrol(0);
619        control.set_dmactive(true);
620        self.schedule_write_dm_register(control)?;
621
622        // read the  version of the debug module
623        let status: Dmstatus = self.read_dm_register()?;
624
625        self.state.progbuf_cache.fill(0);
626        self.state.memory_access_config = MemoryAccessConfig::default();
627        self.state.debug_version = DebugModuleVersion::from(status.version() as u8);
628        self.state.is_halted = status.allhalted();
629
630        if !self.state.debug_version.is_implemented() {
631            return Err(RiscvError::UnsupportedDebugModuleVersion(
632                self.state.debug_version,
633            ));
634        }
635
636        self.state.implicit_ebreak = status.impebreak();
637
638        // check if the configuration string pointer is valid, and retrieve it, if valid
639        self.state.confstrptr = if status.confstrptrvalid() {
640            let confstrptr_0: Confstrptr0 = self.read_dm_register()?;
641            let confstrptr_1: Confstrptr1 = self.read_dm_register()?;
642            let confstrptr_2: Confstrptr2 = self.read_dm_register()?;
643            let confstrptr_3: Confstrptr3 = self.read_dm_register()?;
644            let confstrptr = (u32::from(confstrptr_0) as u128)
645                | ((u32::from(confstrptr_1) as u128) << 8)
646                | ((u32::from(confstrptr_2) as u128) << 16)
647                | ((u32::from(confstrptr_3) as u128) << 32);
648            Some(confstrptr)
649        } else {
650            None
651        };
652
653        tracing::debug!("dmstatus: {:?}", status);
654
655        // Select all harts to determine the width
656        // of the hartsel register.
657        let mut control = Dmcontrol(0);
658        control.set_dmactive(true);
659        control.set_hartsel(0xffff_ffff);
660
661        self.schedule_write_dm_register(control)?;
662
663        let control = self.read_dm_register::<Dmcontrol>()?;
664
665        self.state.hartsellen = control.hartsel().count_ones() as u8;
666
667        tracing::debug!("HARTSELLEN: {}", self.state.hartsellen);
668
669        // Determine number of harts
670
671        let max_hart_index = 2u32.pow(self.state.hartsellen as u32);
672
673        // Hart 0 exists on every chip
674        let mut num_harts = 1;
675        self.state.enabled_harts = 1;
676
677        // Check if anynonexistent is available.
678        // Some chips that have only one hart do not implement anynonexistent and allnonexistent.
679        // So let's check max hart index to see if we can use it reliably,
680        // or else we will assume only one hart exists.
681        let mut control = Dmcontrol(0);
682        control.set_dmactive(true);
683        control.set_hartsel(max_hart_index - 1);
684        self.schedule_write_dm_register(control)?;
685
686        // Check if the anynonexistent works
687        let status: Dmstatus = self.read_dm_register()?;
688
689        // Spec 1.0: stickyunavail means allunavail/anyunavail stay set until
690        // the debugger writes ackunavail=1. Check once and apply throughout.
691        let sticky_unavail = status.stickyunavail();
692
693        if status.anynonexistent() {
694            for hart_index in 1..max_hart_index {
695                let mut control = Dmcontrol(0);
696                control.set_dmactive(true);
697                control.set_hartsel(hart_index);
698                // Clear any sticky unavail state so we read fresh availability.
699                if sticky_unavail {
700                    control.set_ackunavail(true);
701                }
702
703                self.schedule_write_dm_register(control)?;
704
705                // Check if the current hart exists
706                let status: Dmstatus = self.read_dm_register()?;
707
708                if status.anynonexistent() {
709                    break;
710                }
711
712                if !status.allunavail() {
713                    self.state.enabled_harts |= 1 << num_harts;
714                }
715
716                num_harts += 1;
717            }
718        } else {
719            tracing::debug!("anynonexistent not supported, assuming only one hart exists")
720        }
721
722        tracing::debug!("Number of harts: {}", num_harts);
723
724        self.state.num_harts = num_harts;
725
726        // Select hart 0 again - assuming all harts are same in regards of discovered features.
727        // For spec 1.0 DMs, set the keepalive hint to discourage the hart from
728        // entering a low-power state while we are attached.
729        let mut control = Dmcontrol(0);
730        control.set_dmactive(true);
731        control.set_hartsel(0);
732        if self.state.debug_version == DebugModuleVersion::Version1_0 {
733            control.set_setkeepalive(true);
734        }
735
736        self.schedule_write_dm_register(control)?;
737
738        // determine size of the program buffer, and number of data
739        // registers for abstract commands
740        let abstractcs: Abstractcs = self.read_dm_register()?;
741
742        self.state.progbuf_size = abstractcs.progbufsize() as u8;
743        self.state.memory_access_config.has_program_buffer = self.state.progbuf_size != 0;
744        tracing::debug!("Program buffer size: {}", self.state.progbuf_size);
745
746        self.state.data_register_count = abstractcs.datacount() as u8;
747        tracing::debug!(
748            "Number of data registers: {}",
749            self.state.data_register_count
750        );
751
752        // determine more information about hart
753        let hartinfo: Hartinfo = self.read_dm_register()?;
754
755        self.state.nscratch = hartinfo.nscratch() as u8;
756        tracing::debug!("Number of dscratch registers: {}", self.state.nscratch);
757
758        // determine if autoexec works
759        let mut abstractauto = Abstractauto(0);
760        abstractauto.set_autoexecprogbuf(2u32.pow(self.state.progbuf_size as u32) - 1);
761        abstractauto.set_autoexecdata(2u32.pow(self.state.data_register_count as u32) - 1);
762
763        self.schedule_write_dm_register(abstractauto)?;
764
765        let abstractauto_readback: Abstractauto = self.read_dm_register()?;
766
767        self.state.supports_autoexec = abstractauto_readback == abstractauto;
768        tracing::debug!("Support for autoexec: {}", self.state.supports_autoexec);
769
770        // clear abstractauto
771        abstractauto = Abstractauto(0);
772        self.schedule_write_dm_register(abstractauto)?;
773
774        // determine support system bus access
775        let sbcs = self.read_dm_register::<Sbcs>()?;
776
777        // Only version 1 is supported, this means that
778        // the system bus access conforms to the debug
779        // specification 13.2.
780        if sbcs.sbversion() == 1 {
781            // When possible, we use system bus access for memory access
782
783            if sbcs.sbaccess8() {
784                self.state
785                    .memory_access_config
786                    .set_default_method(RiscvBusAccess::A8, MemoryAccessMethod::SystemBus);
787            }
788
789            if sbcs.sbaccess16() {
790                self.state
791                    .memory_access_config
792                    .set_default_method(RiscvBusAccess::A16, MemoryAccessMethod::SystemBus);
793            }
794
795            if sbcs.sbaccess32() {
796                self.state
797                    .memory_access_config
798                    .set_default_method(RiscvBusAccess::A32, MemoryAccessMethod::SystemBus);
799            }
800
801            if sbcs.sbaccess64() {
802                self.state
803                    .memory_access_config
804                    .set_default_method(RiscvBusAccess::A64, MemoryAccessMethod::SystemBus);
805            }
806
807            if sbcs.sbaccess128() {
808                self.state
809                    .memory_access_config
810                    .set_default_method(RiscvBusAccess::A128, MemoryAccessMethod::SystemBus);
811            }
812        } else {
813            tracing::debug!(
814                "System bus interface version {} is not supported.",
815                sbcs.sbversion()
816            );
817        }
818
819        Ok(())
820    }
821
822    /// Disable debugging on the target.
823    ///
824    /// Always attempts to deassert `dmcontrol.dmactive` even when earlier
825    /// cleanup steps (e.g. clearing software-breakpoint enable in DCSR)
826    /// fail.  Without this, a stuck DM (dmistat=3) caused by an abrupt
827    /// disconnect leaves the debug module active with no way to recover
828    /// short of a full power cycle.
829    pub fn disable_debug_module(&mut self) -> Result<(), RiscvError> {
830        // Best-effort: try to clear ebreak bits in DCSR, but do not let
831        // failure prevent us from deactivating the debug module below.
832        if let Err(e) = self.debug_on_sw_breakpoint(false) {
833            tracing::warn!(
834                "disable_debug_module: could not clear sw-breakpoint state: {:?}",
835                e
836            );
837        }
838
839        // Clear any sticky DMI errors (dmistat=3) that may have accumulated
840        // from timed-out operations, so the final dmactive=0 write can
841        // actually reach the debug module.
842        if let Err(e) = self.dtm.clear_error_state() {
843            tracing::warn!(
844                "disable_debug_module: could not clear DMI error state: {:?}",
845                e
846            );
847        }
848
849        let mut control = Dmcontrol(0);
850        control.set_dmactive(false);
851        self.write_dm_register(control)?;
852
853        Ok(())
854    }
855
856    /// Halt all harts on the target.
857    pub fn halt(&mut self, timeout: Duration) -> Result<(), RiscvError> {
858        // Fast path.
859        // Try to do the halt, in a single step.
860        let mut dmcontrol = self.state.current_dmcontrol;
861        tracing::debug!(
862            "Before requesting halt, the Dmcontrol register value was: {:?}",
863            dmcontrol
864        );
865
866        dmcontrol.set_dmactive(true);
867        dmcontrol.set_haltreq(true);
868
869        self.schedule_write_dm_register(dmcontrol)?;
870
871        let result_status_idx = self.schedule_read_dm_register::<Dmstatus>()?;
872
873        // clear the halt request
874        dmcontrol.set_haltreq(false);
875        self.write_dm_register(dmcontrol)?;
876
877        let result_status = Dmstatus(self.dtm.read_deferred_result(result_status_idx)?.into_u32());
878
879        if !result_status.allhalted() {
880            // Not every core has halted in time. Let's do things slowly.
881
882            // set the halt request again
883            dmcontrol.set_haltreq(true);
884            self.write_dm_register(dmcontrol)?;
885
886            // Wait until halted state is active again.
887            self.wait_for_core_halted(timeout)?;
888
889            // clear the halt request
890            dmcontrol.set_haltreq(false);
891            self.write_dm_register(dmcontrol)?;
892        }
893
894        // Both paths above guarantee the core is halted here.
895        self.state.is_halted = true;
896
897        if !self.state.sw_breakpoint_debug_enabled {
898            self.debug_on_sw_breakpoint(true)?;
899        }
900
901        Ok(())
902    }
903
904    /// Halts the core and returns `true` if the core was running before the halt.
905    pub(crate) fn halt_with_previous(&mut self, timeout: Duration) -> Result<bool, RiscvError> {
906        let was_running = if self.state.is_halted {
907            // Core is already halted, we don't need to do anything.
908            false
909        } else {
910            // If we have not halted the core, it may still be halted on a breakpoint, for example.
911            // Let's check status.
912            let status_idx = self.schedule_read_dm_register::<Dmstatus>()?;
913            self.halt(timeout)?;
914            let before_status = Dmstatus(self.dtm.read_deferred_result(status_idx)?.into_u32());
915
916            !before_status.allhalted()
917        };
918
919        Ok(was_running)
920    }
921
922    pub(crate) fn core_info(&mut self) -> Result<CoreInformation, RiscvError> {
923        Ok(CoreInformation {
924            pc: self.read_csr(super::registers::PC.id().0)?,
925        })
926    }
927
928    /// Return whether or not the core is halted.
929    pub fn core_halted(&mut self) -> Result<bool, RiscvError> {
930        if !self.state.is_halted {
931            let dmstatus: Dmstatus = self.read_dm_register()?;
932
933            tracing::trace!("{:?}", dmstatus);
934
935            self.state.is_halted = dmstatus.allhalted();
936        }
937
938        Ok(self.state.is_halted)
939    }
940
941    pub(crate) fn wait_for_core_halted(&mut self, timeout: Duration) -> Result<(), RiscvError> {
942        // Wait until halted state is active again.
943        let start = Instant::now();
944
945        while !self.core_halted()? {
946            if start.elapsed() >= timeout {
947                return Err(RiscvError::Timeout);
948            }
949            // Wait a bit before polling again.
950            std::thread::sleep(Duration::from_millis(1));
951        }
952
953        Ok(())
954    }
955
956    // DCSR register number and privilege-level constants, shared across
957    // halted_access setup and restore paths.
958    const DCSR_REGNO: u16 = 0x7b0;
959    const PRV_MASK: u32 = 0x3;
960    const PRV_M: u32 = 0x3;
961    /// Bit 15: ebreakm -- when set, `ebreak` in M-mode enters debug mode
962    /// rather than taking a normal M-mode exception.  Without this bit the
963    /// implicit `ebreak` at the end of the program buffer would exit debug
964    /// mode and set cmderr=4 (halt/resume).
965    const EBREAKM: u32 = 1 << 15;
966
967    /// Executes an operation while the core is halted.
968    pub fn halted_access<R>(
969        &mut self,
970        op: impl FnOnce(&mut Self) -> Result<R, RiscvError>,
971    ) -> Result<R, RiscvError> {
972        let was_running = self.halt_with_previous(Duration::from_millis(100))?;
973
974        // If requested, force the program buffer privilege level to machine mode
975        // so that memory accesses bypass the MMU and use physical addresses.
976        //
977        // `dcsr.prv` is a hardware-written field: the CPU sets it to the
978        // privilege level at which it halted.  When Linux halts in supervisor
979        // mode (dcsr.prv = S), virtual memory is active in the program buffer,
980        // and on-chip SRAMs at their physical addresses (ILM 0x80000000, DLM
981        // 0x90000000) may not be mapped or may be write-protected in the
982        // supervisor page table.  Forcing prv = M gives direct physical access.
983        //
984        // IMPORTANT: we first try abstract register commands.  If they return
985        // NotSupported (e.g. FU740 DM has no abstract CSR support), fall back
986        // to an *inline* program-buffer CSR read that does NOT call
987        // halted_access (avoiding infinite recursion).  The inline approach
988        // saves/restores s0 via abstract GPR commands (which the DM does
989        // support) and uses csrr/csrw instructions in the program buffer.
990        let saved_prv: Option<u32> = if self.state.force_machine_mode_progbuf {
991            // Try abstract command first, then progbuf fallback.
992            match self.read_dcsr_inline() {
993                Ok(dcsr) => {
994                    let prv = dcsr & Self::PRV_MASK;
995                    let need_prv = prv != Self::PRV_M;
996                    let need_ebreakm = (dcsr & Self::EBREAKM) == 0;
997                    if need_prv || need_ebreakm {
998                        let dcsr_new =
999                            (dcsr & !Self::PRV_MASK & !Self::EBREAKM) | Self::PRV_M | Self::EBREAKM;
1000                        tracing::trace!(
1001                            "halted_access: updating DCSR {:#010x} -> {:#010x}",
1002                            dcsr,
1003                            dcsr_new,
1004                        );
1005                        if let Err(e) = self.write_dcsr_inline(dcsr_new) {
1006                            tracing::warn!("halted_access: could not update DCSR: {:?}", e);
1007                            // Write failed -- do not record prv so the restore
1008                            // path is skipped and op() errors are not masked.
1009                            None
1010                        } else {
1011                            Some(prv)
1012                        }
1013                    } else {
1014                        Some(prv)
1015                    }
1016                }
1017                Err(e) => {
1018                    tracing::warn!("halted_access: could not read DCSR: {:?}", e);
1019                    None
1020                }
1021            }
1022        } else {
1023            None
1024        };
1025
1026        let result = op(self);
1027
1028        // Restore the original dcsr.prv when it was not already M-mode.
1029        // Note: ebreakm is intentionally left set -- it must remain enabled
1030        // for progbuf-based debug access to work on targets like FU740.
1031        if let Some(prv) = saved_prv
1032            && prv != Self::PRV_M
1033        {
1034            match self.read_dcsr_inline() {
1035                Ok(dcsr) => {
1036                    let new_dcsr = (dcsr & !Self::PRV_MASK) | prv;
1037                    let _ = self.write_dcsr_inline(new_dcsr);
1038                }
1039                Err(e) => {
1040                    tracing::warn!(
1041                        "Failed to restore dcsr.prv after halted_access: {e}. \
1042                         Core may resume with incorrect privilege level."
1043                    );
1044                }
1045            }
1046        }
1047
1048        if was_running {
1049            self.resume_core()?;
1050        }
1051
1052        result
1053    }
1054
1055    /// Read DCSR without recursing into `halted_access`.
1056    ///
1057    /// Tries abstract CSR command first.  If that returns `NotSupported`
1058    /// (e.g. FU740 DM), falls back to an inline program-buffer `csrr`
1059    /// that saves/restores s0 via abstract GPR commands.
1060    ///
1061    /// Uses the correct aarsize for the target's XLEN so that strict DM
1062    /// implementations do not reject the access.
1063    fn read_dcsr_inline(&mut self) -> Result<u32, RiscvError> {
1064        match self.abstract_cmd_csr_read(Self::DCSR_REGNO) {
1065            Ok(v) => return Ok(v),
1066            Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::NotSupported)) => {}
1067            Err(e) => return Err(e),
1068        }
1069
1070        let csrr_cmd = assembly::csrr(8, Self::DCSR_REGNO);
1071        self.schedule_setup_program_buffer(&[csrr_cmd])?;
1072
1073        let postexec_cmd = self.postexec_command();
1074
1075        self.run_with_s0_saved(|core| {
1076            core.execute_abstract_command(postexec_cmd.0)?;
1077            core.save_s0_xlen().map(|v| v as u32)
1078        })
1079    }
1080
1081    /// Write DCSR without recursing into `halted_access`.
1082    ///
1083    /// Same strategy as [`Self::read_dcsr_inline`]: abstract first, then
1084    /// inline progbuf.
1085    fn write_dcsr_inline(&mut self, value: u32) -> Result<(), RiscvError> {
1086        match self.abstract_cmd_csr_write(Self::DCSR_REGNO, value) {
1087            Ok(()) => return Ok(()),
1088            Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::NotSupported)) => {}
1089            Err(e) => return Err(e),
1090        }
1091
1092        let csrw_cmd = assembly::csrw(Self::DCSR_REGNO, 8);
1093        self.schedule_setup_program_buffer(&[csrw_cmd])?;
1094
1095        let postexec_cmd = self.postexec_command();
1096
1097        self.run_with_s0_saved(|core| {
1098            core.restore_s0_xlen(value as u64)?;
1099            core.execute_abstract_command(postexec_cmd.0)
1100        })
1101    }
1102
1103    /// Read a CSR register, returning its value as a `u64`.
1104    ///
1105    /// Dispatches to a 32- or 64-bit abstract command based on the XLEN mode.  Falls back to the
1106    /// program buffer if abstract commands are not supported.  On RV32 the result is zero-extended
1107    /// to `u64`; callers that need a `u32` should truncate with `as u32`.
1108    pub(super) fn read_csr(&mut self, address: u16) -> Result<u64, RiscvError> {
1109        // We need to use the "Access Register Command", which has cmdtype 0
1110        // write needs to be clear, transfer has to be set
1111        tracing::debug!("Reading CSR {:#x}", address);
1112        // Always try to read register with abstract command, fallback to
1113        // program buffer if not supported.
1114        let result = if self.state.xlen_64 {
1115            self.abstract_cmd_register_read_64(address)
1116        } else {
1117            self.abstract_cmd_register_read(address).map(u64::from)
1118        };
1119
1120        match result {
1121            Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::NotSupported)) => {
1122                tracing::debug!(
1123                    "Could not read CSR {:#x} with abstract command, falling back to program buffer",
1124                    address
1125                );
1126                self.read_csr_progbuf(address)
1127            }
1128            other => other,
1129        }
1130    }
1131
1132    /// Write a CSR register.
1133    ///
1134    /// Dispatches to a 32- or 64-bit abstract command based on the XLEN mode.  Falls back to the
1135    /// program buffer if abstract commands are not supported.
1136    pub(super) fn write_csr(&mut self, address: u16, value: u64) -> Result<(), RiscvError> {
1137        tracing::debug!("Writing CSR {:#x}", address);
1138        let result = if self.state.xlen_64 {
1139            self.abstract_cmd_register_write_64(address, value)
1140        } else {
1141            self.abstract_cmd_register_write(address, value as u32)
1142        };
1143        match result {
1144            Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::NotSupported)) => {
1145                tracing::debug!(
1146                    "Could not write CSR {:#x} with abstract command, falling back to program buffer",
1147                    address
1148                );
1149                self.write_csr_progbuf(address, value)
1150            }
1151            other => other,
1152        }
1153    }
1154
1155    /// Read a 64-bit general-purpose or CSR register using an abstract command with aarsize=A64.
1156    ///
1157    /// On success, returns the 64-bit value assembled from `data1` (high) and `data0` (low).
1158    pub(super) fn abstract_cmd_register_read_64(
1159        &mut self,
1160        regno: impl Into<RegisterId>,
1161    ) -> Result<u64, RiscvError> {
1162        let regno = regno.into();
1163
1164        if !self.check_abstract_cmd_register_support(regno, CoreRegisterAbstractCmdSupport::READ) {
1165            return Err(RiscvError::AbstractCommand(
1166                AbstractCommandErrorKind::NotSupported,
1167            ));
1168        }
1169
1170        let mut command = AccessRegisterCommand(0);
1171        command.set_cmd_type(0);
1172        command.set_transfer(true);
1173        command.set_aarsize(RiscvBusAccess::A64);
1174        command.set_regno(regno.0 as u32);
1175
1176        match self.execute_abstract_command(command.0) {
1177            Ok(_) => (),
1178            err @ Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::NotSupported)) => {
1179                self.set_abstract_cmd_register_unsupported(
1180                    regno,
1181                    CoreRegisterAbstractCmdSupport::READ,
1182                );
1183                err?;
1184            }
1185            Err(e) => return Err(e),
1186        }
1187
1188        let data0: Data0 = self.read_dm_register()?;
1189        let data1: Data1 = self.read_dm_register()?;
1190        let low: u32 = data0.into();
1191        let high: u32 = data1.into();
1192
1193        Ok(((high as u64) << 32) | (low as u64))
1194    }
1195
1196    /// Write a 64-bit general-purpose or CSR register using an abstract command with aarsize=A64.
1197    pub(super) fn abstract_cmd_register_write_64(
1198        &mut self,
1199        regno: impl Into<RegisterId>,
1200        value: u64,
1201    ) -> Result<(), RiscvError> {
1202        let regno = regno.into();
1203
1204        if !self.check_abstract_cmd_register_support(regno, CoreRegisterAbstractCmdSupport::WRITE) {
1205            return Err(RiscvError::AbstractCommand(
1206                AbstractCommandErrorKind::NotSupported,
1207            ));
1208        }
1209
1210        let low = (value & 0xffff_ffff) as u32;
1211        let high = (value >> 32) as u32;
1212
1213        // Write data1 (high) then data0 (low); side-effects triggered by data0 write.
1214        self.schedule_write_dm_register(Data1(high))?;
1215        self.schedule_write_dm_register(Data0(low))?;
1216
1217        let mut command = AccessRegisterCommand(0);
1218        command.set_cmd_type(0);
1219        command.set_transfer(true);
1220        command.set_write(true);
1221        command.set_aarsize(RiscvBusAccess::A64);
1222        command.set_regno(regno.0 as u32);
1223
1224        match self.execute_abstract_command(command.0) {
1225            Ok(()) => Ok(()),
1226            err @ Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::NotSupported)) => {
1227                self.set_abstract_cmd_register_unsupported(
1228                    regno,
1229                    CoreRegisterAbstractCmdSupport::WRITE,
1230                );
1231                err
1232            }
1233            Err(e) => Err(e),
1234        }
1235    }
1236
1237    fn abstract_cmd_csr_read(&mut self, csr: u16) -> Result<u32, RiscvError> {
1238        if self.state.xlen_64 {
1239            self.abstract_cmd_register_read_64(csr).map(|v| v as u32)
1240        } else {
1241            self.abstract_cmd_register_read(csr)
1242        }
1243    }
1244
1245    fn abstract_cmd_csr_write(&mut self, csr: u16, value: u32) -> Result<(), RiscvError> {
1246        if self.state.xlen_64 {
1247            self.abstract_cmd_register_write_64(csr, value as u64)
1248        } else {
1249            self.abstract_cmd_register_write(csr, value)
1250        }
1251    }
1252
1253    fn save_s0_xlen(&mut self) -> Result<u64, RiscvError> {
1254        if self.state.xlen_64 {
1255            self.abstract_cmd_register_read_64(registers::S0)
1256        } else {
1257            self.abstract_cmd_register_read(registers::S0)
1258                .map(|v| v as u64)
1259        }
1260    }
1261
1262    fn restore_s0_xlen(&mut self, value: u64) -> Result<(), RiscvError> {
1263        if self.state.xlen_64 {
1264            self.abstract_cmd_register_write_64(registers::S0, value)
1265        } else {
1266            self.abstract_cmd_register_write(registers::S0, value as u32)
1267        }
1268    }
1269
1270    /// Read S0 using the correct XLEN width.
1271    ///
1272    /// Semantic alias for [`Self::save_s0_xlen`] — use this when reading S0 to
1273    /// retrieve a result (e.g. after a `csrr` executed in the program buffer)
1274    /// rather than to snapshot it for later restoration.
1275    fn read_s0_xlen(&mut self) -> Result<u64, RiscvError> {
1276        self.save_s0_xlen()
1277    }
1278
1279    /// Write an arbitrary value into S0 using the correct XLEN width.
1280    ///
1281    /// Semantic alias for [`Self::restore_s0_xlen`] — use this when staging a
1282    /// value into S0 (e.g. before a `csrw` in the program buffer) rather than
1283    /// restoring a previously saved snapshot.
1284    fn write_s0_xlen(&mut self, value: u64) -> Result<(), RiscvError> {
1285        self.restore_s0_xlen(value)
1286    }
1287
1288    /// Save S0, run `op`, restore S0 unconditionally, then return the result.
1289    ///
1290    /// Mirrors [`Self::halted_access`] but scoped to S0 save/restore rather
1291    /// than halt/resume.  Using a named helper avoids immediately-invoked
1292    /// closure expressions (`(|| { ... })()`).
1293    fn run_with_s0_saved<R>(
1294        &mut self,
1295        op: impl FnOnce(&mut Self) -> Result<R, RiscvError>,
1296    ) -> Result<R, RiscvError> {
1297        let saved = self.save_s0_xlen()?;
1298        let result = op(self);
1299        let _ = self.restore_s0_xlen(saved);
1300        result
1301    }
1302
1303    /// Write an address into S0 with XLEN-correct width.
1304    ///
1305    /// On RV64 a narrow (A32) abstract write sign-extends the value, turning
1306    /// addresses with bit 31 set (e.g. 0x8000_0000) into large negative
1307    /// 64-bit values.  This helper always uses A64 on RV64 so that S0 holds
1308    /// the correctly zero-extended address.
1309    fn write_address_to_s0(&mut self, address: u64) -> Result<(), RiscvError> {
1310        if self.state.xlen_64 {
1311            self.abstract_cmd_register_write_64(registers::S0, address)
1312        } else {
1313            self.abstract_cmd_register_write(registers::S0, address as u32)
1314        }
1315    }
1316
1317    /// Write an address into S0 and schedule a progbuf execution.
1318    ///
1319    /// On RV64 the abstract command used for the write cannot set `postexec` at
1320    /// the same time as a 64-bit register transfer (the DM would interpret it as
1321    /// two separate operations).  Instead we write S0 via a plain register write
1322    /// first, then issue a separate execute-only abstract command.
1323    ///
1324    /// On RV32 the write and execute are combined in a single `transfer=true,
1325    /// postexec=true` A32 command, matching the existing behaviour.
1326    fn schedule_write_address_to_s0_and_exec(&mut self, address: u64) -> Result<(), RiscvError> {
1327        if self.state.xlen_64 {
1328            self.abstract_cmd_register_write_64(registers::S0, address)?;
1329            let mut command = AccessRegisterCommand(0);
1330            command.set_cmd_type(0);
1331            command.set_transfer(false);
1332            command.set_postexec(true);
1333            command.set_regno(registers::S0.id.0 as u32);
1334            self.schedule_write_dm_register(command)
1335        } else {
1336            self.schedule_write_dm_register(Data0(address as u32))?;
1337            let mut command = AccessRegisterCommand(0);
1338            command.set_cmd_type(0);
1339            command.set_transfer(true);
1340            command.set_write(true);
1341            command.set_aarsize(RiscvBusAccess::A32);
1342            command.set_postexec(true);
1343            command.set_regno(registers::S0.id.0 as u32);
1344            self.schedule_write_dm_register(command)
1345        }
1346    }
1347
1348    /// Mark this interface as operating in RV64 mode.
1349    ///
1350    /// In RV64 mode, memory access methods accept 64-bit addresses without
1351    /// the `valid_32bit_address` restriction.
1352    pub(crate) fn set_xlen_64(&mut self, is_64: bool) {
1353        self.state.xlen_64 = is_64;
1354    }
1355
1356    /// Enable machine-mode execution inside `halted_access`.
1357    ///
1358    /// When set, `halted_access` writes `dcsr.prv = M` after every internal
1359    /// halt so that program-buffer instructions use physical addresses
1360    /// regardless of the privilege level at which the hart was interrupted.
1361    pub(crate) fn set_force_machine_mode_progbuf(&mut self, force: bool) {
1362        self.state.force_machine_mode_progbuf = force;
1363    }
1364
1365    /// Schedules a DM register read, flushes the queue and returns the result.
1366    pub fn read_dm_register<R: MemoryMappedRegister<u32>>(&mut self) -> Result<R, RiscvError> {
1367        tracing::debug!(
1368            "Reading DM register '{}' at {:#010x}",
1369            R::NAME,
1370            R::get_mmio_address()
1371        );
1372
1373        let register_value = self.read_dm_register_untyped(R::get_mmio_address())?.into();
1374
1375        tracing::debug!(
1376            "Read DM register '{}' at {:#010x} = {:x?}",
1377            R::NAME,
1378            R::get_mmio_address(),
1379            register_value
1380        );
1381
1382        Ok(register_value)
1383    }
1384
1385    /// Schedules a DM register read, flushes the queue and returns the untyped result.
1386    ///
1387    /// Use the [`Self::read_dm_register()`] function if possible.
1388    fn read_dm_register_untyped(&mut self, address: u64) -> Result<u32, RiscvError> {
1389        let read_idx = self.schedule_read_dm_register_untyped(address)?;
1390        let register_value = self.dtm.read_deferred_result(read_idx)?.into_u32();
1391
1392        Ok(register_value)
1393    }
1394
1395    /// Schedules a DM register write and flushes the queue.
1396    pub fn write_dm_register<R: MemoryMappedRegister<u32>>(
1397        &mut self,
1398        register: R,
1399    ) -> Result<(), RiscvError> {
1400        // write write command to dmi register
1401
1402        tracing::debug!(
1403            "Write DM register '{}' at {:#010x} = {:x?}",
1404            R::NAME,
1405            R::get_mmio_address(),
1406            register
1407        );
1408
1409        self.write_dm_register_untyped(R::get_mmio_address(), register.into())
1410    }
1411
1412    /// Write to a DM register
1413    ///
1414    /// Use the [`Self::write_dm_register()`] function if possible.
1415    fn write_dm_register_untyped(&mut self, address: u64, value: u32) -> Result<(), RiscvError> {
1416        self.cache_write(address, value);
1417        self.dtm.write_with_timeout(address, value, RISCV_TIMEOUT)?;
1418
1419        Ok(())
1420    }
1421
1422    fn cache_write(&mut self, address: u64, value: u32) {
1423        if address == Dmcontrol::ADDRESS_OFFSET {
1424            self.state.current_dmcontrol = Dmcontrol(value);
1425        }
1426    }
1427
1428    fn schedule_write_progbuf(&mut self, index: usize, value: u32) -> Result<(), RiscvError> {
1429        match index {
1430            0 => self.schedule_write_dm_register(Progbuf0(value)),
1431            1 => self.schedule_write_dm_register(Progbuf1(value)),
1432            2 => self.schedule_write_dm_register(Progbuf2(value)),
1433            3 => self.schedule_write_dm_register(Progbuf3(value)),
1434            4 => self.schedule_write_dm_register(Progbuf4(value)),
1435            5 => self.schedule_write_dm_register(Progbuf5(value)),
1436            6 => self.schedule_write_dm_register(Progbuf6(value)),
1437            7 => self.schedule_write_dm_register(Progbuf7(value)),
1438            8 => self.schedule_write_dm_register(Progbuf8(value)),
1439            9 => self.schedule_write_dm_register(Progbuf9(value)),
1440            10 => self.schedule_write_dm_register(Progbuf10(value)),
1441            11 => self.schedule_write_dm_register(Progbuf11(value)),
1442            12 => self.schedule_write_dm_register(Progbuf12(value)),
1443            13 => self.schedule_write_dm_register(Progbuf13(value)),
1444            14 => self.schedule_write_dm_register(Progbuf14(value)),
1445            15 => self.schedule_write_dm_register(Progbuf15(value)),
1446            e => Err(RiscvError::UnsupportedProgramBufferRegister(e)),
1447        }
1448    }
1449
1450    pub(crate) fn schedule_setup_program_buffer(&mut self, data: &[u32]) -> Result<(), RiscvError> {
1451        let required_len = if self.state.implicit_ebreak {
1452            data.len()
1453        } else {
1454            data.len() + 1
1455        };
1456
1457        if required_len > self.state.progbuf_size as usize {
1458            return Err(RiscvError::ProgramBufferTooSmall {
1459                required: required_len,
1460                actual: self.state.progbuf_size as usize,
1461            });
1462        }
1463
1464        if data == &self.state.progbuf_cache[..data.len()] {
1465            // Check if we actually have to write the program buffer
1466            tracing::debug!("Program buffer is up-to-date, skipping write.");
1467            return Ok(());
1468        }
1469
1470        for (index, word) in data.iter().enumerate() {
1471            self.schedule_write_progbuf(index, *word)?;
1472        }
1473
1474        // Add manual ebreak if necessary.
1475        //
1476        // This is necessary when we either don't need the full program buffer,
1477        // or if there is no implicit ebreak after the last program buffer word.
1478        if !self.state.implicit_ebreak || data.len() < self.state.progbuf_size as usize {
1479            self.schedule_write_progbuf(data.len(), assembly::EBREAK)?;
1480        }
1481
1482        // Update the cache
1483        self.state.progbuf_cache[..data.len()].copy_from_slice(data);
1484
1485        Ok(())
1486    }
1487
1488    /// Perform a single read from a memory location, using system bus access.
1489    fn perform_memory_read_sysbus<V: RiscvValue32>(
1490        &mut self,
1491        address: u64,
1492    ) -> Result<V, RiscvError> {
1493        loop {
1494            let mut sbcs = Sbcs(0);
1495
1496            // Reset the systembus busy error flag.
1497            sbcs.set_sbbusyerror(true);
1498
1499            sbcs.set_sbaccess(V::WIDTH as u32);
1500
1501            sbcs.set_sbreadonaddr(true);
1502
1503            self.schedule_write_dm_register(sbcs)?;
1504            if self.state.xlen_64 {
1505                self.schedule_write_dm_register(Sbaddress1((address >> 32) as u32))?;
1506            }
1507            self.schedule_write_dm_register(Sbaddress0(address as u32))?;
1508
1509            let mut results = vec![];
1510            self.schedule_read_large_dtm_register::<V, Sbdata>(&mut results)?;
1511
1512            // Check that the read was successful
1513            let sbcs = self.read_dm_register::<Sbcs>()?;
1514            if sbcs.sberror() != 0 {
1515                break Err(RiscvError::SystemBusAccess);
1516            }
1517            if !sbcs.sbbusyerror() {
1518                break V::read_scheduled_result(self, &mut results);
1519            }
1520            tracing::debug!("System bus was busy while reading, repeating operation");
1521        }
1522    }
1523
1524    /// Perform multiple reads from consecutive memory locations
1525    /// using system bus access.
1526    /// Only reads up to a width of 32 bits are currently supported.
1527    fn perform_memory_read_multiple_sysbus<V: RiscvValue32>(
1528        &mut self,
1529        address: u64,
1530        data: &mut [V],
1531    ) -> Result<(), RiscvError> {
1532        if data.is_empty() {
1533            return Ok(());
1534        }
1535        loop {
1536            let mut sbcs = Sbcs(0);
1537
1538            // Reset the systembus busy error flag.
1539            sbcs.set_sbbusyerror(true);
1540
1541            sbcs.set_sbaccess(V::WIDTH as u32);
1542
1543            sbcs.set_sbreadonaddr(true);
1544
1545            sbcs.set_sbreadondata(true);
1546            sbcs.set_sbautoincrement(true);
1547
1548            self.schedule_write_dm_register(sbcs)?;
1549
1550            if self.state.xlen_64 {
1551                self.schedule_write_dm_register(Sbaddress1((address >> 32) as u32))?;
1552            }
1553            self.schedule_write_dm_register(Sbaddress0(address as u32))?;
1554
1555            let data_len = data.len();
1556
1557            let mut read_results = Vec::with_capacity(data_len);
1558            for _ in data[..data_len - 1].iter() {
1559                self.schedule_read_large_dtm_register::<V, Sbdata>(&mut read_results)?;
1560            }
1561
1562            self.schedule_write_dm_register(Sbcs(0))?;
1563
1564            // Read last value
1565            self.schedule_read_large_dtm_register::<V, Sbdata>(&mut read_results)?;
1566
1567            let sbcs = self.read_dm_register::<Sbcs>()?;
1568
1569            for out in data.iter_mut() {
1570                *out = V::read_scheduled_result(self, &mut read_results)?;
1571            }
1572
1573            // Check that the read was successful
1574            if sbcs.sberror() != 0 {
1575                break Err(RiscvError::SystemBusAccess);
1576            }
1577            if !sbcs.sbbusyerror() {
1578                break Ok(());
1579            }
1580            tracing::debug!("System bus was busy while reading, repeating operation");
1581        }
1582    }
1583
1584    // TODO: this would be best executed on the probe. RiscvCommunicationInterface should be refactored to allow that.
1585    fn wait_for_idle(&mut self, timeout: Duration) -> Result<(), RiscvError> {
1586        let start = Instant::now();
1587        loop {
1588            let status: Abstractcs = self.read_dm_register()?;
1589            match AbstractCommandErrorKind::parse(status) {
1590                Ok(_) => return Ok(()),
1591                Err(AbstractCommandErrorKind::Busy) => {}
1592                Err(other) => return Err(other.into()),
1593            }
1594
1595            if start.elapsed() > timeout {
1596                return Err(RiscvError::Timeout);
1597            }
1598        }
1599    }
1600
1601    /// Wait for an abstract command to complete by polling the `busy` bit,
1602    /// then check `cmderr`.
1603    ///
1604    /// Unlike [`Self::wait_for_idle`] which only checks `cmderr` (and may
1605    /// return prematurely when busy=1 and cmderr=0), this function polls
1606    /// the `busy` flag to ensure the command has truly finished.  This is
1607    /// critical for autoexec where the next DATA0 read must not arrive
1608    /// while the previous command is still executing.
1609    fn wait_for_abstract_idle(&mut self, timeout: Duration) -> Result<(), RiscvError> {
1610        let start = Instant::now();
1611        loop {
1612            let status: Abstractcs = self.read_dm_register()?;
1613            if !status.busy() {
1614                AbstractCommandErrorKind::parse(status)?;
1615                return Ok(());
1616            }
1617            if start.elapsed() > timeout {
1618                return Err(RiscvError::Timeout);
1619            }
1620        }
1621    }
1622
1623    /// Perform memory read from a single location using the program buffer.
1624    /// Only reads up to a width of 32 bits are currently supported.
1625    fn perform_memory_read_progbuf<V: RiscvValue32>(
1626        &mut self,
1627        address: u64,
1628        wait_for_idle: bool,
1629    ) -> Result<V, RiscvError> {
1630        self.halted_access(|core| {
1631            // assemble
1632            //  lb s1, 0(s0)
1633
1634            let s0 = core.save_s0()?;
1635
1636            let lw_command = assembly::lw(0, 8, V::WIDTH as u8, 8);
1637
1638            core.schedule_setup_program_buffer(&[lw_command])?;
1639
1640            core.schedule_write_address_to_s0_and_exec(address)?;
1641
1642            if wait_for_idle {
1643                core.wait_for_idle(Duration::from_millis(10))?;
1644            }
1645
1646            // Read back s0
1647            let value = core.abstract_cmd_register_read(registers::S0)?;
1648
1649            // Restore s0 register
1650            core.restore_s0(s0)?;
1651
1652            Ok(V::from_register_value(value))
1653        })
1654    }
1655
1656    /// Prime the autoexec pipeline for a batch memory read.
1657    ///
1658    /// The program buffer must already contain:
1659    ///   `lw/ld s1, 0(s0); addi s0, s0, width`
1660    ///
1661    /// After this returns successfully:
1662    /// - DATA0 contains the value at `address` (data\[0\])
1663    /// - S1 contains the value at `address + width` (data\[1\])
1664    /// - S0 = `address + 2 * width`
1665    /// - `abstractauto` is enabled (DATA0 reads trigger the command)
1666    ///
1667    /// Follows OpenOCD's `read_memory_progbuf_inner_startup` pattern.
1668    fn autoexec_prime_pipeline(&mut self, address: u64) -> Result<(), RiscvError> {
1669        // Step 1: Write starting address into S0.
1670        self.write_address_to_s0(address)?;
1671
1672        // Step 2: "Read S1 + postexec" — the command autoexec will repeat.
1673        // Transfers S1 -> DATA0 (garbage, old value) then executes progbuf:
1674        //   s1 = M[s0], s0 += width
1675        let aarsize = if self.state.xlen_64 {
1676            RiscvBusAccess::A64
1677        } else {
1678            RiscvBusAccess::A32
1679        };
1680        let mut cmd = AccessRegisterCommand(0);
1681        cmd.set_cmd_type(0);
1682        cmd.set_transfer(true);
1683        cmd.set_write(false);
1684        cmd.set_aarsize(aarsize);
1685        cmd.set_postexec(true);
1686        cmd.set_regno((registers::S1).id.0 as u32);
1687        self.execute_abstract_command(cmd.0)?;
1688
1689        // Step 3: Enable autoexec on DATA0 reads.
1690        let mut abstractauto = Abstractauto(0);
1691        abstractauto.set_autoexecdata(1);
1692        self.write_dm_register(abstractauto)?;
1693
1694        // Step 4: Read DATA0 (discard garbage from old S1).
1695        // This triggers autoexec: transfer S1->DATA0 = M[addr], then progbuf:
1696        //   s1 = M[addr+width], s0 = addr+2*width
1697        let _: Data0 = self.read_dm_register()?;
1698
1699        // Step 5: Wait for the autoexec-triggered command to complete.
1700        self.wait_for_abstract_idle(Duration::from_millis(100))?;
1701
1702        Ok(())
1703    }
1704
1705    fn read_multiple_autoexec<V: RiscvValue32>(
1706        &mut self,
1707        address: u64,
1708        data: &mut [V],
1709    ) -> Result<(), RiscvError> {
1710        let data_len = data.len();
1711
1712        // Follows OpenOCD's read_memory_progbuf_inner pattern.
1713        //
1714        // Prime the pipeline.  After this returns:
1715        //   DATA0 = data[0], s1 = data[1], s0 = addr + 2*width
1716        //   abstractauto enabled (DATA0 reads fire the command)
1717        self.autoexec_prime_pipeline(address)?;
1718
1719        // Pipeline accounting (N = data_len):
1720        //   After priming: DATA0 = data[0], s1 = data[1]
1721        //   Bulk loop: N-2 DATA0 reads yield data[0..N-2]
1722        //     Each read returns data[i] and triggers autoexec
1723        //     which advances the pipeline by one position.
1724        //   Teardown: read DATA0 -> data[N-2], read S1 -> data[N-1]
1725        let loop_count = data_len.saturating_sub(2);
1726        let chunk_size: usize = 256;
1727        let mut out_idx = 0;
1728
1729        while out_idx < loop_count {
1730            let batch_end = core::cmp::min(out_idx + chunk_size, loop_count);
1731            let batch_len = batch_end - out_idx;
1732
1733            let mut result_idxs = Vec::with_capacity(batch_len);
1734            for _ in 0..batch_len {
1735                let idx = self.schedule_read_dm_register::<Data0>()?;
1736                result_idxs.push(idx);
1737            }
1738
1739            for (i, idx) in result_idxs.into_iter().enumerate() {
1740                let value = self.dtm.read_deferred_result(idx)?.into_u32();
1741                data[out_idx + i] = V::from_register_value(value);
1742            }
1743
1744            match self.wait_for_abstract_idle(Duration::from_millis(100)) {
1745                Ok(()) => {
1746                    out_idx = batch_end;
1747                }
1748                Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::Busy)) => {
1749                    let mut cs = Abstractcs(0);
1750                    cs.set_cmderr(0x7);
1751                    self.write_dm_register(cs)?;
1752                    self.write_dm_register(Abstractauto(0))?;
1753
1754                    let current_addr = if self.state.xlen_64 {
1755                        self.abstract_cmd_register_read_64(registers::S0)?
1756                    } else {
1757                        self.abstract_cmd_register_read(registers::S0)? as u64
1758                    };
1759                    let width = V::WIDTH.byte_width() as u64;
1760                    let progress = ((current_addr - address) / width) as usize;
1761                    let reliable = progress.saturating_sub(2);
1762
1763                    tracing::warn!(
1764                        "Autoexec Busy during chunk [{}, {}). \
1765                         S0={:#x}, progress={}, reliable={}",
1766                        out_idx,
1767                        batch_end,
1768                        current_addr,
1769                        progress,
1770                        reliable,
1771                    );
1772
1773                    if reliable <= out_idx {
1774                        return Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::Busy));
1775                    }
1776
1777                    let new_addr = address + reliable as u64 * width;
1778                    self.autoexec_prime_pipeline(new_addr)?;
1779                    out_idx = reliable;
1780                }
1781                Err(e) => return Err(e),
1782            }
1783        }
1784
1785        // Teardown: disable autoexec, read final two values.
1786        self.write_dm_register(Abstractauto(0))?;
1787
1788        let penult: Data0 = self.read_dm_register()?;
1789        data[data_len - 2] = V::from_register_value(penult.0);
1790
1791        let last_val = if self.state.xlen_64 {
1792            self.abstract_cmd_register_read_64(registers::S1)? as u32
1793        } else {
1794            self.abstract_cmd_register_read(registers::S1)?
1795        };
1796        data[data_len - 1] = V::from_register_value(last_val);
1797
1798        Ok(())
1799    }
1800
1801    fn read_multiple_no_autoexec<V: RiscvValue32>(
1802        &mut self,
1803        address: u64,
1804        data: &mut [V],
1805        wait_for_idle: bool,
1806    ) -> Result<(), RiscvError> {
1807        let data_len = data.len();
1808
1809        self.schedule_write_address_to_s0_and_exec(address)?;
1810
1811        if wait_for_idle {
1812            self.wait_for_idle(Duration::from_millis(10))?;
1813        }
1814
1815        let aarsize = if self.state.xlen_64 {
1816            RiscvBusAccess::A64
1817        } else {
1818            RiscvBusAccess::A32
1819        };
1820        let mut result_idxs = Vec::with_capacity(data_len - 1);
1821        for out_idx in 0..data_len - 1 {
1822            let mut command = AccessRegisterCommand(0);
1823            command.set_cmd_type(0);
1824            command.set_transfer(true);
1825            command.set_write(false);
1826            command.set_aarsize(aarsize);
1827            command.set_postexec(true);
1828            command.set_regno((registers::S1).id.0 as u32);
1829
1830            self.schedule_write_dm_register(command)?;
1831            let value_idx = self.schedule_read_dm_register::<Data0>()?;
1832            result_idxs.push((out_idx, value_idx));
1833
1834            if wait_for_idle {
1835                self.wait_for_idle(Duration::from_millis(10))?;
1836            }
1837        }
1838
1839        let last_value = if self.state.xlen_64 {
1840            self.abstract_cmd_register_read_64(registers::S1)? as u32
1841        } else {
1842            self.abstract_cmd_register_read(registers::S1)?
1843        };
1844        data[data.len() - 1] = V::from_register_value(last_value);
1845
1846        for (out_idx, value_idx) in result_idxs {
1847            let value = self.dtm.read_deferred_result(value_idx)?.into_u32();
1848            data[out_idx] = V::from_register_value(value);
1849        }
1850
1851        Ok(())
1852    }
1853
1854    fn perform_memory_read_multiple_progbuf<V: RiscvValue32>(
1855        &mut self,
1856        address: u64,
1857        data: &mut [V],
1858        wait_for_idle: bool,
1859    ) -> Result<(), RiscvError> {
1860        if data.is_empty() {
1861            return Ok(());
1862        }
1863
1864        if data.len() == 1 {
1865            data[0] = self.perform_memory_read_progbuf(address, wait_for_idle)?;
1866            return Ok(());
1867        }
1868
1869        self.halted_access(|core| {
1870            let s0 = core.save_s0()?;
1871            let s1 = core.save_s1()?;
1872
1873            let lw_command: u32 = assembly::lw(0, 8, V::WIDTH as u8, 9);
1874
1875            core.schedule_setup_program_buffer(&[
1876                lw_command,
1877                assembly::addi(8, 8, V::WIDTH.byte_width() as i16),
1878            ])?;
1879
1880            let use_autoexec = core.state.supports_autoexec && data.len() >= 16;
1881
1882            let read_result: Result<(), RiscvError> = if use_autoexec {
1883                core.read_multiple_autoexec(address, data)
1884            } else {
1885                core.read_multiple_no_autoexec(address, data, wait_for_idle)
1886            };
1887
1888            let _ = core.write_dm_register(Abstractauto(0));
1889            let mut cs_clear = Abstractcs(0);
1890            cs_clear.set_cmderr(0x7);
1891            let _ = core.write_dm_register(cs_clear);
1892            core.state.progbuf_cache = [0u32; 16];
1893            let _ = core.restore_s0(s0);
1894            let _ = core.restore_s1(s1);
1895
1896            read_result
1897        })
1898    }
1899
1900    /// Memory write using system bus
1901    fn perform_memory_write_sysbus<V: RiscvValue>(
1902        &mut self,
1903        address: u64,
1904        data: &[V],
1905    ) -> Result<(), RiscvError> {
1906        if data.is_empty() {
1907            return Ok(());
1908        }
1909
1910        loop {
1911            let mut sbcs = Sbcs(0);
1912            // Reset busy error flag;
1913            sbcs.set_sbbusyerror(true);
1914            // Set correct access width
1915            sbcs.set_sbaccess(V::WIDTH as u32);
1916            sbcs.set_sbautoincrement(true);
1917
1918            self.schedule_write_dm_register(sbcs)?;
1919
1920            if self.state.xlen_64 {
1921                self.schedule_write_dm_register(Sbaddress1((address >> 32) as u32))?;
1922            }
1923            self.schedule_write_dm_register(Sbaddress0(address as u32))?;
1924            for value in data {
1925                self.schedule_write_large_dtm_register::<V, Sbdata>(*value)?;
1926            }
1927
1928            // Check that the write was successful
1929            let sbcs = self.read_dm_register::<Sbcs>()?;
1930            if sbcs.sberror() != 0 {
1931                break Err(RiscvError::SystemBusAccess);
1932            }
1933            if !sbcs.sbbusyerror() {
1934                break Ok(());
1935            }
1936            tracing::debug!("System bus was busy while writing, repeating write");
1937        }
1938    }
1939
1940    /// Perform memory write to a single location using the program buffer.
1941    /// Only writes up to a width of 32 bits are currently supported.
1942    fn perform_memory_write_progbuf<V: RiscvValue32>(
1943        &mut self,
1944        address: u64,
1945        data: V,
1946        wait_for_idle: bool,
1947    ) -> Result<(), RiscvError> {
1948        self.halted_access(|core| {
1949            tracing::debug!(
1950                "Memory write using progbuf - {:#010x} = {:#?}",
1951                address,
1952                data
1953            );
1954
1955            // Backup registers s0 and s1
1956            let s0 = core.save_s0()?;
1957            let s1 = core.save_s1()?;
1958
1959            let sw_command = assembly::sw(0, 8, V::WIDTH as u32, 9);
1960
1961            core.schedule_setup_program_buffer(&[sw_command])?;
1962
1963            // Write the target address into S0 with XLEN-correct width.
1964            core.write_address_to_s0(address)?;
1965
1966            // write data into data 0
1967            core.schedule_write_dm_register(Data0(data.into()))?;
1968
1969            // Write s1, then execute program buffer
1970            let mut command = AccessRegisterCommand(0);
1971            command.set_cmd_type(0);
1972            command.set_transfer(true);
1973            command.set_write(true);
1974
1975            // registers are 32 bit, so we have size 2 here
1976            command.set_aarsize(RiscvBusAccess::A32);
1977            command.set_postexec(true);
1978
1979            // register s1, ie. 0x1009
1980            command.set_regno((registers::S1).id.0 as u32);
1981
1982            core.schedule_write_dm_register(command)?;
1983
1984            if wait_for_idle && let Err(error) = core.wait_for_idle(Duration::from_millis(10)) {
1985                tracing::error!(
1986                    "Executing the abstract command for write_{} failed: {:?}",
1987                    V::WIDTH.byte_width() * 8,
1988                    error
1989                );
1990
1991                return Err(error);
1992            }
1993
1994            core.restore_s0(s0)?;
1995            core.restore_s1(s1)?;
1996
1997            Ok(())
1998        })
1999    }
2000
2001    /// Perform multiple memory writes to consecutive locations using the program buffer.
2002    /// Only writes up to a width of 32 bits are currently supported.
2003    fn perform_memory_write_multiple_progbuf<V: RiscvValue32>(
2004        &mut self,
2005        address: u64,
2006        data: &[V],
2007        wait_for_idle: bool,
2008    ) -> Result<(), RiscvError> {
2009        if data.is_empty() {
2010            return Ok(());
2011        }
2012
2013        if data.len() == 1 {
2014            self.perform_memory_write_progbuf(address, data[0], wait_for_idle)?;
2015            return Ok(());
2016        }
2017
2018        self.halted_access(|core| {
2019            let s0 = core.save_s0()?;
2020            let s1 = core.save_s1()?;
2021
2022            // Setup program buffer for multiple writes
2023            // Store value from register s9 into memory,
2024            // then increase the address for next write.
2025            core.schedule_setup_program_buffer(&[
2026                assembly::sw(0, 8, V::WIDTH as u32, 9),
2027                assembly::addi(8, 8, V::WIDTH.byte_width() as i16),
2028            ])?;
2029
2030            core.write_address_to_s0(address)?;
2031
2032            for value in data {
2033                // write data into data 0
2034                core.schedule_write_dm_register(Data0((*value).into()))?;
2035
2036                // Write s0, then execute program buffer
2037                let mut command = AccessRegisterCommand(0);
2038                command.set_cmd_type(0);
2039                command.set_transfer(true);
2040                command.set_write(true);
2041
2042                // registers are 32 bit, so we have size 2 here
2043                command.set_aarsize(RiscvBusAccess::A32);
2044                command.set_postexec(true);
2045
2046                // register s1
2047                command.set_regno((registers::S1).id.0 as u32);
2048
2049                core.schedule_write_dm_register(command)?;
2050
2051                if wait_for_idle && let Err(error) = core.wait_for_idle(Duration::from_millis(10)) {
2052                    tracing::error!(
2053                        "Executing the abstract command for write_multiple_{} failed: {:?}",
2054                        V::WIDTH.byte_width() * 8,
2055                        error,
2056                    );
2057
2058                    return Err(error);
2059                }
2060            }
2061
2062            // Restore register s0 and s1
2063
2064            core.restore_s0(s0)?;
2065            core.restore_s1(s1)?;
2066
2067            Ok(())
2068        })
2069    }
2070
2071    /// Build a postexec-only abstract command (run the program buffer without a
2072    /// register transfer) that strict DM implementations accept.
2073    ///
2074    /// A `postexec=1, transfer=0` command with `aarsize=0` is rejected as
2075    /// `NotSupported` (abstractcs.cmderr=2) by some DMs — notably the HiSilicon
2076    /// WS63. Set a valid `aarsize` and `regno=x0` explicitly so the program
2077    /// buffer can be executed on those implementations.
2078    fn postexec_command(&self) -> AccessRegisterCommand {
2079        let mut cmd = AccessRegisterCommand(0);
2080        cmd.set_cmd_type(0);
2081        cmd.set_postexec(true);
2082        cmd.set_transfer(false);
2083        cmd.set_aarsize(if self.state.xlen_64 {
2084            RiscvBusAccess::A64
2085        } else {
2086            RiscvBusAccess::A32
2087        });
2088        cmd.set_regno(0x1000); // x0
2089        cmd
2090    }
2091
2092    pub(crate) fn execute_abstract_command(&mut self, command: u32) -> Result<(), RiscvError> {
2093        // ensure that preconditions are fulfilled
2094        // haltreq      = 0
2095        // resumereq    = 0
2096        // ackhavereset = 0
2097
2098        let mut dmcontrol = self.state.current_dmcontrol;
2099        dmcontrol.set_dmactive(true);
2100        dmcontrol.set_haltreq(false);
2101        dmcontrol.set_resumereq(false);
2102        dmcontrol.set_ackhavereset(false);
2103        self.schedule_write_dm_register(dmcontrol)?;
2104
2105        fn do_execute_abstract_command(
2106            core: &mut RiscvCommunicationInterface,
2107            command: Command,
2108        ) -> Result<(), RiscvError> {
2109            // Clear any previous command errors.
2110            let mut abstractcs_clear = Abstractcs(0);
2111            abstractcs_clear.set_cmderr(0x7);
2112
2113            core.schedule_write_dm_register(abstractcs_clear)?;
2114            core.schedule_write_dm_register(command)?;
2115
2116            let start_time = Instant::now();
2117
2118            // Poll busy flag in abstractcs.
2119            let mut abstractcs;
2120            loop {
2121                abstractcs = core.read_dm_register::<Abstractcs>()?;
2122
2123                if !abstractcs.busy() {
2124                    break;
2125                }
2126
2127                if start_time.elapsed() > RISCV_TIMEOUT {
2128                    return Err(RiscvError::Timeout);
2129                }
2130            }
2131
2132            tracing::debug!("abstracts: {:?}", abstractcs);
2133
2134            // Check command result for error.
2135            AbstractCommandErrorKind::parse(abstractcs)?;
2136
2137            Ok(())
2138        }
2139
2140        match do_execute_abstract_command(self, Command(command)) {
2141            err @ Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::HaltResume)) => {
2142                // Re-query the hardware; cached `is_halted` may be stale after
2143                // a self-reboot (e.g. watchdog reset).
2144                self.state.is_halted = false;
2145                if !self.core_halted()? {
2146                    // This command requires the core to be halted.
2147                    // We can do that, so let's try again.
2148                    self.halted_access(|core| do_execute_abstract_command(core, Command(command)))
2149                } else {
2150                    // This command requires the core to be resumed. This is a bit more drastic than
2151                    // what we want to do here, so we bubble up the error.
2152                    err
2153                }
2154            }
2155            other => other,
2156        }
2157    }
2158
2159    /// Check if a register can be accessed via abstract commands
2160    fn check_abstract_cmd_register_support(
2161        &self,
2162        regno: RegisterId,
2163        rw: CoreRegisterAbstractCmdSupport,
2164    ) -> bool {
2165        if let Some(status) = self.state.abstract_cmd_register_info.get(&regno) {
2166            status.supports(rw)
2167        } else {
2168            // If not cached yet, assume the register is accessible
2169            true
2170        }
2171    }
2172
2173    /// Remember, that the given register can not be accessed via abstract commands
2174    fn set_abstract_cmd_register_unsupported(
2175        &mut self,
2176        regno: RegisterId,
2177        rw: CoreRegisterAbstractCmdSupport,
2178    ) {
2179        let entry = self
2180            .state
2181            .abstract_cmd_register_info
2182            .entry(regno)
2183            .or_insert(CoreRegisterAbstractCmdSupport::BOTH);
2184
2185        entry.unset(rw);
2186    }
2187
2188    // Read a core register using an abstract command
2189    pub(crate) fn abstract_cmd_register_read(
2190        &mut self,
2191        regno: impl Into<RegisterId>,
2192    ) -> Result<u32, RiscvError> {
2193        let regno = regno.into();
2194
2195        // Check if the register was already tried via abstract cmd
2196        if !self.check_abstract_cmd_register_support(regno, CoreRegisterAbstractCmdSupport::READ) {
2197            return Err(RiscvError::AbstractCommand(
2198                AbstractCommandErrorKind::NotSupported,
2199            ));
2200        }
2201
2202        // read from data0
2203        let mut command = AccessRegisterCommand(0);
2204        command.set_cmd_type(0);
2205        command.set_transfer(true);
2206        command.set_aarsize(RiscvBusAccess::A32);
2207
2208        command.set_regno(regno.0 as u32);
2209
2210        match self.execute_abstract_command(command.0) {
2211            Ok(_) => (),
2212            err @ Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::NotSupported)) => {
2213                // Remember, that this register is unsupported
2214                self.set_abstract_cmd_register_unsupported(
2215                    regno,
2216                    CoreRegisterAbstractCmdSupport::READ,
2217                );
2218                err?;
2219            }
2220            Err(e) => return Err(e),
2221        }
2222
2223        let register_value: Data0 = self.read_dm_register()?;
2224
2225        Ok(register_value.into())
2226    }
2227
2228    pub(crate) fn abstract_cmd_register_write<V: RiscvValue>(
2229        &mut self,
2230        regno: impl Into<RegisterId>,
2231        value: V,
2232    ) -> Result<(), RiscvError> {
2233        let regno = regno.into();
2234
2235        // Check if the register was already tried via abstract cmd
2236        if !self.check_abstract_cmd_register_support(regno, CoreRegisterAbstractCmdSupport::WRITE) {
2237            return Err(RiscvError::AbstractCommand(
2238                AbstractCommandErrorKind::NotSupported,
2239            ));
2240        }
2241
2242        // write to data0
2243        let mut command = AccessRegisterCommand(0);
2244        command.set_cmd_type(0);
2245        command.set_transfer(true);
2246        command.set_write(true);
2247        command.set_aarsize(V::WIDTH);
2248
2249        command.set_regno(regno.0 as u32);
2250
2251        self.schedule_write_large_dtm_register::<V, Arg0>(value)?;
2252
2253        match self.execute_abstract_command(command.0) {
2254            Ok(_) => Ok(()),
2255            err @ Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::NotSupported)) => {
2256                // Remember, that this register is unsupported
2257                self.set_abstract_cmd_register_unsupported(
2258                    regno,
2259                    CoreRegisterAbstractCmdSupport::WRITE,
2260                );
2261                err
2262            }
2263            Err(e) => Err(e),
2264        }
2265    }
2266
2267    /// Read a CSR value via the program buffer (fallback when abstract commands are unsupported).
2268    ///
2269    /// Executes `csrr s0, addr` in the program buffer, then reads back S0. Width is selected
2270    /// automatically based on the XLEN mode of the interface.
2271    pub fn read_csr_progbuf(&mut self, address: u16) -> Result<u64, RiscvError> {
2272        self.halted_access(|core| {
2273            // Validate that the CSR address is valid
2274            if address > RISCV_MAX_CSR_ADDR {
2275                return Err(RiscvError::UnsupportedCsrAddress(address));
2276            }
2277            // Read CSR value into register 8 (s0)
2278            let csrr_cmd = assembly::csrr(8, address);
2279            core.schedule_setup_program_buffer(&[csrr_cmd])?;
2280            let postexec_cmd = core.postexec_command();
2281            core.run_with_s0_saved(|c| {
2282                c.execute_abstract_command(postexec_cmd.0)?;
2283                c.read_s0_xlen()
2284            })
2285        })
2286    }
2287
2288    /// Read a CSR via the program buffer, forcing 64-bit abstract-command width.
2289    ///
2290    /// Unlike [`Self::read_csr_progbuf`], which uses the XLEN mode that has already been
2291    /// detected, this method temporarily sets `xlen_64 = true` so that S0 is saved and
2292    /// read back with 64-bit abstract commands.  This is necessary when reading CSRs
2293    /// (such as MISA) before XLEN has been determined, e.g. in a vendor `on_connect`
2294    /// sequence.
2295    ///
2296    /// On RV32 targets the underlying 64-bit abstract command will fail with
2297    /// [`AbstractCommandErrorKind::NotSupported`], which is propagated as an error so that
2298    /// callers can handle RV32/RV64 detection gracefully.
2299    pub(crate) fn read_csr_progbuf_64(&mut self, address: u16) -> Result<u64, RiscvError> {
2300        let saved_xlen = self.state.xlen_64;
2301        self.state.xlen_64 = true;
2302        let result = self.read_csr_progbuf(address);
2303        self.state.xlen_64 = saved_xlen;
2304        result
2305    }
2306
2307    /// Write a CSR value via the program buffer (fallback when abstract commands are unsupported).
2308    ///
2309    /// Writes `value` into S0 then executes `csrw addr, s0` in the program buffer. Width is
2310    /// selected automatically based on the XLEN mode of the interface.
2311    pub fn write_csr_progbuf(&mut self, address: u16, value: u64) -> Result<(), RiscvError> {
2312        self.halted_access(|core| {
2313            if address > RISCV_MAX_CSR_ADDR {
2314                return Err(RiscvError::UnsupportedCsrAddress(address));
2315            }
2316            let csrw_cmd = assembly::csrw(address, 8);
2317            core.schedule_setup_program_buffer(&[csrw_cmd])?;
2318            let postexec_cmd = core.postexec_command();
2319            core.run_with_s0_saved(|c| {
2320                c.write_s0_xlen(value)?;
2321                c.execute_abstract_command(postexec_cmd.0)
2322            })
2323        })
2324    }
2325
2326    fn read_word<V: RiscvValue32>(&mut self, address: u64) -> Result<V, crate::Error> {
2327        if !self.state.xlen_64 {
2328            valid_32bit_address(address)?;
2329        }
2330        let result = match self.state.memory_access_method(V::WIDTH, address) {
2331            MemoryAccessMethod::ProgramBuffer => {
2332                self.perform_memory_read_progbuf(address, false)?
2333            }
2334            MemoryAccessMethod::WaitingProgramBuffer => {
2335                self.perform_memory_read_progbuf(address, true)?
2336            }
2337            MemoryAccessMethod::SystemBus => self.perform_memory_read_sysbus(address)?,
2338            MemoryAccessMethod::AbstractCommand => {
2339                return Err(crate::Error::NotImplemented(
2340                    "Memory access using abstract commands is not implemented",
2341                ));
2342            }
2343        };
2344
2345        Ok(result)
2346    }
2347
2348    fn read_multiple<V: RiscvValue32>(
2349        &mut self,
2350        address: u64,
2351        data: &mut [V],
2352    ) -> Result<(), crate::Error> {
2353        if !self.state.xlen_64 {
2354            valid_32bit_address(address)?;
2355        }
2356        let address_range = address..(address + (data.len() * V::WIDTH.byte_width()) as u64);
2357        let access_method = self
2358            .state
2359            .memory_range_access_method(V::WIDTH, address_range);
2360        tracing::debug!(
2361            "read_multiple({:?}) from {:#08x} using {:?}",
2362            V::WIDTH,
2363            address,
2364            access_method
2365        );
2366
2367        match access_method {
2368            MemoryAccessMethod::ProgramBuffer => {
2369                self.perform_memory_read_multiple_progbuf(address, data, false)?;
2370            }
2371            MemoryAccessMethod::WaitingProgramBuffer => {
2372                self.perform_memory_read_multiple_progbuf(address, data, true)?;
2373            }
2374            MemoryAccessMethod::SystemBus => {
2375                self.perform_memory_read_multiple_sysbus(address, data)?;
2376            }
2377            MemoryAccessMethod::AbstractCommand => {
2378                return Err(crate::Error::NotImplemented(
2379                    "Memory access using abstract commands is not implemented",
2380                ));
2381            }
2382        };
2383
2384        Ok(())
2385    }
2386
2387    fn write_word<V: RiscvValue32>(&mut self, address: u64, data: V) -> Result<(), crate::Error> {
2388        if !self.state.xlen_64 {
2389            valid_32bit_address(address)?;
2390        }
2391        match self.state.memory_access_method(V::WIDTH, address) {
2392            MemoryAccessMethod::ProgramBuffer => {
2393                self.perform_memory_write_progbuf(address, data, false)?
2394            }
2395            MemoryAccessMethod::WaitingProgramBuffer => {
2396                self.perform_memory_write_progbuf(address, data, true)?
2397            }
2398            MemoryAccessMethod::SystemBus => self.perform_memory_write_sysbus(address, &[data])?,
2399            MemoryAccessMethod::AbstractCommand => {
2400                return Err(crate::Error::NotImplemented(
2401                    "Memory access using abstract commands is not implemented",
2402                ));
2403            }
2404        };
2405
2406        Ok(())
2407    }
2408
2409    fn write_multiple<V: RiscvValue32>(
2410        &mut self,
2411        address: u64,
2412        data: &[V],
2413    ) -> Result<(), crate::Error> {
2414        if !self.state.xlen_64 {
2415            valid_32bit_address(address)?;
2416        }
2417        let address_range = address..(address + (data.len() * V::WIDTH.byte_width()) as u64);
2418        let access_method = self
2419            .state
2420            .memory_range_access_method(V::WIDTH, address_range);
2421        match access_method {
2422            MemoryAccessMethod::SystemBus => self.perform_memory_write_sysbus(address, data)?,
2423            MemoryAccessMethod::ProgramBuffer => {
2424                self.perform_memory_write_multiple_progbuf(address, data, false)?
2425            }
2426            MemoryAccessMethod::WaitingProgramBuffer => {
2427                self.perform_memory_write_multiple_progbuf(address, data, true)?
2428            }
2429            MemoryAccessMethod::AbstractCommand => {
2430                return Err(crate::Error::NotImplemented(
2431                    "Memory access using abstract commands is not implemented",
2432                ));
2433            }
2434        }
2435
2436        Ok(())
2437    }
2438
2439    pub(crate) fn schedule_write_dm_register<R: MemoryMappedRegister<u32>>(
2440        &mut self,
2441        register: R,
2442    ) -> Result<(), RiscvError> {
2443        // write write command to dmi register
2444
2445        tracing::debug!(
2446            "Write DM register '{}' at {:#010x} = {:x?}",
2447            R::NAME,
2448            R::get_mmio_address(),
2449            register
2450        );
2451
2452        self.schedule_write_dm_register_untyped(R::get_mmio_address(), register.into())?;
2453        Ok(())
2454    }
2455
2456    /// Write to a DM register
2457    ///
2458    /// Use the [`Self::schedule_write_dm_register()`] function if possible.
2459    fn schedule_write_dm_register_untyped(
2460        &mut self,
2461        address: u64,
2462        value: u32,
2463    ) -> Result<Option<DeferredResultIndex>, RiscvError> {
2464        self.cache_write(address, value);
2465        self.dtm.schedule_write(address, value)
2466    }
2467
2468    pub(super) fn schedule_read_dm_register<R: MemoryMappedRegister<u32>>(
2469        &mut self,
2470    ) -> Result<DeferredResultIndex, RiscvError> {
2471        tracing::debug!(
2472            "Reading DM register '{}' at {:#010x}",
2473            R::NAME,
2474            R::get_mmio_address()
2475        );
2476
2477        self.schedule_read_dm_register_untyped(R::get_mmio_address())
2478    }
2479
2480    /// Read from a DM register
2481    ///
2482    /// Use the [`Self::schedule_read_dm_register()`] function if possible.
2483    fn schedule_read_dm_register_untyped(
2484        &mut self,
2485        address: u64,
2486    ) -> Result<DeferredResultIndex, RiscvError> {
2487        // Prepare the read by sending a read request with the register address
2488        self.dtm.schedule_read(address)
2489    }
2490
2491    fn schedule_read_large_dtm_register<V, R>(
2492        &mut self,
2493        results: &mut Vec<DeferredResultIndex>,
2494    ) -> Result<(), RiscvError>
2495    where
2496        V: RiscvValue,
2497        R: LargeRegister,
2498    {
2499        V::schedule_read_from_register::<R>(self, results)
2500    }
2501
2502    fn schedule_write_large_dtm_register<V, R>(
2503        &mut self,
2504        value: V,
2505    ) -> Result<Option<DeferredResultIndex>, RiscvError>
2506    where
2507        V: RiscvValue,
2508        R: LargeRegister,
2509    {
2510        V::schedule_write_to_register::<R>(self, value)
2511    }
2512
2513    /// Check if the connected device supports halt after reset.
2514    ///
2515    /// Returns a cached value if available, otherwise queries the
2516    /// `hasresethaltreq` bit in the `dmstatus` register.
2517    pub(crate) fn supports_reset_halt_req(&mut self) -> Result<bool, RiscvError> {
2518        if let Some(has_reset_halt_req) = self.state.hasresethaltreq {
2519            Ok(has_reset_halt_req)
2520        } else {
2521            let dmstatus: Dmstatus = self.read_dm_register()?;
2522
2523            self.state.hasresethaltreq = Some(dmstatus.hasresethaltreq());
2524
2525            Ok(dmstatus.hasresethaltreq())
2526        }
2527    }
2528
2529    /// Resume the core.
2530    pub fn resume_core(&mut self) -> Result<(), RiscvError> {
2531        self.state.is_halted = false; // `false` will re-query the DM, so it's safe to write
2532
2533        // set resume request.
2534        let mut dmcontrol = self.state.current_dmcontrol;
2535        dmcontrol.set_dmactive(true);
2536        dmcontrol.set_resumereq(true);
2537        self.schedule_write_dm_register(dmcontrol)?;
2538
2539        // check if request has been acknowledge.
2540        let status_idx = self.schedule_read_dm_register::<Dmstatus>()?;
2541
2542        // clear resume request.
2543        dmcontrol.set_resumereq(false);
2544        self.write_dm_register(dmcontrol)?;
2545
2546        let status = Dmstatus(self.dtm.read_deferred_result(status_idx)?.into_u32());
2547        if status.allresumeack() || status.allrunning() {
2548            return Ok(());
2549        }
2550        self.wait_for_resume_ack(Duration::from_millis(50))
2551    }
2552
2553    /// Some cores (WCH Qingke) update dmstatus only after a brief delay; poll
2554    /// for the ack bit or for the hart actually running.
2555    fn wait_for_resume_ack(&mut self, timeout: Duration) -> Result<(), RiscvError> {
2556        let start = Instant::now();
2557        loop {
2558            let dmstatus: Dmstatus = self.read_dm_register()?;
2559            if dmstatus.allresumeack() || dmstatus.allrunning() {
2560                return Ok(());
2561            }
2562            if start.elapsed() >= timeout {
2563                return Err(RiscvError::RequestNotAcknowledged);
2564            }
2565            std::thread::sleep(Duration::from_millis(1));
2566        }
2567    }
2568
2569    /// Perform a reset of all harts on the target and halt them at the first instruction.
2570    pub fn reset_hart_and_halt(&mut self, timeout: Duration) -> Result<(), RiscvError> {
2571        tracing::debug!("Resetting core, setting hartreset bit");
2572
2573        let mut dmcontrol = self.state.current_dmcontrol;
2574        dmcontrol.set_dmactive(true);
2575        dmcontrol.set_hartreset(true);
2576        dmcontrol.set_haltreq(true);
2577
2578        self.write_dm_register(dmcontrol)?;
2579
2580        // Read back register to verify reset is supported
2581        let readback: Dmcontrol = self.read_dm_register()?;
2582
2583        if readback.hartreset() {
2584            tracing::debug!("Clearing hartreset bit");
2585            // Reset is performed by setting the bit high, and then low again
2586            let mut dmcontrol = readback;
2587            dmcontrol.set_dmactive(true);
2588            dmcontrol.set_haltreq(true);
2589            dmcontrol.set_hartreset(false);
2590
2591            self.write_dm_register(dmcontrol)?;
2592        } else {
2593            // Hartreset is not supported, whole core needs to be reset
2594            //
2595            // TODO: Cache this
2596            tracing::debug!("Hartreset bit not supported, using ndmreset");
2597            dmcontrol.set_hartreset(false);
2598            dmcontrol.set_ndmreset(true);
2599            dmcontrol.set_haltreq(true);
2600
2601            self.write_dm_register(dmcontrol)?;
2602
2603            tracing::debug!("Clearing ndmreset bit");
2604            dmcontrol.set_ndmreset(false);
2605            dmcontrol.set_haltreq(true);
2606
2607            self.write_dm_register(dmcontrol)?;
2608        }
2609
2610        let start = Instant::now();
2611
2612        loop {
2613            // check that cores have reset
2614            let readback: Dmstatus = self.read_dm_register()?;
2615
2616            // Spec 1.0: poll ndmresetpending until the system finishes resetting.
2617            if self.state.debug_version == DebugModuleVersion::Version1_0
2618                && readback.ndmresetpending()
2619            {
2620                if start.elapsed() > timeout {
2621                    return Err(RiscvError::RequestNotAcknowledged);
2622                }
2623                continue;
2624            }
2625
2626            if readback.allhavereset() && readback.allhalted() {
2627                break;
2628            }
2629
2630            if start.elapsed() > timeout {
2631                return Err(RiscvError::RequestNotAcknowledged);
2632            }
2633            self.write_dm_register(dmcontrol)?;
2634        }
2635
2636        // clear the reset request
2637        dmcontrol.set_haltreq(false);
2638        dmcontrol.set_ackhavereset(true);
2639        dmcontrol.set_hartreset(false);
2640        dmcontrol.set_ndmreset(false);
2641
2642        self.write_dm_register(dmcontrol)?;
2643
2644        // Reenable halt on breakpoint because this gets disabled if we reset the core
2645        self.debug_on_sw_breakpoint(true)?;
2646
2647        Ok(())
2648    }
2649
2650    fn debug_on_sw_breakpoint(&mut self, enabled: bool) -> Result<(), RiscvError> {
2651        let raw = self.read_csr(0x7b0)?;
2652        let mut dcsr = Dcsr(raw as u32);
2653        tracing::debug!(
2654            "debug_on_sw_breakpoint({}): DCSR before = {:#010x}",
2655            enabled,
2656            raw
2657        );
2658
2659        dcsr.set_ebreakm(enabled);
2660        dcsr.set_ebreaks(enabled);
2661        dcsr.set_ebreaku(enabled);
2662
2663        tracing::debug!(
2664            "debug_on_sw_breakpoint({}): DCSR to write = {:#010x}",
2665            enabled,
2666            dcsr.0
2667        );
2668
2669        self.write_csr(0x7b0, u64::from(dcsr.0))?;
2670        self.state.sw_breakpoint_debug_enabled = enabled;
2671        Ok(())
2672    }
2673
2674    /// Returns a mutable reference to the memory access configuration.
2675    pub fn memory_access_config(&mut self) -> &mut MemoryAccessConfig {
2676        &mut self.state.memory_access_config
2677    }
2678
2679    /// Clear the abstractauto register to disable any auto-execution,
2680    /// clear cmderr, and invalidate the progbuf cache.
2681    ///
2682    /// This should be called during session setup to prevent stale autoexec
2683    /// state from a previous crashed session from interfering.
2684    pub fn clear_abstractauto(&mut self) {
2685        if let Err(e) = self.write_dm_register(Abstractauto(0)) {
2686            tracing::debug!("Failed to clear abstractauto: {:?}", e);
2687        }
2688        // Clear any cmderr that may have been caused by stale autoexec.
2689        let mut abstractcs_clear = Abstractcs(0);
2690        abstractcs_clear.set_cmderr(0x7);
2691        if let Err(e) = self.write_dm_register(abstractcs_clear) {
2692            tracing::debug!("Failed to clear abstractcs cmderr: {:?}", e);
2693        }
2694        // Invalidate the progbuf cache so the next operation fully rewrites it.
2695        self.state.progbuf_cache = [0u32; 16];
2696    }
2697}
2698
2699pub(crate) trait LargeRegister {
2700    const R0_ADDRESS: u8;
2701    const R1_ADDRESS: u8;
2702    const R2_ADDRESS: u8;
2703    const R3_ADDRESS: u8;
2704}
2705
2706struct Sbdata {}
2707
2708impl LargeRegister for Sbdata {
2709    const R0_ADDRESS: u8 = Sbdata0::ADDRESS_OFFSET as u8;
2710    const R1_ADDRESS: u8 = Sbdata1::ADDRESS_OFFSET as u8;
2711    const R2_ADDRESS: u8 = Sbdata2::ADDRESS_OFFSET as u8;
2712    const R3_ADDRESS: u8 = Sbdata3::ADDRESS_OFFSET as u8;
2713}
2714
2715struct Arg0 {}
2716
2717impl LargeRegister for Arg0 {
2718    const R0_ADDRESS: u8 = Data0::ADDRESS_OFFSET as u8;
2719    const R1_ADDRESS: u8 = Data1::ADDRESS_OFFSET as u8;
2720    const R2_ADDRESS: u8 = Data2::ADDRESS_OFFSET as u8;
2721    const R3_ADDRESS: u8 = Data3::ADDRESS_OFFSET as u8;
2722}
2723
2724/// Helper trait, limited to RiscvValue no larger than 32 bits
2725pub(crate) trait RiscvValue32: RiscvValue + Into<u32> {
2726    fn from_register_value(value: u32) -> Self;
2727}
2728
2729impl RiscvValue32 for u8 {
2730    fn from_register_value(value: u32) -> Self {
2731        value as u8
2732    }
2733}
2734impl RiscvValue32 for u16 {
2735    fn from_register_value(value: u32) -> Self {
2736        value as u16
2737    }
2738}
2739impl RiscvValue32 for u32 {
2740    fn from_register_value(value: u32) -> Self {
2741        value
2742    }
2743}
2744
2745/// Marker trait for different values which
2746/// can be read / written using the debug module.
2747pub(crate) trait RiscvValue: std::fmt::Debug + Copy + Sized {
2748    const WIDTH: RiscvBusAccess;
2749
2750    fn schedule_read_from_register<R>(
2751        interface: &mut RiscvCommunicationInterface,
2752        results: &mut Vec<DeferredResultIndex>,
2753    ) -> Result<(), RiscvError>
2754    where
2755        R: LargeRegister;
2756
2757    fn read_scheduled_result(
2758        interface: &mut RiscvCommunicationInterface,
2759        results: &mut Vec<DeferredResultIndex>,
2760    ) -> Result<Self, RiscvError>;
2761
2762    fn schedule_write_to_register<R>(
2763        interface: &mut RiscvCommunicationInterface,
2764        value: Self,
2765    ) -> Result<Option<DeferredResultIndex>, RiscvError>
2766    where
2767        R: LargeRegister;
2768}
2769
2770impl RiscvValue for u8 {
2771    const WIDTH: RiscvBusAccess = RiscvBusAccess::A8;
2772
2773    fn schedule_read_from_register<R>(
2774        interface: &mut RiscvCommunicationInterface,
2775        results: &mut Vec<DeferredResultIndex>,
2776    ) -> Result<(), RiscvError>
2777    where
2778        R: LargeRegister,
2779    {
2780        results.push(interface.schedule_read_dm_register_untyped(R::R0_ADDRESS as u64)?);
2781        Ok(())
2782    }
2783
2784    fn read_scheduled_result(
2785        interface: &mut RiscvCommunicationInterface,
2786        results: &mut Vec<DeferredResultIndex>,
2787    ) -> Result<Self, RiscvError> {
2788        let result = interface.dtm.read_deferred_result(results.remove(0))?;
2789
2790        Ok(result.into_u32() as u8)
2791    }
2792
2793    fn schedule_write_to_register<R>(
2794        interface: &mut RiscvCommunicationInterface,
2795        value: Self,
2796    ) -> Result<Option<DeferredResultIndex>, RiscvError>
2797    where
2798        R: LargeRegister,
2799    {
2800        interface.schedule_write_dm_register_untyped(R::R0_ADDRESS as u64, value as u32)
2801    }
2802}
2803
2804impl RiscvValue for u16 {
2805    const WIDTH: RiscvBusAccess = RiscvBusAccess::A16;
2806
2807    fn schedule_read_from_register<R>(
2808        interface: &mut RiscvCommunicationInterface,
2809        results: &mut Vec<DeferredResultIndex>,
2810    ) -> Result<(), RiscvError>
2811    where
2812        R: LargeRegister,
2813    {
2814        results.push(interface.schedule_read_dm_register_untyped(R::R0_ADDRESS as u64)?);
2815        Ok(())
2816    }
2817
2818    fn read_scheduled_result(
2819        interface: &mut RiscvCommunicationInterface,
2820        results: &mut Vec<DeferredResultIndex>,
2821    ) -> Result<Self, RiscvError> {
2822        let result = interface.dtm.read_deferred_result(results.remove(0))?;
2823
2824        Ok(result.into_u32() as u16)
2825    }
2826
2827    fn schedule_write_to_register<R>(
2828        interface: &mut RiscvCommunicationInterface,
2829        value: Self,
2830    ) -> Result<Option<DeferredResultIndex>, RiscvError>
2831    where
2832        R: LargeRegister,
2833    {
2834        interface.schedule_write_dm_register_untyped(R::R0_ADDRESS as u64, value as u32)
2835    }
2836}
2837
2838impl RiscvValue for u32 {
2839    const WIDTH: RiscvBusAccess = RiscvBusAccess::A32;
2840
2841    fn schedule_read_from_register<R>(
2842        interface: &mut RiscvCommunicationInterface,
2843        results: &mut Vec<DeferredResultIndex>,
2844    ) -> Result<(), RiscvError>
2845    where
2846        R: LargeRegister,
2847    {
2848        results.push(interface.schedule_read_dm_register_untyped(R::R0_ADDRESS as u64)?);
2849        Ok(())
2850    }
2851
2852    fn read_scheduled_result(
2853        interface: &mut RiscvCommunicationInterface,
2854        results: &mut Vec<DeferredResultIndex>,
2855    ) -> Result<Self, RiscvError> {
2856        let result = interface.dtm.read_deferred_result(results.remove(0))?;
2857
2858        Ok(result.into_u32())
2859    }
2860
2861    fn schedule_write_to_register<R>(
2862        interface: &mut RiscvCommunicationInterface,
2863        value: Self,
2864    ) -> Result<Option<DeferredResultIndex>, RiscvError>
2865    where
2866        R: LargeRegister,
2867    {
2868        interface.schedule_write_dm_register_untyped(R::R0_ADDRESS as u64, value)
2869    }
2870}
2871
2872impl RiscvValue for u64 {
2873    const WIDTH: RiscvBusAccess = RiscvBusAccess::A64;
2874
2875    fn schedule_read_from_register<R>(
2876        interface: &mut RiscvCommunicationInterface,
2877        results: &mut Vec<DeferredResultIndex>,
2878    ) -> Result<(), RiscvError>
2879    where
2880        R: LargeRegister,
2881    {
2882        results.push(interface.schedule_read_dm_register_untyped(R::R1_ADDRESS as u64)?);
2883        results.push(interface.schedule_read_dm_register_untyped(R::R0_ADDRESS as u64)?);
2884        Ok(())
2885    }
2886
2887    fn read_scheduled_result(
2888        interface: &mut RiscvCommunicationInterface,
2889        results: &mut Vec<DeferredResultIndex>,
2890    ) -> Result<Self, RiscvError> {
2891        let r1 = interface.dtm.read_deferred_result(results.remove(0))?;
2892        let r0 = interface.dtm.read_deferred_result(results.remove(0))?;
2893
2894        Ok(((r1.into_u32() as u64) << 32) | (r0.into_u32() as u64))
2895    }
2896
2897    fn schedule_write_to_register<R>(
2898        interface: &mut RiscvCommunicationInterface,
2899        value: Self,
2900    ) -> Result<Option<DeferredResultIndex>, RiscvError>
2901    where
2902        R: LargeRegister,
2903    {
2904        let upper_bits = (value >> 32) as u32;
2905        let lower_bits = (value & 0xffff_ffff) as u32;
2906
2907        // R0 has to be written last, side effects are triggered by writes from
2908        // this register.
2909
2910        interface.schedule_write_dm_register_untyped(R::R1_ADDRESS as u64, upper_bits)?;
2911        interface.schedule_write_dm_register_untyped(R::R0_ADDRESS as u64, lower_bits)
2912    }
2913}
2914
2915impl RiscvValue for u128 {
2916    const WIDTH: RiscvBusAccess = RiscvBusAccess::A128;
2917
2918    fn schedule_read_from_register<R>(
2919        interface: &mut RiscvCommunicationInterface,
2920        results: &mut Vec<DeferredResultIndex>,
2921    ) -> Result<(), RiscvError>
2922    where
2923        R: LargeRegister,
2924    {
2925        results.push(interface.schedule_read_dm_register_untyped(R::R3_ADDRESS as u64)?);
2926        results.push(interface.schedule_read_dm_register_untyped(R::R2_ADDRESS as u64)?);
2927        results.push(interface.schedule_read_dm_register_untyped(R::R1_ADDRESS as u64)?);
2928        results.push(interface.schedule_read_dm_register_untyped(R::R0_ADDRESS as u64)?);
2929        Ok(())
2930    }
2931
2932    fn read_scheduled_result(
2933        interface: &mut RiscvCommunicationInterface,
2934        results: &mut Vec<DeferredResultIndex>,
2935    ) -> Result<Self, RiscvError> {
2936        let r3 = interface.dtm.read_deferred_result(results.remove(0))?;
2937        let r2 = interface.dtm.read_deferred_result(results.remove(0))?;
2938        let r1 = interface.dtm.read_deferred_result(results.remove(0))?;
2939        let r0 = interface.dtm.read_deferred_result(results.remove(0))?;
2940
2941        Ok(((r3.into_u32() as u128) << 96)
2942            | ((r2.into_u32() as u128) << 64)
2943            | ((r1.into_u32() as u128) << 32)
2944            | (r0.into_u32() as u128))
2945    }
2946
2947    fn schedule_write_to_register<R>(
2948        interface: &mut RiscvCommunicationInterface,
2949        value: Self,
2950    ) -> Result<Option<DeferredResultIndex>, RiscvError>
2951    where
2952        R: LargeRegister,
2953    {
2954        let bits_3 = (value >> 96) as u32;
2955        let bits_2 = (value >> 64) as u32;
2956        let bits_1 = (value >> 32) as u32;
2957        let bits_0 = (value & 0xffff_ffff) as u32;
2958
2959        // R0 has to be written last, side effects are triggered by writes from
2960        // this register.
2961
2962        interface.schedule_write_dm_register_untyped(R::R3_ADDRESS as u64, bits_3)?;
2963        interface.schedule_write_dm_register_untyped(R::R2_ADDRESS as u64, bits_2)?;
2964        interface.schedule_write_dm_register_untyped(R::R1_ADDRESS as u64, bits_1)?;
2965        interface.schedule_write_dm_register_untyped(R::R0_ADDRESS as u64, bits_0)
2966    }
2967}
2968
2969impl MemoryInterface for RiscvCommunicationInterface<'_> {
2970    fn supports_native_64bit_access(&mut self) -> bool {
2971        self.state.xlen_64
2972    }
2973
2974    fn read_word_64(&mut self, address: u64) -> Result<u64, crate::error::Error> {
2975        let mut ret = self.read_word::<u32>(address)? as u64;
2976        ret |= (self.read_word::<u32>(address + 4)? as u64) << 32;
2977
2978        Ok(ret)
2979    }
2980
2981    fn read_word_32(&mut self, address: u64) -> Result<u32, crate::Error> {
2982        tracing::debug!("read_word_32 from {:#08x}", address);
2983        self.read_word(address)
2984    }
2985
2986    fn read_word_16(&mut self, address: u64) -> Result<u16, crate::Error> {
2987        tracing::debug!("read_word_16 from {:#08x}", address);
2988        self.read_word(address)
2989    }
2990
2991    fn read_word_8(&mut self, address: u64) -> Result<u8, crate::Error> {
2992        tracing::debug!("read_word_8 from {:#08x}", address);
2993        self.read_word(address)
2994    }
2995
2996    fn read_64(&mut self, address: u64, data: &mut [u64]) -> Result<(), crate::error::Error> {
2997        tracing::debug!("read_64 from {:#08x}", address);
2998
2999        for (i, d) in data.iter_mut().enumerate() {
3000            *d = self.read_word_64(address + i as u64 * 8)?;
3001        }
3002
3003        Ok(())
3004    }
3005
3006    fn read_32(&mut self, address: u64, data: &mut [u32]) -> Result<(), crate::Error> {
3007        tracing::debug!("read_32 from {:#08x}", address);
3008        self.read_multiple(address, data)
3009    }
3010
3011    fn read_16(&mut self, address: u64, data: &mut [u16]) -> Result<(), crate::Error> {
3012        tracing::debug!("read_16 from {:#08x}", address);
3013        self.read_multiple(address, data)
3014    }
3015
3016    fn read_8(&mut self, address: u64, data: &mut [u8]) -> Result<(), crate::Error> {
3017        tracing::debug!("read_8 from {:#08x}", address);
3018        self.read_multiple(address, data)
3019    }
3020
3021    fn write_word_64(&mut self, address: u64, data: u64) -> Result<(), crate::error::Error> {
3022        self.write_word(address, data as u32)?;
3023        self.write_word(address + 4, (data >> 32) as u32)
3024    }
3025
3026    fn write_word_32(&mut self, address: u64, data: u32) -> Result<(), crate::Error> {
3027        self.write_word(address, data)
3028    }
3029
3030    fn write_word_16(&mut self, address: u64, data: u16) -> Result<(), crate::Error> {
3031        self.write_word(address, data)
3032    }
3033
3034    fn write_word_8(&mut self, address: u64, data: u8) -> Result<(), crate::Error> {
3035        self.write_word(address, data)
3036    }
3037
3038    fn write_64(&mut self, address: u64, data: &[u64]) -> Result<(), crate::error::Error> {
3039        tracing::debug!("write_64 to {:#08x}", address);
3040
3041        for (i, d) in data.iter().enumerate() {
3042            self.write_word_64(address + i as u64 * 8, *d)?;
3043        }
3044
3045        Ok(())
3046    }
3047
3048    fn write_32(&mut self, address: u64, data: &[u32]) -> Result<(), crate::Error> {
3049        tracing::debug!("write_32 to {:#08x}", address);
3050        self.write_multiple(address, data)
3051    }
3052
3053    fn write_16(&mut self, address: u64, data: &[u16]) -> Result<(), crate::Error> {
3054        tracing::debug!("write_16 to {:#08x}", address);
3055        self.write_multiple(address, data)
3056    }
3057
3058    fn write_8(&mut self, address: u64, data: &[u8]) -> Result<(), crate::Error> {
3059        tracing::debug!("write_8 to {:#08x}", address);
3060        self.write_multiple(address, data)
3061    }
3062
3063    fn supports_8bit_transfers(&self) -> Result<bool, crate::Error> {
3064        Ok(true)
3065    }
3066
3067    fn flush(&mut self) -> Result<(), crate::Error> {
3068        Ok(())
3069    }
3070}
3071
3072/// Access width for bus access.
3073/// This is used both for system bus access (`sbcs` register),
3074/// as well for abstract commands.
3075#[derive(Copy, Clone, PartialEq, PartialOrd, Hash, Eq, Debug)]
3076pub enum RiscvBusAccess {
3077    /// 1 byte
3078    A8 = 0,
3079    /// 2 bytes
3080    A16 = 1,
3081    /// 4 bytes
3082    A32 = 2,
3083    /// 8 bytes
3084    A64 = 3,
3085    /// 16 bytes.
3086    A128 = 4,
3087}
3088
3089impl RiscvBusAccess {
3090    /// Width of an access in bytes
3091    const fn byte_width(&self) -> usize {
3092        match self {
3093            RiscvBusAccess::A8 => 1,
3094            RiscvBusAccess::A16 => 2,
3095            RiscvBusAccess::A32 => 4,
3096            RiscvBusAccess::A64 => 8,
3097            RiscvBusAccess::A128 => 16,
3098        }
3099    }
3100}
3101
3102impl From<RiscvBusAccess> for u8 {
3103    fn from(value: RiscvBusAccess) -> Self {
3104        value as u8
3105    }
3106}
3107
3108/// Different methods of memory access,
3109/// which can be supported by a debug module.
3110///
3111/// The `AbstractCommand` method for memory access is not implemented.
3112#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
3113pub enum MemoryAccessMethod {
3114    /// Memory access using an abstract command is supported
3115    AbstractCommand,
3116    /// Memory access using the program buffer is supported, with explicit waiting for the instructions to complete
3117    WaitingProgramBuffer,
3118    /// Memory access using the program buffer is supported
3119    ProgramBuffer,
3120    /// Memory access using system bus access supported
3121    SystemBus,
3122}
3123
3124memory_mapped_bitfield_register! {
3125    /// Abstract command register, located at address 0x17
3126    /// This is not for all commands, only for the ones
3127    /// from the debug spec.
3128    pub struct AccessRegisterCommand(u32);
3129    0x17, "command",
3130    impl From;
3131    /// This is 0 to indicate Access Register Command.
3132    pub _, set_cmd_type: 31, 24;
3133    /// 2: Access the lowest 32 bits of the register.\
3134    /// 3: Access the lowest 64 bits of the register.\
3135    /// 4: Access the lowest 128 bits of the register.
3136    ///
3137    /// If `aarsize` specifies a size larger than the register’s
3138    /// actual size, then the access must fail. If a register is accessible, then reads of `aarsize` less than
3139    /// or equal to the register’s actual size must be supported.
3140    ///
3141    /// This field controls the Argument Width as referenced in Table 3.1.
3142    pub u8, from into RiscvBusAccess, _, set_aarsize: 22, 20;
3143    /// 0: No effect. This variant must be supported.\
3144    /// 1: After a successful register access, `regno` is incremented (wrapping around to 0). Supporting
3145    /// this variant is optional.
3146    pub _, set_aarpostincrement: 19;
3147    /// 0: No effect. This variant must be supported, and
3148    /// is the only supported one if `progbufsize` is 0.\
3149    /// 1: Execute the program in the Program Buffer
3150    /// exactly once after performing the transfer, if any.
3151    /// Supporting this variant is optional.
3152    pub _, set_postexec: 18;
3153    /// 0: Don’t do the operation specified by write.\
3154    /// 1: Do the operation specified by write.
3155    /// This bit can be used to just execute the Program Buffer without having to worry about placing valid values into `aarsize` or `regno`
3156    pub _, set_transfer: 17;
3157    /// When transfer is set: 0: Copy data from the specified register into arg0 portion of data.
3158    /// 1: Copy data from arg0 portion of data into the
3159    /// specified register.
3160    pub _, set_write: 16;
3161    /// Number of the register to access, as described in
3162    /// Table 3.3. dpc may be used as an alias for PC if
3163    /// this command is supported on a non-halted hart.
3164    pub _, set_regno: 15, 0;
3165}
3166
3167memory_mapped_bitfield_register! {
3168    /// System Bus Access Control and Status (see 3.12.18)
3169    pub struct Sbcs(u32);
3170    0x38, "sbcs",
3171    impl From;
3172    /// 0: The System Bus interface conforms to mainline
3173    /// drafts of this spec older than 1 January, 2018.\
3174    /// 1: The System Bus interface conforms to this version of the spec.
3175    ///
3176    /// Other values are reserved for future versions
3177    sbversion, _: 31, 29;
3178    /// Set when the debugger attempts to read data
3179    /// while a read is in progress, or when the debugger initiates a new access while one is already in
3180    /// progress (while `sbbusy` is set). It remains set until
3181    /// it’s explicitly cleared by the debugger.
3182    /// While this field is set, no more system bus accesses
3183    /// can be initiated by the Debug Module.
3184    sbbusyerror, set_sbbusyerror: 22;
3185    /// When 1, indicates the system bus master is busy.
3186    /// (Whether the system bus itself is busy is related,
3187    /// but not the same thing.) This bit goes high immediately when a read or write is requested for
3188    /// any reason, and does not go low until the access
3189    /// is fully completed.
3190    ///
3191    /// Writes to `sbcs` while `sbbusy` is high result in undefined behavior. A debugger must not write to
3192    /// sbcs until it reads `sbbusy` as 0.
3193    sbbusy, _: 21;
3194    /// When 1, every write to `sbaddress0` automatically
3195    /// triggers a system bus read at the new address.
3196    sbreadonaddr, set_sbreadonaddr: 20;
3197    /// Select the access size to use for system bus accesses.
3198    ///
3199    /// 0: 8-bit\
3200    /// 1: 16-bit\
3201    /// 2: 32-bit\
3202    /// 3: 64-bit\
3203    /// 4: 128-bit
3204    ///
3205    /// If `sbaccess` has an unsupported value when the
3206    /// DM starts a bus access, the access is not performed and `sberror` is set to 4.
3207    sbaccess, set_sbaccess: 19, 17;
3208    /// When 1, `sbaddress` is incremented by the access
3209    /// size (in bytes) selected in `sbaccess` after every system bus access.
3210    sbautoincrement, set_sbautoincrement: 16;
3211    /// When 1, every read from `sbdata0` automatically
3212    /// triggers a system bus read at the (possibly autoincremented) address.
3213    sbreadondata, set_sbreadondata: 15;
3214    /// When the Debug Module’s system bus master encounters an error, this field gets set. The bits in
3215    /// this field remain set until they are cleared by writing 1 to them. While this field is non-zero, no
3216    /// more system bus accesses can be initiated by the
3217    /// Debug Module.
3218    /// An implementation may report “Other” (7) for any error condition.
3219    ///
3220    /// 0: There was no bus error.\
3221    /// 1: There was a timeout.\
3222    /// 2: A bad address was accessed.\
3223    /// 3: There was an alignment error.\
3224    /// 4: An access of unsupported size was requested.\
3225    /// 7: Other.
3226    sberror, set_sberror: 14, 12;
3227    /// Width of system bus addresses in bits. (0 indicates there is no bus access support.)
3228    sbasize, _: 11, 5;
3229    /// 1 when 128-bit system bus accesses are supported.
3230    sbaccess128, _: 4;
3231    /// 1 when 64-bit system bus accesses are supported.
3232    sbaccess64, _: 3;
3233    /// 1 when 32-bit system bus accesses are supported.
3234    sbaccess32, _: 2;
3235    /// 1 when 16-bit system bus accesses are supported.
3236    sbaccess16, _: 1;
3237    /// 1 when 8-bit system bus accesses are supported.
3238    sbaccess8, _: 0;
3239}
3240
3241memory_mapped_bitfield_register! {
3242    /// Abstract Command Autoexec (see 3.12.8)
3243    #[derive(Eq, PartialEq)]
3244    pub struct Abstractauto(u32);
3245    0x18, "abstractauto",
3246    impl From;
3247    /// When a bit in this field is 1, read or write accesses to the corresponding `progbuf` word cause
3248    /// the command in command to be executed again.
3249    autoexecprogbuf, set_autoexecprogbuf: 31, 16;
3250    /// When a bit in this field is 1, read or write accesses to the corresponding data word cause the
3251    /// command in command to be executed again.
3252    autoexecdata, set_autoexecdata: 11, 0;
3253}
3254
3255memory_mapped_bitfield_register! {
3256    /// Abstract command register, located at address 0x17
3257    /// This is not for all commands, only for the ones
3258    /// from the debug spec. (see 3.6.1.3)
3259    pub struct AccessMemoryCommand(u32);
3260    0x17, "command",
3261    /// This is 2 to indicate Access Memory Command.
3262    _, set_cmd_type: 31, 24;
3263    /// An implementation does not have to implement
3264    /// both virtual and physical accesses, but it must
3265    /// fail accesses that it doesn’t support.
3266    ///
3267    /// 0: Addresses are physical (to the hart they are
3268    /// performed on).\
3269    /// 1: Addresses are virtual, and translated the way
3270    /// they would be from M-mode, with `MPRV` set.
3271    pub _, set_aamvirtual: 23;
3272    /// 0: Access the lowest 8 bits of the memory location.\
3273    /// 1: Access the lowest 16 bits of the memory location.\
3274    /// 2: Access the lowest 32 bits of the memory location.\
3275    /// 3: Access the lowest 64 bits of the memory location.\
3276    /// 4: Access the lowest 128 bits of the memory location.
3277    pub _, set_aamsize: 22,20;
3278    /// After a memory access has completed, if this bit
3279    /// is 1, increment arg1 (which contains the address
3280    /// used) by the number of bytes encoded in `aamsize`.
3281    pub _, set_aampostincrement: 19;
3282    /// 0: Copy data from the memory location specified
3283    /// in arg1 into arg0 portion of data.\
3284    /// 1: Copy data from arg0 portion of data into the
3285    /// memory location specified in arg1.
3286    pub _, set_write: 16;
3287    /// These bits are reserved for target-specific uses.
3288    pub _, set_target_specific: 15, 14;
3289}
3290
3291impl From<AccessMemoryCommand> for u32 {
3292    fn from(register: AccessMemoryCommand) -> Self {
3293        let mut reg = register;
3294        reg.set_cmd_type(2);
3295        reg.0
3296    }
3297}
3298
3299impl From<u32> for AccessMemoryCommand {
3300    fn from(value: u32) -> Self {
3301        Self(value)
3302    }
3303}
3304
3305memory_mapped_bitfield_register! { pub struct Sbaddress0(u32); 0x39, "sbaddress0", impl From; }
3306memory_mapped_bitfield_register! { pub struct Sbaddress1(u32); 0x3a, "sbaddress1", impl From; }
3307memory_mapped_bitfield_register! { pub struct Sbaddress2(u32); 0x3b, "sbaddress2", impl From; }
3308memory_mapped_bitfield_register! { pub struct Sbaddress3(u32); 0x37, "sbaddress3", impl From; }
3309
3310memory_mapped_bitfield_register! { pub struct Sbdata0(u32); 0x3c, "sbdata0", impl From; }
3311memory_mapped_bitfield_register! { pub struct Sbdata1(u32); 0x3d, "sbdata1", impl From; }
3312memory_mapped_bitfield_register! { pub struct Sbdata2(u32); 0x3e, "sbdata2", impl From; }
3313memory_mapped_bitfield_register! { pub struct Sbdata3(u32); 0x3f, "sbdata3", impl From; }
3314
3315memory_mapped_bitfield_register! { pub struct Confstrptr0(u32); 0x19, "confstrptr0", impl From; }
3316memory_mapped_bitfield_register! { pub struct Confstrptr1(u32); 0x1a, "confstrptr1", impl From; }
3317memory_mapped_bitfield_register! { pub struct Confstrptr2(u32); 0x1b, "confstrptr2", impl From; }
3318memory_mapped_bitfield_register! { pub struct Confstrptr3(u32); 0x1c, "confstrptr3", impl From; }