The Inextensible RISC-V Emulator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
John Jekel 5f1c791372
Bump version number
5 months ago
.github/workflows Fix remaining unit tests, we're passing everything now! :) 6 months ago
include Finish formatting fixes in IRVE (will need to fix rvsw at a later date) 5 months ago
lib Begin working towards support for RISCV architectural tests 5 months ago
rvsw Improve IRVE loading facilities 5 months ago
scripts More riscvof work 5 months ago
src Fix comments in rust source files 5 months ago
templates Fix comments in rust source files 5 months ago
tests More riscv-arch-test progress 5 months ago
.gitignore More work on riscvof 5 months ago
.gitmodules Now things should be working 6 months ago
CMakeLists.txt Bump version number 5 months ago
Doxyfile More documentation 6 months ago
LICENSE Add a LICENSE file 7 months ago
Makefile Make progress with the GDB server 6 months ago
README.md Remaining README tweaks for now 5 months ago
irve More main.cpp vs lib seperation 7 months ago
irvegdb Make progress with the GDB server 6 months ago
logo.jpg Add a fancy logo :) 6 months ago

README.md

irve

IRVE Smoke Tests IRVE Unit Tests IRVE Integration Tests IRVE RVSW Tests

The Inextensible RISC-V Emulator

IRVE was intended as a "quick and dirty" emulator capable of running the Linux kernel. Since then it has become much more!

Lore

IRVE is the first step on our journey within an overarching project called AGI, the Angry Goose Initiative.

The plan is to use it to better understand the RISC-V architecture (with a focus on Volume 2 in particular). Once we do, we can move on to a hardware implementation in SystemVerilog called LETC!

If you're reading this, as of writing we're in a transition period between wrapping up IRVE and beginning LETC. Exciting stuff!

We do a lot of our planning in this semi-coherent Google Doc if you're interested!

(Also at some point we split IRVE test code off into a hardware-independent repo called RVSW).

Keep in mind that IRVE is slow, managing only about 10-20MHz on a modern Ryzen system even in release mode. The purpose of this was to learn the architecture, not knock the socks of QEMU or anything :)

Okay enough backstory, I want to try this out!

Awesome! We'll walk you through the steps!

Get all the things

We highly recommend doing all of this from a Linux system. We have had some success on macOS, but with the RISC-V toolchain in particular you might encounter issues.

Ensure you have a modern G++ compiler installed than supports C++20. (Clang++ works too with some CMake variable tweaks).

You'll also want a cross compiler if you actually want something to run on the emulator (though you don't need it for the emulator itself). We use riscv-gnu-toolchain for this. It's imperative that you build the Newlib version (since the RVSW test programs don't use dynamic linking as they are bare-metal). Also, since IRVE implements RV32IMA (and some other smaller extensions), you must append --with-arch=rv32ima and --with-abi=ilp32 to the ./configure command.

Don't forget to add all of the riscv32-unknown-elf-gnu-* binaries to your PATH too!

Lastly, in a directory of your choice, clone this repo:

$ git clone https://github.com/JZJisawesome/irve.git
Cloning into 'irve'...
remote: Enumerating objects: 4224, done.
remote: Counting objects: 100% (659/659), done.
remote: Compressing objects: 100% (277/277), done.
remote: Total 4224 (delta 416), reused 476 (delta 377), pack-reused 3565
Receiving objects: 100% (4224/4224), 931.98 KiB | 1.75 MiB/s, done.
Resolving deltas: 100% (2891/2891), done.
$

With that, you should be set to continue!

Compile all the things

We use CMake as our primary build system to compile both libirve, our two emulator frontends irve and irvegdb, and all of our RISC-V test code!

Step 0: Make a build directory in the root of the project with mkdir build

Step 1: Go to the build directory with cd build

Step 2: Do cmake .. to setup CMake (or cmake -DCMAKE_BUILD_TYPE=Release .. for a much faster release build)

