Shop OBEX P1 Docs P2 Docs Learn Events
Direct flag manipulation in assembler (errors noted) — Parallax Forums

Direct flag manipulation in assembler (errors noted)

Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
edited 2010-07-16 05:32 in Propeller 1
Occasionally, it's handy to be able to manipulate the z and c flags directly, without causing other side effects or relying on externally-defined longs. This is often done at the end of a subroutine to return a status or error condition, which the calling program can then check. Herewith is what I came up with for various sets, clears, copies, and complements, plus some saves and restores. Each uses its own instruction as a source of known destination data, which provides the necessary bits for flag manipulation.

set_z         test      $,#0  wz         'Instr = %01100010011111$$$$$$$$$000000000 z = result (instr & 0) == 0
set_nz        test      $,#1  wz         'Instr = %01100010011111$$$$$$$$$000000001 z = result (instr & 1) == 1
set_c         test      $,#1  wc         'Instr = %01100001011111$$$$$$$$$000000001 c = parity (instr & 1) == 1
set_nc        test      $,#0  wc         'Instr = %01100001011111$$$$$$$$$000000000 c = parity (instr & 0) == 0

set_z_c       shr       $,#31 wz,wc,nr   'Instr = %00101011011111$$$$$$$$$000011111 z = result (instr >> 31) == 0, c = instr.0  == 1
set_z_nc      shr       $,#30 wz,wc,nr   'Instr = %00101011011111$$$$$$$$$000011110 z = result (instr >> 30) == 0, c = instr.0 == 0
set_nz_c      shr       $,#1  wz,wc,nr   'Instr = %00101011011111$$$$$$$$$000000001 z = result (instr >> 1) <> 0, c = instr.0  == 1
set_nz_nc     shr       $,#2  wz,wc,nr   'Instr = %00101011011111$$$$$$$$$000000010 z = result (instr >> 2) <> 0, c = instr.0  == 0

[s]mov_z_c       muxnc     $,#1  wz,nr      'Instr = %01110110011111$$$$$$$$$000000001 z = result (nc & instr & 1) == c
mov_z_nc      muxc      $,#1  wz,nr      'Instr = %01110010011111$$$$$$$$$000000001 z = result (c & 1) == nc
mov_c_z       muxz      $,#1  wc,nr      'Instr = %01111001011111$$$$$$$$$000000001 c = parity (z & 1) == nz                   
mov_c_nz      muxnz     $,#1  wc,nr      'Instr = %01111101011111$$$$$$$$$000000001 c = parity (nz & 1) == nz[/s]

swap_z_c      'Left as an exercise for the reader.

[s]not_z         muxz      $,#1  wz,nr      'Instr = %01111010011111$$$$$$$$$000000001 z = result (z & 1) == nz
not_c         muxnc     $,#1  wc,nr      'Instr = %01110101011111$$$$$$$$$000000001 c = parity (nc & 1) == nc[/s]

save_z        muxnz     restore_z,#1
restore_z     test      $,#1 wz          'Instr = %01100010011111$$$$$$$$$00000000[s]z[/s] z = result (instr & nz) == z

save_c        muxc      restore_c,#1
restore_c     test      $,#1 wc          'Instr = %01100001011111$$$$$$$$$00000000c c = parity (instr & c) == c

save_z_c      'Left as an exercise for the reader.
restore_z_c   'Left as an exercise for the reader.




These are, so far, untested. My confidence that they will work is based solely on my trust in the Parallax documentation for these instructions (and my ability to understand it smile.gif ). If the assembler supported macros, these could be defined as such. Otherwise, it wouldn't be the worst idea in the world to include them as native instructions. (The items left as exercises probably can't be done in the same spirit as single instructions and without auxiliary longs.)

-Phil

