Skip to main content

probe_rs/architecture/riscv/
mod.rs

1//! All the interface bits for RISC-V.
2
3use crate::{
4    CoreInterface, CoreRegister, CoreStatus, CoreType, Error, HaltReason, InstructionSet,
5    MemoryInterface, MemoryMappedRegister,
6    architecture::riscv::sequences::RiscvDebugSequence,
7    core::{
8        Architecture, BreakpointCause, CoreInformation, CoreRegisters, RegisterId, RegisterValue,
9    },
10    memory::{CoreMemoryInterface, valid_32bit_address},
11    memory_mapped_bitfield_register,
12    probe::DebugProbeError,
13    semihosting::decode_semihosting_syscall,
14    semihosting::{SemihostingCommand, UnknownCommandDetails},
15};
16use bitfield::bitfield;
17use communication_interface::{AbstractCommandErrorKind, RiscvCommunicationInterface, RiscvError};
18use registers::{FP, RA, RISCV_CORE_REGISTERS, RISCV_WITH_FP_CORE_REGISTERS, SP};
19use registers64::{FP64, PC64, RA64, RISCV64_CORE_REGISTERS, RISCV64_WITH_FP_CORE_REGISTERS, SP64};
20use std::{
21    marker::PhantomData,
22    sync::Arc,
23    time::{Duration, Instant},
24};
25
26#[macro_use]
27pub mod registers;
28pub mod registers64;
29pub use registers::PC;
30pub(crate) mod assembly;
31pub mod communication_interface;
32pub mod dtm;
33pub mod sequences;
34
35pub use dtm::jtag_dtm::JtagDtmBuilder;
36
37/// Time to wait for the core to re-halt after a single instruction step.
38const SINGLE_STEP_TIMEOUT: Duration = Duration::from_millis(100);
39
40// ── Trigger-type helpers (RV64 bit layout) ───────────────────────────────────
41
42/// Unpack a 64-bit `tdata1` register value into `(trigger_type, Mcontrol)`.
43///
44/// On RV64 the trigger type lives in bits \[63:60\] (not \[31:28\] as in the
45/// 32-bit `Mcontrol` bitfield). The low 32 bits are position-compatible with
46/// `Mcontrol` for the remaining fields.
47fn unpack_mcontrol64(raw: u64) -> (u32, Mcontrol) {
48    ((raw >> 60) as u32, Mcontrol(raw as u32))
49}
50
51/// Repack a modified `Mcontrol` back into a 64-bit `tdata1` value, preserving
52/// the upper 32 bits (type, dmode, …) from the original raw read.
53fn repack_mcontrol64(raw: u64, ctrl: Mcontrol) -> u64 {
54    (raw & 0xFFFF_FFFF_0000_0000) | u64::from(ctrl.0)
55}
56
57// ── XlenMode trait ────────────────────────────────────────────────────────────
58
59mod sealed {
60    pub trait Sealed {}
61}
62
63/// Marker trait that distinguishes RV32 from RV64 operation.
64///
65/// Implemented only by [`Xlen32`] and [`Xlen64`].  Methods on the trait encode
66/// all XLEN-dependent differences so that [`RiscvCore`] can be a single generic
67/// struct rather than two near-duplicate types.
68pub trait XlenMode: sealed::Sealed + 'static {
69    /// Configure the communication interface for this XLEN (e.g. set 64-bit mode).
70    fn configure_interface(interface: &mut RiscvCommunicationInterface);
71    /// The `CoreType` reported by this core.
72    fn core_type() -> CoreType;
73    /// The register file for this core, with or without FPU registers.
74    fn registers(fp_present: bool) -> &'static CoreRegisters;
75    /// The program counter register for this core.
76    fn program_counter() -> &'static CoreRegister;
77    /// The frame pointer register for this core.
78    fn frame_pointer() -> &'static CoreRegister;
79    /// The stack pointer register for this core.
80    fn stack_pointer() -> &'static CoreRegister;
81    /// The return address register for this core.
82    fn return_address() -> &'static CoreRegister;
83    /// Wrap a raw `u64` CSR value as the appropriate `RegisterValue` variant.
84    fn csr_to_register_value(v: u64) -> RegisterValue;
85    /// Unwrap a `RegisterValue` into a `u64` for writing to a CSR.
86    fn register_value_to_csr(v: RegisterValue) -> Result<u64, Error>;
87    /// The `InstructionSet` variant for this XLEN when compressed instructions are present.
88    fn compressed_instruction_set() -> InstructionSet;
89    /// The `InstructionSet` variant for this XLEN without compressed instructions.
90    fn uncompressed_instruction_set() -> InstructionSet;
91    /// Extract `(trigger_type, mcontrol_low32)` from a raw `tdata1` value.
92    ///
93    /// `mcontrol_low32` is the low 32 bits of `tdata1`, which is compatible with
94    /// the `Mcontrol` bitfield on both RV32 and RV64.
95    fn unpack_tdata1(raw: u64) -> (u32, u32);
96    /// Repack a mutated low-32 `mcontrol` value back into a full `tdata1`,
97    /// preserving XLEN-specific upper bits from the original raw read.
98    fn repack_tdata1(raw: u64, ctrl_low32: u32) -> u64;
99    /// Build a fresh `tdata1` value for a new execution breakpoint.
100    ///
101    /// `trigger_type` must be 2 (mcontrol) or 6 (mcontrol6). `ctrl_low32`
102    /// holds the common lower-32 control bits (action, match, m, u, execute, …)
103    /// which are position-compatible between the two trigger types.
104    fn build_new_exec_tdata1(trigger_type: u32, ctrl_low32: u32) -> u64;
105    /// Validate a breakpoint address for this XLEN. RV32 restricts to 32 bits.
106    fn validate_bp_address(addr: u64) -> Result<u64, Error>;
107    /// Handle an unknown semihosting command, potentially forwarding to the
108    /// debug sequence.  RV32 forwards to the sequence; RV64 returns it unchanged.
109    fn handle_unknown_semihosting(
110        core: &mut RiscvCore<Self>,
111        details: UnknownCommandDetails,
112    ) -> Result<Option<SemihostingCommand>, Error>
113    where
114        Self: Sized;
115}
116
117// ── Concrete XLEN markers ─────────────────────────────────────────────────────
118
119/// Marker type selecting 32-bit RISC-V operation.
120pub struct Xlen32;
121/// Marker type selecting 64-bit RISC-V operation.
122pub struct Xlen64;
123
124impl sealed::Sealed for Xlen32 {}
125impl sealed::Sealed for Xlen64 {}
126
127impl XlenMode for Xlen32 {
128    fn configure_interface(_interface: &mut RiscvCommunicationInterface) {}
129
130    fn core_type() -> CoreType {
131        CoreType::Riscv
132    }
133
134    fn registers(fp_present: bool) -> &'static CoreRegisters {
135        if fp_present {
136            &RISCV_WITH_FP_CORE_REGISTERS
137        } else {
138            &RISCV_CORE_REGISTERS
139        }
140    }
141
142    fn program_counter() -> &'static CoreRegister {
143        &PC
144    }
145    fn frame_pointer() -> &'static CoreRegister {
146        &FP
147    }
148    fn stack_pointer() -> &'static CoreRegister {
149        &SP
150    }
151    fn return_address() -> &'static CoreRegister {
152        &RA
153    }
154
155    fn csr_to_register_value(v: u64) -> RegisterValue {
156        (v as u32).into()
157    }
158
159    fn register_value_to_csr(v: RegisterValue) -> Result<u64, Error> {
160        let u: u32 = v.try_into()?;
161        Ok(u64::from(u))
162    }
163
164    fn compressed_instruction_set() -> InstructionSet {
165        InstructionSet::RV32C
166    }
167    fn uncompressed_instruction_set() -> InstructionSet {
168        InstructionSet::RV32
169    }
170
171    fn unpack_tdata1(raw: u64) -> (u32, u32) {
172        debug_assert!(
173            raw <= u32::MAX as u64,
174            "RV32 tdata1 read returned value with high bits set"
175        );
176        let ctrl = Mcontrol(raw as u32);
177        (ctrl.type_(), ctrl.0)
178    }
179
180    fn repack_tdata1(_raw: u64, ctrl_low32: u32) -> u64 {
181        u64::from(ctrl_low32)
182    }
183
184    fn build_new_exec_tdata1(trigger_type: u32, ctrl_low32: u32) -> u64 {
185        let mut ctrl = Mcontrol(ctrl_low32);
186        ctrl.set_type(trigger_type);
187        ctrl.set_dmode(true);
188        u64::from(ctrl.0)
189    }
190
191    fn validate_bp_address(addr: u64) -> Result<u64, Error> {
192        valid_32bit_address(addr).map(u64::from)
193    }
194
195    fn handle_unknown_semihosting(
196        core: &mut RiscvCore<Xlen32>,
197        details: UnknownCommandDetails,
198    ) -> Result<Option<SemihostingCommand>, Error> {
199        core.sequence
200            .clone()
201            .on_unknown_semihosting_command(core, details)
202    }
203}
204
205impl XlenMode for Xlen64 {
206    fn configure_interface(interface: &mut RiscvCommunicationInterface) {
207        interface.set_xlen_64(true);
208    }
209
210    fn core_type() -> CoreType {
211        CoreType::Riscv64
212    }
213
214    fn registers(fp_present: bool) -> &'static CoreRegisters {
215        if fp_present {
216            &RISCV64_WITH_FP_CORE_REGISTERS
217        } else {
218            &RISCV64_CORE_REGISTERS
219        }
220    }
221
222    fn program_counter() -> &'static CoreRegister {
223        &PC64
224    }
225    fn frame_pointer() -> &'static CoreRegister {
226        &FP64
227    }
228    fn stack_pointer() -> &'static CoreRegister {
229        &SP64
230    }
231    fn return_address() -> &'static CoreRegister {
232        &RA64
233    }
234
235    fn csr_to_register_value(v: u64) -> RegisterValue {
236        RegisterValue::U64(v)
237    }
238
239    fn register_value_to_csr(v: RegisterValue) -> Result<u64, Error> {
240        v.try_into()
241    }
242
243    fn compressed_instruction_set() -> InstructionSet {
244        InstructionSet::RV64C
245    }
246    fn uncompressed_instruction_set() -> InstructionSet {
247        InstructionSet::RV64
248    }
249
250    fn unpack_tdata1(raw: u64) -> (u32, u32) {
251        let (trigger_type, ctrl) = unpack_mcontrol64(raw);
252        (trigger_type, ctrl.0)
253    }
254
255    fn repack_tdata1(raw: u64, ctrl_low32: u32) -> u64 {
256        repack_mcontrol64(raw, Mcontrol(ctrl_low32))
257    }
258
259    fn build_new_exec_tdata1(trigger_type: u32, ctrl_low32: u32) -> u64 {
260        (u64::from(trigger_type) << 60) | (1u64 << 59) | u64::from(ctrl_low32)
261    }
262
263    fn validate_bp_address(addr: u64) -> Result<u64, Error> {
264        Ok(addr)
265    }
266
267    fn handle_unknown_semihosting(
268        _core: &mut RiscvCore<Xlen64>,
269        details: UnknownCommandDetails,
270    ) -> Result<Option<SemihostingCommand>, Error> {
271        Ok(Some(SemihostingCommand::Unknown(details)))
272    }
273}
274
275// ── Generic core struct ───────────────────────────────────────────────────────
276
277/// An interface to operate a RISC-V core, parameterised by its word width.
278///
279/// Use the type aliases [`Riscv32`] and [`Riscv64`] instead of naming this
280/// type directly.
281pub struct RiscvCore<'state, X: XlenMode> {
282    interface: RiscvCommunicationInterface<'state>,
283    state: &'state mut RiscvCoreState,
284    sequence: Arc<dyn RiscvDebugSequence>,
285    _xlen: PhantomData<X>,
286}
287
288/// An interface to operate a 32-bit RISC-V (RV32) core.
289pub type Riscv32<'state> = RiscvCore<'state, Xlen32>;
290/// An interface to operate a 64-bit RISC-V (RV64) core.
291pub type Riscv64<'state> = RiscvCore<'state, Xlen64>;
292
293// ── Constructors (XLEN-specific) ──────────────────────────────────────────────
294
295impl<'state> RiscvCore<'state, Xlen32> {
296    /// Create a new RV32 RISC-V interface for a particular hart.
297    pub fn new(
298        interface: RiscvCommunicationInterface<'state>,
299        state: &'state mut RiscvCoreState,
300        sequence: Arc<dyn RiscvDebugSequence>,
301    ) -> Result<Self, RiscvError> {
302        Self::new_inner(interface, state, sequence)
303    }
304}
305
306impl<'state> RiscvCore<'state, Xlen64> {
307    /// Create a new RV64 RISC-V interface for a particular hart.
308    pub fn new(
309        interface: RiscvCommunicationInterface<'state>,
310        state: &'state mut RiscvCoreState,
311        sequence: Arc<dyn RiscvDebugSequence>,
312    ) -> Result<Self, RiscvError> {
313        Self::new_inner(interface, state, sequence)
314    }
315}
316
317impl<'state, X: XlenMode> RiscvCore<'state, X> {
318    fn new_inner(
319        mut interface: RiscvCommunicationInterface<'state>,
320        state: &'state mut RiscvCoreState,
321        sequence: Arc<dyn RiscvDebugSequence>,
322    ) -> Result<Self, RiscvError> {
323        X::configure_interface(&mut interface);
324
325        if !state.misa_read {
326            // Determine FPU presence from MISA extensions (F, D, or Q)
327            let misa_val = interface
328                .read_csr(Misa::get_mmio_address() as u16)
329                .unwrap_or(0);
330            let isa_extensions = (misa_val & 0x3ff_ffff) as u32;
331            let fp_mask = (1 << 3) | (1 << 5) | (1 << 16);
332            state.fp_present = isa_extensions & fp_mask != 0;
333            state.misa_read = true;
334        }
335
336        Ok(Self {
337            interface,
338            state,
339            sequence,
340            _xlen: PhantomData,
341        })
342    }
343
344    // ── Private helpers ───────────────────────────────────────────────────────
345
346    fn resume_core(&mut self) -> Result<(), Error> {
347        self.state.semihosting_command = None;
348        self.interface.resume_core()?;
349        Ok(())
350    }
351
352    /// Check if the current breakpoint is a semihosting call.
353    ///
354    /// The Riscv Semihosting Specification, specifies the following sequence of instructions,
355    /// to trigger a semihosting call:
356    /// <https://github.com/riscv-software-src/riscv-semihosting/blob/main/riscv-semihosting-spec.adoc>
357    fn check_for_semihosting(&mut self) -> Result<Option<SemihostingCommand>, Error> {
358        const TRAP_INSTRUCTIONS: [u32; 3] = [
359            0x01f01013, // slli x0, x0, 0x1f (Entry NOP)
360            0x00100073, // ebreak (Break to debugger)
361            0x40705013, // srai x0, x0, 7 (NOP encoding the semihosting call number 7)
362        ];
363
364        // We only want to decode the semihosting command once, since answering
365        // it might change some of the registers.
366        if let Some(command) = self.state.semihosting_command {
367            return Ok(Some(command));
368        }
369
370        let pc: u64 = self.interface.read_csr(X::program_counter().id.0)?;
371
372        let command = if pc < 4 {
373            None
374        } else {
375            // Read the actual instructions, starting at the instruction before the ebreak (PC-4)
376            let mut actual_instructions = [0u32; 3];
377            self.read_32(pc - 4, &mut actual_instructions)?;
378
379            tracing::debug!(
380                "Semihosting check pc={pc:#x} instructions={0:#08x} {1:#08x} {2:#08x}",
381                actual_instructions[0],
382                actual_instructions[1],
383                actual_instructions[2]
384            );
385
386            if TRAP_INSTRUCTIONS == actual_instructions {
387                let syscall = decode_semihosting_syscall(self)?;
388                if let SemihostingCommand::Unknown(details) = syscall {
389                    X::handle_unknown_semihosting(self, details)?
390                } else {
391                    Some(syscall)
392                }
393            } else {
394                None
395            }
396        };
397        self.state.semihosting_command = command;
398        Ok(command)
399    }
400
401    fn determine_number_of_hardware_breakpoints(&mut self) -> Result<u32, RiscvError> {
402        tracing::debug!("Determining number of HW breakpoints supported");
403
404        const TSELECT: u16 = 0x7a0;
405        const TDATA1: u16 = 0x7a1;
406        const TINFO: u16 = 0x7a4;
407
408        let mut tselect_index: u64 = 0;
409
410        // These steps follow the debug specification 0.13, section 5.1 Enumeration
411        loop {
412            tracing::debug!("Trying tselect={}", tselect_index);
413            if let Err(e) = self.interface.write_csr(TSELECT, tselect_index) {
414                match e {
415                    RiscvError::AbstractCommand(AbstractCommandErrorKind::Exception) => break,
416                    other_error => return Err(other_error),
417                }
418            }
419
420            let readback = self.interface.read_csr(TSELECT)?;
421            if readback != tselect_index {
422                break;
423            }
424
425            match self.interface.read_csr(TINFO) {
426                Ok(tinfo_val) => {
427                    if tinfo_val & 0xffff == 1 {
428                        // Trigger doesn't exist, break the loop
429                        break;
430                    } else {
431                        tracing::info!(
432                            "Discovered trigger with index {} and type {}",
433                            tselect_index,
434                            tinfo_val & 0xffff
435                        );
436                    }
437                }
438                // An exception means we have to read tdata1 to discover the type
439                Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::Exception)) => {
440                    let (trigger_type, _) = X::unpack_tdata1(self.interface.read_csr(TDATA1)?);
441                    if trigger_type == 0 {
442                        break;
443                    }
444                    tracing::info!(
445                        "Discovered trigger with index {} and type {}",
446                        tselect_index,
447                        trigger_type,
448                    );
449                }
450                Err(other) => return Err(other),
451            }
452
453            tselect_index += 1;
454        }
455
456        tracing::debug!("Target supports {} breakpoints.", tselect_index);
457        Ok(tselect_index as u32)
458    }
459
460    fn on_halted(&mut self) -> Result<(), Error> {
461        let status = self.status()?;
462        tracing::debug!("Core halted: {:#?}", status);
463        if status.is_halted() {
464            self.sequence.on_halt(&mut self.interface)?;
465        }
466        Ok(())
467    }
468}
469
470// ── CoreInterface implementation ──────────────────────────────────────────────
471
472impl<X: XlenMode> CoreInterface for RiscvCore<'_, X> {
473    fn wait_for_core_halted(&mut self, timeout: Duration) -> Result<(), Error> {
474        self.interface.wait_for_core_halted(timeout)?;
475        self.on_halted()?;
476        self.state.pc_written = false;
477        Ok(())
478    }
479
480    fn core_halted(&mut self) -> Result<bool, Error> {
481        Ok(self.interface.core_halted()?)
482    }
483
484    fn status(&mut self) -> Result<CoreStatus, Error> {
485        // TODO: We should use hartsum to determine if any hart is halted
486        //       quickly
487        let status: Dmstatus = self.interface.read_dm_register()?;
488
489        if status.allhalted() {
490            // determine reason for halt
491            let dcsr = Dcsr(self.interface.read_csr(0x7b0)? as u32);
492
493            let reason = match dcsr.cause() {
494                // An ebreak instruction was hit
495                1 => {
496                    // The chip initiated this halt, therefore we need to
497                    // update pc_written state
498                    self.state.pc_written = false;
499                    if let Some(cmd) = self.check_for_semihosting()? {
500                        HaltReason::Breakpoint(BreakpointCause::Semihosting(cmd))
501                    } else {
502                        HaltReason::Breakpoint(BreakpointCause::Software)
503                    }
504                    // TODO: Add testcase to probe-rs-debugger-test to validate
505                    //       semihosting exit/abort work and unknown semihosting
506                    //       operations are skipped
507                }
508                // Trigger module caused halt
509                2 => HaltReason::Breakpoint(BreakpointCause::Hardware),
510                // Debugger requested a halt
511                3 => HaltReason::Request,
512                // Core halted after single step
513                4 => HaltReason::Step,
514                // Core halted directly after reset
515                5 => HaltReason::Exception,
516                // Reserved for future use in specification
517                _ => HaltReason::Unknown,
518            };
519
520            Ok(CoreStatus::Halted(reason))
521        } else if status.allrunning() {
522            Ok(CoreStatus::Running)
523        } else {
524            Err(Error::Other(
525                "Some cores are running while some are halted, this should not happen.".to_string(),
526            ))
527        }
528    }
529
530    fn halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error> {
531        self.interface.halt(timeout)?;
532        self.on_halted()?;
533        Ok(self.interface.core_info()?)
534    }
535
536    fn run(&mut self) -> Result<(), Error> {
537        // Before we run, we always perform a single instruction step, to
538        // account for possible breakpoints that might get us stuck on the
539        // current instruction.
540        if !self.state.pc_written {
541            self.step()?;
542        }
543        // resume the core.
544        self.resume_core()?;
545        Ok(())
546    }
547
548    fn reset(&mut self) -> Result<(), Error> {
549        self.reset_and_halt(Duration::from_secs(1))?;
550        self.resume_core()?;
551        Ok(())
552    }
553
554    fn reset_and_halt(&mut self, timeout: Duration) -> Result<CoreInformation, Error> {
555        self.sequence
556            .reset_system_and_halt(&mut self.interface, timeout)?;
557        // Chip reset clears hardware breakpoint state
558        self.state.hw_breakpoints_enabled = false;
559        self.on_halted()?;
560        let pc = self.interface.read_csr(0x7b1)?;
561        Ok(CoreInformation { pc })
562    }
563
564    fn step(&mut self) -> Result<CoreInformation, Error> {
565        let halt_reason = self.status()?;
566        if matches!(
567            halt_reason,
568            CoreStatus::Halted(HaltReason::Breakpoint(
569                BreakpointCause::Software | BreakpointCause::Semihosting(_)
570            ))
571        ) {
572            // If we are halted on a software breakpoint, we can skip the
573            // single step and manually advance the dpc.
574            let mut debug_pc = self.read_core_reg(RegisterId(0x7b1))?;
575            // Advance the dpc by the size of the EBREAK (ebreak or c.ebreak) instruction.
576            if self.instruction_set()? == X::compressed_instruction_set() {
577                // We may have been halted by either an EBREAK or a C.EBREAK instruction.
578                // We need to read back the instruction to determine how many bytes to skip.
579                let instruction = self.read_word_32(debug_pc.try_into().unwrap())?;
580                if instruction & 0x3 != 0x3 {
581                    // Compressed instruction.
582                    debug_pc.increment_address(2)?;
583                } else {
584                    debug_pc.increment_address(4)?;
585                }
586            } else {
587                debug_pc.increment_address(4)?;
588            }
589            self.write_core_reg(RegisterId(0x7b1), debug_pc)?;
590            return Ok(CoreInformation {
591                pc: debug_pc.try_into()?,
592            });
593        } else if matches!(
594            halt_reason,
595            CoreStatus::Halted(HaltReason::Breakpoint(BreakpointCause::Hardware))
596        ) {
597            // If we are halted on a hardware breakpoint.
598            self.enable_breakpoints(false)?;
599        }
600
601        // Set it up, so that the next `self.run()` will only do a single step
602        let mut dcsr = Dcsr(self.interface.read_csr(0x7b0)? as u32);
603        dcsr.set_step(true);
604        // Disable any interrupts during single step.
605        dcsr.set_stepie(false);
606        dcsr.set_stopcount(true);
607        self.interface.write_csr(0x7b0, u64::from(dcsr.0))?;
608
609        // Now we can resume the core for the single step.
610        self.resume_core()?;
611        let step_result = self.wait_for_core_halted(SINGLE_STEP_TIMEOUT);
612
613        // On timeout, force a halt so the restore below can run; otherwise
614        // `dcsr.step` stays set and hardware breakpoints stay disabled.
615        if step_result.is_err() {
616            tracing::warn!("Single step did not halt within {SINGLE_STEP_TIMEOUT:?}; forcing halt");
617            if let Err(e) = self.interface.halt(Duration::from_millis(100)) {
618                tracing::warn!("Could not force halt after failed single step: {:?}", e);
619            }
620        }
621
622        // Restore step configuration unconditionally, even after a failed step.
623        let mut dcsr = Dcsr(self.interface.read_csr(0x7b0)? as u32);
624        dcsr.set_step(false);
625        //Re-enable interrupts for single step.
626        dcsr.set_stepie(true);
627        dcsr.set_stopcount(false);
628        self.interface.write_csr(0x7b0, u64::from(dcsr.0))?;
629
630        // Re-enable breakpoints before we continue.
631        if matches!(
632            halt_reason,
633            CoreStatus::Halted(HaltReason::Breakpoint(BreakpointCause::Hardware))
634        ) {
635            // If we are halted on a hardware breakpoint.
636            self.enable_breakpoints(true)?;
637        }
638
639        step_result?;
640
641        let pc = self.read_core_reg(RegisterId(0x7b1))?;
642
643        self.on_halted()?;
644        self.state.pc_written = false;
645        Ok(CoreInformation { pc: pc.try_into()? })
646    }
647
648    fn read_core_reg(&mut self, address: RegisterId) -> Result<RegisterValue, Error> {
649        self.interface
650            .read_csr(address.0)
651            .map(X::csr_to_register_value)
652            .map_err(Error::from)
653    }
654
655    fn write_core_reg(&mut self, address: RegisterId, value: RegisterValue) -> Result<(), Error> {
656        let v = X::register_value_to_csr(value)?;
657        if address == X::program_counter().id {
658            self.state.pc_written = true;
659        }
660        self.interface.write_csr(address.0, v).map_err(Error::from)
661    }
662
663    fn available_breakpoint_units(&mut self) -> Result<u32, Error> {
664        match self.state.hw_breakpoints {
665            Some(bp) => Ok(bp),
666            None => {
667                let bp = self.determine_number_of_hardware_breakpoints()?;
668                self.state.hw_breakpoints = Some(bp);
669                Ok(bp)
670            }
671        }
672    }
673
674    /// See docs on the [`CoreInterface::hw_breakpoints`] trait.
675    ///
676    /// NOTE: For riscv, this assumes that only execution breakpoints are used.
677    fn hw_breakpoints(&mut self) -> Result<Vec<Option<u64>>, Error> {
678        // This can be called w/o halting the core via Session::new -
679        // temporarily halt if not halted.
680        let was_running = !self.core_halted()?;
681        if was_running {
682            self.halt(Duration::from_millis(100))?;
683        }
684
685        const TSELECT: u16 = 0x7a0;
686        const TDATA1: u16 = 0x7a1;
687        const TDATA2: u16 = 0x7a2;
688
689        let mut breakpoints = vec![];
690        let num_hw_breakpoints = self.available_breakpoint_units()? as usize;
691        for bp_unit_index in 0..num_hw_breakpoints {
692            // Select the trigger.
693            self.interface.write_csr(TSELECT, bp_unit_index as u64)?;
694            // Read the trigger "configuration" data.
695            let tdata_raw = self.interface.read_csr(TDATA1)?;
696            let (trigger_type, ctrl_low32) = X::unpack_tdata1(tdata_raw);
697            let tdata_value = Mcontrol(ctrl_low32);
698
699            tracing::debug!(
700                "Breakpoint {}: type={}, {:?}",
701                bp_unit_index,
702                trigger_type,
703                tdata_value
704            );
705
706            // The trigger must be active in at least a single mode
707            let trigger_any_mode_active = tdata_value.m() || tdata_value.s() || tdata_value.u();
708            let trigger_any_action_enabled =
709                tdata_value.execute() || tdata_value.store() || tdata_value.load();
710
711            // Only return if the trigger is for an execution debug action in all modes.
712            // Accept both type 2 (mcontrol) and type 6 (mcontrol6, spec 1.0).
713            if (trigger_type == 2 || trigger_type == 6)
714                && tdata_value.action() == 1
715                && tdata_value.match_() == 0
716                && trigger_any_mode_active
717                && trigger_any_action_enabled
718            {
719                let breakpoint = self.interface.read_csr(TDATA2)?;
720                breakpoints.push(Some(breakpoint));
721            } else {
722                breakpoints.push(None);
723            }
724        }
725
726        if was_running {
727            self.resume_core()?;
728        }
729
730        Ok(breakpoints)
731    }
732
733    fn enable_breakpoints(&mut self, state: bool) -> Result<(), Error> {
734        const TSELECT: u16 = 0x7a0;
735        const TDATA1: u16 = 0x7a1;
736
737        // Loop through all triggers, and enable/disable them.
738        for bp_unit_index in 0..self.available_breakpoint_units()? as usize {
739            // Select the trigger.
740            self.interface.write_csr(TSELECT, bp_unit_index as u64)?;
741            // Read the trigger "configuration" data.
742            let tdata_raw = self.interface.read_csr(TDATA1)?;
743            let (trigger_type, ctrl_low32) = X::unpack_tdata1(tdata_raw);
744            let mut tdata_value = Mcontrol(ctrl_low32);
745
746            // Only modify the trigger if it is for an execution debug action
747            // in all modes (probe-rs enabled it) or no modes (we previously
748            // disabled it). Accept both type 2 (mcontrol) and type 6 (mcontrol6).
749            if (trigger_type == 2 || trigger_type == 6)
750                && tdata_value.action() == 1
751                && tdata_value.match_() == 0
752                && tdata_value.execute()
753                && ((tdata_value.m() && tdata_value.u()) || (!tdata_value.m() && !tdata_value.u()))
754            {
755                tracing::debug!(
756                    "Will modify breakpoint enabled={} for {}: {:?}",
757                    state,
758                    bp_unit_index,
759                    tdata_value
760                );
761                tdata_value.set_m(state);
762                tdata_value.set_u(state);
763                self.interface
764                    .write_csr(TDATA1, X::repack_tdata1(tdata_raw, tdata_value.0))?;
765            }
766        }
767
768        self.state.hw_breakpoints_enabled = state;
769        Ok(())
770    }
771
772    fn set_hw_breakpoint(&mut self, bp_unit_index: usize, addr: u64) -> Result<(), Error> {
773        let addr = X::validate_bp_address(addr)?;
774
775        const TSELECT: u16 = 0x7a0;
776        const TDATA1: u16 = 0x7a1;
777        const TDATA2: u16 = 0x7a2;
778
779        tracing::info!("Setting breakpoint {} at {:#x}", bp_unit_index, addr);
780
781        // select requested trigger
782        self.interface.write_csr(TSELECT, bp_unit_index as u64)?;
783
784        // Verify the trigger is a supported type for execution breakpoints:
785        // type 2 = mcontrol (spec 0.13), type 6 = mcontrol6 (spec 1.0).
786        let (trigger_type, _) = X::unpack_tdata1(self.interface.read_csr(TDATA1)?);
787        if trigger_type != 2 && trigger_type != 6 {
788            return Err(RiscvError::UnexpectedTriggerType(trigger_type).into());
789        }
790
791        // Build the control word. Bits 0–15 are position-compatible between
792        // mcontrol and mcontrol6, so a single Mcontrol value covers both.
793        let mut instruction_breakpoint = Mcontrol(0);
794        // Enter debug mode on trigger fire
795        instruction_breakpoint.set_action(1);
796        // Exact address match
797        instruction_breakpoint.set_match(0);
798        instruction_breakpoint.set_m(true);
799        instruction_breakpoint.set_u(true);
800        // Trigger on instruction fetch
801        instruction_breakpoint.set_execute(true);
802        // Match on address, not data value
803        instruction_breakpoint.set_select(false);
804
805        let tdata1_val = X::build_new_exec_tdata1(trigger_type, instruction_breakpoint.0);
806
807        self.interface.write_csr(TDATA1, 0)?;
808        self.interface.write_csr(TDATA2, addr)?;
809        self.interface.write_csr(TDATA1, tdata1_val)?;
810
811        Ok(())
812    }
813
814    fn clear_hw_breakpoint(&mut self, unit_index: usize) -> Result<(), Error> {
815        // This can be called w/o halting the core via Session::new -
816        // temporarily halt if not halted.
817        tracing::info!("Clearing breakpoint {}", unit_index);
818
819        let was_running = !self.core_halted()?;
820        if was_running {
821            self.halt(Duration::from_millis(100))?;
822        }
823
824        const TSELECT: u16 = 0x7a0;
825        const TDATA1: u16 = 0x7a1;
826        const TDATA2: u16 = 0x7a2;
827
828        self.interface.write_csr(TSELECT, unit_index as u64)?;
829        self.interface.write_csr(TDATA1, 0)?;
830        self.interface.write_csr(TDATA2, 0)?;
831
832        if was_running {
833            self.resume_core()?;
834        }
835
836        Ok(())
837    }
838
839    fn registers(&self) -> &'static CoreRegisters {
840        X::registers(self.state.fp_present)
841    }
842
843    fn program_counter(&self) -> &'static CoreRegister {
844        X::program_counter()
845    }
846
847    fn frame_pointer(&self) -> &'static CoreRegister {
848        X::frame_pointer()
849    }
850
851    fn stack_pointer(&self) -> &'static CoreRegister {
852        X::stack_pointer()
853    }
854
855    fn return_address(&self) -> &'static CoreRegister {
856        X::return_address()
857    }
858
859    fn hw_breakpoints_enabled(&self) -> bool {
860        self.state.hw_breakpoints_enabled
861    }
862
863    fn architecture(&self) -> Architecture {
864        Architecture::Riscv
865    }
866
867    fn core_type(&self) -> CoreType {
868        X::core_type()
869    }
870
871    fn is_64_bit(&self) -> bool {
872        matches!(X::core_type(), CoreType::Riscv64)
873    }
874
875    fn instruction_set(&mut self) -> Result<InstructionSet, Error> {
876        // Check if the Bit at position 2 (signifies letter C, for compressed) is set.
877        let misa_val = self.interface.read_csr(0x301)?;
878        if misa_val & (1 << 2) != 0 {
879            Ok(X::compressed_instruction_set())
880        } else {
881            Ok(X::uncompressed_instruction_set())
882        }
883    }
884
885    fn floating_point_register_count(&mut self) -> Result<usize, Error> {
886        Ok(self
887            .registers()
888            .all_registers()
889            .filter(|r| r.register_has_role(crate::RegisterRole::FloatingPoint))
890            .count())
891    }
892
893    fn fpu_support(&mut self) -> Result<bool, Error> {
894        Ok(self.state.fp_present)
895    }
896
897    fn reset_catch_set(&mut self) -> Result<(), Error> {
898        self.sequence.reset_catch_set(&mut self.interface)?;
899        Ok(())
900    }
901
902    fn reset_catch_clear(&mut self) -> Result<(), Error> {
903        self.sequence.reset_catch_clear(&mut self.interface)?;
904        Ok(())
905    }
906
907    fn debug_core_stop(&mut self) -> Result<(), Error> {
908        self.interface.disable_debug_module()?;
909        Ok(())
910    }
911}
912
913impl<X: XlenMode> CoreMemoryInterface for RiscvCore<'_, X> {
914    type ErrorType = Error;
915
916    fn memory(&self) -> &dyn MemoryInterface<Self::ErrorType> {
917        &self.interface
918    }
919
920    fn memory_mut(&mut self) -> &mut dyn MemoryInterface<Self::ErrorType> {
921        &mut self.interface
922    }
923}
924
925#[derive(Debug)]
926/// Flags used to control the [`SpecificCoreState`](crate::core::SpecificCoreState) for RiscV architecture
927pub struct RiscvCoreState {
928    /// A flag to remember whether we want to use hw_breakpoints during stepping of the core.
929    hw_breakpoints_enabled: bool,
930
931    hw_breakpoints: Option<u32>,
932
933    /// Whether the PC was written since we last halted. Used to avoid incrementing the PC on
934    /// resume.
935    pc_written: bool,
936
937    /// The semihosting command that was decoded at the current program counter
938    semihosting_command: Option<SemihostingCommand>,
939
940    /// Whether the core has FPU support (F, D, or Q extensions present)
941    fp_present: bool,
942
943    /// Whether the MISA CSR has been read.
944    misa_read: bool,
945}
946
947impl RiscvCoreState {
948    pub(crate) fn new() -> Self {
949        Self {
950            hw_breakpoints_enabled: false,
951            hw_breakpoints: None,
952            pc_written: false,
953            semihosting_command: None,
954            fp_present: false,
955            misa_read: false,
956        }
957    }
958}
959
960memory_mapped_bitfield_register! {
961    /// `dmcontrol` register, located at address 0x10
962    pub struct Dmcontrol(u32);
963    0x10, "dmcontrol",
964    impl From;
965
966    /// Requests the currently selected harts to halt.
967    pub _, set_haltreq: 31;
968
969    /// Requests the currently selected harts to resume.
970    pub _, set_resumereq: 30;
971
972    /// Requests the currently selected harts to reset. Optional.
973    pub hartreset, set_hartreset: 29;
974
975    /// Writing 1 clears the `havereset` flag of selected harts.
976    pub _, set_ackhavereset: 28;
977
978    /// Clears the `unavail` state for any selected harts that are currently
979    /// available. When `stickyunavail` is 1 in `dmstatus`, a hart's `unavail`
980    /// bit will not clear on its own; this bit must be written 1 to clear it.
981    /// Optional (spec 1.0).
982    pub _, set_ackunavail: 27;
983
984    /// Selects the definition of currently selected harts. If 1, multiple harts may be selected.
985    pub hasel, set_hasel: 26;
986
987    /// The lower 10 bits of the currently selected harts.
988    pub hartsello, set_hartsello: 25, 16;
989
990    /// The upper 10 bits of the currently selected harts.
991    pub hartselhi, set_hartselhi: 15, 6;
992
993    /// Writes the halt-on-reset request bit for all currently selected hart. Optional.
994    pub _, set_resethaltreq: 3;
995
996    /// Clears the halt-on-reset request bit for all currently selected harts. Optional.
997    pub _, set_clrresethaltreq: 2;
998
999    /// Sets the `keepalive` hint for all currently selected harts. When set,
1000    /// hardware should attempt to keep the hart powered and available for the
1001    /// debugger (e.g. prevent entry into a low-power state). Optional (spec 1.0).
1002    pub _, set_setkeepalive: 5;
1003
1004    /// Clears the `keepalive` hint for all currently selected harts. Optional
1005    /// (spec 1.0).
1006    pub _, set_clrkeepalive: 4;
1007
1008    /// This bit controls the reset signal from the DM to the rest of the system.
1009    pub ndmreset, set_ndmreset: 1;
1010
1011    /// Reset signal for the debug module.
1012    pub dmactive, set_dmactive: 0;
1013}
1014
1015impl Dmcontrol {
1016    /// Currently selected harts
1017    ///
1018    /// Combination of the `hartselhi` and `hartsello` registers.
1019    pub fn hartsel(&self) -> u32 {
1020        (self.hartselhi() << 10) | self.hartsello()
1021    }
1022
1023    /// Set the currently selected harts
1024    ///
1025    /// This sets the `hartselhi` and `hartsello` registers.
1026    /// This is a 20 bit register, larger values will be truncated.
1027    pub fn set_hartsel(&mut self, value: u32) {
1028        self.set_hartsello(value & 0x3ff);
1029        self.set_hartselhi((value >> 10) & 0x3ff);
1030    }
1031}
1032
1033memory_mapped_bitfield_register! {
1034    /// Readonly `dmstatus` register.
1035    ///
1036    /// Located at address 0x11
1037    pub struct Dmstatus(u32);
1038    0x11, "dmstatus",
1039    impl From;
1040
1041    /// 1 when the Debug Module is in the process of performing an ndmreset.
1042    /// Reads as 1 whenever `ndmreset` in `dmcontrol` is 1. Optional; hardwired
1043    /// to 0 on implementations that do not support this field (spec 1.0).
1044    pub ndmresetpending, _: 24;
1045
1046    /// When 1, the `allunavail` and `anyunavail` fields become sticky: once set
1047    /// they remain set until explicitly cleared via `ackunavail` in `dmcontrol`.
1048    /// Optional; hardwired to 0 on implementations that do not support this
1049    /// field (spec 1.0).
1050    pub stickyunavail, _: 23;
1051
1052    /// If 1, then there is an implicit ebreak instruction
1053    /// at the non-existent word immediately after the
1054    /// Program Buffer. This saves the debugger from
1055    /// having to write the ebreak itself, and allows the
1056    /// Program Buffer to be one word smaller.
1057    /// This must be 1 when progbufsize is 1.
1058    pub impebreak, _: 22;
1059
1060    /// This field is 1 when all currently selected harts
1061    /// have been reset and reset has not been acknowledged for any of them.
1062    pub allhavereset, _: 19;
1063
1064    /// This field is 1 when at least one currently selected hart
1065    /// has been reset and reset has not been acknowledged for any of them.
1066    pub anyhavereset, _: 18;
1067
1068    /// This field is 1 when all currently selected harts
1069    /// have acknowledged their last resume request.
1070    pub allresumeack, _: 17;
1071
1072    /// This field is 1 when any currently selected hart
1073    /// has acknowledged its last resume request.
1074    pub anyresumeack, _: 16;
1075
1076    /// This field is 1 when all currently selected harts do
1077    /// not exist in this platform.
1078    pub allnonexistent, _: 15;
1079
1080    /// This field is 1 when any currently selected hart
1081    /// does not exist in this platform.
1082    pub anynonexistent, _: 14;
1083
1084    /// This field is 1 when all currently selected harts are unavailable.
1085    pub allunavail, _: 13;
1086
1087    /// This field is 1 when any currently selected hart is unavailable.
1088    pub anyunavail, _: 12;
1089
1090    /// This field is 1 when all currently selected harts are running.
1091    pub allrunning, _: 11;
1092
1093    /// This field is 1 when any currently selected hart is running.
1094    pub anyrunning, _: 10;
1095
1096    /// This field is 1 when all currently selected harts are halted.
1097    pub allhalted, _: 9;
1098
1099    /// This field is 1 when any currently selected hart is halted.
1100    pub anyhalted, _: 8;
1101
1102    /// If 0, authentication is required before using the DM.
1103    pub authenticated, _: 7;
1104
1105    /// If 0, the authentication module is ready to process the next read/write to `authdata`.
1106    pub authbusy, _: 6;
1107
1108    /// 1 if this Debug Module supports halt-on-reset functionality controllable by the
1109    /// `setresethaltreq` and `clrresethaltreq` bits.
1110    pub hasresethaltreq, _: 5;
1111
1112    /// 1 if `confstrptr0`–`confstrptr3` hold the address of the configuration string.
1113    pub confstrptrvalid, _: 4;
1114
1115    /// Version of the debug module.
1116    pub version, _: 3, 0;
1117}
1118
1119bitfield! {
1120    struct Dcsr(u32);
1121    impl Debug;
1122
1123    /// Debug module version. Value 4 indicates spec 1.0; value 3 indicates 0.13.
1124    xdebugver, _: 31, 28;
1125    /// 1 causes ebreak in VS-mode to be redirected to Debug Mode (spec 1.0).
1126    ebreakvs, set_ebreakvs: 17;
1127    /// 1 causes ebreak in VU-mode to be redirected to Debug Mode (spec 1.0).
1128    ebreakvu, set_ebreakvu: 16;
1129    ebreakm, set_ebreakm: 15;
1130    ebreaks, set_ebreaks: 13;
1131    ebreaku, set_ebreaku: 12;
1132    stepie, set_stepie: 11;
1133    stopcount, set_stopcount: 10;
1134    stoptime, set_stoptime: 9;
1135    cause, set_cause: 8, 6;
1136    /// Virtualization mode (V) the hart was in when Debug Mode was entered.
1137    /// 0 on harts that do not support the hypervisor extension (spec 1.0).
1138    v, set_v: 5;
1139    mprven, set_mprven: 4;
1140    nmip, _: 3;
1141    step, set_step: 2;
1142    prv, set_prv: 1,0;
1143}
1144
1145memory_mapped_bitfield_register! {
1146    /// Abstract Control and Status (see 3.12.6)
1147    pub struct Abstractcs(u32);
1148    0x16, "abstractcs",
1149    impl From;
1150
1151    progbufsize, _: 28, 24;
1152    busy, _: 12;
1153    /// When 1, abstract commands execute with the hart's current privilege level
1154    /// and `mstatus.MPRV` setting instead of being forced to machine mode.
1155    /// Optional; hardwired to 0 if not implemented (spec 1.0).
1156    relaxedpriv, set_relaxedpriv: 11;
1157    cmderr, set_cmderr: 10, 8;
1158    datacount, _: 3, 0;
1159}
1160
1161memory_mapped_bitfield_register! {
1162    /// Hart Info (see 3.12.3)
1163    pub struct Hartinfo(u32);
1164    0x12, "hartinfo",
1165    impl From;
1166
1167    nscratch, _: 23, 20;
1168    dataaccess, _: 16;
1169    datasize, _: 15, 12;
1170    dataaddr, _: 11, 0;
1171}
1172
1173memory_mapped_bitfield_register! { pub struct Data0(u32); 0x04, "data0", impl From; }
1174memory_mapped_bitfield_register! { pub struct Data1(u32); 0x05, "data1", impl From; }
1175memory_mapped_bitfield_register! { pub struct Data2(u32); 0x06, "data2", impl From; }
1176memory_mapped_bitfield_register! { pub struct Data3(u32); 0x07, "data3", impl From; }
1177memory_mapped_bitfield_register! { pub struct Data4(u32); 0x08, "data4", impl From; }
1178memory_mapped_bitfield_register! { pub struct Data5(u32); 0x09, "data5", impl From; }
1179memory_mapped_bitfield_register! { pub struct Data6(u32); 0x0A, "data6", impl From; }
1180memory_mapped_bitfield_register! { pub struct Data7(u32); 0x0B, "data7", impl From; }
1181memory_mapped_bitfield_register! { pub struct Data8(u32); 0x0C, "data8", impl From; }
1182memory_mapped_bitfield_register! { pub struct Data9(u32); 0x0D, "data9", impl From; }
1183memory_mapped_bitfield_register! { pub struct Data10(u32); 0x0E, "data10", impl From; }
1184memory_mapped_bitfield_register! { pub struct Data11(u32); 0x0f, "data11", impl From; }
1185
1186memory_mapped_bitfield_register! { struct Command(u32); 0x17, "command", impl From; }
1187
1188memory_mapped_bitfield_register! { pub struct Progbuf0(u32); 0x20, "progbuf0", impl From; }
1189memory_mapped_bitfield_register! { pub struct Progbuf1(u32); 0x21, "progbuf1", impl From; }
1190memory_mapped_bitfield_register! { pub struct Progbuf2(u32); 0x22, "progbuf2", impl From; }
1191memory_mapped_bitfield_register! { pub struct Progbuf3(u32); 0x23, "progbuf3", impl From; }
1192memory_mapped_bitfield_register! { pub struct Progbuf4(u32); 0x24, "progbuf4", impl From; }
1193memory_mapped_bitfield_register! { pub struct Progbuf5(u32); 0x25, "progbuf5", impl From; }
1194memory_mapped_bitfield_register! { pub struct Progbuf6(u32); 0x26, "progbuf6", impl From; }
1195memory_mapped_bitfield_register! { pub struct Progbuf7(u32); 0x27, "progbuf7", impl From; }
1196memory_mapped_bitfield_register! { pub struct Progbuf8(u32); 0x28, "progbuf8", impl From; }
1197memory_mapped_bitfield_register! { pub struct Progbuf9(u32); 0x29, "progbuf9", impl From; }
1198memory_mapped_bitfield_register! { pub struct Progbuf10(u32); 0x2A, "progbuf10", impl From; }
1199memory_mapped_bitfield_register! { pub struct Progbuf11(u32); 0x2B, "progbuf11", impl From; }
1200memory_mapped_bitfield_register! { pub struct Progbuf12(u32); 0x2C, "progbuf12", impl From; }
1201memory_mapped_bitfield_register! { pub struct Progbuf13(u32); 0x2D, "progbuf13", impl From; }
1202memory_mapped_bitfield_register! { pub struct Progbuf14(u32); 0x2E, "progbuf14", impl From; }
1203memory_mapped_bitfield_register! { pub struct Progbuf15(u32); 0x2F, "progbuf15", impl From; }
1204
1205bitfield! {
1206    /// Trigger type 2 — legacy address/data match control (mcontrol).
1207    struct Mcontrol(u32);
1208    impl Debug;
1209
1210    type_, set_type: 31, 28;
1211    dmode, set_dmode: 27;
1212    maskmax, _: 26, 21;
1213    hit, set_hit: 20;
1214    select, set_select: 19;
1215    timing, set_timing: 18;
1216    sizelo, set_sizelo: 17, 16;
1217    action, set_action: 15, 12;
1218    chain, set_chain: 11;
1219    match_, set_match: 10, 7;
1220    m, set_m: 6;
1221    s, set_s: 4;
1222    u, set_u: 3;
1223    execute, set_execute: 2;
1224    store, set_store: 1;
1225    load, set_load: 0;
1226}
1227
1228bitfield! {
1229    /// Trigger type 6 — new address/data match control (mcontrol6, spec 1.0).
1230    ///
1231    /// Low bits 0–15 are position-compatible with `Mcontrol`. Differences start
1232    /// at bit 16: a unified 4-bit `size` field replaces the split `sizelo`/`sizehi`
1233    /// of the legacy type, and new `hit0`, `vu`, `vs`, and `hit1` bits are added.
1234    struct Mcontrol6(u32);
1235    impl Debug;
1236
1237    type_, set_type: 31, 28;
1238    dmode, set_dmode: 27;
1239    /// MSB of the 2-bit `{hit1, hit0}` field. Hardware sets this on a trigger
1240    /// fire; the debugger should write 0 to clear after observing it.
1241    hit1, set_hit1: 25;
1242    /// When 1, the trigger is active in VS-mode (hypervisor guest supervisor).
1243    vs, set_vs: 24;
1244    /// When 1, the trigger is active in VU-mode (hypervisor guest user).
1245    vu, set_vu: 23;
1246    /// LSB of the 2-bit `{hit1, hit0}` field.
1247    hit0, set_hit0: 22;
1248    select, set_select: 21;
1249    /// Unified size field (4 bits). Replaces the `sizelo`/`sizehi` split of
1250    /// `mcontrol`. Values match those of `sizelo` from the legacy trigger.
1251    size, set_size: 19, 16;
1252    action, set_action: 15, 12;
1253    chain, set_chain: 11;
1254    match_, set_match: 10, 7;
1255    m, set_m: 6;
1256    s, set_s: 4;
1257    u, set_u: 3;
1258    execute, set_execute: 2;
1259    store, set_store: 1;
1260    load, set_load: 0;
1261}
1262
1263memory_mapped_bitfield_register! {
1264    /// Isa and Extensions (see RISC-V Privileged Spec, 3.1.1)
1265    pub struct Misa(u32);
1266    0x301, "misa",
1267    impl From;
1268
1269    /// Machine XLEN
1270    mxl, _: 31, 30;
1271    /// Standard RISC-V extensions
1272    extensions, _: 25, 0;
1273}