Sunday, 8 November 2026

Further Penultimate Cartridge Updates

Another of the behind the scenes updates on the Penultimate Cartridge update that my wonderful Patreon supporters got to see back in August.

In the first part of this post (back in July on Patreon), I had freed up quite a lot of space in the VIC20 Penultimate Cartridge, ready to add more new games.

More new games have since been sourced, tested and added.

As I added the last batch of games, I hit a different problem.

There are two sorts of menus on the Penultimate Cartridge, fixed pages, such as the utilities, paddle games, RAM options etc., and dynamically created lists, such as the disk directory listings and the A-Z games menu.

The A-Z list is dynamically generated from a big array of games, which can be filtered by region (PAL or NTSC or both), or by category (space invaders, maze games etc.) or by creator (TFW8b titles, games by Misfit etc.).

ED: We saw the "Centipede type games" menu in a previous post -

From the same pragmatism and paucity of ambition that previously gave us "no one will ever need more than 640K of RAM", the Y2K "Bug" and the forthcoming attraction "Unix Date Rollover" in 2038, comes "we're never going to fit more than 256 games into the Penultimate Cartridge".

For practical reasons of running on an 8 bit microprocessor with limited RAM and processor cycles, using one byte as the index to that array seemed perfectly reasonable when I designed the dynamic menu however many years ago that was.

It was a calculated risk, I think at the time there were about 100 - 150 games in the ROMs, and they were full, and as is the case today, two 1MByte ROMs is the most we are likely to fit into the cartridge as it currently stands.

This list is already a subset of the games on the cartridge, as the programming utilities, text adventures and paddle-only games are excluded from this list and live in their own dedicated menus.

The "up to 256" items in the A-Z list are also the ones selected by the "Rod's Random ROM Runner" random game selection feature, and again there, you wouldn't want to hit a RAM test program, or an Assembler Monitor or a game that needed a different controller to the one you have.

Why Are You Telling Me This?

