Jump to content
IGNORED

How does the SBC command work?


Recommended Posts

What I know so far - The SBC is, to make things simple, the opposite to ADC, it removes from the accumulator either a specified value or a value at some point in memory.

Now, not only do I not know if that is correct, I also can't seem to use SBC propperly, for if I write SBC#$01, and the accumulator is currently $89, it becomes $87, and not $88.

What's going on?

Thanks!

(sorry for bad english)

Edited by Marcos Moutta
mixed up # and $
Link to comment
Share on other sites

2 hours ago, Marcos Moutta said:

What I know so far - The SBC is, to make things simple, the opposite to ADC, it removes from the accumulator either a specified value or a value at some point in memory.

Now, not only do I not know if that is correct, I also can't seem to use SBC propperly, for if I write SBC#$01, and the accumulator is currently $89, it becomes $87, and not $88.

What's going on?

Thanks!

(sorry for bad english)

 

Both ADC and SBC use the carry flag, except with opposite value.

So, for SBC you generally have the carry flag set first (SEC)

 

  SEC
  LDA #$89
  SBC #1


The above will give you the result you expect.

However, be aware that the 6502 (in general, but not the 6507) also rely on the decimal flag for correct operation of adc/sbc operations. Usually the decimal flag is cleared at the start of every 6502 program so that ADC/SBC are operating in binary as expected.

 

Finally - why have the carry flag at all?  It's so you can do bigger than 8-bit subtracts and adds...

 

  sec
  lda #<$5000
  sbc #<$1500
  sta result
  lda $>$5000
  sbc $>$1500
  sta result+1


in the above, I did a 16 bit subtraction of $5000 - $1500

In the second part (the high bytes) I did not SEC again - because what i wanted was the "carry" result from the first one. It's an overflow of sorts, that affects if we take off an extra one when doing the high bytes. 
Hope this makes sense.


 

 

 

Link to comment
Share on other sites

3 minutes ago, Andrew Davie said:

 

Both ADC and SBC use the carry flag, except with opposite value.

So, for SBC you generally have the carry flag set first (SEC)

 


  SEC
  LDA #$89
  SBC #1


The above will give you the result you expect.

However, be aware that the 6502 (in general, but not the 6507) also rely on the decimal flag for correct operation of adc/sbc operations. Usually the decimal flag is cleared at the start of every 6502 program so that ADC/SBC are operating in binary as expected.

 

Finally - why have the carry flag at all?  It's so you can do bigger than 8-bit subtracts and adds...

 


  sec
  lda #<$5000
  sbc #<$1500
  sta result
  lda $>$5000
  sbc $>$1500
  sta result+1


in the above, I did a 16 bit subtraction of $5000 - $1500

In the second part (the high bytes) I did not SEC again - because what i wanted was the "carry" result from the first one. It's an overflow of sorts, that affects if we take off an extra one when doing the high bytes. 
Hope this makes sense.


 

 

 

So as long as I don't perform any operations that go beyond FF, I don't have to set the carry flag back? Also, what happens to the carry flag if I perform more than one of those? Finally, why are the commands different for ADC and SBC if the flag is the same?

Link to comment
Share on other sites

Just now, Marcos Moutta said:

So as long as I don't perform any operations that go beyond FF, I don't have to set the carry flag back? Also, what happens to the carry flag if I perform more than one of those? Finally, why are the commands different for ADC and SBC if the flag is the same?

 

You should *always* clear the carry before an addition, and *always* set it before a subtraction.
 

Sometimes, you do know for sure what the carry flag value is, and can safely rely on that without doing a SEC or CLC before subtraction/addition. But it can be risky to do if your assumption changes without you realising. Generally, set it or clear it always.

 

They require different values (SEC/CLC) of the carry flag, because that's how binary arithmetic works, basically.  When with an add, if we get an overflow over $FF, then the carry flag is changed to set - and this gives us the +1 for the next higher byte automatically.  Similarly, when with a subtract, if we get an "underflow" we get the carry flag cleared and this gives us the -1 for the next higher byte automaticlaly.

 

  clc
  lda valLO
  adc #1
  sta valLO
  lda valHI
  adc #0
  sta valHI

  

