Converting the “Competition Pro Extra USB” to C64/Amiga/Atari DB9

The new Speedlink Competition Pro Extra USB joystick has all the phsical properties and the excellent switches of the original Competition Pro, but comes with a USB interface. While this is great for use with The64 Mini for example, this joystick can be easily converted into an old-school DB9 joystick to work with Commodore, Amiga and Atari computers and consoles – without giving up the USB interface!

There is a small board inside that converts the output of the switches to USB.

The inputs of the switches come in through this connector:

Converting this joystick into an C64/Amiga/Atari one is as easy as connecting the wires to a female DB9 plug. It is easiest to buy a 9-pin RS-232 extension cable and use the female connector and its wires. I’m using the cable by Renkforce for 6€, so if you get the same, the wire colors should match mine.

This table shows the pinout of the connector inside the Competition Pro Extra, the corresponding DB9 pin and the wire color in the Renkforce cable.

Pin Color Description DB9 Pin Renkforce Color
1      gray Left 3      orange
2      purple Down 2      red
3      blue Right 4      yellow
4      green Up 1      brown
5      yellow GND 8      gray
6      orange Button L 6      blue
7      red Button R 6      blue
8      brown Button L2
9      black Button R2

The joystick has 4 buttons, but basic DB9 joysticks only support one button. In the table above, I decided to wire up both round buttons, and leave the two trigular buttons unconnected.

In case you are using a different DB9 cable, here is the connector pinout:

Pin Description
1 Up
2 Down
3 Left
4 Right
5 (unused)
6 Button
7 (unused)
9 (unused)

Dual-Port: USB and DB9

There are several ways you can make the connections. One is to stick the DB9 wires into the side of the connector, then glue them:

Or you could solder the wires to the other side of the PCB.

The wires for the USB port do not have to be disconnected: As long as the circuitry is not powered through the USB plug, it is completely passive, so you can use the joystick with either of the two connectors!

DB9 Joystick + Adapter

The other option is to remove the USB board and connect the wires from the switches directly to the DB9 wires.

Then, you can use the other side of the RS-232 extension cable and the USB board to build a DB9 to USB adapter:

Through the adapter, you will lose access to the four individual buttons, though.


DB9 joysticks do not have the two D-sub screws. If you are using a an RS-232 connector, it will be wider because of the screws, and you won’t be able to fit two of these into the two control ports of a C64, for example. If you care about this, you will need to cut off the sides of the connector, get a connector without the screws, or cannibalize a broken joystick.

Ultimate Commodore 64 BASIC & KERNAL ROM Disassembly

My side-by-side C64 ROM disassembly/commentary page has been completely redone!

New features:

  • Six different commentaries
    • Original BASIC/KERNAL source comments
    • Data Becker
    • Lee Davison
    • Bob Sander-Cederlof
    • Magnus Nyman
    • Marko Mäkelä
  • Columns can be invidually enabled/disabled
  • Sticky first column
  • Color coding
  • New name: c64disasm

Thanks to @ellduin for the HTML/CSS magic!

The project is maintained on GitHub: – contributions highly welcome.

Visualizing Commodore 1541 Disk Contents

G64 files are C64/1541 disk images that contain all bits as they are physically laid out on the 5¼-inch floppy disk. Let’s visualize them!

This animation shows 28 regular Commodore 1541 disks.

  • A disk contains 35 tracks, counting from the outside to the inside.
  • Every track starts at the bottom and is read counter-clockwise1.
  • Green represents the data. Darker areas have more 0-bits.
  • Red represents a longer sequence of 1-bits.
  • Blue represents a longer sequence of 0-bits.

SYNC, Sector Headers and Data

Track 1 contains 21 sectors. Every sector is prefixed by two small red areas: These are the SYNC marks. The first SYNC marks the sector header, the second one the sector data.

Speed Zones

There are four different speed zones. The first 17 tracks (zone 3) are written at the highest speed: A sector occupies an angle of about 17 degrees. But on the last 5 tracks (zone 0), a sector occupies an angle of about 21 degrees. Yet the linear length of the sectors is about the same – that’s the idea of the different speeds. Higher tracks are shorter, and they contain fewer sectors.

Track # Sectors Speed Zone µs/Byte Raw Kbit/Track
1 – 17 21 3 26 60.0
18 – 24 19 2 28 55.8
25 – 30 18 1 30 52.1
31 – 35 17 0 32 48.8

Tail Gaps

Towards the end of the tracks, there is some unused space. You can see this in the darker and more consistent shading in the image:

About 5 to 10 degrees towards the end of each track are unused, because the space would not fit another sector. Speed zone 2 though looks like it could fit another sector, and in fact, DOS version 1 of the 2040 formatted tracks 18-24 with 20 sectors instead of 19, but this was too tight: If the motor speed was a little off, the last sector would overwrite sector 0.

When a disk is formatted, the pattern of 0x55 (alternating 0 and 1 bits) is written into this area. As long as there are no valid sector headers in the unused space, it can contain anything. There are formatting programs that fill it with all SYNC marks instead:

On some disks, the empty area is about the same size for all tracks. Some formatting programs add extra gaps between the sectors to minimize the tail gap:

40 Tracks

The original 5¼-inch “minifloppy” from 19762 only supported 35 tracks, the 40 track disks came a little later. For compatibility with existing disks3, all Commodore 5¼-inch drives only used 35 tracks, but some users and lots of games used 40 tracks by just extending the format (usually with the slowest speed zone) by 5 tracks.

In this case, the sectors between tracks 31-35 and 36-40 are not visually aligned, because the 5 extra tracks were presumably formatted independently with a different program which used slightly different sector gaps.

There is no specification for the format of the extra tracks. Here is an example that uses speed zone 1 (the second-highest one) with 18 sectors instead of 17:

Custom Formats

Some games used completely custom formats:

This is the game “Cosmic Relief”, which seems to store 11 or 12 sectors per track, with sectors that are about 1.5 the size of regular sectors, and potentially a different encoding. Tracks 17 and 18 have to be in the standard format though: Track 18 contains the directory, and track 17 contains the loader for the custom format, in this case.

Custom formats were usually used for copy protection. The 1541 does not have enough RAM to store the raw bitstream of one track, and the Commodore Serial Bus does not have the data rate to transfer it to the computer in real time. Therefore the only way to copy a disk is sector-by-sector, which only works if the sectors are in a format the copy program understands. Copy programs that supported parallel cables defeated most of these protection schemes.

Create Your Own Visualization

There are lots of copy protection tricks and custom formats that are interesting to look at this way. I have created a Python tool to create these image files from G64 files:

Plase share your own results!

  1. From the drive head’s point of view, a track is an infinite but repeating string of bits with no defined start. MFM-formatted disks used the index hole for a defined start point. The 1541 disk format does not make use of the index hole, so there is no defined track alignment: Any track can be arbitrarily rotated compared to the other tracks. nibconvert from the nibtools package by default writes G64 files aligned to the longest gap, which will usually align to sector 0.

  2. and the SA-400/SA-390 mechanism used in Commodore’s dirst devices

  3. Another reason might have been that the extra tracks would have needed another, slower speed zone for the data to be safe, so it wasn’t as easy as adding 40 track support to the firmware.

Building the Commodore TED Kernal with Modern Tools

The original Commodore TED (C16, C116, Plus/4) source code has recently appeared on It is also available in my Commodore Source Code git repository.

The original source could be built with two different assemblers:

  • Commodore’s own assembler, which ran on PET machines. The master binaries of the C64 ROMs were created by this tool. The source is included in the original archive referenced above.
  • “Boston Systems Office (BSO) relocating cross assembler” (“CY6502”), which ran on VAX/VMS machines. The master binaries of the TED ROMs were created with it, and it was the only supported assembler for the C128 ROMs.

I have converted the source to build with cc65:

The purpose of this is to allow creating updates and derivatives of the TED KERNAL. For this, the components have been put into sections that start at fixed addresses, so that replacing components (like “tape” or “monitor”) will keep the overall layout intact and won’t break symbol addresses.

Building the Original Commodore 1541 DOS Source

You might think the DOS ROM of the Commodore 1541 disk drive has been analyzed to death. But here are two new resources:

  • The original source of all versions of the 1540/1541/1541C/1541-II ROMs.
  • A git repository with all versions in its history, each of them adapted to build with modern tools.

The Original Source

The Dennis Jarvis collection contains source that can build the 2031/1540 ROM. Using the 1571 source from the same collection and the ROM images, I reconstructed the source trees for all versions of the 1540/1541/1541C/1541-II ROMs:

Directory Part Numbers Description
DOS_1540 325302-01, 325303-01 1540
DOS_1541_01 325302-01, 901229-01 1541 (original)
DOS_1541_02 325302-01, 901229-02 1541 (update)
DOS_1541_03 325302-01, 901229-03 1541 (update)
DOS_1541_05 325302-01, 901229-05 1541 (short board)
DOS_1541_06 325302-01, 901229-06 1541 (short board, update)
DOS_1541C_01 251968-01 1541C (original)
DOS_1541C_02 251968-02 1541C (updated)
DOS_1541C_03 251968-03 1541-II

All these directories can be found in the Commodore Source Code repository:

Here is the output of “diff DOS_1540 DOS_1541”, for example:

The Buildable Source

This repository contains all versions of the 1540/1541/1541C/1541-II source, buildable with cc65:

If you want to base your own development on this code:

  • The head of the repository points to the 1541-II version, which contains all of Commodore’s bug fixes. It works on all hardware versions (1540/1541, 1541C/1541-II), but does not contain support for the 1541C track 0 sensor.
  • 251968-02 is the last 1541C version and has track 0 sensor support, but one bug fix found in the 1541-II ROM is missing: ptch15 is supposed to jump to rnget2, not rnget.


Book “Anatomy of the 4040 Disk Drive” by Hilaire Gagne

Hilaire Gagne: Anatomy of the 4040 Disk Drive

(HTML, 632K)

This book provides a complete description of the Commodore 4040 dual floppy drive. The book covers file management, data management disk management, file organization, advanced disk programming, hardware and software interfacing, RAM and ROM disassembly, and application examples.

The book contains a full commented disassembly of “CBM DOS V2.1” for the 4040. (The original source is available at

It was written with an unknown word processor, probably on a Commodore PET, and the original files were part of the estate of Dennis Jarvis.

The conversion tool and the HTML are tracked in a git repository.

Final Cartridge III Monitor for the TED

In my quest to make the C16 more usable, i.e. more like the environment I’m used to, i.e. a C64 with a Final Cartridge III, I’ve ported the Final Cartridge III monitor to the TED series (C16, C116, Plus/4).

I have reverse-engineered the interesting parts of the FC3 ROM before:

The code in the repository now also allows building the monitor standalone for the TED series:

make clean MACHINE=ted PROJECT=monitor monitor.prg

The resulting file is located at $4000 in RAM and can be started with

sys 16384

At the default address of $4000, it requires a memory extension on a C16/C116. By editing the key STARTADDRESS in projects/monitor/monitor.cfg, any address can be selected.

Here are some of the unique FC3 monitor features:

  • Moving the cursor past the first or last line of the screen will continue dumps and disassemblies. It will even disassemble backwards. F3/F5 will also scroll up and down.
  • The O command switches banks (TED: 0 = BASIC + KERNAL, F = all RAM). OD switches to disk drive memory.
  • The I command prints a CBM-ASCII-encoded memory dump.
  • *R tt ss aa and *W tt ss aa read and write a disk block.

C64 Keyboard Layout for the C16

The Commodore 16 is an interesting machine, but the keyboard layout is infuriating. The cursor keys are at an awful place and… and… and… well, it just isn’t the C64 layout I’m used to!

So here’s a patch to the KERNAL ROM to change the C16 key mapping to the C64 one:

At offset 0x2026 of kernal.318004-05.bin (PAL) or kernal.318005-05.bin (NTSC), replace 260 bytes with these:

14 0D 11 88 85 86 87 40 33 57 41 34 5A 53 45 01  
35 52 44 36 43 46 54 58 37 59 47 38 42 48 55 56  
39 49 4A 30 4D 4B 4F 4E 13 50 4C 5C 2E 3A 5E 2C  
2B 3D 3B 2D 5F 1D 2A 2F 31 FF 04 32 20 02 51 03  
94 8D 91 8C 89 8A 8B BA 23 D7 C1 24 DA D3 C5 01  
25 D2 C4 26 C3 C6 D4 D8 27 D9 C7 28 C2 C8 D5 D6  
29 C9 CA DD CD CB CF CE 93 D0 CC A9 3E 5B DE 3C  
DB 3D 5D DD 5F 9D C0 3F 21 FF 04 22 A0 02 D1 83  
94 8D 91 8C 89 8A 8B A4 96 B3 B0 97 AD AE B1 01  
98 B2 AC 99 BC BB A3 BD 9A B7 A5 9B BF B4 B8 BE  
29 A2 B5 30 A7 A1 B9 AA 93 AF B6 A8 3E 5B DE 3C  
A6 3D 5D DC 5F 9D DF 3F 81 FF 04 95 A0 02 AB 83  
FF FF FF FF FF FF FF FF 1C 17 01 9F 1A 13 05 FF  
9C 12 04 1E 03 06 14 18 1F 19 07 9E 02 08 15 16  
12 09 0A 92 0D 0B 0F 0E FF 10 0C 1C FF 1B 1E FF  
FF 1F 1D FF 06 06 FF FF 90 FF FF 05 FF FF 11 FF  

Here’s the patched PAL ROM:

And the NTSC ROM:

(The key formerly known as “CLEAR HOME” is now dead. If you want to assign it a function, replace the first occurence of FF in the patch with the desired PETSCII code.)

And then, you have to add a few stickers to your keyboard!

Analyzing the ROMs of Third Party Disk Drives for the C64

Most Commodore 64 users had a 1541 disk drives, but there were always also third part options. Most of them claimed full 1541 compatibility, which sounds impossible without using the same ROM. Let’s analyze the ROMs of some third party drives!

Spoiler: They all used Commodore’s ROM code, and used varying degrees of obfuscation to hide it.

Blue Chip BCD/5.25 and Rapid Access FD148

The Blue Chip BCD/5.25 and the Rapid Access drives are standard 1541 clones. The power-up message says “CBM DOS V2.6 1541” – the same as a 1541. There is the string “Copyright © 1985 Blue Chip Electronics, Inc.” both at the bottom and the top of the ROM:

c000  43 6f 70 79 72 69 67 68  74 20 28 43 29 20 31 39  |Copyright (C) 19|  
c010  38 35 20 42 6c 75 65 20  43 68 69 70 20 45 6c 65  |85 Blue Chip Ele|  
c020  63 74 72 6f 6e 69 63 73  2c 20 49 6e 63 2e ff ff  |ctronics, Inc...|

ef20  ad 00 18 29 01 d0 f9 a9  01 8d 05 18 4c df e9 43  |...)........L..C|  
ef30  6f 70 79 72 69 67 68 74  20 28 43 29 20 31 39 38  |opyright (C) 198|  
ef40  35 20 42 6c 75 65 20 43  68 69 70 20 45 6c 65 63  |5 Blue Chip Elec|  
ef50  74 72 6f 6e 69 63 73 2c  20 49 6e 63 2e 85 4a 4c  |tronics, Inc..JL|

