Signed addittion/subtraction beyond 8 bits

Programming the 6502 microprocessor and its relatives in assembly and other languages.
Dan Moos
Posts: 277
Joined: 11 Mar 2017
Location: Lynden, WA

Signed addittion/subtraction beyond 8 bits

Post by Dan Moos »

Is there a good tutorial explaining how to do 2s compliment arithmetic on the 6502 when more than a single byte is needed?

Edit: for instance, how do I do 127+1 ?
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Signed addittion/subtraction beyond 8 bits

Post by GARTHWILSON »

Dan Moos wrote:
for instance, how do I do 127+1 ?
It's mostly the same thing as with unsigned. The difference is in how the results are interpreted, not how they're arrived at.  In the case above though, assuming you wanted a positive result, since 8 bits can't represent it in signed, you'd need more than one byte; then the high bit of the high byte has the sign.  Bruce Clark has some good articles indexed at http://6502.org/tutorials/, particularly "Compare Instructions," "Beyond 8-bit Unsigned Comparisons," and "The Overflow (V) Flag Explained."
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
Dan Moos
Posts: 277
Joined: 11 Mar 2017
Location: Lynden, WA

Re: Signed addittion/subtraction beyond 8 bits

Post by Dan Moos »

Let me do a worked example so you can tell me if bi have this correctwhat I want is:

127 -> 01111111 + 1->00000001 =
00000001 00000000

But the answer ADC will give me is 10000000, and the V flag will be set. Thus, it is up to me to interpret the V, C, and N flags after every addition/subtraction in order to "create" the bit pattern I want using software. Correct?
gfoot
Posts: 871
Joined: 09 Jul 2021

Re: Signed addittion/subtraction beyond 8 bits

Post by gfoot »

Your example is not correct, the result should be 128 which doesn't fit in a signed byte, so you need to decide what you want to do - either execute the addition at only 8 bits and accept that it overflowed to -128 (as the V flag indicates), or sign-extend the operands to signed 16 bits ($007F + $0001) and perform a 16-bit addition instead, which will give $0080 with V clear after the high byte addition. That's still 128 of course. Bit for bit, the arithmetic is the same as for unsigned numbers, except for the sign extension and use of the V flag instead of the C flag to detect overflow.

It's worth reading the pages Garth linked especially regarding the overflow flag.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Signed addittion/subtraction beyond 8 bits

Post by GARTHWILSON »

I see gfoot posted while I was writing.  I'll post this anyway, to supplement.

Dan, what you have would not be twos' complement.  The normal way to reach what I suspect is your goal, is simpler.  Think of the circle where positive numbers wrap around to negative numbers, so 127d + 1 turns to -128d.  In twos' complement, 1 00000000b represents 256d, not 128d.
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
Dan Moos
Posts: 277
Joined: 11 Mar 2017
Location: Lynden, WA

Re: Signed addittion/subtraction beyond 8 bits

Post by Dan Moos »

I've read the articles. While I'm sure the information is there, some things aren't clear to me. Sounds like it is indeed a 2s complement misunderstanding.

Let me ask this. As soon as I need to represent a number larger than 127, or smaller than -128, do I need to stop using "7 bit + sign bit" and turn my number into "15 bit + sign bit"?

My , apparently incorrect thinking had been that in order to represent numbers greater than 127 or less than -128, I would have multiple "7 bit plus sign bit" bytes. This of course would be quite a mess to deal with. Is the real method to just us the "word" length required?

If so, this makes the V flag more confusing to me. Tell me if this is correct. If I subtract a byte, and the result is less than 0x80, or I add and the result is greater than 0x7f, is that the criteria for V to be set? In other words, is the behavior dependent on whether I'm adding or subtracting?

Pseudo code demonstrating overflows in both directions would be super helpful.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Signed addittion/subtraction beyond 8 bits

Post by GARTHWILSON »

In twos' complement integers, there's only one sign bit, which will be the high bit of the high byte.  So yes, going to two bytes allows 15 bits plus sign, so you can represent -$8000 to +$7FFF, and counting down from 2, you get 2, 1, 0, $FFFF (which is -1), $FFFE (which is -2), etc..  If you have three-byte signed quantities, you'll have 23 bits plus the sign bit, and the middle and low bytes will be 8 data bits each and they will be ignorant of the sign.  Four-byte signed quantities will have 31 bits plus the sign bit.

The easy thing to remember is that if the V (overflow) flag is set, it just means the apparent sign of the result is incorrect.  For example, if you have $70 (a positive number) and add $60 (another positive number), without carry, the result will be $D0, which appears to be negative because the high bit is set, but it cannot truly be negative because you added two positive numbers, so the apparent negative status is incorrect.  The same would be true of 16-bit numbers $7000+$6000=$D000.
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: Signed addittion/subtraction beyond 8 bits

