Page 1 of 1

CMP Instruction

Posted: Thu Jun 03, 2004 5:02 pm
by andrewem
Hi,

I've been reading up on the CMP instruction (CMP and SBC are the only two that are giving me any grief) and I found some really good information on this web site, and I was doing well until a question poped into my head.

It says on tutorials/compare_beyond.html that "both [CMP and SBC] affect the N, Z, and C flags in exactly the same way".

Given this information I took the source code for my emulated SBC instruction and poped into my CMP instruction (ignoring the carry, not modifying the registers, and ignoring the BCD handling) and the results are NOT the same. Obviously something is wrong.

However, if I take the table (showing how the flags are set) listed on tutorials/compare_instructions.html and implement that in my CMP instruction and not do any subtracting etc. the instruction works perfect.

Am I missing something?

Any clarification on these two instructions would make me so happy... :?

Thanks,

Andrew :?

Posted: Thu Jun 03, 2004 5:45 pm
by BitWise
Computers compare numbers by subtracting one value from the other and looking at result. Thats why CMP and SBC set the flags the same way.

For example if you subtract to equal values the result will be zero and would set the 6502's zero flag. If the values are unequal the result would be non zero. If you subtract a big unsigned value from a small one you generate a 'borrow' which clears the carry flag. Subtracting a small unsigned value from a larger (or equal sized) one does not generate a 'borrow' so the carry would be set.

(I won't complicate this discussion with signed values and overflow -- Look them up when you understand unsigned comparison)

There are a couple of key differences between CMP/CPX/CPY and SBC to remember:
  • 1. CMP/CPX/CPY is not affected by the value of the carry flag at point of execution, SBC is. (CMP/CPX/CPY acts as if there is an implied SEC before the subtraction).
  • 2. CMP/CPX/CPY does not keep the result of the subtraction, it is used only to set the flags then it is discarded, SBC does.
What the document is saying is that settings of the flags after a code sequence like this...

Code: Select all

        SEC
        LDA VAL1
        SBC VAL2
... will be exactly the same as after ...

Code: Select all

        LDA VAL1
        CMP VAL2
... but the value of accumlator is different (i.e. in the first case A = VAL1-VAL2 and in the second A = VAL1)

Re: CMP Instruction

Posted: Fri Jun 04, 2004 5:53 am
by dclxvi
andrewem wrote:
It says on tutorials/compare_beyond.html that "both [CMP and SBC] affect the N, Z, and C flags in exactly the same way".
Not quite. It says that CMP and the sequence SEC SBC affect the N, Z, and C flags in the same way. The D flag is assumed to be zero, so really the SBC sequence is CLD SEC SBC. Anyway, you don't have to take my word for it. Here is a program that demonstrates that it is true. Conveniently, it stops at the first counterexample. It takes about 4 seconds (assuming it passes) at 1 MHz. If it doesn't work on the emulator, then the emulator has a bug.

Code: Select all

; Compare N, Z, and C flag results of CMP and SBC
;
; Returns with ERROR = 0 if the test passes, ERROR = 1 if the test fails
;
; Four additional memory locations are used: ERROR, N1, N2, and SNZC
; These may be located anywhere convenient in RAM
;
TEST  CLD       ; just in case
      LDA #1    ; store 1 in ERROR until the test passes
      STA ERROR
      LDA #0    ; initialize N1 and N2
      STA N1
      STA N2
TEST1 LDA N1

      CMP N2    ; compare N2 to N1

      PHP       ; push CMP flags

      SEC       ; subtract N2 from N1
      SBC N2

      PHP       ; store SEC SBC flags in SNZC
      PLA
      STA SNZC
      PLA       ; pull CMP flags
      EOR SNZC
      AND #$83  ; mask N, z, and C flags
      BNE TEST2
      INC N2
      BNE TEST1
      INC N1
      BNE TEST1
      LDA #0    ; the test passes, so store 0 in ERROR
      STA ERROR
TEST2 RTS
I really didn't intend for the tutorial to be an introduction to the CMP instruction. It's more of a compilation of different comparison techniques and optimization tips. The title is "Beyond 8-bit unsigned comparisons" and one section is named "Review of compare instructions', so a familarity with the CMP instruction was assumed.
andrewem wrote:
Given this information I took the source code for my emulated SBC instruction and poped into my CMP instruction (ignoring the carry, not modifying the registers, and ignoring the BCD handling) and the results are NOT the same. Obviously something is wrong.
I can only guess where the problem might be, but when you "ignore" BCD handling, you must subtract as though the D flag is ZERO, and when you "ignore" the carry you must subtract as though it were ONE.

Also, CMP does not affect the V flag, unlike SBC.

Posted: Mon Jun 07, 2004 8:30 pm
by Mats
Well, I run the code of "dclxvi" and got as result "ERROR=0" confirming (as expected) that:


"CMP and SBC affect the N, Z, and C flags in exactly the same way"

as expected.