Sunday, 4 October 2026

Penultimate Cartridge +3 DCR V7.70

A preview my wonderful Patreon supporters got back in July:

This week I have been mostly working on the Penultimate Cartridge.

Every year or so, we decide it is time to refresh the games list, this time we have a few new games to add, including the great Thrust-like but utterly unpronounceable Gravzronox from Misfit (which TFW8b refers to as "Gaviscon" as he has given up trying to pronounce it).

Also from Misfit, the upcoming game which is not called "Doctor Michael Portillo".

There are also hints that we might have something new from Hewco, and one or two from me, including the VIC20 version of Perilous Swamp, and something else I started ages ago that I must get around to finishing.

Edit: this was referring to my rewrite of TimeBomb in assembler.

Making Space

The problem is, the Penultimate Cartridge is full. We have two megabytes of EPROM space, providing about 300 titles at the moment (I haven't counted them in a while, but that works out an average of about 7K each, so it sounds about right).

Edit: the previous release has a total of 241 titles in the A-Z list, not including adventure games, board games, paddle games, utilities and programming tools, all of which are on separate menus.

It usually comes down to what games can be removed to make way for the new ones. Sometimes we find one that have managed to avoid being culled previously as they are still quite good, and ones that probably should go, but we have to keep because of historical significance etc.

For example, in the last release, we finally got rid of the "official" version of Q*Bert, because it really isn't very good.

No effort is made to deal with colour clash, simply adding a black square into the yellow diamonds when you hop onto them. It was also NTSC only with no adjustment for PAL systems.

We tried to keep that because it was Q*Bert.

In the end, we have Topper, which is a much better version.

Even Max is better.

Both better versions of Q*Bert than Q*Bert, so it went, and that was only an 8K ROM.

The same sort of rules apply, so we have been going through trying to find space for two 32K ROM games, a couple of 8K games and potentially more.

We almost got to the point of considering removing some of the less visible things.

Things like the text adventures and the paddle games are both on separate menus rather than the main list.

One target was Pinball Spectacular.

Not a bad pinball simulator, but it was two 16K ROMs, one for PAL and one for NTSC, which seemed to be very different internally, with not much direct commonality.

Other games where there were PAL and NTSC versions turned out to be a handful of bytes different, and I was able to store the NTSC version and patch those few bytes to create a PAL version from the menu program when it was launched.

So Pinball Spectacular in total was 32K. It that was to be removed, that would get us one of the new games, what about the rest?

An Idea

Then I had an idea.

I had previously been able to make some space by using a program called Exomiser to compress some of the programs, but it was only able to deal with PRG files from 8-24K, and we found that it didn't work on some of the programs we tried, and others were barely reduced in size, but where it did work, it worked well, some games went down to less than half their original size

I was looking through at some of the older cartridge images in there, ones from the 1980s, like Avenger and Donkey Kong etc.

Some of those looked to have space in them, or runs of $00 or $AA of $FF etc.

I wondered if I could use a simple compression algorithm like Run Length Encoding (RLE) to compress these files.

This is an old technique where you look runs of repeated characters, so a run of twenty $FF characters, could be replaced with a single $FF and a count of 20.

That works really well with data which is only long runs of the same character, large monochrome bitmaps for example.

The worst case is all the characters are different, so you get 1x $17, 1x $0F, 1x $12, 1x $0C, 1x $40 etc. Best case is they are all the same character, so you get 256x $42.

With a 256 byte data block, the best case is 2 bytes, a massive saving, but the worst case if 512 bytes, double the original size.

I tried this out and it was pretty awful, most of the data blocks were over 500 characters.

Even in the cases where it was sort of effective, it only barley did better than a straight copy.

A few cases were a bit shorter, but certainly no two-byte results.

Another Idea

Then I had another idea.

Why don't I process the 256 bytes blocks, and if the compressed length is >= 256 bytes, then I set that block as a straight block copy. If it is < 256 bytes then I store the RLE version.

On decompression, I will have a table of each block type, start address and destination.

It will either by a straight block copy or an RLE decompression.

I tried it.

It was rubbish.

All but two of the blocks were straight copies, and with the overhead of the block table, the file was larger than before.

A Third Idea

The third idea burned down, fell over, and then sank into the swamp.

The Forth Idea

But the forth idea, the forth idea worked.

It is a little convoluted, but basically I need to have an 8K block of ROM at address $A000 to run the game.

I can't Exomise that as it's not a PRG file and doesn't have the normal load addresses.

But, what if I create a program. A program which consists of a small copy routine, then an 8K block of data.

All* it will do when it runs, is copy the immediately following 8K block of code up to $A000 in RAM, then poke at the Penultimate cartridge to turn that 8K block read-only and reset the VIC. When the VIC resets, it sees a cartridge ROM signature in the right place at $A000 and runs the game.

(* not quite all)

I put that together as a test and ran it, and it decompressed to 50% of the original size.

I tried it, and it ran, took a second or so to decompress, you could see the tell-tale flashing A in the bottom right hand corner. I had arranged it so that it would not clear the screen, so the LOADING message still started there.

And then the game started as if it was running from a cartridge.

Great, it turns out there are quite a lot of cartridge games that this could be applied to.

I tried a few more games and most of them were going down to about half.

This time it was right, it would work, and no one would have to get nailed to anything.

A Bonus

There is a little bonus with this. 

I mentioned previously that I was patching some of the PAL/NTSC ROMs, well, now I have this little loader program running and copying the cartridge image into RAM.

That is an ideal place to put the patching code. I can do a simple test to read the VIC 20 ROM and check what version it is an then apply the patch if necessary, before making the RAM read-only. (RORAM?)

A quick refresher on the way the VIC20 deals with screen positioning:

It doesn't.

Well, rather it can, but it does not initialise anything when a cartridge is detected, so it is down to the game designer if they call the standard KERNAL routines and get the standard size screen, or if they do it themselves.

Glossing over lot of detail, the two relevant registers in the VIC chip, are $9000 and $9001. These contain a horizontal and vertical offset of the screen respectively. Basically, the width of the left border, and the height of the top border. How far the top left character in the text area of the screen will be from the top left corner of the actual screen.

On a normal VIC when it boots to the BASIC READY prompt, the values will be $0C and $26 for PAL.

And $05 and $19 for NTSC.

If you happen to put an NTSC KERNAL ROM into a PAL VIC, you would get the screen in the wrong place.

And vice versa.

There is a table of default values in both versions of the the KERAL ROM at $EDE4. And a routine at $E518 which will copy those into the VIC, setting up the normal screen.

Some games will call the routine to setup the VIC to the default values.

Others will read the table and use the values to determine if this is a PAL or NTSC system then apply their own values.

The reason many did not, or could not, use the default values, is the offsets change depending on how many rows and columns you have the screen set to.

The VIC is very configurable, so you see games going to all the extremes.

Some tall and thin, some short and wide.

Some max it out to get the most screen area, so much so they don't fit onto the smaller NTSC window.

Many just setup the VIC how they want and if you happen to be in the wrong region, it is going to be in the wrong position on the screen.

Some games, particularly NTSC cartridges, had the option to use arrow keys or sometimes the joystick (or in one case F5 and F7) to adjust the screen centering to suit your system.

All of this could have been avoided if they had a well documented and well publicised KERNAL function you could call that would setup the screen for a given row and column size and set the appropriate offsets for your region, either by calculation or lookup table.

Since I was looking at writing code to patch the games that already had PAL and NTSC versions, this was also an ideal place to patch games that did not have both PAL or NTSC versions.

There were many games, including things like Centipede, that did not have a PAL version, or any adjustment, so with a patch as part of the loader, I can bring many more games that were previously not available in the other region.

I could also pre-set the starting points for games that had the arrow key or joystick adjustments so they would start in an appropriate position for the current region.

User Experience

TFW8b was initially a little concerned that the decompression delay might affect the user experience, but with this change affecting more than half of the games I was looking it, it changes the user experience it was previously:

1) Select Game

