P2 Instructions TESTB & TESTBN
Cluso99
Posts: 18,069
The instructions TESTB & TESTBN seem to me to give the wrong results for the Z flags
mov lmm_x,#0 testb lmm_x,#0 wz ' nz <<<<< testbn lmm_x,#0 wz ' z <<<<< testb lmm_x,#0 wc ' nc testbn lmm_x,#0 wc ' c and lmm_x,#1 wz ' z mov lmm_x,#1 testb lmm_x,#0 wz ' z <<<<< testbn lmm_x,#0 wz ' nz <<<<< testb lmm_x,#0 wc ' c testbn lmm_x,#0 wc ' nc and lmm_x,#1 wz ' nzAm I missing something or is it a bug?
Comments
Change wasn't mentioned though, broke a lot of code.
Found out the hard way.
IIRC caught garryj out too.
And it seems wrong to me - more like a bug unless someone can recall there being a specific reason to make it appear backwards.
I went back and forth on this and decided to make it so the bit goes into Z without being inverted.
What prompted the change was that there are now flag operators like ANDZ which can quickly confuse things. I figured it was easier to have everyone picture moving bits into/from Z or C, rather than the usual Z semantics, which make things way more complex, in light things like XORZ, DRVZ, etc.
However, IMHO the changes now make it even more confusing rather than simplifying, because it is no longer consistent. Sometimes Z is set to mean zero, and other times it is cleared to mean zero. This is evident as shown in the above example where AND produces the expected result whereas TESTB produces the reverse.
BTW I hadn't realised there are other instructions that implement it reversed too
For 'TEST D,S WZ, Z=1 when result=0. This is the case for all register-level operations.
For the bit tests TESTB/TESTP, the bit/pin goes into or interacts with C/Z. For TESTBN/TESTPN the NOT bit goes into or interacts with C/Z.
How would you like Z handled in these different cases?
As TESTBx/TESTPx can write to either C or Z the two flags must be treated the same. Chip made the right decision.
To avoid any confusion you can always use these conditionals in Pnut. Eezy peezy
To me, TESTP and TESTB families are just the same. They are not a move of the pin/bit, they are a test of that pin/bit and Z is set if the result is "0" in the same way as the TEST instruction which is really an AND with NR.
C in these instances is identical to other instructions that set C for "1" (excluding parity results).
IIRC MOVCZ may be in this category too.
FWIW I got caught when setting Z and C and then doing an IF_C_NE_Z instruction modifier.
So, IMHO it is an unnecessary quirk and it has to go in the tricks and traps list.
Just my 2c.
I was caught out because it was changed (discovered when existing code broke), not because I was confused.
What ozpropdev said
Why would you say the bit instructions are a shift into Z rather than a test and set Z if 0?
Convince me please as I cannot see why it is opposite to all the other instructions that set Z.
I got caught out because it operated in reverse to the other instructions which set Z. To me, it's just plain and simply wrong
For bit instructions, C and Z are just two bitvariables with that names. You can read them from registerbits or portbits and do logical operation with it. It's much harder to do that if one of the bitvariables (Z) has inverted logic level.
C also has many other meanings than Carry, depending on the instruction, why is this a problem for Z ?
By that assumption, then all the other instructions that set Z are wrong too
C is set if the bit=1
Z is set if the bit=0 (ie it IS zero). That is what the Z flag means.
Currently, you test the bit, and if it is zero, then Z is cleared (ie not zero). Next you follow with a conditional instruction based on the flag setting..
testb reg,#0 wz ' Z=SET=1, NZ=0
if_nz xxxx
Now that will be executed if NZ (ie if the bit was zero)
At this time, it's so simple to fix.
I found the use of C and Z on the P1 to be counterintuitive at times.
If you think of them as Condition Flags CF1 and CF2, then the operation being same for bitwise operations makes sense.
Then for multi-bit operations: if the result overflows, set CF1, otherwise clear it; and if all bits are clear, set CF2, otherwise clear it.
It just happens that the flags are named C and Z instead of CF1 and CF2.
-Phil
The problem is that counterintuitive for one person may be intuitive for another. I believe that's what we are seeing here.
I have had to place a special comment in my code to show that Z is set opposite to what is expected.
So, I think I must agree with Cluso here.
C and Z flags should always be set based on the result of the operation, unless the operation (or part of it) is to explicitly set or clear the C/Z flag(s).
Either you need to rename the TESTB and TESTBN instructions to indicated that they explicitly manipulate the C/Z flags differently than expected, or they should set the flags according to the result of the operation.
Doing something else, just because you like it, makes something inconsistent (not just within this chip, but with ALL other chips across MPUs and CPUs).
I don't see how these can be changed without multiplying the confusion. That none of you guys complaining have bothered to address this tells me that you don't have any solution, either.
The problem here is that we've transcended traditional Z-flag simplicity and there's no going back.
EDIT: I note there is already another TEST/TESTN instruction that has different operation. Changing the name might be the best answer alright.