Update: Thanks to mpark for correcting my spelling via private communication. (He needn't have worried about embarrassing me online, though. I have a pretty thick skin.) I had spelled "exercise" as "exercize", thinking that the two were British and American variants, respectively. But unlike many such words, "exercise" doesn't have an Americanized (Americanised?) equivalent.

Post Edited (Phil Pilgrim (PhiPi)) : 3/3/2010 7:08:07 PM GMT

Comments

  • LeonLeon Posts: 7,620
    edited 2008-11-14 17:58
    Macros could be implemented by a macro-processor like m4. m4 is a lot more powerful than the built-in macro facilities provided by most assemblers.

    Leon

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Amateur radio callsign: G1HSM
    Suzuki SV1000S motorcycle
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2010-03-01 18:44
    I just noticed that the mux instructions used in the above flag manipulations are just wrong. The flags that are set are set based on the entire value of the result (of course, d'oh!) and not just the bits affected by the mux. (It's those pesky $$$$$$$$$s in the instruction, which is also the destination, that make the result unpredictable.) I will have to revisit this in the near future.

    -Phil
  • kuronekokuroneko Posts: 3,623
    edited 2010-04-02 07:29
    suggested replacements (tested):

    mov_z_c                 muxnc   $, $ wz,nr
    mov_z_nc                muxc    $, $ wz,nr
    mov_c_z                 muxz    $, $ wc,nr
    mov_c_nz    if_z_or_nc  muxnz   $, $ wc,nr    ' condition flips parity to odd (required)
                                                  ' this nop's for z = 0 AND c = 1 (c == nz)
    not_z                   muxz    $, $ wz,nr
    not_c                   muxnc   $, $ wc,nr
    
    swap_z_c    if_z_ne_c   sumc    $, $ wc,wz,nr
    

    Post Edited (kuroneko) : 4/2/2010 9:15:44 AM GMT
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2010-04-02 15:40
    $,$ == brilliant! Thanks, kuroneko, nicely done!

    -Phil
  • BeanBean Posts: 8,129
    edited 2010-07-15 11:16
    Hey guys I need some help.

    I need to be able to set and/or clear the carry and zero flags in LMM.

    In LMM using $ doesn't work, because it is usually greater than $1FF and it doesn't point to the instruction anyway.

    Any ideas ?

    I "think" [noparse][[/noparse] cmpsub 0,0 WC,NR ] will work to set the carry in both native and LMM. Yes·?

    Bean

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Use BASIC on the Propeller with the speed of assembly language.
    PropBASIC thread http://forums.parallax.com/showthread.php?p=867134

    March 2010 Nuts and Volts article·http://www.parallax.com/Portals/0/Downloads/docs/cols/nv/prop/col/nvp5.pdf
    NEW PropBasic Blog: http://propbasic.blogspot.com
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    There are two rules in life:
    · 1) Never divulge all information
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    If you choose not to decide, you still have made a choice. [noparse][[/noparse]RUSH - Freewill]
  • kuronekokuroneko Posts: 3,623
    edited 2010-07-15 11:42
    For setting Z or C cmpsub will be OK, i.e.

    cmpsub 0, 0 wc,wz,nr
    


    For clearing this will do

    neg 0, #1 wc,wz,nr
    


    Do you need combined settings as well?
  • kuronekokuroneko Posts: 3,623
    edited 2010-07-16 05:32
    For completeness, LMM aware flag macros:

    set_z_c                 cmpsub  0, 0 wz,wc,nr
    set_z_nc                neg     0, #0 wz,wc,nr
    set_nz_nc               neg     0, #1 wz,wc,nr
    
    set_nz_c                cmp     reg, #1 wz,wc           ' reg holding NULL, e.g. par
                            cmpsub  reg, #0 wz,wc           ' reg holding non-NULL value
    


    I haven't found a location independent way for nz_c (yet)a. But most of the time par's shadow is unused so

    cmp par, #1 wz,wc
    


    works just fine. Having said that, if you can't locate a reliable non-NULL register in your setup then that's really sad indeed (there must be some code in there somewhere).

    a But I figured out that mov[noparse][[/noparse]dis] sets C with unsigned borrow (D<S).
Sign In or Register to comment.