Sunday 10 November 2024

VIC20 Multipart Game Conversions - Tank War

Tank War is a pretty simple Atari 2600 Combat clone for the Commodore VIC20. One or two players drive tanks around a fixed maze shooting at each other.

Very slowly.

But then again, I guess tanks do move quite slowly anyway, so lets call it an accurate simulation. 

And it has tank controls, but again, so do tanks.

When this was suggested to be added to the recent update to the Penultimate Cartridge, I found a PRG file in the archive, but that was missing the instructions screen, so I set about converting the cassette version.

You know the score with these by now, the memory on an unexpanded VIC20 is small, so you can't fit the instructions and the game in at the same time. Most games of the time got around that by loading in a program that contained only the title screen and instructions, and then loading the game over the top of that ready to play. Some were clever enough to do that in the background whilst you were reading the instructions, others left you hanging on a Loading.... screen.

The tape version of Tank War puts up a single screen of instructions, and then loads the game in the background. Should be nice and easy......

Step one then is to extract the programs. I loaded the first one from tape. It is BASIC as expected and listed it.

The code immediately jumps to line 110 (which prints the instructions), then jumps back to line 10 (which pokes a short machine code routine into memory and runs it).

The plan here is a cartridge conversion. Code I have used many times before copies a block of data from the ROM into RAM at the appropriate location and then runs it. For the multipart games, to get the second part, I replace the tape loading code with a jump back into the ROM. The code there then copies the second block of data into RAM over the top and the first and then runs that.

Here I just need to get ride of all the data statements at the start, the FOR loop and SYS command, and check which of the POKEs I need to keep. Finally I will add the SYS command in to jump back to the ROM.

Since this was quite a simple few changes, I just made the mods in the Vice VIC20 emulator I had been using to test things.

To test it, I just put a breakpoint on the jump address to check it gets called.

I tested it and .... it reset the VIC?

I was a little confused, thought I might have left some of the old SYS calls in or got the new SYS call wrong, but they all looked right.

Just to make sure I hadn't broken anything, I thought I would compare the files, and to do that, I used petcat, a useful command line utility the comes as part of the vice emulator. Pass it a PRG file and it print outs the program listing.

Hello, what's going on there.

Two magic hidden lines?

    0 rem *** tank war ***

    1 ifpeek(849)<>43thensys64802:rem"{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}

    2 sys850:rem"{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}{del}

Those do not show in the listing as the code at the start is hidden by the REM statements full of backspace characters. That's quite neat really.

Let's see what it is doing.

    1 if peek(849) <> 43 then sys 64802

This checks to see if the value at 849 is 43, if not is calls the routine at 64082 ($FD22), which is the system warm reset, which explains what I was seeing.

(I normally try to keep to talking about things in hexadecimal, as it is often easier to follow, but since a lot of this is BASIC, I will have to use a lot of decimals, the $ prefix is used to indicate hexadecimal values)

But what is it testing. Well, 849 is somewhere in the cassette buffer. Really?

So, the author knew after loading the unmodified version from tape, the value in the tape buffer at 849 would be 43. OK.

Let's check the other line.

    2 sys 850

Oh, so now it has checked the right value is at 849, it starts to run code from 850.

Let's check the RAM

Oh, is that all?

849 ($0351) is 43 ($2B) and 850 ($0352) is $60, an RTS instruction. So if the right data is in the first bytes, it will execute the second byte, the RTS instruction, and return back to where it was called from. If it is wrong, it could do anything, but most likely lock up.

That means if you were to edit the file and re-SAVE it, the new version would not have those extra bytes, and so it would fail to work. Neat.

Now I know those are those lines are there, I can just delete them, along with the comment line (may as well, it makes the file smaller).

Let's see what's left.

   10 data 169,1,162,1,160,1,32,186,255,169,0,162,255,160,255,32,189, 255,169,0,162,255,160

   20 data 255,32,213,255,76,0,16

   30 for a=0 to 29 : read b : poke 256+a, b : next : sys 256

The code in lines 10-30 contains a small machine code routine which is POKEd into addresses 256 ($100) upwards. This is the bottom of the stack. A reasonable place to put code, and one that is not exploited much.

The code is standard fare for this sort of things. Call SETLFS, SETNAM and LOADSP, which together are the equivalent of the BASIC "LOAD" command.

It then jumps to $1000 to run the newly load code, the game itself.

That means it never actually executes line 100?

   100 poke649,0:poke37150,2:poke788,194:printchr$(142)chr$(8)

A little odd, maybe left over from a previous version? Let's investigate.

   poke 649, 0

This sets the length of the keyboard buffer to 0. Not ideal as I need that for a "press any key" routine.

   poke 37150, 2

This disables the restore key interrupt

   poke 788, 194

Addresses 788 and 789 ($0314-$0315) contains the address of the routine used for hardware interrupts.

Normally this is $EABF, but this poke changes that to $EAC2. This jumps into the same routine slightly later, bypassing a call to $FFEA, which updates the jiffy clock and checks for the RUN/STOP key, so that poke will stop RUN/STOP being checked.

   print chr$(142) chr$(8)

This sets uppercase font mode, and then locks it from being changed.

That all seems sensible, I presume the code originally jumped to 100 to do this before displaying the instructions, but it must have been bypassed at some point.

I changed line end form

  210 print"{grn}    {down}please wait...{red}"

  220 goto10

to

  210 print"{grn}    {down}press a key...{red}"

  220 poke198,0:wait198,1

  230 sys41088

There is no line 10 to go back to, so I just wait for a key press and then just back into the ROM for part 2.

I borrowed a neat little "press a key" trick I have seen in several of these loaders.

   poke 198, 0 : wait 198, 1

This clears the count of keys in the keyboard buffer and waits for it to change to 1. Quite neat really.

It doesn't consume the keypress, so it will still be in the keyboard buffer. (I was hoping it would mean if you pressed F1, that would be read by the game and it would start immediately, but that didn't happen, I guess it clears the queue when it starts up.)

Speaking of part 2. That was slightly unusual. The load address was $1000, rather than the usual $1001 for a BASIC program. Not really a problem, this is not BASIC, so it is using every last byte available from $1000 to $1DFF.

That $0E00 bytes plus $0200 from the intro and the small ROM loader code means it is slightly annoyingly a little over 4K. Ideally I would have fitted it all into an 4K cartridge, but I will just have to go for 8K.

In the Penultimate, I can crop it down to 4K + one extra 256 byte page, so I get most of that space back.

Time to test it out.

And there we go.

I wanted to test that it would loop back around to the start page correctly. 

It took ages.

The AI is rubbish. It doesn't seem to track or intentionally fire at the player. The controls are also a bit lumpy, so it's also not that easy to wipe the AI player out.

I was hoping it would stop at 10, and it did indeed.

I guess it is first to 10 wins.

And back to the title page.

But wait, I hear you all cry (which is unlikely as there are probably only 3 of you who will ever read this.)

But wait, how did those magic bytes get added to the end of the file in the first place?

I am pleased you asked.

It is all to do with the filename.

Looking at the tape buffer after loading the Tank War.

What you get is 01 (not sure what that signifies?), then $1001, the load address and $12D0, the end address, then the filename, "TANK-WAR". The $2B and $60 are hiding amongst all the spaces on the line below.

But how do you do that?

Here I have entered a simple program and saved it with the name "NORMAL".

If I reset to clear the memory, and then load it, this is what is in the tape buffer.

The filename is there, followed by lots of zeroes.

What you need to do is make the filename longer than 16 characters.

Here you can see the "TS" I have added to the end (it wraps around to the next line on the screen). It is also shown in the "SAVING" message below that.

If I now do a reset and reload, the TS has been dropped from the filename, as only the first 16 characters are displayed.

But, if you look in the tape buffer:

There is the "TS" I secretly added.

But hang on, that's just letters, how do you get the 43 and the RTS?

Another good question.

CHR$(43) is a + in PETSCII, so that is easy

RTS is $60, which is a horizontal line in PETSCII, so you just press the right keys.

Well, not quite. There is a uneasy relationship between character codes and what is displayed on the screen PETSCII horizontal bar is $60, but when you press shift + * to get that, it shows, but in memory it is actually $40 and when you load it back, you get $C0 !?!?!?!

Even if you do POKE 7835, 96 (which should put the value $60 into address $1E9B), that puts the right value into screen RAM, but when you load it back, you get $A0.

It can drive you mad.

To save my pulling out what remaining hair I have, I tried the following poking in the values for $20, $60, $A0, $E0, all the variations + and - $40.

None of those worked.

I also tried $00 $10 $20 etc. up to $F0, and none of them end up with 60 in the file, I got $20 $40 $50 $20 $30 $C0 $D0 $A0 $B0....

It does not look like anything you can type into a BASIC SAVE command will result in $60 as required.

