Shop OBEX P1 Docs P2 Docs Learn Events
P2 Instructions TESTB & TESTBN - Page 2 — Parallax Forums

P2 Instructions TESTB & TESTBN

24

Comments

  • Cluso99Cluso99 Posts: 18,069
    edited 2018-12-09 10:43
    cgracey wrote: »
    How would you like Z handled in these different cases?
    TESTB   {#}D         WZ
    TESTBN  {#}D         WZ
    TESTB   {#}D       ANDZ
    TESTBN  {#}D       ANDZ
    TESTB   {#}D        ORZ
    TESTBN  {#}D        ORZ
    TESTB   {#}D       XORZ
    TESTBN  {#}D       XORZ
    

    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.
    The Z flag is set if the result is zero, and reset (ie NZ) if the result is not zero (1 or anything else), as it is with other instructions.
    That includes AND, OR, TEST, TESTN, MOV, etc.

    Saying that TESTB/TESTBN/TESTP/TESTPN moves the bit into Z is the confusing part. It should be described as testing the bit/pin and Z is set accordingly where Z means ZERO and NZ means NOT-ZERO. Then all following IF_xxx conditions work as expected too.

    IIRC MOVCZ falls into this problem setting Z too ??? (cannot check ATM)

    Chip, until I actually used the TESTB instruction, I had not realised it was not as expected, and my code was not working as expected. I seem to recall being caught before. But really, isn't this what we are supposed to be doing, finding gremlins in the engineering sample chips, where at least they can be fixed.
    Chip, I do hope you are not taking this personally! It's a fantastic P2. I just want it to be the best that it can be.
  • Cluso99Cluso99 Posts: 18,069
    edited 2018-12-09 10:50
    Chip,
    Can you explain the purpose of the MODCZ instruction please? I follow the straight resetting/setting of the C & Z flags, but what I don't follow is the reason (ie use) for using 4 bits for setting each of C & Z.
  • Chip,
    My answer applies to ALL instructions that set/clear the C/Z flags based on ALU operations. The only exception should be instructions that are intended to manipulate the C/Z flags in an explicit way (like one that restores those flags from a saved store).

    Those special ANDZ/ORZ/XORZ things are weird, and don't really belong in the same place as WZ/WC/WCZ. I'm not even sure why they exist, and what they are good for... I assume the operation is for them is to do the TESTB/TESTBN parts and then the result is AND/OR/XOR'd with whatever is in the Z flag already (from the previous instruction(s)). So it's a three operand operation. The "consistent" way to set the flag afterwards, is to set it based on the result of the whole operation. If you want the "result" out then it should go into the D register someplace.

  • Cluso99 wrote: »
    Chip,
    Can you explain the purpose of the MODCZ instruction please? I follow the straight resetting/setting of the C & Z flags, but what I don't follow is the reason (ie use) for using 4 bits for setting each of C & Z.

    See here
    http://forums.parallax.com/discussion/comment/1437740/#Comment_1437740
  • evanhevanh Posts: 15,915
    Cluso99 wrote: »
    Can you explain the purpose of the MODCZ instruction please?
    EEEE 1101011 CZ1 0cccczzzz 001101111	MODCZ   c,z      {WC/WZ/WCZ}	Modify C and Z according to cccc and zzzz. C = cccc[{C,Z}], Z = zzzz[{C,Z}].
    
    [{C,Z}] is a 2-bit index. So that'll be an index into the four operand bits.


  • cgraceycgracey Posts: 14,152
    edited 2018-12-09 12:00
    Roy Eltham wrote: »
    Chip,
    My answer applies to ALL instructions that set/clear the C/Z flags based on ALU operations. The only exception should be instructions that are intended to manipulate the C/Z flags in an explicit way (like one that restores those flags from a saved store).

    Those special ANDZ/ORZ/XORZ things are weird, and don't really belong in the same place as WZ/WC/WCZ. I'm not even sure why they exist, and what they are good for... I assume the operation is for them is to do the TESTB/TESTBN parts and then the result is AND/OR/XOR'd with whatever is in the Z flag already (from the previous instruction(s)). So it's a three operand operation. The "consistent" way to set the flag afterwards, is to set it based on the result of the whole operation. If you want the "result" out then it should go into the D register someplace.

    So, here is what would seem right, maybe:

    TESTB reg,bitindex WZ 'Z=!bit
    TESTB reg,bitindex WC 'C=bit

    TESTBN reg,bitindex WZ 'Z=bit
    TESTBN reg,bitindex WC 'C=!bit

    TESTB reg,bitindex ANDZ 'Z &= bit
    TESTB reg,bitindex ANDC 'C &= bit

    TESTBN reg,bitindex ANDZ 'Z &= !bit
    TESTBN reg,bitindex ANDC 'C &= !bit
  • cgracey wrote: »
    How would you like Z handled in these different cases?
    TESTB   {#}D         WZ
    TESTBN  {#}D         WZ
    TESTB   {#}D       ANDZ
    TESTBN  {#}D       ANDZ
    TESTB   {#}D        ORZ
    TESTBN  {#}D        ORZ
    TESTB   {#}D       XORZ
    TESTBN  {#}D       XORZ
    

    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.

    Yes and it would be far more confusing for Z to be the opposite of C in TESTBx/TESTPx. I think the mnemonics are the only truly confusing thing now and MOVBx/MOVPx would be better.
  • Chip,
    I don't think so.

    The Z flag used in the AND/OR/XOR is what the Z flag was at the start of the instruction. So the flag that was there influences the result, but the result is not written to the flag. The flag is just set if the result is zero, and cleared if it is not zero.
    It's a different instruction really, and would require a S, D slot if you wanted the result written someplace.

    These instructions are intending to be operations with/on the Z or C flags, and are oddball. Normally, the ONLY way to manipulate the Z or C flags is by having a result of an operation set them accordingly, but by directly doing logic operations on them. You are doing something non-standard.

    I think the only solution that keeps the functionality you want is to name the instructions differently, so that they are explicitly operations on the flags. Calling them TESTB and TESTBN implies that they will set the flags like any other TEST would.
    Perhaps this?

    ANDZ reg, bitindex 'Z &= bit
    ANDZN reg, bitindex 'Z &= !bit

    ANDC reg, bitindex 'C &= bit
    ANDCN reg, bitindex 'C &= !bit

    The WZ/WC should be absent in the syntax (but it will still write to the Z or C flag).

    This way it's explicit what it's doing.

    The TESTB reg,bitindex WC 'C = bit should be SETC reg,bitindex, and then the Z variant could be SETZ reg,bitindex (and be the same as SETC, instead of inverted). Again the WZ/WC should be absent in the syntax.

    This will make it more clear what the operations actually are. and I think that makes it less confusing with respect to how the Z/C flags end up being set/cleared.

  • cgracey wrote: »
    Roy Eltham wrote: »
    Chip,
    My answer applies to ALL instructions that set/clear the C/Z flags based on ALU operations. The only exception should be instructions that are intended to manipulate the C/Z flags in an explicit way (like one that restores those flags from a saved store).

    Those special ANDZ/ORZ/XORZ things are weird, and don't really belong in the same place as WZ/WC/WCZ. I'm not even sure why they exist, and what they are good for... I assume the operation is for them is to do the TESTB/TESTBN parts and then the result is AND/OR/XOR'd with whatever is in the Z flag already (from the previous instruction(s)). So it's a three operand operation. The "consistent" way to set the flag afterwards, is to set it based on the result of the whole operation. If you want the "result" out then it should go into the D register someplace.

    So, here is what would seem right, maybe:

    TESTB reg,bitindex WZ 'Z=!bit

    TESTBN reg,bitindex WZ 'Z=bit

    NO! Change the name but keep the operation as it is. Rev A is done and it's too late to complain now.
  • cgraceycgracey Posts: 14,152
    I think a syntax change could be in order, but the instructions are fine.

    ANDZ reg,bit WZ

    ...would be okay, but what about the version that uses what is now TESTBN? How does that get called out?

    t's important to have a suffix showing that a flag is being affected, in any case.
  • evanhevanh Posts: 15,915
    edited 2018-12-09 14:11
    [double post]
  • evanhevanh Posts: 15,915
    cgracey wrote: »
    ANDZ reg,bit WZ
    That's it, add Tony's in:
    BMOVZ
    BANDZ
    BORZ
    BXORZ

    BNMOVZ
    BNANDZ
    BNORZ
    BNXORZ

    PMOVZ
    PANDZ
    PORZ
    PXORZ

    PNMOVZ
    PNANDZ
    PNORZ
    PNXORZ
  • evanhevanh Posts: 15,915
    edited 2018-12-09 14:31
    NMOV could be NOT. And NXOR be XNOR.

    EDIT: So even PNANDCZ fits the 7 character limit. It also means the WCZ part is implicit and shouldn't be an added parameter.

    EDIT2: Or, since that is a huge number of aliases in total, maybe it should be like PNAND reg,bit WCZ

    EDIT3: Hehe, of course your common syntax is ANDN, so that means PANDN reg,bit WCZ

    EDIT4: Oops, I see CZ combo is not an option. It's either C or Z.
  • evanhevanh Posts: 15,915
    BMOV reg,bit WC/WZ
    BAND reg,bit WC/WZ
    BOR reg,bit WC/WZ
    BXOR reg,bit WC/WZ

    BNOT reg,bit WC/WZ
    BANDN reg,bit WC/WZ
    BORN reg,bit WC/WZ
    BXORN reg,bit WC/WZ

    PMOV reg,bit WC/WZ
    PAND reg,bit WC/WZ
    POR reg,bit WC/WZ
    PXOR reg,bit WC/WZ

    PNOT reg,bit WC/WZ
    PANDN reg,bit WC/WZ
    PORN reg,bit WC/WZ
    PXORN reg,bit WC/WZ
  • evanhevanh Posts: 15,915
    Hmm, that breaks what Roy is wanting. Since it is only the D-bit that gets NOTed before ANDing.

    How about:
    CANDB reg,bit
    ZANDB reg,bit
    CANDNB reg,bit
    ZANDNB reg,bit

    CANDP reg,bit
    ZANDP reg,bit
    CANDNP reg,bit
    ZANDNP reg,bit
  • Well, what was mildly confusing to me has just become terribly confusing :confused:
    From a syntax standpoint, I didn't have any problem knowing what to do because to me the "B" and "P" signified singular, so the bit:flag or pin:flag TEST relationship made sense. You just temporarily interpret Z the same as C and you can use the instruction prefix to clarify what's going on:
                    testb   urx, #J_IDLEB           wc      ' Wait for rise of J or K, mutually exclusive
                    testb   urx, #K_RESUMEB         wz
            if_00   jmp     #disconnected                   ' J and K still low, so keep waiting for connect
            if_10   jmp     #.connect_test                  ' J high is FS connect state and K high is LS
            if_01   jmp     #.connect_test
    .se1_test
                    waitx   ##_1ms * 100                    ' J and K high is the illegal SE1 state, so wait and retest
    
    AFAIK, TESTP[N] and TESTB[N] are the only two instruction groups that break the "Z" mold? As was stated earlier, the C flag interpretation means something other than carry depending on instruction context, so why must Z be sacrosanct?
  • garryj wrote: »
    Well, what was mildly confusing to me has just become terribly confusing :confused:
    From a syntax standpoint, I didn't have any problem knowing what to do because to me the "B" and "P" signified singular, so the bit:flag or pin:flag TEST relationship made sense. You just temporarily interpret Z the same as C and you can use the instruction prefix to clarify what's going on:
                    testb   urx, #J_IDLEB           wc      ' Wait for rise of J or K, mutually exclusive
                    testb   urx, #K_RESUMEB         wz
            if_00   jmp     #disconnected                   ' J and K still low, so keep waiting for connect
            if_10   jmp     #.connect_test                  ' J high is FS connect state and K high is LS
            if_01   jmp     #.connect_test
    .se1_test
                    waitx   ##_1ms * 100                    ' J and K high is the illegal SE1 state, so wait and retest
    
    AFAIK, TESTP[N] and TESTB[N] are the only two instruction groups that break the "Z" mold? As was stated earlier, the C flag interpretation means something other than carry depending on instruction context, so why must Z be sacrosanct?

    I agree with Garry on this.
  • I don't think changing the actual instruction coding makes sense since Rev A exists now, but if there is a clearer set of mnemonics that can be used for the instructions, that might make sense to assist assembly language programmers.

    Personally I'd fall on the size of consistency in how Z is treated, it's just want people coming from other assembly languages will expect.
  • TonyB_TonyB_ Posts: 2,178
    edited 2018-12-09 20:33
    I didn't mean to be so blunt earlier. Cluso has a genuine concern about how an instruction called TEST should work, but a name change could take care of that, I think. The bottom line is that people have written code based on how the instructions work now. I've used wc, wz, andc, orc, xorc, xorz. None of it tested yet because I don't have a P2. Quite often in this context the flag to choose will be the one not already in use, so consistency is important vital.
  • Chip,
    I think having the suffix WC/WZ carries the implication that those flags will be set according to the result.
    I also think that having the flag name in the instruction suffices for knowing the flag will be changed by the instruction.

    Here's what I think makes everything clear:
    SETZB  reg,bitindex ' Z = Bit
    SETZNB reg,bitindex ' Z = !Bit
    SETCB  reg,bitindex ' C = Bit
    SETCNB reg,bitindex ' C = !Bit
    ANDZB  reg,bitindex ' Z = Z & Bit
    ANDZNB reg,bitindex ' Z = Z & !Bit
    ANDCB  reg,bitindex ' C = C & Bit
    ANDCNB reg,bitindex ' C = C & !Bit
    ORZB  reg,bitindex ' Z = Z | Bit
    ORZNB reg,bitindex ' Z = Z | !Bit
    ORCB  reg,bitindex ' C = C | Bit
    ORCNB reg,bitindex ' C = C | !Bit
    XORZB  reg,bitindex ' Z = Z ^ Bit
    XORZNB reg,bitindex ' Z = Z ^ !Bit
    XORCB  reg,bitindex ' C = C ^ Bit
    XORCNB reg,bitindex ' C = C ^ !Bit
    
    SETZP  pinindex     ' Z = Pin
    SETZNP pinindex     ' Z = !Pin
    SETCP  pinindex     ' C = Pin
    SETCNP pinindex     ' C = !Pin
    ANDZP  pinindex     ' Z = Z & Pin
    ANDZNP pinindex     ' Z = Z & !Pin
    ANDCP  pinindex     ' C = C & Pin
    ANDCNP pinindex     ' C = C & !Pin
    ORZP  pinindex     ' Z = Z | Pin
    ORZNP pinindex     ' Z = Z | !Pin
    ORCP  pinindex     ' C = C | Pin
    ORCNP pinindex     ' C = C | !Pin
    XORZP  pinindex     ' Z = Z ^ Pin
    XORZNP pinindex     ' Z = Z ^ !Pin
    XORCP  pinindex     ' C = C ^ Pin
    XORCNP pinindex     ' C = C ^ !Pin
    

    These all fit in the same space as the existing TESTB/BN and TESTP/PN space. Just without the WZ/WC/ANDZ/ANDC/ORZ/ORC/XORZ/XORC suffixes (they are indicated by the instruction name instead.
  • garryjgarryj Posts: 337
    edited 2018-12-09 21:04
    How about getting super-simple and create the aliases WA, WB and WAB to use for these outlier instructions and let the doc explain how to interpret them A and B?

    Edit: Roy's suggestion looks good.
  • Roy ElthamRoy Eltham Posts: 3,000
    edited 2018-12-09 20:48
    To be clear, I am saying change the names (compiler/assembler side), not the actual encoding or functionality.

    I think it's vitally important that the suffix WC/WZ not be on these, because that is what implies that the flags will be set according to the value of the result (like the normal logic and test operations).
  • Roy Eltham wrote: »
    Chip,
    I think having the suffix WC/WZ carries the implication that those flags will be set according to the result.
    I also think that having the flag name in the instruction suffices for knowing the flag will be changed by the instruction.

    Here's what I think makes everything clear:
    SETZB  reg,bitindex ' Z = Bit
    SETZNB reg,bitindex ' Z = !Bit
    SETCB  reg,bitindex ' C = Bit
    SETCNB reg,bitindex ' C = !Bit
    ANDZB  reg,bitindex ' Z = Z & Bit
    ANDZNB reg,bitindex ' Z = Z & !Bit
    ANDCB  reg,bitindex ' C = C & Bit
    ANDCNB reg,bitindex ' C = C & !Bit
    ORZB  reg,bitindex ' Z = Z | Bit
    ORZNB reg,bitindex ' Z = Z | !Bit
    ORCB  reg,bitindex ' C = C | Bit
    ORCNB reg,bitindex ' C = C | !Bit
    XORZB  reg,bitindex ' Z = Z ^ Bit
    XORZNB reg,bitindex ' Z = Z ^ !Bit
    XORCB  reg,bitindex ' C = C ^ Bit
    XORCNB reg,bitindex ' C = C ^ !Bit
    
    SETZP  pinindex     ' Z = Pin
    SETZNP pinindex     ' Z = !Pin
    SETCP  pinindex     ' C = Pin
    SETCNP pinindex     ' C = !Pin
    ANDZP  pinindex     ' Z = Z & Pin
    ANDZNP pinindex     ' Z = Z & !Pin
    ANDCP  pinindex     ' C = C & Pin
    ANDCNP pinindex     ' C = C & !Pin
    ORZP  pinindex     ' Z = Z | Pin
    ORZNP pinindex     ' Z = Z | !Pin
    ORCP  pinindex     ' C = C | Pin
    ORCNP pinindex     ' C = C | !Pin
    XORZP  pinindex     ' Z = Z ^ Pin
    XORZNP pinindex     ' Z = Z ^ !Pin
    XORCP  pinindex     ' C = C ^ Pin
    XORCNP pinindex     ' C = C ^ !Pin
    

    These all fit in the same space as the existing TESTB/BN and TESTP/PN space. Just without the WZ/WC/ANDZ/ANDC/ORZ/ORC/XORZ/XORC suffixes (they are indicated by the instruction name instead.

    Change all of those SETs to MOVs and it'll work. If you are going to insist on the semantics of WZ then I'll have to insist on something even more fundamental:
    SET means make 1 and CLEAR means make 0.
  • I'd be ok with the SET*'s being MOV* instead (e.g. SETZB -> MOVZB)
  • Cluso99Cluso99 Posts: 18,069
    edited 2018-12-10 07:59
    The basics of the problem to me, is that Z should be set if the result is ZERO, and C is set if the result is NON-ZERO/PARITY.

    Fundamentally, the Z flag is set to mean a ZERO result, and the C flag is opposite where the C flag is set basically for a NON-ZERO result.

    This is the same for any micro with a Z flag.

    The problem is being driven by thinking that the result is being shifted into the Z flag, instead of the "normal" usage where the Z flag is set as a test of the result. The underlying subtlety is grasping that Z set means ZERO.

    C doesn't have this problem because whether you test the result, or shift it in to the flag, the result is the same.

    C has a RCL/RCR instruction. Fortunately there is no RZL/RZR instruction to confuse things.

    So, to me, Roy's solution does not fix the fundamental issue that Z is opposite to C, and Z always represents a ZERO result.

    Agreed, the ultimate fix can be achieved by swapping/changing the source instruction codes.

    Here is my preference, which is a combo of Roy's suggestion...
    TESTB[N] reg,bitno [WC/WZ/WCZ]
    TESTP[N] pinno     [WC/WZ/WCZ]
    AND/OR/XORB[N] reg,bitno [WC/WZ/WCZ]
    AND/OR/XORP[N] pinno [WC/WZ/WCZ]
    
    where Z is set if the result is ZERO, C is set if the result is NON-ZERO
     And Z is reset if the result is NON-ZERO, C is reset if the result ZERO. 
    
  • CALLs that modify the flags write D[30] or S[30] to Z.
    RCZL writes D[30] to Z.
    RCZR writes D[0] to Z.

    Z does not always mean zero.
  • Cluso if it helps you, just think of all these new instructions as being in a different category being those that manipulate the flag bits directly. In contrast all/most of the other ones that use WZ, WC set the flag bits based on the just computed Result. And of course for any ALU type operations if the result is zero, Z=1. However for this new category of instructions which manipulate flag states themselves, Z is set/clear by basic boolean operations that work on the flag bits and other inputs. It helped me deal with it thinking that way. Removing the WZ from TESTB also helps with this concept a lot.

    I think Roy's names are pretty good with MOV instead of SET.
  • It's all good and well until we start writing some real assembly code as garryj did and then we will see where it can be confusing or awkward. Maybe I might have a problem but then I think I will anyway, the P2 is radically different even from the P1.

    Here is Roy's suggestion tidied up using mov instead of set.
    MOVZB   reg,bitindex     ' Z = Bit
    MOVZNB  reg,bitindex     ' Z = !Bit
    MOVCB   reg,bitindex     ' C = Bit
    MOVCNB  reg,bitindex     ' C = !Bit
    ANDZB   reg,bitindex     ' Z = Z & Bit
    ANDZNB  reg,bitindex     ' Z = Z & !Bit
    ANDCB   reg,bitindex     ' C = C & Bit
    ANDCNB  reg,bitindex     ' C = C & !Bit
    ORZB    reg,bitindex     ' Z = Z | Bit
    ORZNB   reg,bitindex     ' Z = Z | !Bit
    ORCB    reg,bitindex     ' C = C | Bit
    ORCNB   reg,bitindex     ' C = C | !Bit
    XORZB   reg,bitindex     ' Z = Z ^ Bit
    XORZNB  reg,bitindex     ' Z = Z ^ !Bit
    XORCB   reg,bitindex     ' C = C ^ Bit
    XORCNB  reg,bitindex     ' C = C ^ !Bit
    
    MOVZP   pinindex         ' Z = Pin
    MOVZNP  pinindex         ' Z = !Pin
    MOVCP   pinindex         ' C = Pin
    MOVCNP  pinindex         ' C = !Pin
    ANDZP   pinindex         ' Z = Z & Pin
    ANDZNP  pinindex         ' Z = Z & !Pin
    ANDCP   pinindex         ' C = C & Pin
    ANDCNP  pinindex         ' C = C & !Pin
    ORZP    pinindex         ' Z = Z | Pin
    ORZNP   pinindex         ' Z = Z | !Pin
    ORCP    pinindex         ' C = C | Pin
    ORCNP   pinindex         ' C = C | !Pin
    XORZP   pinindex         ' Z = Z ^ Pin
    XORZNP  pinindex         ' Z = Z ^ !Pin
    XORCP   pinindex         ' C = C ^ Pin
    XORCNP  pinindex         ' C = C ^ !Pin
    
  • Cluso,
    I was with you, and still would be if they leave them called TESTB/TESTNB/etc.

    However, these instructions are meant to manipulate the C and Z flags in an explicit way using source bit or pin. I think with the instruction names changed it becomes clear what's happening and the actual functionality doesn't need to change.
    If they were changed to work like you want, then they can't do what they are intended to do, because the whole point of them is to manipulate the C/Z flags directly.
Sign In or Register to comment.