In the above I show adding +1 to a 16-byte "variable" which is in two 8-bit parts, valLO and valHI

In fact, the "normal" way to do this is to define just "VAL" as 2 bytes long, and do this...

 

 clc
 lda val
 adc #1
 sta val
 lda val+1
 adc #0
 sta val+1

I didn't write it like that in the first example, as I didn't want you to get confused as to what "val+1" meant. It's NOT adding one to val. It's referencing the high byte in the 2-byte-long "val" variable.  In other words, the "adc #1" is doing addition. The "lda val+1" is just referencing a memory location and doesn't do any addition at all. That's just for helping the assembler know which memory address you're referencing.

 

 

 



 

 

 

Link to comment
Share on other sites

47 minutes ago, Marcos Moutta said:

So as long as I don't perform any operations that go beyond FF, I don't have to set the carry flag back?

Py65 Monitor

       PC  AC XR YR SP NV-BDIZC
6502: 0000 00 00 00 ff 00110000
.a 1000
$1000  a9 01     LDA #$01    
$1002  c9 00     CMP #$00    
$1004  b0 1a     BCS $1020      
$1006            

       PC  AC XR YR SP NV-BDIZC
6502: 0000 00 00 00 ff 00110000
.a 1020
$1020  69 01     ADC #$01    
$1022  8d 00 20  STA $2000     
$1025            

       PC  AC XR YR SP NV-BDIZC
6502: 0000 00 00 00 ff 00110000
.g 1000

       PC  AC XR YR SP NV-BDIZC
6502: 1025 03 00 00 ff 00110000
.m 2000
2000:  03

You must set or clear carry to be sure ;) 

Edited by zbyti
CMP & Carry Flag
Link to comment
Share on other sites

Quote

The CMP, CPX, and CPY instructions are used for comparisons as their mnemonics suggest. The way they work is that they perform a subtraction. In fact,


    CMP NUM

is very similar to:


    SEC
    SBC NUM

Both affect the N, Z, and C flags in exactly the same way. However, unlike SBC, (a) the CMP subtraction is not affected by the D (decimal) flag, (b) the accumulator is not affected by a CMP, and (c) the V flag is not affected by a CMP. A useful property of CMP is that it performs an equality comparison and an unsigned comparison. After a CMP, the Z flag contains the equality comparison result and the C flag contains the unsigned comparison result, specifically:

  • If the Z flag is 0, then A <> NUM and BNE will branch
  • If the Z flag is 1, then A = NUM and BEQ will branch
  • If the C flag is 0, then A (unsigned) < NUM (unsigned) and BCC will branch
  • If the C flag is 1, then A (unsigned) >= NUM (unsigned) and BCS will branch

In fact, many 6502 assemblers will allow BLT (Branch on Less Than) and BGE (Branch on Greater than or Equal) to be used as synonyms for BCC and BCS, respectively.

The N flag contains most significant bit of the of the subtraction result. This is only occasionally useful. However, it is NOT the signed comparison result, as is sometimes claimed, as the following examples illustrate:

After:


    LDA #$01 ;  1 (signed),   1 (unsigned)
    CMP #$FF ; -1 (signed), 255 (unsigned)

A = $01, C = 0, N = 0 (the subtraction result is $01 - $FF = $02), and Z = 0. The comparison results are:

  • Equality comparison: false, since $01 <> $FF
  • Signed comparison: 1 >= -1
  • Unsigned comparison: 1 < 255

After:


    LDA #$7F ;  127 (signed), 127 (unsigned)
    CMP #$80 ; -128 (signed), 128 (unsigned)

A = $7F, C = 0, N = 1 (the subtraction result is $7F - $80 = $FF), and Z = 0. The comparison results are:

  • Equality comparison: false, since $7F <> $80
  • Signed comparison: 127 >= -128
  • Unsigned comparison: 127 < 128

Notice that in both cases the signed comparison result is the same (the first number is greater than or equal to the second), but the N flag is different.

The CPX and CPY instructions are exactly like the CMP instruction, except that they use the X and Y registers, respectively, instead of the accumulator.

http://www.6502.org/tutorials/compare_beyond.html

Edited by zbyti
link
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...