SX Microcontroller Comparison Program Flow Methods

Compare values

Robin Abbott - robin.abbott@dial.pipex.com says:

I find it easier to show the state of the flags in a table, consider:
        mov     W, X
        mov     W, Y-w

This subtracts X from Y and leaves the result in W. Now look at flags for the compare operations:

Y - X

C

Z

test

Y > X

1

0

snc skip snz or swap X and Y, or decrease Y by 1 and use Y >= X

Y >= X

1

?

snc

Y == X

1

1

snz

Y <> X

?

0

sz

Y <= X

?

?

sz sc or swap X and Y, or decrease Y by 1 and use Y < X

Y < X

0

0

sc

James Newton says:

Note that there are only four single bit unique operations:
  1. if Y = X, then the result of the subtraction will be zero and the zero flag ( and the carry flag ) will be set. We need only check for Zero to know that the two values are equal
  2. if Y<>X, then the zero flag will not be set.
  3. If Y < X then an overflow will occur on subtraction of X from Y and the Carry flag will be clear ( as will the Zero flag) so we need only check for no Carry to be certain that Y < X
  4. If Y >= X then the subtraction will not cause an overflow and we need only see that the Carry flag is set to be sure that Y was either more than or equal to X.

Other comparisons can be made by reversing the X and Y values and performing the same, single bit, tests. One alternative is to test more than one flag bit to find the result

  1. If Y > X then the Carry flag will be set but that flag would also be set if they were equal. We must also know that the Zero flag is not set. This is a logical AND of the Carry and Zero flags.
  2. If Y <= X then either the Zero flag (and the Carry flag) will be set (they were equal) or the Carry flag (and the Zero flag) will be cleared (unequal but Y < X). We must make both tests in a logic OR system.

