Trenchangle: Tower Defense on the C64

I picked up Issue 31 of Zzap! 64 yesterday evening and had a quick look at the covermount disk. There’s a few really good-looking games there but one that caught my eye was Trenchangle, a tower defense game!

Zzap!64 disk with cute disk art!

I’m a sucker for the genre, but it took me several tries to even finish level one. I should have added arrows to the arrow tower instead of expanding the tech tree available. Lesson learned.

The game doesn’t require a joystick, and it’s possibly easier to play in an emulator because you can use the cursor keys to navigate. I couldn’t see anywhere to redefine keys so that joystick might make it easier to play on a real machine.

Game progress can be saved and reset, which means I’ll definitely be coming back to this game for quick plays. It looks like it saves in a file called “GEOTSTATE”, which wasn’t there when I first opened the D64 file so it can be deleted.

There is a cracked and trained copy on CSDB, but this is a brand new C64 game. Support the developer and pay what you want on their itch.io page.

DolphinDOS 2: Fixing a 35-Year-Old Bug That Never Was

DolphinDOS 2 is a replacement ROM for the Commodore 64 and its 1541 floppy disk drive that dramatically speeds up disk access by using a parallel cable between the two machines. Instead of the glacial CBM serial bus, data transfers happen byte-at-a-time over an 8-bit parallel port, making loads roughly 25x faster. I’ve been maintaining a custom version for myself. It changes the keys used to list the contents of disks and load programmes to match the Action Replay that I’m more familiar with.

A Commodore 64 boot up screen saying
"COMMODORE 64 BASIC V2
DOLPHINDOS 2.0 38911 BASIC BYTES FREE

READY.

It also works in Vice, Ultimate64 and Commodore 64 Ultimate!

While I blogged about buying a real Commodore 64 in 2019, I didn’t post about buying an Ultimate 64 a few months later. The version I have is the non-Elite version but it’s quite a wonderful device. Unfortunately, life got in the way and the machine lay mostly unused for years. I must make a post about that little beauty one of these days. Anyway …

I just released version 1.2 of my DolphinDOS 2 project, and there’s a bug fix for a seemingly rare problem: a bug in the original DolphinDOS 2 ROM from the late 1980s that almost certainly never manifested on real hardware. It seems so rare I’ve never read of anyone complaining about it on any C64-related Facebook group until this bug report surfaced. The parallel port would randomly be switched off when a C64 Ultimate was switched on!

It was never my intention to go diving into the assembly of this project. I just wanted to change some keys around, but I had Claude Code look at it, with the relevant sections of the C64 Programmer’s Guide at hand for reference. I honestly don’t have time to fix a rare bug like this, but Claude did. Here’s what it said about the bug. I would be interested in hearing what C64 developers who have looked at the RAM in a real 1541 have to say.

The 1541 drive ROM uses four flag bytes at $6000–$6003 in drive RAM to control DolphinDOS features: R (read), F (fast format), V (verify), and P (parallel port). A value of $12 means disabled; anything else means enabled. The original ROM never initialises these flags at boot. It relies on whatever happens to be in RAM when the drive powers on.

On a real 1541 with SRAM, that RAM almost always powers up as zeroes — so $6003 is never $12, and the parallel port is always enabled. It just works accidentally.

On the C64 Ultimate, the emulated 1541 RAM isn’t zeroed so predictably. Sometimes $6003 powers up containing $12, and the parallel port silently disables itself. A user reported that their C64 Ultimate was randomly booting with the parallel port off. That’s something that would never happen on the original hardware.

The fix was simple enough, set the important memory locations to zero, although it took a couple of tries before it worked.

The fix adds a small init routine at the end of the 1541 ROM’s free space that zeroes $6000–$6003 and sets the track interleave at $6023 during the drive’s boot sequence. The tricky part was that the 1541 ROM has a checksum that the drive verifies on startup. If it doesn’t match, the drive refuses to boot. The new jump target was chosen so its address bytes sum to the same value as the original, keeping the checksum valid without needing a separate compensation byte.

Claude Code did the analysis and wrote the patch. I pointed it at the disassembly and the bug report, and it identified the uninitialised RAM as the root cause, found free space in the ROM, worked out the checksum constraint, and produced a working fix. The reporter tested it on their C64 Ultimate and confirmed it resolved the issue. I tested it in Vice and on my Ultimate64.

Other changes in 1.2:

  • Tapping F1 now auto-runs after loading: previously F1 loaded the first program from disk but left you at the READY prompt. Now it executes RUN automatically.
  • Cursor colour changed from cyan to white matching the look of the Action Replay I’m used to.
  • kernal.asm is now compilable. I converted it to ACME assembler format, so you can modify and rebuild the C64 kernal ROM from source.
  • Install instructions updated for the latest Ultimate64 firmware (which seems to match the C64 Ultimate instructions I found online).

The release is on GitHub. If you’re running DolphinDOS 2 on an Ultimate64 or C64 Ultimate, it’s worth updating.

You can also find the original kernal files here, along with different versions of them. My 1541.rom is based on the c1541-20-6.rom found there. My kernal.rom is based on kernal-20-2.rom. There is a third revision of that kernal rom too. I asked Claude to tell me what was different between them:

kernal-20-2 vs kernal-20-3: What’s different

The code is functionally almost identical. The 911 byte differences break down into a few categories:

  1. The version byte at $FF80
    v2: $03
    v3: $00
    Confusingly, the “revision 2” ROM has version byte $03 and “revision 3” has $00. The filenames may not reflect the actual revision order — kernal-20-3 might actually be an earlier or alternate build.
  2. Code insertion at $EF5C: STOP key check (+5 bytes)
    The biggest functional difference. At the start of the parallel LOAD path, v3 inserts:
    EF5C JSR $FFE1 ; STOP - check RUN/STOP key
    EF5F BNE $EF5C ; loop if not pressed
    EF61 BEQ $EF2E ; if pressed, abort
    v2 has no STOP key check here — it jumps straight into the transfer. This 3-instruction insertion (5 bytes) shifts all the code that follows by 5 bytes, which accounts for the majority of the single-byte differences (they’re all branch targets and jump addresses adjusted by +5 or +6 to compensate for the shift).
  3. Parallel handshake: SEI added at $F841 (+1 byte)
    v3 adds SEI (disable interrupts) at the entry to the parallel handshake routine. v2 doesn’t disable interrupts. This shifts the code in that block by 1 byte and cascades into further address adjustments.
  4. Parallel transfer timeout: timer-based vs loop-based ($F910–$F968)
    This is the most interesting technical difference. Both ROMs have a timeout when waiting for the drive to respond during parallel detection, but they implement it differently:
    v2 (loop-based):
    F92E LDX #$13 ; outer counter
    F932 LDA $DD0D ; check CIA2 interrupt flags
    F935 AND #$10 ; FLAG pin set?
    F937 BNE $F948 ; yes → drive responded
    F939 DEX ; no → count down
    F93A BNE $F932
    F93C DEC $A5 ; nested loop
    F93E BNE $F932
    Uses a nested DEX/DEC loop (~5000 iterations) as a timeout.

    v3 (CIA timer-based):
    F931 LDA #$FF
    F933 STA $DC07 ; Timer B high byte = $FF
    F936 LDA #$19
    F938 STA $DC0F ; Start timer B, one-shot
    F93B LDA $DD0D ; check FLAG pin
    F93E AND #$10
    F940 BNE $F950 ; drive responded
    F942 LDA $DC06 ; read timer low byte
    F945 CMP $DC06 ; compare with itself (has it changed?)
    F948 BNE $F93B ; timer still running → keep waiting

    Uses CIA1 Timer B for a hardware-timed timeout. More precise and CPU-independent.
  5. Parallel fallback path: error handling ($F88B)
    v2: JSR $EE85 → falls into standard IEC byte receive
    v3: LDA #$00; JMP $EE16 → explicitly loads zero and jumps to a different IEC entry point
  6. Serial LOAD: error recovery ($EFF1)
    v2: JMP $EFCF — unconditional jump to byte receive
    v3: BCS $EFD4 — conditional branch on carry, only retries if carry set
  7. Data table pointer at $F0F1
    v2: BIT $DD0D (2C 0D DD)
    v3: STX $DC0C (8E 0C DC)
    Different CIA register access — v3 writes to the serial port register rather than reading the interrupt flags. This changes how the timer/shift register state is managed after a transfer.
  8. Jump table entries ($F8B1–$F8C9)
    Several address entries in what appears to be a function pointer table are shifted by +6 bytes, consistent with the cumulative code insertion offsets.

Summary

Changev2 (your base) v3
STOP key during parallel LOADNo checkPolls STOP key
Interrupt disable on handshakeNo SEI SEI at entry
Parallel detect timeoutSoftware loopCIA Timer B
Error recovery on serial fallbackUnconditional retryConditional on carry
Version byte $FF80$03$00

v3 appears to be a more defensive build — it adds interrupt protection, hardware-timed timeouts, and a STOP key escape during parallel transfers. These are the kinds of changes you’d make after encountering real-world reliability issues on certain hardware configurations.

Whether v3 is “better” depends on context. The CIA timer approach is more robust, but the STOP key polling loop at $EF5C is a tight busy-wait that could introduce latency. For the Ultimate64’s emulated parallel port, which is inherently reliable, v2’s simpler approach is probably fine.

Looks like version 2 of the 1541 kernal rom is fine for our use case.

I’m using Claude Code in my work at Automattic all the time. It’s been a huge help in getting through bug fixes and adding new features to the various projects I’m working on. I’ll be posting more about WordPress related goodness soon. Stay tuned.

Choo! Choo! Freeze64!

Freeze64 issue 68, featuring an illustration of a train and riders on horses

Well, chug along and check this out! Freeze64 Issue 68 steamed its way into my mailbox, featuring a review of a train robbers game I never knew existed. Plus, there’s another captivating instalment in Andrew Braybrook’s Uridium “making of” series. I always enjoy diving into the technical details of retro development. You’re constrained so much, it’s a challenge fitting a game into such an environment.

Impossible Mission III looks great too. I wish I was able to get further in the original game. Maybe this one will be easier. C64 games are hard as nails, aren’t they? Quite unforgiving compared to (many of) today’s games.

Writing C64 ASM in VS Code

Thanks to this Hackaday article, I found a video describing how to use Visual Studio Code to write 6502 assembler for the Commodore 64!

It’s been a long time since I’ve done any ASM on the C64, and compared to the programming environments available these days, I was working in the dark ages with my Action Replay monitor, typing code directly into memory.

Kick Assembler is used to assemble the code into a .prg file, using the KickAss (C64) extension for VS Code to launch the emulator with the code loaded into memory. I see Kick Assembler 8-Bit Retro Studio is mentioned in the comments, and it is indeed still being developed, so it might be the better choice, but either will make developing on the C64 much simpler.

It gives a nice overview of using Git to track changes too, something I would have also loved on the C64. So many files prefixed with numbers as I experimented with effects …

Play C64 Games Online

The Great Gianna Sisters title screen

If you’re in the mood for some retro gaming, head on over to this site, where you can play lots of old Commodore 64 games in your browser! Unfortunately, Firefox caused the audio to stutter, but the games play fine in Edge. I tested Flimbo’s Quest and The Great Gianna Sisters, and they were perfect. I somehow made it to level 5 in the latter game rather quickly. I normally use all my lives in level 2!

There is a huge C64 games archive at archive.org, and there are loads of demos there too! Give Arkanoid 2 a spin while you’re over there. It’s even trained, and you can play with infinite lives! The keyboard controls are the two shift keys and space to fire. 🙂

Goodbye to 2022

The great Oli Frey created the cover for Zzap!64 issue 68, 1990. It was the last picture in the Zzap!64 2022 calendar. It celebrated the release of Chase HQ 2. I don’t remember playing that game, but I must have. I definitely played the first game and it wasn’t great. Here’s a play through of it. Are those Dick Tracy adverts at the side of the road? Oh dear!

Time to put the calendar away but I guess I can use it again in 2033, 2039, 2050, 2061, 2067, 2078, 2089, 2095, 2101, 2107, and 2118. I wonder if people will still use paper calendars in 2118?

RIP Oliver Frey

ZZAP!64 Issue #50: Speedball

Back in the day, magazines were a huge part of the computer scene. Each machine had a dedicated magazine, and if you were lucky, more than one.

I bought my Commodore 64 in 1989, but I had a Speccy 48K before that. A company called Newsfield published a magazine called Crash that catered to the interests of the Speccy, and also one called Zzap!64 for the C64. The transition from Speccy to C64 meant moving from one magazine to another of course. One constant in both worlds was Oliver Frey’s amazing artwork that graced the covers of both magazines.

My favourite is probably the cover of issue 50 of Zzap!64, the first issue of that magazine I ever bought, but he painted so many others it’s hard to choose.

Choose I did however, as I bought a number of prints off his website in late 2021. I bought the Speedball print featured above, as well as the Retrograde and Elite covers. I’m awful for hoarding things and I still have the tube the prints came in with what is probably Oliver’s writing on it, or maybe his partner, Roger’s, who knows?

All this is to say I’m a huge fan and admirer of Oli’s work. So it was with great sadness that I read that he passed away at 7:55 this morning. He was only 74. Thank you for the art, Oli. My condolences to your partner, family and friends.

Bye Bye Relics of 1999

It’s about time I dumped some of this stuff. Two of my machines have a CDROM drive but I don’t use either of them. I haven’t had a 1.44MB floppy drive in well over a decade, or more likely fifteen years!

I recently found the binder with these items, the motherboard manual and other things. They were stored away in a dark corner of a cupboard for more than 20 years. Safe in their dark spot but ever so slowly decomposing. The machine they belonged to has been long disposed of.

When was the last time you installed software from a CDROM or a floppy disk? I ripped the DVD box set of “All Creatures Great and Small (1978)” last December. It was on my ageing Macbook, but I do not remember the last time I used a PC floppy disk at all.

February 2012 was the last time I used a C64 disk. I archived as many of my C64 disks as I could then. Those disks are still in the attic. I don’t know if I’ll ever be able to throw them out. I guess they’ll be disposed when I’m gone and they’re an ancient artefact of a bygone era.