Sunday, 15 June 2025

A ZX81 game on a ZX81 emulator on a Jupiter Ace emulator on a Windows emulator

When I started working on ZX81 BASIC for the Minstrel 4th, I had a fairly clear idea of what I wanted to get working, and also what I did not expect to work.

As is often the case, my target was to get 3D Monster Maze working. I knew that would require slow mode, and that was going to be a challenge, but I thought that should be achievable.

I knew that games that use various high resolution graphics techniques on the ZX81 were not going to work. The display was generated in a such a different way, it was not going to be transparent, if even possible at all.

When I got it working, I went through the list of games I expected to work, and they all did, with one exception, Tut-Tut. I did not understand that, it _should_ have worked.

It's sequel, Minoss Knossos worked fine, and many similar games also worked, but Tut-Tut didn't.

What would happen is the text of the title screen would start to appear, and then the screen would be overwritten with a repeating pattern and it would just lock up.

I needed to debug what was going on to try to find a solution, either:

  1. Fix the ROM code so the original game could run unmodified
  2. Produce a custom build of Tut-Tut that would run

Ideally option 1, but option 2 if necessary.

A great option for debugging things like this is the EightyOne emulator. This can emulate the ZX80, ZX81, ZX Spectrum, Jupiter Ace and many variants and similar systems.

I had been able to use it to debug the ZX80 BASIC for Minstrel 4th.

That is running with the hardware set for a 48K + 3K Jupiter Ace, and the 8K Ace ROM replaced with the new one ZX80 for Minstrel 4th ROM.

The ZX81 version wouldn't work directly for a couple of reasons.

The Ace ROM is 8K, so it is easy to swap that for another 8K ROM.

The original ZX80 ROM is 4K, so that left 4K for the new display code and LOAD and SAVE functions, which was more than enough space.

The original ZX81 BASIC ROM is already 8K, and I needed to add some functions. I was making use of the extra 5K ROM I had cheated out of the Jupiter Ace memory map for the Minstrel 4th.

The 5K is in an area where the Font RAM is write-only, so nothing would happen when you read it, and also an area where the base 1K of RAM is mirrored 3 times, and I don't think I found anything which needed the mirrored versions.

That fitted quite neatly, if you write to $2800-2FFF, the font RAM is written. If you read from $2800-2FFF, you get the extra ROM.

That is understandably not supported in EightyOne. To get around that, I tried an alternative build of the ZX81 8K ROM by taking out the trigonometry functions that take a lot of space and were not required for 10 PRINT style programs.

That left enough space to add the new display routines in to gap where the trig routines were.

I tried that, but it didn't work. I wasn't sure why, at the time I think I had seen it going into the floating point number routines and assumed I had cut out something it needed.

By that point, I had the full 8K + 5K ROM working on real hardware, so I didn't spend any more time on the trig-delete version.

But now I need to do some debugging, so time to revisit this.

The EightyOne project is open source, so I thought I could add in support for the extra ROM space.

My results vary with building open source projects, so lets see how I get on with this one.

Oh, OK, it's built using Borland C++ Builder. Wow, that used to be my job for a couple of years, Delphi and C++ Builder, but I don't think I have touched either for about 20 years.

The project documentation was excellent. There is a lot to do to setup the build environment and various dependencies, but it covered all the steps in detail, and it all worked.

The project successfully complied first time. Very impressed. Credit to Paul Farrow for that.

Now that I had it building, time to adapt the code. Adding the 5K was slightly complicated by the way the memory is arranged, there is a 64K array covering the whole address space and the ROM is loaded into it, and optionally it can be made writeable.

On the Jupiter Ace, the various disparate sections of ROM and RAM are all part of this same memory array, but I need to have writes going to font RAM, and reads coming from the ROM for the overlapping section.

The easiest option seemed to be creating a separate array for the font RAM, as that is only used in the memory write routine and screen draw routines, so it was easy enough to change those.

With that change and the code rebuilt, I was able to start testing, I got the initial banner, but then the screen went off.

The banner routine is in the extra ROM, so that is apparently working. It took me a while to figure this one out. Looking at the memory monitor, I saw that it had written some extra characters after the last line. I had miscounted and it was copying an extra line. (I think I had it correct originally, but it got set one off when I was trying to optimise that code).

It shouldn't make any difference, and indeed it does not on the Minstrel 4th hardware, as this is running fine on that.

The Ace has a requirement that the byte directly after screen RAM, $2700, should be 0. The Ace hardware uses this as a sort of null terminator. (it is also used by the optional colour hardware to control a latch if a value > $7F is written there, which was was happening here)

The Minstrel 4th does not care about that byte, so does not check it.

When I fixed that, I got a K prompt, and it was apparently working until I tried to type a line of code.

Slightly odd, it sort of rolled up like it does on the ZX80 and then locked up? I wouldn't expect the Ace to do that, it should always generate a stable display.

It took me a while of debugging and trawling through code to find it, but I finally spotted some code in the emulator which detected the start of a SAVE, when it hit certain addresses it would start recording, and would duly stop drawing the screen to make sure that went as planned.

The code in those locations in the ZX81 ROM was actually part of the floating point number parser, so when it hit that point, the emulator would think a SAVE was happening and start to process that, including stopping the display and jumping over some code.

I temporarily commented out that checks and that fixed it.

That is probably why the trig-delete version of the ROM was failing previously.

OK, next is LOADing files. I expected this was going to be tricky, as it was designed to load Jupiter Ace files, although it did support ZX81 .P files in ZX81 mode.

I wonder if it will just work?

Can't hurt to try.

It did not initially work, but I tried turning off turbo load and auto load and playing it in real time.

No way.

Well I'll go to the foot of our stairs.

So that is the unmodified ZX81 version of 3D Monster Maze running on ZX81 BASIC for the Minstrel 4th running on a Jupiter Ace emulator running on a Windows 7 emulator running on a Linux PC.

Very impressive that the emulator will do that without any idea that anyone would ever had a need to load a .P file into a Jupiter Ace.

Time to give Tut-Tut a go.

Ah, I guess that is good. It does the same thing as the real Minstrel 4th hardware. The number of letters it prints before locking up seem related to how fast it runs, I found a line in the Z88DK code which might explain that - from gen_tv_field.asm "ZX80 (and ZX81 in FAST mode) trick to try to keep the display stable. This subroutine should be called in theory after every 1475ms".

It starts to print the credits screen, that should say "ZX81KEYBOARDADVENTURES", then it gets overwritten by a repeating pattern.

Then it just locks up.

I didn't know why this happens, it's sequel Minoss Knossoss works fine, and that is also built using Z88DK.

Right, now I can debug this. Wish me luck.

Many thanks to David @ZX81KeyboardAdventures for help with this and supplying the source code so I could see what was going on and build test versions.

Or at least I could if I could get the compiler for it (Z88DK) to build......... I try not to say anything negative, so I will just repeat how well documented the EightyOne code was and how setting up the build environment and all the dependencies for EightyOne worked first time.....

Anyway, I finally gave up and downloaded a Z88DK Windows pre-built binaries package.

I was then able to build versions of Tut-Tut and Minoss to try to see what the trigger was.

It didn't take long. It was printf. That was not used in the later game, but was one of the first things in Tut-Tut.

I got it down to a test program with just a main function with a single printf and then a while loop and it broke in the same way as the full game had.

That simple program was almost 4K - there was a lot of library code along with the printf.

I stepped through the code, trying to see what was the problem.

Then I spotted it. The code was reassigning the IY register for it's own use.

On the ZX81, this is set to $4000, the base of RAM, and used to simplify access to the system variables which are stored there.

One such access was in the display routine.

BIT     7,(IY+$3B)

This is doing a test of bit 7 of the CDFLAG variable at $403B.

That is fine as long as IY stays at $4000 as it normally does, but the code used by printf was changing it, so that line was actually testing bit 7 of the wrong bit of memory (sorry, the wrong byte of memory).

Based on that, it was thinking it was in FAST mode, rather than SLOW mode.

That meant it would go on to the display routine, and not POP the saved registers off the stack.

Next time around the loop it would again test the wrong location, and leave another 12 bytes on the stack.

And so the stack would go downwards through all of RAM, with a repeating pattern of 12 bytes (4 register pairs and two return addresses).

I should have recognised that, seems obvious now.

I replaced that with two instructions that did the same thing, but with a hard coded address and so no reliance on IY (and in 5 bytes and 21 cycles instead of 4 bytes and 20)

