/********************************************************************
*                                                                   *
* Laboratoire MASI CAO-VLSI, UPMC, Copyright 1991 1992 1993 1994    *
*                                                                   *
* Software support Email : cao-vlsi@masi.ibp.fr                     *
*                                                                   *
* Authors : Zouina AKTOUF &                                         *
*           El Arabi RHOMARI &                                      *
*           Jose MARTINS DOS SANTOS &                               *
*           Jean-Paul CHAPUT                                        *
*                                                                   *
* Supervision & Modifications : Lotfi BEN AMMAR                     *
*                                                                   *
********************************************************************/
#include  "dpr_R.h"
/* -------------------------------------------------------------- */
/*  Module  :  "mvcon_I.c"                                        */


/* Internal constant of module. */
#define        C_SUPP_MaxLenString             4096
#define        C_SUPP_UserDPCon                0
#define        C_SUPP_UserDPData               1
#define        C_SUPP_DataTypeTerminal        ((char)0)
#define        C_SUPP_DataTypeBlock           ((char)1)
#define        C_SUPP_DataTypeUnknow          ((char)64)
#define        C_SUPP_ConSideDefault          ((char)0)
#define        C_SUPP_ConSideNorth            ((char)1)
#define        C_SUPP_ConSideSouth            ((char)2)
#define        C_SUPP_ConSideEast             ((char)3)
#define        C_SUPP_ConSideWest             ((char)4)
#define        C_SUPP_ConSideUnknow           ((char)64)


/* Internal structures of module. */

/* Structure holding specific informations of the whole Data-Path. */
typedef struct {
	char TYPE;  /* Type of the Data-Path (BLOCK or TERNINAL). */
	} udpdata;

/* Structure holding specific informations for data-path
   connectors placement. */
typedef struct udpcon {
	         char *NAME; /* Name of the connector.                   */
	         char  SIDE; /* Side where the terminal will be set.     */
	struct udpcon *NEXT; /* Pointer to the next element of the list. */
	} udpcon_list;


/* Internal variables of module. */
static       char  Dut_StringBuffer[C_SUPP_MaxLenString];
static       char *TABL_SIDE[] = {"DEFAULT",
								  "NORTH"  ,
								  "SOUTH"  ,
								  "EAST"   ,
								  "WEST"   };
static       char *TABL_TYPE[] = {"TERMINAL",
								  "BLOCK"   };
static ptype_list PtUdpData    = {(ptype_list*)NULL,
								        (void*)NULL,
								  C_SUPP_UserDPData};
static ptype_list PtUdpConHead = {(ptype_list*)NULL,
								        (void*)NULL,
								  C_SUPP_UserDPCon};


/* Macros definitions of the module. */

/* Convert a connector side or a Data-Path type into a string. */
#define  DutMC_SideToStr(aside)  ( TABL_SIDE[(int)(aside)] )
#define  DutMC_TypeToStr(atype)  ( TABL_TYPE[(int)(atype)] )


/* Definition of module internal functions. */
static       char  Dut_StrToType();
static       char  Dut_StrToSide();
static phcon_list *Dut_MovPhCon();
static udpdata     *Dut_AddUdpData();
static udpcon_list *Dut_AddUdpCon();
static        long  Dut_LoadUdp();
static        void  Dut_SaveUdp();
static        void  Dut_MovLsPhCon();



/*  Function  :  'Dut_StrToType'                                  */
/* -------------------------------------------------------------- */

static char  Dut_StrToType(aStrType)
	char *aStrType;
{
	if (!strcmp(TABL_TYPE[(int)C_SUPP_DataTypeTerminal],aStrType))
		return(C_SUPP_DataTypeTerminal);
	if (!strcmp(TABL_TYPE[(int)C_SUPP_DataTypeBlock   ],aStrType))
		return(C_SUPP_DataTypeBlock);

	return( C_SUPP_DataTypeUnknow);
}


/*  Function  :  'Dut_AddUdpData'                                 */
/* -------------------------------------------------------------- */