(The Rapid Access version does not contain the $C000 message.)

Comparing the ROMs to any version of the 1541 ROM shows lots and lots of differences. Yet, the ROM looks suspicously like a 1541 ROM. The error messages:

e500  20 21 22 23 24 27 d2 45  41 44 89 52 83 20 54 4f  | !"#$'.EAD.R. TO|  
e510  4f 20 4c 41 52 47 c5 50  8b 06 20 50 52 45 53 45  |O LARG.P.. PRESE|  
e520  4e d4 51 cf 56 45 52 46  4c 4f 57 20 49 4e 8b 25  |N.Q.VERFLOW IN.%|  
e530  28 8a 89 26 8a 20 50 52  4f 54 45 43 54 20 4f ce  |(..&. PROTECT O.|  
e540  29 88 20 49 44 85 30 31  32 33 34 d3 59 4e 54 41  |). ID.01234.YNTA|  
e550  58 89 60 8a 03 84 63 83  20 45 58 49 53 54 d3 64  |X.`...c. EXIST.d|  
e560  83 20 54 59 50 45 85 65  ce 4f 20 42 4c 4f 43 cb  |. TYPE.e.O BLOC.|  
e570  66 67 c9 4c 4c 45 47 41  4c 20 54 52 41 43 4b 20  |fg.LLEGAL TRACK |  
e580  4f 52 20 53 45 43 54 4f  d2 61 83 06 84 39 62 83  |OR SECTO.a...9b.|  
e590  06 87 01 83 53 20 53 43  52 41 54 43 48 45 c4 70  |....S SCRATCHE.p|  
e5a0  ce 4f 20 43 48 41 4e 4e  45 cc 71 c4 49 52 89 72  |.O CHANNE.q.IR.r|  
e5b0  88 20 46 55 4c cc 73 c3  42 4d 20 44 4f 53 20 56  |. FUL.s.BM DOS V|  
e5c0  32 2e 36 20 31 35 34 b1  74 c4 52 49 56 45 06 20  |2.6 154.t.RIVE. |  
e5d0  52 45 41 44 d9 09 c5 52  52 4f d2 0a d7 52 49 54  |READ...RRO...RIT|  
e5e0  c5 03 c6 49 4c c5 04 cf  50 45 ce 05 cd 49 53 4d  |...IL...PE...ISM|  
e5f0  41 54 43 c8 06 ce 4f d4  07 c6 4f 55 4e c4 08 c4  |ATC...O...OUN...|  
e600  49 53 cb 0b d2 45 43 4f  52 c4 48 86 f9 8a 0a aa  |IS...ECOR.H.....|

And the commands, file control methods and file types:

fe80  a8 68 aa 68 40 12 04 04  90 56 49 44 4d 42 55 50  |.h.h@....VIDMBUP|  
fe90  26 43 52 53 4e 84 05 c1  f8 1b 5c 07 a3 f0 88 23  |&CRSN.....\....#|  
fea0  0d ed d0 c8 ca cc cb e2  e7 c8 ca c8 ee 51 dd 1c  |.............Q..|  
feb0  9e 1c 52 57 41 4d 44 53  50 55 4c 44 53 50 55 52  |..RWAMDSPULDSPUR|  
fec0  45 45 52 53 45 4c 51 47  52 4c 08 00 00 3f 7f bf  |EERSELQGRL...?..|

All these string sections are at the same locations and have the same encoding. Disassembling the code shows how it’s possible that the ROMs are so different nevertheless – 1541 on the left, Blue Chip on the right:

.,c2b3  A4 A3       LDY $A3         .,c2b3  A4 A3       LDY $A3  
.,c2b5  F0 14       BEQ $C2CB       .,c2b5  F0 12       BEQ $C2C9  
.,c2b7  88          DEY             .,c2b7  88          DEY  
.,c2b8  F0 10       BEQ $C2CA       .,c2b8  F0 0E       BEQ $C2C8  
.,c2ba  B9 00 02    LDA $0200,Y     .,c2ba  A9 0D       LDA #$0D  
.,c2bd  C9 0D       CMP #$0D        .,c2bc  D9 00 02    CMP $0200,Y  
.,c2bf  F0 0A       BEQ $C2CB       .,c2bf  F0 08       BEQ $C2C9  
.,c2c1  88          DEY             .,c2c1  88          DEY  
.,c2c2  B9 00 02    LDA $0200,Y     .,c2c2  D9 00 02    CMP $0200,Y  
.,c2c5  C9 0D       CMP #$0D        .,c2c5  F0 02       BEQ $C2C9  
.,c2c7  F0 02       BEQ $C2CB       .,c2c7  C8          INY  
.,c2c9  C8          INY             .,c2c8  C8          INY  
.,c2ca  C8          INY             .,c2c9  8C 74 02    STY $0274  
.,c2cb  8C 74 02    STY $0274       .,c2cc  C0 2A       CPY #$2A  
.,c2ce  C0 2A       CPY #$2A        .,c2ce  90 0C       BCC $C2DC  
.,c2d0  A0 FF       LDY #$FF        .,c2d0  A9 FF       LDA #$FF  
.,c2d2  90 08       BCC $C2DC       .,c2d2  8D 2A 02    STA $022A  
.,c2d4  8C 2A 02    STY $022A       .,c2d5  A9 32       LDA #$32  
.,c2d7  A9 32       LDA #$32        .,c2d7  4C C8 C1    JMP $C1C8  
.,c2d9  4C C8 C1    JMP $C1C8       .,c2da  FF FF       .byte $FF, $FF

All over the place, instructions were shuffled around, in order to make the code look different, but behave the same. In some cases, the new code saves a byte or two, so filler bytes had to be added to keep the code layout the same.

Interestingly, whoever did this, seems to have lost interest at $D200 – the code after that is mostly untouched. Other than that, there only seems to be one more difference: The ROM checksum check has been disabled.

So the ROM is clearly Commodore’s code (based on version -05), shuffling around instructions doesn’t changed anything about that.

Commander C-II

The Commander C-II ROM also shows lots of differences compared to the 1541 ROM, but again, the well-known strings are are the right spots. The power-up message is unchanged, and (more or less broken) variations of the message “© 1984 Commander Electronics” can be found at the bottom and the top of the ROM.

c010  55 55 55 55 55 55 55 55  28 43 29 20 31 39 38 34  |UUUUUUUU(C) 1984|  
c020  00 43 6f 6d 6d 61 6e 64  65 72 20 45 6c 65 63 74  |.Commander Elect|  
c030  72 6f 6e 69 63 73 55 55  55 55 55 55 55 55 55 55  |ronicsUUUUUUUUUU|

ef30  55 55 55 55 55 55 55 28  43 29 20 31 39 38 34 20  |UUUUUUU(C) 1984 |  
ef40  41 6f 6d 6d 61 6e 64 65  72 20 45 6c 65 63 74 72  |Aommander Electr|  
ef50  6f 6e 69 63 73 c9 30 f0  06 c9 31 f0 02 09 80 29  |onics.0...1....)|

This is the reason for the difference in this case:

.,c2b3  A4 A3       LDY $A3         .,c2b2  A4 A3       LDY $A3  
.,c2b5  F0 14       BEQ $C2CB       .,c2b4  F0 14       BEQ $C2CA  
.,c2b7  88          DEY             .,c2b6  88          DEY  
.,c2b8  F0 10       BEQ $C2CA       .,c2b7  F0 10       BEQ $C2C9  
.,c2ba  B9 00 02    LDA $0200,Y     .,c2b9  B9 00 02    LDA $0200,Y  
.,c2bd  C9 0D       CMP #$0D        .,c2bc  C9 0D       CMP #$0D  
.,c2bf  F0 0A       BEQ $C2CB       .,c2be  F0 0A       BEQ $C2CA  

A big chunk of the code ($C100-$CEE1) is moved up by one byte! All references to this code have been properly updated – it seems they reverse engineered the ROM into buildable assembly source for that. The changes of the function addresses will introduce incompatibilities with third party code though that accesses these functions directly.

In addition, throughout the code, the following type of change was made:

.,c2d9  4C C8 C1    JMP $C1C8       .,c2d8  4C C7 81    JMP $81C7

RAM and ROM don’t nearly fill the 64 KB address space, and incomplete address decoding leads to lots of mirrors of RAM and ROM in the address space. The Commander C-II ROM uses random mirrors for most ROM and RAM accesses.

This ROM is based on the 1541-II version of Commodore’s code, and again, moving code and obfuscating addresses doesn’t make it an independent creation.

Enhancer 2000

I found two different ROMs for the Enhancer 2000. Let’s start with enhancer_2000.bin, which has a power-up message of “ENHANCER 2000 2.0” and the following string at $C000:


It’s based on version -05 of Commodore’s code, and at several sections throughout the ROM, it uses the same trick of shuffling instructions – but this was done independently of the Blue Chip ROM.

This ROM doesn’t just have swapped instructions though – big chunks have been completely rewritten, including the send and receive code on the serial bus and the GCR encoding/decoding. It would be interestig to analyze what the advantages of these new implementations are!

And there is a lot of new code, too. The previously unused areas are full, and the “boot clip” autostart code at $E780 was replaced with new code as well. I couldn’t find what calls this code, but some of it compares the second character of the command against one of these: “LUMPBIND-T”, and jumps to one of 10 functions based on it. It looks like the device implements some extra commands! The manual doesn’t mention anything though – early devices are supposed to have had original 1541 ROMs, so maybe this manual is based on that.

The other version, Enhancer 2000 Comtel 2.6.bin, shows the original 1541 power-up message (“CBM DOS V2.6 1541”) and has a different string at $C000:

1651 E. EDINGER #209
P.O. BOX 15485
(714)953-6165 TELEX:503727

It seems to be a later version, because in addition to everything in the version already described, it also uses the “mirror address” method to make all remaining code look different – even in the added code!

Interestingly, the string with the added command characters has been changed to “LUPBCDHN B”.

This version of the Enhancer 2000 ROM is the most obfuscated 1541 ROM copy I’ve found!

Indus GT

Now for something lighter! The Indus GT has a few extra features compared to the 1541, like a two-digit display to show the current track, a write protect button, and a drive “1” (same syntax as Commodore’s dual drive units) that accesses tools on a built-in ROM.

The ROM is based on version -05 of the 1541 ROM, diligently binary-patched to support the extra features. The power-up string has been changed to “INDUS GT C64 V1.1”. And that’s it! No obfuscation! Just a plain feature-enhanced 1541 ROM. Most of the “ROM disk” code lives in an extra 8 KB ROM at $A000 (together with the ROM disk contents), and the existing ROM calls out to it.

MSD SD-1 and SD-2

The MSD drives are the most interesting ones. SD-1 is a single-drive device, and SD-2 has two drives, allowing the “1:” syntax of Commodore’s dual drives and supporting file copy across drives (“C” command) as well as disk copy (“D” command). Both devices also have both an IEEE-488 and a Commodore Serial bus.

These devices diverge a lot from Commodore’s offerings: No Commodore device ever had both ports, and all Commodore devices with two drives had two CPUs – the MSDs have only one CPU. The documented RAM layout (including the location of the I/O chips) also doesn’t match any Commodore device.

Comparing the disassemblies shows that the MSD ROMs are very different from 1541 ROMs, but they don’t show any signs of obfuscation.

So have the MSD ROMs independently developed?


Most of the code is still Commodore’s, it is just organized differently. Pratically any core function in the 1541 ROM can be found in the MSD ROM somewhere, line by line. The ROM of the 1541 must have been reverse engineered into buildable source code, and the new features were then added, probably also by looking at the ROM of some other devices (like the 2031 or SFD-1001 for the IEEE-488 code, and the 4040, 8050 or 8250 to see how two drives are handled).


Drive Shuffling Relocation Mirror addresses Rewritten code Added features Different layout
Blue Chip BCD/5.25
Commander C-II
Enhancer 2000 (✓)
Indus GT
MSD SD-1 and SD-2

None of the ROMs of any of the 5.25″ disk drives for the C64 that I could find were independently developed. Some supposedly just shipped with the exact Commodore code for a while, until Commodore threatened to sue them, so they obfuscated their use of the copyrighted material. It’s unlikely that this would have fooled Commodore, but in times where it was tricky to convince a judge that code could be copyrighted at all, it was probably good enough.

Ironically, it was not the hardware, but the obfuscations of the software that caused some compatibility issues. Some addresses were different, some messages weren’t what apps expected. GEOS for example reads some ROM contents to decide what fast loader to use. Many users replaced the ROM chips of their clones with EPROMs containing the original Commodore code, which fixed most compatibility issues!

But not all 3rd party manufacturers borrowed Commodore’s code. Devices that didn’t use 5.25″ disks, like hard drives and 3.5″ disk drives, were quite incompatible with the 1541 and practically all games anyway, so there was no need to use the most compatible ROM in the first place. Still, developing a complete reimplementation of Commodore DOS is costly.

Creative Micro Devices (CMD) went that route. Their CMD HD (bridging to SCSI), CMD FD (3.5″ HD and ED) and RAMLink (RAM disk) devices used a DOS that was implemented from scratch.

More Research

There are still some open questions:
* Are the Enhancer 2000 versions of Serial and GCR better?
* What do the added commands of the Enhancer 2000 do?
* How exactly was the ROM of the MSD devices created?
* Are there ROMs of more 1541 clones out there? (Please submit them to!)

Reconstructing the Unreleased C128 ROM Update

The C128 source dump over at that appeared recently contains source for a version 2 kernel, which was never released. The known versions are 0 and 1. Let’s see whether we can reconstruct the ROM image!

Release Notes

These are the release notes for the version 2 C128 KERNAL:

         C128 ROM RELEASE NOTES: 318020-06  


   1.  # 318023-03 --> EDITOR, KERNEL, CP/M ($C000-$FFFF, U32) cksum= E424  
   2.  # 318020-06 --> EDITOR, KERNEL, CP/M ($C000-$FFFF)      cksum= DFC4

       1.  SECURE.  This kernel initialization routine has been modified  
           to accomodate technological advances in DRAMs.  The discharge  
           rates for data cells has lengthened considerably and it is no  
           longer possible to rely upon the  loss  of data as indicative  
           of a  power cycle as opposed to a  reset.  The SECURE routine  
           has been patched to also check the  contents of the  8568 VDC  
           registers.  These will  contain  $FF  if  power  cycled.  The  
           previous  testing of a "CBM" RAM key in  bank one remains for  
           compatability.  This patch required new code in patch area.

       2.  DLABYE.  This kernel  serial  I/O routine has been patched to  
           provide a longer delay.  This should prevent certain randomly  
           occurring DEVICE NOT READY errors, particularly at 2MHz. This  
           is a single byte patch totally inline.

       3.  OPN232.  This kernel  routine  has  been patched to correctly  
           return error status.  When  implementing  an X-line interface  
           it was possible to receive an error when there was none. This  
           is a single byte patch totally inline.

       4.  The ROM  signature at location $CFFC  and  $CFFD  (lo/hi)  is  

       5.  The ROM revision byte at location $CFFE, has incremented from  
           $01 to $02.

       6.  The ROM checksum byte at  location  $CFFF,  has  changed from  
           $3C to $3B.

       7.  The Kernel revision byte at location  $FF80  has  incremented  
           from $01 to $02.

       Fred Bowen        05/30/88.

The “31802x-0y” numbers are Commodore Product IDs for the physical ROM chips:

Product ID System Description Size Status
318020-05 C128/C128D KERNAL version 2 16 KB released
318020-06 C128/C128D KERNAL version 3 16 KB unreleased
318023-02 C128DCR C64 ROM + KERNAL version 2 32 KB released
318023-03 C128DCR C64 ROM + KERNAL version 3 32 KB unreleased

Parsing the .LST Files

In addition to the source trees of the two versions, the archive also contains an .LST file for each version. An .LST file is generated during assembly and consists of every source line annotated with the current address and the generated object bytes.

Here is an example line:

     E000   A2 FF        2367   start   ldx #$ff        ;normal /reset entry
  • E000 is the address of the code
  • A2 FF is the object code produced by the line
  • 2367 is the global line number of the project (counts all source lines starting from 1)
  • The remainder is the original source line.

After cutting out just the addresses and the object code, we can easily compare the two files:

for i in 05 06; do  
  cat kernal/318020_$i/kernal.lst | grep "^     [0-9A-F]...   [0-9A-F]" | cut -c -25 > $i.txt  
diff 05.txt 06.txt

The Differences

This is the result:

<      E01B   20 E1F0  
>      E01B   20 CF9E  
<      F098   90 09  
>      F098   90 08  
<      F09D   30 04  
>      F09D   30 03  
>      CF9E   A2 0F  
>      CFA0   20 CDDA  
>      CFA3   C9 FF  
>      CFA5   D0 06  
>      CFA7   CA  
>      CFA8   10 F6  
>      CFAA   4C E224  
>      CFAD   4C E1F0  
<      FF80   01  
>      FF80   02           
  • $E01B: jsr secure_patch instead of jsr secure (bullet point 1)
  • $F098/$F09D: two branches have different destinations (bullet point 3)
  • $CF9E: secure_patch, a new patch in the patch area (bullet point 1)
  • $FF80: the updated KERNAL revision byte (bullet point 7)

So the changes are minor and can easily be manually patched into a copy of kernal.318020-05.bin.

What is weird though is that the release notes mention a difference in DLABYE, but there doesn’t seem to be one. This is the code in both versions:

dlabye  jsr scatn       ;always release atn  
dladlh  txa             ;delay and then release clock & data  
        ldx #10         ;delay approx 60 us  
10$     dex  
        bne 10$  
        jsr clkhi  
        jmp datahi

The single-byte patch for the increased delay mentioned by the release notes would probably have to be a change in the number of iterations in the loop.

The release notes also mention that some version and checksum bytes in the file have changed. We don’t have to calculate them ourselves, they are provided for us (bullet points 4, 5 and 6 in the release notes):

CFFC   3E 8C  
CFFE   02  


Now how do we verify that the resulting binray is correct? The release notes states the checksum of the new ROM!

    2.  # 318020-06 --> EDITOR, KERNEL, CP/M ($C000-$FFFF)      cksum= DFC4

I couldn’t find any documentation on what algorithm is used for the checksum, but there are also release notes for the 318020-05 ROM that states the checksum for the ROM we have:

    3.  # 318020-05 --> EDITOR, KERNEL, CP/M ($C000-$FFFF, U35) cksum= EEC4

As it turns out, it is just the lower 16 bits of all bytes added up. This Python code does it:

import sys  
c = 0  
for i in bytearray(  
    c = (c + i) & 0xffff  
print hex(c)

I tested the algorithm with several existing ROMs and the checksum always matched the release notes.

Now let’s test it with our newly created 318020-06 ROM:

$ python < kernal.318020-06_canditate.bin  

The checksum should be 0xdfc4, but our file has a checksum of 0xe68b – a difference of 0x6c7. Because of the way the checksum works, this means we are not close. A difference in a single byte would mean the checksum could not be off by more than $ff.


So no, it seems we can’t reconstruct the exact 318020-06 ROM image, and it is unclear what the differences are.

If anyone has any ideas, I’d be very interested!

In the meantime, here is the “best-we-can-do” image:

kernal.318020-06_canditate.bin (32768 bytes)

It contains the initialization and RS232 patches and identifies as version 2.