2) Load Game

3) Adjust Screen

4) Play Game

It is now:

1) Select Game

2) Load Game

3) Game Decompresses and Patch if Necessary

4) Play Game

I think that is an acceptable swap. Ideally, the decompression step would be eliminated, but unless more storage magically appears, this seems the best option.

It also freed up an awful lot of space in the cartridge.

Enough for the two new 32K games, and about 8 more 32K games (or 32 more 8K games).

(N.B. we did find a number of nice recent games from one author that we wanted to add, but unfortunately we could not get in touch with them so they were removed from the cartridge at the last minute)

That should keep us going for this update and the next one or even two, before the Penultimate +4 eventually appears in a few years with some yet to be imagined vast storage data cube.

Update: Totaliser Results

The A-Z list does not include adventure games, board games, paddle games, utilities and programming tools, all of which are on separate menus.

The previous release has a total of 241 titles in the A-Z list. Removing NTSC-only, that is 224 on PAL systems, and without PAL-only, that is 190 on NTSC.

The updated release has a total of 245 titles in the A-Z list (243 on PAl systems, 215 on NTSC)

You can see TFW8b's new video showing the updated cartridge in action on the You Tubes (look out for the flashing letter A bottom right of the screen during loading).

Adverts

The VIC20 Penultimate Cartridge +3 DCR is available now from the Future Was 8 bit.


