

import com.xilinx.JBits.CoreTemplate.*;
import com.xilinx.JBits.Virtex.ConfigurationException;
import com.xilinx.JRoute.Virtex.ResourceDB.*;
import com.xilinx.JBits.Virtex.Expr;
import com.xilinx.JBits.Virtex.Bits.*;

/* These imports are used to use some static methods*/
import com.xilinx.JBits.Virtex.Util;
import java.lang.reflect.Array;
/** 
 *  This defines a Distributed Arithmetic look-up table Core. This core is the only one that can be changed in the run time since it holds all Digital filter constants
 * 
 *  <p>
 *
 * Inputs connected to F1 and G1 of Slice 0 at the selected row<p>
 *
 * Outputs connected to XQ and YQ located at col+word width<p>
 *
 *<pre>
 * ADDRESS = NO TAPS
 * OUTPUT = WORDSIZE
 * CONTENTS SIZE = WORDSIZE 
 *
 *    DALUT Rules 
 * 1) # of LUTs = wordsize
 * 2) wordsize should be larger than taps ( # taps <= wordsize )
 * 3) # taps should be multiple of 4 ( no. of luts should be divided into groups of 4 and the remaining luts )
 * 4) # taps can be less than 4
 * 5) Word size must be a power of 2
 *
 *</pre>
 *
 <pre>
 *Growth direction:
 *I |  O
 *N |  U
 *  \/ T
 *rows
 *</pre>
*
*  <p>
*
*  Copyright (c) 2000 Jamil Khatib.<p>
*
*  <p>
*
*  Created    0.1  6 October 2000<p>
*  Author     Jamil Khatib<p>
*
*
*<pre>
* Bugs:
* 1) TAPS = 4 only
* 1) error in conversion and filling LUT when # taps is larger than 4
* 2) Taps should be >= 4
*</pre>
*
*/
public class Dalut extends RTPCore 
{


    Port DoutPort;
    Port DinPort;
    Port clkPort;

    int Taps = 0;
    int [] constants;
    int WordSize = 0;
    
    int [] DALUT;
    int [][] LUTS;


    int MyTag =     0x0801;
    
    /* Define this for debug purposes only */
    boolean debug = true;
    
 
    /////////////////////////////  
    /**
     * Creates an instance of a Dalut  to be used in DA filter.
     *
     * @param  instanceName   the name assigned to this instance
     * @param  clk            the external net to be connected to the CLK port
     * @param  Din            the external bus to be connected to the Data in port, the size of Din port specifies the no of filter taps(no of constants)
     * @param  Dout           the external bus to be connected to the Data out port, the size of Dout port specifies word width. 
     * @param  Constants      this integer array defines the filter constants
     * 
     */

    public  Dalut(String instanceName, int[] Constants, Net clk, Bus Dout, Bus Din)throws Exception
    {
        super(instanceName);

        /* 
           Set global constants
        */

        constants = Constants;
        Taps =  Din.getWidth();
        WordSize =  Dout.getWidth();
          
        if(Array.getLength(constants) != Taps)
            throw new Exception("Unmatched No. of Taps and Constants Error");

        /* Checking the rules */
        if((WordSize%2)!= 0)
            throw new Exception("Not supported value for word size [rule5]");
        if(Taps > WordSize)
            throw new Exception("Not supported value for taps and word size [rule2]");

        if((Taps % 4 )!= 0)
            throw new Exception("Not supported value for taps [rule3]");

        /* Define the core's ports */
        clkPort = newInputPort("CLK", clk);
        DoutPort = newOutputPort("DataOut", Dout);
        DinPort = newInputPort("AddressIn", Din);


        generate_romContents();
        covert_dalut_luts();



        return;
        
    }/*Dalut(String instanceName, int[] constants, Net clk, Bus Dout, Bus Din)*/

    /////////////////////////////
    /**
     * Implement this DALUT
     */
    public final void implement()
    {

        // set the core absolute offset
  
        Offset offset = calcAbsoluteOffset();

        int row = offset.getVerOffset(Gran.CLB);
        int col = offset.getHorOffset(Gran.CLB);

        PrintDebugMsg("[DALUT] Location  Row = "+ row + " Col " + col);
        
        // configure the clbs using relative location
        configureCLBs(row, col);

        InternalRoute(row, col);
        

        // Create pins
        CreatePins(row, col);

        return ;
        
    }/*implement()*/


    /////////////////////////////  

    /**
     * Get the hight granularity of the core.
     *
     */
    public int getHeightGran()
    {
        return Gran.CLB;
    }/*getHeightGran()*/


    /////////////////////////////  
    /**
     * Get the width granularity of the core.
     *
     */
    public int getWidthGran() 
    {
        return Gran.CLB;
    }/*getWidthGran() */


    /////////////////////////////  

