Page 1 of 1

Negating a number

Posted: Mon May 13, 2013 1:46 pm
by Dafydd
So I found this code on the wiki and it seems to work:

Code: Select all

; A = -A
eor #$FF
sec
adc #0
but two's complement is normally inverting all the bits and then adding 1, so that e.g. $00 = $FF + $01 = $00 (where the addition, in this case, results in the carry flag being set).

However

Code: Select all

lda #$00
eor #$FF
adc #$01
does not seem to yield a = 0.

What am I missing about the carry flag and why would it make a difference whether it's set before the adc instruction in the first code example? And why add with 0 instead of with 1?

Re: Negating a number

Posted: Mon May 13, 2013 2:02 pm
by lidnariq
Since neither LDA nor EOR affect the C flag, you should end up with 0 or 1 in A, corresponding to whether C was set before you started.

ADC always does A←A+C+argument.

It doesn't matter whether the +1 in the correction after the EOR comes from #immediate or from C.

Re: Negating a number

Posted: Mon May 13, 2013 2:18 pm
by Dafydd
Wait - the contents of C are added to A when doing ADC? :shock: ... wow. This changes things. Thanks for clearing that up.

How could I not know this already

Re: Negating a number

Posted: Mon May 13, 2013 2:33 pm
by Dafydd
By the way, does SBC do A←A+C-argument, or A←A-C-argument?

Re: Negating a number

Posted: Mon May 13, 2013 2:36 pm
by lidnariq
The latter.

Re: Negating a number

Posted: Mon May 13, 2013 2:48 pm
by Dafydd
Actually that's what the C stands for in ADC: ADd with Carry.
Yeah, but I thought that only meant that it would set Carry upon overflow (whyever I would think that, and however useful that might be), as opposed to ADD which would only... add. I don't think I've ever seen it explained anywhere what it means to Add with Carry and that it would do A←A+C+argument.

Look at this page, for example: http://www.6502.buss.hk/6502-instruction-set/adc
ADC #10 | Perform the ADC operation between $10 (Decimal 16) and the content of the Accumulator
... which does not mention Carry, and as far as I know, the Carry flag is not part of the content of the Accumulator.

Anyway, thanks to you, I know how it works now. So thanks again.

Re: Negating a number

Posted: Mon May 13, 2013 3:37 pm
by Dafydd
According to wikipedia,
subtract with carry computes a+not(b)+C
and since not(b) = (-b-1) = -(b+1), this should mean that SBC does A←A+C-(argument+1), or A←A+C-1-argument. So that's why the Carry flag needs to be set before subtractions.

Re: Negating a number

Posted: Mon May 13, 2013 6:29 pm
by blargg
SBC is more like add carry and one's complement of operand to A. Thus you set carry to have it add two's complement to A (and clear carry to do a borrow). It's all so elegant.

BTW, a way of intuitively grasping negation is that you first flip all the bits, which is equivalent to subtracting the value from $FF. But you want it subtracted from $100, which is one more, so you add one.

Re: Negating a number

Posted: Mon May 13, 2013 7:35 pm
by tokumaru
Dafydd wrote:this should mean that SBC does A←A+C-(argument+1), or A←A+C-1-argument. So that's why the Carry flag needs to be set before subtractions.
In subtractions, I like to think of the carry flag as value you put there (i.e. SEC) to be borrowed. If it doesn't need to be borrowed (i.e. no underflow) it will remain there, otherwise it will be borrowed and the carry will be clear after the operation, indicating that the next SBC must borrow 1 from the next place. I know this is not the actual logic within the CPU, but conceptually this works fine.

Re: Negating a number

Posted: Mon May 13, 2013 11:09 pm
by koitsu
tokumaru wrote:
Dafydd wrote:this should mean that SBC does A←A+C-(argument+1), or A←A+C-1-argument. So that's why the Carry flag needs to be set before subtractions.
In subtractions, I like to think of the carry flag as value you put there (i.e. SEC) to be borrowed. If it doesn't need to be borrowed (i.e. no underflow) it will remain there, otherwise it will be borrowed and the carry will be clear after the operation, indicating that the next SBC must borrow 1 from the next place. I know this is not the actual logic within the CPU, but conceptually this works fine.
FWIW, this is exactly how I conceptualise it as well. :-)