Shop OBEX P1 Docs P2 Docs Learn Events
CALL with passing flags — Parallax Forums

CALL with passing flags

If I do the following PASM2, will it pass the C flag into the #rx routine?

      MODC _SET
      call #rx wc

Comments

  • @ke4pjw said:
    If I do the following PASM2, will it pass the C flag into the #rx routine?

          MODC _SET
          call #rx wc
    

    Sigh, no, that won't work with relative addressing.

  • Normal CALL/RET/RET doesn't touch the flag bits.

  • So CALL will pass the flags to the called routine? Seems to be a lot about it saving the state of the flags and everything in the manual, but it does not say if it passes them or not. I suppose I can test. I really wish I could do JMP/RET in inline PASM.

  • @ke4pjw said:
    So CALL will pass the flags to the called routine? Seems to be a lot about it saving the state of the flags and everything in the manual, but it does not say if it passes them or not.

    All the CALL instructions save the flags, but only RET WCZ actually restores them (and you can generalize this: only instructions with a W* effect suffix will ever change the flag bits)

    I really wish I could do JMP/RET in inline PASM.

    You can. If you couldn't do branches inline ASM would be mighty pointless. Not sure how many stack levels you can use without it messing up (the internal call stack just drops the oldest value on overflow). Not sure if CALLA/RETA work (i.e. PTRA is pointed at the spin stack on inline asm entry).

  • I think it may be a matter of CALL not modifying the flags. I tried this bit of code and it did work.

    pub call_test(count, tix)
    
      org
    .loop           modc      _clr                          wc              ' LED on
                    call      #.set_led
                    modc      _set                          wc
                    call      #.set_led
                    djnz      count, #.loop
                    jmp       #.done  
    
    .set_led        drvc      #56
        _ret_       waitx     tix
    
    .done
      end
    
  • JonnyMacJonnyMac Posts: 9,104
    edited 2022-02-01 19:06

    This version seems to suggest that the flags are not saved and restored with call and ret. The set_led code clears C which causes the P57 LED to go on and stay on after the first call to set_led.

    pub call_test(count, tix)
    
      org
    .loop           modc      _clr                          wc              ' LED on
                    call      #.set_led
                    drvc      #57
                    modc      _set                          wc
                    call      #.set_led
                    drvc      #57
                    djnz      count, #.loop
                    jmp       #.done  
    
    .set_led        drvc      #56
                    waitx     tix
                    modc      _clr                          wc
                    ret
    
    .done
      end
    
  • @Wuerfel_21 said:
    All the CALL instructions save the flags, but only RET WCZ actually restores them (and you can generalize this: only instructions with a W* effect suffix will ever change the flag bits)

    >
    Yeah, I am having trouble understanding what that means. If I have C set, perform a CALL, does the C flag persist into the routine?

    @Wuerfel_21 said:

    I really wish I could do JMP/RET in inline PASM.

    You can. If you couldn't do branches inline ASM would be mighty pointless. Not sure how many stack levels you can use without it messing up (the internal call stack just drops the oldest value on overflow). Not sure if CALLA/RETA work (i.e. PTRA is pointed at the spin stack on inline asm entry).

    When using RET with inline PASM, it will immediately return from the whole PUB. You must use CALL to execute a routine with a RET. It sets up another stack, etc. I think it can be called 4 or 5 deep. I am not wanting to do recursion though. I just wanted to jump to another routine and return to the JMP.

    Bah. I think I just need to nuke what I was attempting to do and start over from scratch. Too many gotchas at this point for me to keep track of.

  • @ke4pjw said:

    @Wuerfel_21 said:
    All the CALL instructions save the flags, but only RET WCZ actually restores them (and you can generalize this: only instructions with a W* effect suffix will ever change the flag bits)

    >
    Yeah, I am having trouble understanding what that means. If I have C set, perform a CALL, does the C flag persist into the routine?

    Yes. As said, only instructions with a WC/WZ/WCZ effect will change the flag bits.

  • JonnyMacJonnyMac Posts: 9,104
    edited 2022-02-01 19:35

    Yeah, I am having trouble understanding what that means. If I have C set, perform a CALL, does the C flag persist into the routine?

    My simple little LED blinker demonstrates that it does.

    @Wuerfel_21 said:
    All the CALL instructions save the flags, but only RET WCZ actually restores them (and you can generalize this: only instructions with a W* effect suffix will ever change the flag bits)

    I missed that. I added wcz to the ret line in the set_led routine and the behavior is as expected with save/restore.

  • @JonnyMac said:
    This version seems to suggest that the flags are not saved and restored with call and ret. The set_led code clears C which causes the P57 LED to go on and stay on after the first call to set_led.

    The PASM manual I printed a few weeks ago says that RET can "optionally restore the C and Z flag state as it was prior."

    So it sounds like the C or Z does get passed into the CALLed routine, but cannot be passed back out.

  • JonnyMacJonnyMac Posts: 9,104
    edited 2022-02-01 21:27

    The PASM manual I printed a few weeks ago says that RET can "optionally restore the C and Z flag state as it was prior."
    So it sounds like the C or Z does get passed into the CALLed routine, but cannot be passed back out.

    As Ada pointed out, you must add WCZ to the RET at the end of your routine to restore saved flags. This is what the manual means by optionally -- you have the option to add WCZ to RET.

    I verified that with this:

    pub call_test(count, tix)
    
      org
    .loop           modc      _clr                          wc              ' LED on
                    call      #.set_led
                    drvc      #57
                    modc      _set                          wc
                    call      #.set_led
                    drvc      #57
                    djnz      count, #.loop
                    jmp       #.done
    
    .set_led        drvc      #56
                    waitx     tix
                    modc      _clr                          wc
                    ret                                     wcz             ' restore flags
    
    .done
      end
    

    As you can see, the set_led routine always clears C. By adding WCZ to RET the state of C before CALL is restored.

  • evanhevanh Posts: 15,915
    edited 2022-02-01 22:27

    Terry,
    In general, the C and Z flags are left alone unless applying an optional WC, WZ, or WCZ to the instruction. This even applies to something like the RCL instruction. Which, btw, explicitly uses C flag as part of its 33-bit bit-rotation.

    So, that general rule means CALL will leave the flags untouched. What state the flag were in before CALLing will stay the same inside the subroutine. Here's an entry from the instruction spreadsheet:
    CALL D {WC/WZ/WCZ} Call to D by pushing {C, Z, 10'b0, PC[19:0]} onto stack. C = D[31], Z = D[30], PC = D[19:0].

    So, it puts a copy of the flags and program counter onto the stack. But that doesn't change the flags. What can change the flags is if WCZ is specified - note the curly brackets for optional part of instruction.

    The last sentence with C=D[31] shows what will happen if the optional parts are used.

  • The explicit flag writes that are available on the CALL instruction, when performing a CALL to an absolute address, is what threw me off. Also the description of it saving the flags for the RET. Nothing explicitly states flags carry into the CALL routine. I think to most people that is implicit with a JMP, but with a new stack and everything with CALL, it wasn't as obvious.

  • Thanks everyone! Much appreciated!

  • evanhevanh Posts: 15,915

    Oh, a CALL machine instruction is not same as a language based call - Which may introduce some sort of context. With the machine instruction, the stack is still the same stack. Just one new entry added.

Sign In or Register to comment.