Monday, January 05, 2015

Space Harrier Protection Mechanism

The Sega Enhanced package has been updated with a fix for a protection issue when running the game on Enduro Racer hardware. Sega protected the original game code, to prevent it from running on hardware without the i8751 microcontroller.

It was previously thought that the protection was defeated, however an interesting bug surfaced. Interestingly, MAME did not correctly support the protection either. This resulted in Space Harrier being flawed on MAME, with the life counter incorrectly incremented.

More details from the UKVAC post are below:

This all came to light when Space Harrier world champion and fine upstanding member of the UKVAC community Jodo mentioned in the discussion that there was a *bug* in Space Harrier when played on Enduro Racer hardware whereby occasionally your lives remaining would NOT decrease when you got hit by an enemy, or in some cases your lives remaining would actually *increase* when you got hit by an enemy.  He posted a video of it in action and I then also confirmed that the issue existed using both patched and unpatched SH roms in MAME.

Well this fascinated me and, as I've become rather adept at fixing Sega code bugs in the past few years, I thought I'd look into it deeper to hopefully resolve it.

As you may be aware it's possible to play Space Harrier on an Enduro Racer board set.  The only difference between an SH board set and an ER board set is the inclusion of an i8751 protection MCU on SH.

It was originally thought that the only purpose of the MCU was to check the main cpu roms at boot time, generate a vblank interrupt for the main cpu and process analog inputs/pass them to the main cpu.

It now turns out that this is not the case and the MCU does further protection on the game code.  This is the *bug* (it isn't actually a bug, it's protection code).

The protection routine starts at address $4aae in the main cpu code.  It works by querying the in-game timer (the timer that starts when you start a new game) and if the timer is a multiple of $200 (512) seconds it adds 1 to the word value @ $400f0 in memory.

This value is then copied, every vblank, to $124306 (in shared ram) by the code @ $4e86.  This is the trigger for bad things to start happening.

The value at $124306 is queried whenever you lose a life by the code @ $75ca and the following happens, based on the value held in that memory location at that time :-

if the value is 0 then nothing further happens (this is what the value should ALWAYS be)

if the value is 1 (i.e. after 512 seconds of gameplay) then the in-game frame counter is ANDed with a value of 1 and the result is ADDED to your lives remaining count.  The routine which subtracts 1 from your lives remaining count is then called and the game continues.  What this means, in effect, is that, after 512 seconds of gameplay, you've got a 50/50 chance of NOT losing a life when you get hit by a bad guy.

if the value is 2 (i.e. after 1024 second of gameplay) then the in-game frame counter is ANDed with a value of 3 and the result is ADDED to your lives remaining count.  The routine which subtracts 1 from your lives remaining count is then called and the game continues.  What this means, in effect, is that, after 1024 seconds of gameplay, you've got a 25% chance of losing a life, a 25% chance of NOT losing a life, a 25% chance of GAINING a life or a 25% chance of GAINING 2 lives, when hit by a bad guy.

if the value is 3 or higher (i.e. after 1536 seconds of gameplay) then the in-game frame counter is ANDed with a value of 7 and the result is ADDED to your lives remaining count.  The routine which subtracts 1 from your lives remaining count is then called and the game continues.  What this means, in effect, is that you're now swimming in extra lives, to the point that the game will eventually crash if you keep getting hit by the bad guys (as you've accumulated so many lives by this point).


Long serving and well respected MAME dev team member Chris Hardy (Junofirstman on here) has confirmed my initial findings.  He believes the MCU writes a value of zero to address $400f0 every vblank, so the absence of this simulated code in SH running on ER hardware or in MAME meant that the above phenomenon was happening after 512 seconds of gameplay.

Chris has updated the MAME driver and submitted it and also suggested a patch to the roms for playing on ER hardware which will eliminate the problem.

So, taking a step back, I think this was a pretty crafty protection scheme by Sega.  Time delayed protections are usually very effective and the most difficult to find as they often don't start kicking in until a long time after the game has booted (as is the case here, ~8.5 minutes of gameplay until the effect is noticed).  This means that the bootleggers may have thought that they'd overcome the MCU protection if they managed to clone the functionality of it sufficiently to get the game to boot.  They may not then have proceeded to test it sufficiently long enough to notice the time delayed protection effects kicking in.

What this would mean though is that, if SH was bootlegged and the bootleggers didn't overcome the time based protection and arcade operators bought a bootleg board instead of a genuine Sega board then the operators would likely have been losing money as the players would have been getting much longer gameplay for their 10/20p due to all the extra lives they'd have been getting.  So Sega's idea was to hit the operators where it hurt, in the pocket.

Thanks go out to Chris Hardy, Jodo, Mark Haysman and Ordyne for all chipping in with info and to Sega for making awesome games with semi-awesome protection.