Success's hidden gem Guardian Force is a truly amazing game, but has one very unfortunate flaw: the program is extremely poorly optimized in terms of input latency. Even on the ST-V arcade hardware, the game has somewhere on the order of 6 to 7 frames of input lag. This is beyond the point of uncomfortable, and makes the game almost unbearably hard to control.
So, I had a feeling there would be some low-hanging fruit here. You don't get 6 to 7 frames of input lag if you're even remotely paying attention to how your inputs are handled. So, time to pop open IDA and MAME and get cracking. Turns out, yes there are at least 2 frames of easy-to-fix lag in software.
Here's a little tutorial on setting up the patch, since it's a little different from most things. But hopefully it should be obviously easier than most.
Installing
Burn the binary file (available on my website) to any 8-bit ROM with a similar pinout to the 27C010. The file size is very small, and this is the only ROM size required. So you could use a 27C020, 040, 080, etc. You don't need to even repeat the file for those ROMs, it's very forgiving.
Once your ROM is burned, open up the cart. You will see an empty EPROM socket on the cart's board, as shown below.
Simply put the ROM you've burned in that socket, and close it back up. That's it! Sega was very clever when they designed their carts, weren't they?
Dev Log
So with this, I had to figure out how the patch EPROM worked on the ST-V. It turns out it's really simple, all I really had to do was take parts of the beginning of the regular ROM data (just the bootstrap, essentially) and work some patching code into it. From there, I needed to find the sources of input lag and devise how to remove them. So, it's watchpoint time.
In the end, I traced the input data coming from the hardware through 2 interstitial buffers which were implemented by Success. We'll name the points here as:
- hw_inp, the input data exposed directly from the hardware
- smpc_buffer, the input data which would normally come from Saturn pads
- smpc_parsed, the input data which is derived from smpc_buffer
We can look at these buffers in two ways: who fills them, and what order are they filled? If the buffers are used optimally (in a way which does not increase latency), these should essentially flow the exact same way. In Guardian Force's case, they literally flow the opposite.
Code: Select all
Who fills who?
Hardware -fills-> hw_inp -fills-> smpc_buffer -fills-> smpc_parsed -fills-> Player's Input Code
What order are they filled?
Frame Start -> hw_inp -> Player's Input Code -> smpc_parsed -> smpc_buffer -> Frame End
The obvious fix here is to invert the order of fills. In this way, each buffer reads from the buffer that was just filled, meaning it's still along the same frame's data. Thus, we remove 2 frames of input lag.
I'm sure there are more dumb sources of lag (it's still somewhere around 4 frames on hardware!), but this is such a massive improvement already that I figured it was worth posting.