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-wThis subtracts X from Y and leaves the result in W. Now look at flags for the compare operations:
Y - X |
C |
Z | test |
---|---|---|---|
|
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:
- 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
- if Y<>X, then the zero flag will not be set.
- 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
- 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
- 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.
- 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 szw == Y Y XOR w == 0 xor w, Y szfr == 0 fr == 0 test fr szw == 0 w == 0 test w szX != 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 sncfr < n -n + fr < 0 mov w, # -n add w, fr sncfr - n < 0
(mov w, #n; use fr < w; if CARRYX start with stc) mov w, #n mov w, fr - w sncfr < w fr - w < 0
( if CARRYX start with stc) mov w, fr - w sncw < 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 scfr >= 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 scw >= 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 scfr1 - 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 scfr > 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 scfr - 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 scfr > 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 skipw > 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 sncfr1 - 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 sncfr <= 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 sncfr - 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 sncfr <= 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 snzw <= fr (use fr >= w) w <= n (not possible; mov temp, w; use fr <= n) n <= X (see X >= n) See also:
- Structured programmind macros (if else repeat while until, etc...) for use with the SX Key Device Programmer and Debugger
- sasmcond.src Optimized conditionals(IsZero,Eq,Lt,LE,IsNotZero,NE,Gt,GE) and structures (IF, ELSEIF, ELSE, ENDIF / REPEAT, WHILE, UNTIL / SELECT CASE) for the new SASM supplied with the new SXKey 2.0
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 true16 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 less16 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 greaterAlso:
- 16bit signed comparisons in SX/B and asm by Perter Verkaik
- SX Microcontroller Bit Math Method Testing bits in W
Interested: