Expand description
Composable and generic RISC-V interpreter.
This interpreter is designed to work with abstractions from ab-riscv-primitives crate and is
similarly composable with a powerful macro system and trait abstractions over handling of
memory, syscalls, etc.
The immediate needs dictate the current set of available instructions and extensions. Consider contributing if you need something not yet available.
ab-riscv-act4-runner crate in the repository contains a complementary RISC-V Architectural
Certification Tests runner for https://github.com/riscv-non-isa/riscv-arch-test that ensures
correct implementation.
Does not require a standard library (no_std) or an allocator, never panics, almost 100% of the
API abstractions are usable in const, including several extensions beyond base ISA.
§Supported ISA variants and extensions
ISA variants:
- RV32I (version 2.1)
- RV32E (version 2.0)
- RV64I (version 2.1)
- RV64E (version 2.0)
Extensions:
- A (version 2.1)
- M (version 2.0)
- B (version 1.0.0)
- Zaamo (version 1.0.0)
- Zabha (version 1.0.0)
- Zacas (version 1.0.0)
- (experimental) Zalasr (version 1.0.0)
- Zalrsc (version 1.0.0)
- Zawrs (version 1.0.0)
- Zba (version 1.0.0)
- Zbb (version 1.0.0)
- Zbc (version 1.0.0)
- Zbkb (version 1.0.1)
- Zbkc (version 1.0.1)
- Zbkx (version 1.0.1)
- Zbs (version 1.0.0)
- Zca (version 1.0.0)
- Zcb (version 1.0.0)
- (experimental) Zcmp (version 1.0.0)
- Zicond (version 2.0)
- Zicsr (version 2.0)
- Zkn (version 1.0.1)
- Zknd (version 1.0.1)
- Zkne (version 1.0.1)
- Zknh (version 1.0.1)
- Zkr (version 1.0.1)
- Zvbb (version 1.0.0)
- Zvbc (version 1.0.0)
- ZveXx (version 1.0.0), where
Xis anything allowed by the specification like Zve32x or Zve64x - Zvkb (version 1.0.0)
- Zvl*b (version 1.0.0), where
*is anything allowed by the specification like Zvl128b or Zvl512b
All extensions except experimental pass all relevant RISC-V Architectural Certification Tests (ACTs) using the ACT4 framework.
Any permutation of compatible extensions is supported.
Experimental extensions may not have ACT4 tests yet and are not guaranteed to work correctly.
§Design choices
This crate was designed with a blockchain use case in mind, though it is in no way tied to any particular blockchain and is completely general purpose. As a result, the implementation is designed to be precise and non-ambiguous.
A few key points:
- anything “reserved” in the specification is considered to be illegal
- anything “optional” in the specification is considered to be illegal
- anything “implementation-defined” in the specification is selected to be the most natural and deterministic
- type system is used to make the majority of invalid invariants impossible to represent in code and/or decode
Examples:
vma/vtaare always undisturbed in vector extensions- Zve64x extension instructions are purposefully restricted to what it is required to be capable of, although it would be cheaper to support the fuller feature set only required by V extension
§Instruction implementations are assembled, not compiled in place
Instruction implementations are not compiled where they are written. build.rs calls
ab_riscv_macros::process_instruction_macros(), which parses the sources marked with the
#[instruction] and #[instruction_execution] attribute macros and writes a generated
execution implementation per instruction set into OUT_DIR.
Macros have documentation about how they work, but the important thing is that match
expressions are parsed and re-assembled as needed instead of being compiled in place.
Two things follow from this, and both constrain how instruction implementations must be written:
- the same arm is expanded into more than one crate, so a
crate::-relative path inside an arm resolves against whichever crate it landed in and is avoided. Shared code is reached through helper modules re-exported fromprelude- likerv64_zbb_helpersand similar - so that an arm can name them unqualified wherever it ends up - because each arm is kept separately and names exactly the operands its instruction uses, the
same arms can be emitted as something other than one large
match. Emitting them as standalone per-instruction functions, dispatched by tail call, is what allows an interpreter to avoid decoding operands that the instruction about to run does not use, and to stop paying for extensions that are compiled in but never executed
Modules§
- basic
- Basic implementations of various interpreter traits
- prelude
- Re-export of all traits, core types, and instruction helpers
- rv32
- Base RISC-V RV32 instruction set
- rv64
- Base RISC-V RV64 instruction set
- v
- V extension
- zawrs
- Zawrs extension
- zicond
- Zicond extension
- zicsr
- Zicsr extension
- zkr
- Zkr extension
- zvbb
- Zvbb extension
- zvbc
- Zvbc extension
Macros§
Structs§
- Opaque
Threaded Execution Result ThreadedExecutionResultin the shape tail-called handlers return it in.- Packed
Address - Address wrapper for
ExecutionErrorwith an alignment of 4 rather than its natural one. - Rs1Rs2
Operand Values rs1/rs2instruction operands- Rs1Rs2
Operands rs1/rs2instruction operands- Threaded
Execution Result - Outcome of
ThreadedExecutableInstruction::execute_threaded().
Enums§
- CsrError
- CSR error
- Execution
Error - Execution errors.
- Execution
Result - Where execution continues after an instruction, or why it could not.
- Fetch
Instruction Result - Result of
InstructionFetcher::fetch_instruction()call - Virtual
Memory Error - Errors for
VirtualMemory
Traits§
- Basic
Int - Basic integer types that can be read and written to/from memory freely
- Csrs
- CSRs (Control and Status Registers)
- Executable
Instruction - Trait for executable instructions
- Executable
Instruction Csr - Executable
Instruction Operands rs1/rs2instruction operands- Instruction
Fetcher - Generic instruction fetcher.
- Program
Counter - Generic program counter
- Register
File - A GPR (General Purpose Register) file abstraction
- System
Instruction Handler - Custom handler for system instructions
ecallandebreak - Threaded
Executable Instruction - Tail-call-threaded counterpart of
ExecutableInstruction. - Virtual
Memory - Virtual memory interface