LD      A,($403B)

BIT     7,A

Let's see if that helps.

No way.

You're kidding me.

That was it.

That was what was causing the problem.

I have expanded one of the flowcharts from the previous post.

The test in the IRQ handler (right) was working correctly, and pushing the registers onto the stack each frame, but the test in the display routine (left) was looking in the wrong place and going down the wrong path and not poping the registers back off the stack. So the stack just kept growing and growing until it had taken over the world. (Well, until it filled all the RAM.)

Side note: the screen looks a little grey, that is because it is running in inverse video mode. In ZX81 mode, it is non-inverse, so has a bright white background.

The Jupiter Ace is meant to be white on black.

So the choice is yours.

Well, it would be if I were to publish this. It would be nice to add the Minstrel 4th option to the official build of EightyOne, and maybe the Minstrel 2 and 3 as well, although I don't know how much use that would be other than to a couple of people working on the ROMs.

But that's not the end, the final thing to test the full experience, loading Tut-Tut from the ZX81 tape into a Minstrel 4th?

OK, here goes.

After a little fiddling with the levels, I got it loading, the countdown helps to see it start moving.

Almost there.

Great, that's working nicely.

A ZX81 game, loaded from tape into ZX81 BASIC for Minstrel 4th.

More updates

I have tweaked a few more things. I had previously displayed the "mists of time" screen whenever FAST mode was enabled, but I have now changed that to only when it is activated using the "FAST" command.

That should be less obtrusive in the short bursts when processing a line of code being added, but still be there to cover the big gaps like generating the maze in 3D Monster Maze or drawing the map in Perilous Swamp.

By the way, when it says "TO START PRESS ANY KEY"....

It actually means "PRESS ANY KEY EXCEPT SPACE BECAUSE THAT IS BREAK AND IT WILL STOP THE GAME", but I guess they didn't have enough space to fit that all in.

Still, it allows you to have a look at the game in BASIC, something I spent a long time doing back in the day.

And since it is BASIC, you can just start it again with RUN.

You might think the player (the X in the top left) is trapped there, but in this game, you can move diagonally.

Still didn't help me rescue the Princess though. Maybe next time.

Another issue I was able to track down with the debugging environment was an occasional glitch, where the LOADING .... box is not display, just the countdown.

That was due to drawing that before switching to FAST mode, so occasionally the screen would be redrawn after the LOADING box had been drawn.

That has also been fixed. It only seemed to happen in NTSC mode. I wouldn't recommend using the ZX80 or ZX81 ROMs in NTSC mode anyway. The timing is different, and most software will be expecting the PAL 50Hz timing.

The big delay at the end of the display routine was tweaked to make it match 100% PAL ZX81 speed - at least according to the CLCKFREQ program I have been using, does anyone have any suggestions for other benchmarks I could use to double check?

However in NTSC mode this delay makes it run about 1/3 the speed of a ZX81.

For reference, a real ZX81 in NTSC mode (i.e. a TS1000) reports about 1/2 the speed of a ZX81.

This is just in SLOW mode, FAST mode performance is identical.

On the ZX81, there was a jumper that set a bit on the keyboard / tape input port. The software would read that and adjust the screen timing accordingly. There is no PAL/NTSC jumper on the Jupiter Ace.

There was an NTSC version, but that had either a different PCB or a modified PCB to rearrange the counter logic to change the framerate. Because of that, there is no easy way for the software running on the Minstrel 4th to know which framerate is selected to adjust the delay. Maybe it could count frames and clock cycles to detect and adjust it's delay accordingly?

I have updated the ROM to V1.4, If anyone is interested in testing this, I have posted the ROM on my Patreon. It is still experimental, but seems to be working.


Adverts

This Minstrel 4th (with the updated ROM including ZX81 BASIC) is available as a kit or built and tested, from my Tindie store.

It is now also available from Z80kits.com, home of the RC2014. 


There you can get a bundle with the Minstrel 4th, RC2014 backplane and whatever modules you wan to go with it.


Patreon

You can support me via Patreon, and get access to advance previews of development logs on new projects and behind the scenes updates. New releases like this will be notified to Patreon first, if you want to be sure to get the latest things. This also includes access to my Patreon only Discord server for even more regular updates.