62 lines
1.9 KiB
Markdown
62 lines
1.9 KiB
Markdown
# A simple RISC-V emulator
|
|
|
|
This is a toy emulator for RISC-V, made for educational purposes.
|
|
The goal is to have a base rv32i instruction set (the bare minimum) plus a M-extension for division and multiplication. It is capable of running normal ELF binaries produced by compiling C programs with GCC. It also has support for attaching the GDB debugger to the GDB stub port, so you can debug your programs running in the virtual machine.
|
|
|
|
The code is small and compact on purpose, to make the implementation easy to understand.
|
|
|
|
## Compiling and running
|
|
|
|
You'd need [nix package manager](https://nixos.org/) in order to build the project. This is because installing cross-toolchain to compile an example project is difficult, and I don't know of other ways except nix that make it easy.
|
|
|
|
If you don't have it, install it like this:
|
|
|
|
```sh
|
|
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
|
|
```
|
|
|
|
Now, to build the emulator:
|
|
|
|
```sh
|
|
nix develop
|
|
|
|
eval "$configurePhase"
|
|
ninja
|
|
```
|
|
|
|
As a result you should get an executable called `rve`
|
|
|
|
## Cross-toolchain and an example program in C
|
|
|
|
There is an example program which you can compile. It requires some custom toolchain so currently not built with CMake. To compile it:
|
|
|
|
```sh
|
|
cd example
|
|
make
|
|
```
|
|
|
|
As a result, you'll get an `example` binary. To execute it:
|
|
|
|
```sh
|
|
./rve ../example/example
|
|
```
|
|
|
|
The expected output of the example program is `40320`.
|
|
|
|
## Debugging programs under GDB
|
|
|
|
The virtual machine contains an implementation of GDB stub protocol. To run the program in debug mode, execute:
|
|
|
|
```sh
|
|
./rve --debug ../example/example
|
|
```
|
|
|
|
The program would load, and stop at first instruction. It will then prompt you to connect the debugger.
|
|
Then run `riscv32-none-elf-gdb`, and in the gdb prompt, type:
|
|
|
|
```
|
|
file ../example/example
|
|
target remote :1234
|
|
```
|
|
|
|
From now on, you can set breakpoints, examine variables, registers and memory as you would expect under GDB.
|