    /**
     * Create pins
     *
     * @param  row    Row location of the core
     * @param  col    Column location of the core
     *
     */
    private void CreatePins(int row, int col)
    {
        
        Pin output;
        Pin input;

        /* connect output pins to ports */
        try {
            int j =0;

            int incRow = 0;
                        
            for (int i = 0 ; i < (WordSize/2); i++) 
                {

                    PrintDebugMsg("[DALUT]in Create Pines 1 ");
                    

                    output = new Pin(Pin.CLB, row-incRow, col, Wires.Slice_XQ[i%2]);
                 
                    DoutPort.setPin(j++, output);

                    output = new Pin(Pin.CLB, row-incRow, col, Wires.Slice_YQ[i%2]);

                    DoutPort.setPin(j++, output);

                    incRow += i%2;
                    
                    
                }

            PrintDebugMsg("[DALUT]No of rows = "+incRow);
            
        } catch (WidthMismatchException wme) {
            System.out.println(wme);
            System.exit(-1);
        }


        /* connect input pins to ports */
        try {
 //            int NO_groups =  Taps/4;  
//             int NO_LUTS = WordSize /  NO_groups;
            

             int j =0; /* j represents the address lines*/
            
            int incRow = 0;
            
        //     int no_luts = 0;
                    
            for (int i = 0 ; i < (WordSize/2); i++) 
                {
                            
                    PrintDebugMsg("[DALUT]in Create Pines 2 ");
                            
                            
                    input = new Pin(Pin.CLB, row-incRow, col, Wires.SliceF1[i%2]);
                            
                    DinPort.setPin(j, input);

                    input = new Pin(Pin.CLB, row-incRow, col, Wires.SliceF2[i%2]);
                            
                    DinPort.setPin(j+1, input);

                    input = new Pin(Pin.CLB, row-incRow, col, Wires.SliceF3[i%2]);
                            
                    DinPort.setPin(j+2, input);

                    input = new Pin(Pin.CLB, row-incRow, col, Wires.SliceF4[i%2]);
                            
                    DinPort.setPin(j+3, input);

                    /*********End of LUT 1**********/
                    input = new Pin(Pin.CLB, row-incRow, col, Wires.SliceG1[i%2]);
                            
                    DinPort.setPin(j, input);

                    input = new Pin(Pin.CLB, row-incRow, col, Wires.SliceG2[i%2]);
                            
                    DinPort.setPin(j+1, input);

                    input = new Pin(Pin.CLB, row-incRow, col, Wires.SliceG3[i%2]);
                            
                    DinPort.setPin(j+2, input);
                            
                    input = new Pin(Pin.CLB, row-incRow, col, Wires.SliceG4[i%2]);
                            
                    DinPort.setPin(j+3, input);
                    /*********End of LUT 2**********/

                    incRow += i%2;

//                     no_luts +=2;
                            
//                     if(no_luts == NO_LUTS ) 
//                         j += 4;

                            
                }

            

            
            PrintDebugMsg("[DALUT]No of rows = "+incRow);
            
        } catch (WidthMismatchException wme) {
            System.out.println(wme);
            System.exit(-1);
        }



        return;
        
    }/* CreatePins(int row, int col)*/
    

    /////////////////////////////  

    /**
     * Perform internal routings.
     *
     * @param  row    Row location of the core
     * @param  col    Column location of the core
     */
    private void InternalRoute(int row, int col)
    {
        int iRow = row;
        int iCol = col;

        return;
    }/*InternalRoute(int row, int col)*/
    


    /////////////////////////////  

    /**
     * Configure CLBs.
     *
     * @param  row    Row location of the core
     * @param  col    Column location of the core
     *
     */
    private void configureCLBs(int row, int col)
    {

        int iRow = row;
     
        int iCol = col;
     
        Pin[] clkPin = new Pin[WordSize/2];
        int incRow=0;
        int j =0;
        
        try{
            

            for (int i = 0 ; i < (WordSize/2); i++) 
                {
         
                    PrintDebugMsg("[DALUT]in ConfigureCLB 1 ");

                    /* define the clock pin */
                    clkPin[i] = new Pin(Pin.CLB,row-incRow,  col, Wires.SliceClk[i%2]);


                    Bitstream.set(row-incRow, col, S0CE.S0CE, S0CE.OFF);
                    Bitstream.set(row-incRow, col, S1CE.S1CE, S1CE.OFF);
           
                    Bitstream.set(row-incRow, col, SliceControl.LatchMode[i%2], SliceControl.OFF[i%2]);

                    Bitstream.set(row-incRow, col, SliceControl.LatchMode[i%2], SliceControl.OFF[i%2]);



                    Bitstream.set(row-incRow, col, LUT.F[i%2], Util.InvertIntArray( LUTS[j++]));

                            
                    Bitstream.set(row-incRow, col, LUT.G[i%2],  Util.InvertIntArray(LUTS[j++]));
                            
                            
                    Bitstream.set(row-incRow, col, SliceControl.X.X[i%2], SliceControl.X.FOUT[i%2]); 
                    Bitstream.set( row-incRow,col, SliceControl.XDin.XDin[i%2], SliceControl.XDin.X[i%2]);
                            
                            
                    Bitstream.set(row-incRow, col, SliceControl.Y.Y[i%2], SliceControl.Y.GOUT[i%2]);
                    Bitstream.set(row-incRow, col, SliceControl.YDin.YDin[i%2], SliceControl.YDin.Y[i%2]);
                            
                    tagCLB(row-incRow, col, MyTag);
         
                    incRow += i%2;
         
                }
    
        } catch (ConfigurationException ce) {
            System.out.println("[DALUT]"+ce);
            System.exit(-1);
        }

        try {
            clkPort.setPin(0, clkPin);
        } catch (WidthMismatchException ce) {
            System.out.println(ce);
            System.exit(-1);
        }

        return;
        
    }/* configureCLBs(int row, int col)*/
    



