Invalid money division discrepancy

From Glitch City Wiki
Jump to navigation Jump to search

The invalid money division discrepancy refers to an inconsistency for dividing glitch money values in Pokémon Red, Blue, and Yellow between the cartridge and Virtual Console versions.

Example

The value hex:11F0C6 would be displayed as 11[bad tile]0[bad tile]6 Pokédollars on the Trainer Card in both Game Boy and VC RBY.

When halved on a Game Boy it becomes hex:5C563 which is displayed as 5[bad tile]563, but when halved on the Nintendo 3DS it becomes 54483.

This is due to money being stored as binary-coded decimal (BCD) in RBY, which is manipulated by a BCD-specific hardware CPU instruction. The original raw hardware for this instruction performs as few validity checks as possible, while the 3DS's emulation of this hardware performs an extra check, causing a final result with no bad tiles.[1]

Explanation

There is no BCD instruction for halving (or shifting) a number in hardware; the game must manually perform long division.[2] Long division naturally has subtractions inside.

In order to perform BCD addition/subtraction, the code first performs regular addition/subtraction in hexadecimal, then relies on the DAA (Decimal Adjust register A) hardware instruction. This instruction automatically adds/subtracts hex:6 or hex:60 from a byte if the previous addition/subtraction resulted in an invalid digit or involved a carry/borrow. For example:

  • hex:9 plus hex:9 normally yields hex:12, but it will also report to the CPU that this addition involved a carry. The DAA instruction will then detect the carry and add another hex:6 to yield hex:18.
  • hex:9 plus hex:1 normally yields hex:A, but the DAA instruction will notice the invalid digit and add another hex:6 to yield hex:10.
  • hex:10 minus hex:9 normally yields hex:7, but it will also report to the CPU that this subtraction involved a borrow. The DAA instruction will then detect the borrow and subtract another hex:6 to yield hex:1.
  • hex:10 minus hex:1 normally yields hex:F, but it will also report a borrow. The DAA instruction may either detect the borrow or notice the invalid digit, and subtract another hex:6 to yield hex:9.

Note that in the last case, there is technically no need to look for invalid digits when subtracting, because the only way to get them is through a borrow. The Game Boy hardware ignores invalid digits for subtraction, but the 3DS's emulator looks at invalid digits for subtraction. This difference in behavior ultimately leads to the money discrepancy.

Finally, the DAA instruction only works on one byte at a time, so BCD addition/subtraction must be done one byte at a time. In order to handle more than one byte, the code uses the "add with carry" and "subtract with carry" operations, which report to the CPU if a carry/borrow occurs and automatically add/subtract 1 from the result if the previous add/subtract with carry operation reported a carry/borrow. For example:

  • In order to perform hex:1000 minus hex:222, the code must first subtract the rightmost bytes (hex:00 minus hex:22 yielding hex:DE). DAA then turns this into hex:78, then it reports a carry/borrow.
  • The code then subtracts the leftmost bytes (hex:10 minus hex:2 yielding hex:E), then 1 is automatically subtracted due to the above "subtract with carry" reporting a borrow, then DAA turns the hex:D into hex:7.
  • This leaves hex:7 in the leftmost byte of the result and hex:78 in the rightmost byte, for a final result of hex:778.

All of the above is needed to understand how halving hex:11F0C6 turns into hex:54483 on the 3DS. When the game wants to determine the ten-thousands place during long division, it tries to count how many times hex:20000 can be subtracted from hex:11F0C6. During this, the game performs [hex:C6 minus hex:00 with DAA] and [hex:F0 minus hex:00 with DAA]. On the Game Boy, both of these operations have no effect because no borrows occur. On the 3DS:

  • hex:C6 minus hex:00 yields hex:C6. The DAA instruction notices the invalid digit and subtracts hex:60, yielding hex:66. It then reports that a borrow has occurred, due to invalid digits pre-DAA ordinarily indicating a borrow.
  • hex:F0 minus hex:00 yields hex:F0, then 1 is automatically subtracted due to the reported borrow, then DAA turns the hex:EF into hex:89. It then reports that a borrow has occurred again for the same reason.
  • hex:11 minus hex:2 yields hex:F, then 1 is automatically subtracted due to the newly reported borrow, then DAA turns the hex:E into hex:8.
  • The 3DS's emulator has just performed "hex:11F0C6 - hex:20000 = hex:88966". hex:20000 can be subtracted four more times before the remaining money is less than hex:20000, so the ten-thousands place is 5 and the remaining money is hex:8966.
  • There are no more invalid digits, so the rest of the long division and the subtractions inside play out normally. The remaining digits, hex:8966, are divided by hex:2 to yield hex:4483, and the final result of the division is hex:54483.

Speedrunning

For the catch 'em all category of Pokémon Red and Blue, speedrun.com have listed the following in the rules addressing the discrepancy:

"The 3DS Virtual Console version is not allowed due to an error in how money manipulation is emulated."


YouTube video

YouTube video by ChickasaurusGL

References