Invalid money division discrepancy: Difference between revisions

Jump to navigation Jump to search
Content added Content deleted
No edit summary
 
Line 9: Line 9:


===Explanation===
===Explanation===
There is no BCD instruction for halving (or shifting) a number in hardware; the game must manually perform long division.<ref>https://github.com/pret/pokered/blob/master/engine/math/bcd.asm</ref>
There is no BCD instruction for halving (or shifting) a number in hardware; the game must manually perform long division.<ref>https://github.com/pret/pokered/blob/master/engine/math/bcd.asm</ref> 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:
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:
Line 17: Line 17:
* 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.
* 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. Crucially, it is easier to ignore invalid digits when manufacturing hardware (circuitry), but it is easier to detect the invalid digits anyway when emulating hardware. (The emulator may say "detect all invalid digits" instead of "detect invalid digits only when adding".) This difference in behavior ultimately leads to the inconsistency in this article.
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 Game Boy hardware only supports adding/subtracting one byte at a time for BCD values. 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:
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.
* 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.
* 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.