Instruction-level RISC-V simulator with a generated decoder/executer and an optional x86-64 JIT backend.
- ELF64 loader with a simple MMU and paging support.
- RV64I ISA description in YAML, codegen via Ruby DSL.
- Interpreter with a basic-block cache.
- x86-64 JIT via asmjit (basic blocks and function-level JIT for small programs).
- Optional modules/callbacks and profiling/PGO helper script.
- CMake 3.21+
- C++17 compiler
- Ruby (for code generation)
- Boost program_options
- asmjit (JIT backend)
asmjit must be available to CMake (find_package(asmjit REQUIRED)), either via
system packages or a local build. If you build it yourself, point CMake to its
config directory:
cmake -S . -B build -Dasmjit_DIR=/path/to/asmjit/lib/cmake/asmjitmkdir -p build
cmake -S . -B build
cmake --build build -j$(nproc)The binary is build/bin/riscv_sim.
-DDEBUG_EXECUTION=ON # verbose per-instruction logging
-DENABLE_MODULES=ON # build modules support (callbacks)
-DPROFILING=ON # add -g + frame pointers for perf/valgrind
-DGENERATE_PGO=ON # build instrumentation for profile generation
-DOPTIMIZE_PGO=ON # build with existing profiles (mutually exclusive with GENERATE_PGO)Notes:
ENABLE_MODULESonly affects availability of--moduleat runtime.GENERATE_PGOandOPTIMIZE_PGOare mutually exclusive.
build/bin/riscv_sim --input=./e2e_tests/queens.elfCLI options:
--input, -i path to ELF (required)
--config, -c config file (default: ./config/configx86.conf)
--module, -m module name (requires ENABLE_MODULES=ON; incompatible with JIT)
--output, -o statistic dump file (optional)Examples:
build/bin/riscv_sim --config=./config/configx86.conf --input=./e2e_tests/queens.elfYou can also use the helper script:
./run_x86.sh --elf ./e2e_tests/queens.elf
./run_x86.sh --no-pgo
./run_x86.sh --generate-pgoThe default config file is config/configx86.conf (see also config/config.conf).
It controls:
use_jit(0/1)bb_cache_sizecached_bb_sizejit_boundmax_cyclesinitial_pc,initial_reg_val,read_delay
Modules vs JIT
- Modules are compile-time (
-DENABLE_MODULES=ON) and runtime (--module=...). - JIT is controlled by
use_jitin the config file. - Modules and JIT are mutually exclusive: if
use_jit=1, modules are disabled. To use modules, setuse_jit=0in your config.
Build a test ELF with a RISC-V toolchain that matches the ISA in
isa/rv64i_isa.yml:
riscv64-unknown-elf-gcc -o sum.elf sum.c -march=rv64i -mabi=lp64 -nostdlib -T simple.ldIf you use a different ISA or ABI, adjust the flags accordingly.
src/: simulator core (Machine, Hart, MMU) and JIT.config/: CLI and simulator config parsing.isa/andisa/dsl/: YAML ISA descriptions and Ruby codegen.decode_execute_module/: generated decoder/executer sources.e2e_tests/: sample programs and linker script.