M4ZVM, a new modern Z-Machine for the TRS-80 model 4

This is a new(ish), modern polished Z-Machine interpreter for the TRS-80 Model 4 supporting z1-z8* games. It requires a minimum of 128k of memory and is purpose built to take maximum advantage of TRS-80 model 4 hardware including:

  • reverse characters
  • displays accented characters (limited set that exists in hardware)
  • keyboard mapping includes Fn keys, supporting Beyond Zork function key macros
  • renders full 80x24 screen including split screen for Seastalker
  • support for up to 64k Dynamic Memory
  • timed input (interrupt driven)
  • cached Disk I/O
  • support for expanded memory above 128k
  • high speed story execution - faster than the z3 only terp available at the time
  • written in hand crafted z80 assembler
  • debug mode available (can be toggled while in play on an emulator)

There is also a command line switch to optionally enable the Tandy bit, which seemed an appropriate feature for a Tandy machine.
*z6 support is limited and somewhat experimental - excludes mouse,graphics and complex screen operations.

I’ve been developing and updating releases of M4ZVM for some months now, so the code is reasonably well tested, with continued development on minor enhancements, so it’s about time it was announced here. It’s currently at Release 10, which has been used in the Puddlebuid toolchain to add TRS-80 Model 4 to the available platforms for Hibernated 1. M4ZVM Release 11 is undergoing testing and is expected shortly, bringing even more speed and minor features, along with some other minor bugfixes.

I’ve spent a lot of time on optimising the code, so most stories compiled with Inform 6 and earlier are very playable. PunyInform story files will play well, as do the original Infocom games. Specifically on the z6 front, Arthur and Shogun work albeit with some minor screen glitches. Zork 0 and Journey are not playable due to complex screen usage although their z5 early development versions play just fine. Ziptest.z6 also passes (in my opinion anyway) all the non-screen/graphics/mouse tests (disagrees with some WinFrotz results which I’m working through reporting), meaning that the unreleased Milliways as well as the German version of Zork also execute as-is. Inform 7 games will load but I would not call them playable, and they will eventually run out of stack.

The code is based on ZXZVM, and inherits the GPL2.0 license. Some of the updates for speed and minor bugfixes that I’ve made have already been ported back into the core, and more are expected to follow as time allows. So many people to thank, but in particular a shout out to Fredrik Ramsberg for much support on ideas and motivation to keep improving and debugging my code. Z-machine racing is way more fun than I ever expected.

If you are after the binaries and more screenshots, head to:
Full source code and binaries including history are available from:

Comments, feedback, feature suggestions and bug reports are welcome.

A Mind Forever Voyaging
AMFV trs80-2

Beyond Zork
Beyond Zork trs80-0


This is totally cool. I’m going to try it on my real TRS-80…


OK, the code builds and runs on trs80gp. Tomorrow, I’ll try it on a real M4p. Hopefully have a picture.

Can vids be posted here?

Thank you! It would be great to see it in action! I play it on a Model 4p, although with a floppy drive emulator.

I don’t think you can embed a video, but you should be able to link to youtube video.

As an example, here’s a video of M4ZVM rendering Beyond Zork on a trs80gp. I’ve linked to part way through the video after the game has loaded:
Beyond Zork on a TRS-80 Model 4 (emulated) using M4ZVM v10c (no audio) - YouTube

So here are photos running Deadline/z3 and BeyondZork/z5 v60 from a 5.25" floppy disk.

Performance is good. When run from the virtual HD, performance is better than the emulator (!)
Running directly off floppy, performance isn’t bad at all. At least so far in my tests.

5.25" have 180K on them, and can fit M4ZVM as well if the game file is small. eg deadline fits.
Bzork/z5 on its own is 256k.

I discovered, my floppy drive is actually double sided! And formatted it 40 tracks, DD, DS to give 360k.
Then put the game file on it and run from FD.

All seems good!

You might notice this machine has a 3.5" drive too. This is non-standard for trs-80, so i didn’t use this.

