↖️ Blog Archive

perilus, Part Five

Bradley Gannon

2026-02-28

TL;DR: perilus now supports 34 of the 42 instructions in the RV32I set. The remaining instructions are jalr, lui, auipc, and all B-types except beq. Code is here.


My progress this week is mostly uninteresting—kind of like my recent piano progress—because a good deal of it has to do with refactoring tests and scrutinizing generated waveforms. I only had to make minor extensions to the existing Harris-like design to add support for many more instructions. The ones that remain will require a little more thinking, but in general this processor is shaping up nicely. My first goal for next time will be to complete the RV32I set. Then I’ll make another pass through the test suite to clean up TODOs and try to find obvious logic bugs. Maybe I’ll add another short program test that uses more instructions.

But after that’s all done, I have a more ambitious idea for how to continue. I could move on to improving performance—probably by adding a pipeline—or starting to add support for an instruction set extension, but I think it would be much more fun to add some memory-mapped I/O (MMIO) to this system. A UART peripheral would be especially neat because I could use it to build a basic REPL. I was recently reminded of the existence of FORTH, which I think would be a perfect fit for this system. If I can build a small FORTH kernel in RISC-V assembly that uses the MMIO UART, then I can use it to start building up a FORTH dictionary and writing more interesting programs. All I’d really need is a way to define new words (typically the : word in FORTH) and ideally a way to dump the dictionary to the UART so I can save it elsewhere. I’m sure there’s more to it than that, but it seems like an elegant approach with a high fun:pain ratio.

To make this work, I’ll first need to set up a “free-standing” simulation program with Verilator. The Chisel tests I’ve been running until now use Verilator internally, but this isn’t suitable for the open-ended simulation I want to do with arbitrary I/O. The Chisel tests are also quite slow (dozens of seconds for the one test program I’ve written, giving maybe a few cycles per second), and I’m hopeful that using Verilator directly will be faster. If I’m wrong and it’s too slow to use, then I’ll have to shelve this idea for now. Verilator takes the Verilog from Chisel and converts it into C++ source code, which I can then compile into a binary that I write to provide the bridge between stdin/stdout and the virtual UART.

As for the UART itself, it’ll be its own module in the Chisel code and will probably end up being a few parallel/serial converting shift registers and a bit of sequential logic. The main processor will need some minor changes to support MMIO, but I don’t anticipate this being a big problem. I’ll want to create a memory map table somewhere so I can keep the addresses straight as I potentially add more peripherals.

I definitely won’t finish this UART piece next time or even get that far down the path, but within three or four project periods I’d like to at least be able to run a program that simulates perilus, type some characters, and have some software in the simulator echo them back to me.