Can I use two complement for SUB instruction gameboy emulation?

1k views Asked by At

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 ?

2

There are 2 answers

1
lvd On BEST ANSWER

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.

0
Alexey Frunze On

You can find the answers to how add/sub work and carry/overflow flags are set here:

My answer to: Overflow and Carry flags on Z80

My answer to: How does an adder perform unsigned integer subtraction?