This repository has code and descriptions related to reverse engineering the Hydro Thunder Diego board. The Diego board is used to interface between the arcade game controls and the Quantum3D Quicksilver II system running the Hydro Thunder software.
Many of these scripts were written along the way while reverse engineering and eventually became obsolete for my needs, so for example the comments may not be accurate, or some of the code may not even function as originally intended (I haven't gone back and fully re-tested all scripts). The code is (somewhat intentionally) messy, since I left things like debugging print statements in the code, though (sometimes) commented out, to make it easier to revisit testing or future reverse engineering.
There are a couple threads on the KLOV forums where some Hydro Thunder and Diego reverse engineering was discussed, which may be of interest: https://forums.arcade-museum.com/threads/confirmed-working-hydro-thunder-video-card-security-bypass.357654/ and https://forums.arcade-museum.com/threads/hydro-thunder-preservation-how-to-run-on-a-modern-pc.513527/ .
These were mostly focused on getting the game to work with a stock 3DFX Voodoo2 instead of the custom card used in Hydro Thunder, but also discussed the Diego.
In particular, thanks to linkinpark9812 from the KLOV forums for reverse engineering the CPLD on the video card, which was required for communicating with the Diego board. Some of my scripts use his CPLD security functions.
Interfaces the Diego with BackForceFeeder, which along with vJoy, provides a virtual joystick supporting force feedback for Windows (used for PC games, emulators, etc.).
My fork of njz3's project: https://github.com/pdaderko/vJoyIOFeederWithFFB
Related - my simple script to interface with BackForceFeeder: https://github.com/pdaderko/vJoyIOFeederWithFFB/blob/master/bff_translate/bff_translate.py
Simulates the Diego board from a PC terminal window. Allows you to play Hydro Thunder with a keyboard, which could be useful for troubleshooting if you suspect you have a bad Diego board. It also repeatedly sends the video card enable sequence, which allows the PC to boot past the 6 beep startup error that occurs when no Diego is present, as well as enabling video to see that the game is working.
Decodes bits from PC and Diego communications. Also confirms the checksum and parity checks passed.
Man-in-the-middle between the Diego and PC. It verifies and decodes data, (optionally) modifies the data, re-encodes the data, then outputs to the other side
Pieces of relevant code with my comments from decompiling the Hydro Thunder executable with Ghidra ( https://github.com/NationalSecurityAgency/ghidra )
At startup, the Diego repeatedly sends data, informing the PC that it is present, but not initialized. Once the PC starts to boot, it sends an initialization command to the Diego and waits approximately 1 second for a message from the Diego with the initialized bit set (bit 6 of byte 0). If it doesn't receive this message, the PC will give a 6 beep error. To get around this, you can simply always send simulated Diego messages with the initialized bit set.
As the computer continues to boot, the Diego and PC will begin a handshake process. The Diego periodically sends a 32-byte sequence to enable the video card output, at which point the video will become visible. This is a fixed security sequence and can be replayed to simulate the Diego.
Before becoming active, the Diego flashes all of the control panel lights, doesn't output any control input data, and ignores any input from the PC. The Diego continuously outputs a seemingly random security sequence in its serial messages, looking for a valid response. The response is calculated in the CPLD of the proprietary Voodoo2 card and returned in the PC serial messages. Once the Diego receives a valid response, the inputs and outputs become enabled. While the PC passes the data between the Diego and video card, it doesn't check whether the data is valid. The PC will accept data from a simulated Diego without any security bits (though as discussed above, if using the proprietary video card, it requires the security sequence to enable video).
Both the Diego and PC fill unused payload bits with random data, presumably to make it more difficult to reverse engineer its protocol. This data can be safely ignored, and when simulating messages, these values can be fixed (e.g. all 0s).
A security sequence is generated by the Diego board to ensure the entire system is present, including the Diego and PC with its proprietary 3DFX Voodoo2 video card.
The security sequence originates from the Diego board, which gets passed to the PC over the serial port and into a CPLD on the proprietary 3DFX Voodoo2 video card, which outputs its response data back to the PC, getting passed to the Diego over the serial port. With an incorrect video card, the Diego will never unlock, causing non-functional controls. Without the special sequence from the Diego, the original video card will never output video.
Every payload (for both PC and Diego) is 8 bytes before checksum and encoding
-bit 7 of byte 0 is an even parity bit
Bytes 8 and 9 are a Fletcher-16 checksum over 8 payload bytes, similar to description at the bottom of: https://en.wikipedia.org/wiki/Fletcher%27s_checksum#Example_calculation_of_the_Fletcher-16_checksum (byte 8=CB1, byte 9=CB0)
-slightly modified in that CB0 does one more calculation round inputting the CB1 value, and the final value used is 255 minus CB0
After the payload, parity, and checksum are generated, the data is put on the RS232 lines at 38400 8N1 with encoding based on the SLIP protocol
-every message starts and ends with 0xC0
-0xC0 in payload is substituted with 0xDB 0xDC
-0xDB in payload is substituted with 0xDB 0xDD
Receiving is done in the opposite order - SLIP encoding removed, checksum verified, parity checked
byte 0 bit 7: even parity
byte 0 bit 6: initialize Diego
byte 0 bit 5: security clock
byte 0 bit 4: unknown, always 0
byte 0 bit 3: random bit, ignore
byte 0 bit 2: security reset
byte 0 bits 1 to 0: security sequence bits
byte 1 bits 7 to 2: random bits, ignore
byte 1 bits 1 to 0: unknown, always 0
byte 2: force feedback (two's complement, negative for right force, positive for left force)
byte 3 bit 7: header top lamp
byte 3 bit 6: header bottom lamp
byte 3 bits 5 to 4: random bits, ignore
byte 3 bit 3: high view lamp
byte 3 bit 2: low view lamp
byte 3 bit 1: pilot view lamp
byte 3 bit 0: boost lamp
byte 4 bits 7 to 4: random bits, ignore
byte 4 bits 3 to 0: bits shift up and down, causes LEDs on Diego to toggle, showing some life (seemingly no other function)
byte 5: always 0x80 except 0x00 in first message (seemingly no functionality)
byte 6: always 0xFF except 0x84 in first set of messages (seemingly no functionality)
byte 7: random bits, ignore
byte 0 bit 7: even parity
byte 0 bit 6: Diego initialized
byte 0 bit 5: security clock
byte 0 bit 4: unknown, always 0
byte 0 bit 3: random bit, ignore
byte 0 bit 2: security reset
byte 0 bits 1 to 0: security sequence bits
byte 1 bit 7: random bit, ignore
byte 1 bits 6 to 4: coin 5 count (0 if never used, otherwise loops from 1 through 7)
byte 1 bits 3 to 1: coin 4 count (0 if never used, otherwise loops from 1 through 7)
byte 1 bit 0, byte 2 bits 7 to 6: coin 3 count (0 if never used, otherwise loops from 1 through 7)
byte 2 bits 5 to 3: coin 2 count (0 if never used, otherwise loops from 1 through 7)
byte 2 bits 2 to 0: coin 1 count (0 if never used, otherwise loops from 1 through 7)
byte 3: steering (8-bits unsigned, 0x00 is full left, 0xFF is full right)
byte 4: throttle (8-bits unsigned, 0x00-ish is full reverse, 0xFF-ish is full throttle), controls seem to malfunction when throttle is 0x00 or 0xFF and boost is pressed, maybe due to calibration?
byte 5 bit 7: DIP switch 7
byte 5 bit 6: DIP switch 6
byte 5 bit 5: DIP switch 5
byte 5 bit 4: DIP switch 4
byte 5 bit 3: DIP switch 3
byte 5 bit 2: DIP switch 2
byte 5 bit 1: DIP switch 1
byte 5 bit 0: DIP switch 0
byte 6 bit 7: test switch
byte 6 bit 6: volume up switch
byte 6 bit 5: volume down switch
byte 6 bit 4: credit switch
byte 6 bit 3: pilot view switch
byte 6 bit 2: low view switch
byte 6 bit 1: high view switch
byte 6 bit 0: boost switch
byte 7: random bits, ignore
Determine the remaining unknown bits. I'm fairly certain that bits labeled "random" are unused based on the decompilation. The bits labeled "unknown" appear to have code associated with them, though their functionality is unknown at the moment.
One or more of the bits may be related to the coin counter, though I haven't had time to investigate.