/*******************************************************************************
Copyright(c) 2000 - 2006 Analog Devices. All Rights Reserved.

By using this module you agree to the terms of the Analog Devices License
Agreement for DSP Software. 

********************************************************************************
Module Name: dilation.asm
Label name : __dilation


Description:   For a detailed description, please refer to the file "readme.txt".
               which is included in the main project.

*******************************************************************************/
 .section     L1_code;
.global      __dilation;
.align        8;
    
__dilation:

    [--SP] = (R7:6,P5:3);
    R7 = [SP+32];            // Address of structured element
    I1 = R7;                 // Initialize I register to structure element 
                             // address
    B1 = R7;                 // Initialize base register
    L1 = 18;                 // Initialize  L register
    M0 = 8;                  // Initials to fetch h11
    M1 = 6;                  // initialize to skip 3 element in structured 
                             // element array
    P5 = R0;                 // Address of input array
    M3 = R0;                 // duplicate the address
    P0 = R2;                 // Number of columns  (N)
    P1 = R2;                 // Duplicate the number of columns
    R6 = R1-R1(NS)||I1+= M0;// Increment to fetch h11 element and clear r6
    R7 = 1;                           
    P2 = R1;                // Number of rows    (M)
    P3 = R2;                // Number of columns
    P0+=-4;                 // Columns -4
    R3 = R2 << 1 ||R0 = B[P5++](Z)||R1.L = W[I1++];
                            // r3= 2*Col,fetch first input and h11 
    M0 = R3;                   
    r2 = R7 << 1;
    R3 = R3+R2(NS)||P4 = [SP+36];
                            // Address of output array 
    M2 = R3;                // 2*col +2
    P3+= 2;                // Col+2
    P1+= -2;               // Col-2
    P2+= -2;               // ROW-2;
    
/////////////////////// FIRST ROW ///////////////////////////////////
                            // First row  and last row is computed separately. 
                            // In each row first and last elements are computed 
                            // separately.
    
    A0 = R0.L*R1.L(IS) || R0 = B[P5++](z)||R1.L = W[I1++];
                            // fetch x(0,1) and h12 
    R2 = W[P5++P1](Z) || R3.L = W[I1++];
                            // dummy fetches to increment P5 and I1 
    A0+= R0.L *R1.L(IS) ||R0 = B[P5++](Z) || R1.L = W[I1++];
                            // fetch x(1,0) and h21 
    A0+=R0.L*R1.L(IS)  ||R0 = B[P5](Z) || R1.L = W[I1++];
                            // fetch x(1,1) and h22 
    R2 = (A0+=R0.L * R1.L )(IS)|| I1+= M1;
                            // Increment I1 to fetch h10 
    CC = R2==0;             // check if result is zero
    IF !CC R2 = R7;         // if not R2==1
    P5 = M3;                // Initialize P5 to  input array
    B[P4++] = R2;           // store the result
    
    LSETUP(FIRST_ROW_ST,FIRST_ROW_END)LC0 = P1;
                            // loop counter == COL-2 
FIRST_ROW_ST:  
        R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch X(0,0) and H10 
        A0 = R0.L *R1.L(IS) ||R0 = B[P5++](z) ||R1.L = W[I1++];
                            // fetch X(0,1) and H11 
        A0+=R0.L*R1.L(IS)  ||R0 = B[P5] (z)||R1.L = W[I1++];
                            // fetch X(0,2) and H12 
        P5 = P5+P1;         // increment P5 to fetch x(1,0)
        A0+= R0.L *R1.L (IS) ||R0=B[P5++](Z) || R1.L = W[I1++];
                            // fetch X(1,0) and H20 
        A0+= R0.L *R1.L (IS)||R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch X(1,1) and H21 
        A0+= R0.L *R1.L(IS) ||R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch X(1,2) and H22 
        R2 = (A0+= R0.L *R1.L)(IS) || I1+= M1;
                            // Increment I1 to fetch h10 
        CC = R2 ==0;       // check if result is 0
        IF !CC R2 = R7;     // if not r2 =  = 1
        P5-= P3; 
FIRST_ROW_END:  
        B[P4++] = R2;
                            // store the result 
    
    R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch x(0,N-2) and H10 
    A0 = R0.L *R1.L (IS) ||R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch x(0,n-1) and H11 
    R2 = W[P5++P1](Z) || R3.L = W[I1++];
                            // dummy fetch to increment P5 and I1 pointers 
    A0+= R0.L * R1.L (IS)|| R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch x(1,N-2) and H20 
    A0+= R0.L * R1.L (IS)|| R0 = B[P5++](z)|| R1.L = W[I1++];
                            // fetch x(1,N-1) and H21 
    R2 = (A0+= R0.L *R1.L) (IS) ||I1+= 4;
                            // Increment to fetch h01 
    CC = R2 == 0;
    IF !CC R2 = R7;                             
    P5 = M3;                // Initialize P5 to starting of  input array
    B[P4++] = R2;           // store output of last element in first row
    