Sorry the pictures are poor. I should set up a proper camera for good ones.

If you’d like me to try a particular Z file, let me know.


Thank you so much for the screen shots and feedback. Very nice setup you have there! While I don’t have any specific z games that need testing at this point, any and all bug reports or feature suggestions are welcome.

I have mode the location of the binaries clearer- they are in the zout directory.

In am amusing side story, the reason you notice that it runs faster on the real hardware than the emulator was actually uncovered in my recent optimizing for the upcoming M4ZVM Release 11. While removing some unused code, my code ran slower on the trs80gp emulator depending on how many bytes I removed. You’ll notice that the release notes for today’s v2.4.6 update includes “• Eliminated spurious wait states on $3C00 … $3FFF in Model 4 memory map 2+3.” which was discovered through investigating M4ZVM performance.

1 Like

If you are keen or curious and have some spare time, the latest update is uploaded. I haven’t found any regressions or bugs so far, so I expect I’ll commit the tag as Release 11 soon. If you spot anything feel free to let me know! Binary is in zout · main · sijnstra / m4zvm · GitLab with the full source in the directory above it as usual.

So I found a bug, fixed it, and have now tagged Release 11. You’ll find that apart from some further speed improvements above 10B, it also has some extra tweaks that help Shogun to now have a proper reverse text status line, along with some other minor cosmetic fixes to the input lines for Beyond Zork if you use the function key shortcuts.

1 Like

[Squees at vintage tech!]

This reminds me of a Commodore Pet my dad owned when I was tiny, but it had a tape drive instead of TWO types of advanced floppy drives! And the tiniest keyboard.


I’ve been playing around with this interpreter, and you’ve done a great job. It’s fast, even when dealing with z8 files. But I noticed in my current work in progress and my past game that it doesn’t display the status line properly if there are two. Like this:


The status line is white on black, just like the game text. One status line like Curses works fine, but not with two. It’s not a big deal, but it does look a little strange when the text starts to scroll by.

I just thought I’d let you know. Great work so far!


This is great! I’ve been wondering for a long time about adapting ZXZVM to other machines, in particular ones running CP/M. Did you discover anything useful for adapting ZXZVM to CP/M?


Thank you so much for the kind words as well as the feedback. Much appreciated! I was able to fix the behaviour so that it works as expected now.

And thank you for sharing the game title & version - I was able to track down what was happening. With most games, it was displaying correctly, and with my recent updates to inspect colour change requests it was working even more reliably, even on multi-line status lines. After some sleuthing, it turns out this game behaves different to any I’ve seen before - after selecting the reverse style for the status line, it was changing the font to fixed width. Turns out I was erroneously tuning off highlighting when changing fonts. It’s now updated, so feel free to grab the latest binary from zout · main · sijnstra / m4zvm · GitLab and let me how you go, or if you spot any other strange behaviour!

entangled trs80-3


Thank you so much!

As you can probably guess, I have poured many hours into this project and have certainly learned a lot along the way and I am happy to share anything I’ve learned. This port is actually tailored heavily to the TRS-80 model 4, and requires 128K of memory. It runs on some the native TRS-80 operating systems “TRS-DOS” and “LS-DOS”, so doesn’t use the CP/M BDOS calls. I did actually start with the ZXZVM “Joyce” version which does use CP/M calls and has the terminal control strings laid out clearly, so a custom compile for a specific CP/M platform could work easily enough from that display-wise including some cursor control, although there will be limitations depending on the terminal. A port to CP/M is also on my wish list to do but I haven’t started yet other than some planning. I’ve been focused on getting the most out of this one for now.

The main challenge of CP/M would be the memory footprint. I had 128K to play with, so no problem for me other than having to totally re-write the bank select code used in the other ZXZVM versions. Out of the box CP/M is limited to the 8080/z80 64K memory map if you want to be totally generic. This leaves a few options, one of which someone else has implemented using a page file. I haven’t tried it yet, and I imaging it would be okay if you had the page file in a RAM drive. There’s the source along with a good write-up including some additional considerations at Memotech MTX 512 - Tapeview (primrosebank.net)

