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

#include  <genlib.h>

#include   DUT_H
#include  "dplimits.h"
#include  "xnor2mask.h"


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


/* Module internal constants. */
#define        E_XNOR2MASK_WIDTH         2
#define        E_XNOR2MASK_SLICE         3
#define        E_XNOR2MASK_NOVIEW        4
#define        E_XNOR2MASK_OPENVBE       5
#define        E_XNOR2MASK_MODELNAME     6


/* Names of tristate leaf cells. */
static char *TablLeafCellXnor2mask[3] = { "bnxr2x_fp",
									       "nxr2x_fp",
										  "n1xr2x_fp"};


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

/* Internal functions of module. */
static       void  Dgn_ErrorXnor2mask();
static       void  Dgn_VhdlXnor2mask();
static       void  Dgn_NetlistXnor2mask();


/*  Function  :  'Dgn_DispatchXnor2mask'                          */
/* -------------------------------------------------------------- */
/*  Interface of controllable XNOR2 mask generator.               */

extern char *Dgn_DispatchXnor2mask(xnor2mask_modelname,
								   xnor2mask_width    ,
								   xnor2mask_slice    ,
								   xnor2mask_xlmask   ,
								   xnor2mask_msb0     ,
								   xnor2mask_vhdl     ,
								   xnor2mask_netlist  ,
								   xnor2mask_icon     )
	char *xnor2mask_modelname;  /* Model name.                    */
	long  xnor2mask_width;      /* Bus wide.                      */
	long  xnor2mask_slice;      /* LSB starting slice.            */
	long *xnor2mask_xlmask;     /* Mask to apply.                 */
	long  xnor2mask_msb0;       /* Zero as MSB index.             */
	long  xnor2mask_vhdl;       /* Generation of behavioral view. */
	long  xnor2mask_netlist;    /* Generation of netlist view.    */
	long  xnor2mask_icon;       /* Generation of icon.            */
{
	static short  DispachXnor2mask_FirstCall = FALSE;
	static  char  ModelName[C_SUPP_MBKSZNAME];

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

	/* Check if, at least, one view is asked. */
	if (   (xnor2mask_netlist == FALSE)
		 &&(xnor2mask_vhdl    == FALSE)
		 &&(xnor2mask_icon    == FALSE) )
		Dut_PrintError( E_XNOR2MASK_ERROR, E_XNOR2MASK_NOVIEW);

	/* Check the bus wide. */
	if ((xnor2mask_width < 1) || (xnor2mask_width > DP_WIDTH))
		Dut_PrintError( E_XNOR2MASK_ERROR,
					    E_XNOR2MASK_WIDTH,
					      xnor2mask_width);

	/* Check the LSB starting slice. */
	if ((xnor2mask_slice < 0) || ( xnor2mask_slice
							     +xnor2mask_width > DP_WIDTH))
		Dut_PrintError( E_XNOR2MASK_ERROR,
					    E_XNOR2MASK_SLICE,
					      xnor2mask_slice);

	/* Check the model name. */
	if (xnor2mask_modelname == (char*)NULL)
		/* Build a more explicit model name. */
		(void*)sprintf( ModelName, "xnor2m%s_%ldx%ldx%ld%c_cl"   ,
					    Dut_XlToStr(xnor2mask_xlmask,
									       DP_WIDTH ,
							  C_SUPP_BaseHexadecimal)            ,
					                       DP_WIDTH              ,
					                xnor2mask_width              ,
					                xnor2mask_slice              ,
					              ((xnor2mask_msb0 ) ? 'm' : 'l'));
	else
		strcpy( ModelName, xnor2mask_modelname);

	/* Generation of behaviorial view. */
	if (xnor2mask_vhdl)
		Dgn_VhdlXnor2mask( ModelName      ,
						   xnor2mask_width ,
						   xnor2mask_slice ,
						   xnor2mask_xlmask,
						   xnor2mask_msb0  );

	/* Generation of netlist view. */
	if (xnor2mask_netlist)
		Dgn_NetlistXnor2mask( ModelName       ,
							  xnor2mask_width ,
							  xnor2mask_slice ,
							  xnor2mask_xlmask,
							  xnor2mask_msb0  );

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


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

static void  Dgn_ErrorXnor2mask()
{
	Dut_AddError( E_XNOR2MASK_ERROR, E_XNOR2MASK_WIDTH,
				  "invalid bus width : %ld.");
	Dut_AddError( E_XNOR2MASK_ERROR, E_XNOR2MASK_SLICE,
				  "invalid LSB starting slice : %ld.");
	Dut_AddError( E_XNOR2MASK_ERROR, E_XNOR2MASK_MODELNAME,
				  "Missing model name.");
	Dut_AddError( E_XNOR2MASK_ERROR, E_XNOR2MASK_NOVIEW,
				  "No view to generate.");
	Dut_AddError( E_XNOR2MASK_ERROR, E_XNOR2MASK_OPENVBE,
				  "Unable to create file : \"%s\".");
}


/*  Function  :  'Dgn_NetListXnor2mask'                           */
/* -------------------------------------------------------------- */
/*  Generation of XNOR2 cotrollable mask behavioral view.         */

static void  Dgn_VhdlXnor2mask(xnor2mask_modelname,
							   xnor2mask_width    ,
							   xnor2mask_slice    ,
							   xnor2mask_xlmask   ,
							   xnor2mask_msb0     )
	char *xnor2mask_modelname;  /* Model name.         */
	long  xnor2mask_width;      /* Bus width.          */
	long  xnor2mask_slice;      /* LSB starting slice. */
	long *xnor2mask_xlmask;     /* Mask to apply.      */
	long  xnor2mask_msb0;       /* Zero as MSB index.  */
{
	FILE *Xnor2maskFile;
	long  BitIndex,     LenString,      TmpTime;
	char  BusWide[256], TmpString[256];

	/* *** Creating the file holding behavioral view. *** */
	if ((Xnor2maskFile=mbkfopen(xnor2mask_modelname,
							                  "vbe",
						                 WRITE_TEXT)) == (FILE*)NULL)
		Dut_PrintError( E_XNOR2MASK_ERROR, E_XNOR2MASK_OPENVBE,
					                         xnor2mask_modelname);


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

	/* Standart begin of header. */
	fprintf( Xnor2maskFile, 
"-- ###-------------------------------------------------------------###\n"
			);
	fprintf( Xnor2maskFile, 
"-- #                                                                 #\n"
			);
	fprintf( Xnor2maskFile,
"-- #    Alliance CAD System 2.0                                      #\n"
			);
    fprintf( Xnor2maskFile,
"-- #      FITPATH Package 0.0                                        #\n"
			);
    fprintf( Xnor2maskFile,
"-- #                                                                 #\n"
			);
    fprintf( Xnor2maskFile,
"-- # Author :     Jean-Paul CHAPUT                                   #\n" 
			);
    fprintf( Xnor2maskFile,
"-- # E-mail : cao-vlsi@masi.ibp.fr                                   #\n"
			);
	fprintf( Xnor2maskFile, 
"-- # *************************************************************** #\n"
			);
	fprintf( Xnor2maskFile,
"-- #                                                                 #\n"
			);
    fprintf( Xnor2maskFile,
"-- # Generator : \"xnor2maskg\" (non-inverter tristate)                 #\n"
			);
	fprintf( Xnor2maskFile, 
"-- # --------------------------------------------------------------- #\n"
			);

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

	/* Give the call used to generate the model. */
	sprintf(  TmpString, "\"xnor2maskg %ld %ld %ld",
			                       DP_WIDTH        ,
			                xnor2mask_width        ,
			                xnor2mask_slice        );
    fprintf( Xnor2maskFile  , "-- # Generator Call : %-45s  #\n", TmpString);
	sprintf(  TmpString, "%s%s -vhdl"                         ,
			  Dut_XlToStr(xnor2mask_xlmask,
						  xnor2mask_width ,
				    C_SUPP_BaseHexadecimal)                   ,
			             (xnor2mask_msb0  ) ? " -msb0"  : ""  );
    fprintf( Xnor2maskFile  , "-- # %62s  #\n",          TmpString);
	sprintf(      TmpString, "-o %s\""       , xnor2mask_modelname);
    fprintf( Xnor2maskFile  , "-- # %62s  #\n",          TmpString);

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


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


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

	/* Controls terminals. */
	fprintf( Xnor2maskFile, "%14s :  in BIT;\n",  "msk");

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

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

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


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

	fprintf( Xnor2maskFile,     "\tWITH msk SELECT\n"               );
	fprintf( Xnor2maskFile,   "\t\to%s <=\n"                        , BusWide);
	fprintf( Xnor2maskFile, "\t\t\tnot  i0%s         WHEN '0',\n"   , BusWide);
	fprintf( Xnor2maskFile, "\t\t\tnot (i0%s xor %s) WHEN '1';\n\n" , BusWide,
			                 Dut_XlToStrVHDL(xnor2mask_xlmask,xnor2mask_width));

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

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

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

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


/*  Fonction  :  'Dgn_NetListXnor2mask'                           */
/* -------------------------------------------------------------- */
/*  Generation of XNOR2 cotrollable mask Netlist.                 */

static void  Dgn_NetlistXnor2mask(xnor2mask_modelname,
								  xnor2mask_width    ,
								  xnor2mask_slice    ,
								  xnor2mask_xlmask   ,
								  xnor2mask_msb0     )
	char *xnor2mask_modelname;  /* Model name.         */
	long  xnor2mask_width;      /* Bus wide.           */
	long  xnor2mask_slice;      /* LSB starting slice. */
	long *xnor2mask_xlmask;     /* Mask to apply.      */
	long  xnor2mask_msb0;       /* Zero as MSB index.  */
{
	long       BitNumber;
	long       MskValue;
	long       BusIndex;
	long  LeafCellIndex;

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

	char  BusNameI0[C_SUPP_MBKSZNAME];
	char  BusNameO[ C_SUPP_MBKSZNAME];
	char  PinNameI0[C_SUPP_MBKSZNAME];
	char  PinNameO[ C_SUPP_MBKSZNAME];


	/* Model names (slices and buffer). */
	LeafCellBuffrName = TablLeafCellXnor2mask[0];

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

	/* Name of data bus terminals. */
	if (!xnor2mask_msb0)
	{
		sprintf( BusNameI0,"i0[%ld:%ld]", xnor2mask_width-1
				                         +xnor2mask_slice  ,
				                          xnor2mask_slice  );
		sprintf( BusNameO , "o[%ld:%ld]", xnor2mask_width-1
				                         +xnor2mask_slice  ,
				                          xnor2mask_slice  );
	}
	else
	{
		sprintf( BusNameI0,"i0[%ld:%ld]", DP_WIDTH-xnor2mask_slice
				                                  -xnor2mask_width  ,
				                          DP_WIDTH-xnor2mask_slice-1);
		sprintf( BusNameO , "o[%ld:%ld]", DP_WIDTH-xnor2mask_slice
				                                  -xnor2mask_width  ,
				                          DP_WIDTH-xnor2mask_slice-1);
	}
 
	/* Creation of figure terminals. */
	/* **** Control terminals **** */
	LOCON(     "msk", IN   ,      "msk");

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

	/* **** Supply terminals **** */
	LOCON(     "vdd", INOUT,      "vdd"); 
	LOCON(     "vss", INOUT,      "vss"); 
	
	
	/* Creation of leaf cells instances. */
	/* ("xnormals" cells of column)       */
	for( LeafCellIndex=xnor2mask_slice,BitNumber=xnor2mask_width; 
		 LeafCellIndex<xnor2mask_slice          +xnor2mask_width;
		 LeafCellIndex++             ,BitNumber--             )
	{
	    /* Select the correct mask cells. */
	    LeafCellSliceName = TablLeafCellXnor2mask[
			2-Dut_XlGetBit(     xnor2mask_xlmask,
		          LeafCellIndex-xnor2mask_slice )];

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

		/* Build signals names. */
		sprintf( PinNameI0, "i0[%ld]", BusIndex);
		sprintf( PinNameO ,  "o[%ld]", BusIndex);

		/* Leaf cell instanciation. */
		LOINS( LeafCellSliceName,
			   LeafCellInstaName,
				       PinNameI0,
				      "sign_msk",
				       PinNameO , "vdd", "vss", EOL);
	}


	/* Creation of buffer instance. */

	/* Build buffer instance name. */
	sprintf( LeafCellInstaName, "bxnor2mask_%ld", DP_WIDTH);

	/* Buffer instanciation. */
	LOINS( LeafCellBuffrName,
		   LeafCellInstaName,
		               "msk",
		          "sign_msk", "vdd", "vss", VSS, EOL);

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