;;  Copyright 1987 by NeXT Inc.
;;  Author - John Strawn
;;      
;;  Modification history
;;  --------------------
;;      06/26/87/jms - initial file created from DSPAPSRC/template
;;      02/15/88/jms - change neg B to tst B in initialization
;;                   - added OPTIONAL_NOP
;;      02/23/88/jms - cosmetic changes to code and documentation
;;      03/29/88/jms - fix bugs in CALLING DSP PROGRAM TEMPLATE
;;      
;;  ------------------------------ DOCUMENTATION ---------------------------
;;  NAME
;;      lveq - vector logical equivalence 
;;          - create vector with TRUE/FALSE comparison of two input vectors
;;      
;;  SYNOPSIS
;;      include 'stdmacros' ; load standard DSP macro package
;;      lveq    pf,ic,sinp_a,ainp_a0,iinp_a0,sinp_b,ainp_b0,iinp_b0,sout,aout0,iout0,cnt0
;;      
;;  MACRO ARGUMENTS
;;      pf      =   global label prefix (any text unique to invoking macro)
;;      ic      =   instance count (such that pf\_lveq_\ic is globally unique)
;;      sinp_a  =   input vector A memory space ('x' or 'y')
;;      ainp_a0 =   input vector A base address (address of A[1,1])
;;      iinp_a0 =   initial increment for input vector A
;;      sinp_b  =   input vector B memory space ('x' or 'y')
;;      ainp_b0 =   input vector B base address
;;      iinp_b0 =   initial increment for input vector B
;;      sout    =   output vector C memory space ('x' or 'y')
;;      aout0   =   output vector C base address
;;      iout0   =   initial increment for output vector C 
;;      cnt0    =   initial element count
;;      
;;  DSP MEMORY ARGUMENTS
;;      Access      Description                     Initialization
;;      ------      -----------                     --------------
;;      x:(R_X)+    input vector A base address     ainp_a0
;;      x:(R_X)+    input vector A increment        iinp_a0
;;      x:(R_X)+    input vector B base address     ainp_b0
;;      x:(R_X)+    input vector B increment        iinp_b0
;;      x:(R_X)+    output vector C base address    aout0
;;      x:(R_X)+    output vector C increment       iout0
;;      x:(R_X)+    element count                   cnt0
;;      
;;  DESCRIPTION
;;      The lveq array-processor macro computes C = TRUE/FALSE 
;;      comparison of A and B. In pseudo-C notation:
;;
;;      ainp_a    =   x:(R_X)+;    
;;      iinp_a    =   x:(R_X)+;    
;;      ainp_b    =   x:(R_X)+;    
;;      iinp_a    =   x:(R_X)+;    
;;      aout      =   x:(R_X)+;    
;;      iout      =   x:(R_X)+;
;;      cnt       =   x:(R_X)+;
;;
;;      for (n=0;n<cnt;n++) 
;;          if ( NOT (sinp_a:ainp_a[n*iinp_a] XOR sinp_b:ainp_b[n*iinp_b]) == 0)
;;              sout:aout[n*iout] = 0xFFFFFF;       /* TRUE     */
;;          else sout:aout[n*iout] = 0;             /* FALSE    */
;;      
;;  MEMORY USE  
;;      7 x-memory arguments
;;      program memory locations:
;;                          sout==x     sout==y
;;          sinp_a  sinp_b 
;;          x       x       23          22
;;          x       y       21 (!)      22 
;;          y       x       23          22 
;;          y       y       22          23 
;;
;;  EXECUTION TIME 
;;      sinp_a==sinp_b: cnt*5+20 instruction cycles
;;      sinp_a!=sinp_b: cnt*5+19 instruction cycles
;;      
;;  DSPWRAP ARGUMENT INFO
;;      lveq (prefix)pf,(instance)ic,
;;          (dspace)sinp_a,ainp_a0,iinp_a0,
;;          (dspace)sinp_b,ainp_b0,iinp_b0,
;;          (dspace)sout,aout0,iout0,cnt0
;;      
;;  DSPWRAP C SYNTAX
;;      ierr    =   DSPlveq(aA,iA,aB,iB,aC,iC,n);   /* vector logical equivalence
;;          aA  =   input A vector base address
;;          iA  =   input A address increment
;;          aB  =   input B vector base address
;;          iB  =   input B address increment
;;          aC  =   output C vector base address
;;          iC  =   output C vector address increment
;;          n   =   element count                   */
;;      
;;  CALLING DSP PROGRAM TEMPLATE    ; see also DSPAPSRC/test/tlveq.asm 
;;      include 'stdmacros' 
;;      beg_ap  'tlveq'
;;      symobj  ax_vec,bx_vec
;;      beg_xeb
;;          radix   16
;;ax_vec    dc 1,2,3,4,5,6,107,108,109,110,111,112
;;bx_vec    dc 101,102,103,104,105,106,107,108,109,110,111,112
;;          radix   A  
;;      end_xeb
;;      new_xeb out1_vec,12,$777
;;      lveq    ap,1,x,ax_vec,1,x,bx_vec,1,x,out1_vec,1,12
;;      end_ap  'tlveq'
;;      end
;;      
;;  TEST PROGRAM
;;      DSPAPSRC/test/tlveq.asm
;;      
;;  SOURCE
;;      DSPAPSRC/lveq.asm
;;      
;;  REGISTER USE 
;;      A       TRUE or FALSE for each output term
;;      B       accumulator; temp for testing for cnt==0
;;      X0      cnt
;;      X1      term from A vector
;;      Y0      FALSE (=0)
;;      Y1      TRUE (=$FFFFFF)
;;      
        beg_def 'lveq'