Another way to get the > and <= comparisons is to increase or decrease the value of one of the parameters prior to the subtraction. In the case of a constant, one can simply add or subtract 1. A very subtle trick is to load W with the ones complement value (which is not the same as the negative value see: http://www.geocities.com/SiliconValley/2499/essays.html#TWOS) and then add the other rather than subtracting. This is the equivelent of takeing the negative (twos complement, which is the ones complement plus one), subtracting one and then adding.

Also, note that for the SX processor, the use of the carryx option may require that the carry flag be cleared or set prior to executing any add or subtract and can actually help by increaseing or decreaseing the result, and on any processor, don't forget banking!

This table compiles all the best known methods for makeing different comparisons under various conditions. In each case, truth of condition is indicated by the skip occuring so if you want a conditional jump, when the condition being false should result in a skip of the jump, be sure to reverse the polarity of the skip. I.e. sc <-> snc, sz <-> snz
Compairson Case Method (pick one) Code
X == Y
(Y could be #n or fr)
fr == Y (if not CARRYX) fr - Y == 0
(use fr < Y, change sc to snz)
mov w, Y
mov w, X-w
sz
(if CARRYX) Y XOR fr == 0
(mov w, X; use w == Y)
mov w, X
xor w, Y
sz
w == Y Y XOR w == 0
xor w, Y
sz
fr == 0 fr == 0
test fr
sz
w == 0 w == 0
test w
sz
X != Y (use X == Y, change == to != and snz to sz)
X < Y fr < Y
(Y is fr or n)
fr - Y < 0
(mov w, Y; use fr < w; if CARRYX start with stc)
mov w, Y
mov w, fr - w
snc
fr < n -n + fr < 0
mov w, # -n
add w, fr
snc
fr - n < 0
(mov w, #n; use fr < w; if CARRYX start with stc)
mov w, #n
mov w, fr - w
snc
fr < w fr - w < 0
( if CARRYX start with stc)
mov w, fr - w
snc
w < fr (use fr > w)
w < n (not possible?; mov temp, w; use fr < n)
n < Y (use X > n, change Y to X)
X >= n fr >= Y
(Y is fr or n)
fr - Y >= 0
(mov w, fr; use fr >=w; if CARRYX start with stc)
mov w, Y
mov w, fr-w
sc
fr >= n -n + fr >= 0
( if CARRYX start with clc)
mov w, #-n
add w, fr
sc
(mov w, #n, use fr >= w)
fr >= w fr - w >= 0
( if CARRYX start with stc)
mov w, fr - w
sc
w >= fr (use fr <= w)
w >= n (not possible?; mov temp, w; use fr >= n)
n >= Y (use X <= n, change Y to X)
X > Y fr1 > fr2 fr1 - fr2 > 0
-> fr1 - fr2 >= 1, fr1 - fr2 - 1 >= 0, fr1 - (~fr2+1) - 1 >= 0, ~fr2 + fr1 >= 0
( if CARRYX start with clc)
mov w, /fr2
add w, fr1
sc
fr1 - fr2 > 0, fr1 - fr2 >= 1, fr1 - fr2 - 1 >= 0, fr1 - (fr2+1) >= 0
(mov w, ++fr2; use fr1 >= w; if CARRYX start with stc)
mov w, ++fr2
mov w, fr1 - w
sc
fr > n fr - n > 0
-> fr - n >= 1, fr - n - 1 >= 0, fr - (~n+1) - 1 >= 0, ~n + fr >= 0
(if CARRYX start with clc)
mov w, #~n
add w, fr
sc
fr - n > 0, -> fr - n >= 1, fr - n - 1 >= 0, fr - (n+1) >= 0
(mov w, #(n + 1);use fr >= w; if CARRYX start with stc)
mov w, #(n + 1)
mov w, fr - w
sc
fr > w fr > w, fr >= w + 1, fr - w - 1 >= 0, fr + (~w + 1) - 1 >= 0, ~w + fr >= 0
(if CARRYX start with clc)
not w
add w, fr
sc
(if OPTIONX) ??? fr >= w + 1, fr - (w + 1) >= 0
(if optionx; clrb option.rtw, inc 1, use fr >= w;endif; if CARRYX start with stc)
clrb option.rtw
inc 1
mov w, fr - w
sc
(if CARRYX) ???? fr > w, fr >= w + 1, fr - w - 1 >= 0
(if carryx; clc; use fr >= w; endif)
clc
mov w, fr - w ; - ~C
sc
(if not CARRYX)?
mov w, fr - w
sc
snz
skip
w > fr (use fr < w )

      
w > n (not possible; mov temp,w; use fr > n)
n > Y (see X < n, change Y to X)
X <= Y fr1 <= fr2 fr1 - fr2 <= 0
-> fr1 - fr2 < 1, fr1 - fr2 - 1 < 0, fr1 - (~fr2+1) - 1 < 0, ~fr2 + fr1 < 0
(if CARRYX start with clc)
mov w, /fr2
add w, fr1
snc
fr1 - fr2 <= 0, fr1 - fr2 < 1, fr1 - fr2 - 1 < 0, fr1 - (fr2+1) < 0
(mov w, ++fr2; use fr1 < w; if CARRYX start with stc)
mov w, ++fr2
mov w, fr1 - w
snc
fr <= n fr - n <= 0
-> fr - n < 1, fr - n - 1 < 0, fr  + (~n+1) -1 < 0, ~n + fr < 0
(if CARRYX start with clc)
mov w, #~n
add w, fr
snc
fr - n <= 0, fr - n < 1, fr - n - 1 < 0, fr - (n + 1) < 0
(mov w, #(n + 1); use fr < w; if CARRYX start with stc)
mov w, #(n + 1)
mov w, fr - w
snc
fr <= w fr < w + 1, fr - w - 1 < 0,  fr + (~w + 1) - 1, ~w + fr < 0
(if CARRYX start with clc)
not w
add w, fr
snc
(if OPTIONX) ??? fr < w + 1, fr - (w + 1) < 0
(if optionx; clrb option.rtw, inc 1, use fr < w;endif; if CARRYX start with stc)
clrb option.rtw
inc 1
mov w, fr - w
snc
(if CARRYX) ???? w - fr <= 0, w - fr < 1, w - fr - 1 < 0
(if carryx;clc;use fr < w;endif)
clc
mov w, fr - w ; - ~c
snc
(if not CARRYX)?
mov w, fr - w
sc
snz
w <= fr (use fr >= w)

      
w <= n (not possible; mov temp, w; use fr <= n)
n <= X (see X >= n)

See also:

Tony Nixon says

Just a few code snippets I discovered in the last two weeks while writing some new software.

{ed: these have been extensivly rewritten by Nikolai Golovchenko with input from Scott Dattalo}

;if RAMx == Y
	mov	W, #0-Y
	add	W, RAMx
	snb	Z	;aka snz
	jmp	True

;if RAMx <> Y
	mov	W, #0-Y
	add	W, RAMx
	sb	Z	;aka sz
	jmp	True

;if RAMx <= Y
	mov     W, #255-Y
	add     W, RAMx
	sb      C
	jmp     True

;if RAMx > Y
	mov     W, #255-Y
	add     W, RAMx
	snb     C
	jmp     True

;if RAMx < Y
	mov     W, #-Y	;Note: Y should be greater then zero.
	add     W, RAMx
	sb      C
	jmp     True

;if RAMx >= Y
	mov     W, #-Y	;Note: Y should be greater then zero.
	add     W, RAMx
	snb     C
	jmp     True

Just following on from the previous snippets, in an effort to make comparisons easier to understand, here are some more. The best part is, the Z flag is ignored.

;if RAMx > RAMy
        mov     W, /RAMy        ;w = 255 - RAMy
        add     W, RAMx
        snb     C
        jmp     true

;if RAMx <= RAMy
        mov     W, /RAMy
        add     W, RAMx
        sb      C
        jmp     true

;if RAMx < RAMy
        mov     W, /RAMx        ;w = 255 - RAMx
        add     W, RAMy
        snb     C
        jmp     true

;if RAMx >= RAMy
        mov     W, /RAMx
        add     W, RAMy
        sb      C
        jmp     true


16 BIT VALUES

16 Bit comparisons are based on 16 bit substraction. But result of substraction isn't written to file registers. Note that these comparison routines can be extended to any length of data.

;RAM > X / RAM <= X
	;substract lower bytes
        mov     W, #(X + 1) & $FF      ;w = lower byte of (x + 1)
        mov     W, RAML-W
	;substract higher bytes with carry propagation
        mov     W, #(X + 1) >> 8        ;w = higher byte of (x + 1)
        sb      C                       ;skip if no borrow
         incsz  WREG                    ;increment accumulator and skip if zero
          mov   W, RAMH-W               
	;check flags
        snb     C
        jmp     greater
        jmp     less_or_equal

;RAM < X / RAM >= X
	;substract lower bytes
        mov     W, #X & $FF            ;w = lower byte of X
        mov     W, RAML-W
        mov     W, #X >> 8              ;w = higher byte of X
	;substract higher bytes with carry propagation
        sb      C                       ;skip if no borrow      
         incsz  WREG                    ;increment accumulator and skip if zero
          mov   W, RAMH-W
	;check flags
        snb     C
        jmp     greater_or_equal
        jmp     less

16 bit registers comparisons

;RAMY < RAMX / RAMY >= RAMX
        mov     W, RAMXL
        mov     W, RAMYL-W

        mov     W, RAMXH
        sb      C               ;skip if no borrow
         movsz  W, ++RAMXH
          mov   W, RAMYH-W

        snb     C
        jmp     greater_or_equal
        jmp     less

;RAMY > RAMX / RAMY <= RAMX
        mov     W, RAMYL
        mov     W, RAMXL-W

        mov     W, RAMYH
        sb      C               ;skip if no borrow
         movsz  W, ++RAMYH
          mov   W, RAMXH-W

        snb     C
        jmp     less_or_equal
        jmp     greater

Also:

Interested: