CMPX/CMPSX Z flag issue — Parallax Forums

# CMPX/CMPSX Z flag issue

Posts: 2,763
edited 2016-06-15 06:41
Chip
I started a seperate thread for this issue highlighted by garri on another thread.
As garryi points out the Z flag is not being set and returns the previous Z state.

Here's another test snippet.
```dat		org

or	dirb, ##\$ffff
mov	outb,#0

setcz	#%01 wc,wz	'set z flag = 1 (z)
cmpx	a,b wz,wc
setbz	outb,#0		'led0 on

setcz	#%00 wc,wz	'set z flag = 0 (nz)
cmpx	a,b wz,wc
setbz	outb,#1		'led1 off, should be on

me		jmp	#me

a		long	3
b		long	3
```

• Posts: 13,588
edited 2016-06-15 07:43
Those instructions are working correctly. They are just not documented, yet.

SUBX
SUBSX
CMPX
CMPSX

In the instructions above, the X means 'extended'. These instructions use the carry as an input and they also AND the old Z flag with what would have been the new Z flag in the non-X instruction versions. These are useful for multi-long additions, subtractions, and comparisons, where you'd like both C and Z to be valid at the end of the operation.

Here is an example where two 64-bit values are compared:
```	cmp	v1+0, v2+0	wc,wz	'compare lower longs
cmpx	v1+1, v2+1	wc,wz	'compare upper longs

'c=1 if v1 < v2
'z=1 if v1 = v2
```
• Posts: 2,763
Thanks Chip

I see now how I got my wires crossed there.
Using the P1 manal as a reference I read the following.
```CMPX

Instruction: Compare two unsigned values plus C.

CMPX Value1, <#> Value2

Result: Optionally, equality and greater/lesser status is written to the Z and C flags.
```
The description of the result led me to believe it operated the same as CMP as the wording is the same.
It's probably at this point in the manual it should mention the Old Z is ANDed with the New Z and not on the next page.

I hear the echo of one of my old lecturer's now "READ the manual!"
<:(

• Posts: 2,763
@garryi
Based on my new found knowledge from the P1 docs, does this give you the result you expect.
Note the CMPX line is preceeded by a SETCZ instruction and the CMPX instruction has it's fields reversed as the comparison is D field aginst S field +C.
```' Test CMPX Z flag not being written as expected.

dat
org

setword	dirb, ##\$ffff, #0	' P123-A9 USER_LED15..0 used for feedback
setword	outb, #0, #0
mov	flag, #0
.status
mov	d, status		' Fetch rx status
setbyte	outb, status, #1	' Show rx status byte on USER_LED15..8
shr	d, #8		wc	' Data byte to d, new byte toggle bit into C
if_c	or	outb, #\$80		' Show state of C on USER_LED7
setcz	#1 wz			' <<< set Z = 1
cmpx	_1,flag		wz	' flag = 0 + C = 1: CMPX flag, #1 -> Z, toggle flag?
' flag = 0 + NC = 0: CPMX flag, #1 -> NZ, flag unchanged?
' flag = 1 + C = 2: CMPX flag, #1 -> NZ, flag unchanged?
' flag = 1 + NC = 1: CMPX flag, #1 -> Z, toggle flag?
if_z	or	outb, #\$40		' Show state of Z on USER_LED6
if_z	xor	flag, #1		' New byte state change, so toggle flag
or	outb, flag		' Show state of flag register
waitx	##60_000_000
setword	outb, #0, #0
notb	status, #7		' Toggle new byte status flag
jmp	#.status

_1		long	1
status		long	\$7784
flag		res	1
d		res	1
```

• Posts: 2,474
edited 2016-06-15 11:59
This reminds me. I need to update the unit tests I had written: https://github.com/Seairth/P2UnitTests. They were for the 2015-10-29 image, so are a little bit out of date. However, for instructions like this, you can still look at the truth table at the end of each unit test. For instance, CMPX contains:
```	'       d           s            cz  r           rcz
tests	long	\$0000_0003, \$0000_0002, %00, \$0000_0003, %00
long	\$0000_0003, \$0000_0002, %10, \$0000_0003, %00
long	\$0000_0003, \$0000_0002, %11, \$0000_0003, %01
long	\$0000_0003, \$0000_0003, %00, \$0000_0003, %00
long	\$0000_0003, \$0000_0003, %01, \$0000_0003, %01
long	\$0000_0003, \$0000_0003, %10, \$0000_0003, %10
long	\$0000_0003, \$0000_0004, %00, \$0000_0003, %10
long	\$0000_0003, \$0000_0004, %10, \$0000_0003, %10
long	\$8000_0000, \$7FFF_FFFF, %00, \$8000_0000, %00
long	\$7FFF_FFFF, \$8000_0000, %00, \$7FFF_FFFF, %10
long	\$FFFF_FFFE, \$FFFF_FFFF, %00, \$FFFF_FFFE, %10
long	\$FFFF_FFFE, \$FFFF_FFFF, %10, \$FFFF_FFFE, %10
long	\$FFFF_FFFE, \$FFFF_FFFE, %00, \$FFFF_FFFE, %00
long	\$FFFF_FFFE, \$FFFF_FFFE, %01, \$FFFF_FFFE, %01
long	\$FFFF_FFFE, \$FFFF_FFFE, %10, \$FFFF_FFFE, %10
long	\$FFFF_FFFE, \$FFFF_FFFD, %00, \$FFFF_FFFE, %00
long	\$FFFF_FFFE, \$FFFF_FFFD, %10, \$FFFF_FFFE, %00
long	\$FFFF_FFFE, \$FFFF_FFFD, %11, \$FFFF_FFFE, %01
```

where D, S, and CZ are initial values, and R and RCZ are the result values.
• Posts: 11,976
edited 2016-06-15 14:18
I tried this USB code snippet in the docs also and it didn't seem to work for me either.

So, maybe docs are wrong or instruction is wrong?
• Posts: 337
Thanks all for the help and education!

I suspected it might be a doc hiccup. In the context of the example, it looked like the P2 CMPX differed from the P1 and my forum searches missed the link to @Seairth's great work.

But since it's much easier to change docs than silicon, I thought it would be prudent to ask