static udpdata *Dut_AddUdpData(aPtLoFig,aDpType)
	phfig_list *aPtLoFig;
	      char  aDpType;
{
	if (PtUdpData.DATA == (void*)NULL)
		PtUdpData.DATA = (void*)mbkalloc(sizeof(udpdata));

	((udpdata*)(PtUdpData.DATA))->TYPE = aDpType;

	return( (udpdata*)(PtUdpData.DATA));
}


/*  Function  :  'Dut_StrToSide'                                  */
/* -------------------------------------------------------------- */

static char  Dut_StrToSide(aStrSide)
	char *aStrSide;
{
	if (!strcmp(TABL_SIDE[(int)C_SUPP_ConSideDefault],aStrSide))
		return(C_SUPP_ConSideDefault);
	if (!strcmp(TABL_SIDE[(int)C_SUPP_ConSideNorth  ],aStrSide))
		return(C_SUPP_ConSideNorth  );
	if (!strcmp(TABL_SIDE[(int)C_SUPP_ConSideSouth  ],aStrSide))
		return(C_SUPP_ConSideSouth  );
	if (!strcmp(TABL_SIDE[(int)C_SUPP_ConSideEast   ],aStrSide))
		return(C_SUPP_ConSideEast   );
	if (!strcmp(TABL_SIDE[(int)C_SUPP_ConSideWest   ],aStrSide))
		return(C_SUPP_ConSideWest   );

	return( C_SUPP_ConSideUnknow);
}


/*  Function  :  'Dut_AddUdpCon'                                  */
/* -------------------------------------------------------------- */

static udpcon_list *Dut_AddUdpCon(aPtLoFig,aConName,aConSide)
	lofig_list *aPtLoFig;
	      char *aConName;
	      char  aConSide;
{
	udpcon_list *PtNew, *PtCurr;

	PtNew = mbkalloc(sizeof(udpcon_list));

	PtNew->NAME = namealloc(aConName);
	PtNew->SIDE =           aConSide;

	for( PtCurr  = (udpcon_list*)(PtUdpConHead.DATA);
		 PtCurr != (udpcon_list*)NULL;
		 PtCurr  = PtCurr->NEXT)
		if (PtNew->NAME == PtCurr->NAME)
		{
			fflush( stdout);
			fflush( stderr);

			fprintf(
				stderr,
				"*** AddUdpCon ***:Duplicate connector name:\"%s\".\n",
				PtNew->NAME);

			exit(1);
		}

	PtNew->NEXT = (udpcon_list*)(PtUdpConHead.DATA);
	PtUdpConHead.DATA = (void*)PtNew;

	return(PtNew);
}


/*  Function  :  'Dut_LoadUdp'                                    */
/* -------------------------------------------------------------- */

