Buckley
Found on:
"Chuckie Egg 2"
"Colony"
"Dark Empire"
"Legions Of Death"
"Milk Race"
"Molecule Man"
"Pro Mountain Bike Simulato"
"Psycho Hopper"
"Xenon"
Loader files:"Colony"
"Dark Empire"
"Legions Of Death"
"Milk Race"
"Molecule Man"
"Pro Mountain Bike Simulato"
"Psycho Hopper"
"Xenon"
ROM Header 1
Contains only filename
ROM Data 1
Autostart and uses standard Kernal routine to load next file which it then starts
ROM Header 2
Contains only filename
ROM Data 2
Contains the turbo loader
Encoding:Contains only filename
ROM Data 1
Autostart and uses standard Kernal routine to load next file which it then starts
ROM Header 2
Contains only filename
ROM Data 2
Contains the turbo loader
Endianess:MSbF
Threshold:0x190
Lead-in:100 x %011111111 (<-9 bits)
Sync:0x00
Structure:Threshold:0x190
Lead-in:100 x %011111111 (<-9 bits)
Sync:0x00
Header:9 bytes
Checksum:Yes
Checksum:Yes
Header:
00-01 ?? (Unused) One of them should be the checksum cancellation byte.
02 Data checksum
03-04 Changes a jump vector used by the loader. Triggering new code to be run after each file.
Basically displays the intro picture and after last file clears it and starts the game.
05-06 Bytes to load, High/low order.
07-08 Load start address, High/Low order
Checksum:
Header checksum. Sum of all header bytes should be zero.
Data checksum. Sum of all bytes including header bytes.
The data checksum byte is in the header. Loader doesn't check it or even calculates it.
Loader uses nine bits per byte.
The first bit whch would have been the most significant one is just rotated out of the byte
and ignored. This bit always seems to be a '0' bit.
Loader also inverts loaded bits, so passig threshold means a '0' bit.
Checksum:
Chuckie Egg 2 is slightly different from the rest.
It calculates the number of bytes to load differently and therefore loads 1 byte more than what the header says.
Three releases of Chuckie Egg known so far, Original release by A'n'F, Now Games 2 compilation and the Icon Design re-release.
All three load one addional byte.
The original release by A'n'F and the Now Games 2 release uses a different threshold, 0x01f4.
00-01 ?? (Unused) One of them should be the checksum cancellation byte.
02 Data checksum
03-04 Changes a jump vector used by the loader. Triggering new code to be run after each file.
Basically displays the intro picture and after last file clears it and starts the game.
05-06 Bytes to load, High/low order.
07-08 Load start address, High/Low order
Checksum:
Header checksum. Sum of all header bytes should be zero.
Data checksum. Sum of all bytes including header bytes.
The data checksum byte is in the header. Loader doesn't check it or even calculates it.
Loader uses nine bits per byte.
The first bit whch would have been the most significant one is just rotated out of the byte
and ignored. This bit always seems to be a '0' bit.
Loader also inverts loaded bits, so passig threshold means a '0' bit.
Checksum:
Chuckie Egg 2 is slightly different from the rest.
It calculates the number of bytes to load differently and therefore loads 1 byte more than what the header says.
Three releases of Chuckie Egg known so far, Original release by A'n'F, Now Games 2 compilation and the Icon Design re-release.
All three load one addional byte.
The original release by A'n'F and the Now Games 2 release uses a different threshold, 0x01f4.
.pc = $1153
.label bitCount = $cb
.label readByte = $ce
.label checksum = $cf
.label SCROLY = $d011
.label RASTER = $d012
.label SCROLX = $d016
.label VMCSB = $d018
.label IRQMSK = $d01a
.label EXTCOL = $d020
.label BGCOL0 = $d021
.label CIAPRA = $dc00
.label CIDDRA = $dc02
.label TIMALO = $dc04
.label TIMAHI = $dc05
.label TIMBLO = $dc06
.label TIMBHI = $dc07
.label CIAICR = $dc0d
.label CIACRA = $dc0e
.label CIACRB = $dc0f
.label CI2PRA = $dd00
.label C2DDRA = $dd02
.label TI2ALO = $dd04
.label TI2AHI = $dd05
.label TI2BLO = $dd06
.label TI2BHI = $dd07
.label CI2ICR = $dd0d
.label CI2CRA = $dd0e
.label CI2CRB = $dd0f
// Autostart code jumps here
START:jsrinitLoad// Sets up environment, timers, IRQ etc.
lda#$ff
staCIDDRA
C_115b:lda#0
staCIAPRA
ldaD_13ff// value is 0 from start
cmp#$03
bneC_116f
jsr$e000
lda#$02
staD_13ff
C_116f:ldaD_13ff
beqC_1177
jsrC_13e0
C_1177:jsrC_117f
bneC_115b
jmpC_1189
C_117f:lda$cd// Starts as $ff from initialization code @1198
cmp#$04
bneC_1186
rts
C_1186:cmp#$03
rts
C_1189:lda$01
ora#$20
sta$01
lda#$7f
staCIAICR
nop
C_1195:jmp($00c4)// $c4/$c5 is part of file header area, so this vector is changed for every file loaded.
// These are the values that will be loaded
// $13B7 $1352 $1153 $1153 $139E
//
// INIT environment
//
initLoad:lda#$05
sta$01// Disconnect Kernal
lda#0
staEXTCOL
lda#$56
staC_124d+1// Modifying JMP instr
lda#$12
staC_124d+2// Modifying JMP instr
lda#$7f
staCIAICR
staCI2ICR
lda#0
staCIACRA
lda#$48
staCIACRB
lda#0// Timer A = $0008, Timer B = $ffff
staTIMAHI
lda#$ff
staTIMBHI
lda#$08
staTIMALO
lda#$ff
staTIMBLO
lda#$ff
sta$cd
lda#0
stareadByte
lda#$1e
sta$ca
lda#0
staIRQMSK
sei
lda#$e7// New NMI vector $12e7
sta$fffa
lda#$12
sta$fffb
lda#$08// New IRQ vector $1208
sta$fffe
lda#$12
sta$ffff
lda#$90
staCIAICR// Enable FLAG IRQ
cli
lda#$59
staCIACRB// Timer B: Load latched value, one-shot mode, count times Timer A counts down, start
lda#$11
staCIACRA// Timer A: Load latched value, continous mode, start
rts
// IRQ Vector
IRQ:pha
txa
pha
tya
pha
ldaCIAICR
ldaEXTCOL
eor#$01
staEXTCOL
ldyTIMBHI
ldaTIMBLO
// Restart timers
ldx#$59
stxCIACRB
ldx#$11
stxCIACRA
// Invert Timer B low byte
// Timer B counts how many times Timer A has counted down from 8
ldx#0
eor#$ff
clc
adc#$01
cmp#$0f
bccbadPulse// < 120? 0.000122 us
cmp#$78
bcsbadPulse// >= 960? 0.000974 us
decbitCount
bmibyteDone
cmp#$32// 400 0.000406 us
ldareadByte
rol// rol = MSbF
eor#$01// Invert read bit
stareadByte
jmpC_12da
byteDone:lda#$08
stabitCount
cpy#$ff
C_124d:jmpIRQ//SMC, Jump to IRQ will never occur. Will be changed before first jump.
// Possible jumps $1256, $12da, $12ac, $128e (Read header)
badPulse:lda#$08
stabitCount
bneC_124d
C_1256:bneC_1285
lda$cd
beqC_1270
ldareadByte
stxreadByte
cmp#$ff
bneC_1285
dec$ca
beqC_126b
jmpC_12da
C_126b:stx$cd
jmpC_12da
C_1270:ldareadByte
stxreadByte
cmp#0
bneC_127b
jmpC_1308
C_127b:cmp#$ff
beqC_1282
jmpC_131f
C_1282:jmpC_12da
C_1285:lda#$1e
sta$ca
incbitCount
jmpC_12da
C_128e:beqC_1293
jmpC_131f
C_1293:ldareadByte
stxreadByte
ldy$ca
sta$00bf,y// Store header, 9 bytes
clc
adcchecksum// Only used when reading header. So no data checksum
stachecksum
dec$ca
bneC_12da
ldachecksum
bneC_131f
jmpC_12ee
C_12ac:bneC_131f
incEXTCOL
incEXTCOL
ldareadByte
stxreadByte
ldy#0
sta($c0),y// Store read byte
inc$c0
bneC_12c2
inc$c1
C_12c2:dec$c2
lda$c2
cmp#$ff
bneC_12cc
dec$c3
C_12cc:ora$c3
beqC_12d3
jmpC_12da
C_12d3:inc$cd
lda#$da
staC_124d+1// Modifies JMP instr
C_12da:ldaCIAICR// Checks if serial shift reg finished a byte!?
and#$08
bneC_131f
pla
tay
pla
tax
pla
rti
// NMI vector
NMI:pha
lda#$04
sta$cd
pla
rti
C_12ee:inc$cd
lda#$ac
staC_124d+1// Modifies JMP instr
// Create a copy of load start address and load size
lda$c2
sta$d2
lda$c3
sta$d3
lda$c0
sta$d0
lda$c1
sta$d1
jmpC_12da
C_1308:lda#$04
staEXTCOL
inc$cd
lda#$8e// Sets jump to routine for fetching header
staC_124d+1// Modifies JMP instr
lda#$09
sta$ca
lda#0
stachecksum
jmpC_12da
// This seems to create some sort of 16bit checksum, it's never called though-
C_131f:lda#$da
staC_124d+1// Modifies JMP instr
lda#$04
sta$cd
bneC_12da
ldy#0
sty$d4
sty$d5
C_1330:clc
lda($d0),y
adc$d4
sta$d4
lda$d5
adc#0
sta$d5
inc$d0
bneC_1343
inc$d1
C_1343:dec$d2
lda$d2
cmp#$ff
bneC_134d
dec$d3
C_134d:ora$d3
bneC_1330
rts
// This addres is triggered by data in the header of the first file
// there is a JMP ($00c4) at $1195. $c4/$c5 vector is part of header
// This is triggered after second file
// Displays the intro picture
C_1352:ldaC2DDRA
ora#$03
staC2DDRA
ldaCI2PRA
and#$fc
ora#$02
staCI2PRA
lda#$90
staVMCSB
ldaSCROLX
ora#$18
staSCROLX
lda#$07
staEXTCOL
lda#$07
staBGCOL0
ldy#$03
C_137d:ldx#0
C_137f:lda$6000,x// SMC
C_1382:sta$d800,x// SMC
dex
bneC_137f
incC_137f+2// Modifies LDA instr
incC_1382+2// Modifies STA instr
dey
bplC_137d
lda#$38
staSCROLY
lda#$03
staD_13ff
jmpSTART
// This addres is triggered by data in the header of the first file
// there is a JMP ($00c4) at $1195. $c4/$c5 vector is part of header
// This is triggered after fifth and last file file
C_139e:ldy#$07
C_13a0:ldx#0
C_13a2:lda$1800,x// SMC
C_13a5:sta$6000,x// SMC
dex
bneC_13a2
incC_13a2+2// Modifies LDA instr
incC_13a5+2// Modifies STA instr
dey
bplC_13a0
jmp$8001
// This addres is triggered by data in the header of the first file
// there is a JMP ($00c4) at $1195. $c4/$c5 vector is part of header
// This is triggered after first file
C_13b7:lda#$7f
staCI2ICR
lda#0
staTI2AHI
staTI2BHI
lda#$18
staTI2ALO
lda#$0c
staTI2BLO
lda#$11
staCI2CRA
lda#$51
staCI2CRB
lda#$82
staCI2ICR
jmpSTART
C_13e0:ldaRASTER
cmp#200// Check if we're before raster line 200
bccC_13f4
ldaD_1400
bneC_13e0
lda#$01
staD_1400
jmpC_13fc
C_13f4:lda#0
staD_1400
jmpC_13e0
C_13fc:jmp$e003
D_13ff:.byte0
D_1400:.byte0,0,0
.label bitCount = $cb
.label readByte = $ce
.label checksum = $cf
.label SCROLY = $d011
.label RASTER = $d012
.label SCROLX = $d016
.label VMCSB = $d018
.label IRQMSK = $d01a
.label EXTCOL = $d020
.label BGCOL0 = $d021
.label CIAPRA = $dc00
.label CIDDRA = $dc02
.label TIMALO = $dc04
.label TIMAHI = $dc05
.label TIMBLO = $dc06
.label TIMBHI = $dc07
.label CIAICR = $dc0d
.label CIACRA = $dc0e
.label CIACRB = $dc0f
.label CI2PRA = $dd00
.label C2DDRA = $dd02
.label TI2ALO = $dd04
.label TI2AHI = $dd05
.label TI2BLO = $dd06
.label TI2BHI = $dd07
.label CI2ICR = $dd0d
.label CI2CRA = $dd0e
.label CI2CRB = $dd0f
// Autostart code jumps here
START:jsrinitLoad// Sets up environment, timers, IRQ etc.
lda#$ff
staCIDDRA
C_115b:lda#0
staCIAPRA
ldaD_13ff// value is 0 from start
cmp#$03
bneC_116f
jsr$e000
lda#$02
staD_13ff
C_116f:ldaD_13ff
beqC_1177
jsrC_13e0
C_1177:jsrC_117f
bneC_115b
jmpC_1189
C_117f:lda$cd// Starts as $ff from initialization code @1198
cmp#$04
bneC_1186
rts
C_1186:cmp#$03
rts
C_1189:lda$01
ora#$20
sta$01
lda#$7f
staCIAICR
nop
C_1195:jmp($00c4)// $c4/$c5 is part of file header area, so this vector is changed for every file loaded.
// These are the values that will be loaded
// $13B7 $1352 $1153 $1153 $139E
//
// INIT environment
//
initLoad:lda#$05
sta$01// Disconnect Kernal
lda#0
staEXTCOL
lda#$56
staC_124d+1// Modifying JMP instr
lda#$12
staC_124d+2// Modifying JMP instr
lda#$7f
staCIAICR
staCI2ICR
lda#0
staCIACRA
lda#$48
staCIACRB
lda#0// Timer A = $0008, Timer B = $ffff
staTIMAHI
lda#$ff
staTIMBHI
lda#$08
staTIMALO
lda#$ff
staTIMBLO
lda#$ff
sta$cd
lda#0
stareadByte
lda#$1e
sta$ca
lda#0
staIRQMSK
sei
lda#$e7// New NMI vector $12e7
sta$fffa
lda#$12
sta$fffb
lda#$08// New IRQ vector $1208
sta$fffe
lda#$12
sta$ffff
lda#$90
staCIAICR// Enable FLAG IRQ
cli
lda#$59
staCIACRB// Timer B: Load latched value, one-shot mode, count times Timer A counts down, start
lda#$11
staCIACRA// Timer A: Load latched value, continous mode, start
rts
// IRQ Vector
IRQ:pha
txa
pha
tya
pha
ldaCIAICR
ldaEXTCOL
eor#$01
staEXTCOL
ldyTIMBHI
ldaTIMBLO
// Restart timers
ldx#$59
stxCIACRB
ldx#$11
stxCIACRA
// Invert Timer B low byte
// Timer B counts how many times Timer A has counted down from 8
ldx#0
eor#$ff
clc
adc#$01
cmp#$0f
bccbadPulse// < 120? 0.000122 us
cmp#$78
bcsbadPulse// >= 960? 0.000974 us
decbitCount
bmibyteDone
cmp#$32// 400 0.000406 us
ldareadByte
rol// rol = MSbF
eor#$01// Invert read bit
stareadByte
jmpC_12da
byteDone:lda#$08
stabitCount
cpy#$ff
C_124d:jmpIRQ//SMC, Jump to IRQ will never occur. Will be changed before first jump.
// Possible jumps $1256, $12da, $12ac, $128e (Read header)
badPulse:lda#$08
stabitCount
bneC_124d
C_1256:bneC_1285
lda$cd
beqC_1270
ldareadByte
stxreadByte
cmp#$ff
bneC_1285
dec$ca
beqC_126b
jmpC_12da
C_126b:stx$cd
jmpC_12da
C_1270:ldareadByte
stxreadByte
cmp#0
bneC_127b
jmpC_1308
C_127b:cmp#$ff
beqC_1282
jmpC_131f
C_1282:jmpC_12da
C_1285:lda#$1e
sta$ca
incbitCount
jmpC_12da
C_128e:beqC_1293
jmpC_131f
C_1293:ldareadByte
stxreadByte
ldy$ca
sta$00bf,y// Store header, 9 bytes
clc
adcchecksum// Only used when reading header. So no data checksum
stachecksum
dec$ca
bneC_12da
ldachecksum
bneC_131f
jmpC_12ee
C_12ac:bneC_131f
incEXTCOL
incEXTCOL
ldareadByte
stxreadByte
ldy#0
sta($c0),y// Store read byte
inc$c0
bneC_12c2
inc$c1
C_12c2:dec$c2
lda$c2
cmp#$ff
bneC_12cc
dec$c3
C_12cc:ora$c3
beqC_12d3
jmpC_12da
C_12d3:inc$cd
lda#$da
staC_124d+1// Modifies JMP instr
C_12da:ldaCIAICR// Checks if serial shift reg finished a byte!?
and#$08
bneC_131f
pla
tay
pla
tax
pla
rti
// NMI vector
NMI:pha
lda#$04
sta$cd
pla
rti
C_12ee:inc$cd
lda#$ac
staC_124d+1// Modifies JMP instr
// Create a copy of load start address and load size
lda$c2
sta$d2
lda$c3
sta$d3
lda$c0
sta$d0
lda$c1
sta$d1
jmpC_12da
C_1308:lda#$04
staEXTCOL
inc$cd
lda#$8e// Sets jump to routine for fetching header
staC_124d+1// Modifies JMP instr
lda#$09
sta$ca
lda#0
stachecksum
jmpC_12da
// This seems to create some sort of 16bit checksum, it's never called though-
C_131f:lda#$da
staC_124d+1// Modifies JMP instr
lda#$04
sta$cd
bneC_12da
ldy#0
sty$d4
sty$d5
C_1330:clc
lda($d0),y
adc$d4
sta$d4
lda$d5
adc#0
sta$d5
inc$d0
bneC_1343
inc$d1
C_1343:dec$d2
lda$d2
cmp#$ff
bneC_134d
dec$d3
C_134d:ora$d3
bneC_1330
rts
// This addres is triggered by data in the header of the first file
// there is a JMP ($00c4) at $1195. $c4/$c5 vector is part of header
// This is triggered after second file
// Displays the intro picture
C_1352:ldaC2DDRA
ora#$03
staC2DDRA
ldaCI2PRA
and#$fc
ora#$02
staCI2PRA
lda#$90
staVMCSB
ldaSCROLX
ora#$18
staSCROLX
lda#$07
staEXTCOL
lda#$07
staBGCOL0
ldy#$03
C_137d:ldx#0
C_137f:lda$6000,x// SMC
C_1382:sta$d800,x// SMC
dex
bneC_137f
incC_137f+2// Modifies LDA instr
incC_1382+2// Modifies STA instr
dey
bplC_137d
lda#$38
staSCROLY
lda#$03
staD_13ff
jmpSTART
// This addres is triggered by data in the header of the first file
// there is a JMP ($00c4) at $1195. $c4/$c5 vector is part of header
// This is triggered after fifth and last file file
C_139e:ldy#$07
C_13a0:ldx#0
C_13a2:lda$1800,x// SMC
C_13a5:sta$6000,x// SMC
dex
bneC_13a2
incC_13a2+2// Modifies LDA instr
incC_13a5+2// Modifies STA instr
dey
bplC_13a0
jmp$8001
// This addres is triggered by data in the header of the first file
// there is a JMP ($00c4) at $1195. $c4/$c5 vector is part of header
// This is triggered after first file
C_13b7:lda#$7f
staCI2ICR
lda#0
staTI2AHI
staTI2BHI
lda#$18
staTI2ALO
lda#$0c
staTI2BLO
lda#$11
staCI2CRA
lda#$51
staCI2CRB
lda#$82
staCI2ICR
jmpSTART
C_13e0:ldaRASTER
cmp#200// Check if we're before raster line 200
bccC_13f4
ldaD_1400
bneC_13e0
lda#$01
staD_1400
jmpC_13fc
C_13f4:lda#0
staD_1400
jmpC_13e0
C_13fc:jmp$e003
D_13ff:.byte0
D_1400:.byte0,0,0