
import  java.io.IOException;

import  com.xilinx.JBits.Virtex.JBits;
import  com.xilinx.JBits.Virtex.Devices;
import  com.xilinx.JBits.Virtex.Util;
import  com.xilinx.JBits.Virtex.ConfigurationException;
import com.xilinx.JBits.Virtex.Bits.*;
import com.xilinx.JBits.Virtex.Expr;
import  com.xilinx.JBits.Virtex.RTPCore.Tags;

import com.xilinx.JRoute.Virtex.Router.Port;
import com.xilinx.JRoute.Virtex.Router.RouterWithPorts;
import com.xilinx.JRoute.Virtex.ResourceDB.Wires;
import com.xilinx.JRoute.Virtex.Router.Pin;
import com.xilinx.JRoute.Virtex.Router.RouteException;

import  MyRTPCore.RecodingConstMult;
import  com.xilinx.JBits.Virtex.RTPCore.ConstantPort;
import  com.xilinx.JBits.Virtex.RTPCore.RegisterPort;
import  com.xilinx.JBits.Virtex.RTPCore.Kcm8;




public class MultTest {



    /**
       A function returning the binary code of an int.
    */
    public static int[] BinaryCode  (int k) {
	int b[] = new int[32];
	int l = 0;
	int kk=k;
	
	while((kk!=0) && (l<32)) {
	    b[l] = kk % 2;
	    l++;
	    kk = kk>>1;
	}
	return b;
    }


    /** This is a function that counts the average number of CLBs 
     for all the possible 16 bit multipliers */

    protected static int exhaustiveTest16(JBits jBits, RouterWithPorts router)
    {
	RecodingConstMult mult;
	int i;
	int s = 0;
	int ls = 0;
	int maxwidth=0;
	for (i=0; i<65535; i++) {
	    mult = new RecodingConstMult (16,16,i);
	    ls = mult.getClbHeight() * mult.getClbWidth();
	    if (mult.getClbWidth()>maxwidth)
		maxwidth = mult.getClbWidth();
	    s = s + ls;
	    System.out.println (i+": "+ls+";   Avg size = " 
				+ ((float)s)/((float) i) +
				" CLBs; max width "+ maxwidth);
	}
	return 0;
    }




    /**
     this is a test function, it instantiates a constant multiplier,
     feeds it a constant value, and connects its output to a register.
     The constant and the output are in the first CLB column, 
     and the multiplier is two CLBs away for readability.
    It returns the width of the multiplier. 
    The size is given in CLBs.
    
    */

    protected static int test(JBits jBits, RouterWithPorts router,
			       int size, int row, int col, int x, int K)
	throws ConfigurationException {
	int i;
	long time1, time2;
	ConstantPort  constant = null;
	RegisterPort output = null;
	RecodingConstMult mult   = null;
	
	// the constant in slice 0, the result in slice 1
	constant = new ConstantPort(2*size, x,0);
	constant.setRouter(router);
	constant.set(jBits, row, col);
	output = new RegisterPort(4*size, 1);
	output.setRouter(router);
	output.set(jBits, row, col);
	
	time1 = System.currentTimeMillis();
	mult = new RecodingConstMult(2*size,2*size, K);
	time1 = System.currentTimeMillis() - time1;
	time2 = System.currentTimeMillis();
	mult.set(jBits, router, row, col+2);
	time2 = System.currentTimeMillis() - time2;
	System.out.println(" Time: " + time1 + " + " + time2 + " ms.");

	// CLB (0,1) will provide a null value
	Pin zero = new Pin(row,col+1,Wires.S0_X);
	// the routing 
 	System.out.println("Wiring the multiplier");
	try {
	    // the X input
	    for (i=0; i<2*size; i++) {
		router.route(constant.getOut()[i], 
			     mult.X[i]);
	    }
	    // the output
	    System.out.println(" Wiring the output port. Width: " 
			       + mult.Out.length);
	    for (i=0; i<4*size; i++) {
		router.route(mult.Out[i], output.getIn()[i]);
		//output.getIn()[i].setDrivenBy(mult.Out[i]);
	    }
	    // the zero input
	    System.out.println(" Wiring the Zero port");
	    router.route(zero, mult.Zero);
	} 
	catch(RouteException a) {
	    System.out.println(a);
	}

	// compute and print the binary code of the expected result
	int b[];
	System.out.print("Result should be ");
	b = BinaryCode(K*x);
	for (i=b.length-1; i>=0; i--)
	    System.out.print(b[i] + " ");
	System.out.println();

	return mult.getClbWidth();
    }
	

/**
**  This is the main program.
**
*/

public static void
main(String  args[]) {
   String  usage = "Usage:  MultTest -<device> <infile.bit> <outfile.bit>.  Exiting.";
   int       result;
   int       i;
   int       size;
   int       bits = 0;
   int       bytes = 0;
   int       row;
   int       col;
   int       clbRows;
   int       clbColumns;
   int       deviceCount;
   int       deviceType = Devices.UNKNOWN_DEVICE;;
   String    infileName = "";
   String    outfileName = "";
   String    deviceName = "";
   JBits     jBits;

   /*
   **  Parse command line parameters
   */

   if (args.length == 3) {
      deviceName = args[0];
      infileName = args[1];
      outfileName = args[2];
      } else {
         System.out.println(usage);
         System.exit(-1);
         }  /* end if() */

   /* Get rid of "-" in device name flag */
   if (deviceName.startsWith("-") == true)
      deviceName = deviceName.substring(1);

   /* Get the device type */
   deviceType = Devices.getDeviceType(deviceName);
   if (deviceType == Devices.UNKNOWN_DEVICE) {
      System.out.println("Did not recognize device type.  Exiting");
      System.exit(-2);
      }

   /* Be sure the device is supported */
   if (Devices.isSupported(deviceType) == false) {
      System.out.println("Unsupported device type.  Exiting");
      System.exit(-3);
      }

   System.out.println("Device:  " + Devices.getDeviceName(deviceType));

   /* Get the device model */
   jBits = new JBits(deviceType);

   /* Read in the bit file */
   System.out.println("Reading in "+infileName+".");
   System.out.println("");

   try {
      jBits.read(infileName);
      } catch (Exception e) {
         System.out.println("Could not read in bitstream from file " +
                            infileName + ".  Exiting.");
         System.exit(-4);
      }  /* end catch() */

   System.out.println("Success reading from bitstream file "+infileName+".");
  
   /*
   **  Construct some objects and write them to the bitstream
   */

   

   try {

	RouterWithPorts router;
	
	// Set up the router object     
	router = new RouterWithPorts(jBits/*, System.out*/);

	long time1 = System.currentTimeMillis();
	//Kcm8 kcm8 = new Kcm8(221);
	//kcm8.set(jBits,10,10);
	time1 = System.currentTimeMillis() - time1;

	System.out.println("********time1 = "+time1);

	//test(jBits, router,4,0,20, 17,221);

	
	test(jBits, router,8,0,4,-10000,58995);
	
	 test(jBits, router,8,0,12,-10000,57344);


// 	// test a few multipliers 	    
// 	for (i=1; i<12; i++)
// 	    test(jBits, router,4,12,4*(i-1),13,i);
   } 
   catch (ConfigurationException ce) {

         System.out.println(ce);
         System.out.println("Exiting.");
	 ce.printStackTrace();
	 System.exit(-5);

      }  /* end catch() */

   /* Write out the bitstream file */
   System.out.println("Writing file " + outfileName + ".");

   try {
      jBits.write(outfileName);
      } catch (IOException  ioe) {
         System.out.println("Error writing file " + outfileName + ".  Exiting.");
         System.exit(-5);
      }  /* end catch() */

   System.out.println("Success writing to " + outfileName + ".");
   
   System.out.println("Exiting.");

   }  /* end main() */



}  /* end class MultTest */