static long  Dut_LoadUdp(aLoFigName)
	char *aLoFigName;
{
#define  DutMC_ParserNextToken(ptstart,ptnext)                          \
             if (((ptnext)=strchr((ptstart),',')) == NULL)              \
			 {                                                          \
				 fflush(stdout);                                        \
				 fflush(stderr);                                        \
                                                                        \
				 fprintf(                                               \
					 stderr,                                            \
					 "*** LoadUdp ***:Syntax error line:%ld.\n(%s)\n",  \
													   ParserCurrLine,  \
													 Dut_StringBuffer); \
																		\
				 exit(1);                                               \
			 }                                                          \
             *((ptnext)++) = (char)0;

#define  DutMC_ParserLastToken(ptstart,ptend)                           \
             if (((ptend)=strchr((ptstart),'\n')) == NULL)              \
			 {                                                          \
				 fflush(stdout);                                        \
				 fflush(stderr);                                        \
                                                                        \
				 fprintf(                                               \
					 stderr,                                            \
					 "*** LoadUdp ***:Syntax error line:%ld.\n(%s)\n",  \
													   ParserCurrLine,  \
													 Dut_StringBuffer); \
																		\
				 exit(1);                                               \
			 }                                                          \
             *ptend = (char)0;


	      FILE *UdpFile;
	lofig_list *PtLoFig;
		   
		  long  ParserCurrLine;
		  long  ParserExitLoop;
		  char *PtName, *PtSide, *PtType, *PtEnd;
		  char           VlSide,  VlType;


	if ((PtLoFig=getlofig(aLoFigName,'A')) == (lofig_list*)NULL)
	{
		fflush(stdout);
		fflush(stderr);

		fprintf(
			stderr,
			"*** MovLsPhCon ***:Logical figure \"%s\" not found.\n",
													     aLoFigName);

		exit(1);
	}

	/* *** Opening the file holding user datas. *** */
	if ((UdpFile=mbkfopen(PtLoFig->NAME,
						          "dpr",
						      READ_TEXT)) == (FILE*)NULL)
	{
		fprintf(
			stderr,
			"*** LoadUdp ***:File \"%s.dpr\" not found: ignored.\n\n",
													 PtLoFig->NAME);

		return(0);
	}

    for( ParserCurrLine=1    ,
		 ParserExitLoop=FALSE;
        fgets(Dut_StringBuffer,C_SUPP_MaxLenString-1,UdpFile)!=NULL;
		 ParserCurrLine++    ) 
	{
        if (strncmp(Dut_StringBuffer,"EOF",3) == 0)
            {ParserExitLoop = TRUE; break;}

        if (Dut_StringBuffer[1] != ' ')
		{
			fflush(stdout);
			fflush(stderr);

			fprintf(
				stderr,
				"*** LoadUdp ***:Syntax error line:%ld.\n(%s)\n",
												  ParserCurrLine,
												Dut_StringBuffer);

			exit(1);
		}

        switch( Dut_StringBuffer[0] )
		{
        /* Connector placement data record. */
            case 'C' :
				PtName = Dut_StringBuffer+2;
				DutMC_ParserNextToken( PtName, PtSide);
				DutMC_ParserLastToken( PtSide, PtEnd );

				if ((VlSide=Dut_StrToSide(PtSide))
					       == C_SUPP_ConSideUnknow)
				{
					fflush(stdout);
					fflush(stderr);

					fprintf(
						stderr,
						"*** LoadUdp ***:Syntax error line:%ld.\n(%s)\n",
														  ParserCurrLine,
														Dut_StringBuffer);

					exit(1);
				}

				(void)Dut_AddUdpCon(PtLoFig,PtName,VlSide);
				break;
			case 'D' :
				PtType = Dut_StringBuffer+2;
				DutMC_ParserLastToken( PtType, PtEnd );

				if ((VlType=Dut_StrToType(PtType))
					       == C_SUPP_DataTypeUnknow)
				{
					fflush(stdout);
					fflush(stderr);

					fprintf(
						stderr,
						"*** LoadUdp ***:Syntax error line:%ld.\n(%s)\n",
														  ParserCurrLine,
														Dut_StringBuffer);

					exit(1);
				}

				(void)Dut_AddUdpData(PtLoFig,VlType);
				break;
		}
	}
	
	/* Check if the EOF has been read. */
	if (ParserExitLoop == FALSE)
	{
		fflush(stdout);
		fflush(stderr);

		fprintf(
			stderr,
			"*** LoadUdp ***:Syntax error line:%ld.\n(%s)\n",
											  ParserCurrLine,
													 "<EOF>");

		exit(1);
	}

	return(1);

#undef  DutMC_ParserLastToken
#undef  DutMC_ParserNextToken
}


/*  Function  :  'Dut_SaveUdp'                                    */
/* -------------------------------------------------------------- */

