/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit :  Synthetiseur de FSM                                       */
/*    Fichier :  syf_main.c                                                  */
/*                                                                          */
/*    (c) copyright 1992 Laboratoire MASI equipe CAO & VLSI                 */
/*    Tous droits reserves                                                  */
/*    Support : e-mail cao-vlsi@masi.ibp.fr                                 */
/*                                                                          */
/*    Auteur(s) :  C. Sarwary                            le : 04/03/1992     */
/*                                                                          */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*                                                                          */
/***************************************************************************/
#include <stdio.h>
#include <math.h>
#include MUT_H 
#include LOG_H 
#include <signal.h>
#include"../beh104/beh104.h"
#include "syf_auto.h"
#include "syf_must.h"
#include "syf_beh2fsm.h"
#include "y.tab.h"
extern FILE *yyin;
extern FILE *syf_y_in;
int syf_rom, syf_pseudorom, syf_stack, syf_save, syf_kiss, syf_lax, syf_scan ;
char *syf_of ;

/*---------------------------------------------------------------
Fonction main.
Deux structures circuits sont allouees, une pour le Beh(il en faut 
necessairement une), et une autre pour evaluer les couts pour le codage.
On ne peut se contenter d'un seul . . . 
-----------------------------------------------------------------*/
main(argc,argv)
int argc;
char *argv[];
{
char *parFile ;
char name[20];
int numBit,i,l,k,AME=0 ;
int FIN =0;
struct syf_befig *beh ;
long beg, end ;
long delay ;
chain_list *listGrp ;
pState state ;
pCircuit pC ;
char Name[30] ;
char *getenv();
int msgBus() ;
int val,par ;

#ifndef  SYF_CORE
signal(SIGBUS,(void *)msgBus) ;
signal(SIGSEGV,(void *)msgBus) ;
#endif

syf_stack = 0 ;
syf_pseudorom = 0 ;
syf_save = 0 ;
syf_kiss = 0 ;
syf_lax = 0 ;
syf_rom = 0 ;
syf_scan = 0 ;
syf_of = NULL ;

if(argc < 3)
	msg(ER_PARAM) ;

FILE_NAME = mbkalloc(strlen(argv[2]) + 7) ;
for(i = 3; i < argc; i++)
	{
	if(!strcmp(argv[i],"-of"))
		{ 
		if(argc == i + 1)
			{
			msg(ER_PARAM) ;
			exit(-1) ;
			}
		syf_of = mbkalloc(strlen(argv[i+1]) + 1) ;
		strcpy(syf_of,argv[i+1]) ;
		syf_of[strlen(argv[i+1])] = '\0' ;
		i++ ;
		}
	else if(!strcmp(argv[i],"-stack"))
		syf_stack = 1 ;
	else if(!strcmp(argv[i],"-pseudorom")) 
		syf_pseudorom = 1 ;
	else if(!strcmp(argv[i],"-save"))
		syf_save = 1 ;
	else if(!strcmp(argv[i],"-kiss"))
		syf_kiss = 1 ;
	else if(!strcmp(argv[i],"-lax")) 
		syf_lax = 1 ;
	else if(!strcmp(argv[i],"-rom")) 
		syf_rom = 1 ;
	else if(!strcmp(argv[i],"-scan")) 
		syf_scan = 1 ;
	else
		msg(ER_PARAM) ;	
	}

initializeBdd(2) ;

alliancebanner("SYF","2.2","FSM Synthesizer","92-93","2.0") ;
 
SYF_COMPILE = 0 ;
if (!getenv("MBK_TRACE"))
    syf_trace = 0 ;
else
    if(strcmp("0",getenv("MBK_TRACE")))
		syf_trace = 1 ;
	else
		syf_trace = 0 ;
rempMaskTab();

/*
if(argc == 2 || argc == 3 && !strcmp(argv[2],"relax"))
	{
	sprintf(FILE_NAME,"%s.fsm",argv[1]) ;

	FSM_FILE = (char *)mbkalloc(200) ;
    if (!getenv("SL_FSM_LIB"))
       strcpy(FSM_FILE,".");
    else
	   strcpy(FSM_FILE,getenv("SL_FSM_LIB"));

	FSM_FILE = (char *)genNAME("%s/%s.fsm",FSM_FILE,argv[1]) ;

	if(argc == 2)
		PRINCIPAL(0) ;
	else
		PRINCIPAL(1) ;
	}
*/

if(syf_kiss)
	sprintf(FILE_NAME,"%s.kiss2",argv[2]) ;
else	
	sprintf(FILE_NAME,"%s.fsm",argv[2]) ;

FSM_FILE = (char *)mbkalloc(100) ;
if (!getenv("MBK_WORK_LIB"))
	strcpy(FSM_FILE,".");
else
	strcpy(FSM_FILE,getenv("MBK_WORK_LIB"));

sprintf(FSM_FILE,"%s/%s",FSM_FILE,FILE_NAME) ;

if(syf_kiss)
	{
	printf("input file format : kiss2\n") ;
	pC = compileKiss() ;
	}
else
	pC = compile() ;

if(!(strncmp(argv[1],"-r",2))) 
	{
	val = atoi(argv[1] + 2);
	if(val > 0)
		AME = val ;
	syf_cod(RECUIT,pC,AME,0) ;
    }
else if(!(strncmp(argv[1],"-h",2))) 
	{
	val = atoi(argv[1] + 2);
	if(val > 0)
		AME = val ;
	syf_cod(FORC,pC,AME,0) ;
    }
else if(!(strncmp(argv[1],"-m",2))) 
	{
	val = atoi(argv[1] + 2);
	if(val > 0)
		AME = val ;
	syf_cod(MUST,pC,AME,0) ;
   	 }
else if(!(strcmp(argv[1],"-v")))  
	 {
	syf_cod(VERT,pC,AME,0) ;
   	 }
else if(!(strncmp(argv[1],"-a",2)))
	 {
	val = atoi(argv[1] + 2);
	if(val > 0)
		AME = val ;
	syf_cod(ALEA,pC,AME,0) ;
   	 }
else if(!strcmp(argv[1],"-j")) 
	 {
	syf_cod(JEDI,pC,AME,0) ;
   	 }
else if(!strncmp(argv[1],"-u",2))
	 {
	 printf("'-u' Option no disponible\n") ;
	 exit(-1) ;
	val = atoi(argv[1] + 2);
	if(val > 0)
		AME = val ;
	syf_cod(MUSE,pC,AME,0) ;
   	}
else if(!strncmp(argv[1],"-s",2))
	 {
	val = atoi(argv[1] + 2);
	if(val > 0)
		AME = val ;
	 syf_cod(ASP,pC,AME,0) ;
   	 }
else  if(!strncmp(argv[1],"-n",2))
	 {
	val = atoi(argv[1] + 2);
	if(val > 0)
		AME = val ;
	syf_cod(NEWC,pC,AME,0) ;
	}
else 
	msg(ER_PARAM) ;

/*
	if ( argc < 5)
		destroyAuxAuto() ;  destruction des Var Aux pour optim. qui suit *
	printf("*********** COUTBEH : %d\n",coutBehAuto(beh)) ;
    	minimBehAbl(beh) ;
	printf("*********** COUTBEH : %d\n",coutBehAuto(beh)) ;
*/

return(0) ;
}

