Skip to main content

ab_riscv_interpreter/
lib.rs

1//! Composable and generic RISC-V interpreter.
2//!
3//! This interpreter is designed to work with abstractions from [`ab-riscv-primitives`] crate and is
4//! similarly composable with a powerful macro system and trait abstractions over handling of
5//! memory, syscalls, etc.
6//!
7//! [`ab-riscv-primitives`]: ab_riscv_primitives
8//!
9//! The immediate needs dictate the current set of available instructions and extensions. Consider
10//! contributing if you need something not yet available.
11//!
12//! `ab-riscv-act4-runner` crate in the repository contains a complementary RISC-V Architectural
13//! Certification Tests runner for <https://github.com/riscv-non-isa/riscv-arch-test> that ensures
14//! correct implementation.
15//!
16//! Does not require a standard library (`no_std`) or an allocator, never panics, almost 100% of the
17//! API abstractions are usable in const, including several extensions beyond base ISA.
18//!
19//! ## Supported ISA variants and extensions
20//!
21//! ISA variants:
22//! * RV32I (version 2.1)
23//! * RV32E (version 2.0)
24//! * RV64I (version 2.1)
25//! * RV64E (version 2.0)
26//!
27//! Extensions:
28//! * A (version 2.1)
29//! * M (version 2.0)
30//! * B (version 1.0.0)
31//! * Zaamo (version 1.0.0)
32//! * Zabha (version 1.0.0)
33//! * Zacas (version 1.0.0)
34//! * (experimental) Zalasr (version 1.0.0)
35//! * Zalrsc (version 1.0.0)
36//! * Zawrs (version 1.0.0)
37//! * Zba (version 1.0.0)
38//! * Zbb (version 1.0.0)
39//! * Zbc (version 1.0.0)
40//! * Zbkb (version 1.0.1)
41//! * Zbkc (version 1.0.1)
42//! * Zbkx (version 1.0.1)
43//! * Zbs (version 1.0.0)
44//! * Zca (version 1.0.0)
45//! * Zcb (version 1.0.0)
46//! * (experimental) Zcmp (version 1.0.0)
47//! * Zicond (version 2.0)
48//! * Zicsr (version 2.0)
49//! * Zkn (version 1.0.1)
50//! * Zknd (version 1.0.1)
51//! * Zkne (version 1.0.1)
52//! * Zknh (version 1.0.1)
53//! * Zkr (version 1.0.1)
54//! * Zvbb (version 1.0.0)
55//! * Zvbc (version 1.0.0)
56//! * ZveXx (version 1.0.0), where `X` is anything allowed by the specification like Zve32x or
57//!   Zve64x
58//! * Zvkb (version 1.0.0)
59//! * Zvl*b (version 1.0.0), where `*` is anything allowed by the specification like Zvl128b or
60//!   Zvl512b
61//!
62//! All extensions except experimental pass all relevant RISC-V Architectural Certification Tests
63//! (ACTs) using the ACT4 framework.
64//!
65//! Any permutation of compatible extensions is supported.
66//!
67//! Experimental extensions may not have ACT4 tests yet and are not guaranteed to work correctly.
68//!
69//! ## Design choices
70//!
71//! This crate was designed with a blockchain use case in mind, though it is in no way tied to any
72//! particular blockchain and is completely general purpose. As a result, the implementation is
73//! designed to be precise and non-ambiguous.
74//!
75//! A few key points:
76//! * anything "reserved" in the specification is considered to be illegal
77//! * anything "optional" in the specification is considered to be illegal
78//! * anything "implementation-defined" in the specification is selected to be the most natural and
79//!   deterministic
80//! * type system is used to make the majority of invalid invariants impossible to represent in code
81//!   and/or decode
82//!
83//! Examples:
84//! * `vma`/`vta` are always undisturbed in vector extensions
85//! * Zve64x extension instructions are purposefully restricted to what it is required to be capable
86//!   of, although it would be cheaper to support the fuller feature set only required by V
87//!   extension
88
89#![expect(incomplete_features, reason = "generic_const_*")]
90#![feature(
91    adt_const_params,
92    const_closures,
93    const_cmp,
94    const_convert,
95    const_default,
96    const_destruct,
97    const_index,
98    const_ops,
99    const_option_ops,
100    const_result_trait_fn,
101    const_trait_impl,
102    const_try,
103    generic_const_args,
104    generic_const_items,
105    inherent_associated_types,
106    integer_widen_truncate,
107    macroless_generic_const_args,
108    min_generic_const_args,
109    signed_bigint_helpers,
110    widening_mul
111)]
112#![cfg_attr(test, feature(const_block_items, try_blocks))]
113#![cfg_attr(
114    not(any(
115        all(target_arch = "riscv32", target_feature = "zbkx"),
116        all(target_arch = "riscv64", target_feature = "zbkx")
117    )),
118    feature(portable_simd)
119)]
120#![cfg_attr(
121    any(
122        all(
123            target_arch = "riscv32",
124            any(
125                target_feature = "zbb",
126                target_feature = "zbc",
127                target_feature = "zbkb",
128                target_feature = "zbkx",
129                target_feature = "zknd",
130                target_feature = "zkne",
131                target_feature = "zknh"
132            ),
133            not(miri)
134        ),
135        all(
136            target_arch = "riscv64",
137            any(
138                target_feature = "zbb",
139                target_feature = "zbc",
140                target_feature = "zbkx",
141                target_feature = "zknd",
142                target_feature = "zkne",
143                target_feature = "zknh"
144            ),
145            not(miri)
146        )
147    ),
148    feature(riscv_ext_intrinsics)
149)]
150#![no_std]
151
152pub mod basic;
153pub mod prelude;
154mod private;
155pub mod rv32;
156pub mod rv64;
157pub mod v;
158pub mod zawrs;
159pub mod zicond;
160pub mod zicsr;
161pub mod zkr;
162pub mod zvbb;
163pub mod zvbc;
164
165#[cfg(feature = "alloc")]
166extern crate alloc;
167
168use crate::private::BasicIntSealed;
169use ab_riscv_primitives::prelude::*;
170#[cfg(feature = "alloc")]
171use alloc::boxed::Box;
172use core::fmt;
173use core::marker::Destruct;
174use core::ops::{ControlFlow, Sub};
175
176type RegisterType<I> = <<I as Instruction>::Reg as Register>::Type;
177type Address<I> = RegisterType<I>;
178
179/// A GPR (General Purpose Register) file abstraction
180pub const trait RegisterFile<Reg>
181where
182    Reg: [const] Register,
183{
184    /// Read register value
185    fn read(&self, reg: Reg) -> Reg::Type;
186
187    /// Write register value
188    fn write(&mut self, reg: Reg, value: Reg::Type);
189}
190
191/// Errors for [`VirtualMemory`]
192#[derive(Debug, thiserror::Error)]
193pub enum VirtualMemoryError {
194    /// Out-of-bounds read
195    #[error("Out-of-bounds read at address {address}")]
196    OutOfBoundsRead {
197        /// Address of the out-of-bounds read
198        address: u64,
199    },
200    /// Out-of-bounds write
201    #[error("Out-of-bounds write at address {address}")]
202    OutOfBoundsWrite {
203        /// Address of the out-of-bounds write
204        address: u64,
205    },
206}
207
208/// Basic integer types that can be read and written to/from memory freely
209pub trait BasicInt: Sized + Copy + BasicIntSealed + 'static {}
210
211impl BasicIntSealed for u8 {}
212impl BasicIntSealed for u16 {}
213impl BasicIntSealed for u32 {}
214impl BasicIntSealed for u64 {}
215impl BasicIntSealed for i8 {}
216impl BasicIntSealed for i16 {}
217impl BasicIntSealed for i32 {}
218impl BasicIntSealed for i64 {}
219
220impl BasicInt for u8 {}
221impl BasicInt for u16 {}
222impl BasicInt for u32 {}
223impl BasicInt for u64 {}
224impl BasicInt for i8 {}
225impl BasicInt for i16 {}
226impl BasicInt for i32 {}
227impl BasicInt for i64 {}
228
229/// Virtual memory interface
230pub const trait VirtualMemory {
231    /// Read a value from memory at the specified address
232    fn read<T>(&self, address: u64) -> Result<T, VirtualMemoryError>
233    where
234        T: BasicInt;
235
236    /// Unchecked read a value from memory at the specified address.
237    ///
238    /// # Safety
239    /// The address and value must be in-bounds.
240    unsafe fn read_unchecked<T>(&self, address: u64) -> T
241    where
242        T: BasicInt;
243
244    /// Read a contiguous byte slice from memory
245    fn read_slice(&self, address: u64, len: u32) -> Result<&[u8], VirtualMemoryError>;
246
247    /// Read as many contiguous bytes as possible starting at `address`, up to `len` bytes total.
248    ///
249    /// Can return an empty slice in cases like when the address is out of bounds.
250    fn read_slice_up_to(&self, address: u64, len: u32) -> &[u8];
251
252    /// Write a value to memory at the specified address
253    fn write<T>(&mut self, address: u64, value: T) -> Result<(), VirtualMemoryError>
254    where
255        T: BasicInt;
256
257    /// Write a contiguous byte slice to memory
258    fn write_slice(&mut self, address: u64, data: &[u8]) -> Result<(), VirtualMemoryError>;
259}
260
261#[cfg(feature = "alloc")]
262impl<M> VirtualMemory for Box<M>
263where
264    M: VirtualMemory,
265{
266    #[inline(always)]
267    fn read<T>(&self, address: u64) -> Result<T, VirtualMemoryError>
268    where
269        T: BasicInt,
270    {
271        self.as_ref().read(address)
272    }
273
274    #[inline(always)]
275    unsafe fn read_unchecked<T>(&self, address: u64) -> T
276    where
277        T: BasicInt,
278    {
279        // SAFETY: Guaranteed by the caller
280        unsafe { self.as_ref().read_unchecked(address) }
281    }
282
283    #[inline(always)]
284    fn read_slice(&self, address: u64, len: u32) -> Result<&[u8], VirtualMemoryError> {
285        self.as_ref().read_slice(address, len)
286    }
287
288    #[inline(always)]
289    fn read_slice_up_to(&self, address: u64, len: u32) -> &[u8] {
290        self.as_ref().read_slice_up_to(address, len)
291    }
292
293    #[inline(always)]
294    fn write<T>(&mut self, address: u64, value: T) -> Result<(), VirtualMemoryError>
295    where
296        T: BasicInt,
297    {
298        self.as_mut().write(address, value)
299    }
300
301    #[inline(always)]
302    fn write_slice(&mut self, address: u64, data: &[u8]) -> Result<(), VirtualMemoryError> {
303        self.as_mut().write_slice(address, data)
304    }
305}
306
307/// Placeholder for custom errors in [`ExecutionError`]
308#[derive(Debug, Copy, Clone)]
309pub struct CustomErrorPlaceholder;
310
311impl fmt::Display for CustomErrorPlaceholder {
312    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
313        Ok(())
314    }
315}
316
317/// Program counter errors
318#[derive(Debug, thiserror::Error)]
319pub enum ProgramCounterError<Address, CustomError = CustomErrorPlaceholder> {
320    /// Unaligned instruction
321    #[error("Unaligned instruction at address {address}")]
322    UnalignedInstruction {
323        /// Address of the unaligned instruction fetch
324        address: Address,
325    },
326    /// Memory access error
327    #[error("Memory access error: {0}")]
328    MemoryAccess(#[from] VirtualMemoryError),
329    /// Custom error
330    #[error("Custom error: {0}")]
331    Custom(CustomError),
332}
333
334/// Generic program counter
335pub const trait ProgramCounter<Address, Memory, CustomError = CustomErrorPlaceholder> {
336    /// Get the current value of the program counter
337    fn get_pc(&self) -> Address;
338
339    /// Get the previous value of the program counter before executing an `instruction`.
340    ///
341    /// This is usually called from under instruction execution when the program counter is already
342    /// advanced during instruction fetching. As such, `pc - instruction_size` is expected to never
343    /// underflow.
344    #[inline(always)]
345    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
346    fn old_pc(&self, instruction_size: u8) -> Address
347    where
348        Address: [const] From<u8> + [const] Sub<Output = Address>,
349    {
350        // TODO: Wrapping subtraction would be nice, but causes a lot of additional generic bounds
351        //  that are bad for ergonomics
352        self.get_pc() - Address::from(instruction_size)
353    }
354
355    /// Set the current value of the program counter
356    fn set_pc(
357        &mut self,
358        memory: &Memory,
359        pc: Address,
360    ) -> Result<ControlFlow<()>, ProgramCounterError<Address, CustomError>>;
361}
362
363/// Execution errors
364#[derive(Debug, thiserror::Error)]
365pub enum ExecutionError<Address, CustomError = CustomErrorPlaceholder> {
366    /// Program counter error
367    #[error("Program counter error: {0}")]
368    ProgramCounter(ProgramCounterError<Address, CustomError>),
369    /// Memory access error
370    #[error("Memory access error: {0}")]
371    MemoryAccess(VirtualMemoryError),
372    /// Unsupported `ecall` instruction
373    #[error("Unsupported `ecall` instruction at address {address:#x}")]
374    EcallUnsupported {
375        /// Address of the unsupported instruction
376        address: Address,
377    },
378    /// Unimplemented/illegal instruction
379    #[error("Unimplemented/illegal instruction at address {address:#x}")]
380    IllegalInstruction {
381        /// Address of the `unimp` instruction
382        address: Address,
383    },
384    /// Invalid instruction
385    #[error("Invalid instruction at address {address:#x}: {instruction:#010x}")]
386    InvalidInstruction {
387        /// Address of the invalid instruction
388        address: Address,
389        /// Instruction that caused the error
390        instruction: u32,
391    },
392    /// CSR error
393    #[error("CSR error: {0}")]
394    CsrError(CsrError<CustomError>),
395    /// Custom error
396    #[error("Custom error: {0}")]
397    Custom(CustomError),
398}
399
400const impl<Address, CustomError> From<ProgramCounterError<Address, CustomError>>
401    for ExecutionError<Address, CustomError>
402{
403    #[inline(always)]
404    fn from(value: ProgramCounterError<Address, CustomError>) -> Self {
405        Self::ProgramCounter(value)
406    }
407}
408
409const impl<Address, CustomError> From<VirtualMemoryError> for ExecutionError<Address, CustomError> {
410    #[inline(always)]
411    fn from(value: VirtualMemoryError) -> Self {
412        Self::MemoryAccess(value)
413    }
414}
415
416const impl<Address, CustomError> From<CsrError<CustomError>>
417    for ExecutionError<Address, CustomError>
418{
419    #[inline(always)]
420    fn from(value: CsrError<CustomError>) -> Self {
421        Self::CsrError(value)
422    }
423}
424
425/// Result of [`InstructionFetcher::fetch_instruction()`] call
426#[derive(Debug, Copy, Clone)]
427pub enum FetchInstructionResult<Instruction> {
428    /// Instruction fetched successfully
429    Instruction(Instruction),
430    /// Control flow instruction encountered
431    ControlFlow(ControlFlow<()>),
432}
433
434/// Generic instruction fetcher
435pub const trait InstructionFetcher<I, Memory, CustomError = CustomErrorPlaceholder>
436where
437    Self: ProgramCounter<Address<I>, Memory, CustomError>,
438    I: Instruction,
439{
440    /// Fetch a single instruction at a specified address and advance the program counter on
441    /// successful fetch
442    fn fetch_instruction(
443        &mut self,
444        memory: &Memory,
445    ) -> Result<FetchInstructionResult<I>, ExecutionError<Address<I>, CustomError>>;
446}
447
448/// CSR error
449#[derive(Debug, thiserror::Error)]
450pub enum CsrError<CustomError = CustomErrorPlaceholder> {
451    /// Read only CSR
452    #[error("Read only CSR {csr_index:#x}")]
453    ReadOnly {
454        /// Index of CSR where write was attempted
455        csr_index: u16,
456    },
457    /// Illegal read access
458    #[error("Illegal read access to CSR {csr_index:#x}")]
459    IllegalRead {
460        /// Index of the accessed CSR
461        csr_index: u16,
462    },
463    /// Illegal write access
464    #[error("Illegal write access to CSR {csr_index:#x}")]
465    IllegalWrite {
466        /// Index of the accessed CSR
467        csr_index: u16,
468    },
469    /// Unknown CSR
470    #[error("Unknown CSR {csr_index:#x}")]
471    Unknown {
472        /// Index of the accessed CSR
473        csr_index: u16,
474    },
475    /// Insufficient privilege level
476    #[error(
477        "Insufficient privilege level for CSR {csr_index:#x}: required {required:?}, \
478        current {current:?}"
479    )]
480    InsufficientPrivilege {
481        /// Index of the accessed CSR
482        csr_index: u16,
483        /// Required privilege level
484        required: PrivilegeLevel,
485        /// Current privilege level
486        current: PrivilegeLevel,
487    },
488    /// Custom error
489    #[error("Custom error: {0}")]
490    Custom(CustomError),
491}
492
493/// CSRs (Control and Status Registers)
494pub const trait Csrs<Reg, CustomError = CustomErrorPlaceholder>
495where
496    Reg: [const] Register,
497    CustomError: [const] Destruct,
498{
499    /// Current privilege level
500    #[inline(always)]
501    fn privilege_level(&self) -> PrivilegeLevel {
502        PrivilegeLevel::Machine
503    }
504
505    /// Reads register value
506    fn read_csr(&self, csr_index: u16) -> Result<Reg::Type, CsrError<CustomError>>;
507
508    /// Writes register value
509    fn write_csr(&mut self, csr_index: u16, value: Reg::Type) -> Result<(), CsrError<CustomError>>;
510}
511
512/// Custom handler for system instructions `ecall` and `ebreak`
513pub const trait SystemInstructionHandler<
514    Reg,
515    Regs,
516    Memory,
517    PC,
518    CustomError = CustomErrorPlaceholder,
519> where
520    Reg: Register,
521{
522    // TODO: Figure out the correct API for this method
523    /// Handle a `fence` instruction
524    #[inline(always)]
525    fn handle_fence(&mut self, pred: u8, succ: u8) {
526        let _: u8 = pred;
527        let _: u8 = succ;
528        // NOP by default
529    }
530
531    // TODO: Figure out the correct API for this method
532    /// Handle a `fence.tso` instruction
533    #[inline(always)]
534    fn handle_fence_tso(&mut self) {
535        // NOP by default
536    }
537
538    /// Handle an `ecall` instruction
539    fn handle_ecall(
540        &mut self,
541        regs: &mut Regs,
542        memory: &mut Memory,
543        program_counter: &mut PC,
544    ) -> Result<ControlFlow<()>, ExecutionError<Reg::Type, CustomError>>;
545
546    /// Handle an `ebreak` instruction.
547    ///
548    /// NOTE: the program counter here is the current value, meaning it is already incremented past
549    /// the instruction itself.
550    #[inline(always)]
551    fn handle_ebreak(&mut self, regs: &mut Regs, memory: &mut Memory, pc: Reg::Type) {
552        // These are for cleaner trait API without leading `_` on arguments
553        let _: &Regs = regs;
554        let _: &mut Memory = memory;
555        let _: Reg::Type = pc;
556        // NOP by default
557    }
558}
559
560/// `rs1`/`rs2` instruction operands
561#[derive(Debug, Default, Copy, Clone)]
562pub struct Rs1Rs2Operands<Reg> {
563    /// `rs1` operand.
564    ///
565    /// Zero register if `rs1` was missing in the original instruction definition.
566    pub rs1: Reg,
567    /// `rs2` operand.
568    ///
569    /// Zero register if `rs2` was missing in the original instruction definition.
570    pub rs2: Reg,
571}
572
573/// `rs1`/`rs2` instruction operands
574#[derive(Debug, Default, Copy, Clone)]
575pub struct Rs1Rs2OperandValues<RegType> {
576    /// `rs1` operand value.
577    ///
578    /// Zero if `rs1` was missing in the original instruction definition.
579    pub rs1_value: RegType,
580    /// `rs2` operand value.
581    ///
582    /// Zero if `rs2` was missing in the original instruction definition.
583    pub rs2_value: RegType,
584}
585
586/// `rs1`/`rs2` instruction operands
587pub const trait ExecutableInstructionOperands
588where
589    Self: Instruction,
590{
591    /// `rs1`/`rs2` instruction operands.
592    ///
593    /// Returns zero register for `rs1`/`rs2` that were missing in the original instruction
594    /// definition.
595    fn get_rs1_rs2_operands(self) -> Rs1Rs2Operands<Self::Reg>;
596}
597
598pub const trait ExecutableInstructionCsr<ExtState, CustomError = CustomErrorPlaceholder>
599where
600    Self: Instruction,
601{
602    /// Prepare CSR read.
603    ///
604    /// This method is called on each extension one by one with the `raw_value` (contents of the
605    /// corresponding CSR register) and initially zero-initialized `output_value`. In return value
606    /// every extension can accept (`Ok(true)`), ignore (`Ok(false)`) or reject (`Err(CsrError)`)
607    /// read request. For accepted reads the extension must update `output_value` accordingly, which
608    /// will be the value used by the `Zicsr` extension handler.
609    ///
610    /// Some extensions will just copy `raw_value` to output value, others will copy only some bits
611    /// or zero some bits of the `raw_value`, as required by the specification.
612    ///
613    /// `will_write` indicates whether the CSR instruction performing this read will also perform a
614    /// write immediately afterward (as part of the same instruction). It is always `true` for
615    /// `csrrw{,i}`, and `true` for `csrrs{,i}`/`csrrc{,i}` unless their `rs1`/`zimm` operand is
616    /// zero (in which case they are a pure read with no write). Some CSRs (e.g. `Zkr`'s `seed`)
617    /// are only legal to access through a genuine read-write instruction and must reject the read
618    /// when `will_write` is `false`.
619    ///
620    /// If no extension returns `Ok(true)`, the read operation is implicitly rejected as illegal
621    /// access.
622    #[inline(always)]
623    fn prepare_csr_read(
624        ext_state: &ExtState,
625        csr_index: u16,
626        will_write: bool,
627        raw_value: RegisterType<Self>,
628        output_value: &mut RegisterType<Self>,
629    ) -> Result<bool, CsrError<CustomError>> {
630        // These are for cleaner trait API without leading `_` on arguments
631        let _: &ExtState = ext_state;
632        let _: u16 = csr_index;
633        let _: bool = will_write;
634        let _: RegisterType<Self> = raw_value;
635        let _: &mut RegisterType<Self> = output_value;
636        // The default implementation is to not allow anything
637        Ok(false)
638    }
639
640    /// Prepare CSR write.
641    ///
642    /// This method is called on each extension one by one with `write_value` being prepared by the
643    /// `Zicsr` extension handler. In return value every extension can accept (`Ok(true)`), ignore
644    /// (`Ok(false)`) or reject (`Err(CsrError)`) write request. For accepted writes the extension
645    /// must update `output_value` accordingly, which will be written to the corresponding CSR
646    /// register.
647    ///
648    /// Some extensions will just copy `write_value` to output value, others will copy some bits or
649    /// zero some bits of the `write_value`, as required by the specification.
650    ///
651    /// If no extension returns `Ok(true)`, the write operation is implicitly rejected as illegal
652    /// access.
653    #[inline(always)]
654    fn prepare_csr_write(
655        ext_state: &mut ExtState,
656        csr_index: u16,
657        write_value: RegisterType<Self>,
658        output_value: &mut RegisterType<Self>,
659    ) -> Result<bool, CsrError<CustomError>> {
660        // These are for cleaner trait API without leading `_` on arguments
661        let _: &mut ExtState = ext_state;
662        let _: u16 = csr_index;
663        let _: RegisterType<Self> = write_value;
664        let _: &mut RegisterType<Self> = output_value;
665        // The default implementation is to not allow anything
666        Ok(false)
667    }
668}
669
670/// Type alias for the result returned by [`ExecutableInstruction::execute`]
671pub type ExecutableInstructionResult<T, I, CustomError> = Result<
672    ControlFlow<
673        T,
674        (
675            <I as Instruction>::Reg,
676            <<I as Instruction>::Reg as Register>::Type,
677        ),
678    >,
679    ExecutionError<Address<I>, CustomError>,
680>;
681
682/// Trait for executable instructions
683pub const trait ExecutableInstruction<
684    Regs,
685    ExtState,
686    Memory,
687    PC,
688    InstructionHandler,
689    CustomError = CustomErrorPlaceholder,
690> where
691    Self: ExecutableInstructionOperands + ExecutableInstructionCsr<ExtState, CustomError>,
692{
693    /// Execute instruction.
694    ///
695    /// Instructions might place additional constraints on `ExtState` to require additional
696    /// registers or other resources. If no such constraint is used, `()` can be used as a
697    /// placeholder.
698    ///
699    /// On success `Ok(ControlFlow::Continue((rd, rd_value)))` is returned, which will be written
700    /// into the register file. In most cases this is the only register that needs to be written. If
701    /// no value needs to be written, `Ok(ControlFlow::Continue(Default::default()))` should be
702    /// returned, which corresponds to `Ok(ControlFlow::Continue(Reg::ZERO, 0))` and is no-op.
703    fn execute(
704        self,
705        rs1rs2_values: Rs1Rs2OperandValues<<Self::Reg as Register>::Type>,
706        regs: &mut Regs,
707        ext_state: &mut ExtState,
708        memory: &mut Memory,
709        program_counter: &mut PC,
710        system_instruction_handler: &mut InstructionHandler,
711    ) -> ExecutableInstructionResult<(), Self, CustomError>;
712}