All Tynemouth products are still available, and I can ship worldwide.

Including the limited edition 10th anniversary recreation of the very first Penultimate Cartridge:


International shipping is a bit complicated at the moment, so if you want to order from outside the UK, please contact me using the contact link at the top of this page.

See here for more information:

Sorry to have to do this, and I know this is going to affect sales, but please understand it is the only option I have right now.


Patreon

If you enjoy posts like this, you can support me via Patreon, and get access to advance previews of blog posts, and exclusive posts.

You also get progress updates on new projects and other behind the scenes updates, as well as access to my Patreon only Discord server for even more regular updates, and to discuss your own projects.

Sunday, 27 September 2026

Tynemouth 9 Way D Joystick for Minstrel 4th and RC2014 V2.0

This is the new Multi-Standard 9 way D joystick interface for the Minstrel 4th and RC2014.

It might not be immediately obvious what has changed from the previous V1.0 board.

We could play spot the difference, but the main changes are the address jumpers have gone and there are now DIP switches with more options.

The jumpers were sort of pointless, as most people would have set them to ID $01 to make the joystick port compatible with the Boldfield joystick for the Jupiter Ace.

You could have set it to a non-standard ID if you wanted, but that would have only worked with suitably modified software.

You could have set it to ID 31 and pretended to be a Kempston interface, but that would not have worked as the joystick signal bits are arranged in a different order on the Kempston interface.

That is where the V2.0 board comes in.

It now has two DIP switches to select one of three interfaces it can emulate.

  • Boldfield Joystick is a vintage standard for the Jupiter Ace
  • Kempston Joystick is a vintage standards for the ZX81 and ZX Spectrum
  • ZXpand which is relatively modern, and supported by some newer ZX81 games

To support those three addresses and three different arrangements of bits, there is now a GAL where there the 74HC240 was on the original.

This now handles part of the address decoding, the multiplexing of the joystick signals to the appropriate data bits, and acts as an 8-bit latch, like the 74HC240. Inverting the signals as required for Boldfield and Kempston, but not ZXpand.

This should be useful for the Minstrel 4th and it's ability to run Jupiter Ace and ZX81 software, so there is a good chance that one or other of those formats will be supported.

Games like Paul Farrow's ZX81 Kong can support the Kempston interface. Press X to select the controls (because C is mapped to the X key, because Jupiter Ace).

Colin Dooley's Valkyr for the Jupiter Ace support the Boldfield interface.

David Stephenson's Zevious Seven for the ZX81 deserves special mention as it supports all three!

It asks the user to press fire, and is scanning the keyboard and the three interface options.

Whichever one it detects you pressing fire on, it uses for the game. Neat. That is how I normally recommend doing control selection if you need to.

You might have noticed I haven't included a game with just ZXpand support.

That is because I couldn't find one.

Well, I found a couple, including Paul Farrow's Against The Elements, that support the ZXpand joystick, but use high resolution graphics that do not work on ZX81 BASIC for Minstrel 4th.

I found another, ZXagon, which lists ZXpand support, but that didn't seem to be working. I think it was using the mode which only works with the ZXpand ROM that has a patched INKEY$ function, rather than reading the port directly.

There does not seem to have been much uptake unfortunately, which is why I added Kempston support to the Minstrel ZXpand.

If anyone knows of a game I have missed that supports the ZXpand IO port joystick, but doesn't need high resolution graphics, let me know.

Programming / Testing

If you want to use this in your own games, then just read from the appropriate port and check the appropriate bits.

Plug in the card to the RC2014 slot on the side of the Minstrel 4th, or a backplane if you are using one and add a suitable Atari or Commodore style 9 way D joystick (not Atari 5200, Spectrum +2, Sega or things like that). No mice, paddles, light pens, serial adapters or Elks.