/*---------------------------------------------------------
traiteDc	: applique la simplification par dc sur le beh d'automate.
----------------------------
parametres	: befig.
----------------------------
return		: void.
-----------------------------------------------------------*/
void traiteDc(beh)
struct syf_befig *beh ;
{
int i ;
pState state ;
pCircuit pC ;
char *Name ;

pC = beh->CIRCUI ;
printf("traitement des DC lies aux etats\n") ;
rempliBddAuto() ;
dc2abl() ;

if(autoSys->ablDc != NULL)
	{
	/* On elimine les "state"_s et _m de pC->pTI pour que syf_makeBddBeh() ne 
	les garde pas comme var intermediaire, rempliBddAutoReg les rajout apres*/
	state = autoSys->state ;
	displayCct(pC,1) ;
	for(i = 0; i < autoSys->numberState; i++)
		{
		Name = nameSl(state->name) ;
		deleteTH(pC->pTI,Name,state->name) ;
		Name = nameMa(state->name) ;
		deleteTH(pC->pTI,Name,state->name) ;
		deleteTH(pC->pTI,"push") ;
		deleteTH(pC->pTI,"pop") ;
		deleteTH(pC->pTI,"nop") ;
		state++ ;
		}
	displayCct(pC,1) ;
	for(i = 0; i < autoSys->numberReg; i++)
		addInputCct(pC,nameindex(CURENT_STATE,i)) ;
	for(i = 0; i < autoSys->numberReg; i++)
		addInputCct(pC,nameindex(NEXT_STATE,i)) ;
	syf_makeBddBeh(beh,beh->CIRCUI,1,syf_trace,100) ;
	rempliBddAutoReg(beh->CIRCUI) ;
	rempliOutCctAuto(beh->CIRCUI) ;
	/*displayDc() ;
	displayCct(pC) ;*/
	syf_displayBehMap(beh) ;
	simplifDcAutoBeh(beh) ;
	syf_displayBehMap(beh) ;
   	/*syf_beh_debug(beh,"befig");*/
	}
else
	printf("No Don't Care\n") ;
}
	
