Joust - Under the hood


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.

A rotating disk

Download WSF system ROM

v1.09


      




; 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"