Fun & Games with Joust
Background
With the WSF boards I'd had a couple of reports about the occasional
crash with Joust. Well, apart from one manufacturing faulty board I
didn't do a lot of digging into the issue, seeing as the beta testers
hadn't found anything and couldn't really get anything to be reproducible.
Plus Robotron, which is the same hardware, had been played to death without
incident. I figured it was either a game glitch or a power supply problem
which has caused all sorts of crap in the past eg. don't run games
at 4.25v and expect them to be stable !.
Next Version of WSF
So fast forward to testing the new v1.1 of the WSF hardware and using
Joust as the test 'mule'. The game ROMs for the test board were
modified to never decrement player lives so a game could be left playing
for hours.. or even days ( seriously ).
After some intensive testing what happened ? Joust crashed.. and
we could get it to repeat. But not at the same point, or the same time, or the same level. It
looked to be.... RANDOM.
Software or Hardware ?
First step let's check the software. A new set of ROMs was burned,
pulled from an original machine just to be paranoid, and then run with
lives set at 255. Well, the
results were no problems, hours without anything going wrong. That's a
"phew" at least the hardware wasn't screwed up.
Where's the problem ?
With it narrowed down the the software, that meant one thing. It was
something to do with the 'ego' patch made to the Joust ROMs, which allow for
more than 5 sets of the same initials to be entered. But what ? ROM
checksums passed and the code change was benign, what was happening ?
This smelled like it could be a check against modifying the game code. So
time to dig through the original code to find what was going on.
Although... this type of thing is made a lot easier by being able to hook up a logic
analyzer to the game board and watching to see if anything accesses the
changed area of code. When something accesses that area of memory, and it
wasn't either the power-up test checksum or the code being executed, then
you know you're onto something.
Well, sure enough the culprit was found and here for viewing enjoyment is
why Joust is a b*****d. Very very nasty Mr.Bill Pfutzenreuter [ the
accredited original programmer ].
None of the other games have his type of check and it appears to be
limited to Joust only (!)
Quick Summary
During gameplay a 16 bit checksum is taken of most of the low ROM area,
but ONLY of even memory addresses. If the value does not match a stored checksum,
then it will randomly corrupt a single byte of memory. This byte could be
completely harmless, it could cause a game glitch or it could corrupt something
important and cause the game to crash.
From testing the checksum took about 8 minutes to complete and then could
cause a corruption. You can be 'lucky' and have it do nothing visible
until you hit levels 20 and up. Coupled with it's random nature it's
annoyingly tricky to repeat in the wild.
Before anyone asks, no there isn't an Odd memory address checksum.
The FIX
Updated master ROM for the WSF board which fixes game code checksum
issue and retains the 'ego patch' allowing multiple initials.
The update just moves the checksum change for the 'BRA' to an even address
in an area of unexecuted code.
Offset Change Purpose
00004886: 24 -> 20 ; changes BCC to BRA ( ie. always branch )
00004888: 0A -> 0E ; fix EVEN checksum
Note: Change is from original gamecode to modified code.
Updated ROM
New ROM version 1.09
This can be burned onto an 1Meg x 8 bit EPROM eg. 27C080, 27c801 or
27C8000 to replace the EPROM on the board.
|
; Summary:
;
; After doing important functions like moving enemies, updating the player position etc.,
; this routine checksums the low ROMs from 0000 to 7FFF inclusive on EVEN addresses only (!)
; The checksum is compared to the value at $EEC1 and if the values to do not match
; a random address in the range $A000 to $AFE0 is incremented ( aka. corrupted ).
; Now as this address could be something completely innocuous the corruption can have no effect on
; the game. However, it could also be something very important and cause everything to crash.
;
; This code is called as part of the normal interrupt (IRQ) processing and depending on
; how much is being updated on-screen, the code can be skipped resulting in > 16ms per-iteration.
; From observation it can take up to 8 minutes to complete the checksum.
;
; As the code takes so long to run and the memory corruption can be benign, the net result
; can take a long time to cause any problems and you can play for a while without any impact
; being visible.
;
;
; Why does this happen ?
;
; Because the high score initials patch altered an even address, and fixed the main ROM checksums on an odd address
; the even only checksum routine failed (EEK!) and so causing a random corruption of memory.
;
;
;
;
;
;Notes:
; ROM is always paged in and this code is executed every approximately 16mSec
;
; Datapointer (DP) = $A0 so RAM access is in the range $A0xx
; U = $A218
; --------------------------------------------------------------------------------------------------
; --------------------------------------------------------------------------------------------------
ECF8 ROM_ingame_checksum_clear:
ECF8 6F 4D
ECF8 clr $D,u ; checksum address (hi)
ECFA 6F 4E clr $E,u ; checksum address (lo)
ECFC 6F 4F clr $F,u ; checksum current value ( $F,U ) is this a coincidence ?
ECFE
ECFE ROM_ingame_checksum:
ECFE 86 01 lda #1
ED00 BD E0 37 jsr loc_0_E037 ; dispatch game code ( move players, enemies etc. )
ED03 AE 4D ldx $D,u ; get the next checksum address
ED05 A6 81 lda ,x++ ; a = the byte to be added ( always ROM note ), increment
; address by 2
ED07 AB 4F adda $F,u ; add to the running checksum total
ED09 A7 4F sta $F,u ; save total
ED0B AF 4D stx $D,u ; save the next address to check
ED0D 2A EF bpl Rigc_lop ; loop until address $8000 reached
; ( odd as there's still 4k of low EPROM left which could be
; checked ? $8000-$8FFF ? )
ED0F B1 EE C1 cmpa even_checksum ; $EEC1 contains the checksum value) do the checksums
; match ?
ED12 27 E4 beq ROM_ingame_checksum ; equal then start all over again
ED14 BD 7A 75 jsr screw_with_memory ; really it does screw with memory.. randomly
ED17 20 DF bra ROM_ingame_checksum
; --------------------------------------------------------------------------------------------------
; --------------------------------------------------------------------------------------------------
7A75 screw_with_memory: ; seriously that's what this does (!)
7A75 BD E0 18 jsr get_pseudo_random_number
; uses $A00D, $A00E which are updated every 4mSec IRQ
; A = 00-FF 'random' number
7A78 49 rola ; shift a, removing low bit ( bit 0 becomes '0', carry into bit 7 )
7A79 C6 10 ldb #$10
7A7B 3D mul ; D = A*B, effectively A<<4, so low 5 bits of A = '0'
7A7C 8A A0 ora #$A0 ; 'á' ; D = $Axx0
; at this point the Random number is value from
; A000 to AFE0
; so D = an address on a 32 byte boundary anywhere in this range
7A7E 1F 01 tfr d, x ; move D into X
7A80 6C 84 inc ,x ; corrupt that area of memory and possibly
; do something nasty
7A82 39 rts ; "Hah Hah, I just totally fragged something"
|
|