////////////  MIDDLE   LOOP   //////////////////////////////////////////////
    
    P3 = M0;                // Initialized to 2*col

    LSETUP(ROW_ST,ROW_END)LC0 = P2;
                            // loop counter  =  =  ROW-2 (M-2) 
    P2 = M2;                // Initialized to 2*COL+2
ROW_ST:
        R0 = B[P5++](z)||R1.L  = W[I1++];
                            // fetch x(0,0) and H01 
        A0 = R0.L *R1.L(IS) || R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch x(0,1) and H02 
        R2 = W[P5++P1](Z) ||R3.L = W[I1++];
                            // dummy fetch to adjust P5 and I1 
        A0+= R0.L*R1.L(IS) || R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch x(1,0) and H11 
        A0+= R0.L* R1.L(IS) || R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch x(1,1) and H12 
        R2 = W[P5++P1](Z)|| R3.L = W[I1++];
                            // dummy fetch to adjust P5 and I1 
        A0 += R0.L*R1.L(IS) || R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch x(2,0) and H21 
        A0 += R0.L* R1.L(IS) || R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch x(2,1) and H22 
        P5 -= P2;               // P5 modified to stating of the row
        R2 = (A0 += R0.L*R1.L )(IS)||R0 = B[P5++](z) || R1.L = W[I1++];
                            //fetch first element of the row and h00 
        R2 = MAX(R2,R6);
        R2 = MIN(R2,R7);
        B[P4++] = R2 || NOP;// store the output
    
///////////////// CORE LOOP      //////////////////////////////////////
                            // Here data is processed to get two pixel output 
                            // at a time
    
        LSETUP(COL_ST,COL_END)LC1 = P1 >> 1;
                            // loop counter  = =(COL-2)/2 
COL_ST:
            A0 = R0.L*R1.L(IS) ||R0 = B[P5++](z) || R1.H = W[I1++];
                            // fetch x(0,1) and h01 
            A1 = R0.L * R1.L ,A0+= R0.L*R1.H(IS)  || R0 = B[P5++](z)
            || R1.L = W[I1++];
                            // fetch x(1,2) and h02 
            A1+= R0.L *R1.H ,A0+= R0.L *R1.L(IS) || R0 = B[P5++](z) 
            || R1.H = W[I1++];
                            // fetch x(1,3) and h10 
            P5 = P5+P0;     // move  P5 to starting of next row
            A1+=  R0.L *R1.L (IS) ||R0 = B[P5++](z) ||R1.L = W[I1++];
                            // fetch x(1,0) and h11 
            A0+= R0.L *R1.H(IS)|| R0 = B[P5++](z) ;
                            // fetch x(1,1) 
            A1+= R0.L * R1.H,A0+= R0.L *R1.L(IS) ||R0 = B[P5++](z)
            || R1.H = W[I1++];
                            // fetch x(1,2) and h12 
            A1+=  R0.L *R1.L ,A0+= R0.L *R1.H(IS)|| R0 = B[P5++](z)
            ||R1.L = W[I1++];
                            // fetch x(1,3) and h20 
            P5 = P5+P0;               // move P5 to starting of next row
            A1+=  R0.L *R1.H(IS)||R0 = B[P5++](z)|| R1.H = W[I1++];
                            // fetch x(2,0) and h21 
            A0+= R0.L*R1.L(IS)  ||R0 = B[P5++](z);
                            // fetch x(2,1) 
            A1+= R0.L * R1.L ,A0+= R0.L *R1.H(IS) ||R0 = B[P5++] (z)
            ||R1.L = W[I1++];
                            // fetch x(2,2) and h22 
            A1+= R0.L *R1.H,R2 = (A0+=R0.L *R1.L)(IS)||R0 = B[P5++](z);
                            // fetch x(2,3) 
            P5-=P2;         // modify P5 to process next set of data
            R3 = (A1+=R0.L *R1.L)(IS)||R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch x(0,2) and h00 
            CC = R2==0;
            IF !CC R2 = R7;
            CC = R3==0;
            IF !CC R3 = R7;
            MNOP||B[P4++] = R2;
                            // store first output
