#include  <stdio.h>

#include  <genlib.h>

#include  "support.h"
#include  "dplimits.h"
#include  "add3.h"

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


/* Module internal constants. */

/* Names of adder-substracter leaf cells. */
static char *TabLeafCellAdd3[6] = {   "bcsacsa_fp",
								      "csacsa0_fp",
									 "csacsai_fp",
									"csacsap_fp",
                                   "csacsa0i_fp",
                                  "csacsa0p_fp"
                                   };


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

/* Internal functions of module. */
static       void  Dgn_ErrorAdd3();
static       void  Dgn_VhdlAdd3();
static       void  Dgn_NetlistAdd3();


/*  Function  :  'Dgn_DispatchAdd3'                                */
/* -------------------------------------------------------------- */
/*  Interface of adder/buffer generator.                       */

extern char *Dgn_DispatchAdd3(add3_modelname,
							  add3_width    ,
							  add3_slice    ,
							  add3_msb0     ,
							  add3_vhdl     ,
							  add3_netlist  ,
							  add3_icon     )
	char *add3_modelname;  /* Model name.                    */
	long  add3_width;      /* Bus wide.                      */
	long  add3_slice;      /* give the LSB starting slice.   */
	long  add3_msb0;       /* Zero as MSB index.             */
	long  add3_vhdl;       /* Generation of behavioral view. */
	long  add3_netlist;    /* Generation of netlist view.    */
	long  add3_icon;       /* Generation of icon.            */
{
	static short  DispachAdd3_FirstCall = FALSE;
	static  char  ModelName[C_SUPP_MBKSZNAME];

	/* The first time the generator is called : */
	/*     - Load specific errors.            */
	if (!DispachAdd3_FirstCall)
	{
		Dgn_ErrorAdd3();
		DispachAdd3_FirstCall = TRUE;
	}

	/* Check if, at least, one view is asked. */
	if (   (add3_netlist == FALSE)
		 &&(add3_vhdl    == FALSE)
		 &&(add3_icon    == FALSE) )
		Dut_PrintError( E_ADD3_ERROR, E_ADD3_NOVIEW);

	/* Check the bus wide. */
	if ((add3_width < 0) || (add3_width > C_DPLIMITS_MAXSLICE))
		Dut_PrintError( E_ADD3_ERROR, E_ADD3_WIDTH, add3_width);

	/* Check the LSB starting slice. */
	if ((add3_slice < 0) || ( add3_slice
							+add3_width > DP_WIDTH))
		Dut_PrintError( E_ADD3_ERROR, E_ADD3_SLICE, add3_slice);

	/* Check the model name. */
	if (add3_modelname == (char*)NULL)
#ifndef  CRUNCH_FILENAME
		/* Build a more explicit model name. */
		(void*)sprintf( ModelName, "add3_%ldx%ldx%ld%c_cl",
					                   DP_WIDTH              ,
					                 add3_width              ,
					                 add3_slice              ,
					               ((add3_msb0 ) ? 'm' : 'l'));
#else
		/* Build the crunched model name. */
		strcpy( ModelName, Dut_MakeCrunchModelName(
									    "iv"       ,
									8L,  DP_WIDTH-1,
									8L, add3_width-1,
									8L, add3_slice  ,
									0L, add3_msb0   ));
#endif
	else
		strcpy( ModelName, add3_modelname);

	/* Generation of behaviorial view. */
	if (add3_vhdl)
		Dgn_VhdlAdd3( ModelName,
			   	   	   add3_width,
			   		   add3_slice,
			   		   add3_msb0 );

	/* Generation of netlist view. */
	if (add3_netlist)
		Dgn_NetlistAdd3( ModelName,
						  add3_width,
						  add3_slice,
						  add3_msb0 );

	/* Generation of icone. */
	/* if (add3_icon) */
	
	/* Return name of the generated model. */
	return((add3_modelname == (char*)NULL) ?     ModelName 
		                                  : add3_modelname);
}


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

static void  Dgn_ErrorAdd3()
{
	Dut_AddError( E_ADD3_ERROR, E_ADD3_WIDTH,
				  "add3alid bus width : %ld.");
	Dut_AddError( E_ADD3_ERROR, E_ADD3_MODELNAME,
				  "Missing model name.");
	Dut_AddError( E_ADD3_ERROR, E_ADD3_NOVIEW,
				  "No view to generate.");
	Dut_AddError( E_ADD3_ERROR, E_ADD3_OPENVBE,
				  "Unable to create file : \"%s\".");
}


