/*******************************************************************************
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: perimeter.asm
Label name: __perimeter


Description:   For a detailed description, please refer to the file "readme.txt".
               which is included in the main project.

*******************************************************************************/
 .section   L1_code;
.global    __perimeter;
.align      8;
    
__perimeter:

    [--SP]=(R7:5,P5:3);
    P4=[SP+36];             // address of output array
    P5=R0;                  // Address of input array
    M0=R0;
    P1=R2;                  // Number of columns
    M1=R2;                  // Number of columns
    P0=R2;
    P3=R2;
    P2=R1;                  // Number of rows
    R7=1;                   // Initialize to 1
    R5.H=-4; 
    R5.L=1;                 // Initialize to mask element
    P3+=-1;
//////////////////// First Row  ///////////////////////////////////////////////

    LSETUP(FIRST_ROW_ST,FIRST_ROW_END)LC0=P1;
FIRST_ROW_ST:
        R0=B[P5++](Z);
                            // fetch input 
FIRST_ROW_END:
        B[P4++]=R0;
                            // store input as output 
    
    P5=M0;                  // Address of input
    R3=R2<<1 ||R0=B[P5++](Z);
                            // fetch first input 
    R3+=-1;                 // 2*col-1
    P1+=-2;                 // Col-2
    P2+=-2;                 // ROW-2;
    P0+=-3;                 // COL-3
    
//////////////// Middle loop ///////////////////////////////////////
    LSETUP(ROW_ST,ROW_END)LC0=P2;
                            // loop counter == ROW-2 (M-2) 
    P2=R3;                  // 2*col
    NOP;
ROW_ST: B[P4++]=R0;
                            // store input as output 
        R0=B[P5++](Z);      // fetch x01
        LSETUP(COL_ST,COL_END)LC1=P1>>1;
                            // loop counter ==(COL-2)/2 
COL_ST:     A1=R0.L * R5.L (IS)||R1=B[P5](z);
                            // A1=x01,fetch x02 
            R2=R1-R1(NS)||R0=W[P5++P1](Z);
                            // clear r2 and increment pointer to next row 
            A0=R1.L * R5.L (IS) || R0=B[P5++](Z);
                            // A1=x02, fetch x10 
            A1+=R0.L * R5.L(IS)||  R0=B[P5++](z);
                            // A1+=x10,fetch x11 
            A1+=R0.L * R5.H,A0+=R0.L * R5.L(IS)||R0=B[P5++](z);
                            // A1+=-4*x11, a0+=x11,fetch x12 
            A1+=R0.L * R5.L,A0+= R0.L *R5.H(IS)||R0=B[P5++](z);
                            // A1+=x12,A0+=-4*x12,fetch x13 
            R3=R1-R1(NS)||R1=W[P5++P0](Z);
                            // clear r3 and increment pointer to next row 
            A0+=R0.L *R5.L(IS) || R0=B[P5++](z);
                            // A0+=x13,fetch x21 
            R1=(A1+=R0.L *R5.L)(IS) || R0=B[P5](Z);
                            //R1= first result, fetch x22 
            CC=R1<0;        // check if r1 <0
            P5-=P2;         // decrement pointer to first row
            R6=(A0+=R0.L*R5.L)(IS)||R0=B[p5++](Z);
                            // A0+=x22 
            IF CC R3=R7;    // if true output ==1
            B[P4++]=R3;     // store first result
            CC=R6<0;        // check for send output
            IF CC R2=R7;    // if true output ==1
COL_END:    B[P4++]=R2;
                            // store second output 
        P5=P5+P3;
        R0=B[P5++](Z);
        B[P4++]=R0;         // store  last element as zero
        R0=B[P5++](Z);      // fetch first element of next row
        P5-=P3;
ROW_END:R1=B[P5--](Z);
                            // dummy fetch to decrement the pointer 
////////////////////  LAST ROW   //////////////////////////////////////////////
    P0=M1;     
    p5=p5+p3;
    LSETUP(LAST_ROW_ST,LAST_ROW_END)LC0=P0;
LAST_ROW_ST:
        R0=B[P5++](z);         
LAST_ROW_END:
        B[P4++]=R0 ;
                            // store last row output as input 
    
    (R7:5,P5:3)=[SP++];     // POP r7-5 and P5-3
    RTS;
    NOP;                    // To avoid one stall if LINK or UNLINK happens to 
                            // be the  next instruction in the memory.
__perimeter.end:                            
