Hello I'm writing an emulator for Game Boy.
And I'm struggling with SUB intruction
SUB a, 0x92
given a = 0x90
.
What I am doing is :
0x90 + (-0x92)
I use 2 complement method for substraction.
-0x92 <=>
2_complement(0x92) <=>
2_complement(10010010) <=>
01101101 + 1 <=>
01101110
So the substraction is equivalent to the following addition:
1001 0000 (0x90)
+0110 1110 (-0x92)
---------
1111 1110 (0xFE)
During the process, there is no carry and no half carry so I don't set the flags. And I think it's a mistake because other emulators (like BGB does. Note that the result is correct, only the flags are incorrect.
So I suppose real processor doesn't use 2 complement method because there is no free way to retrieve carry and half-carry.
Still, can I use two complement for emulating the SUB instruction with flag handling, or should I rely on "classic" substraction logic ?
Real CPUs do really rely on inversion of an argument while doing subtraction.
Note first that two's-complement is by itself another addition (you add 1 after inverting all bits), so doing exactly like that would be slow.
Let's look at adding just an inverted argument:
0x90 + (~0x92) = 0x90 + 0x6D = 0xFD and you get no carry. Off by 1 from correct result.
To fix the result, you must add another one, which is conveniently done by passing carry in = 1 to the adder. Thus, you must invert incoming carry just like you've done with the argument. Not surprisingly, resulting carry is also inverted.
An example: subtract 0x12 from 0x34: 0x34 + (~0x12) + 1(inverted incoming carry) = 0x34 + 0xED + 1 = 0x122: no carry out (take inverted output carry) and correct result. Incoming carry is 1: 0x34+0xED+0 = 0x121 (no carry out, result is less by 1).
There are, however, CPUs that don't invert incoming and resulting carry: those include 6502 (inverted carry inputs and outputs SBC command) and 32bit ARMs. They only invert argument.