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.*;

import com.xilinx.Netlist.SYM.*;

import com.xilinx.JBits.Virtex.RTPCore.Basic.Clock;

import java.lang.reflect.Array;

/** 
*  This defines a Distributed Arithmetic based digital filter Core. This core is the top level core.
* 
*  <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>
*
*    DAfilter rules
* 1) Unsigned no.
* 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
* 6)
*
*</pre>
*
<pre>
*Growth direction:
*I |  O
*N |  U
*  \/ T
*rows
*</pre>
*
*  <p>
*
*  Copyright (c) 2000 Jamil Khatib.<p>
*
*  <p>
*
*  Created    0.1  12 October 2000<p>
*  Author     Jamil Khatib<p>
*
*
*<pre>
* Bugs:
* 1) calcHight and calcWidth must be fixed
* 
*</pre>
*
*/
public class DAfilter extends RTPCore 
{

    Port DoutPort;
    Port DinPort;
    Port clkPort;
    
    int NoRows = 0;
    int NoCols = 0;

    int NO_TAPS;
    int WordSize;
    int [] constants;
    

//    Net clk;
    
 //                Net load = new Net("load",null);
//                 Bus Datain = new Bus("DataIn",null,WORD_WIDTH);
//                 Bus DALUTin = new Bus("DALUTin",null,NO_TAPS);
//                 Bus DALUTout = new Bus("DALUTout",null,WORD_WIDTH);

    
    int MyTag =     0x0803;
    
    // These variables have initial dummy variables
    int WORD_WIDTH = 8;



    /* Define this for debug purposes only */
    boolean debug = true;

    
    /////////////////////////////  
    /**
     * Creates an instance of a Distributed Arithmetic Filter core.
     *
     * @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 word width
     * @param  Dout           the external bus to be connected to the Data out port, the size of Dout port specifies no of filter taps
     * @param  Constants      this integer array defines the filter constants and no of taps from the no of constants
     */

    public DAfilter(String instanceName, Net CLK, Bus Dout, Bus Din,int[] Constants) 
    {
        super(instanceName);
        /* 
           Calculate No of rows and no columens (taps and word size) based on the input and output pins 
        */

        NO_TAPS =  Array.getLength(Constants);
        WordSize =  Din.getWidth();
 
        if(NO_TAPS != 4 || WordSize < 2)
            {
                System.out.println("Can not implement this parameter");
                System.exit(-1);
     
            }

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

//        clk = CLK;
        
        constants = Constants;

        /* compute core width and height */      
        setHeight(WordSize);
        setWidth(WordSize);

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


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

        try
            {





                // configure the clbs using relative location
                //        configureCLBs(row, col);

                //        InternalRoute(row, col);
        

                // Create pins
                //        CreatePins(row, col);

                /* Create Top level net and bus */
                Net load = new Net("load",this);
                Bus Datain = new Bus("DataIn",this,WORD_WIDTH);
                Bus DALUTin = new Bus("DALUTin",this,NO_TAPS);
                Bus DALUTout = new Bus("DALUTout",this,WORD_WIDTH);
                Net clk = this.newNet("Clk"); /* this is another alternative of defining a net */
                

                DinPort.setIntSig(Datain);
                DoutPort.setIntSig(DALUTout);
                clkPort.setIntSig(clk);



                /* Create  cores */
                Shift2D shifter;
                Dalut dalut;
         
             
                shifter = new Shift2D("Shifter",clk,DALUTin,Datain,load);
                dalut = new Dalut("DALUT",constants,clk,DALUTout,DALUTin);
         
       
                  addChild(shifter);
                  addChild(dalut);
                
         
                if(debug)
                    dalut.test_parm();
         
                /* Place the core*/
                Offset shiftOffset;
                Offset dalutOffset;

                // set the core absolute offset
  
                Offset offset = calcAbsoluteOffset();
                
                int ROW = offset.getVerOffset(Gran.CLB);
                int COL = offset.getHorOffset(Gran.CLB);


                shiftOffset = shifter.getRelativeOffset();
                shiftOffset.setVerOffset(Gran.CLB,0);
                shiftOffset.setHorOffset(Gran.CLB,0);

                dalutOffset = dalut.getRelativeOffset();
                dalutOffset.setVerOffset(Gran.CLB,0);
                dalutOffset.setHorOffset(Gran.CLB,(WORD_WIDTH/2));

                PrintDebugMsg("[TOP] Location  Row = "+ ROW + " Col " + COL);

                /* Implement RTPCores */
                shifter.implement();
                dalut.implement();
         
         
                /* Connect Top level nets */
                try {
                    Bitstream.connect(clk);
                    Bitstream.connect(DALUTin);
                  
         
                } catch ( ConnectionException e) {
                    e.printStackTrace();
                    System.exit(-1);
                }




//                 /* 
//                  * Define SYM pins.
//                  */
//                 try {
//                     //            SYM.add(clk);
//                     //            SYM.add(load);
//                     //           SYM.add(Din);
//                     SYM.add(DALUTin);
//                     SYM.add(DALUTout);
           

//                 } catch (SYMexception se) {
//                     System.out.println(se);
//                 }

//                 CoreOutput.writeSymFile("InternalDAF.sym");


            }
        catch(Exception e)
            {

                System.out.println(e);
                System.exit(-1);
            }




        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;


        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)
    {


        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,int taps)
    {
    
        return (taps/2);
    }/*calcHeight(int wordsize,int taps)*/


    /////////////////////////////
    /** calculates core width
     * @param  wordsize     word size
     * @param taps no of filter taps (no of constants)
     */
    public static int calcWidth(int wordsize,int taps)
    {
        return (wordsize/2)+1;
    }/*calcWidth(int wordsize,int taps)*/

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

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



}