static void  Dut_SaveUdp(aLoFigName)
	char *aLoFigName;
{
	       FILE *UdpFile;
	 lofig_list *PtLoFig;
	udpcon_list *PtCurr;

	if ((PtLoFig=getlofig(aLoFigName,'A')) == (lofig_list*)NULL)
	{
		fflush(stdout);
		fflush(stderr);

		fprintf(
			stderr,
			"*** SaveUdp ***:Logical figure \"%s\" not found.\n",
													  aLoFigName);

		exit(1);
	}

	/* *** Creating the file holding user datas. *** */
	if ((UdpFile=mbkfopen(PtLoFig->NAME,
						          "dpr",
						     WRITE_TEXT)) == (FILE*)NULL)
	{
		fflush(stdout);
		fflush(stderr);

		fprintf(
			stderr,
			"*** LoadUdp ***:File \"%s.udp\" not found.\n",
											 PtLoFig->NAME);

		exit(1);
	}


	if (PtUdpData.DATA != (void*)NULL)
		fprintf( UdpFile, "D %s\n",
			DutMC_TypeToStr(((udpdata*)(PtUdpData.DATA))->TYPE));		

	for( PtCurr  = (udpcon_list*)(PtUdpConHead.DATA);
		 PtCurr != (udpcon_list*)NULL;
		 PtCurr  = PtCurr->NEXT)
		fprintf( UdpFile, "C %s,%s\n", PtCurr->NAME,
				       DutMC_SideToStr(PtCurr->SIDE));

	fprintf( UdpFile, "EOF\n");

	fclose(UdpFile);
}


/*  Function  :  'Dut_MovPhCon'                                   */
/* -------------------------------------------------------------- */

static phcon_list *Dut_MovPhCon(aPtPhFig,aConSide,aConName)
	phfig_list *aPtPhFig;
	      char  aConSide;
	      char *aConName;
{
	phcon_list *PtPhCon;

	for( PtPhCon  =  aPtPhFig->PHCON ;
		 PtPhCon != (phcon_list*)NULL;
		 PtPhCon  = PtPhCon->NEXT    )
		if (PtPhCon->NAME == aConName)
		{
		    if (aConSide == C_SUPP_ConSideDefault)
				return( PtPhCon);

			if (  (PtPhCon->XCON != aPtPhFig->XAB1)
				&&(PtPhCon->XCON != aPtPhFig->XAB2))
			{
				fprintf(stderr,
"*** MovPhCon ***:Unable to move connector \"%s\" of model \"%s\"\n.",
											            PtPhCon->NAME,
											           aPtPhFig->NAME);
				return( PtPhCon);
			}

		    switch( aConSide )
			{
			    case C_SUPP_ConSideNorth:
					PtPhCon->ORIENT = NORTH;
					PtPhCon->LAYER  = ALU1;
					PtPhCon->WIDTH  = 1*SCALE_X;
					PtPhCon->XCON   = aPtPhFig->XAB1;
					PtPhCon->YCON   = aPtPhFig->YAB2;

					return( PtPhCon);
			    case C_SUPP_ConSideSouth:
			        PtPhCon->ORIENT = SOUTH;
					PtPhCon->LAYER  = ALU1;
					PtPhCon->WIDTH  = 1*SCALE_X;
					PtPhCon->XCON   = aPtPhFig->XAB1;
					PtPhCon->YCON   = aPtPhFig->YAB1;

					return( PtPhCon);
			    case C_SUPP_ConSideEast:
			        PtPhCon->ORIENT = EAST;
					PtPhCon->LAYER  = ALU2;
					PtPhCon->WIDTH  = 2*SCALE_X;
					PtPhCon->XCON   = aPtPhFig->XAB2;
				 /* PtPhCon->YCON   = aPtPhFig->YAB1; */

					return( PtPhCon);
			    case C_SUPP_ConSideWest:
			        PtPhCon->ORIENT = WEST;
					PtPhCon->LAYER  = ALU2;
					PtPhCon->WIDTH  = 2*SCALE_X;
					PtPhCon->XCON   = aPtPhFig->XAB1;
				 /* PtPhCon->YCON   = aPtPhFig->YAB2; */

					return( PtPhCon);
				default:
					fprintf(stderr,
"*** MovPhCon ***:Invalid side '%c' for connector \"%s\" of model \"%s\".\n",
																    aConSide,
																    aConName,
					               							 aPtPhFig->NAME);
					return( (phcon_list*)NULL);
			}
		}

	fprintf(stderr,
"*** MovPhCon ***:No physical connector \"%s\" in model \"%s\".\n",
											   aConName           ,
											   aPtPhFig->NAME     );

	return( (phcon_list*)NULL);
}


/*  Function  :  'Dut_MovLsPhCon'                                 */
/* -------------------------------------------------------------- */

static void  Dut_MovLsPhCon(aFigName)
	char *aFigName;
{
	 lofig_list *PtLoFig;
	 phfig_list *PtPhFig;
	udpcon_list *PtCurr;

	if ((PtLoFig=getlofig(aFigName,'A')) == (lofig_list*)NULL)
	{
		fflush(stdout);
		fflush(stderr);

		fprintf(
			stderr,
			"*** MovLsPhCon ***:Logical figure \"%s\" not found.\n",
													       aFigName);

		exit(1);
	}

	if ((PtPhFig=getphfig(aFigName,'A')) == (phfig_list*)NULL)
	{
		fflush(stdout);
		fflush(stderr);

		fprintf(
			stderr,
			"*** MovLsPhCon ***:Physical figure \"%s\" not found.\n",
													        aFigName);

		exit(1);
	}

	for( PtCurr  = (udpcon_list*)(PtUdpConHead.DATA);
		 PtCurr != (udpcon_list*)NULL;
		 PtCurr  = PtCurr->NEXT)
		(void)Dut_MovPhCon(PtPhFig,PtCurr->SIDE,
						           PtCurr->NAME);
}


/*  Function  :  'Dut_SetABTerminal'                              */
/* -------------------------------------------------------------- */

extern void  Dut_SetABTerminal(aFigName)
	char *aFigName;
{
	phfig_list *PtPhFig;
	lofig_list *PtLoFig;
	phcon_list *PtPhCon;

	if ((PtLoFig=getlofig(aFigName,'A')) == (lofig_list*)NULL)
	{
		fflush(stdout);
		fflush(stderr);

		fprintf(
			stderr,
			"*** SetABTerminal ***:Logical figure \"%s\" not found.\n",
													          aFigName);

		exit(1);
	}

	if ((PtPhFig=getphfig(aFigName,'A')) == (phfig_list*)NULL)
	{
		fflush(stdout);
		fflush(stderr);

		fprintf(
			stderr,
			"*** SetABTerminal ***:Physical figure \"%s\" not found.\n",
													           aFigName);

		exit(1);
	}

/*	if (PtUdpData == (void*)NULL) return;  */
	if (((udpdata*)(PtUdpData.DATA))->TYPE 
		        != C_SUPP_DataTypeTerminal)
		return;

	printf( "Streching AB.\n");

	for( PtPhCon  =  PtPhFig->PHCON  ;
		 PtPhCon != (phcon_list*)NULL;
		 PtPhCon  = PtPhCon->NEXT    )
		switch( PtPhCon->ORIENT )
		{
		    case NORTH:
		        PtPhCon->YCON += 10*SCALE_X;
				break;
		    case SOUTH:
		        PtPhCon->YCON -= 10*SCALE_X;
				break;
			case EAST:
			case WEST:
/* 				if (PtPhCon->YCON == PtPhFig->YAB1) */
/* 					PtPhCon->YCON -= 10*SCALE_X;    */
					
/* 				if (PtPhCon->YCON == PtPhFig->YAB2) */
/* 					PtPhCon->YCON += 10*SCALE_X;    */
					
				break;
		}

	PtPhFig->YAB1 -= 10*SCALE_X;
	PtPhFig->YAB2 += 10*SCALE_X;

	(void)addphcon( PtPhFig      ,
				    SOUTH        ,
				    "vdd"        , 
				    PtPhFig->XAB1,
				    PtPhFig->YAB1,
				    ALU1         ,	
				    8*SCALE_X    );
	(void)addphcon( PtPhFig      ,
				    SOUTH        ,
				    "vss"        , 
				    PtPhFig->XAB1,
				    PtPhFig->YAB1,
				    ALU1         ,	
				    10*SCALE_X   );


	puts("Saving the modified physical figure.");
	savephfig(PtPhFig);
}



/*  Function  :  'move_globalcon'                                 */
/* -------------------------------------------------------------- */

extern void  move_globalcon(aFigName)
	char *aFigName;
{
	if (Dut_LoadUdp(aFigName))
	{
		Dut_MovLsPhCon(   aFigName);
		Dut_SetABTerminal(aFigName);
	}
}
