/*******************************************************************************
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: conv2d3x3_gen.asm
Label name: __conv2d3x3_gen


Description:   For a detailed description, please refer to the file "readme.txt".
               which is included in the main project.

*******************************************************************************/
.section L1_code;
.global __conv2d3x3_gen;
.align 8;
    
__conv2d3x3_gen:
    [--SP] = R7;            // Save R7
    P0 = R1;                // Loop counter for rows of input
    P1 = 2;                 // Counter for first two columns
    P2 = R2;                // Number of columns
    R3 = R1.L * R2.L (ISS2) || R7 = [SP+16];
                            // R7 = Address of Mask
    
    I2 = R7;                // Starting address of mask
    B2 = R7;                // Base address of circular buffer
    L2 = 20;                // Length of mask = 20 (9 * 2  +  1 dummy location)
        
    I0 = R0;                // Starting address of input matrix.
    B0 = R0;                // Base address of circular buffer

    
    L0 = R3;                // Circular buffer of length 2 * row * col
    L3 = R3;                // Circular buffer of length 2 * row * col
    
    R2 = R2 << 1 || R7 = [SP+20] || R3 = [I2--];
                            // 2 * col , Address of output matrix, Make I2 point
                            // to end of mask
    M3 = R2;                // M3 = 2 * col
    L1 = R2;                // Circular buffer of length 2 * col
    
    B3 = R7;                // Base address of circular buffer
    
    R1 = R2 << 1;
    M2 = R1;                // 4 * col
    
    I3 = R7;                // Address of output buffer.

    
    R2 += -4;
    M0 = R2;                // 2 * col  -  4
    
    P2 += -2;               // Col - 2
    
    I0 -= M2 || R3 = [I2--];// Modify I0, Fetch h0,dummy
    
    LSETUP (FIRST_TWO_COLS_ST, FIRST_TWO_COLS_END) LC0 = P0; 
                            // Loop to keep track of rows of i/p(counter = row)
FIRST_TWO_COLS_ST:
        M1 = 4;             // Column offset = 4.
        LSETUP (CONV_ST, CONV_END) LC1 = P1; 
CONV_ST:    B1 = I0;
            I1 = B1;
            I1 -= M1;       // Column offset is subtracted from circular buffer
            R1.L = W[I1++]; // Fetch x0
            A0 = R1.L * R3.L ||  R1.L = W[I1++] || R3 = [I2--]; 
                            // A0 = x0*h0,  x1  ,  h1,h2
            A0 += R1.L * R3.H || R1.L = W[I1++] || I0 += M3;
                            // A0 += x1*h1,  x2  , Modify Row pointer
            B1 = I0;
            I1 = B1;
            I1 -= M1;       // Column offset is subtracted from circular buffer
            A0 += R1.L * R3.L || R1.L = W[I1++] ||  R3 = [I2--];
                            // A0 += x2*h2,  x10, h3,h4
    
            A0 += R1.L * R3.H ||  R1.L = W[I1++] || I0 += M3; 
                            // A0 += x10*h3,  x11 , Modify row pointer
            A0 += R1.L * R3.L || R1.L = W[I1++] ||  R7 = [I2--]; 
                            // A0 += x11*h4,  x12  , h5,h6
            B1 = I0;
            I1 = B1;
            I1 -= M1;       // Column offset is subtracted from circular buffer
            A0 += R1.L * R7.H || R1.L = W[I1++]; 
                            // A0 += x12*h5,  x20
    
            A0 += R1.L * R7.L ||  R1.L = W[I1++] || R3 = [I2--];
                            // A0 += x20*h6,  x21 , h7,h8
            A0 += R1.L * R3.H || R1.L = W[I1++]; 
                            // A0 += x21*h7,  x22
            R0.L = (A0+=R1.L*R3.L) || I0 -= M2 || R3 = [I2--]; 
                            // A0 += x22*h8, Reset row pointer , h0,dummy
            M1 = 2;         // Column offset for last column
CONV_END:   W[I3++] = R0.L; // Store the output
    
        I0 += M3;           // Modify row pointer
FIRST_TWO_COLS_END:
        I3 += M0;           // Modify output pointer
    
    R1 = M2;                // 4*col
    R1 += 2;
    M1 = R1;                // 4*col + 2
    M2 = -8;                // -8
    
    R1.L = W[I0++] || R2 = [I2--];
                            // Fetch x0 , h1,h2
    
    LSETUP (ROW_ST,ROW_END1) LC0 = P0; 
                            // Loop to keep track of rows of i/p(counter = row)
ROW_ST: A0 = R1.L * R3.L ||  R1.L = W[I0++] || I3 += 4;
                            // A0 = x0*h0, x1 , Modify output pointer after each
                            // row
        LSETUP (COL_ST, COL_END) LC1 = P2; 
                            // Loop for all columns in a row except first two, 
                            // ctr = (col-2)/2
COL_ST:     A0 += R1.L * R2.H || R1.L = W[I0] || I0 += M0;    
                            // A0 += x1*h1,  x2
            A0 += R1.L * R2.L || R1.L = W[I0++] || R3 = [I2--];
                            // A0 += x2*h2,  x10 ,  h3,h4
    
            A0 += R1.L * R3.H ||  R1.L = W[I0++] || I2 -= 4; 
                            // A0 += x10*h3,  x11 , Modify I2
            A0 += R1.L * R3.L || R1.L = W[I0] || I0 += M0; 
                            // A0 += x11*h4,  x12
            A0 += R1.L * R7.H || R1.L = W[I0++]; 
                            // A0 += x12*h5,  x20
    
            A0 += R1.L * R7.L ||  R1.L = W[I0++] || R3 = [I2--];
                            // A0 += x20*h6,  x21 , h7,h8
            A0 += R1.L * R3.H || R1.L = W[I0] || I0 -= M1; 
                            // A0 += x21*h7,  x22
            R0.L=(A0 += R1.L * R3.L) || R1.L = W[I0++] || R3 = [I2++M2]; 
                            // A0 += x22*h8, x0 , h0,dummy
COL_END:    A0 = R1.L * R3.L ||  R1.L = W[I0++] || W[I3++] = R0.L;
                            // A0 = x0*h0,  x1  , store output
ROW_END1:
        R1.L=W[I0++];       // Fetch x0 for next output
    
    R7 = [SP++];            // Restore R7
    RTS;                 
    NOP;                    //to avoid one stall if LINK or UNLINK happens to be
                            //the next instruction after RTS in the memory.
__conv2d3x3_gen.end:                            
