#include  <stdio.h>

#include  <genlib.h>

#include  "support.h"
#include  "dplimits.h"
#include  "adsb2.h"

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


/* Module internal constants. */

/* Names of adder-substracter leaf cells. */
static char *TabLeafCellAdsb2[6] = {    "bnxr2csa_fp",
								       "nxr2csa0_fp",
									  "nxr2csai_fp",
									 "nxr2csap_fp",
                                    "nxr2csa0i_fp",
                                   "nxr2csa0p_fp"
                                   };


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

/* Internal functions of module. */
static       void  Dgn_ErrorAdsb2();
static       void  Dgn_VhdlAdsb2();
static       void  Dgn_NetlistAdsb2();


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

extern char *Dgn_DispatchAdsb2(adsb2_modelname,
							  adsb2_width    ,
							  adsb2_slice    ,
							  adsb2_msb0     ,
							  adsb2_vhdl     ,
							  adsb2_netlist  ,
							  adsb2_icon     )
	char *adsb2_modelname;  /* Model name.                    */
	long  adsb2_width;      /* Bus wide.                      */
	long  adsb2_slice;      /* give the LSB starting slice.   */
	long  adsb2_msb0;       /* Zero as MSB index.             */
	long  adsb2_vhdl;       /* Generation of behavioral view. */
	long  adsb2_netlist;    /* Generation of netlist view.    */
	long  adsb2_icon;       /* Generation of icon.            */
{
	static short  DispachAdsb2_FirstCall = FALSE;
	static  char  ModelName[C_SUPP_MBKSZNAME];

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

	/* Check if, at least, one view is asked. */
	if (   (adsb2_netlist == FALSE)
		 &&(adsb2_vhdl    == FALSE)
		 &&(adsb2_icon    == FALSE) )
		Dut_PrintError( E_ADSB2_ERROR, E_ADSB2_NOVIEW);

	/* Check the bus wide. */
	if ((adsb2_width < 0) || (adsb2_width > C_DPLIMITS_MAXSLICE))
		Dut_PrintError( E_ADSB2_ERROR, E_ADSB2_WIDTH, adsb2_width);

	/* Check the LSB starting slice. */
	if ((adsb2_slice < 0) || ( adsb2_slice
							+adsb2_width > DP_WIDTH))
		Dut_PrintError( E_ADSB2_ERROR, E_ADSB2_SLICE, adsb2_slice);

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

	/* Generation of behaviorial view. */
	if (adsb2_vhdl)
		Dgn_VhdlAdsb2( ModelName,
			   	   	   adsb2_width,
			   		   adsb2_slice,
			   		   adsb2_msb0 );

	/* Generation of netlist view. */
	if (adsb2_netlist)
		Dgn_NetlistAdsb2( ModelName,
						  adsb2_width,
						  adsb2_slice,
						  adsb2_msb0 );

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


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

static void  Dgn_ErrorAdsb2()
{
	Dut_AddError( E_ADSB2_ERROR, E_ADSB2_WIDTH,
				  "adsb2alid bus width : %ld.");
	Dut_AddError( E_ADSB2_ERROR, E_ADSB2_MODELNAME,
				  "Missing model name.");
	Dut_AddError( E_ADSB2_ERROR, E_ADSB2_NOVIEW,
				  "No view to generate.");
	Dut_AddError( E_ADSB2_ERROR, E_ADSB2_OPENVBE,
				  "Unable to create file : \"%s\".");
}


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

static void  Dgn_VhdlAdsb2(adsb2_modelname,
					      adsb2_width    ,
					      adsb2_slice    ,
						  adsb2_msb0     )
	char *adsb2_modelname;  /* Nom du modele.           */
	long  adsb2_width;      /* Largeur du bus.          */
	long  adsb2_slice;      /* LSB starting slice.      */
	long  adsb2_msb0;       /* Zero comme index du MSB. */
{
	FILE *Adsb2File;
	long  BitIndex,     LenString,      TmpTime,  SelBusIndex;
	char  BusWide[256], BusWide0[256], BusWide1[256], TmpString[256], SelBus[256];

	/* *** Creating the file holding behavioral view. *** */
	if ((Adsb2File=mbkfopen(adsb2_modelname,
						            "vbe",
						       WRITE_TEXT)) == (FILE*)NULL)
		Dut_PrintError( E_ADSB2_ERROR, E_ADSB2_OPENVBE,
					                  adsb2_modelname);

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

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

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

	/* Give the call used to generate the model. */
	sprintf(  TmpString, "\"adsb2g %ld %ld %ld %s -vhdl -o %s\"" ,
			                        DP_WIDTH                      ,
			                       adsb2_width                      ,
			                       adsb2_slice                      ,
			                      (adsb2_msb0     ) ? " -msb0"  : "",
			                       adsb2_modelname                  );
    fprintf( Adsb2File  , "-- # Generator Call : %-45s  #\n", TmpString);

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


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

		  sprintf( BusWide0,"(%ld downto %ld)", adsb2_width
				                                +adsb2_slice  ,
				                                adsb2_slice+1);

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

		  sprintf( BusWide0,"(%ld to %ld)", DP_WIDTH-adsb2_slice
				                                    -adsb2_width+1 ,
				                            DP_WIDTH-adsb2_slice  );

		  sprintf( BusWide1,"(%ld to %ld)", DP_WIDTH-adsb2_slice
				                                    -adsb2_width+1 ,
				                            DP_WIDTH-adsb2_slice-1);
        }

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

    /* Control terminals. */
	fprintf( Adsb2File, "%14s :  in  BIT;\n", "op"  );
	fprintf( Adsb2File, "%14s :  out BIT;\n", "cout");
	fprintf( Adsb2File, "%14s :  out BIT;\n", "ovr" );

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

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


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


	/* *** Behavioral view *** */
	strcpy( SelBus, "sel");
	for ( SelBusIndex=1; SelBusIndex < adsb2_width ; SelBusIndex ++ )
		strcat( SelBus, "&sel" );

	fprintf( Adsb2File, "ARCHITECTURE behaviour_data_flow OF %s IS\n\n",
			                                            adsb2_modelname);

    fprintf( Adsb2File, "SIGNAL carry : BIT_VECTOR%s;\n",BusWide1);
    fprintf( Adsb2File, "SIGNAL sel   : BIT;\n");

	fprintf( Adsb2File, "BEGIN\n\n");
	fprintf( Adsb2File, "\tsel <= op ;\n\n");
	fprintf( Adsb2File, "\tcarry(0) <= sel ;\n\n");
	fprintf( Adsb2File, "\to%s <= i0%s xor (%s xor i1%s) xor carry%s ;\n\n", BusWide, BusWide, SelBus, BusWide, BusWide);
	fprintf( Adsb2File, "\tcarry%s <= (i0%s and (%s xor i1%s)) or (i0%s and carry%s) or (carry%s and (%s xor i1%s));\n\n" , BusWide0, BusWide, SelBus, BusWide, BusWide, BusWide, BusWide, SelBus, BusWide);
	fprintf( Adsb2File, "\tcout <= carry(%ld);\n\n", DP_WIDTH-adsb2_slice);
	fprintf( Adsb2File, "\tovr <= carry(%ld) xor carry(%ld);\n\n", DP_WIDTH-adsb2_slice, DP_WIDTH-adsb2_slice-1);

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

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

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

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


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

static void  Dgn_NetlistAdsb2(adsb2_modelname,
						     adsb2_width    ,
						     adsb2_slice    ,
						     adsb2_msb0     )
	char *adsb2_modelname;  /* Model name.            */
	long  adsb2_width;      /* Bus wide.              */
	long  adsb2_slice;      /* LSB starting slice.    */
	long  adsb2_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  BusNameO[ C_SUPP_MBKSZNAME];

	char  PinNameI0[C_SUPP_MBKSZNAME];
	char  PinNameI1[C_SUPP_MBKSZNAME];
	char  PinNameO[ C_SUPP_MBKSZNAME];
	char  SignalName0[C_SUPP_MBKSZNAME];
	char  SignalName1[C_SUPP_MBKSZNAME];


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

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

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

 
	/* Creation of figure terminals. */

	/* **** Control terminals **** */
	LOCON( "op"   , IN    , "op"    );
	LOCON( "cout" , OUT   , "cout"  );
	LOCON( "ovr"  , OUT   , "ovr"   );

    /* **** Data bus terminals **** */
	LOCON( BusNameI0, IN  , BusNameI0);
	LOCON( BusNameI1, IN  , BusNameI1);
	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=adsb2_slice;
		 LeafCellIndex<adsb2_slice+adsb2_width-1; LeafCellIndex++)
	{
		number = (adsb2_slice+adsb2_width-1-LeafCellIndex)%2;
        SignalIndex0 = ( adsb2_slice + adsb2_width -2 - LeafCellIndex ) ;
        SignalIndex1 = ( adsb2_slice + adsb2_width -1 - LeafCellIndex ) ;
		

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

		/* Build signals names. */
		sprintf( PinNameI0, "i0[%ld]", BusIndex);
		sprintf( PinNameI1, "i1[%ld]", BusIndex);
		sprintf( PinNameO ,  "o[%ld]", BusIndex);
		sprintf( SignalName0 , "cin_%ld", SignalIndex0 );
		sprintf( SignalName1 , "cin_%ld", SignalIndex1 );

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

        
        if (LeafCellIndex==adsb2_slice)

		/* Terminal leaf cell instanciation. */
		LOINS( LeafCellSliceName,
			   LeafCellInstaName,
			          PinNameI0 ,
			          PinNameI1 ,
                      SignalName0 ,
     				  "sel",
					  PinNameO , "vdd", "vss", EOL);
	
        else
		/* Leaf cell instanciation. */
		LOINS( LeafCellSliceName,
			   LeafCellInstaName,
	        		  PinNameI0 ,
	         		  PinNameI1 ,
  					  "sel",
					  SignalName1,
	      		      SignalName0  ,
               		  PinNameO, "vdd", "vss", EOL);
	}

    /* Creation of intermediaire cells */
    /* Intermediaire instance */
    LeafCellSliceName = TabLeafCellAdsb2[1];
	LeafCellIndex = adsb2_slice+adsb2_width-1;

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

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

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

	/* Intermediaire instanciation */
	LOINS( LeafCellSliceName,
		   LeafCellInstaName,
                   PinNameI0,
		    	   PinNameI1,
				      "sel" ,
			        "cin_0" ,
			         "cout" ,
                   PinNameO , "vdd","vss",EOL);

	/* Creation of buffer instance. */

	/*  buffer instance name. */
	sprintf(LeafCellInstaName, "badsub_%ld",(DP_WIDTH-adsb2_slice)); 
	LeafCellSliceName = TabLeafCellAdsb2[0];

	/* Buffer instanciation. */
	LOINS( LeafCellSliceName,
		   LeafCellInstaName,
				    "op"    ,
				    "sel"   ,
		           "cin_0"  ,
		            "cout"  ,
		            "ovr"   , "vdd", "vss", VSS, EOL);

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