Shop OBEX P1 Docs P2 Docs Learn Events
POP's setting of C and Z flags, I'd like it changed. Anyone use it? — Parallax Forums

POP's setting of C and Z flags, I'd like it changed. Anyone use it?

evanhevanh Posts: 15,126
edited 2018-10-14 04:55 in Propeller 2
In the early days PUSH and POP for the small hardware stack was built around just storing addresses only. But it also saved and optionally restored the C and Z condition code flags.

About a year back, I think, that was changed to PUSHing an ordinary full 32 bits - no flag bits. And POP restores 32 bits, but with optionally the top two bits still replacing C and Z. It seems to be something of a leftover. I have my doubts as to whether anyone even wants that as a feature. Is condition flag setting via this method in use?

I'd like to have POP set the Z flag to indicate the popped value as being zero or not. EDIT: Looking at POPA/B instructions. Make it the same as those would be perfect.

«1

Comments

  • evanhevanh Posts: 15,126
    Rather crazily, I've already got a better solution. That was short lived. :)

    It does still seem a slight oddity. Is this something worth straightening out anyway?

  • cgraceycgracey Posts: 14,133
    It is intended as a way to restore flags on RET.
  • evanhevanh Posts: 15,126
    Yeah, but it's still an oddball. No worries though.

  • evanhevanh Posts: 15,126
    edited 2018-10-14 07:27
    Actually, no, pushing and popping don't do that. All the CALLx/RETx instructions still have the original flag handling as you've indicated. That works fine. Push and pop are not call and return though.

    PUSHA/POPA/PUSHB/POPB handle C and Z as per the maths and logic instructions do. PUSH is the same.

    POP is the odd one out.

  • RaymanRayman Posts: 13,797
    Looks like the RCZL instruction is meant for this...

    But, still need to clear top two bits. Unless it's an address I guess...
  • evanhevanh Posts: 15,126
    The compiler/simulator authors on the forum haven't made any remarks. Given the brazen topic title, I'm inclined to think they're okay with such a small change. And probably agree with it.

  • cgraceycgracey Posts: 14,133
    edited 2018-10-15 03:49
    I think you are right. C needs to equal the MSB and Z needs to indicate 0.

    I will change the Verilog for the respin.

    Thanks for pointing this out. I had been coming from the CALL/RET paradigm and wasn't thinking about PUSH/POP normally.
  • jmgjmg Posts: 15,140
    evanh wrote: »
    Actually, no, pushing and popping don't do that. All the CALLx/RETx instructions still have the original flag handling as you've indicated. That works fine. Push and pop are not call and return though.

    PUSHA/POPA/PUSHB/POPB handle C and Z as per the maths and logic instructions do. PUSH is the same.

    POP is the odd one out.

    'odd one out' is never a good thing.
    Unless there is a compelling use case, it seems simpler to make all behave the same.


    cgracey wrote: »
    I think you are right. C needs to equal the MSB and Z needs to indicate 0.

    I will change the Verilog for the respin.

    Thanks for pointing this out. I had been coming from the CALL/RET paradigm and wasn't thinking about PUSH/POP normally.

    So that makes all POPs the same ?
    and {WC/WZ/WCZ} control if the POP actually does modify C,Z ?
  • cgraceycgracey Posts: 14,133
    jmg wrote: »
    evanh wrote: »
    Actually, no, pushing and popping don't do that. All the CALLx/RETx instructions still have the original flag handling as you've indicated. That works fine. Push and pop are not call and return though.

    PUSHA/POPA/PUSHB/POPB handle C and Z as per the maths and logic instructions do. PUSH is the same.

    POP is the odd one out.

    'odd one out' is never a good thing.
    Unless there is a compelling use case, it seems simpler to make all behave the same.


    cgracey wrote: »
    I think you are right. C needs to equal the MSB and Z needs to indicate 0.

    I will change the Verilog for the respin.

    Thanks for pointing this out. I had been coming from the CALL/RET paradigm and wasn't thinking about PUSH/POP normally.

    So that makes all POPs the same ?
    and {WC/WZ/WCZ} control if the POP actually does modify C,Z ?

    Correct.
  • evanhevanh Posts: 15,126
    Thanks Chip.

    Confirmation regarding the various RETx instructions, I note they have optional setting of C/Z flags. Does that mean flag restoring from stack is optional?

  • evanhevanh Posts: 15,126
    edited 2018-10-15 04:18
    As in
    RET    wcz
    
    would be required to make it preserve the flags across a call. (I strongly suspect a yes)

    EDIT: What about the _RET_ case?

  • cgraceycgracey Posts: 14,133
    edited 2018-10-15 04:36
    evanh wrote: »
    As in
    RET    wcz
    
    would be required to make it preserve the flags across a call. (I strongly suspect a yes)

    EDIT: What about the _RET_ case?

    Correct for 'RET WCZ'

    _RET_ affects C/Z per the associated instruction's rules.
  • cgraceycgracey Posts: 14,133
    evanh wrote: »
    Thanks Chip.

    Confirmation regarding the various RETx instructions, I note they have optional setting of C/Z flags. Does that mean flag restoring from stack is optional?

    Yes, you can effectively preserve C and/or Z through a CALL by ending the called routine with 'RET WC/WZ/WCZ'.
  • evanhevanh Posts: 15,126
    cgracey wrote: »
    _RET_ affects C/Z per the instruction's rules.
    _RET_         <inst>  <ops>	Execute <inst> always and return if no branch. If <inst> is not branching then return by popping stack[19:0] into PC.
    

    No flags mentioned so not preserved. :( I like the flag preservation.

  • jmgjmg Posts: 15,140
    edited 2018-10-15 04:44
    cgracey wrote: »
    evanh wrote: »
    As in
    RET    wcz
    
    would be required to make it preserve the flags across a call. (I strongly suspect a yes)

    EDIT: What about the _RET_ case?

    Correct for 'RET WCZ'

    That reads somewhat counter-intuitively.
    In all other cases, WCZ takes what could be the current live C/Z values, and updates CZ.

    In the RET case, is it the older values, that were stored on the call, that are placed in CZ.
    If you leave off the WCZ, I presume the current subroutine C/Z values are returned instead.

    Does that need a clearer syntax, like
    RET RCZ for Restore CZ (or PCZ for pop CZ / preserve caller CZ)

    ie that's a semantic change in assembler (alias), for clarity, not a verilog change.
  • evanhevanh Posts: 15,126
    JMG,
    It doesn't look so bad in the formatted source, eg:
    '===============================================
    putch
    '		rqpin   temp1, #tx_pin  wc    'transmiting?  (read Z to see if actively shifting out)
    		testp   #tx_pin         wz    'buffer free?  (IN state shows Y buffer full status)
    'if_nz_and_c	jmp     #putch                'wait while Smartpin is both full (nz) and transmitting (c)
    if_nz		jmp     #putch                'wait while Smartpin is full (nz)
    		wypin   char, #tx_pin         'write new byte to Y buffer
    		ret                     wcz
    
    
  • In some situations I've been using _RET_ and RET with wc/wz/wcz:
    ' /* dstrcmp, dstrncmp
    '------------------------------------------------------------------------------
    ' Compare at most the first n bytes of str1 and str2 (zero terminated).
    '------------------------------------------------------------------------------
    ' On entry: Reg PTRA: str1 pointer.
    '           Reg PTRB: str2 pointer.
    '           Reg lmm_c: maximum characters to compare (dstrncmp).
    ' On exit: Reg dstr_ret1: count of matched characters.
    '          C, Z flags set according to CMPS str1[n], str2[n]:
    '          if_b str1 < str2, if_a str1 > str2, if_e str1 == str2.
    '------------------------------------------------------------------------------
    dstrcmp         mov     lmm_c, ##$-1
    dstrncmp
                    mov     dstr_ret1, #0                   ' Matched character count
    .loop
                    rdbyte  dtx, ptra++
                    rdbyte  drx, ptrb++
                    cmp     dtx, drx                wz
            if_ne   jmp     #.exit                          ' str1[n] != str2[n]?
                    cmp     dtx, #0                 wz
            if_e    jmp     #.exit                          ' If one is zero, both are zero
                    incmod  dstr_ret1, lmm_c        wc
            if_nc   jmp     #.loop                          ' Matched or at length limit?
    .exit
            _ret_   cmps    dtx, drx                wcz
    ' */
    
  • jmgjmg Posts: 15,140
    evanh wrote: »
    No flags mentioned so not preserved. :( I like the flag preservation.

    That then requires the opposite default ?

  • evanhevanh Posts: 15,126
    garryj wrote: »
    In some situations I've been using _RET_ and RET with wc/wz/wcz:
    .exit
            _ret_   cmps    dtx, drx                wcz
    

    I've just tested that idea Garry: CMPS is controlling the flags. _RET_ does nothing to them.

  • jmgjmg Posts: 15,140
    evanh wrote: »
    garryj wrote: »
    In some situations I've been using _RET_ and RET with wc/wz/wcz:
    .exit
            _ret_   cmps    dtx, drx                wcz
    

    I've just tested that idea Garry: CMPS is controlling the flags. _RET_ does nothing to them.

    Because it is common to return boolean function results in C, I think that's the correct operation ?
    - ie function controls C value, and ret does not pop anything.
  • evanhevanh Posts: 15,126
    edited 2018-10-15 06:54
    C language is probably agnostic on exactly how a boolean is returned but I doubt the condition codes are typically used.

    I'm pretty certain, from what Gary has said just now, that his code assumes that _RET_ restores the calling C and Z flags.

    It's funny, I hadn't been relying on preservation of condition codes in any of my code but had wanted it many times on the Propeller simply because conditional execution can so readily make use of such a feature. I've only realised, today, that the option is there at all.

  • jmgjmg Posts: 15,140
    evanh wrote: »
    C language is probably agnostic on exactly how a boolean is returned but I doubt the condition codes are typically used.

    Certainly back before C gained a native boolean type, it was less common, but because MCUs usually have opcodes for directly testing carry, it makes sense to not waste a register returning 1 or 0 - even more so on a 32b MCU with limited memory.

    one example: http://www.keil.com/support/man/docs/c51/c51_ap_funcret.htm

  • evanhevanh Posts: 15,126
    Ha ha, bit-fields work for storage. So that point is mute.

    Code speed upon exit testing would be a point I'd believe. But even there, most non-RISC architectures modify the flags on most opcodes, rapidly negating any speed advantage.

  • TonyB_TonyB_ Posts: 2,105
    edited 2018-10-15 12:49
    evanh wrote: »
    garryj wrote: »
    In some situations I've been using _RET_ and RET with wc/wz/wcz:
    .exit
            _ret_   cmps    dtx, drx                wcz
    

    I've just tested that idea Garry: CMPS is controlling the flags. _RET_ does nothing to them.
    evanh wrote: »
    I'm pretty certain, from what Gary has said just now, that his code assumes that _RET_ restores the calling C and Z flags.

    No, the point that garryj is making is that he wants the flags to be written by the last instruction in a routine and return without the need for a separate RET afterwards that would waste time and code. There is only instruction prefix available for _RET_ and it can't either restore the flags or leave them alone. How it is now is the best option.

    Changing how POP handles the flags would have a detrimental affect in the following situation: if the POP pops a return address then the flags on entry to the routine will be lost. I think it would be good if we had instructions that could read and write the flags on the top of the stack in the TOS register directly and there is spare opcode bit in RCZR/RCZL.
  • evanhevanh Posts: 15,126
    edited 2018-10-15 13:51
    I'll wait for Gary to confirm on his use of _RET_ vs RET. His statement doesn't read like that. It is terse though.

    Tony,
    All popping instructions have optional wcz bit-fields. You only overwrite the flags you want. That doesn't change. The only actual change is the new meaning of Z when POP is setting the condition codes. EDIT: It will be the same as the other POPA/POPB instructions.

  • evanh wrote: »
    C language is probably agnostic on exactly how a boolean is returned but I doubt the condition codes are typically used.

    I'm pretty certain, from what Gary has said just now, that his code assumes that _RET_ restores the calling C and Z flags.

    It's funny, I hadn't been relying on preservation of condition codes in any of my code but had wanted it many times on the Propeller simply because conditional execution can so readily make use of such a feature. I've only realised, today, that the option is there at all.
    @jmg and @TonyB_ described my thinking better than I did. I like using _RET_ mainly because is saves a cycle, with the bonus that you know at a glance that CMPS "owns" the flags.
  • evanhevanh Posts: 15,126
    Okay, thanks for the update.

    I should have tried reading the code I guess. CMPS only make sense as the last instruction when it's meant to set the flags.

    I got POP to a better place though! :)

  • cgraceycgracey Posts: 14,133
    I made the change and tested it:

    POP reg WC/WZ/WCZ

    C = reg[31]
    Z = (reg == 0)

    RET WC/WZ/WCZ

    C = reg[31]
    Z = reg[30]
  • cgracey wrote: »
    I made the change and tested it:

    POP reg WC/WZ/WCZ

    C = reg[31]
    Z = (reg == 0)

    RET WC/WZ/WCZ

    C = reg[31]
    Z = reg[30]

    POPping a return address can give you value of C on entry to a routine, as before, but not entry Z. Just an observation.
  • cgraceycgracey Posts: 14,133
    TonyB_ wrote: »
    cgracey wrote: »
    I made the change and tested it:

    POP reg WC/WZ/WCZ

    C = reg[31]
    Z = (reg == 0)

    RET WC/WZ/WCZ

    C = reg[31]
    Z = reg[30]

    POPping a return address can give you value of C on entry to a routine, as before, but not entry Z. Just an observation.

    You have to do:

    TESTB popped_value,#30 wz
Sign In or Register to comment.