Step 3: Perform the compile with make. For speed, you should probably do make -j <Number of threads here> instead to use all of your host's threads

NOTE: If you just want to compile irve (ex. if you don't have a cross compiler), do make irve instead.

Run all of the things

The irve front end (the one you likely care about) is placed in build/src/irve, but the symlink in the root of the project already links to this for your convenience.

Every argument to irve is a binary file to load into memory. Files containing a .vhex8 suffix are assumed to be 8-bit-wide Verilog hex files, and are loaded into memory starting at 0x00000000, unless the addresses in the file (@xxxxxxxx) specify otherwise. At the moment, every other file extension is assumed to be a flat binary and is loaded at 0xC0000000.

Assuming you've build all of the RVSW testfiles, you can run a test program like hello_world like this (from the root of the repo):

$ ./irve rvsw/compiled/src/single_file/c/hello_world.vhex8 
IRVE> Starting IRVE
IRVE>  ___ ______     _______ 
IRVE> |_ _|  _ \ \   / / ____|
IRVE>  | || |_) \ \ / /|  _|  
IRVE>  | ||  _ < \ V / | |___ 
IRVE> |___|_| \_\ \_/  |_____|
IRVE> 
IRVE> The Inextensible RISC-V Emulator
IRVE> Copyright (C) 2023 John Jekel and Nick Chan
IRVE> See the LICENSE file at the root of the project for licensing info.
IRVE> 
IRVE> libirve Version 0.7.0 Commit 5893f445e8638dc6015d3a9731ad45db78310698
IRVE> libirve built at 21:16:56 on Jul 27 2023
IRVE> irve executable built at 21:16:57 on Jul 27 2023
IRVE> ------------------------------------------------------------------------
IRVE> 
IRVE> 
IRVE> Fuzzish Build: Set seed to 1690508132
IRVE> Initializing emulator...
IRVE> Loading memory image from file "rvsw/compiled/src/single_file/c/hello_world.vhex8"
IRVE> Initialized the emulator in 1489348us
IRVE> RV: "Hello World!\n"
IRVE> Emulation finished in 1499us
IRVE> 1574 instructions were executed
IRVE> Average of 1050033.355570 instructions per second (1.050033MHz)
IRVE> IRVE is shutting down. Bye bye!
$

Or, to run an S-mode test program, specify the OGSBI binary first:

$ ./irve rvsw/compiled/sbi/ogsbi/ogsbi.vhex8 rvsw/compiled/src/single_file/cxx/hello_cxx_smode.vhex8 
IRVE> Starting IRVE
[...]
IRVE> Initializing emulator...
IRVE> Loading memory image from file "rvsw/compiled/sbi/ogsbi/ogsbi.vhex8"
IRVE> Loading memory image from file "rvsw/compiled/src/single_file/cxx/hello_cxx_smode.vhex8"
IRVE> Initialized the emulator in 1526844us
IRVE> RV: "OGSBI> OGSBI is starting up...\n"
IRVE> RV: "OGSBI>   ___   ____ ____  ____ ___\n"
IRVE> RV: "OGSBI>  / _ \ / ___/ ___|| __ )_ _|\n"
IRVE> RV: "OGSBI> | | | | |  _\___ \|  _ \| |\n"
IRVE> RV: "OGSBI> | |_| | |_| |___) | |_) | |\n"
IRVE> RV: "OGSBI>  \___/ \____|____/|____/___|\n"
IRVE> RV: "\n"
IRVE> RV: "OGSBI> RVSW's First SBI Implementation\n"
IRVE> RV: "OGSBI> Copyright (C) 2023 John Jekel and Nick Chan\n"
IRVE> RV: "OGSBI> See the LICENSE file at the root of the project for licensing info.\n"
[...]
IRVE> RV: "OGSBI> Function: sbi_debug_console_write()\n"
IRVE> RV: "Hello World from hello_world_t::hello_world_t()!\n
[...]
IRVE> RV: "OGSBI> LEGACY Function: sbi_shutdown()\n"
IRVE> RV: "OGSBI>   Shutting down, au revoir! ...\n"
IRVE> Emulation finished in 34219us
IRVE> 55761 instructions were executed
IRVE> Average of 1629533.300213 instructions per second (1.629533MHz)
IRVE> IRVE is shutting down. Bye bye!
$

