Signed addittion/subtraction beyond 8 bits
Signed addittion/subtraction beyond 8 bits
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 ?
Edit: for instance, how do I do 127+1 ?
- GARTHWILSON
- Forum Moderator
- Posts: 8773
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
Re: Signed addittion/subtraction beyond 8 bits
Dan Moos wrote:
for instance, how do I do 127+1 ?
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?
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
Re: Signed addittion/subtraction beyond 8 bits
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?
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?
Re: Signed addittion/subtraction beyond 8 bits
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.
It's worth reading the pages Garth linked especially regarding the overflow flag.
- GARTHWILSON
- Forum Moderator
- Posts: 8773
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
Re: Signed addittion/subtraction beyond 8 bits
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.
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?
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
Re: Signed addittion/subtraction beyond 8 bits
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.
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.
- GARTHWILSON
- Forum Moderator
- Posts: 8773
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
Re: Signed addittion/subtraction beyond 8 bits
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.
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?
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
Re: Signed addittion/subtraction beyond 8 bits
Going back to the worked example: The above code is intended to be educational, and as such is deliberately unoptimised.
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
Last edited by Chromatix on Sun Oct 01, 2023 5:55 am, edited 1 time in total.
Re: Signed addittion/subtraction beyond 8 bits
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
Neil
Re: Signed addittion/subtraction beyond 8 bits
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.
Re: Signed addittion/subtraction beyond 8 bits
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
Neil
Re: Signed addittion/subtraction beyond 8 bits
Chromatix wrote:
Well, the 6502 doesn't support signed BCD anyway.
33 + -48 -> $33 + $52 = $85 -> -15
The N flag is wrong, but otherwise it seems to work.
Re: Signed addittion/subtraction beyond 8 bits
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.
In fact for BCD it might be better to use a whole extra byte for signed overflow detection. It is a bit clunky though.
Re: Signed addittion/subtraction beyond 8 bits
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"?
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.
Re: Signed addittion/subtraction beyond 8 bits
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:
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
Code: Select all
clc
lda var1Lo
adc var2Lo
sta resLo
lda var1Hi
adc var2Hi
sta resHi
bvs overflow
...
overflow:
lda #eVALU
jmp errorAlso 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/
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/