Sega Master System / Mark III / Game Gear
X-Terminator is a rare device that is very similar to the Pro Action Replay. It sits between the system and the game cartridge and injects code to write to memory. Some information is here:
This page is about how it works, based only on disassemblies of the ROM dumps. You can view the disassembly here:
There is hardware in the X-Terminator to allow selecting which ROM/RAM is selected for the lower 16KB based on some rules: either the device ROM/RAM, or the cartridge ROM. Higher addresses seem to always map to cartridge RAM, but the range $4000-$7fff is never accessed, only $8000..$dfff is expected to map to the cartridge.
This switch allows the device to hook the Z80 interrupt vector at $0038, which is used for frame and line interrupts. It assumes that all games will use these, which is probably true. As a result, the device menu code cannot use frame interrupts; it works simply by accessing the screen slowly enough to not cause issues during active display, and performing spin waits any time it needs to delay.
In the injected interrupt handler, it checks bit 0 read from address $0007. If this is 0, it jumps to its own menu at address $0000.
If the reset button was not pressed, it proceeds to write data to six memory locations specified in device RAM. As these default to address $0000, there is no effect - this is mapped to the X-Terminator's own ROM - but if a suitable cheat code is entered, it will write to RAM and have some effect.
It has no way to run only in VBlank interrupts, so games using HBlank interrupts may show some slowdown or graphical glitches as the HBlank code is delayed.
The device menu shows at startup. The user can select to enter codes (default) or search for cheats.
The code entry screen allows the user to enter up to six cheat codes. The default zero values have no effect.
Pressing boots the game. This executes some code in system RAM to read from address $0038 (to swap back to the game) and jumps to address 0. It does not attempt to replicate any BIOS state.
There is function to search for cheat codes. This is the reason why it has 8KB of RAM - the majority is used to track memory values during a code search. It has similar search modes to the Pro Action Replay. One notable difference from the PAR is that it will also detect and search for cheats in the on-cartridge RAM, but only the first 8KB of it. This may be needed for games using it as extra scratch memory, or for hacking save games.
Similar to the PAR, only having 8KB of RAM means it can only "search" a little less than 2KB of the potential memory locations at once - as it needs four bytes to track each location - which means the trickier cheat searches will take several iterations as it needs to eliminate possibilities to free space to even start considering later locations. As it searches the save RAM first, it'll be especially slow to find codes on games with save RAM.
Overall, these search algorithms are reasonable for a lot of cases but will also fail to find cheat codes in a lot of cases. There is no allowance for 16-bit or higher numbers, or single-bit flags.
The “lives” cheat scanner takes the value you enter (in decimal) and looks for bytes that have values equal to it in BCD or hex, for a range of one either side. e.g. a value of 99 would be searched for as $98, $99, $9a, $63, $64, $65 hex. On subsequent interactions of the scan process it requires that the offset is the same as previous matches, e.g. an address matching for an equal value for 99 must then match an equal value for the next searched value.
As this is filtering by value, it is likely to cover the full range of RAM in the first iteration, making it the fastest way to find a cheat, if you know the value to search for (and the searched value is not a common value like 0 or 1).
The “timer” scanner works by searching for delta changes from some initial value. The user may only enter a number from -9 to +9. Values are searched for a delta change of that amount, but always using BCD maths. Searches are only at the byte level. As it needs to find delta changes, it needs to track values for all possible memory locations until they are discarded; this means it needs a few iterations to even look at the higher addresses.
As it’s only ever looking at single byte BCD values, it seems like it will only ever find values that you could have found quicker using the Lives method.
Energy Bar mode is a bit more tricky, and therefore also makes harder to discard possible values. You start by capturing some “100%” value, which cannot be exceeded. You then iterate by picking a value of “about 25%”, “about 50%”, “about 75%” or exactly 100% of this initial value. At each stage it will discard values that are unacceptably far from the value you picked. This means, for example, that a “roughly 25%” value is considered acceptable if it is less than 50% of the previously captured 100% value.
However, as again it can’t track all of the memory due to only having 2KB of device RAM, it has to try to capture more values as possibilities get excluded. Some of these may be captured in one of the non-100% iterations, meaning the corresponding 100% value is unknown. It therefore treats these with an even greater margin. For example, an address known to have a “roughly 75%” value is only trusted to have >50%, and thus can only be used to discard numbers at the 25% and 100% levels. This means it will take longer to discard possibilities.
"Power" mode again searches for bytes, but this time the three possible states are equal, greater or less than some known starting value. At each iteration, values can be discarded if the known state is incompatible with the new state. For example, if the value stored is the "equal" value and the new state is "greater", then it can be discarded if the current value is not greater than the stored value. However, if the value stored is only known to be greater than what is wanted, it can't be discarded if the current value is also greater than what is wanted, because even if it is a different value, we can't know if that value is the target.
"Status" mode searches for bytes whose bits all invert when something is in the "opposite" state. This will only really work for cases where the game uses a whole byte for a flag, and flips between $ff and $00. It can't find single-bit flags.
"Other possibility" mode is the last scanner mode. This searches for bytes that are either equal to the initial state, or different in any way at all. If bytes are captured in a "different" iteration then the "correct" value is again unknown, and they are less useful because you can't tell if a new value is indeed different to the initial state.