6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun May 12, 2024 1:00 am

All times are UTC




Post new topic Reply to topic  [ 17 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Sat Sep 30, 2023 8:47 pm 
Offline

Joined: Sat Mar 11, 2017 1:56 am
Posts: 276
Location: Lynden, WA
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 ?


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 30, 2023 9:47 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8433
Location: Southern California
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?


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 30, 2023 10:19 pm 
Offline

Joined: Sat Mar 11, 2017 1:56 am
Posts: 276
Location: Lynden, WA
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?


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 30, 2023 11:40 pm 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
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.


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 30, 2023 11:53 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8433
Location: Southern California
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?


Top
 Profile  
Reply with quote  
PostPosted: Sun Oct 01, 2023 2:09 am 
Offline

Joined: Sat Mar 11, 2017 1:56 am
Posts: 276
Location: Lynden, WA
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.


Top
 Profile  
Reply with quote  
PostPosted: Sun Oct 01, 2023 3:59 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8433
Location: Southern California
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?


Top
 Profile  
Reply with quote  
PostPosted: Sun Oct 01, 2023 5:07 am 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
Going back to the worked example:
Code:
; 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.

Top
 Profile  
Reply with quote  
PostPosted: Sun Oct 01, 2023 5:29 am 
Offline

Joined: Mon Jan 19, 2004 12:49 pm
Posts: 684
Location: Potsdam, DE
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


Top
 Profile  
Reply with quote  
PostPosted: Sun Oct 01, 2023 5:58 am 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
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.


Top
 Profile  
Reply with quote  
PostPosted: Sun Oct 01, 2023 8:56 am 
Offline

Joined: Mon Jan 19, 2004 12:49 pm
Posts: 684
Location: Potsdam, DE
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


Top
 Profile  
Reply with quote  
PostPosted: Sun Oct 01, 2023 9:27 am 
Offline

Joined: Tue Sep 03, 2002 12:58 pm
Posts: 298
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.


Top
 Profile  
Reply with quote  
PostPosted: Sun Oct 01, 2023 10:04 am 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
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.


Top
 Profile  
Reply with quote  
PostPosted: Sun Oct 01, 2023 12:20 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10800
Location: England
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.


Top
 Profile  
Reply with quote  
PostPosted: Thu Oct 05, 2023 7:49 am 
Offline
User avatar

Joined: Wed Feb 14, 2018 2:33 pm
Posts: 1411
Location: Scotland
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:
        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/


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 17 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 7 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: