#include  <time.h>
#include  <stdio.h>
#include  <string.h>

#include  <genlib.h>

#include   DUT_H
#include  "dplimits.h"
#include  "pdfft.h"


/*      Alliance CAD System 2.0                                   */
/*        FITPATH Package 0.0                                     */
/*                                                                */
/*  Author  :      Jean-Paul CHAPUT                               */
/*  E-mail  :  cao-vlsi@masi.ibp.fr                               */
/* ************************************************************** */
/*  module  :  "pdfft.c"                                          */


/* Module internal constants. */
#define        E_PDFFT_WIDTH         2
#define        E_PDFFT_SLICE         3
#define        E_PDFFT_NOVIEW        4
#define        E_PDFFT_OPENVBE       5
#define        E_PDFFT_MODELNAME     6


/* Names of tristate leaf cells. */
static char *TablLeafCellPdfft[5] = { "pdffb7_fp",
									  "pdffp7_fp",
									  "pdffi7_fp",
									  "pdffq7_fp",
									  "pdffj7_fp"};


/* Interface function of module.
   extern       char *Dgn_DispachPdfft();
   */

/* Internal functions of module. */
static       void  Dgn_ErrorPdfft();
static       void  Dgn_VhdlPdfft();
static       void  Dgn_NetlistPdfft();


/*  Function  :  'Dgn_DispatchPdfft'                              */
/* -------------------------------------------------------------- */
/*  Interface scannable D flip-flops generator.                   */

extern char *Dgn_DispatchPdfft(pdfft_modelname,
							   pdfft_width    ,
							   pdfft_slice    ,
							   pdfft_msb0     ,
							   pdfft_vhdl     ,
							   pdfft_netlist  ,
							   pdfft_icon     )
	char *pdfft_modelname;  /* Model name.                    */
	long  pdfft_width;      /* Bus wide.                      */
	long  pdfft_slice;      /* LSB starting slice.            */
	long  pdfft_msb0;       /* Zero as MSB index.             */
	long  pdfft_vhdl;       /* Generation of behavioral view. */
	long  pdfft_netlist;    /* Generation of netlist view.    */
	long  pdfft_icon;       /* Generation of icon.            */
{
	static short  DispachPdfft_FirstCall = FALSE;
	static  char  ModelName[C_SUPP_MBKSZNAME];

	/* The first time the generator is call : */
	/*     - Load specific errors.            */
	if (!DispachPdfft_FirstCall)
	{
		Dgn_ErrorPdfft();
		DispachPdfft_FirstCall = TRUE;
	}

	/* Check if, at least, one view is asked. */
	if (   (pdfft_netlist == FALSE)
		 &&(pdfft_vhdl    == FALSE)
		 &&(pdfft_icon    == FALSE) )
		Dut_PrintError( E_PDFFT_ERROR, E_PDFFT_NOVIEW);

	/* Check the bus wide. */
	if ((pdfft_width < 2) || (pdfft_width > DP_WIDTH))
		Dut_PrintError( E_PDFFT_ERROR, E_PDFFT_WIDTH, pdfft_width);

	/* Check the LSB starting slice. */
	if ((pdfft_slice < 0) || ( pdfft_slice
							 +pdfft_width > DP_WIDTH))
		Dut_PrintError( E_PDFFT_ERROR, E_PDFFT_SLICE, pdfft_slice);

	/* Check the model name. */
	if (pdfft_modelname == (char*)NULL)
		/* Build a more explicit model name. */
		(void*)sprintf( ModelName, "pdfft_%ldx%ldx%ld%c_cl"  ,
					                   DP_WIDTH              ,
					                pdfft_width              ,
					                pdfft_slice              ,
					              ((pdfft_msb0 ) ? 'm' : 'l'));
	else
		strcpy( ModelName, pdfft_modelname);

	/* Generation of behaviorial view. */
	if (pdfft_vhdl)
		Dgn_VhdlPdfft(ModelName  ,
			   		  pdfft_width,
					  pdfft_slice,
			   		  pdfft_msb0 );

	/* Generation of netlist view. */
	if (pdfft_netlist)
		Dgn_NetlistPdfft(ModelName  ,
						 pdfft_width,
						 pdfft_slice,
						 pdfft_msb0 );

	/* Generation of icon. */
	/* if (pdfft_icon) */
	
	/* Return name of the generated model. */
	return((pdfft_modelname == (char*)NULL) ?       ModelName 
		                                    : pdfft_modelname);
}


/*  Function  :  'Dgn_ErrorPdfft'                                  */
/* -------------------------------------------------------------- */
/*  Adds generator specific errors to the main errors data base.  */

static void  Dgn_ErrorPdfft()
{
	Dut_AddError( E_PDFFT_ERROR, E_PDFFT_WIDTH,
				  "invalid bus width : %ld.");
	Dut_AddError( E_PDFFT_ERROR, E_PDFFT_SLICE,
				  "invalid LSB starting slice : %ld.");
	Dut_AddError( E_PDFFT_ERROR, E_PDFFT_MODELNAME,
				  "Missing model name.");
	Dut_AddError( E_PDFFT_ERROR, E_PDFFT_NOVIEW,
				  "No view to generate.");
	Dut_AddError( E_PDFFT_ERROR, E_PDFFT_OPENVBE,
				  "Unable to create file : \"%s\".");
}


/*  Function  :  'Dgn_NetListPdfft'                               */
/* -------------------------------------------------------------- */
/*  Generation scannable D flip-flops behavioral view.            */

static void  Dgn_VhdlPdfft(pdfft_modelname,
						   pdfft_width    ,
						   pdfft_slice    ,
						   pdfft_msb0     )
	char *pdfft_modelname;  /* Model name.         */
	long  pdfft_width;      /* Bus width.          */
	long  pdfft_slice;      /* LSB starting slice. */
	long  pdfft_msb0;       /* Zero as MSB index.  */
{
	FILE *PdfftFile;
	long  ConIndex;
	long  BitIndex,     LenString,      TmpTime;
	char  BusWide[  256],
	      BusWideQ[ 256], 
	      PinNameQS[256], TmpString[256];

	/* *** Creating the file holding behavioral view. *** */
	if ((PdfftFile=mbkfopen(pdfft_modelname,
						              "vbe",
						         WRITE_TEXT)) == (FILE*)NULL)
		Dut_PrintError( E_PDFFT_ERROR, E_PDFFT_OPENVBE,
					                   pdfft_modelname);


	/* *** Write an identification header *** */

	/* Standart begin of header. */
	fprintf( PdfftFile, 
"-- ###-------------------------------------------------------------###\n"
			);
	fprintf( PdfftFile, 
"-- #                                                                 #\n"
			);
	fprintf( PdfftFile,
"-- #    Alliance CAD System 2.0                                      #\n"
			);
    fprintf( PdfftFile,
"-- #      FITPATH Package 0.0                                        #\n"
			);
    fprintf( PdfftFile,
"-- #                                                                 #\n"
			);
    fprintf( PdfftFile,
"-- # Author :     Jean-Paul CHAPUT                                   #\n" 
			);
    fprintf( PdfftFile,
"-- # E-mail : cao-vlsi@masi.ibp.fr                                   #\n"
			);
	fprintf( PdfftFile, 
"-- # *************************************************************** #\n"
			);
	fprintf( PdfftFile,
"-- #                                                                 #\n"
			);
    fprintf( PdfftFile,
"-- # Generator : \"pdfftg\" (Scannable D Flip-Flop)                    #\n"
			);
	fprintf( PdfftFile, 
"-- # --------------------------------------------------------------- #\n"
			);

	/* Print name of the generated file. */
	sprintf(  TmpString, "\"%s.vbe\"."            ,pdfft_modelname);
    fprintf( PdfftFile  , "-- # File : %-55s  #\n",      TmpString);
	fprintf( PdfftFile,
"-- #                                                                 #\n"
			);

	/* Print date of generation. */
	TmpTime                = time((time_t*)NULL);
	sprintf( TmpString, "%s", asctime(localtime(&TmpTime)) );
	LenString              = strlen( TmpString);
	TmpString[LenString-1] = (char)0;
    fprintf( PdfftFile  , "-- #           Date : %-45s  #\n", TmpString);

	/* Give the call used to generate the model. */
	sprintf(  TmpString, "\"pdfftg %ld %ld %ld%s -vhdl -o %s\"" ,
			                      DP_WIDTH                      ,
			                   pdfft_width                      ,
			                   pdfft_slice                      ,
			                  (pdfft_msb0     ) ? " -msb0"  : "",
			                   pdfft_modelname                  );
    fprintf( PdfftFile  , "-- # Generator Call : %-45s  #\n", TmpString);

	fprintf( PdfftFile, 
"-- ###-------------------------------------------------------------###\n"
			);


	/* Select terminals (and signals) bus indexation. */
	/* (depending to the flag "pdfft_msb0")            */
	if (!pdfft_msb0)
	{
		sprintf( BusWide ,  "(%ld downto %ld)", pdfft_width-1
				                               +pdfft_slice  ,
				                                pdfft_slice  );
		sprintf( PinNameQS, "q%ld"            , pdfft_width-1
				                               +pdfft_slice  );
		sprintf( BusWideQ , "(%ld downto %ld)", pdfft_width-2
				                               +pdfft_slice  ,
				                                pdfft_slice  );
	}
	else
	{
		sprintf( BusWide  ,   "(%ld to %ld)", DP_WIDTH-pdfft_slice
				                                      -pdfft_width  ,
				                              DP_WIDTH-pdfft_slice-1);
		sprintf( PinNameQS,   "q%ld"        , DP_WIDTH-pdfft_slice
				                                      -pdfft_width  );
		sprintf( BusWideQ ,   "(%ld to %ld)", DP_WIDTH-pdfft_slice
				                                      -pdfft_width+1,
				                              DP_WIDTH-pdfft_slice-1);
	}


	/* *** Interface description. *** */
	fprintf( PdfftFile, "\nENTITY %s IS\n\tPORT(\n", pdfft_modelname);

	/* Controls terminals. */
	fprintf( PdfftFile, "%14s : in    BIT;\n",  "scin");
	fprintf( PdfftFile, "%14s :   out BIT;\n", "scout");
	fprintf( PdfftFile, "%14s : in    BIT;\n",  "test");
	fprintf( PdfftFile, "%14s : in    BIT;\n",   "wen");
	fprintf( PdfftFile, "%14s : in    BIT;\n",    "ck");

	/* Terminals of data pdffts. */
	fprintf( PdfftFile, "%14s : in    BIT_VECTOR%s;\n",  "d", BusWide  );
	fprintf( PdfftFile, "%14s : inout BIT;\n"         ,       PinNameQS);
	fprintf( PdfftFile, "%14s :   out BIT_VECTOR%s;\n",  "q", BusWideQ );
	fprintf( PdfftFile, "%14s :   out BIT_VECTOR%s;\n", "nq", BusWide  );

	/* Supplies terminals. */
	fprintf( PdfftFile, "%14s :  in BIT;\n", "vdd");
	fprintf( PdfftFile, "%14s :  in BIT\n" , "vss");

	/* *** End of interface description *** */
	fprintf( PdfftFile, "\t);\nEND %s;\n\n\n", pdfft_modelname);


	/* *** Behavioral view *** */
	fprintf( PdfftFile, "ARCHITECTURE behaviour_data_flow OF %s IS\n\n",
			                                            pdfft_modelname);
	
	/* Internal signals declaration. */
	fprintf( PdfftFile, "\tSIGNAL ten : BIT;\n");
	fprintf( PdfftFile, "\tSIGNAL den : BIT;\n");
	fprintf( PdfftFile, "\tSIGNAL cks : BIT;\n");
	/* Internal register declaration. */
	for( BitIndex=pdfft_slice; 
		 BitIndex<pdfft_slice+pdfft_width; BitIndex++)
	{
		fprintf( PdfftFile, "\tSIGNAL inst_pdfft_%ld_memm_s", BitIndex);
	    fprintf( PdfftFile, ": REG_BIT REGISTER;\n"      );
		fprintf( PdfftFile, "\tSIGNAL inst_pdfft_%ld_mems_s", BitIndex);
	    fprintf( PdfftFile, ": REG_BIT REGISTER;\n"      );
	}

	fprintf( PdfftFile, "\nBEGIN\n\n");

	/* *** Compute internal signals *** */
	fprintf( PdfftFile, "\tten <=     ck and      test;\n");
	fprintf( PdfftFile, "\tden <=     ck and (not test) and wen;\n");
	fprintf( PdfftFile, "\tcks <= not ck;\n\n");

	/* *** Write D flip-flops when in test mode *** */
	fprintf( PdfftFile, "\twt:BLOCK(ten) BEGIN\n ");
	/* Loop on bus wide. */
	for( BitIndex=pdfft_slice; 
		 BitIndex<pdfft_slice+pdfft_width; BitIndex++)
	{
		fprintf( PdfftFile, "\t\tinst_pdfft_%ld_memm_s <= GUARDED ", BitIndex);

		if (BitIndex == pdfft_slice)
			fprintf( PdfftFile, "scin;\n");
		else
			fprintf( PdfftFile, "inst_pdfft_%ld_mems_s;\n", BitIndex-1);
	}
	fprintf( PdfftFile, "\tEND BLOCK wt;\n\n");

	/* *** Write D flip-flops when in normal mode *** */
	fprintf( PdfftFile, "\twd:BLOCK(den) BEGIN\n");
	/* Loop on bus wide. */
	for( BitIndex=pdfft_slice; 
		 BitIndex<pdfft_slice+pdfft_width; BitIndex++)
	{
		if (!pdfft_msb0) ConIndex =              BitIndex;
		else             ConIndex = DP_WIDTH -1 -BitIndex;

		fprintf( PdfftFile, "\t\tinst_pdfft_%ld_memm_s <= GUARDED ", ConIndex);
		fprintf( PdfftFile,              "d(%ld);\n"               , ConIndex);
	}
	fprintf( PdfftFile, "\tEND BLOCK wd;\n\n");

	/* *** Write slave registers *** */
	fprintf( PdfftFile, "\tws:BLOCK(cks) BEGIN\n");
	for( BitIndex=pdfft_slice; 
		 BitIndex<pdfft_slice+pdfft_width; BitIndex++)
	{
		fprintf( PdfftFile, "\t\tinst_pdfft_%ld_mems_s <= GUARDED ", BitIndex);
		fprintf( PdfftFile, "    inst_pdfft_%ld_memm_s;\n"         , BitIndex);
	}
	fprintf( PdfftFile, "\tEND BLOCK ws;\n\n");
	/* Affect "scout". */
	fprintf( PdfftFile, "\tscout <= inst_pdfft_%ld_mems_s;\n\n",
			                                         BitIndex-1);

	/* *** Affect the outputs. *** */

	/* Loop on bus wide. */
	for( BitIndex=pdfft_slice; 
		 BitIndex<pdfft_slice+pdfft_width-1; BitIndex++)
	{
		if (!pdfft_msb0) ConIndex =              BitIndex;
		else             ConIndex = DP_WIDTH -1 -BitIndex;

		fprintf( PdfftFile, "\t q(%ld) <=     inst_pdfft_%ld_mems_s;\n",
				                                               ConIndex,
				                                               ConIndex);
		fprintf( PdfftFile, "\tnq(%ld) <= not inst_pdfft_%ld_mems_s;\n",
				                                               ConIndex,
				                                               ConIndex);
	}


	if (!pdfft_msb0) ConIndex =              BitIndex;
	else             ConIndex = DP_WIDTH -1 -BitIndex;

	fprintf( PdfftFile, "\t %s <=         inst_pdfft_%ld_mems_s;\n",
			                                              PinNameQS,
			                                               ConIndex,
			                                               ConIndex);
	fprintf( PdfftFile, "\tnq(%ld) <= not inst_pdfft_%ld_mems_s;\n",
			                                               ConIndex,
				                                           ConIndex);


	/* Check supplies connections. */
	fprintf( PdfftFile, "\n\t-- ****************>");
	fprintf( PdfftFile,   " Supplies Check "      );
	fprintf( PdfftFile,   "<****************\n\n" );

	fprintf( PdfftFile, "\tASSERT ((vdd = '1') and (vss = '0'))\n");
	fprintf( PdfftFile, "\t\tREPORT \"Power supply is missing on %s.\"\n",
			                                              pdfft_modelname);
	fprintf( PdfftFile, "\t\tSEVERITY WARNING;\n\n");

	/* *** End of behavioral view *** */
	fprintf( PdfftFile, "END behaviour_data_flow;\n");

	/* *** Close the file holding the behavioral view *** */
	fclose( PdfftFile);
}


/*  Fonction  :  'Dgn_NetListPdfft'                               */
/* -------------------------------------------------------------- */
/*  Generation of Scannable D Flip-Flop Netlist.                  */

static void  Dgn_NetlistPdfft(pdfft_modelname,
							  pdfft_width    ,
							  pdfft_slice    ,
							  pdfft_msb0     )
	char *pdfft_modelname;  /* Model name.         */
	long  pdfft_width;      /* Bus wide.           */
	long  pdfft_slice;      /* LSB starting slice. */
	long  pdfft_msb0;       /* Zero as MSB index.  */
{
	long       BusIndex;
	long  LeafCellIndex;

	char *LeafCellSliceName;
	char *LeafCellBuffrName;
	char  LeafCellInstaName[C_SUPP_MBKSZNAME];

	char  BusNameD[  C_SUPP_MBKSZNAME];
	char  BusNameNQ[ C_SUPP_MBKSZNAME];
	char  BusNameQ[  C_SUPP_MBKSZNAME];
	char  PinNameD[  C_SUPP_MBKSZNAME];
	char  PinNameNQ[ C_SUPP_MBKSZNAME];
	char  PinNameQS[ C_SUPP_MBKSZNAME];
	char  PinNameQ[  C_SUPP_MBKSZNAME];
	char  PinNameTIN[C_SUPP_MBKSZNAME];


	/* Model names (slices and buffer). */

	/* Creation of the new logical figure. */
	DEF_LOFIG( pdfft_modelname);

	/* Name of data bus terminals. */
	if (!pdfft_msb0)
	{
		sprintf( BusNameD , "d[%ld:%ld]", pdfft_width-1
				                         +pdfft_slice  , 
				                          pdfft_slice  );
		sprintf( PinNameQS, "q%ld"      , pdfft_width-1
				                         +pdfft_slice  );
		sprintf( BusNameQ , "q[%ld:%ld]", pdfft_width-2
				                         +pdfft_slice  ,
				                          pdfft_slice  );
		sprintf( BusNameNQ,"nq[%ld:%ld]", pdfft_width-1
				                         +pdfft_slice  ,
				                          pdfft_slice  );
	}
	else
	{
		sprintf( BusNameD , "d[%ld:%ld]", DP_WIDTH-pdfft_slice
				                                  -pdfft_width  ,
				                          DP_WIDTH-pdfft_slice-1);
		sprintf( PinNameQS, "q%ld"      , DP_WIDTH-pdfft_slice
				                                  -pdfft_width);
		sprintf( BusNameQ , "q[%ld:%ld]", DP_WIDTH-pdfft_slice
				                                  -pdfft_width+1,
				                          DP_WIDTH-pdfft_slice-1);
		sprintf( BusNameNQ,"nq[%ld:%ld]", DP_WIDTH-pdfft_slice
				                                  -pdfft_width  ,
				                          DP_WIDTH-pdfft_slice-1);
	}
 
	/* Creation of figure terminals. */
	/* **** Control terminals **** */
	LOCON(    "scin", IN   ,     "scin");
	LOCON(   "scout",   OUT,    "scout");
	LOCON(    "test", IN   ,     "test");
	LOCON(     "wen", IN   ,      "wen");
	LOCON(      "ck", IN   ,       "ck");

	/* **** Data bus terminals **** */
	LOCON( BusNameD , IN   , BusNameD );
	LOCON( PinNameQS,   OUT, PinNameQS);
	LOCON( BusNameQ ,   OUT, BusNameQ );
	LOCON( BusNameNQ,   OUT, BusNameNQ);

	/* **** Supply terminals **** */
	LOCON(     "vdd", INOUT,      "vdd"); 
	LOCON(     "vss", INOUT,      "vss"); 


	/* Instance of bottom column. */	
	LeafCellIndex=pdfft_slice;

	/* Select leaf cell model name. */
	LeafCellSliceName = TablLeafCellPdfft[3+LeafCellIndex%2];

	/* Build leaf cell name. */
	sprintf( LeafCellInstaName, "pdfft_%ld", LeafCellIndex);
		
	/* Compute terminal index. */
	if (!pdfft_msb0) BusIndex =              LeafCellIndex;
	else             BusIndex = DP_WIDTH -1 -LeafCellIndex;

	/* Build signals names. */
	sprintf( PinNameD  ,   "d[%ld]", BusIndex  );
	sprintf( PinNameQ  ,   "q[%ld]", BusIndex  );
	sprintf( PinNameNQ ,  "nq[%ld]", BusIndex  );
	sprintf( PinNameTIN, "tio"     );

	/* Leaf cell instanciation. */
	LOINS( LeafCellSliceName,
		   LeafCellInstaName,
		               "ten",
		          PinNameTIN,
		               "den",
		          PinNameD  ,
		          PinNameQ  ,
		          PinNameNQ ,
		               "cks", "vdd", "vss", EOL);

	
	/* Creation of leaf cells instances. */
	/* ("normals" cells of column)       */
	for( LeafCellIndex=pdfft_slice+1; 
		 LeafCellIndex<pdfft_slice+pdfft_width-1; LeafCellIndex++)
	{
	    /* Select leaf cell model name. */
	    LeafCellSliceName = TablLeafCellPdfft[1+LeafCellIndex%2];

		/* Build leaf cell name. */
		sprintf( LeafCellInstaName, "pdfft_%ld", LeafCellIndex);
		
		/* Compute terminal index. */
		if (!pdfft_msb0) BusIndex =              LeafCellIndex;
		else             BusIndex = DP_WIDTH -1 -LeafCellIndex;

		/* Build signals names. */
		sprintf( PinNameD  ,   "d[%ld]", BusIndex  );
		sprintf( PinNameQ  ,   "q[%ld]", BusIndex  );
		sprintf( PinNameNQ ,  "nq[%ld]", BusIndex  );
		sprintf( PinNameTIN,   "q[%ld]", BusIndex-1);

		/* Leaf cell instanciation. */
		LOINS( LeafCellSliceName,
			   LeafCellInstaName,
			               "ten",
			          PinNameTIN,
			               "tio",
			               "den",
			          PinNameD  ,
			          PinNameQ  ,
			          PinNameNQ ,
			               "cks", "vdd", "vss", EOL);
	}


	/* Last cell of the column (i.e., the MSB). */
	/* Select leaf cell model name. */
	LeafCellSliceName = TablLeafCellPdfft[1+LeafCellIndex%2];

	/* Build leaf cell name. */
	sprintf( LeafCellInstaName, "pdfft_%ld", LeafCellIndex);
		
	/* Compute terminal index. */
	if (!pdfft_msb0) BusIndex =              LeafCellIndex;
	else             BusIndex = DP_WIDTH -1 -LeafCellIndex;

	/* Build signals names. */
	sprintf( PinNameD  ,   "d[%ld]", BusIndex  );
	sprintf( PinNameNQ ,  "nq[%ld]", BusIndex  );
	sprintf( PinNameTIN,   "q[%ld]", BusIndex-1);

	/* Leaf cell instanciation. */
	LOINS( LeafCellSliceName  ,
		   LeafCellInstaName  ,
		               "ten"  ,
		            PinNameTIN,
		               "tio"  ,
		               "den"  ,
		            PinNameD  ,
		            PinNameQS ,
		            PinNameNQ ,
			            "cks" , "vdd", "vss", EOL);


	/* Creation of buffer instance. */

	/* Select buffer model name. */
	LeafCellBuffrName = TablLeafCellPdfft[0];
	/* Build buffer instance name. */
	sprintf( LeafCellInstaName, "bpdfft_%ld", DP_WIDTH);

	/* Buffer instanciation. */
	LOINS( LeafCellBuffrName,
		   LeafCellInstaName,
		              "scin",
		             "scout",
		              "test",
		               "wen",
		                "ck",
		               "ten",
		               "tio",
		           PinNameQS,
		               "den",
		               "cks", "vdd", "vss", VSS, EOL);

	/* Ends and write to disk the new figure. */
	SAVE_LOFIG();
}
