The Oberon 0 compiler I recently wrote (in Python) after following the online Compiler Construction course [1, 2] included much more than a single pass compiler. In the best tradition of such courses based on the work of N. Wirth, the lexer and parser are followed by a code generator that produces actual executables (binary) for a simplified RISC machine of sorts. In this particular case, the RISC machine was based on an imaginary architecture, (almost exactly) in between a MIPS and an ARM 32-bit core. My Oberon 0 project [link] includes therefore also a disassember (see the Decode function in the osg.py module) that helps verifying and debugging the (binary) code produced. Eventually a virtual machine (found in the risc.py module) does execute the code and therefore performes the ultimate test of correctness.
As part of the larger Oberon project, Wirth and his team actually did develop the core into silicon (using an FPGA) and demonstrated an entire system hardware/software/OS based on the Oberon design.
Besides, seeing the Oberon 0 VM running only inside my Mac was not sufficiently rewarding as an experience for me.
I needed to see LEDs blinking! So I decided to transform this virtual machine (written in Python on my Mac) into a virtual machine written in C and running on a PIC on my desk.
Since a PIC16F1716 had been sitting on a breadboard on my desk for the last couple of weeks (I honestly cannot remember why it got there in the first place), I did fire up MPLAB X and thanks to the MPLAB Code Configurator, in a couple of minutes I had a project scheleton up and running. An hour or so later the entire virtual machine was reproduced in all its detail. [link to GitHub repository]
I hope the irony of having an 8-bit microcontroller running a virtual machine designed truly around a 32-bit instruction set won’t escape you?!
Yet, there is nothing wrong with this exercise. A virtual machine is exactly what the name implies: an abstraction and as such it must transcend architectures, hardware implementation details, and performance factors. After all that is exactly the reason why we do create them!
The exercise is no different than my previous Z80 (Spectrum) virtual-ization on a PIC32 [project link] or the Pymite VM running (Python byte-codes) on a PIC24/PIC32 [link].
For maximum convenience, I ended up connecting the PIC microcontroller to an MCP2221 breakout board (serial to USB bridge) and from there I had it download code and communicate back to my Mac to test and debug extensively the design.
Sure enough, I got my blinking LED: “Hello (Embedded) World!”