rrs-lib

Crates.iorrs-lib
lib.rsrrs-lib
version0.1.0
sourcesrc
created_at2021-08-09 20:27:35.811006
updated_at2021-08-09 20:27:35.811006
descriptionA library for building RISC-V instruction set simulators
homepagehttps://gregchadwick.co.uk/blog/building-rrs-pt1/
repositoryhttps://github.com/GregAC/rrs/tree/main/rrs-lib
max_upload_size
id433942
size73,388
Greg Chadwick (GregAC)

documentation

README

Rust RISC-V Simulator Library (rrs-lib)

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).

Usage

[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:

use rrs_lib::{HartState, MemAccessSize, Memory};
use rrs_lib::memories::VecMemory;
use rrs_lib::instruction_executor::{InstructionExecutor, InstructionException};
use rrs_lib::instruction_string_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
  // process_instruction internally and handles things like updating the PC.
  let mut executor = InstructionExecutor {
      hart_state: &mut hart,
      mem: &mut mem,
  };

  // Execute first instruction
  output_disass(&mut executor);
  assert_eq!(executor.step(), Ok(()));
  assert_eq!(executor.hart_state.registers[2], 0x1234b000);

  // Execute second instruction
  output_disass(&mut executor);
  assert_eq!(executor.step(), Ok(()));
  assert_eq!(executor.hart_state.registers[3], 0xf387e000);

  // Execute third instruction
  output_disass(&mut executor);
  assert_eq!(executor.step(), Ok(()));
  assert_eq!(executor.hart_state.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 output_disass<M: Memory>(executor: &mut InstructionExecutor<M>) {
  let mut outputter = InstructionStringOutputter { insn_pc: executor.hart_state.pc };
  let insn_bits = executor.mem.read_mem(executor.hart_state.pc, MemAccessSize::Word).unwrap();
  println!("{}", rrs_lib::process_instruction(&mut outputter, insn_bits).unwrap());
}
Commit count: 0

cargo fmt