1

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 ?

Demeter Purjon
  • 373
  • 1
  • 12

2 Answers2

2

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?

Community
  • 1
  • 1
Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
2

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.

lvd
  • 793
  • 3
  • 12
  • 2
    I think probably the key part of this answer is: *resulting carry is also inverted*. So the original author is right that the additive form produces neither carry nor half-carry. But he should invert that result and **set** the carry and half carry flags. Is that a fair thing to say? – Tommy Jan 03 '17 at 20:58