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!
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:
|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|
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
E000is the address of the code
A2 FFis the object code produced by the line
2367is 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
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
jsr secure_patchinstead of
jsr secure(bullet point 1)
$F09D: two branches have different destinations (bullet point 3)
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
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.
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.