/*---------------------------------------------------------
compileKiss	: Compile un fichier de format KISS2.
----------------------------
parametres	: aucun.
----------------------------
return		: une structure circuit.
-----------------------------------------------------------*/
pCircuit compileKiss()
{
int i, j, k, l;
char name[20] ;
int FIN = 0;
pCircuit pC ;

printf("Running FSM Compiler Kiss format ......\n") ;
fflush(stdout) ;
if (!(yyin=fopen(FSM_FILE,"r")))
	{
	printf("%s : doesn't exist\n",FSM_FILE);
	exit(-1);
	}

if(yyparse() == 1)
	exit(-1) ;
defaultName() ;
l = strlen(FSM_FILE);
i =0 ;
while((i < l +1) &&(!FIN))
	{
	if(FSM_FILE[l-i] == '/') FIN =1; 
	else i++;
	}
for(k=0; k< i; k++)
	{
	if(FSM_FILE[l-i+k+1] == '.')
		{
		name[k] = '\0';
		k =i;
		}
	else      name[k] = FSM_FILE[l-i+k+1];
	}

autoSys->numberReg = NUMBER_BIT(autoSys->numberState);  
printf("--> Number of States : %d\n",autoSys->numberState) ;
getTypeMachine() ;
if(autoSys->typeMachine == MOORE)
	printf("--> Type FSM : MOORE\n") ;
else
	printf("--> Type FSM : MEALEY\n") ;
if(syf_trace)
	{
	printf("----> Number of states : %d\n",autoSys->numberState) ;
	printf("----> Number of registers : %d\n",autoSys->numberReg) ;
	}
autoSys->name = namealloc(name);  
autoSys->dc = autoSys->code + autoSys->numberState;
/*if(syf_trace)
	equivState() ;*/
trans2Abl();
pC = NULL ;
/*pC = rempliBddAuto() ;*/
return(pC) ;
}
/*---------------------------------------------------------
compile		: compile le fichier d'entree : FSM_FILE.
----------------------------
parametres	: aucun.
----------------------------
return		: une structure circuit.
-----------------------------------------------------------*/
pCircuit compile()
{
int i, j, k, l;
char name[20] ;
int FIN = 0;
pCircuit pC ;

printf("Running VHDL Compiler .....\n") ;
fflush(stdout) ;
if (!(yyin=fopen(FSM_FILE,"r")))
	{
	printf("%s : doesn't exist\n",FSM_FILE);
	exit(-1);
	}
syf_y_in  =  yyin ;

if(syf_y_parse() == 1)
	exit(-1) ;
SYF_HEDFIG->FLAG = SYF_ERRFLG;
if(SYF_HEDFIG->FLAG != 0 )
	{
	  syf_error(200,NULL);
		exit(1);
	}

initInOutST(SYF_HEDFIG) ;
l = strlen(FILE_NAME);
i =0 ;
while((i < l +1) &&(!FIN))
	{
	if(FILE_NAME[l-i] == '/') FIN =1; 
	else i++;
	}
for(k=0; k< i; k++)
	{
	if(FILE_NAME[l-i+k+1] == '.')
		{
		name[k] = '\0';
		k =i;
		}
	else      name[k] = FILE_NAME[l-i+k+1];
	}

autoSys->name = namealloc(name);  
autoSys->dc = autoSys->code + autoSys->numberState;
beh2Auto(SYF_HEDFIG) ;
syf_beh_verify(SYF_HEDFIG) ;
/*if(!syf_stack)
	flattenStack() ;*/
/*verifPushPop() ; */

autoSys->numberReg = NUMBER_BIT(autoSys->numberState);  
printf("--> Number of States : %d\n",autoSys->numberState) ;
getTypeMachine() ;
if(autoSys->typeMachine == MOORE)
	printf("--> Type FSM : MOORE\n") ;
else
	printf("--> Type FSM : MEALEY\n") ;
if(syf_trace)
	{
	printf("----> Number of states : %d\n",autoSys->numberState) ;
	printf("----> Number of registers : %d\n",autoSys->numberReg) ;
	}
trans2Abl();

pC = NULL ;
/*pC = rempliBddAuto() ;*/
/*displayAuto() ;*/
return(pC) ;
}
/*---------------------------------------------------------
syf_cod	: synthese avec le codage MUSTANG.
----------------------------
parametres	: type de codage(differents algo).
----------------------------
return		: void.
-----------------------------------------------------------*/
void syf_cod(typeCod, pC, ame,dc)
char typeCod ;
pCircuit pC ;
int ame, dc ;
{
pOut savOut, saveOut() ;
struct syf_befig *beh ;
char out_file[50] ;
char name[50],extend[50] ;
char *path ;
char saveRes[20] ;
char *bidon ;
pCircuit makeCctBeh() ;
int i ;
char *getenv() ;

bidon = mbkalloc(200) ;
verifOption() ;
strcpy(extend,autoSys->name) ;

fsm_verify() ;
printf("FSM's States Encoding .....\n") ;
fflush(stdout) ;

razSys() ;
if(!syf_pseudorom && !syf_rom)
	{
	savOut = saveOut(autoSys->out) ;/*Comme out2Abl n'est pas definitif, on
					sauvegarde out,et on le recupere avant le prochain out2Abl*/
	out2Abl();/*on relance cette fonction apres genStack, ici elle sert pour
			calcul de cout par constructBehGivCost(recuit et stack) */
	}
switch(typeCod)
	{
	case RECUIT :
		strcat(extend,"r") ;
		autoSys->codage = namealloc("RECUIT");
		recuit(); 
		break ;
	case MUST :
		strcat(extend,"m") ;
		autoSys->codage = namealloc("MUSTANG");
		mustang(ame); 
		break ;
	case ASP :
		strcat(extend,"s") ;
		autoSys->codage = namealloc("sASP");
		asp(0,ame); 
		break ;
	case ALEA :
		strcat(extend,"a") ;
		autoSys->codage = namealloc("ALEATOIRE");
		codageAleatoire(autoSys->numberReg,ame); 
		break ;
	case FORC :
		strcat(extend,"h") ;
		autoSys->codage = namealloc("hFORCAGE");
		codageHorizontal(autoSys->numberReg,ame); 
		break ;
	case VERT :
		strcat(extend,"v") ;
		autoSys->codage = namealloc("VERTICAL");
		codageVertical(autoSys->numberReg); 
		break ;
	case JEDI :
		strcat(extend,"j") ;
		autoSys->codage = namealloc("JEDI");
		mustJedi(); 
		break ;
	case MUSE :
		printf("Syf : '-u' Optin no disponible\n") ;
		return ;
		/*autoSys->codage = namealloc("uMUSE");
		strcat(extend,"u") ;
		muse(ame); */
		break ;
	case NEWC :
		printf("Syf : '-n' Optin no disponible\n") ;
		return ;
		/*autoSys->codage = namealloc("NEW_COD");
		strcat(extend,"n") ;
		nc_genGroup(0,ame);*/ 
		break ;
	default :
		printf("SyF : Unknwon Encoding Algorithm\n") ;
		exit(-1) ;
	}
verifCode() ;
if(syf_of == NULL)
	autoSys->name = namealloc(extend) ;
else
	autoSys->name = namealloc(syf_of) ;
if (syf_save)
		saveCode();

if(syf_rom)
	driveRomOut() ;

if(flagPile)
	{
	if(syf_stack)
		optimCodForStack(pC) ;
	rempStackFixCode() ;

	if(syf_trace)
		{
		displayMask() ;
		displayStack() ;
		fflush(stdout) ;
		}
	}

if(syf_trace)
	printf("------ code2Abl -----\n") ;
code2Abl();
if(syf_trace)
	printf("------ end code2Abl -----\n") ;
if(syf_trace)
	displayCode(1) ;

if(flagPile ==1)
	{
	if(syf_trace)
		printf("----- ctrl2Abl ----\n") ;
	ctrl2Abl();
	if(syf_trace)
		printf("----- end ctrl2Abl ----\n") ;
	if(autoSys->typeReg == REG_D)
		{
		if(syf_trace)
			printf("********* D stack generation *********\n") ;
    	genStackD();
		}
	else
		{
		if(syf_trace)
			printf("********* MS stack generation *********\n") ;
    	genStackD();
		completStackForMS() ;
		}
	}
if(autoSys->typeReg == REG_D)
	{
	if(syf_trace)
		printf("D Registers generation\n") ;
	genRegD();
	}
else
	{
	if(syf_trace)
		printf("MS registers generation\n") ;
	genReg();
	}
if(!syf_pseudorom && !syf_rom)
	{
	/* Avant la synthese des out on recupere out original */
	freeOut(autoSys->out) ;
	autoSys->out = savOut ;
	}

if(syf_pseudorom)
	{
	if(syf_trace)
		printf("******** OUTPUT OPTIMIZATION *********\n") ;
	if(autoSys->typeReg == REG_D)
		genRegOutD() ;
	else
		genRegOut() ;
	if(syf_trace)
		printf("******** OUTPUT GENERATION *********\n") ;
	synthOut() ;
	}
else if(!syf_rom)
	{
	if(syf_trace)
		printf("******** OUTPUT GENERATION *********\n") ;
	out2Abl();
	}

if(dc == 1)
	destroyAuxAuto() ; /**** Pour le traiteDc *****/
if(syf_rom)
	beh = a2behRom(pC) ;
else
	beh = auto2beh(pC) ;
syf_mapCarExprBeh(beh,simplif10Expr) ;
syf_mapCarExprBeh(beh,simplifNotExpr) ;
if(syf_trace)
	syf_displayBehMap(beh,1) ;
/*#ifndef ARCHI_PC*/
pC = makeCctBeh(beh,0,syf_trace) ; /*eliminer partout ailleur le pC */
if(syf_trace)
	displayCct(pC) ;
/*if(syf_eval)
	{
	printf("-----> Initial cost, number of litterals : %d\n",coutBehAuto(beh)) ;
	printf("behavioral Minimizer running ......\n") ;
	fflush(stdout) ;
	minimBehAbl(beh,syf_trace) ;
	printf("-----> Estimated cost, number of litterals: %d\n",coutBehAuto(beh));
	fflush(stdout) ;
	}
	*/
if(dc == 1)
	traiteDc(beh) ;
/*#endif */
syf_vhdlsavebefig(beh) ;
}
/*---------------------------------------------------------
razSys		: Reinitialise de certaines structures d' autoSys pour un nouveau 
			  codage.
----------------------------
parametres	: rien .
----------------------------
return		: void.
-----------------------------------------------------------*/
razSys()
{
int i, numReg ;

autoSys->dc = NULL ;
autoSys->ablDc = NULL ;
for(i = 0; i < NUMBER_CODE(autoSys->numberReg); i++)
	{   
	(autoSys->code + i)->code = 0 ;
	(autoSys->code + i)->abl = NULL ;
	}
if(autoSys->typeReg == REG_D)
	numReg = autoSys->numberReg ;
else
	numReg = 2 * autoSys->numberReg ;
for(i = 0; i < numReg; i++)
	{   
	(autoSys->reg + i)->name = NULL ;
	(autoSys->reg + i)->abl = NULL ;
	(autoSys->reg + i)->cnd = NULL ;
	(autoSys->reg + i)->bdd = NULL ;
	}
}

