This crate contains components to implement a RISC-V instruction set simulator. It is designed to be modular so should prove useful for any application that needs to decode or otherwise work with RISC-V instructions.
rrs-lib supports RV32IM, there is no privileged support, CSR instructions or exceptions/interrupts (though these are planned).
toml
[dependencies]
rrs-lib = "0.1"
A key trait of rrs-lib is InstructionProcessor. It contains one function per RISC-V instruction. The process_instruction function decodes an instruction and calls the appropriate function in an InstructionProcessor. An InstructionProcessor could execute an instruction, disassemble instruction or something else entirely (e.g. compute statistical information on instructions executed). rrs-lib provides InstructionProcessor implementations to execute RISC-V code and produce instruction disassembly in a string. This example demonstrates both:
```rust use rrslib::{HartState, MemAccessSize, Memory}; use rrslib::memories::VecMemory; use rrslib::instructionexecutor::{InstructionExecutor, InstructionException}; use rrslib::instructionstring_outputter::InstructionStringOutputter;
fn simulate_riscv() { let mut hart = HartState::new(); // Memory contains these instructions: // lui x2, 0x1234b // lui x3, 0xf387e // add x1, x2, x3 let mut mem = VecMemory::new(vec![0x1234b137, 0xf387e1b7, 0x003100b3]);
hart.pc = 0;
// InstructionExecutor implements IntructionProcessor. The step function calls // processinstruction internally and handles things like updating the PC. let mut executor = InstructionExecutor { hartstate: &mut hart, mem: &mut mem, };
// Execute first instruction outputdisass(&mut executor); asserteq!(executor.step(), Ok(())); asserteq!(executor.hartstate.registers[2], 0x1234b000);
// Execute second instruction outputdisass(&mut executor); asserteq!(executor.step(), Ok(())); asserteq!(executor.hartstate.registers[3], 0xf387e000);
// Execute third instruction outputdisass(&mut executor); asserteq!(executor.step(), Ok(())); asserteq!(executor.hartstate.registers[1], 0x05bc9000);
// Memory only contains three instructions so next step will produce a fetch error assert_eq!(executor.step(), Err(InstructionException::FetchError(0xc))); }
fn outputdisass