Page 1 of 2

comparing 16 bit numbers

Posted: Sun May 17, 2020 10:15 pm
by Dan Moos
On a vanilla 65c02, what is the best way to compare 2 16 bit numbers? Specifically trying to check which of two addresses are larger.

Do i just do a normal subtraction, and watch the carry/zero flags, or is there a slicker way?

I mostly ask because whenever I do something, I invariably later see a method that is both better, and embarrassingly obvious. :roll:

Re: comparing 16 bit numbers

Posted: Sun May 17, 2020 11:40 pm
by BigDumbDinosaur
Dan Moos wrote:
On a vanilla 65c02, what is the best way to compare 2 16 bit numbers? Specifically trying to check which of two addresses are larger.

Do i just do a normal subtraction, and watch the carry/zero flags, or is there a slicker way?

I mostly ask because whenever I do something, I invariably later see a method that is both better, and embarrassingly obvious. :roll:
Here's how I would do it:

Code: Select all

;16-bit number comparison...
;
         lda #>x               ;MSB of 1st number
         cmp #>y               ;MSB of 2nd number
         bcc islower           ;X < Y
;
         bne ishigher          ;X > Y
;
         lda #<x               ;LSB of 1st number
         cmp #<y               ;LSB of 2nd number
         bcc islower           ;X < Y
;
         beq issame            ;X = Y
;
         bne ishigher          ;X > Y

Re: comparing 16 bit numbers

Posted: Mon May 18, 2020 12:11 am
by Dan Moos
Thanks.

The branch instructions, especially in these cases still tie my brain in a knot. I know what they do, I know how they work , ect. But I still sorta "lose the ball" sometimes.

Re: comparing 16 bit numbers

Posted: Mon May 18, 2020 12:23 am
by BillG
I just happen to be working on code like that right now...

Code: Select all

        lda     I+1
        cmp     J+1
        bne     Decide
        lda     I
        cmp     J
Decide  blo     Lower
blo is an alias for bcc.

Re: comparing 16 bit numbers

Posted: Mon May 18, 2020 12:59 am
by Chromatix
The general pattern of multi-byte compares is:

1: Compare the most-significant bytes first, using either the signed or unsigned comparison rule as appropriate. If they are unequal, they determine the overall result.

2: Otherwise, continue to less significant bytes in turn, until you find a pair that is unequal or you run out of bytes. These comparisons should always use the unsigned comparison rule, even on signed values.

3: If you run out of bytes before finding any that differ, the overall result is that the values are equal.

For comparing multi-byte unsigned values, I prefer the following construction:

Code: Select all

  LDA x+1
  CMP y+1
  BNE :+
  LDA x+0
  CMP y+0
: BCC lower
  BNE higher
  BEQ same

Re: comparing 16 bit numbers

Posted: Mon May 18, 2020 1:48 am
by teamtempest
The approaches described so far all work fine, but if you're more concerned about small size than fastest average execution:

Code: Select all

         lda addr0
         cmp addr1
         lda addr0+1
         sbc addr1+1
         bcc  addr1IsBigger
         bne addr0IsBigger
         ; else equal...

Re: comparing 16 bit numbers

Posted: Mon May 18, 2020 6:02 am
by BigEd
There's an article by Bruce Clark:
Beyond 8-bit Unsigned Comparisons by Bruce Clark

Re: comparing 16 bit numbers

Posted: Mon May 18, 2020 6:47 am
by drogon
Might be worth noting that some assemblers have aliases either built-in or via macros for the branch instructions, so:

Code: Select all

BLT -> BCC ; Branch if Less Than
BGE -> BCS ; Branch if Greater than Equal
Or just do what I did for a while and write them on a post-it on the side of my screen..

-Gordon

Re: comparing 16 bit numbers

Posted: Mon May 18, 2020 7:03 am
by unclouded
drogon wrote:
BLT -> BCC ; Branch if Less Than
Every single time I see "BLT" I think of Bacon, Lettuce and Tomato.

Re: comparing 16 bit numbers

Posted: Mon May 18, 2020 7:49 am
by Chromatix
"Yeah, my BLT drive just went AWOL, and I've got this big project due tomorrow for Mr. Kawasaki, and if I don't have it in he's going to make me commit harakiri - you know these new Japanese management techniques."

Re: comparing 16 bit numbers

Posted: Mon May 18, 2020 3:14 pm
by barrym95838
Motorola's convention is to use BLO for unsigned and BLT for signed, so BillG has it right, by at least one definition of "right".

Re: comparing 16 bit numbers

Posted: Tue May 25, 2021 4:11 pm
by watermelon
The AVR202 [1] explains the implementation of 16-bit arithmetic in the Assembler language of the 8-bit AVR microcontroller: Simple subroutines extendable to 32 bits or any data word length. Code density and processing speed are comparable with 16-bit microcontrollers. There is a running example code. According to the following algorithm, the operation is performed: The least significant bytes of the words are added. Then the high bytes of the terms are added, taking into account the carry. There are so many numbers in my life, just recently I was haunted by the number 111, I just saw it everywhere! Then I read about its meaning at https://www.zodiacsigns-horoscope.com/a ... 1-meaning/, and now I give even more importance to numbers.

Re: comparing 16 bit numbers

Posted: Tue May 25, 2021 4:21 pm
by BigEd
(welcome, watermelon. I think you meant to link to this AVR application note)

Re: comparing 16 bit numbers

Posted: Tue May 25, 2021 6:51 pm
by BB8
teamtempest wrote:
The approaches described so far all work fine, but if you're more concerned about small size than fastest average execution:

Code: Select all

         lda addr0
         cmp addr1
         lda addr0+1
         sbc addr1+1
         bcc  addr1IsBigger
         bne addr0IsBigger
         ; else equal...
The "; else equal..." part is wrong.
Let's take the two values $6502 and $6501 (so, in little endian: 02 65 01 65). The first compare will be 02-01, which will give a set Carry flag (and an unset Zero flag). The second operation will take the Carry and subtract 65 from 65. This will produce a set Zero flag (and a set Carry flag). The Zero flag will reflect only the equality of the high bytes.
The "bne addr0IsBigger" is technically correct, but what flows through could still be Greater [or Equal].
When you use SBC to do a multibyte compare, you have to check the equality separately.

Code: Select all

         lda addr0
         cmp addr1
         lda addr0+1
         sbc addr1+1
         bcc  addr1IsBigger
         ;addr0IsGreaterOrEqual

Re: comparing 16 bit numbers

Posted: Sun Feb 27, 2022 7:47 pm
by speculatrix
I've read the above and the tutorial, but would appreciate a sanity check on a general-purpose routine for comparing 32-bit numbers. Does this made sense?

Code: Select all

; Compare two 32-bit values

NUMA = $4000    ; LSB for NUMA. Other bytes in NUMA+1, NUMA+2, NUMA+3
NUMB = $4004    ; like above

.compare_32bit
  lda NUMA+3
  cmp NUMB+3
  bcc less_than      ; NUMA < NUMB
  bne more_than      ; if NUMA+3 <> NUMB+3 then NUMA > NUMB 
  lda NUMA+2
  cmp NUMB+2
  bcc less_than
  bne more_than
  lda NUMA+1
  cmp NUMB+1
  bcc less_than
  bne more_than
  lda NUMA
  cmp NUMB
  bcc less_than
  bne more_than
.equal
  ; stuff
.less_than
  ; stuff
.more_than
  ; stuff
rts