lveq    macro pf,ic,sinp_a,ainp_a0,iinp_a0,sinp_b,ainp_b0,iinp_b0,sout,aout0,iout0,cnt0
        beg_mac 'lveq'

        ; argument definitions
        new_xarg    pf\_lveq_\ic\_,ainp_a,ainp_a0
        new_xarg    pf\_lveq_\ic\_,iinp_a,iinp_a0
        new_xarg    pf\_lveq_\ic\_,ainp_b,ainp_b0
        new_xarg    pf\_lveq_\ic\_,iinp_b,iinp_b0
        new_xarg    pf\_lveq_\ic\_,aout,aout0
        new_xarg    pf\_lveq_\ic\_,iout,iout0
        new_xarg    pf\_lveq_\ic\_,cnt,cnt0


        ; get inputs
        ;;  the choice of R_I2 for *A* and R_I1 for *B* is dictated by
        ;;  address register requirements for xy move, below
        move            x:(R_X)+,R_I2   ; input vector A base address to R_I2
        move            x:(R_X)+,N_I2   ; input vector A address increment to N_I2
        move            x:(R_X)+,R_I1   ; input vector B base address to R_I1
        move            x:(R_X)+,N_I1   ; input vector B address increment to N_I1
        move            x:(R_X)+,R_O    ; output address to R_O
        move            x:(R_X)+,N_O    ; output increment to N_O
        move            x:(R_X)+,B      ; count

        ; set up loop and pipelining
        tst     B        B,X0           ; squirrel away count for do loop
        jeq     pf\_lveq_\ic\_loop1     ; protect againt count=0

        ; establish TRUE, FALSE contants.  The M's *should* contain
        ; $FFFFFF for free, but this method is truly safe. 
        clr     A
        not     A       A,Y0      ; FALSE=0
        move            A1,Y1     ; TRUE=$FFFFFF (specify a1 to avoid limiting)

        ; finish pipelining	
        if "sinp_a"=="sinp_b"||"sinp_a"=='y'
            move            sinp_b:(R_I1)+N_I1,B
            move            sinp_a:(R_I2)+N_I2,X1
        else
            move            sinp_a:(R_I2)+N_I2,X1    sinp_b:(R_I1)+N_I1,B
        endif

        ; inner loop 
        do      X0,pf\_lveq_\ic\_loop1
            eor     X1,B    sinp_a:(R_I2)+N_I2,X1
            teq     Y1,A    ; TRUE, and sign extension happens for free
            tne     Y0,A    ; FALSE
            if "sinp_b"=="sout" 
                move    A,sout:(R_O)+N_O    
                move    sinp_b:(R_I1)+N_I1,B
            else
                if "sinp_b"=='x'
                    move    sinp_b:(R_I1)+N_I1,B    A,sout:(R_O)+N_O
                else
                    move    A,sout:(R_O)+N_O        sinp_b:(R_I1)+N_I1,B
                endif
            endif
pf\_lveq_\ic\_loop1
        OPTIONAL_NOP    ; from defines.asm, to prevent the macro from ending
                        ; at the end of a loop. If you remove the nop, or if
                        ; you redefine OPTIONAL_NOP to be just ' ', then the 
                        ; macro loaded next might begin with an op code which
                        ; is illegal after the end of a loop.
        
        end_mac 'lveq'
        endm
        end_def 'lveq'

