Q3VM for the eZ80

18 Aug 2025

Recently, I watched some videos on the YouTube channel, Tariq10x, specifically his reviews of Wolfenstein, Doom, and Quake code. It’s an excellent code analysis trilogy. I have included links to the videos at the bottom of this post.

His review of Quake, in particular, mentioned something I was only vaguely aware of before – ID’s development of a Virtual Machine system within the game platform.

I started to think about how a VM within my eZ80’s firmware might be an interesting thing to develop. With only 128K ROM and 4K RAM – there is only so much we can fit in there. Could a VM help memory usage?

A VM for some of the code might be able to achieve better memory usage than full native code. (The assembly code generated by the C compiler is not very efficient.) Could I move my USB driver code (all written in C) to a VM environment?

So when I found the q3vm fork by Jan Zwiener at https://github.com/jnz/q3vm, I started to think about using this VM for my eZ80 firmware.

The q3vm project contains three main parts:


Q3VM’s main goal was portability - to enable game devs to create mods that will run on all platforms. It’s not trying to be super performant - as it will call out to the host for all performance critical operations.

With the hosting code (vm.c) written in C89 version of C - same as Zilog’s C compiler - it seemed like it may be possible to host the VM on the eZ80.

The Q3VM solution is quite small - compared to other so called small VM. (I have previously considered things like Lua - which I might revisit - but its smallest size is still larger than the 128K ROM.)

There were a few things I noticed, that needed further consideration:

  1. vm.c/vm.h are quite small, but its current process is to copy all of the bytecode image into RAM - even readonly segments for code and constant data. As our eZ80 only has 8K of RAM, with some of that already allocated, the memory model of the VM would need to be modified.
  2. The LCC compiler is only C89 compliant - that’s ok - so is the Zilog ZDS compiler!
  3. The LCC compiler’s int type is 32bits - it has no support for eZ80’s unusual 24bit integer.
  4. Addresses/pointers are also 32 bits wide - a bit of an overkill for this little CPU with only a 24 bit address bus.
  5. The memory layout of the segments is not what I would have expected - it is CODE -> DATA -> LIT -> BSS (BSS includes space for the stack). DATA is the initialised variables that need to be copied to RAM. LIT are the readonly bits (string constants etc). As mentioned in point 1, this needs to be rejigged.
  6. The CODE and DATA segments have their own address spaces. The code can not be mutated (despite being copied into RAM) – data writes are always directed to the DATA/BSS segments address space.
  7. I am not so interested in the portability capability - I would prefer a solution that supports 24bit integer - as this would make integrating with native code much easier.

I have been hacking at this for a bit - and so far have managed to get a highly modified version of the VM Host running within the eZ80’s firmware.

Some key points of the solution so far are:

My ultimate goals are:

  1. Move some of the USB driver code to run within the VM.
  2. Port some of the V99x8/HDMI driver code to also run within the VM.
  3. Once I get both USB and Video code within the firmware - I will be able to have a system that can boot into its own ‘CRT’ mode - no need for a serial connection.
  4. Provide hooks for applications to also host ‘VM’ code.

But this is still very experimental. I have yet to confirm:

  1. Will it actually save memory? – after adding the overhead of the vm.c code - will it be worth it?
  2. Will performance be adequate?
  3. Can I actually achieve the required functional changes? (eg 24 bit integers).

Time will tell…..


Tariq10x’s ID Trilogy:

Previous

Next