An (almost) purely functional virtual machine for emulating the MIPS Architecture. I wrote this as a way to review the code I had written for a university class. Since I couldn’t use the provided VM after the semester finished, I decided to make my own VM.
However in addition to writing the VM, my other goals were to use this as an opportunity to learn the Racket programming language better, and to think about programming in as purse of a functional way as possible.
$ racket main.rkt --twoints examples/collatz.mips Enter value for register 1: 0 Enter value for register 2: 121 Running MIPS program. MIPS program completed normally. $01 = 0x00000000 $02 = 0x00000001 $03 = 0x0000005f $04 = 0x00000000 $05 = 0x00000000 $06 = 0x00000000 $07 = 0x00000000 $08 = 0x00000000 $09 = 0x00000000 $10 = 0x00000000 $11 = 0x00000001 $12 = 0x00000002 $13 = 0x00000003 $14 = 0x00000000 $15 = 0x00000000 $16 = 0x00000000 $17 = 0x00000000 $18 = 0x00000000 $19 = 0x00000000 $20 = 0x00000000 $21 = 0x00000000 $22 = 0x00000000 $23 = 0x00000000 $24 = 0x00000000 $25 = 0x00000000 $26 = 0x00000000 $27 = 0x00000000 $28 = 0x00000000 $29 = 0x00000000 $30 = 0x01000000 $31 = 0x8123456c
I say this is “almost purely functional” because in the end I cheated a little: On command line initiation, a few global flags are set to enable or disable various pieces of functionality (for example, more verbose logging). While this is not necessarily the best design for long-term sustainability, it was a compromise I made in order to write the feature at all.
Unlike creating a site in Django, or working on a school project, there’s no predefined structure that I could follow when programming it. This wasn’t a large barrier to starting the project, however after completing it, I came back a few times to see if I could better structure the project.
I wanted to test my code, however by leaving that to an afterthought, it became quite challenging. Following the above structural issues, in restructuring my code into testable pieces I found it broke down nicely along divisions that I had ignored before.
It’s significantly faster than I expected. Benchmarking on my laptop, the first iteration ran at around 200kHz, which seems pretty fast for an interpreted language.
I’m also pretty happy with how the code turned out. It’s fairly tight and functional. It could definitely be improved in a few ways, but for my first non-school functional programming project, I think it’s pretty darn good.
In Racket, you can define contracts for your code, creating a programmatic guarantee that your inputs and outputs will conform to some shape. However, they’re just another tool. When I first discovered them, I went overboard and gave everything a contract. Of course, that ended up being a huge pain to fight with any time I refactored anything, and so learned to use them sparingly.
Every time you think you’ve finished writing the program, you think of another way to make things even simpler. At some point however you have to say enough is enough, before you throw away a lot of time for little in the way of benefits.
While the project works, there’s all sorts of small pieces that I could add to it. Some that I’ve thought of are:
If you’re interested in looking at the source for UWME, you can find it on GitHub.