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

#include  <genlib.h>

#include   DUT_H
#include  "dplimits.h"
#include  "nul.h"


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


/* Module internal constants. */
#define        E_NUL_WIDTH         2
#define        E_NUL_SLICE         3
#define        E_NUL_NOVIEW        4
#define        E_NUL_OPENVBE       5
#define        E_NUL_MODELNAME     6


/* Names of zero detect leaf cells. */
static char *TablLeafCellNul[2] = {   "o2_fp",
								     "no2_fp"};


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

/* Internal functions of module. */
static       void  Dgn_ErrorNul();
static       void  Dgn_VhdlNul();
static       void  Dgn_NetlistNul();


/*  Function  :  'Dgn_DispatchNul'                              */
/* -------------------------------------------------------------- */
/*  Interface of nulants generator.                             */

extern char *Dgn_DispatchNul(nul_modelname,
							   nul_width    ,
							   nul_slice    ,
							   nul_msb0     ,
							   nul_vhdl     ,
							   nul_netlist  ,
							   nul_icon     )
	char *nul_modelname;  /* Model name.                    */
	long  nul_width;      /* Bus wide.                      */
	long  nul_slice;      /* LSB starting slice.            */
	long  nul_msb0;       /* Zero as MSB index.             */
	long  nul_vhdl;       /* Generation of behavioral view. */
	long  nul_netlist;    /* Generation of netlist view.    */
	long  nul_icon;       /* Generation of icon.            */
{
	static short  DispachNul_FirstCall = FALSE;
	static  char  ModelName[C_SUPP_MBKSZNAME];

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

	/* Check if, at least, one view is asked. */
	if (   (nul_netlist == FALSE)
		 &&(nul_vhdl    == FALSE)
		 &&(nul_icon    == FALSE) )
		Dut_PrintError( E_NUL_ERROR, E_NUL_NOVIEW);

	/* Check the bus wide. */
	if ((nul_width < 3) || (nul_width > DP_WIDTH))
		Dut_PrintError( E_NUL_ERROR, E_NUL_WIDTH, nul_width);

	/* Check the LSB starting slice. */
	if ((nul_slice < 0) || (nul_slice+nul_width > DP_WIDTH))
		Dut_PrintError( E_NUL_ERROR, E_NUL_SLICE, nul_slice);

	/* Check the model name. */
	if (nul_modelname == (char*)NULL)
		/* Build a more explicit model name. */
		(void*)sprintf( ModelName, "nul_%ldx%ldx%ld%c_cl"   ,
					                      DP_WIDTH              ,
					                nul_width              ,
					                nul_slice              ,
					              ((nul_msb0 ) ? 'm' : 'l'));
	else
		strcpy( ModelName, nul_modelname);

	/* Generation of behaviorial view. */
	if (nul_vhdl)
		Dgn_VhdlNul( ModelName      ,
						  nul_width ,
						  nul_slice ,
						  nul_msb0  );

	/* Generation of netlist view. */
	if (nul_netlist)
		Dgn_NetlistNul( ModelName      ,
							 nul_width ,
							 nul_slice ,
							 nul_msb0  );

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


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

static void  Dgn_ErrorNul()
{
	Dut_AddError( E_NUL_ERROR, E_NUL_WIDTH,
				  "invalid bus width : %ld.");
	Dut_AddError( E_NUL_ERROR, E_NUL_SLICE,
				  "invalid LSB starting slice : %ld.");
	Dut_AddError( E_NUL_ERROR, E_NUL_MODELNAME,
				  "Missing model name.");
	Dut_AddError( E_NUL_ERROR, E_NUL_NOVIEW,
				  "No view to generate.");
	Dut_AddError( E_NUL_ERROR, E_NUL_OPENVBE,
				  "Unable to create file : \"%s\".");
}


/*  Function  :  'Dgn_NetListNul'                           */
/* -------------------------------------------------------------- */
/*  Generation of NOR2 cotrollable cons behavioral view.         */

static void  Dgn_VhdlNul(nul_modelname,
							  nul_width    ,
							  nul_slice    ,
							  nul_msb0     )
	char *nul_modelname;  /* Model name.         */
	long  nul_width;      /* Bus width.          */
	long  nul_slice;      /* LSB starting slice. */
	long  nul_msb0;       /* Zero as MSB index.  */
{
	FILE *NulFile;
	long  BitIndex,     LenString,      TmpTime;
	long *xlnul, XlIndex;
	char  BusWide[256], TmpString[256];

	/* *** Creating the file holding behavioral view. *** */
	if ((NulFile=mbkfopen(nul_modelname,
							                "vbe",
						               WRITE_TEXT)) == (FILE*)NULL)
		Dut_PrintError( E_NUL_ERROR, E_NUL_OPENVBE,
					                      nul_modelname);


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

	/* Standart begin of header. */
	fprintf( NulFile, 
"-- ###-------------------------------------------------------------###\n"
			);
	fprintf( NulFile, 
"-- #                                                                 #\n"
			);
	fprintf( NulFile,
"-- #    Alliance CAD System 2.0                                      #\n"
			);
    fprintf( NulFile,
"-- #      FITPATH Package 0.0                                        #\n"
			);
    fprintf( NulFile,
"-- #                                                                 #\n"
			);
    fprintf( NulFile,
"-- # Author :     Jean-Paul CHAPUT                                   #\n" 
			);
    fprintf( NulFile,
"-- # E-mail : cao-vlsi@masi.ibp.fr                                   #\n"
			);
	fprintf( NulFile, 
"-- # *************************************************************** #\n"
			);
	fprintf( NulFile,
"-- #                                                                 #\n"
			);
    fprintf( NulFile,
"-- # Generator : \"nulg\" (zero detect generator)                      #\n"
			);
	fprintf( NulFile, 
"-- # --------------------------------------------------------------- #\n"
			);

	/* Print name of the generated file. */
	fprintf( NulFile, 
"-- # File  :                                                         #\n"
			);
	sprintf(      TmpString, "\"%s.vbe\"."   , nul_modelname);
    fprintf( NulFile  , "-- # %62s  #\n",          TmpString);
	fprintf( NulFile  ,
"-- #                                                                 #\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( NulFile, "-- #           Date : %-45s  #\n", TmpString);

	/* Give the call used to generate the model. */
	sprintf(  TmpString, "\"nulg %ld %ld %ld",
			                      DP_WIDTH        ,
			                nul_width        ,
			                nul_slice        );
    fprintf( NulFile  , "-- # Generator Call : %-45s  #\n", TmpString);
	sprintf(  TmpString, "%s -vhdl"                        ,
			             (nul_msb0  ) ? " -msb0"  : ""  );
    fprintf( NulFile  , "-- # %62s  #\n",          TmpString);
	sprintf(      TmpString, "-o %s\""       , nul_modelname);
    fprintf( NulFile  , "-- # %62s  #\n",          TmpString);

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


	/* Select terminals (and signals) bus indexation. */
	/* (depending to the flag "nul_msb0")            */
	if (!nul_msb0)
		sprintf( BusWide, "(%ld downto %ld)", nul_width-1
				                             +nul_slice  ,
				                              nul_slice  );
	else
		sprintf( BusWide,     "(%ld to %ld)", DP_WIDTH-nul_slice
				                                      -nul_width  ,
				                              DP_WIDTH-nul_slice-1);


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

	/* Controls terminals. */

	/* Terminals of data nuls. */
	fprintf( NulFile, "%14s : in    BIT_VECTOR%s;\n",  "i0", BusWide);
	fprintf( NulFile, "%14s :   out BIT;\n"         ,   "o");

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

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


	/* *** Behavioral view *** */
	fprintf( NulFile, "ARCHITECTURE behaviour_data_flow OF %s IS\n\n",
			                                            nul_modelname);
	fprintf( NulFile, "BEGIN\n\n");

	xlnul = Dut_XlAlloc();
	for( XlIndex=0; XlIndex < C_SUPP_XLSIZE; XlIndex++)
		Dut_XlSetLong( xlnul, XlIndex, 0L);

	fprintf( NulFile, "\to <= \'1\' WHEN (i0%s = %s) ELSE \'0\';\n\n",
			                                                  BusWide,
			                         Dut_XlToStrVHDL(xlnul,nul_width));

	Dut_XlFree( xlnul);

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

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

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

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


/*  Fonction  :  'Dgn_NetListNul'                               */
/* -------------------------------------------------------------- */
/*  Generation of NOR2 cotrollable cons Netlist.                  */

static void  Dgn_NetlistNul(nul_modelname,
								 nul_width    ,
								 nul_slice    ,
								 nul_msb0     )
	char *nul_modelname;  /* Model name.         */
	long  nul_width;      /* Bus wide.           */
	long  nul_slice;      /* LSB starting slice. */
	long  nul_msb0;       /* Zero as MSB index.  */
{
	long        BitNumber;
	long        BusIndex;
	long   LeafCellIndex;
	long  SigUnusedIndex = 0L;

	char *LeafCellSliceName;
	char  LeafCellInstaName[C_SUPP_MBKSZNAME];

	char  BusNameI0[   C_SUPP_MBKSZNAME];
	char  ConNameO[    C_SUPP_MBKSZNAME];
	char  PinNameI0[   C_SUPP_MBKSZNAME];
	char  SigInternIN[ C_SUPP_MBKSZNAME];
	char  SigInternOUT[C_SUPP_MBKSZNAME];
	char  SigUnused[   C_SUPP_MBKSZNAME];


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

	/* Name of data bus terminals. */
	sprintf( ConNameO , "o");
	if (!nul_msb0)
		sprintf( BusNameI0, "i0[%ld:%ld]", nul_width-1
				                          +nul_slice  ,
				                           nul_slice  );
	else
		sprintf( BusNameI0, "i0[%ld:%ld]", DP_WIDTH-nul_slice
				                                   -nul_width  ,
				                           DP_WIDTH-nul_slice-1);
 
	/* Creation of figure terminals. */
	/* **** Control terminals **** */

	/* **** Data bus terminals **** */
	LOCON( BusNameI0, IN   , BusNameI0);
	LOCON( ConNameO ,   OUT, ConNameO );

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

	
	LeafCellSliceName = TablLeafCellNul[0];


	/* First cell of ZERO detect. */
	LeafCellIndex = nul_slice+1;
	
	/* Build leaf cell name. */
	sprintf( LeafCellInstaName, "nul_%ld", LeafCellIndex);
		
	/* Compute terminal index. */
	if (!nul_msb0) BusIndex =              LeafCellIndex;
	else           BusIndex = DP_WIDTH -1 -LeafCellIndex;

	/* Build signals names. */
	sprintf( PinNameI0   ,     "i0[%ld]", BusIndex+((nul_msb0) ? 1 : (-1)));
	sprintf( SigInternIN ,     "i0[%ld]", BusIndex                       );
	sprintf( SigInternOUT, "nul_sig%ld" , LeafCellIndex                  );
	sprintf( SigUnused   , "nul_unused%ld", SigUnusedIndex++);

	/* Leaf cell instanciation. */
	LOINS(LeafCellSliceName,
		  LeafCellInstaName,
		       PinNameI0   , 
		       SigInternIN ,
		       SigUnused   ,
		       SigInternOUT, "vdd", "vss", EOL);
	
	/* Creation of leaf cells instances. */
	/* ("normals" cells of column)       */
	for( LeafCellIndex=nul_slice          +2;
		 LeafCellIndex<nul_slice+nul_width-1;
		 LeafCellIndex++                    )
	{
		/* Build leaf cell name. */
		sprintf( LeafCellInstaName, "nul_%ld", LeafCellIndex);
		
		/* Compute terminal index. */
		if (!nul_msb0) BusIndex =              LeafCellIndex;
		else           BusIndex = DP_WIDTH -1 -LeafCellIndex;

		/* Build signals names. */
		sprintf( PinNameI0   ,     "i0[%ld]",      BusIndex  );
		sprintf( SigInternIN , "nul_sig%ld" , LeafCellIndex-1);
		sprintf( SigInternOUT, "nul_sig%ld" , LeafCellIndex  );
		sprintf( SigUnused   , "nul_unused%ld", SigUnusedIndex++);

		/* Leaf cell instanciation. */
		LOINS( LeafCellSliceName,
			   LeafCellInstaName,
				    PinNameI0   , 
			        SigInternIN ,
			        SigUnused   ,
			        SigInternOUT, "vdd", "vss", EOL);
	}


	LeafCellSliceName = TablLeafCellNul[1];


	/* First cell of ZERO detect. */
	/* LeafCellIndex = nul_slice+nul_width-1; */
	
	/* Build leaf cell name. */
	sprintf( LeafCellInstaName, "nul_%ld", LeafCellIndex);
		
	/* Compute terminal index. */
	if (!nul_msb0) BusIndex =              LeafCellIndex;
	else           BusIndex = DP_WIDTH -1 -LeafCellIndex;

	/* Build signals names. */
	sprintf( PinNameI0   ,     "i0[%ld]",      BusIndex  );
	sprintf( SigInternIN , "nul_sig%ld" , LeafCellIndex-1);
	sprintf( ConNameO    ,       "o"    );

	/* Leaf cell instanciation. */
	LOINS(LeafCellSliceName,
		  LeafCellInstaName,
		       PinNameI0   , 
		       SigInternIN ,
		       ConNameO    , "vdd", "vss", EOL);

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