Ah, well, whenever I add a load of games to the list, I need to remember to hover over the array constructor to check it is still under 256 items. (I don't think the assembler has the equivalent of a #assert, although I must look into that ...)

Ah, 260 items. Whoops.

That is a useful feature of Visual Studio Code, although continuing the rant from a previous blog post, I can't actually edit this file in VS Code as every time I try to type inside the array it "helpfully" blocks out half of the screen with a hovering box.

That is now showing 259 items as I had already removed one. The menu used to contains "Matrix" and "Attack of the Mutant Camels", as the game seems to be known by both names, but both launched the same game.

That used up two menu entries, so I have commented out the "Matrix" one. The game does not give it's name on screen, other than the letters AMC, and that is a better name anyway.

ED: Later I was also running out of space in the menu ROM itself and reversed to "Matrix" as that was 21 bytes shorter, and yes, I was really that short of space. But not space in the overall ROM (which I freed up by adding compression and combining multiple regions of the same game), and not the number of items in the games menu (which I hope is not a spoiler that I will have freed up by the end of this post), but next I was short of space in the ROM which contains that list and the code for the menu and file browser, but more on that in a later post.

Making (more) Space

I still would like to avoid removing any games if I can, since there is still space to fit the binaries in the ROM, the only limitation is the menu entries ... #foreshadowing

Looking thorough the menu ROM, there are a few things that stand out as options. There are several games which have different PAL and NTSC versions. These require two menu items. One which will only appear on the PAL menu, and one which will only appear on the NTSC menu.

When the cartridge starts up, it checks if this is a PAL or NTSC VIC and limits the menu accordingly to games that will run on the current system and removes any which will not fit on the screen or will show screen corruption due to different screen sizes / timings.

If you press the "A" key in the menu (not to be confused with the "ANY" key), it will show you all the items, including the ones that will not work properly on your system, indicated by the X in the right hand column.

There are two versions of Alien Blitz, neither of which has screen adjustment, so the NTSC version is not normally shown here in PAL land. (also neither of them is a Blitz game, although they do contain Aliens, so 50% is OK I suppose)

If you run it the NTSC version, you will see it is off the screen.

Although thanks to the frustrating VIC20 screen settings, that ROM runs correctly in NTSC land.

The PAL version is horizontally centered (although not vertically), but does not work in NTSC.

Also on the the excluded list there was "Alien Sidestep". This is one which does not work on a PAL VIC. I must look into why, it displays the menu, as usual out of place, but it never starts the game.

I have tried pressing all the buttons, the usual fire, space, enter, run/stop, f1-7, and all the others, including the any key. For some reason it is stuck in the title screen and never exits.

The same ROM on NTSC is fine.

Again, Why Are You Telling Me This?

Well, using the technique I developed in the previous post, I can free up some of the menu entries by creating some multi-region versions.

The multi-region version will usually free up even more space in the ROM, but more importantly will replaced the two entries with a single one.

The only problem is I have already tackled the easier ones in the previous post. The few that remain were not modified last time as they looked like they could be tricky, or ones where they were in places that would leave small gaps in the ROM, requiring it to be manually defragmented, which is a long a tedious task, although ultimately rewarding each time you find a combination of games that add up to exactly $80 blocks (32K).

Alien Blitz

Since I have already mentioned it, I will start with Alien Blitz.

This is slightly odd as the NTSC version is a cartridge, and the PAL version is a PRG file, presumably recovered from a tape. I guess the cartridge was more popular in the US and tapes were more common in the UK?

I could just patch the NTSC cartridge version (and maybe do a better job of the alignment and centre it in both directions?), but since there is an original PAL version, I should use that.

I considered a few ways to do this, but this is what I came up with.

The original NTSC cartridge was 4K, and the PAL PRG file is 3.5K.

I extended the 4K NTSC cartridge into an 8K cartridge.

The VIC cartridge header is as follows:

  • 2 byte cold start vector
  • 2 byte NMI vector
  • The letters "A0" (indicating this is a cartridge that lives at A000)
  • The letters "CBM" (Commodore Business Machines - Business? in a games cartridge?)

The 4K ROM started with the addresses it would jump to at boot to start the ROM. I modified those to point at a new routine I put in the empty upper 4K of the cartridge ROM.

Here I checked if this was a PAL or NTSC VIC (check the first byte of the VIC settings at $EDE4, if it is $05, this is an NTSC VIC).

If it was NTSC, I jumped back to the start routine in ROM. The NTSC ROM runs as normal with only a slight deviation from the normal start process.

If it is PAL, I go through the initialisation routine (since this is bypassed when starting a ROM cartridge), and then copy the 3.5K game from the end of the ROM into base RAM where it would normally have been loaded to, and call the appropriate BASIC ROM routines to treat it as if it had just been loaded from tape and run it.

The resulting 8K cartridge is now actually slightly larger than the separate PAL and NTSC versions, but I have freed up enough space elsewhere that I can take the 0.5K hit in exchange for saving one menu entry.

Rigel Attack

This was an interesting one, we had two 12K PRG files, one for PAL, one for NTSC, which were clearly built from the same source, but with too many differences due to all the code being relocated when building the different versions.

If you load the wrong region, the player ship falls off the bottom of the screen.

Originally, I had both versions in the Cartridge

12K + 12K = 24K

Later, I exomised both, so that reduced the total to

6K + 6K = 12K

That was using the old system of having two entries on the menu, one for PAL and one for NTSC, when different versions were required. Now with hitting the menu limit, I need a single file and a single menu entry.

Here again, there were a few options, I could have a loader program that would copy either the PAL or NTSC program into the right place in RAM and then run it.

However, due to a stoke of luck, I could use a similar technique to the multi-region Alien Blitz cartridge above.

Normally the PRG header is as follows:

A zero, The first byte in memory ($1200 in this case) is always zero.

A two byte pointer to the end of the header.

Then the first (and usually only) line of code

A two byte line number (normally 10, although I prefer to use 6502)

The code itself

A zero to end the line

Two zeroes to end the header

The line of code is normally something like

10 SYS4621

4621 is the address of the code to run, $120D (I remember that as I used to have a Citizen 120D+ printer for my Amiga 500).

This is stored as $9E, the token for SYS, and then the four characters for "4", "6", "2" and "1".

The code then starts immediately after at $120D.

That means you can change that to any number up to 9999 ($270F), without having to move any code.

In this case, the line was slightly different.

10 SYS 4622

This is jumping to 4622 ($120E) because it is one byte longer, the code includes a space after the SYS command, so everything is moved along one byte.

The code line is now the $9E SYS token, the space character " ", then the address "4", "6", "2" and "2". (N.B. the space after the line number is never stored, it is always added when the program is listed)

The code then follows at 4622 ($120E).

I built up a program with both versions and added some code to launch the appropriate version.

The PAL game runs from $1200 to $3FFF.

The NTSC game follows from $4000 to $6CFF.

The loader code is at $6D00, 27904 in decimal. Five digits.

Because of the extra space in the SYS command, it was possible to change it to a five digit number. Had I been limited to four digits, I couldn't have had the test program below address 10000 in decimal, and that is the middle of the PAL game.

The space and 4622 were changed to 27904 and everything else in the PAL version was left the same.

10 SYS27904

This now runs the code at $6D00 at start up.

This checks the first byte of VIC settings, $05 for NTSC, $0C for PAL. If it detects PAL, it jumps to $120E, and starts the game that is already in place.

If it is NTSC, it copies the NTSC version from $4000 down to $1200, then jumps to $120E and starts that version.

The combined file is 24K, but when exomised, is only 7K.

24K originally, down to 12K in recent versions, finally down to 7K, and also frees up 1 more space in the menu.

Win win.

K-Razy Antiks

This one was a bit k-razy.

The game itself certainly is. No clue what is going on there.

The NTSC version was two 8K ROMs.

The PAL version was a 4K ROM and an 8K ROM.

Looking at the lower 8K ROM of the NTSC version, the first 4K is one byte different to the PAL version, and then the next 4K is seemingly rubbish, random data. Possibly when it was ripped, 8K was read when there was only a 4K ROM present?

The upper 8K ROM is 15 bytes different, presumably region changes.

However, there is one odd difference in some odd code.

It starts off OK, copying what is probably character data, from the ROM at $Axxx range into the RAM at $1xxx.

It then zeroes the whole of zero page ($00xx), which is fair enough. If you don't want to use any KERNAL or BASIC functions that need zero page, go for it.

STA $00,x

Then it zeroes a page of memory from $8000 to $80FF.

STA $8000,x

This area is where the character ROM lives. It is writing to the character ROM, or at least trying to?

Makes no sense.

In the NTSC version, one byte of that is changed, and that line now reads

STA $B000,x

This zeroes a page of memory from $B000 to $B0FF.

$B000 is the cartridge ROM. Now it is trying to write to the cartridge ROM?

If you happen to be running from RAM, this will overwrite some code and stop the game running. Maybe that is intentional copy protection, but then why change it in the NTSC version?

Or maybe did someone patch that in the past to allow it to run from RAM and $8000 was the best thing they could have of changing it to where it would do no harm (other than bus contention, since the VIC address decoding does not include the R/W line, so it will enable the ROM, which will write data to the bus at the same time as the CPU is also trying to write to it, with hilarious consequences, eventually)

The RAM the Penultimate Cartridge runs the game from is read-only, so it is not a problem in this case.

Atlantis

This was an easy one, two 4K carts, one for PAL, one for NTSC.

If you got the wrong region, it would crash horribly.

This one I converted like the ones in the previous post. A new PRG file, containing both cartridge versions.

The appropriate one is selected and copied into RAM and then run.

Originally 2x 4K, the combined program was 8.5K.

That exomised down to 4K and freed up another menu space.

Is That Enough?

Along the same lines as Atlantis, I converted Squishem, Spider City, Terraguard and Sub Chase.

With those I was able to free up enough space to get the menu down to 249 entries.

Safe for now.

Well, it would be if the menu data had not overflowed the available space in the part of the ROM where it lives, so I had to shuffle a lot of code around to make it fit.

But we're OK for now.

Still space for some more games, but limited menu entries available.

I am going to need to make some big changes if I need to add anything significantly more over the next few years.

Maybe I need to start thinking about the Penultimate +4 ...

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.

Stop Press!

I am going to do another batch of Mini PET 40/80s with keyboard, with a few updates.

These are pre-order now, shipping worldwide end of November. £450 kit / £500 built.

Available exclusively from me, contact me using the link at the top of the page to get a price for shipping and any duties, based on your address.

The Mini PET 40/80 internal PET replacement boards are also available now, £350 kit / £375 built.

Again contact me if interested.


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, 1 November 2026

Cosmic Snake - Writing Code Without Using Zero

In the previous post, I looked at Cosmic Snake for the VIC20, a game which was partly written in BASIC, and partly in assembler, with the code hidden in REM statements at the start of the program.

This is a technique used a lot on the ZX81, but rarely in Commodore BASIC as it has one major limitation - you cannot use zero.

If any of the code assembles to a binary $00, it will be seen as the end-of-line marker and the code after will be truncated.

That also means you cannot JSR, JMP, read or write to any addresses containing zero, (i.e. $9600, $1E00, $0042, etc.). There are ways around this, as we will see, but it complicates some things and leads to some convoluted code to avoid it.

If you have any variables or tables in this space, you also need to make sure they will never contain zero.

I guess this must be what it was like to write VMDII assembler for your VIC XX if you were a Roman.

Aiming For Zero

Here are three lines of code just to get A to $00, because you can't do LDA #$00.

Four bytes seems a bit unnecessary.

This is not a Z80, so you can't do XOR A, which would set A to zero.

If it not later 65C02, so we cannot use the nice STZ opcode which stores a zero.

It is going to need at least two bytes, which is what LDA #$00 would have been anyway.

There are many places in memory which will already contain $00.

It is defined that the start of BASIC memory should be zero, so $1000 would always be zero, you could read that

LDA $1000

The first line number is 0, so $00 $00 is stored at $1003 and $1004, you could read one of those

LDA $1003

But those are three bytes (still less that four), so to get down to two bytes needs a read operation from zero page.

There are various unused locations there that could be set to zero, POKE the address from BASIC, set it once to $01 and decrement it, or find one that would always be zero, for example:

  *0099     153      Input device (normally 0)

and then

LDA $99

Although giving that a name would be clearer

LDA ZP_ZERO

would assemble to two bytes, the same size as LDA #$00.

But it seems that none of those are used, instead we have lots of alternative workarounds.

Reverse Engineering

I find this an interesting challenge. Looking at the code as it currently is, there is a whole bunch of bytes. Some are code, some are data, some are BASIC line structure, and some are just padding.

I like working through and finding a variable and trying to work out what it is being used for. Where is is written to? when is it read from? what values will it contain?

The process was just a case of divide and conquer, breaking things down into functions and blocks and trying to work out what each one does.

As the code is a mixture of BASIC line structure, code, possible variables or tables and padding, I can't just run it through a disassembler as a whole.

Instead, I am using the disassembler in Vice.

I start at each REM statement line and look for valid code.

This section looks like a function.

The two bytes before are CLI, $58, the "X" character that fills the REM statements, so I think it is safe to assume that the function starts at $18C8.

The only jump, a BNE is to an address within the function, so I think it finishes at the RTS.

I cut and paste that section into Visual Studio Code, which I am using as an editor.

I don't need all the address and bytes on the left, so I can use the block select, which is quite handy to have in VS Code and is something I used to like about Notepad++.

Hold down SHIFT + ALT and you can select just that block that I need to remove, and then press TAB to set the code in it's normal location 4 characters from the left hand edge.

The *=$18C8 sets the address, so when the file is assembled, this code will overwrite what is currently at $18C8, which is a run of $58, the "X" padding characters. Overwriting the file like this means I don't need to worry about line formatting or padding, just blocks of code.

This is a local label, for local people. There is nothing for you here.

I am starting to split it up into sections, the first being the slightly convoluted way to make A=0.

As mentioned before, the BNE instruction branches back into this function, so I can replace that with a local label.

The - branches back to the nearest - label before the branch instruction, and a + will branch the next + label after the branch. You can do -- and ++ etc. to nest these on some assemblers, but I tend to switch to names at that point to avoid confusion, but for simple loops like this and "skip over the next few lines", they are ideal.

That just cleans things up a bit, my aim is to get rid of as many of the magic numbers as I can, and replace everything with named values or local labels where appropriate, etc.

Don't Keep Asking Me Why Reg

One of those is in the range $900x, which is the VIC chip.

It looks like it is writing A (which is zero) to $9009, which is the paddle Y register? Y Reg? Why?

Ah, but X starts at $01, so the instruction

STA $9009,X

Will actually write $00 to $9009 + 1, which is $900A. This is the register which controls the frequency of oscillator 1, which is more likely to be what we want here.

Then X is incremented, and checked against 6, if it is not 6, it loop back around.

The second time around, X is 2, so it writes to $900B, the frequency of oscillator 2.

Then $900C, the frequency of oscillator 3, then $900D, the frequency of the noise source.

The last time around the loop, it writes to $9009+5 ($900E), setting the VIC volume to 0.

That makes more sense, this is basically a "stop making sounds" function.

To make that clearer, rather than

STA VIC_PADDLE_Y, X

I have written that as

STA VIC_OSC1_FREQ-1,X

$900A-1 is $9009, so the code assembles to the same thing, but it is hopefully clearer what is intended rather than leaving it as just the number $9009 or changing it confusingly to VIC_PADDLE_Y.

Continuing on with the next section, and I can see in there are several calls to $18B6, which can now be updated.

There Has to be Another Way

It is interesting to note that there is no reason for this one-based confusion. It is used throughout the code, in many cases because it is just easier to avoid zero that way. But in this case, it is almost confusing for confusing sake, or maybe just a desire to keep everything one based rather than a mix of zero- and one-based?

The code actually starts by setting X to 0, and then sets it back to 1. It could have been left as zero, and then the function would read more logically.

Or, start with X as 5, and decrement until it gets to 0, we need it to keep going for that last loop, so you can change the branch instruction to BPL -, branch is the number is positive, which will be correct for 5 down to 0, but when it rolls around to $FF, the test will fail and it will move on to the RTS.

Going backwards is not always an option, but in this case, i would actually be better to start by setting the volume to 0 first.

You might also consider using X as an offset to the VIC base address $9000, and run the loop from $09 to $0E.

But the VIC base address is $9000, and that would assemble as $9D, $00, $90, which contains $00 and would cause the rest of this line to be truncated.

For now, I am leaving all the code as is, so I can continue to build a binary identical version.

Line 0

The first line is line 0, ironically you can use zero as a line number. This does not appear to start with valid code?

It seems to be rubbish until $1080 where it looks to be a valid function.

This fits with the BASIC code, which calls SYS 4224, which is $1080.

I worked that out to be a function that copies the data from $1006 onwards into RAM at $1D88, which is later set to be user defined graphics.

It is a little more than a straight copy.

It reads the data, byte by byte, and checks each one to see if it equals $01. If it does, it subtracts $01 to get the otherwise unobtainable $00 value. Presumably there was no need for any $01s in the character data.

You can see the results after the copy, the source first, then the destination, with all the $01 bytes changed to $00.

Fire!

Another short function that shed some light on things was this one.

>C:1150  22 91 60 58  58 58 58 58  58 58 58 58  00 5c 12 02   ".`XXXXXXXXX.\..

>C:1160  00 8f 02 02  58 58 ad 11  91 09 df c9  ff f0 05 a9   ....XX..........

This shows the end of line 1, with the row of XXX padding characters, then the $00 which indicates the end of line (the only time you can use a zero, other than in line numbers and the address of the next line).

$125C is set as the address of the next line, and $0002 as the line number.

There is then the $8F which is the REM token, then some code?

It does not start with valid code, two $02 (invalid op-codes, causing a CPU JAM), then two $58 padding characters, then what looks like a function follows at $1166.

This again ends with an RTS and appears self contains as the only branch, a BEQ will jump to the RTS line.

As before, I split that up, but left space for the two $02 bytes. I used another *= to skip over the padding bytes.

$9111 is the VIA#1 PORT A, and it looks to be masking off bit PA5, which is the joystick fire button.

If that is high, then the button is not pressed, so the function exits via the BEQ and the RTS.

If it does not equal $FF, then the pin must be low, so fire is pressed.

When this happens, it sets address $1162 to $01.

Hang on, that is the address of one of the $02 values above.

OK, so those are used as variables, I added V_ and R_ prefixes to try to track variables and routines (also T_ for tables and L_ for links), and a local label for the branch forward.

V_1162 starts as $02. Elsewhere in the code, in what I think is initialisation, it is set to $02.

The rest of this routine reads from an address which is the IO chip, and based on the bit is is checking, this is looking for fire being pressed. If it is pressed, it sets this flag variable to $01.

Elsewhere, it checks if the value is $01 and starts a process I worked out to be firing the missile.

Once it sets the missile in motion, it sets the value back to $02.

It also sets to back to $02 later during the movement of the missile.

There are no other references I can see to V_1162, so I think that is it's entire job.

From that, I can say that is a "Fire has been pressed" flag, and the other variable here V_1163 is "a missile has been launched" flag.

These are only ever set to $01 or $02, and are only checked for those value.

I think I can conclude the values are being used as

  • TRUE / ACTIVE = $01
  • FALSE / INACTIVE = $02

I am sure the programmer would have liked to use the more standard $00 for false and anything else for true, but of course we can't use $00 here, so the logic here is using $01 and $02.

There is another function buttoned up. I have left the literals for the mask values, I could have changed those to PA5_MASK or FIRE_MASK, but I think it is fine for now, I have added appropriate comments.

Turning the Tables

The third line number 2 started with a block of numbers before the valid code started.

Those were referenced by the following code. Registers A, X and Y were stored in $177E, $1780 and $1781 respectively, and were restored at the end of the function.

There was then a reference to $1778, but this was +X, so $1779,$177A etc.

I worked out this was the "update the score" function, and $1778 was a lookup table for scores.

The scores were of course stored plus one, but I thought it would be better to show those as 50+1 etc.

The temporary A,X and Y register locations were also named and the final byte was a variable used to store the number of points read from the table.

It would then loop around that many times, updating the score digits directly on the screen.

(why not load Y with the number of points and then DEY to avoid the compare, and why use JMP - when BNE - would have been shorter and also protected against infinite loops as it would eventually hit zero and not branch)

Writing to the screen

When I see JSR calls in the range of $B000 - FFFF, these are KERNAL routines, normally well defined and documented, so when I see those I can replace them with the function names.

Likewise, there are defined ares in zero page and $0200-$03FF that can be labelled appropriately to help understand what is going on.

This short function, followed by lots of padding, references two known memory locations.

From those, I could also understand the relevance of the values $07 and $39 in the code.

This is setting the current colour used by the kernal print routines to $07 (yellow) and using the print routine to print a character $39 to the screen.

This is one in the range which was copied over at the start of the code, and I had worked out was the snake graphic.

In order to use that function, there must be a call to set the location on the screen somewhere ...

Found it, a call to $FFF0.

It took me quite a while to work all that out because some of the references were to a variable at $1508, e.g.

LDX $1508

but others were as if $1508 was the start of a table

LDA $1508,X

I need to remember how the author is working here, it makes more sense when that is written as

LDA $1509-1,X

I worked out that $1508 was an index to the current portion of the snake being drawn, and there were several tables this indexed showing X and Y positions and I think direction (or possibly status).

With those defined, the code makes more sense.

This sets the X and Y location to be printed using the PLOT function.

Those are read from a table using an index (stored plus one to avoid containing zero, so the table address is -1)

And of course, the values are also stored plus one as they cannot contain zero.

(there really is a whole lot of work required to avoid using zero here)

But Wait, That's Cheating!

This function started by reading and writing to certain bytes in the $1Dxx region. This is where the user defined graphics are stored in this setup. Is it changing part of a character?

I thought this might have been related to the mushrooms being blasted away by fire, but that is handled by one of four different characters with different states of destruction.

I finally worked out that these were actually being used as variables.

Variables in real RAM!

Variables that can contain zero!!

But that is cheating!!!

If you are going to do that, why not put all the variables in there so we don't have to do this +1, -1 all the time.

Why not put the code there as well, save us all a headache?

I worked out these are being used as player X and Y locations. When the joystick is checked and the player needs to be, the new location is calculated and what is there is checked, using the KERNAL PLOT and the zero page CURSOR_POS and CURSOR_LINE_PTR functions, (which is quite a neat way of doing it)

That all seemed to make sense, following the code through until I hit a line that didn't make sense.

The code is reading in the port which contains several bits which are the joystick directions (3 directions plus fire, the 4th direction is on another port, because VIC20....)

If it detects the joystick is to the right, it increments the player Y position, to the left, decrements Y, etc.

When it comes to checking up, it should skip over the 

DEC NEW_PLAYER_X 

line if the joystick is not held up.

But rather than

BCS $10E9

Which would branch over the next line and continue, it does

BCS $10E7

This branches into the middle of the next instruction.

It just happens that $86 $1D represents a valid bit of code which does not break anything.

It unnecessarily writes X to address $1D, which is some temporary storage for strings in BASIC.

0019-0021 25-33 Stack for temporary strings

All I can say is the author was very lucky, that could easily have been invalid code and broken things, but by a fluke, it works out to be an innocuous instruction and it continues at $10E9 where it was meant to go.


I have not completed the whole disassembly, I will probably return to it at some point. It is an interesting process, and keeps my mind occupied anyway on days when I don't have the energy to do anything else.

I learned a few new tricks, but I suppose the main takeaway is, yes, you can store code in REM statements on a VIC20, but you really, REALLY, shouldn't.

I suppose you could rewrite this as "code at the end of the file" style, I wonder how much better / easier it would be..... No.....

Or even entirely in assembler ....

No.... Must not rewrite it ......

Adverts

All Tynemouth products are still available direct from me, 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.

Stop Press!

I am going to do another batch of Mini PET 40/80s with keyboard, with a few updates. 

These are pre-order now, shipping worldwide in November. £450 kit / £500 built.

Available exclusively from me, contact me using the link at the top of the page to get a price for shipping and any duties, based on your address.

The Mini PET 40/80 internal PET replacement boards are also available now, £350 kit / £375 built.

Again contact me if interested.


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. Paid Patreon supports will be getting the third part shortly, and maybe a forth part three will follow if there is any interest

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.