perilus, Part Five2026-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.