Assembler

In assembler, the minimum you need is:

IN A,(31)

I use 31 in these examples for the Kempston interface, replace with 1 for Boldfield or 7 for ZXpand as appropriate. 

Note the ZXpand interface itself requires a two stage operation, request a joystick read, then read the port. The request part is not required with this board, and will be ignored. The joystick data will always be read afresh from the port.

Forth

Forth has a built-in IN word that reads the port in the same way.

A simple test word is as follows:

: JOY
BEGIN
     CR 31 IN . 0 
UNTIL
 ;

This will continually read values and scroll down the screen.

Being Forth, that scrolls by very fast.

ZX81 BASIC

ZX81 BASIC does not have an IN word, that wasn't added until the ZX Spectrum.

To get around that needs a little bit of assembler.

XOR A
LD B,A
IN A,(31)
LD C,A
RET

To get that into the ZX81 requires a bit of poking around with a REM statement.

You start with a REM statement on line 1 with 6 characters. Then poke the values of the assembled Z80 code into the addresses where those characters are stored.

1 REM ......
10 POKE 16514,175
20 POKE 16515,71
30 POKE 16516,219
40 POKE 16517,31
50 POKE 16518,79
60 POKE 16519,201

The 31 on line 40 is the address of the port, so you can change that to 1 or 7 as required.

One you run that, the REM statement changes.

You can then delete lines 10-60.


A shortcut is to start with the REM statement containing the following:

  • Inverse J (shift + 9, J, shift + 9)
  • . (any character, will be replaced by POKE 16515,71)
  • <= (shift + R, note not < then =, <= is a single character)
  • 3 (which is 31 for the Kempston interface or any character to replace with POKE 16517,1 or 16517,7)
  • . (any character, will be replaced by POKE 16518,79)
  • TAN (shift + newline, shift + E. note a single character, not T A N)

You can enter the POKE for the missing characters in immediate mode if you like.

PRINT USR 16514 will call this new code.

You can then make a simple test program. I put the SCROLL first otherwise it prints the first line then starts scrolling from the middle of the screen.

ZX81 BASIC shows off an interesting feature here.

The zeroes scroll past quite fast, but as soon as you move the joystick and the numbers appear, things slow down.

I think this is due to the storage of numbers as floating point in ZX81 BASIC, so it has to convert to a 5 bytes floating point representation, then parse that back to display it. There is a shortcut for 0 which skips the conversion steps.

Here I press down on the Boldfield interface setting, which shows up as 2. Then I change to down and left and it shows 8+2, 10. Then I finally get the answer by pressing fire which adds 32.

The Boldfield and ZXpand versions of the test program only differ by the character after the <=, a top left quarter graphic for Boldfield, and a bottom right inverse quarter graphic for the ZXpand. (the author adds a note at this time stating he would welcome suggestions for better names for the battenburg characters)

With the ZXpand, the rest state is 255, and when you move that bit goes low, so you end up with values like 247 for fire, 255-8.

That's Great, Dave, Where Can I Get One?

The Tynemouth 9 way D Joystick V2.0 for Minstrel 4th and RC2014 is available as a kit or assembled from my Tindie store. As with everything else on there, if you are outside of the UK, please contact me directly as international shipping calculations don't work on Tindie so I have to get prices on a case by case basis.

It is also available as an add-on option when ordering a Minstrel 4th kit.


All items are still available, and I can ship worldwide.

Including the Minstrel 2 (ZX80), 3 (ZX81) and Minstrel 4th (Jupiter Ace / ZX80 / ZX81 / Lambda 8300 / RC2014,) with built in keyboards

All versions are available in kit form, or pre-built, and optionally the new Minstrel ZXpand II SD card and joystick interface for the 2 and 3 or the Software Serial and 9 way D Joystick for the 4th.

International shipping is a bit complicated at the moment, so if you want to order from outside the UK, please contact me using the contact link at the top of this page.

See here for more information:

Sorry to have to do this, and I know this is going to affect sales, but please understand it is the only option I have right now.


Patreon

If you enjoy posts like this, you can support me via Patreon, and get access to advance previews of blog posts, and exclusive posts.

You also get progress updates on new projects and other behind the scenes updates, as well as access to my Patreon only Discord server for even more regular updates, and to discuss your own projects.