Sunday 10 December 2023

ZX80 BASIC on a Minstrel 4D - Part 3 - Testing some flicker-free games

Continuing the series of posts from Patreon in November, working on getting ZX80 BASIC running on the Minstrel 4D. This one reworked from several posts.

In the previous post I got ZX80 BASIC running on the Minstrel 4D, and with the help of new LOAD and SAVE routines was able to load ZX80 games.

This is a modified ZX80 ROM running on Minstrel 4D hardware which was designed to run the Jupiter Ace ROM.

I had tried lots of programs which used the normal ZX80 display mechanism, including board games and text adventures etc. Games that suit the display - think - display type mechanism the ZX80 used.

Due to the way the screen is displayed on the ZX80, it was not possible to do the sort of fast moving shoot-em-up style games, at least not in BASIC.

I wanted to see some space invaders, and luckily back in the day some ingenious methods were found to make that happen.

Flicker-free games

All of the games I had tested up to this point used the display in the standard ZX80 way. There would normally be a screen flicker when the AI player was making there move, but here the screen remains static until it is next updated.

I am hoping that the many "flicker-free" games for the ZX80 will be usable

The idea in brief is to bypass part of the display routines in ROM, and then run short blocks of precisely timed code in the gaps at the top and bottom of the screen, returning to the ROM code to do the actual screen drawing.

Each of the blocks of code needs to take exactly the same number of cycles, so you have to be very careful with anything that is conditional (did the player fire, does that alien need to move down a row etc.) so that all paths through the code take the same number of cycles.

I will link for reference Paul Farrow and George Beckett's work on this subject:

The first one I tried was a simple demo from the article that first introduced this concept.

That was unfortunately the only one that worked at that point.

I did some more research and a bit of debugging, and was able to tweak the way my new display routines generated the display to fit with the expectations of the flicker-free games.