    /////////////////////////////
    /** tag CLB to make BoardScope viewing easier
     * @param  row    Row location of the clb
     * @param  col    Column location of the clb
     * @param  tag    Tag ID

     */
    private void tagCLB(int row, int col, int tag)
    {
   
        try 
            {

                Bitstream.getVirtex().setTag(row, col, tag);

            } catch (ConfigurationException ce) 
                {

                    System.out.println("ERROR: unable to tag CLB " +
                                       "at R" + row + "C" + col);
                    System.out.println(ce);
                    System.exit(-1);
                }
        return;
        
    }/*tagCLB(int row, int col, int tag)*/

    /////////////////////////////
    /** calculates core hight based on word size and no of taps
     * @param  wordsize     word size
     * @param taps no of filter taps (no of constants)
     */
    public static int calcHeight(int wordsize)
    {
    
        return wordsize/2;
    }/*calcHeight(int wordsize,int taps)*/


    /////////////////////////////
    /** calculates core width
     */
    public static int calcWidth() 
    {
        return 1;
    }/*calcWidth()*/

    /////////////////////////////    
    /** Prints a debug Message
     */

    private void PrintDebugMsg(String msg)
    {
        if(debug)
            System.out.println(msg);
        
        return;
        
    }/*PrintDebugMsg(String msg)*/


    /******************************************************************
     * 
     *
     * Generates the LUT (rom) contents
     *
     * Inputs:
     * constants[] : Filter's constants
     * DALUT[]    : Array to store the LUT constants 
     * 
     *****************************************************************
     */

    private void generate_romContents()
    {

        int i= 0;
        int j = 0;
        int num_const = Taps; 
        int max_addr = (int)Math.pow(num_const,2);
        int flag = 0; /* defines the location where the address bits are 1 */
        int index = 0;
    
        DALUT = new int [max_addr];
    
        for (i= 0;i < max_addr; i++)/* i = rom address*/
            {
                index = i;
                DALUT[i] = 0;
        
                for (j = 0; j < num_const; j++)
                    {
                        flag = 0x1 & index;  /* Mask the first bit*/

                        /* Multiply the flag with the current constant*/

                        DALUT[i] = DALUT [i] + ( constants[j] * flag);
            
                        index >>=1; /* get next bit in the address*/
            
                    }
            }
    
        return ;
    } /*generate_romContents()*/

    /******************************************************************
     * void covert_dalut_luts()
     *
     * Converts DALUT "rom" contents to arrays of luts
     *
     * Inputs:
     * none: it uses the gobal array DALUT 
     * 
     ******************************************************************/

    private void covert_dalut_luts()
    {
        int tmp [][];
        
        int taps = Taps; // max_addr = 2**Taps
        
        int max_addr = Array.getLength(DALUT);
                       
        int size = WordSize;
        
        tmp = new int [max_addr][size];
        

        LUTS  = new int [size][16];

       
        // Convert from inetger to binary
        for(int i= 0; i < max_addr; i++)
            {
                tmp[i] = Util.IntToIntArray(DALUT[i],size);
                
            }
        
        // Fill the LUTs
        // Set a bit of the current(at selected address) word at each LUT
        for(int i =0; i< max_addr ; i++)
            { 

                for(int j =0; j < size; j++)
                    {
                        LUTS[j][i%16] = tmp[i][j];

                    }
            }
                
    }/* covert_dalut_luts() */



    /****************/
   
    public void test_parm()
    {
        int i =0;
        int max_addr = (int)Math.pow(Taps,2);
    	int j=0;

        System.out.println("====DAfilter Testing procedure====");
        System.out.println("Taps = " +Taps + "  Word size = " + WordSize );
        System.out.println("Filter Constants:");
    
    

        for(i=0; i <Taps ; i++)
            System.out.println("Constant[" +i+ "]= " + constants[i]);
    
        System.out.println("DALUT contents:");

        for(i=0; i <max_addr ; i++)
            System.out.println("DALUT[" +i+ "]= " + DALUT[i]);


        System.out.println("---LUTs contents---");    
		
        for(i =0; i<WordSize ; i++)
            {
                
                System.out.println("== LUT["+ i + "] ==");
                for(j =0; j < 16; j++)
                    System.out.println("[" + LUTS[i][j] + "]");
            }
        

        return;
    
    
    }/* test_parm*/
        
}