I think it must have been done with some assembler similar to that shown above to load the program, but setting a filename with a $60 at the end.

I think I will leave it there. There are already enough head shaped dents in my wall from dealing with Commodore screen codes vs character sets in the past. I will leave that as an exercise for the reader. I need to go for a lie down.


Advertisements

Tank War is one of the games that have been added to the upcoming release of the Penultimate, in it's normal +2 format and the new +3 version which has a built in SD2IEC drive.

More of those should be shipping this week, I will go into more detail in a full post to follow.


Minstrel 2 and 3 kits are available from my Tindie store, with worldwide shipping. Versions avaiable for ZX81 case or standalone with keyboard, and also Misntrel 3 with ZXpand microSD card interface.

I will slowly be moving things over there from my SellMyRetro store, so if there is anything that you want, let me know and I'll add it.

More info can be found here:

Patreon

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

Sunday 3 November 2024

Minstrel 2 Update

I recently reopened my Tindie store, see http://blog.tynemouthsoftware.co.uk/2024/10/a-change-of-plan.html

Before I did that, I was running low on stock on most things, so I needed to order more boards.

Since I was doing that, I thought it would be a good opportunity to make a few changes.

This is the new Minstrel 2, a Z80 based self assembly computer kit which is compatible with the Sinclair ZX80.

This is now a single PCB "Minstrel 2 + Keyboard" version.

Although it is still available without the keyboard to fit a ZX81 case.

And I suppose I should keep the "dual detachable keyboard" version as well.

I will offer built version, but most people want to build their own kits.

I forget how many single resistors there are in the ZX80 design.

It doesn't look too bad when they are all in little bags.

Assembly is straightforward, start with the smaller parts, the resistors, capacitors and diodes.

These should all be neatly in line.

I have used a different brand for some of the capacitors, these have a much clearer marking, see the 104 and 473. They do not currently have all the values, so those are still the older style (e.g. K16 470J).

The ICs should all line up nicely as well. I love the way the Texas Instruments 14 and 16 pin ICs are the same width, so you can mix them and they all look the same (can you spot where it changes?).

Next all the taller parts, the connectors and pin headers.

I added two footprints for the 5V regulator on the V2.9 version of the main PCB. The switching regulator is recommended, and is set back a little to fit better in a ZX81 case.

The 7805 linear regulator can be used, but will require a small heatsink (I should have removed it from the "+Keyboard" version as there isn't space to fit one where it would be in the "for ZX81 case" version.)

Finally, the three big chips in sockets, including one of the last Z80s ever made (while stocks last).

To protect them in transit (and so I don't need to count to 40 lots of times), the switches are supplied inserted into the PCB.

If you think they will get in the way, you might want to remove those until you have finished the rest of the soldering.

If you fit the screws and spacers to the overlay PCB, it is useful to make sure all the switches are sitting flat and correctly aligned.

You can then screw on the pillars and solder the switches in place.

(N.B. you don't actually have to solder the switches in place, they will work just on the mechanical connection, certainly for testing. However, long term the legs can tarnish over time and you might start to get an intermittent connection. It is also more difficult to solder later if they have tarnished)

Time for some testing.

The traditional 10 PRINT.

And also in 4K BASIC mode (note the different font with no slash in the zero).

Also time to try some games.

Paul Farrow's ZX81 Kong is a good test as this runs on the ZX80 style hardware of the Minstrel 2, and shows off the changes in the last Minstrel 2 update to clean up the glitches around adjacent inverted and non-inverted characters, which showed up on the Kong in the title screen.

All nice and clean and evenly sized pixels.

The cost of some parts have increased dramatically, but I have tried to keep the pricing as it was before.

And there are an awful lot of them to add up.

And of course the Z80's, they must be worth $1M each by now.

I am in the process of revisiting the documentation for the Minstrel 2 and 3. With the Minstrel 2 in particular being expanded quite a bit with a new "theory of operation" section along the lines of the one in the Minstrel 3.

I also want to have a go at redrawing the schematic as a single large page in the style of the original, although I am not sure how that will go. I might end up selling that as a poster instead.


Advertisements

Minstrel 2 and 3 kits are available from my Tindie store, with worldwide shipping. Versions avaiable for ZX81 case or standalone with keyboard, and also Misntrel 3 with ZXpand microSD card interface.

I will slowly be moving things over there from my SellMyRetro store, so if there is anything that you want, let me know and I'll add it.

More info can be found here:

Patreon

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