I started with probably the earlier games, those from Macronics (

Breakout is working well, with a small caveat. It takes over some of the display drawing, and includes turning on and off the VSync generator. Yes, the same one that now drives the speaker. Yes it now makes a ticking sound.

The code use IN FE and OUT FE instructions to turn on and off the sync generator. The actual values used are not important on the ZX80. The IN is only decoded as IO READ where A0=0, i.e. any even address would do. The OUT is only decoded as IO WRITE, so any address could be used. FF seems the best option, as FD is used on the ZX81 to control the NMI generator (decoded as A1=0), so FF is safe as it will not trigger either of those.

See for more details.

They published breakout as a type in listing. Yes, that is the entire game. The highlighted D3 FE is the relevant instruction, changing that to D3 FF will stop the clicking sound and will still work on the ZX80 and the Minstrel 4D.

George Beckett generated a patched version, and that works nicely. It is not ideal, but patching the games or modifying the hardware are the only options here. There are only a few games like this, so we can provide patched versions of any of those which use OUT FE.

Space Invaders

Macronics released two versions of Space Invaders (or Space Intruders), a full screen one for 3K RAM which works fine.

They also produced a version which runs on an unexpanded 1K machine. To make that fit, they reduced the number of rows on the screen. Trying that version on the Minstrel 4D, the game is playing correctly, but the remnants of the BASIC program are still visible in the part of the screen that is not being updated. (note this is one of those games where you need to type GO TO 100 to start it rather than run)

I adjusted my display routine to pad out the rest with spaces, so that now works fine.

I could centre it vertically based on the number of rows being drawn, but as far as I know it is only this one game, and is how it would have looked on the ZX80, so I will just leave it for the moment.

Hampson's Plane

George Beckett has produced a flicker-free implementation of Hampson's Plane for the ZX80.

It didn't initially work, but that turned out to be it not detecting that a key had been pressed. The actual display side was fine it was just waiting for the user the enter the skill level.

The keyboard differences will be an issue for a few games that implement their own keyboard routine, reading a byte from the keyboard port and then doing a comparison without masking off bits.

On the ZX80, bits 0-4 are defined for the keyboard columns. The other three are not relevant to the keyboard. Bit 7 is the tape input, and will normally be low. Bit 6 is pulled high on UK systems, but will read low on USA systems, and bit 5 is undefined so may read high or low.

On the Ace, the same bits 0-4 are defined for the keyboard. Bit 5 is the tape input, again normally low. Bits 6 and 7 are undefined but will float high on the Minstrel 4D. (see a previous blog post about the issues a similar problem caused with type 2 interrupts on the game Valkyr).

I suggested rotating a bit at a time into carry and testing that, which also worked out a bit more efficient and is consistent timing.

However, there is another issue because it has it's own keyboard scanning routine rather than the ROM one, it will misread the bottom row (see the previous post)

It would be possible to produce special builds for the 4D or possibly one that detects the system. There are various ways that could be done.

  • Read of port FE, bit 7 will be high on the 4D, but is the tape on the ZX80, so will read low.
  • Alternatively, and probably more reliably, pick a byte in ROM that is going to be different. The first byte in the ZX80 ROM is 21. But the new 4D version is C3, so just read 0000 to tell.
  • Or maybe a more subversive method would be to add "Press C to continue" on the first screen, and then seeing if that reads as C (ZX80) or V (Minstrel 4D).

George implemented the changes (with Press C to start) and also switched to using OUT FF to get rid of the background hum and it is now running well on both the ZX80 and the Minstrel 4D.


Paul Farrow has adapted Mazogs to run on the ZX80 with flicker-free display.

I was pleased to see that ran well. It also ran without the clicking sound, I believe it uses OUT FF instructions, so does not trigger the speaker in the Minstrel 4D.

But unfortunately his versions of Kong and Pacman do not. I think this is something to do with the autostart rather than the flicker free, but I will investigate further. (they are now working, but that is a whole blog post of it's own - coming next week).

This is all I get when they load?


With the exceptions of the Kong, Pacman and the Metropolis demo (which I knew would not work), all the games I have tried have worked.

I think pretty much any ZX80 software will just work, but there are a couple of caveats.

Anything in BASIC should be fine, and even machine code as long as it calls the ROM routines for reading the keyboard reading, load and save and video generation, everything is fine.

If any code has it's own keyboard routines, then the bottom row of keys will read wrong.

If any code has it's own load routine, they will fail as the tape signal is read from a different pin.

Flicker-free games are also working, but because they have a partial display routine which includes sending the signals that now trigger the speaker, there is going to be humming without a hardware mod or patching the games to not use OUT FE,A

In the next post I will go into details of why Kong and Pacman were not working, and what was required to get them running.


Minstrel 4D

Minstrel 4D kits and ready built units are available from


You can support me via Patreon, and get access to advance previews of blog posts and behind the scenes updates. These are often in more detail than I can fit in here. This also includes access to my Patreon only Discord server for even more regular updates.

Sunday 3 December 2023

ZX80 BASIC on a Minstrel 4D - Part 2 - New tape load and save routines

Continuing the series of posts from Patreon in early November, working on getting ZX80 BASIC running on the Minstrel 4D.

Yesterday I gave up on trying to make the old ZX80 tape load routine work. I do not know what exactly is wrong, I have tried all the combinations I can think, and is just isn't working.

So, I wrote a new one.

A new tape loading routine

The screen border on the Minstrel 4D is driven by the load signal, so you can see the data on the tape in it's groups of 4 or 9 pulses, which represent the 0's and 1s.

The ZX80 cannot generate the screen during loading, so normally the screen is just black. As the hardware on the Minstrel 4D is different, the screen persist with the last update, so the LOAD command remains visible where it was typed until the program has loaded.

I thought it might cause the user to think they hadn't pressed return, or it had not registered, so I tried blanking the screen, which sort of worked. I also tried filling it with 50% grey characters, which is not normal to see on a ZX80, so acts as a "something is going on and nothing is being drawn on the screen".

Loading is a difficult thing to debug, but I realised I could make use of the display. I will go into more detail in a future post, but I can write to the display when the Z80 is doing other things.

Here I am writing the bits remaining counter when it gets to the end of a byte. Most of the time with the old load routine, I was lucky to get more than a single 1. This was an unusual occasion I captured when the volume level on the tape was wrong and the data was rubbish, but it was rubbish in just the right way to make the old tape routine accept that rubbish and try to load it.

I decided to write a new load routine, and see if that worked.

The idea seems to be the a series of either 4 or 9 pulses, followed by a gap. A wrote code to detect the transitions in the signal (so polarity would not be an issue), and waited until there was a big enough gap since the last transition to count as the end.

This shows a 1 and a 0 being detected. Yellow is the sampling pulses, green is the input signal, and blue shows writes to RAM once a bit has been detected.

I used the debug to record the 0s and 1s here showing the 66 bytes that make up the "Hello" program I was testing with.

There is no formatting to the data, no header or end marker. End detection on the ZX80 is based on the data in the file itself. It is written to RAM from 0x4000 upwards, overwriting all the system variables, including E_LINE, the end marker. As memory fills up with data being loaded, the current address is compared with E_LINE until they match, and then loading is complete and the program is listed. (E_LINE is initially set to a high address so that it will not stop before E_LINE has been overwritten with the value from the tape)

Yay, finally. Can you imagine how relieved I was to finally get that working (at about 5AM this morning, but who's counting).

And it even worked.

I needed to remove the debug, but it then went back to being a sort of boring grey. 

I think I can do better than that.

Now when you type LOAD, the screen is cleared and you get a little box.

As loading progresses, the current address is displayed. I thought about subtracting 4000, so it counted up from 0000 instead of 4000, but I think it's fine like that. It also counts in hex as that is far easier to do. Very easy as it happens due to the character set of the ZX80. Character 28 through 37 are 0 to 9, and 38 goes straight to A, so characters 28 through to 43 are 0123456789ABCDEF. To display a number in hex, just add 28 to it. (It is a little more complicated in practice as you need to split the byte into two nibble, and display each one separately.)

That seems to be working quite nicely. I was a little worried about the extra overhead, but it only adds a small delay, see the extra write pulses in blue at the end of a byte, more than enough space before the next one starts.

I successfully loaded many programs, including a large text adventure, Citadel.

And a version of Othello with a surprisingly good AI player.


I knew save was going to have similar problems to load. The hardware of the Ace is again fairly similar to that of the ZX80 when it comes to saving, but the actual triggers are different.

The ZX80 re-purposes the VSync generator to drive the mic input of a cassette recorder. So again, when it is doing that, it cannot drive the TV signal, but that's par for the course with the ZX80.

Here the signal is turned on by any IO writes, and turned off by keyboard IO reads.

The IO read to the keyboard doubles to turn the sync signal off and also read the column which includes the space key, so that can be used to abort the save.

The sync signal generated is a series of pulses representing 0s and 1s. A 0 is 4 pulses, a 1 is 9 pulses. There are no byte or block markers.

The version which is recorded on the tape is AC coupled by the capacitor C14, so ends up as a stream of pulses of 300us / 3.33kHz, which is within the range of a basic 1980s domestic cassette recorder.

The Minstrel 4D has the same output section as the Jupiter Ace, which is something resembling a proper IO port. In this case, a 1 bit output port latching the value of D3 written to I/O port FE.

In order to make save work on the ZX80 4K BASIC on the Minstrel 4D, I just need to change the IO write (to unused address 0xFF) to be a write to 0xFE with D3 set to 1, and the reads of 0xFE to be writes to 0xFE with D3 set to 0.

I need to add extra reads to 0xFE to check for the break key. This is only tested between bytes, so an extra read there shouldn't be a problem.

The only problem is the speaker on the Ace is also controlled by IO reads and writes to port FE so it will click on an off with each byte.

I don't think there is a way around that. I can't change the hardware, so it's either clicking or no way to abort a save once it has started.

Testing out save, that worked fine.

Rather than having to mess around patching in place, I decided it would be easier to just create a new save function, that way I could also use the on screen counter the same as the new load routine.

That all seems to work as expected, I have tried saving and loading and all seems to work well and interchangeably with a Minstrel 2 running the original ZX80 4K BASIC ROM.

In the next post I will be trying out some games and seeing if the special "flicker-free" programs work.


Minstrel 4D

Minstrel 4D kits and ready built units are available from


You can support me via Patreon, and get access to advance previews of blog posts and behind the scenes updates. These are often in more detail than I can fit in here. This also includes access to my Patreon only Discord server for even more regular updates.

Sunday 26 November 2023

ZX80 BASIC on a Minstrel 4D - Part 1

Yes, you read that right, ZX80 4K Integer BASIC running on a Minstrel 4D.

This is the first part in a series of posts where I will be starting with building a modified version of ZX80 BASIC and later moving on to a version of ZX81 BASIC that will run on the Minstrel 4D hardware. The final goal will be to get it running as a ZX81, and capable of running an unmodified version of 3D Monster Maze.

I will talk about the practicalities of how that works in a later post, in this post I talk about the initial idea and getting it running.

It was one of those occasions where a silly idea crept into my head and I had to give it a go.

Back in the dim and distant part, one of the original plans for the Minstrel 4th / 4D is that as well as the standard Forth, it would include other language and utility ROMs.

There are two jumpers on the 4th and two DIP switches on the Minstrel 4D to select alternate ROM images, although none were supplied as standard. The memory map of the Minstrel also has an 5K extra space available, meaning these language ROMs could be up to 13K.

I worked for quite a while on a version of Microsoft BASIC, adapted from NASOM BASIC, but I never quite got that right.

I should maybe go back and try that again, but it has been such a long time, I would probably end up starting all over again.

The main issue was the screen editor. The version of BASIC is designed to work with a serial terminal, as seen with things like the RC2014.

I tried to adapt the Ace screen editor, but that is a bit odd with the bottom one or two rows also effectively being the keyboard buffer.

I also looked at adapting the NASCOM screen editor, but that was also problematic due to the way it had a 48 column display in the middle of 64 byte screen lines.

Anyway, that didn't happen so got shelved.


And then, two years later, I had an idea. Hey, why not use the screen editor from the Spectrum.

But wait, why use the NASCOM BASIC, why not use the Spectrum BASIC as well.

Hey, why not make the Spectrum ROM run on the Minstrel 4th.

Well. That was last Sunday (*at the time of writing this post which went to Patreon about a month ago)

I spent a while working on the Spectrum version, but it was clear that it was going to require a lot of work to simplify the pixel based display with colour attributes to one that was character based.

Hey, what about the ZX81? That was character based, let's use that.

So I started again, but this time with the ZX81 ROM. That version is almost working, but there were some issues with slow mode that I need to rethink.

Hey, what about the ZX80? That doesn't have slow mode.

So, I started again, this time with the ZX80 4K Integer BASIC ROM.

And well, it works. There will be a full blog post explaining how I modified it to work, but for the moment, suffice to say I have it running on the Minstrel 4D.

There are various things to deal with to make it usable. The first is the keyboard, the Ace has it's bottom row of keys shifted around compared to the Sinclair machines, so I needed to adjust the key tables to cope with the new layout (for the moment, the Symbol Shift key will be the ZX80's full stop and comma key). I may look at remapping to match the symbols and maybe even a tokeniser for BASIC so you type in P R I N T rather than pressing O (yes, it was on O on the 4K BASIC, not P).

The next thing to tackle was loading. And this is where I initially got stuck. I needed to load programs to test things further, but was having no luck loading.

Hardware wise, the ZX80 and the Ace have very similar hardware for reading the keyboard and the tape. I have redrawn them in the same way, to highlight the difference. Can you spot it?

Yes, the tape input is on D5 on the Ace, rather than D7 on the Sinclair machines. D7 is handy as you can use the RLA instruction to move bit 7 into the carry flag, where it can be easily tested. In bit 5, you either have to do three RLA instructions, or use BIT 5,A to test it.

I did some clever shuffling around to make that work and keep the same number of bytes and T-states, and tried it out.

And it didn't work.

And two days later, after trying all sorts of stuff, it still doesn't work.

I am not sure why yet. It seems to be doing all the right things, but it's just not reading the bits.

Here yellow shows the reads from the port and green shows the signal from the tape. I will probably write a long blog post on this at some point on the ZX80/81 tape loading, but basically 4 pulses then a gap means a 0, 9 pulses then a gap means a 1.

This is very different from the way the Ace did it with different length pulses for 0 and 1 See an annotated listing by George Beckett:

The full ZX80 disassembly by Geoff Wearmouth can be found here for those playing along at home:

You can see my modified ZX80 ROM it is sampling multiple times per pulse, as expected.

Compare that to the ZX80(ignore the slow rise on the green pulse, it is fine at a logic level, and this is the cleaned up version)

Here I have added the blue trace showing writes to RAM as each bit is read. I didn't include that on the shots of my modified version is it isn't writing to RAM, so imagine a flat blue line doing nothing.

Looking at the code, it seems that rather than counting pulses as I expected, it is actually looking for the long period without a change.

A count is started after a bit has been read, and it waits until the signal goes flat. If that is after X counts, it is a 0, if it has reached Y counts and it is a 1, anything over that is an error.

I have spent quite a while probing around at various different machines loading, but no success on the 4D with the modified ZX80 ROM.

I also tried on a Minstrel 4th, which should be pretty much the same other than it does not have the Minstrel SD cleaning up the tape signal, but that proved to be the same.

I even tried going back to the original LOAD routines and modified the hardware to use D7, in case it was my changes at fault.

Summing up where I currently am:

  • Is it the signal processing on the 4D? No. Tried a Minstrel 4th.
  • Is it the D5/D7 swap? No. Tried to swap it in hardware.
  • Does the TZXduino produce the correct output? Yes, it loads into a Minstrel 2.
  • Does the 4D board work with the Ace ROM loading from the same source? Yes.
  • Are there interrupts going off during loading to affect the timing? No.
  • Is it down to something else you have changed? Maybe, but I don't know what.
  • Have you tried turning it off and then on again. Yes.

So I am confused. I may try to write an alternate tape loading routine, or adapt the one from the ZX81 or ZX Spectrum, but I do not understand why the original does not work.

The remainder of the BASIC seems to work as expected. Thanks to George Beckett for trying out typing in a longer BASIC test program which ran fine.

Today is Saturday, in case you needed to know.(* well, it was)

That is running in the Eighty One emulator, set to Jupiter Ace, as I can't load it yet.

Lots of things still to do, I might look at a tokeniser, and adding some extra commands, like IN and OUT, and maybe JOYSTICK to return the value read by the joystick port, and a version of the Spectrum's BEEP command. And then possibly a machine code monitor.......

Any other suggestions?

And then, I need to do all that again for the ZX81 ROM, but I think it is best to keep working on the ZX80 version for the moment as there is loads of space and the lack of slow mode just makes things easier whilst I get these things sorted.

Oh, and then I need to adapt the Minstrel SD and menu etc. so it will work with these new ROMs as well as the Ace one......

But, first I need to get the loading sorted. Spoilers, the next part is titled "Writing a new tape LOADing routine".


Minstrel 4D

Minstrel 4D kits and ready built units are available from


You can support me via Patreon, and get access to advance previews of blog posts and behind the scenes updates. These are often in more detail than I can fit in here. This also includes access to my Patreon only Discord server for even more regular updates.