Reconstructing the Unreleased C128 ROM Update

The C128 source dump over at zimmers.net 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
                                 318023-03


THE FOLLOWING MODIFICATIONS HAVE BEEN MADE TO THE 318020-05 KERNEL  CODE TO
CREATE A NEW ROM SET RELEASED ON 05/30/88.  THIS  RELEASE IS FOR USE IN THE
FOLLOWING SYSTEMS:  C128, C128D, C128CR, C128DCR.  ROMS WILL BE BUILT FOR
ONLY THE CURRENT 32K BYTE "CR" SYSTEMS, HOWEVER (318023-03).

   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
           $8C3E.

       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
done
diff 05.txt 06.txt

The Differences

This is the result:

14c14
<      E01B   20 E1F0
---
>      E01B   20 CF9E
1986c1986
<      F098   90 09
---
>      F098   90 08
1988c1988
<      F09D   30 04
---
>      F09D   30 03
3264a3265,3272
>      CF9E   A2 0F
>      CFA0   20 CDDA
>      CFA3   C9 FF
>      CFA5   D0 06
>      CFA7   CA
>      CFA8   10 F6
>      CFAA   4C E224
>      CFAD   4C E1F0
3284c3292
<      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$
        tax
        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
CFFF   3B

Checksum

Now how do we verify that the resulting binary 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(sys.stdin.read()):
    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 cksum.py < kernal.318020-06_canditate.bin
0xe68b

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.

Conclusion

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.

5 thoughts on “Reconstructing the Unreleased C128 ROM Update”

  1. Looking into the binary “complete.german.318077-03.bin” from zimmers.net:

    (1) It contains all but one patches from above, only the f098 patch is missing. But it contains the DLABYE Patch:

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

    So I am quit sure that this is one of the missing pieces.

    Reply
    • Is there some element of corrupted data here? My reasoning:

      – Point 3 of Fred Bowen’s original summary describes the OPN232 patch as _a_ single-byte inline change.

      – The unreleased ROM image being analyzed contains _two_ single-byte changes.

      – The German ROM which MarkusC64 references only contains one of those single-byte changes .

      – It’s stated that the unreleased ROM image does not in fact contain the four altered bytes described in points 4 through 6. Does some combination of including or not including various of those three individual changes help solve the checksum mystery?

      – MarkusC64 reports that the German ROM includes all 7 of these patches, albeit with one variation in the object code, _and_ that ROM’s part number ends in -03… just like the unreleased North American ROM was to be. I’d like to interpret that as meaning “oh hey, it’s already out there” — but certainty would require analysis of the OPN232 routine, to figure out just what it’s _supposed_ to look like. One change, or two?

      Reply

Leave a Comment