/*  Function  :  'Dgn_NetListAdd3'                                 */
/* -------------------------------------------------------------- */
/*  Generation of adder/substracter behvioral view.                 */

static void  Dgn_VhdlAdd3(add3_modelname,
					      add3_width    ,
					      add3_slice    ,
						  add3_msb0     )
	char *add3_modelname;  /* Nom du modele.           */
	long  add3_width;      /* Largeur du bus.          */
	long  add3_slice;      /* LSB starting slice.      */
	long  add3_msb0;       /* Zero comme index du MSB. */
{
	FILE *Add3File;
	long  BitIndex,     LenString,      TmpTime;
	char  BusWide[256], BusWide0[256], BusWide1[256], TmpString[256];

	/* *** Creating the file holding behavioral view. *** */
	if ((Add3File=mbkfopen(add3_modelname,
						            "vbe",
						       WRITE_TEXT)) == (FILE*)NULL)
		Dut_PrintError( E_ADD3_ERROR, E_ADD3_OPENVBE,
					                  add3_modelname);

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

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

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

	/* Give the call used to generate the model. */
	sprintf(  TmpString, "\"add3g %ld %ld %ld %s -vhdl -o %s\"" ,
			                        DP_WIDTH                      ,
			                       add3_width                      ,
			                       add3_slice                      ,
			                      (add3_msb0     ) ? " -msb0"  : "",
			                       add3_modelname                  );
    fprintf( Add3File  , "-- # Generator Call : %-45s  #\n", TmpString);

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


	/* Select terminals (and signals) bus indexation. */
	/* (depending to the flag "add3_msb0")             */
	if (!add3_msb0)
		{ sprintf( BusWide, "(%ld downto %ld)", add3_width-1
				                                +add3_slice  ,
				                                add3_slice  );

		  sprintf( BusWide0,"(%ld downto %ld)", add3_width
				                                +add3_slice  ,
				                                add3_slice+1);

		  sprintf( BusWide1,"(%ld downto %ld)", add3_width
				                                +add3_slice  ,
				                                add3_slice  );
        }
	else
		{ sprintf( BusWide, "(%ld to %ld)", DP_WIDTH-add3_slice
				                                    -add3_width   ,
				                            DP_WIDTH-add3_slice-1);

		  sprintf( BusWide0,"(%ld to %ld)", DP_WIDTH-add3_slice
				                                    -add3_width+1 ,
				                            DP_WIDTH-add3_slice  );

		  sprintf( BusWide1,"(%ld to %ld)", DP_WIDTH-add3_slice
				                                    -add3_width+1 ,
				                            DP_WIDTH-add3_slice-1);
        }

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

    /* Control terminals. */
	fprintf( Add3File, "%14s :  in  BIT;\n", "cout_0"  );
	fprintf( Add3File, "%14s :  out BIT;\n", "cout_1"  );
	fprintf( Add3File, "%14s :  out BIT;\n", "ovr" );

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

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


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


	/* *** Behavioral view *** */
	fprintf( Add3File, "ARCHITECTURE behaviour_data_flow OF %s IS\n\n",
			                                            add3_modelname);

    fprintf( Add3File, "SIGNAL carry1 : BIT_VECTOR%s;\n",BusWide1);
    fprintf( Add3File, "SIGNAL carry2 : BIT_VECTOR%s;\n",BusWide1);
    fprintf( Add3File, "SIGNAL s      : BIT_VECTOR%s;\n",BusWide);

	fprintf( Add3File, "BEGIN\n\n");
	fprintf( Add3File, "\tcarry2(0) <= cout_0 ;\n\n" );
	fprintf( Add3File, "\tcarry1(0) <= '0' ;\n\n" );
	fprintf( Add3File, "\ts%s <= i0%s xor i1%s xor i2%s;\n\n" , BusWide, BusWide, BusWide, BusWide );
	fprintf( Add3File, "\to%s <= s%s xor carry2%s xor carry1%s;\n\n" , BusWide, BusWide, BusWide, BusWide );
	fprintf( Add3File, "\tcarry1%s <= (i0%s and i1%s) or (i0%s and i2%s) or (i2%s and i1%s);\n\n" , BusWide0, BusWide, BusWide, BusWide, BusWide, BusWide, BusWide);
	fprintf( Add3File, "\tcarry2%s <= (s%s and carry1%s) or (s%s and carry2%s) or (carry1%s and carry2%s);\n\n" , BusWide0, BusWide, BusWide, BusWide, BusWide, BusWide, BusWide);
	fprintf( Add3File, "\tcout_1 <= carry1(%ld);\n\n" ,DP_WIDTH-add3_slice );
	fprintf( Add3File, "\tovr <= carry2(%ld) xor carry2(%ld);\n\n" , DP_WIDTH-add3_slice , DP_WIDTH-add3_slice-1);

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

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

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

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


/*  Function  :  'Dgn_NetListAdd3'                                 */
/* -------------------------------------------------------------- */
/*  Generation of adder/substracter netlist view.                   */

static void  Dgn_NetlistAdd3(add3_modelname,
						     add3_width    ,
						     add3_slice    ,
						     add3_msb0     )
	char *add3_modelname;  /* Model name.            */
	long  add3_width;      /* Bus wide.              */
	long  add3_slice;      /* LSB starting slice.    */
	long  add3_msb0;       /* Zero as MSB index.     */
{
	int   number;
	long  BusIndex;
	long  SignalIndex0;
	long  SignalIndex1;
	long  LeafCellIndex;

	char *LeafCellSliceName;
	char  LeafCellInstaName[C_SUPP_MBKSZNAME];

	char  BusNameI0[C_SUPP_MBKSZNAME];
	char  BusNameI1[C_SUPP_MBKSZNAME];
	char  BusNameI2[C_SUPP_MBKSZNAME];
	char  BusNameO[ C_SUPP_MBKSZNAME];

	char  PinNameI0[C_SUPP_MBKSZNAME];
	char  PinNameI1[C_SUPP_MBKSZNAME];
	char  PinNameI2[C_SUPP_MBKSZNAME];
	char  PinNameO[ C_SUPP_MBKSZNAME];
	char  Carry1Name0[C_SUPP_MBKSZNAME];
	char  Carry1Name1[C_SUPP_MBKSZNAME];
	char  Carry2Name0[C_SUPP_MBKSZNAME];
	char  Carry2Name1[C_SUPP_MBKSZNAME];


	/* Select name of the leaf cell model. */

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

	/* Name of data bus terminals. */
	if (!add3_msb0)
	{
		sprintf( BusNameI0,"i0[%ld:%ld]", add3_width-1+add3_slice, add3_slice);
		sprintf( BusNameI1,"i1[%ld:%ld]", add3_width-1+add3_slice, add3_slice);
		sprintf( BusNameI2,"i2[%ld:%ld]", add3_width-1+add3_slice, add3_slice);
		sprintf( BusNameO , "o[%ld:%ld]", add3_width-1+add3_slice, add3_slice);
	}
	else
	{
		sprintf( BusNameI0,"i0[%ld:%ld]", DP_WIDTH-add3_slice
				                                  -add3_width  ,
				                          DP_WIDTH-add3_slice-1);
		sprintf( BusNameI1,"i1[%ld:%ld]", DP_WIDTH-add3_slice
				                                  -add3_width  ,
				                          DP_WIDTH-add3_slice-1);
		sprintf( BusNameI2,"i2[%ld:%ld]", DP_WIDTH-add3_slice
				                                  -add3_width  ,
				                          DP_WIDTH-add3_slice-1);
		sprintf( BusNameO , "o[%ld:%ld]", DP_WIDTH-add3_slice
				                                  -add3_width  ,
				                          DP_WIDTH-add3_slice-1);
	}

 
	/* Creation of figure terminals. */

	/* **** Control terminals **** */
	LOCON( "cout_0"   , IN    , "cout_0"    );
	LOCON( "cout_1"   , OUT   , "cout_1"    );
	LOCON( "ovr"  , OUT   , "ovr"   );

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

	/* **** Supply terminals **** */
	LOCON( "vdd",  INOUT ,  "vdd"); 
	LOCON( "vss",  INOUT ,  "vss"); 
	
	
	/* Creation of leaf cells instances. */

         

	/* ("normals" cells of column)       */
	for( LeafCellIndex=add3_slice;
		 LeafCellIndex<add3_slice+add3_width-1; LeafCellIndex++)
	{
		number = (add3_slice+add3_width-1-LeafCellIndex)%2;
        SignalIndex0 = ( add3_slice + add3_width -2 - LeafCellIndex ) ;
        SignalIndex1 = ( add3_slice + add3_width -1 - LeafCellIndex ) ;
		

		/* Build terminal leaf cell name. */
        if (LeafCellIndex==add3_slice)
          {
              if (number==0)
           	      LeafCellSliceName=TabLeafCellAdd3[4];
              else
           	      LeafCellSliceName=TabLeafCellAdd3[5];
          }
		/* Build leaf cell name. */
        else
          {
              if (number==0)
               	  LeafCellSliceName=TabLeafCellAdd3[2];
        	  else
           		  LeafCellSliceName=TabLeafCellAdd3[3];
          }
		     
		/* Compute terminal index. */
		if (!add3_msb0) BusIndex =              LeafCellIndex;
		else            BusIndex = DP_WIDTH -1 -LeafCellIndex;

		/* Build signals names. */
		sprintf( PinNameI0, "i0[%ld]", BusIndex);
		sprintf( PinNameI1, "i1[%ld]", BusIndex);
		sprintf( PinNameI2, "i2[%ld]", BusIndex);
		sprintf( PinNameO ,  "o[%ld]", BusIndex);
		sprintf( Carry1Name0 , "carry1_%ld", SignalIndex0 );
		sprintf( Carry1Name1 , "carry1_%ld", SignalIndex1 );
		sprintf( Carry2Name0 , "carry2_%ld", SignalIndex0 );
		sprintf( Carry2Name1 , "carry2_%ld", SignalIndex1 );

		/* Built instance name. */
		sprintf(LeafCellInstaName, "adsub_%ld", (LeafCellIndex-add3_slice) ); 

        
        if (LeafCellIndex==add3_slice)

		/* Terminal leaf cell instanciation. */
		LOINS( LeafCellSliceName,
			   LeafCellInstaName,
			          PinNameI0 ,
			          PinNameI1 ,
			          PinNameI2 ,
     				  "cout_0",
					  Carry1Name0,
					  Carry2Name0,
					  PinNameO , "vdd", "vss", EOL);
	
        else
		/* Leaf cell instanciation. */
		LOINS( LeafCellSliceName,
			   LeafCellInstaName,
	        		  PinNameI0 ,
	         		  PinNameI1 ,
	         		  PinNameI2 ,
  					  "cout_0",
					  Carry1Name1,
	      		      Carry2Name1  ,
	      		      Carry1Name0  ,
					  Carry2Name0,
               		  PinNameO, "vdd", "vss", EOL);
	}

    /* Creation of intermediaire cells */
    /* Intermediaire instance */
    LeafCellSliceName = TabLeafCellAdd3[1];
	LeafCellIndex = add3_slice+add3_width-1;

	/* Compute terminal index. */
	if (!add3_msb0) BusIndex =              LeafCellIndex ;
	else            BusIndex = DP_WIDTH -1 -LeafCellIndex;

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

	/* Built instance name. */
	sprintf(LeafCellInstaName, "add3_%ld", (DP_WIDTH-add3_slice-1) ); 

	/* Intermediaire instanciation */
	LOINS( LeafCellSliceName,
		   LeafCellInstaName,
                   PinNameI0,
		    	   PinNameI1,
		    	   PinNameI2,
				   "cout_0",
				  "carry1_1",
				  "carry2_1",	
				   "cout_1",
				  "carry2_0",
                   PinNameO , "vdd","vss",EOL);

	/* Creation of buffer instance. */

	/*  buffer instance name. */
	sprintf(LeafCellInstaName, "add3_%ld",(DP_WIDTH-add3_slice)); 
	LeafCellSliceName = TabLeafCellAdd3[0];

	/* Buffer instanciation. */
	LOINS( LeafCellSliceName,
		   LeafCellInstaName,
				    "cout_1" ,
   					"cout_0" ,
		            "carry2_1" ,
		            "carry2_0" ,
		            "ovr"   , "vdd", "vss", VSS, EOL);

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