Extending SimRV: Adding New ISA Extensions
This guide outlines the process for onboarding new RISC-V extensions (e.g., Vector V,
Bit-Manipulation Zb*, Crypto K) into the SimRV architecture.
The simulator uses a decode-and-dispatch pipeline model, so new extensions follow a linear integration path through define → decode → execute → state → TUI.
1. Register the Extension and Opcodes
All core ISA definitions and shared constants live in
include/simrv/Define.hpp.
-
Extension Bit: Add your extension to the
IsaExtensionenum (e.g.,V = 21for Vector). -
misaProfiles: Ensure the extension bit is included in the appropriatemisa_profile_bits()entries if it belongs to a standard profile. -
Opcodes and Funct fields:
- Add new major opcodes to the
Opcodeenum. -
Add sub-operation discriminants to
Funct3,Funct7, or create a dedicated enum (e.g.,Funct6Vector) for dense sub-encoding spaces. -
Operation ID (Profiling and Instruction Mix):
- Add every new instruction to the
OperationIdenum. -
Define range sentinels at the bottom of the enum (e.g.,
kOpRangeRv32vBegin/kOpRangeRv32vEnd) so thatTracerand instruction-mix stats can bucket your extension correctly. -
Requirements Check: Update
required_extension_for_instruction()so the core raisesIllegalInstructionwhen the extension is disabled inmisa.
2. Decode the Instruction
Instruction decoding logic lives in:
- include/simrv/pipeline/Decoder.hpp — field extraction helpers
- src/pipeline/Decoder.cpp — master decode switch
Steps:
-
Decoder Helpers: If the extension introduces new instruction formats (e.g., Vector
vtype,vmmask fields), add extraction methods to theDecoderclass. -
Operation Identification: Update the
simrv::pipeline::decoder()function. This is the master lookup usingswitch/caseoverOpcodeandFunct3/Funct7to map raw instruction bits to your newOperationIdvalues. -
Compressed (RVC) variants: If your extension includes 16-bit forms, handle them in the decompression path before the main decode switch.
3. Implement Execution Logic
Execution routing happens in the Execute stage:
- src/execute/ExecuteUnit.cpp — routing hub
- src/execute/ExecuteUnitInt.cpp — integer ops
- src/execute/ExecuteUnitFloat.cpp — FP ops
Steps:
-
Routing: Inside the execute dispatch, add a case for your
OperationIdrange or individual operations, delegating to a new execute unit if warranted. -
Execution Context:
- Fetch operands from
PipelineContext(populated during the ID stage). -
For non-standard state (e.g., vector registers), route to a new dedicated unit (e.g.,
VectorUnit::execute()). -
Writeback: Store results back into
PipelineContextwriteback fields soCPU::writeback_registers()can commit them to architectural state during WB stage.
4. Add Architectural State (Registers / CSRs)
If the extension requires new architectural state (e.g., 32 vector registers of variable length):
-
Types: Define new register identifiers and associated types in
include/simrv/xlen/Types.hpp. -
State Storage: Add state arrays or structs to
ArchStateinsideinclude/simrv/core/Cpu.hpp(embedded inCPUviastate_). -
Control and Status Registers (CSRs):
- Add new CSR addresses to the
Csrenum inDefine.hpp. - Implement read/write behavior, access control, and illegal-instruction guards in
src/core/CsrFile.cpp.
5. Instruction Explainer Integration
SimRV's interactive educational explainer (InstructionExplainer) shows per-instruction
descriptions in the TUI EXPLAIN pane and via --explain-inst CLI. Ensure new instructions
appear correctly:
-
Mnemonic and Assembly Rep: Add entries to
InstructionExplainer::get_mnemonic()andget_assembly_repr()insrc/util/InstructionExplainer.cpp. -
Description: Add a short educational description to
get_description(). Include the ISA extension name in the description so users can identify which extension an instruction belongs to. -
Format: Set the correct
InstructionFormat(R, I, S, B, U, J, R4, CR, CI, CSS, CIW, CL, CS, CB, CJ) returned byget_format().
6. TUI and Tracer Integration
To maintain full observability:
-
Tracer: Ensure
OPERATION_NAMEstrings are populated for all newOperationIdvalues so instruction-mix output and trace files work correctly. -
TUI Register & Subsystem Panes: The TUI is split into modular components under
src/tui/panels/: - If you add new architectural state (e.g., vector registers), update
src/tui/panels/LeftPaneRegs.cppor create a dedicated panel view. Add a new view type ininclude/simrv/tui/panels/LeftPane.hppand wire it into the pane cycler. - Use the centralized theme helpers from
TuiTheme.hpp— never hardcode raw ANSI escape sequences.
7. Testing and Validation
-
ISA Tests: Set
RISCV_TESTS_DIR=/path/to/riscv-testsat CMake configuration time. ISA tests and lockstep checks will automatically register matching targets. -
Vector Tests: For vector extensions, set
SIMRV_VECTOR_TESTS_DIR=/path/to/riscv-vector-testsor--vector-tests-dir. -
Gate Suite: Run the CTest gate suite to validate regression coverage across both architectures: