Q3VM for the eZ80 Part 2

28 Aug 2025

As per my previous post, I have been working on porting and exploring q3vm for use within the eZ80’s firmware.

I have a new repo hosting the code at https://github.com/dinoboards/q3vm

And, oh my - I seemed to have created a lot of commits!

343 commits added to upstream

a few steps back, and a few more forward. No artificial colours, artificial flavours or artificial intelligence included.

At this stage, I have manage to host a small piece of test code within the vm, interpreted by the eZ80’s firmware. The vm consumes about 5.5K of ROM storage - not bad. Not sure yet of performance nor about how large the actual bytecode images will end up being.

It has taken quite a bit of effort to port the code base, as I didn’t want to just use the q3vm as is, but change a few specific things.

First let me just recap a bit about the q3vm and how it works.

So what is q3vm? Here is how the upstream project describes it:

Q3VM is a lightweight embeddable interpreter/Virtual Machine (VM) for compiled bytecode files .qvm based on good old C-language input files (.c). A complete C compiler to generate (.qvm) files is included (LCC). The interpreter is based on the Quake III Arena virtual machine (hence the name q3vm) but the interpreter is not tied to Quake III Arena.

So its a way to compile code and produce a binary file - like most compilers. But the binary file is not an executable or machine code image, ready for execution on your favourite CPU, but rather, a machine code for a virtual CPU - a Virtual Machine if you like.

This bytecode needs to be ‘interpreted’ by our favourite CPU - so its not going to be the fastest way to execute code. So why do it this way? There are many reasons for this model. For me, the bytecode has the potential to use less actual memory for a given piece of code. This could help as I try to squeeze more code into my favourite CPU’s on chip 128K flash ROM.

‘Virtual Machines’ have been used for quite some time to solve memory, portability and other issues. Discussion of vm in general and their history is a topic for another day.

As part of the porting process, I have made a few changes to the implementation, including:

  1. The default int type change from a traditional 32 bits to 24 bits; aligning with eZ80’s CPU 24 bit registers.
  2. Lots of new and many changed opcodes within the VM – the bytecode is not compatible with the original q3vm - but thats ok.
  3. Optimisation of vm.c and vm.h for Zilog’s ZDS eZ80 compiler.
  4. 4 byte alignment removed and all code and data defaults to single byte alignment - the advantage of 8bit CPUs!
  5. c pointer widths are now 24 bits.
  6. The code and readonly memory is no longer copied to RAM. Reads are directed to the ROM image.
  7. Refinements to the trace output when debugging mode is enabled.
  8. New conditional compile define, MEMORY_SAFE, to enable memory access safety checks.
  9. New command line option q3asm -l to produce a listing file.

Producing a bytecode image file

Creating the bytecode image to feed to the q3vm interpreter is achieve with the following process:

  1. Use lcc to compile C89 .c code files to IL text representation .vmasm files.
  2. Use q3asm to translate and link a set of .vmasm files to a binary bytecode .qvm file.
  3. Embed vm.c and vm.h into a host C application to interpret/execute the bytecode.

Executing the bytecode

Once the bytecode binary data has been produced, it can then be executed by the q3vm interpreter. The process for executing code within the q3vm is:

  1. Embed the binary data into the eZ80’s firmware ROM image.
  2. Reserve a small amount of on-chip RAM
  3. Incorporate the vm.c and vm.h source files into the firmware’s code base.
  4. Updated the firmware to initialise the q3vm
  5. And then direct calls to vm.c to load and execute functions within q3vm.

Next step

The next step is to port some real useful code to run within the VM. I have graphics driver code I want to move over and I also want to explore moving some of the USB driver code over.

Now the fun begins….

Previous