riscv-128bit-vm-1.1.0 is not a library.
RISC-V 128-bit Virtual Machine
A high-performance 128-bit RISC-V virtual machine implemented in Rust, featuring custom instruction set extensions and advanced memory management.
Features
- 128-bit Registers: Full support for RISC-V 128-bit integer extension (I)
- 32 Floating-Point Registers: Support for F/D/Q floating-point extensions
- 32 Vector Registers: Support for V vector extension
- Built-in Assembler: Direct loading and execution of RISC-V assembly code
- Flexible Memory System: Configurable memory size with byte/half-word/word/double-word/quad-word access
- Interactive Debugger: Full-featured debugger with breakpoints, watchpoints, execution history, and step-by-step execution
- Debug Support: Single-step execution, instruction tracing, register state inspection
- Exception Handling: Complete exception capture and reporting mechanism
Supported Extensions
Base Integer Instructions (I)
| Type |
Instructions |
| R-type |
ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND |
| I-type |
ADDI, SLTI, SLTIU, XORI, ORI, ANDI, SLLI, SRLI, SRAI |
| Load |
LB, LH, LW, LD, LQ, LBU, LHU, LWU, LDU |
| Store |
SB, SH, SW, SD, SQ |
| Branch |
BEQ, BNE, BLT, BGE, BLTU, BGEU |
| U-type |
LUI, AUIPC |
| Jump |
JAL, JALR |
| System |
ECALL, EBREAK |
M Extension (Integer Multiplication/Division)
| Instruction |
Description |
| MUL |
Multiply low |
| MULH |
Multiply high signed |
| MULHSU |
Multiply high signed-unsigned |
| MULHU |
Multiply high unsigned |
| DIV |
Divide signed |
| DIVU |
Divide unsigned |
| REM |
Remainder signed |
| REMU |
Remainder unsigned |
A Extension (Atomic Memory Operations)
| Instruction |
Description |
| LR.D |
Load Reserved |
| SC.D |
Store Conditional |
| AMOADD.D |
Atomic Add |
| AMOSWAP.D |
Atomic Swap |
| AMOAND.D |
Atomic AND |
| AMOOR.D |
Atomic OR |
| AMOXOR.D |
Atomic XOR |
| AMOMAX.D |
Atomic Maximum signed |
| AMOMAXU.D |
Atomic Maximum unsigned |
| AMOMIN.D |
Atomic Minimum signed |
| AMOMINU.D |
Atomic Minimum unsigned |
F Extension (Single-Precision Floating-Point)
| Category |
Instructions |
| Load/Store |
FLW, FSW |
| Arithmetic |
FADD.S, FSUB.S, FMUL.S, FDIV.S, FSQRT.S |
| Sign Injection |
FSGNJ.S, FSGNJN.S, FSGNJX.S |
| Min/Max |
FMIN.S, FMAX.S |
| Convert |
FCVT.W.S, FCVT.WU.S, FCVT.S.W, FCVT.S.WU, FCVT.L.S, FCVT.LU.S, FCVT.S.L, FCVT.S.LU |
| Move |
FMV.X.S, FMV.S.X |
| Compare |
FEQ.S, FLT.S, FLE.S |
| Classify |
FCLASS.S |
D Extension (Double-Precision Floating-Point)
| Category |
Instructions |
| Load/Store |
FLD, FSD |
| Arithmetic |
FADD.D, FSUB.D, FMUL.D, FDIV.D, FSQRT.D |
| Sign Injection |
FSGNJ.D, FSGNJN.D, FSGNJX.D |
| Min/Max |
FMIN.D, FMAX.D |
| Convert |
FCVT.W.D, FCVT.WU.D, FCVT.D.W, FCVT.D.WU, FCVT.L.D, FCVT.LU.D, FCVT.D.L, FCVT.D.LU |
| Move |
FMV.X.D, FMV.D.X |
| Compare |
FEQ.D, FLT.D, FLE.D |
| Classify |
FCLASS.D |
| Precision Convert |
FCVT.D.S, FCVT.S.D |
Q Extension (Quad-Precision Floating-Point)
| Category |
Instructions |
| Load/Store |
FLQ, FSQ |
| Arithmetic |
FADD.Q, FSUB.Q, FMUL.Q, FDIV.Q, FSQRT.Q |
| Sign Injection |
FSGNJ.Q, FSGNJN.Q, FSGNJX.Q |
| Min/Max |
FMIN.Q, FMAX.Q |
| Convert |
FCVT.W.Q, FCVT.WU.Q, FCVT.Q.W, FCVT.Q.WU, FCVT.L.Q, FCVT.LU.Q, FCVT.Q.L, FCVT.Q.LU |
| Move |
FMV.X.Q, FMV.Q.X |
| Compare |
FEQ.Q, FLT.Q, FLE.Q |
| Classify |
FCLASS.Q |
| Precision Convert |
FCVT.Q.S, FCVT.S.Q, FCVT.Q.D, FCVT.D.Q |
V Extension (Vector Operations)
- Vector load/store operations
- Vector integer operations
- Vector floating-point operations
- Vector configuration (vsetvli, vsetvl)
- Support for various element widths (8/16/32/64/128/256/512/1024-bit)
- Length multiplier (LMUL) support
C Extension (Compressed Instructions)
16-bit compressed instructions for code size reduction:
- C.ADDI4SPN, C.LW, C.LD, C.SW, C.SD
- C.ADDI, C.JAL, C.LI, C.ADDI16SP, C.LUI
- C.SRLI, C.SRAI, C.ANDI, C.SUB, C.XOR, C.OR, C.AND
- C.J, C.BEQZ, C.BNEZ
- And more...
Zicsr Extension (Control and Status Registers)
| Instruction |
Description |
| CSRRW |
CSR Read/Write |
| CSRRS |
CSR Read/Set |
| CSRRC |
CSR Read/Clear |
| CSRRWI |
CSR Read/Write Immediate |
| CSRRSI |
CSR Read/Set Immediate |
| CSRRCI |
CSR Read/Clear Immediate |
Zifencei Extension (Instruction Fence)
| Instruction |
Description |
| FENCE.I |
Instruction cache synchronization |
Zba/Zbb/Zbc Extensions (Bit Manipulation)
| Category |
Instructions |
| Shift-Add |
SH1ADD, SH2ADD, SH3ADD, SH1ADD.UW, SH2ADD.UW, SH3ADD.UW |
| Rotate |
ROL, ROR, RORI |
| Logic |
ANDN, ORN, XORN |
| Count |
CLZ, CTZ, CPOP |
| Carry-less |
CLMUL, CLMULR, CLMULH |
| Min/Max |
MIN, MAX, MINU, MAXU |
| Bit Extract/Insert |
BEXTI, BCLRI, BSETI, BINVI |
| Special |
ADD.UW, SLLI.UW |
Pseudo-Instructions
The assembler supports the following pseudo-instructions for simplified programming:
nop -> addi x0, x0, 0
mv rd, rs -> addi rd, rs, 0
not rd, rs -> xori rd, rs, -1
neg rd, rs -> sub rd, x0, rs
li rd, imm -> lui + addi (automatically expanded based on immediate)
j label -> jal x0, label
ret -> jalr x0, x1, 0
call label -> auipc + jalr
beqz rs, label -> beq rs, x0, label
...and more
Installation
Prerequisites
Building
git clone https://github.com/olele114/riscv-128bit-vm.git
cd riscv-128bit-vm
cargo build --release
The compiled executable will be located at target/release/riscv-128bit-vm.exe.
Usage
Command Line Arguments
riscv-128bit-vm [options] [program_file]
Options:
--help Show help message
--memory <size> Set memory size in bytes (default: 16MB)
--debug Enable debug mode
--trace Enable execution tracing
--step Run in single-step mode
-d, --debugger Start interactive debugger
--history <n> Set execution history size (default: 1000)
--load-addr <addr> Set program load address (default: 0x0)
Supported File Formats
| Extension |
Format |
| .bin, .raw |
Raw binary machine code |
| .s, .asm |
RISC-V assembly source (auto-assembled) |
Interactive Debugger
The interactive debugger provides powerful debugging capabilities:
Debugger Commands:
Execution Control:
c, continue Continue execution
s, step Single step (enter function calls)
n, next Step over (skip function calls)
finish Step out of current function
u, until <addr> Run until address
Breakpoints:
b, break <addr> Set breakpoint at address
tb, tbreak <addr> Set temporary breakpoint (removed after hit)
d, delete [id] Delete breakpoint (all if no id)
enable <id> Enable breakpoint
disable <id> Disable breakpoint
ignore <id> <n> Ignore breakpoint for N hits
info b List all breakpoints
Watchpoints:
watch <addr> [size] [type] Set memory watchpoint
type: r(ead), w(rite), a(ccess)
watchreg <reg> [fp] Watch register (fp for float)
dwatch <id> Delete watchpoint
info w List all watchpoints
Inspection:
p, print <$reg> Print register value
p, print <addr> [size] Print memory contents
reg, registers Print all registers
x <addr> [size] Examine memory
disas <addr> [n] Disassemble N instructions
History & Navigation:
history [n] Show last N execution history entries
where Show current position and instruction
reset Reset VM to initial state
Other:
help, ? Show help
q, quit Exit debugger
Examples
riscv-128bit-vm program.bin
riscv-128bit-vm program.s
riscv-128bit-vm --load-addr 0x80000000 firmware.asm
riscv-128bit-vm --debug --trace program.s
riscv-128bit-vm --step program.s
riscv-128bit-vm -d program.s
riscv-128bit-vm --memory 0x2000000 -d program.bin
riscv-128bit-vm --history 5000 -d program.s
Assembly Language Examples
Basic Computation
# Simple calculation example
.text
li a0, 42 # Load immediate 42 into a0
li a1, 10 # Load immediate 10 into a1
add a2, a0, a1 # a2 = a0 + a1 (result: 52)
sub a3, a0, a1 # a3 = a0 - a1 (result: 32)
ebreak # Stop execution
Loop Example
# Calculate 1+2+3+4+5 = 15
.text
li t0, 0 # Accumulator
li t1, 1 # Counter
li t2, 6 # End condition
loop:
add t0, t0, t1 # Accumulate
addi t1, t1, 1 # Counter +1
blt t1, t2, loop # If t1 < 6, continue loop
mv a0, t0 # Store result in a0 (15)
ebreak
Memory Operations
# Data storage and loading
.text
li t0, 0x1000 # Memory address
li t1, 0x12345678 # Test data
sw t1, 0(t0) # Store word
lw t2, 0(t0) # Load word
addi t3, t2, 1 # t3 = t2 + 1
ebreak
Floating-Point Example
# Floating-point computation
.text
li t0, 0x1000 # Memory address for FP data
# Store and load single-precision
flw f0, 0(t0) # Load single-precision
fadd.s f2, f0, f1 # Add single-precision
# Store and load double-precision
fld f4, 8(t0) # Load double-precision
fmul.d f6, f4, f5 # Multiply double-precision
ebreak
Atomic Operations Example
# Atomic memory operations
.text
li t0, 0x1000 # Memory address
lr.d t1, 0(t0) # Load reserved
addi t1, t1, 1 # Increment
sc.d t2, t1, 0(t0) # Store conditional
beqz t2, done # If success (t2 == 0), done
j atomic_retry # Retry on failure
done:
ebreak
Programming Interface
Basic Usage
use riscv::virtual_machine::{VirtualMachine, VMConfig};
use riscv::memory;
fn main() {
let config = VMConfig::new();
let mut vm = VirtualMachine::new(config);
vm.initialize();
vm.load_program("program.bin", 0x0).unwrap();
vm.run();
vm.print_register_state();
}
Loading Assembly Code
vm.load_assembly("program.s", 0x0).unwrap();
let source = r#"
li a0, 42
add a1, a0, a0
ebreak
"#;
vm.load_assembly_string(source, 0x0).unwrap();
Single-Step Execution
vm.start();
while vm.is_running() && !vm.has_exception() {
vm.step();
vm.print_register_state();
}
Interactive Debugger
use riscv::virtual_machine::{VirtualMachine, VMConfig};
let config = VMConfig::new().with_debugger().with_history_size(2000);
let mut vm = VirtualMachine::new(config);
vm.initialize();
vm.load_assembly("program.s", 0x0).unwrap();
vm.run_debugger();
Debugger API
if let Some(debugger) = vm.get_debugger_mut() {
let bp_id = debugger.breakpoints.add_address(0x80000100);
let cond = debugger::BreakCondition::RegisterEqual { reg: 10, value: 42 };
debugger.breakpoints.add_conditional(0x80000200, cond);
debugger.watchpoints.add_memory(0x1000, 8, debugger::WatchpointType::Write);
}
if let Some(debugger) = vm.get_debugger() {
for bp in debugger.breakpoints.list() {
println!("Breakpoint {} at 0x{:x}, hits: {}",
bp.id, bp.address().unwrap_or(0), bp.hit_count);
}
}
Project Structure
riscv-128bit-vm/
├── Cargo.toml
└── src/
├── main.rs # Main program entry
└── riscv/
├── mod.rs # Module exports
├── cpu.rs # CPU implementation
├── register.rs # Register file (GPR, FPR, VR, CSR)
├── memory.rs # Memory system with AMO support
├── instruction.rs # Instruction decoder
├── executor.rs # Instruction executor
├── virtual_machine.rs # VM interface
├── assembler.rs # Assembler
└── debugger.rs # Interactive debugger
Register Mapping
General-Purpose Registers
| Register |
ABI Name |
Purpose |
| x0 |
zero |
Hardwired zero |
| x1 |
ra |
Return address |
| x2 |
sp |
Stack pointer |
| x3 |
gp |
Global pointer |
| x4 |
tp |
Thread pointer |
| x5-x7 |
t0-t2 |
Temporary registers |
| x8 |
s0/fp |
Saved register / Frame pointer |
| x9 |
s1 |
Saved register |
| x10-x17 |
a0-a7 |
Function arguments / Return values |
| x18-x27 |
s2-s11 |
Saved registers |
| x28-x31 |
t3-t6 |
Temporary registers |
Floating-Point Registers
| Register |
ABI Name |
Purpose |
| f0-f7 |
ft0-ft7 |
FP temporary registers |
| f8-f9 |
fs0-fs1 |
FP saved registers |
| f10-f17 |
fa0-fa7 |
FP arguments / Return values |
| f18-f27 |
fs2-fs11 |
FP saved registers |
| f28-f31 |
ft8-ft11 |
FP temporary registers |
Vector Registers
| Register |
ABI Name |
Purpose |
| v0-v31 |
v0-v31 |
Vector registers |
License
MIT License