Run the Linux kernel

TODO explain how to compile and configure the kernel

TODO explain how to run both the M-mode and S-mode kernel by using nommulinux or ogsbi and then specifiying the path to the kernel Image

Info About the IRVE RISC-V Environment / Capabilities

This has been moved to our Google Doc!

How to cross compile manually

Not recommended for beginners. This README section may be a bit more rough than others due to being more of a braindump by me during the debugging process.

Assembly

Step 1: Assemble the file like this: riscv32-unknown-elf-gcc -march=rv32ima -mabi=ilp32 -ffreestanding -nostartfiles -static-libgcc -lgcc -mstrict-align -T path/to/irve.ld path/to/your/assembly_file.s

BE CAREFUL IF YOU USE THIS COMMAND: riscv32-unknown-elf-as -march=rv32ima -mabi=ilp32 path/to/your/assembly_file.s It does not link the assembly, so references (like to symbols or jump targets) may be unresolved.

C code

Step 1: Do riscv32-unknown-elf-gcc -march=rv32ima -mabi=ilp32 -nostartfiles -static -static-libgcc --specs=nosys.specs -lc -lgcc -mstrict-align -T path/to/irve.ld path/to/crt0.s path/to/your/remaining/c/files/here

NOTE: Software floating point, other missing CPU features will be emulated by libgcc (you won't have to do anything)!

NOTE: The C standard library will be available, BUT since we are using --specs=nosys.specs, you will have to implement certain "system calls" for it in order for ex. printf to work.

If we used --specs=nano.specs or others, more would be implemented for us, but Newlib (the c standard library implementation for embedded systems) dosn't know how to use IRVE_DEBUG_ADDR

NOTE: To implement these functions, this may come in handy: https://interrupt.memfault.com/blog/boostrapping-libc-with-newlib#implementing-newlib

Making a .vhex8 file

Step 2: Objcopy the resulting a.out file to Verilog hex file with riscv32-unknown-elf-objcopy ./a.out -O verilog path/to/result.vhex8

What's all this I've been hearing about XRVE?

Originally the plan was to write an emulator in Rust called XRVE: The eXtensible RISC-V Emulator.

I fr***ing LOVE Rust, but just wasn't up to fighting the borrow check this time around.

At the moment, the plan is to do XRVE after LETC, though it likely would be seperate from AGI and quite a while in the future.

In the end I think it was good to do it this way as, now that we've experimented with how to best lay out things for emulation in C/C++, we can better plan out the XRVE Rust code base in the future!

Automated Testing

We use Github Actions for our default IRVE configuration.

Additionally I have a private Jenkins setup that tests some other configurations automatically (ex. with Rust enabled). I run my Jenkins agents on several University of Waterloo engineering servers. It's great having access to those computing resources, so to whom it may concern, thanks a ton!

Licensing

IRVE code

See the LICENSE file for more info

Other code

xrve

Developed alongside/before/after but mostly after eventually IRVE (that was a mouthful)

Licensed in the same way :)

rv32esim

Based in part on JZJ's old rv32esim

I (John Jekel) freely release that old code under the MIT License too!

Nick's Old Emulation Code

This served as a good base for parts of IRVE. Thanks Nick!

jzjcoresoftware

MIT License

Copyright (c) 2020 John Jekel

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Anything else

Any other bits of code from other places that didn't make it here will recieve attribution alongside where they're used! :)

IRVE - "Working our way up to stuff!"