Post by Chromatix »

Going back to the worked example:

Code: Select all

; First operand, signed 16-bit
LDA #127
STA $10
STZ $11

; Second operand, signed 16-bit
LDA #1
STA $20
STZ $21

; Add them together, store in a third place
CLC
LDA $10    ; 127
ADC $20    ; plus 1
STA $30    ; equals 128
LDA $11    ; 0*256
ADC $21    ; plus 0*256
STA $31    ; equals 0*256

; N flag (sign bit of high byte) now reflects whether the result is overall negative
BMI @negative
BPL @notNegative

; V flag (overflow flag resulting from high-byte addition) now reflects whether the result was too large to be correctly represented by a 16-bit signed integer
BVS @overflow
BVC @notOverflow

; Z flag DOES NOT indicate whether final result is zero - to get that, use the following:
LDA $30
ORA $31
BEQ @zero
BNE @nonzero
The above code is intended to be educational, and as such is deliberately unoptimised.
Last edited by Chromatix on Sun Oct 01, 2023 5:55 am, edited 1 time in total.
barnacle
Posts: 1831
Joined: 19 Jan 2004
Location: Potsdam, DE
Contact:

Re: Signed addittion/subtraction beyond 8 bits

Post by barnacle »

With one caveat: ensure that the D (decimal) flag is clear when you execute this code... or you will be pulling your hair out.

Neil
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: Signed addittion/subtraction beyond 8 bits

Post by Chromatix »

Well, the 6502 doesn't support signed BCD anyway. In Decimal mode, all values are essentially unsigned, and you'll have to store an explicit sign flag if you want one.
barnacle
Posts: 1831
Joined: 19 Jan 2004
Location: Potsdam, DE
Contact:

Re: Signed addittion/subtraction beyond 8 bits

Post by barnacle »

Indeed. But it's not immediately obvious that that's the case. As you said, the difference between signed and unsigned is in the interpretation, not the representation.

Neil
John West
Posts: 383
Joined: 03 Sep 2002

Re: Signed addittion/subtraction beyond 8 bits

Post by John West »

Chromatix wrote:
Well, the 6502 doesn't support signed BCD anyway.
Are you sure about that? With 10's complement, and values $50 and over being negative, we get sums like
33 + -48 -> $33 + $52 = $85 -> -15
The N flag is wrong, but otherwise it seems to work.
gfoot
Posts: 871
Joined: 09 Jul 2021

Re: Signed addittion/subtraction beyond 8 bits

Post by gfoot »

I'd say that if the N flag and V flag are wrong then it's not supported as such, as you need significant extra instructions to interpret the result.

In fact for BCD it might be better to use a whole extra byte for signed overflow detection. It is a bit clunky though.
User avatar
BigEd
Posts: 11463
Joined: 11 Dec 2008
Location: England
Contact:

Re: Signed addittion/subtraction beyond 8 bits

Post by BigEd »

Dan Moos wrote:
Let me ask this. As soon as I need to represent a number larger than 127, or smaller than -128, do I need to stop using "7 bit + sign bit" and turn my number into "15 bit + sign bit"?
Yes, if you want to be dealing with signed numbers
Quote:
My , apparently incorrect thinking had been that in order to represent numbers greater than 127 or less than -128, I would have multiple "7 bit plus sign bit" bytes.
Indeed, that's a misapprehension - but useful to see you say it, because it tells us that there's something that needs to be explained.
User avatar
drogon
Posts: 1671
Joined: 14 Feb 2018
Location: Scotland
Contact:

Re: Signed addittion/subtraction beyond 8 bits

Post by drogon »

FWIW: In a recent project I had to implement signed 16-bit arithmetic and decided to check for overflow because I think that's the right thing to do and for the first time in about 45 years of 6502 coding, I checked the overflow bit and used BVS:

Code: Select all

        clc
        lda     var1Lo
        adc     var2Lo
        sta     resLo

        lda     var1Hi
        adc     var2Hi
        sta     resHi
        bvs     overflow
...


overflow:
        lda     #eVALU
        jmp     error
there's no magic to multi-byte arithmetic and you only need to check for overflow on the highest bytes you add (or subtract - I use other means for multiply, divide and mod) but it adds a bit of completeness to it all and it sort of surprises me that it's taken so long for me to use that particular instruction.

Also interesting to note that this code (for a Basic interpreter) checks overflow when things like BCPL, C, etc. don't check at all and just wrap... I wasn't going to bother until I found some code producing odd results and it was overflowing that was the cause.

-Gordon
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
Post Reply