New Program Code
Adding the hardware is one thing but to support the EEPROM there needs to be a some driver routines that talk using the ''microwire' to the 93c56 device. One thing about the serial EEPROM is that it's more complex to talk to than a parallel memory. Traditional parallel memory is simple to deal with, once you have the hardware in place the CPU just reads and writes to it. With the serial device you need to write some routines to send data serially, 1 bit at a time to the device. The device also needs to be sent commands, to tell it what you want to do, eg. write a byte or read a byte.
Fortunately as a base I had some code I'd already written,
but not for z80, it simply required some porting to Z80 assembler.
Full details of how the EEPROM works, the commands it uses are all contained in
the Datasheet for the device. See the main page for a link to the Microchip
version of the 93C56.
Size Constraints
The new code and routines had very limited space to fit
in, so the code was written with the aim of keeping things as tight as
possible. The serial routines fitted with only a byte to spare from $3F30 ->
$3FA0 and at the rest of the routines $3565, both these area's do not interfere with the game code.
Some of the code might appear a little strange but small code size was the most
important factor
Patches
All this new code doesn't do a great deal of good without patching the original game to make use of it, this is where some detective work comes into play. Basically it involves disassembling the game code and working out what routines do what. The source code below details all the patch points for the game ROMs where routines have been modified to call the new code.
Full Source + Patch Comments
The source was compiled using "TASM Z80 Assembler. Version 3.1 February, 1998.
Copyright (C) 1998 Squak Valley Software"
Features Added
; ----------------------------------------------------------------- ; Donkey Kong High-Score save & Serial EEPROM driver ; ----------------------------------------------------------------- ; ; - Version 1.0 ; - Another JROK production ; - 31st JAN 2001 ; ; Note: this code has been written purely to keep size to a ; minimum, so some of it may appear a little bizzare but it ; saves bytes.. trust me on that ;-) ; ; - code designed for ST 93C56A / 93C66A - serial EEPROM ; - which supports 8bit read/write *** MUST be a 256x8 device *** ; - 512x8 ( 93c66 also works ) ; ; Assembled using "TASM z80 Assembler. Version 3.1" ; ; ----------------------------------------------------------------- ; Code is divided into two part ; ; part 1 - $3565 - Highscore functions, save/restore/reset etc. ; ; part 2 - $3F30 - Serial EEPROM driver routines, read/write ; ; ----------------------------------------------------------------- ; Control Addresses ; ; Serial Data Read Port = bit 7 address $7C00 ; Output latch 6H - Q7 = 7d06 = clock ; Output Latch 6H - Q6 = 7d07 = data ; Output Latch 5H - Q1 = 7d81 = Chip Select ; ; Output latches only use bit 0 for output bit ; ; ; ; ----------------------------------------------------------------- ; Game Program Patches ; ----------------------------------------------------------------- ; ; ; ----------------------------------------------------------------- ; ROM DK.5E loaded ($0000-$0fff) ; ----------------------------------------------------------------- ; ; $1C6 - sets on screen "high score" ; - patch to call 'restore high-scores' @$25B ; - jp $025B ; ; $1CA - start location of copy changed ( $1B2 -> $1b8 ) ; $1CD - length of copy changed ( 9 bytes -> 3 bytes ) ; ; $25A - old initialize HS Table now just a return ( $C9 - ret ) ; $25b - new call to restore high-scores and set on-screen HS ; ; ; @25b call 3565h ; call restore or initialize ; ld hl, 611Dh ; < set on screen to 1st high ; ; score entry ; jp loc_0_1C9 ; ; ----------------------------------------------------------------- ; ROM DK.5C loaded ($1000-$1fff) ; ----------------------------------------------------------------- ; ; $14A6: 1E 3C <- high-score time ( 60 seconds ) ; $1557: 88 68 <- high-score data end of entry area ; $1558: 75 74 for 12 digits ; ; ; $15F3 - calls save_inits (ROM 5B) - jp $3593 ; ; ; ; ; ----------------------------------------------------------------- ; ROM DK.5A loaded ($3000-$3fff) ; ----------------------------------------------------------------- ; ; $3565 - Save Scores Code ; ; $373D to $3745 2D <- underscore characters ; ; $3F30 - EEPROM routines ; ; ; ; ; ; ----------------------------------------------------------------- ; ; ; ; ; INo .EQU $7C00 ; 7d06 = clock ; 7d07 = data ; 7d81 = Select .DEFINE cs_active ld ( hl ), l ; enable EEPROM .DEFINE cs_inactive ld ( hl ), 0 ; disable EEPROM .org $3565 ; always enable the write to the EEPROM call enable_write ; check for 1p & 2p start + 1p JUMP held down ; if all held down then reset the high-score table ld a, ( $7d00 ) and $0C ld c,a ld a, ( $7c00 ) and $10 or c cp $1C jr z, RESET_HST ; set read mode and read in the HST ld c,0 call READ_WRITE_HST ; see if the first byte is $94 ( as it should be ) xor a ld b,a call get_a_byte cp $94 jr nz, RESET_HST call CALC_CS ; checksum it ld c,a ld b, $AA ; address $AA = the checksum byte call get_a_byte cp c ret z ; checksum's is ok. jr RESET_HST ; ----------------------------------------------------------------- SAVE_INITS: ; ----------------------------------------------------------------- ; this routine is called FROM #15F3 call SAVE_HS_TABLE ld de, $31a ; Name has been registered ret ; ----------------------------------------------------------------- CALC_CS: ; ----------------------------------------------------------------- ; simple 8bit checksum ld b, $AA ld hl, $6100 ; $6100-$60A9 checksum xor a ccs_lop: add a,(hl) inc hl djnz ccs_lop ret ; ----------------------------------------------------------------- RESET_HST: ; ----------------------------------------------------------------- ; create a new high-score table ld hl, $6100 ld a, 1 ld c, $94 ld e, $F4 chr_next_entry: ld ( hl ), c inc hl ld ( hl ), $77 ; screen address inc hl ld ( hl ),a ; 1st inc hl ld b, 4 ; spaces cht_l0: ld ( hl ) , $10 inc hl djnz cht_l0 ; score digits ld b, 6 cht_l1: ld ( hl ) ,0 inc hl djnz cht_l1 ld b, 14 ; NAME cht_l2: ld (hl), $10 inc hl djnz cht_l2 ld ( hl ), $3F ; end of text char inc hl ld b, 4 cht_l3: ld ( hl ) , 0 ; score value inc hl djnz cht_l3 ld ( hl ), e ; end address inc hl ld ( hl ), $76 inc hl inc c inc c inc e inc e inc a cp 6 jr nz, chr_next_entry ; now save the HST ; ----------------------------------------------------------------- SAVE_HS_TABLE: ; ----------------------------------------------------------------- ld c, 1 ; read/write ; ----------------------------------------------------------------- READ_WRITE_HST: ; ----------------------------------------------------------------- ;c = 0 read ;c = 1 write ld de, $6100 rw_hst_lop0: ld b,e ld a,c and a jr z, dord dowr: ld a, ( de ) call write_a_byte jr cntn dord: call get_a_byte ld ( de ),a cntn: inc de ld a,e cp $aa ; address 0 to $AA jr nz, rw_hst_lop0 ld a,c and a ; if reading just end ret z ; ; write mode so calc and save checksum call CALC_CS ; calc and write HS ld b, $AA call write_a_byte ret ; *********************************************** ; * ; * Second section of code !! ; * ; * The EEPROM read/write routines !! ; * ; * This needed to fit between $3F30 and $3f9F ; * ; *********************************************** .org $3f30 ; ----------------------------------------------------------------- write_a_byte: ; ----------------------------------------------------------------- ; b = address (0-255) ; a = value to write push af ld a, $40 ; write op-code call send_op_and_address pop af wb_sb: call send_8_bits cs_inactive ; signal 'start' write jr wait_end ; ----------------------------------------------------------------- get_a_byte: ; ----------------------------------------------------------------- ; b = address to read ; a = value read ld a, $80 ; read op-code call send_op_and_address push bc ld b,8 gb_lop0: ; 1st bit of read is a dummy bit call do_clock ld a, ( INo ) rlca rl c djnz gb_lop0 ld a,c xor 255 ; data is inverted by the LS240 ; so it must be inverted to get ; the correct byte pop bc jr we_end ; ----------------------------------------------------------------- send_op_and_address: ; ----------------------------------------------------------------- call send_op_code call start_bit ; set a8 high ( only for 93c66) ld a,b ; 8bit address ; ----------------------------------------------------------------- send_8_bits: ; ----------------------------------------------------------------- ; a = byte to send ld b, 8 sb_lop1: rlca ; rotate a and clock the ld ( ix + 01 ), a ; bits out call do_clock djnz sb_lop1 ret ; ----------------------------------------------------------------- enable_write: ; ----------------------------------------------------------------- xor a ; 00 11xxxxxxx enable write call send_op_code ; opcode dec a ; x = don't care ; ld b,9 ; clock out 9 bits call sb_lop1 jr we_end ; ----------------------------------------------------------------- start_bit: ; ----------------------------------------------------------------- ; only bit0 of writing to the control latches ; is used so 'l' is used to set any of the ; latches to 1 ( as bit 0 of 'l' = 1 ) ld ( ix + 01 ), l ; data high ; ----------------------------------------------------------------- do_clock: ; ----------------------------------------------------------------- ld ( ix + 00 ), l ; clock high ld ( ix + 00 ), 0 ; clock low ret ; ----------------------------------------------------------------- send_op_code: ; ----------------------------------------------------------------- ld hl, $7d81 ; Select ld ix, $7d06 ; Clk/Data index cs_active ; enable eeprom call start_bit ; A reg. bit 7 & 6 = opcode call send_opc ; write the op code send_opc: rlca ; this gets executed twice ld ( ix + 01 ), a ; writing the two bits of jr do_clock ; opcode to the EEPROM ; ----------------------------------------------------------------- wait_end: ; ----------------------------------------------------------------- ; during a write the EEPROM pulls dataout ; low, ( it's inverted by the LS240 ) so you ; have to wait for bit 7 to go low ; for write to have completed cs_active ; when Q = low ( data IN0 =high ) ; Q = high ( data IN0 =low ) we_wait: ld a, ( INo ) ; bit7 = (0=1) (1=0) 1= EEPROM write busy rlca jr c, we_wait ; loop while 1 we_end: cs_inactive ; disable EEPROM ret .end |