COL_END:    B[P4++] = R3;
                            // store next output 
        A0 = R0.L *R1.L (IS)||R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch x(0,N-2) and h01 
        R2 = W[P5++P1](Z) ||R3.L = W[I1++];
                            // dummy fetch to increment P5 and I1 
        A0+= R0.L *R1.L (IS)||R0=B[P5++](z) || R1.L = W[I1++];
                            // fetch  X(1,N-2) and H10; 
        A0+= R0.L*R1.L(IS) ||R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch  X(1,N-1) and H11; 
        R2 = W[P5++P1](Z) || R3.L = W[I1++];
                            // dummy fetch to increment P5 and I1 
        A0+= R0.L *R1.L (IS)||R0 = B[P5++] (z)|| R1.L = W[I1++];
                            // fetch x(2,N-2) and h20 
        A0+= R0.L*R1.L(IS) ||R0 = B[P5++] (z)|| R1.L = W[I1++];
                            // fetch x(2,N-1) and h21; 
        R2 = (A0+=R0.L *R1.L)(IS)|| I1+= 4;
                            // modify I1 to fetch h01 
        CC = R2==0;
        IF !CC R2 = R7;                                      
        P5-= P3;           // modify P5 to starting of next row
ROW_END:
        B[P4++] = R2;   
    
////////////////////  LAST ROW   //////////////////////////////////////////////
    P2=P1;
    P2+= 4;                // P2==Col +2
    R0 = B[P5++](z)||R1.L = W[I1++];
                            // fetch h01 and x(M-2,0) 
    A0 = R0.L *R1.L(IS) || R0 = B[P5++](z)||R1.L = W[I1++];
                            // fetch x(M-2,1) and h02 
    R2 = W[P5++P1](Z)|| R3.L = W[I1++];
                            // dummy fetch to increment P5 and I1 
    A0+=R0.L*R1.L(IS)||R0 = B[P5++](z)||R1.L = W[I1++];
                            // fetch x(M-1,0) and h11 
    A0+=R0.L *R1.L (IS)||R0 = B[P5++](z)||R1.L = W[I1++];
                            // fetch x(M-1,2) and h12 
    P5-=P2;      
    MNOP|| I1+=M1;          // I1 is modified to fetch h00
    R2 = (A0+=R0.L *R1.L) (IS)||R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch x(M-2,0) and  h00 
    CC = R2==0;
    IF !CC R2 = R7;
    B[P4++] = R2;           // store the result
    
    
    LSETUP(LAST_ROW_ST,LAST_ROW_END)LC0 = P1;
LAST_ROW_ST:
        A0 = R0.L*R1.L (IS) ||R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch x(M-2,1) and h01 
        A0+=R0.L *R1.L(IS) ||R0 = B[P5](z) || R1.L = W[I1++];
                            // fetch x(M-2,2) and h02 
        P5 = P5+P1;         // modify P5 to  next row
        A0+=R0.L *R1.L(IS) ||R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch x(M-1,0) and h10 
        A0+=R0.L *R1.L(IS) ||R0 = B[P5++](Z) || R1.L = W[I1++];
                            // fetch x(M-1,1) and h11 
        A0+=R0.L *R1.L(IS) ||R0 = B[P5++](z) || R1.L = W[I1++];
                            // fetch x(M-1,2) and h12 
        I1 += M1;             // modify I1 to fetch h00
        P5 -= P2;
        R2 = (A0+=R0.L *R1.L)(IS)||R0 = B[P5++] (z)|| R1.L = W[I1++];
                            // fetch h00 
        CC = R2==0;
        IF !CC R2 = R7;
LAST_ROW_END:
        B[P4++] = R2;       // store the result
    
    A0 = R0.L *R1.L(IS) || R0 = B[P5++](z)||R1.L = W[I1++];
                            // fetch x(m-2,N-1) and h01 
    R2 = W[P5++P1](Z) || R3.L = W[I1++];
                            // dummy fetch to increment P5 to next row and I1 
                            // to fetch h10 
    A0+=R0.L*R1.L(IS)||R0 = B[P5++](z)||R1.L = W[I1++];
                            // fetch h10 and x(m-1,N-2) 
    A0+= R0.L *R1.L (IS)||R0 = B[P5++](z)||R1.L = W[I1++];
                            // fetch h11 and x(m-1,N-1) 
    R2 = (A0+=R0.L *R1.L )(IS);
    CC = R2 ==0;
    IF !CC R2 = R7;
    B[P4++] = R2 ;          // store the final output pixel
    (R7:6,P5:3) = [SP++];   // POP r7 and P5-3
    RTS;
    NOP;                    // To avoid one stall if LINK or UNLINK happens to 
                            // be the  next instruction in the memory.
__dilation.end:                            