msg(n)
int n ;
{
switch (n)
	{
	case ER_PARAM :
		printf("syf    : usage syf -option <input_file> [-stack] [-pseudorom] [-save] [-of <output file name>]\n") ;	
		printf("option :  -s Uses a \"vertical\" encoding algrithm.\n") ;
		printf("          -m Uses a \"horizontal\" encoding algrithm.\n");
		printf("          -a Uses a random encoding.\n");
		printf("          -h Uses an encoding given by user through <file>.par file.\n");
		exit(-1) ;

	default :
		printf("syf: errno unknown\n") ;
		exit(-1) ;
	}
}
msgBus()
{
printf("syf : Fatal error.\n");
printf("Please, send your file to cao-vlsi@masi.ibp.fr\n");
exit(-1) ;
}
/*---------------------------------------------------------
givParam	: ouvre le fichier de parametres et les lit. s'il n'y a pas de 
			  fichier de parametres renvoie 0, sinon 1.
			  codage.
----------------------------
parametres	: les adresses de parametres .
----------------------------
return		: int.
-----------------------------------------------------------*/
givParam(fileName,outOpt,stackOpt,behavOpt)
char *fileName ;
int *outOpt, *stackOpt, *behavOpt ;
{
FILE *file ;
char *s ;
char par[30] ;
char newline[30] ;
int val,line ;

/* par defaut les parm sont a 1 */
*outOpt = 1 ;
*stackOpt = 1 ;
*behavOpt = 1 ;

for(line = 0; line < 30; line++)
	newline[line] = (char)NULL ;
line = 0 ;
if((file = fopen(fileName,"rt")))
	{
	s = (char *)mbkalloc(200) ;
 
	while(fgets(s,200,file) != NULL)
		{
		while(!strncmp(s," ",1) || !strncmp(s," ",1))/*elimination des blancs*/
			s++ ;
 	 
		line++ ;
		if(strncmp(s,"#",1) && strncmp(s,"\n",1) && strcmp(s,""))
			{
			if((sscanf(s,"%s %d %s",par, &val, newline) != 2) || (val != 0 && val != 1))
				{
			   printf("syf : assignement error in %s, Line %d\n",fileName,line);
				exit(-1) ;
				}
			if(!strcmp(par,"OUT_OPTIM") || !strcmp(par,"out_optim"))
					*outOpt = val ;
			else if(!strcmp(par,"STACK_OPTIM") || !strcmp(par,"stack_optim"))
					*stackOpt = val ;
			else if(!strcmp(par,"BEHAV_OPTIM") || !strcmp(par,"behav_optim"))
					*behavOpt = val ;
			else
				{
				printf("syf : Invalide Parameter name in %s, Line %d\n",fileName,line);
				exit(-1) ;
				}
			}
		}
	}
/*#ifdef ARCHI_PC
*stackOpt = 0 ;
*behavOpt = 0 ;
#endif*/
}
/*---------------------------------------------------------
verifOption	: Verifie la coherence des options :
			  - pseudorom et typeMachine non MOORE.
			  - stack et machine sans pile.
----------------------------
parametres	: .
----------------------------
return		: .
-----------------------------------------------------------*/
verifOption()
{

if(autoSys->typeMachine != MOORE && syf_pseudorom)
	{
	printf("MEALEY FSM : pseudorom implementation impossible\n") ;
	exit(-1) ;
	}
if(!flagPile && syf_stack)
	{
	printf("FSM without STACK: STACK optimization impossible\n") ;
	exit(-1) ;
	}
if(syf_rom && syf_pseudorom)
	{
	printf("rom and pseudorom incompatible options\n") ;
	exit(-1) ;
	}
}