The high level dream plan for a CP/M version coming out of my port would include trimming features to make more space, retaining the LRU disk cache as much as possible, and limiting the DynMem available.


You are probably right about the fixed width, but the code looks like this:

style reverse; font off;

So I’m not calling style fixed. I’m also not sure what font off does. I started using it when I wrote Entangled. I don’t know why I added the line, font off.

And I tried out the new version. It works with Entangled and my latest work in progress. Sweet! It’s neat being able to play these games on old computers, using emulators, and seeing it in the proper fonts. The crystal clear displays help too. Thanks again for doing this. It’s a real treat.


Here’s what DM4 says about font:

"font off switches into a fixed-pitch display style. It is now guaranteed that the interpreter will print all characters at the same width. font on restores the usual state of affairs."

This is a bit of an odd thing to do at this point, since the font in the upper window is always fixed-pitch.


Some 8-bit i8080/Z80 CP/M machines can have more than 64K. S100 machines and the P112 immediately come to mind as do other recently designed Z80 CP/M machines. I’m somewhat sure that some of the Kaypro luggables can be upgraded past 64K.

font off compiles as @set_font 4 for V5+. On V3/4 it dinks a header bit: (0-->8) bit 1.

It’s not strictly true that the upper window is always fixed-pitch. (In V3 the status line can be any font, since the game doesn’t do cursor positioning in it.) But in V5 we assume that it is, so font off is redundant there. But it’s not surprising that some code does it anyway, just in case. (There was a lot of “just in case” when dealing with poorly-standardized interpreters in the early 90s.)

1 Like

I guess it really depends on the target machine. Indeed the machines can have more than 64K, however, CP/M doesn’t really have a way to take advantage of it by itself, which is why RAM drive is the most common use of anything above 64K. Anything more than that and some flexible, configurable code to take full advantage of the hardware bank switching would be needed. Certainly doable, just would need to cover:

  • the method for switching a bank in and out - the port number and the data to be sent will vary.
  • the size of the memory that is banked in and out will vary by what the hardware supports. The Joyce version of ZXZVM switches in 16K blocks, whereas in M4ZVM I was limited by hardware to only being able to switch in 32K blocks.
  • there may be limitations of where the memory switches in. I needed to be mindful of where my memory management routines were running as well as the location of the stack pointer as my options were different to that on the Joyce version.

As an extra side note I also needed to turn off interrupt routines while paging the memory in and out to avoid the potential clash of high-memory routines attempting to execute while switched out.

On available memory it also does depend on how early a model you look at. As far as I can tell, Kaypro II was limited to 64K, although the later Kaypro 4+88 had 256K. That’s why I’m thinking for retro machines it might be nicer to limit the Dynmem size (and reduce the list of story files that can run). For more modern CP/M machines with higher clock speeds and well above 128K, including the P112 and many others, paging out to a file in the ram drive would hopefully be fast enough to make it work and be enjoyable.

Version bump to Release 12!

New features:

  • tuning and optimisations
  • a slight increase in disk cache buffer space
  • sentence space implemented to get Shogun to display properly
  • and a new command line switch to optionally turn off sound!
    Updates including source ready to download from sijnstra / m4zvm · GitLab
1 Like

Version bump - Release 13:

Most notable is that I’ve enabled a switch in the source code to compile a cut-down memory map 64K version. This means there are a few of the larger, more epic games that won’t work such as Trinity and Beyond Zork, however, some people never did put that second bank of RAM in their model 4, so this way they won’t miss out on the fun.

; [+] Changes memory map to enable new 64K version (limits which games can work)
;		To select 64K, comment out HighBanks flag in in_zxzvm.inc
; [+] Rewrote scrolling routines to fix cosmetics where upper window > 7 lines
; [+] Use native DOS error messages to improve error message meaning
; [+] Multiple speed improvements across core and routines
; [+] Rewrote save/restore to be faster using LRL 256, including to be backward compatible
; [+] Bugfixes
1 Like