RISC-V Emulator part 5: Implementing RVA

This will be a brief post about some design details specific to RVA: Avoiding implementation repetition A lot of instruct instruction do the same thing in 32-bit and 64-bit RVA instructions. To avoid code dumplication, we can template the functions. For example, we can amoaddw and amoaddd this way: template <typename T> { Cpu::reg_name rs1 = decoder.rs1(); Cpu::reg_name rs2 = decoder.rs2(); Cpu::reg_name rd = decoder.rd(); uint64_t addres = cpu.regs[rs1]; T val1 = cpu->bus....

July 15, 2023 · 2 min

RISC-V Emulator part 4: Compiling and running RISC-V binaries

To test out our emulator, we need to write some assembly and compile it. To do that, we first need to get a compiler toolchain. While we can use pre-compiled ones available on brew/apt, I had bad experience with them being improperly configured or had old builds with certain bugs present. Instead, we will build our own toolchain. riscv-gnu-toolchain To build and install the toolchain, we will use riscv-gnu-toolchain. First, clone the repository:...

July 15, 2023 · 4 min

RISC-V Emulator part 3: Instruction execution

In this post, we will start implementing the instruction execution logic. We already fetched the instruction and created a decoder class, now lets tie everything together to ghave RVI fully implemented. Instruction execution Since standardized RISC-V instructions are either 32-bit or 16-bit, we will need to implement two different instruction execution functions. Lets add execute32 inside our cpu class, where we will switch on the opcode and call the appropriate function:...

July 15, 2023 · 4 min

RISC-V Emulator part 2: Instruction fetching and decoding

As a prerequise, download RISC-V Unprivledged Specification from here. At the time of this writing, Volume 1, Unprivileged Specification version 20191213 will be used. Instruction fetching The first step of CPU needs to do to execute an instruction is to fetch it from memory. RISC-V specification standardized instructions are almost exclusively 32-bit, with the exception of RVC (compressed instructions) that are 16-bit. For now, we will only focus on RVI (base integer instructions)....

July 7, 2023 · 6 min

RISC-V Emulator part 1: Getting started

In this post, we will set up the project environment and write the basic code needed to get started. This project will be written in C++, and will be using CMake as the build system. An Ubuntu machine will be assumed for some of the steps, but the steps should be similar for other Linux distributions and macOS. Setting up the project First, get the basic dependencies: sudo apt install build-essential cmake git Then, create a new directory for the project and initialize a git repository:...

June 25, 2023 · 6 min

Writing a RISC-V Emulator that can boot Linux

For the past several months I have been working on a RISC-V emulator, mainly inspired by mini-rv32ima. The goal of my project was to create such an emulator myself, but with some key differences: a 64-bit core instead of a 32-bit one, implemnting the FPU, compressed instructions, and a MMU. The end goal was to be able to boot Linux on it as well as have a graphical output that will be used maily to play doom....

June 25, 2023 · 6 min