/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit : DESB  v2.n                                                  */
/*    Fichier : genexpr.c                                                   */
/*                                                                          */
/*    (c) copyright 1991 Laboratoire MASI equipe CAO & VLSI                 */
/*    Tous droits reserves                                                  */
/*    Support : e-mail cao-vlsi@masi.ibp.fr                                 */
/*                                                                          */
/*    Auteur(s) : Marc LAURENTIN                        le : 06/09/1991     */
/*                                                                          */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*                                                                          */
/****************************************************************************/

                     /*------------------------------------*
                      |  Generation VHDL "bas-niveau"      |
                      *------------------------------------*/  

#include "head.h"

static int LABEL_INDEX = 0 ;

static short pathIsResist();
static list_list *  prepLatchPath();
static void  restoreLatchPath();
static long comInPath();

/****************************************************************************
 *                         fonction dualexpr();                             *
 ****************************************************************************/

    /*-----------------------------------------------------------*
     |  Renvoie une chaine de caracteres contenant l'expression  |
     |  VhDl d'un cone  ~HZ                                      |
     *-----------------------------------------------------------*/

char * dualexpr(cone)
cone_list * cone;
{
short flagup = 0;
short flagex = 0;
short flagdw = 0;
short pathVss = 0 ;
list_list * path;
int i=1;
int maxLength = 4000 ;
char * res ;



char * expr=(char*)malloc(5000);

strcpy(expr,(char*)cone->NAME);

strcat(expr," <= ");
   for(path=cone->PATH;path != NULL;path=path->NEXT)
   {
      if(((path->TYPE)&BLEEDER) ==BLEEDER) continue;   
      if((path->TYPE & PATH_PARA)==PATH_PARA) continue ;

      if(((path->TYPE)&VSS )== VSS) 
      {
      pathVss = 1;
      continue;
      }

      if(((path->TYPE)&VDD)==VDD)
      {
      flagup=1;
      strcat(expr,genprod(path));
      strcat(expr," or ");
      }
      if(((path->TYPE)&EXT)==EXT)
      {
         if(((link_list*)path->DATA)->NEXT!=NULL)
         {
         flagex=1;
         strcat(expr,genexprod(path));
         strcat(expr," or ");
         }
      }

      if(strlen(expr) > maxLength)
      {
      expr=(char*)realloc(expr,((5000)+(i*1000)));
         if(expr==NULL)
         {
         d2vFatalError(4,NULL,NULL,NULL,0);
         }
      i++ ;
      maxLength+=1000 ;
      }
   }

   if (((flagup+flagex)==0) && (pathVss!=0))
   {
   strcat(expr,"not(");
      for (path=cone->PATH;path != NULL; path=path->NEXT)
      {
         if((path->TYPE & PATH_PARA)==PATH_PARA) continue ;
         if  ((path->TYPE & (VSS|BLEEDER))==VSS)
         {
         flagdw =1 ;
         strcat(expr,genprod(path));
         strcat(expr," or ");
         }
         else continue ;
      }
   }

   if (((flagup+flagex)==0) && (pathVss==0)) /* cone connecteur */
   {
   free(expr);
   return(""); 
   }
   
   /* on enleve le dernier or */ 
   expr[strlen(expr)-4]='\0';

   if(flagdw!=0) strcat(expr,")");

strcat(expr," ;\n");
res=(char*)mbkalloc(strlen(expr)+1);
strcpy(res,expr);
free(expr);
return(res);
}




/****************************************************************************
 *                         fonction genprod();                              *
 ****************************************************************************/

    /*----------------------------------------------*
     |  renvoie l'expression vhdl dune branche VDD  |
     |          ou VSS                              |
     |  entree : un pointeur de branche             |
     |  sortie : une chaine de caractere            |
     *----------------------------------------------*/

char * genprod(ptpath)
list_list * ptpath;
{
char buff[3000];
char * res = NULL;
cone_list * ptcone = NULL ;
link_list * ptlink = NULL ;
short n_link = 0;
short n_resist = 0;

strcpy(buff,"(");

   for ( ptlink = (link_list*)ptpath->DATA;ptlink != NULL ;ptlink=ptlink->NEXT)
   {
   n_link++;

      if ((ptlink->TYPE & TP ) == TP ) 
      {
      strcat(buff,"not ");
      }

   ptcone=(cone_list*)ptlink->TRANS->GRID;
   strcat(buff,(char*)ptcone->NAME);
   strcat(buff," and ");
   }

   /*  J'enleve le dernier ET , on rajoute une parenthese */
   buff[strlen(buff)-5]=')';
   buff[strlen(buff)-4]='\0';

res=(char*)mbkalloc(strlen(buff)+1);
strcpy(res,buff);
return(res);
} 
         
         

/****************************************************************************
 *                         fonction genexprod();                            *
 ****************************************************************************/

    /*----------------------------------------------*
     |  renvoie l'expression vhdl dune branche EXT  |
     |          connecteur compris                  |
     |  entree : un pointeur de branche             |
     |  sortie : une chaine de caractere            |
     *----------------------------------------------*/
char * genexprod(ptpath)
list_list * ptpath;
{
char buff[3000];
char * res = NULL;
cone_list * ptcone = NULL ;
link_list * ptlink = NULL ;
locon_list * connect = NULL ;

strcpy(buff,"(");

   for ( ptlink = (link_list*)ptpath->DATA;ptlink != NULL ;ptlink=ptlink->NEXT)
   {
      if ((ptlink->TYPE & TP ) == TP ) 
      {
      strcat(buff,"not ");
      ptcone=(cone_list*)ptlink->TRANS->GRID;
      strcat(buff,(char*)ptcone->NAME);
      strcat(buff," ");
      }
      else  if((ptlink->TYPE & TN)==TN)
      {
      ptcone=(cone_list*)ptlink->TRANS->GRID;
      strcat(buff,(char*)ptcone->NAME);
      }
      else if((ptlink->NEXT== NULL))
      {
      connect=(locon_list*)ptlink->TRANS;
      strcat(buff,(char*)connect->NAME);
      }

   strcat(buff," and ");
   }
   

/*on enleve le dernier ET , on rajoute une parenthese */
buff[strlen(buff)-5]=')';
buff[strlen(buff)-4]='\0';

res=(char*)mbkalloc(strlen(buff)+1);
strcpy(res,buff);
return(res);
} 
         
         
/****************************************************************************
 *                         fonction genexssconct();                           *
 ****************************************************************************/

    /*----------------------------------------------*
     |  renvoie l'expression vhdl dune branche EXT  |
     |          connecteur non compris              |
     |  entree : un pointeur de branche             |
     |  sortie : une chaine de caractere            |
     *----------------------------------------------*/

char * genexssconct(ptpath)
list_list * ptpath;
{
char buff[3000];
char * res = NULL;
cone_list * ptcone = NULL ;
link_list * ptlink = NULL ;

strcpy(buff,"(");

   for ( ptlink = (link_list*)ptpath->DATA;ptlink != NULL ;ptlink=ptlink->NEXT)
   {
      if ((ptlink->TYPE & TP ) == TP ) 
      {
      strcat(buff,"not ");
      ptcone=(cone_list*)ptlink->TRANS->GRID;
      strcat(buff,(char*)ptcone->NAME);
      strcat(buff," ");
      }
      else  if((ptlink->TYPE & TN)==TN)
      {
      ptcone=(cone_list*)ptlink->TRANS->GRID;
      strcat(buff,(char*)ptcone->NAME);
      }
      else break ;

   strcat(buff," and ");
   }
   

/*on enleve le dernier ET , on rajoute une parenthese */

buff[strlen(buff)-5]=')';
buff[strlen(buff)-4]='\0';

res=(char*)mbkalloc(strlen(buff)+1);
strcpy(res,buff);
return(res);
} 

/****************************************************************************
 *                         fonction hzexpr();                               *
 ****************************************************************************/

     /*---------------------------------------------------*
      |   Renvoie l'expression vhdl d' un cone HZ         |
      |   Entree : Un pointeur de cone HZ                 |
      |   Sortie : Une chaine de caractere                |
      *---------------------------------------------------*/

char * hzexpr(cone)
cone_list * cone ;
{
short flagup = 0;
short flagdw = 0;
short flagex = 0;
char *res;
char buff[5];
list_list * path;

char * fup=(char*)malloc(8000);
char * fdw=(char*)malloc(8000);
char * fex=(char*)malloc(8000);
char * expr ;

int szFup = 5000 ;
int szFdw = 5000 ;
int szFex = 5000 ;

int iFup = 1;
int iFdw = 1;
int iFex = 1;





   for(path=cone->PATH;path != NULL;path=path->NEXT)
   {
      if((path->TYPE & BLEEDER)==BLEEDER) continue ;
      if((path->TYPE & PATH_PARA)==PATH_PARA) continue ;
      if((path->TYPE & VDD)==VDD)
      {
         if(flagup==0)
         {
         sprintf(fup,"\nlb%d",LABEL_INDEX++);
         strcat(fup," : block (( ");
         }
      flagup=1;
      strcat(fup,genprod(path));
      strcat(fup," or ");
      }

      else if((path->TYPE & VSS)==VSS)
      {
         if(flagdw==0)
         {
         sprintf(fdw,"\nlb%d",LABEL_INDEX++);
         strcat(fdw," : block (( ");
         }
      flagdw=1;
      strcat(fdw,genprod(path));
      strcat(fdw," or ");
      }

      else if(((path->TYPE & EXT)==EXT)&&(((link_list*)path->DATA)->NEXT!=NULL))
      {
      link_list * link;
         if(flagex==0) sprintf(fex,"\nlb%d",LABEL_INDEX++);
         else 
         {
         sprintf(buff,"\nlb%d",LABEL_INDEX++);
         strcat(fex,buff);
         }
      flagex=1;
      strcat(fex," : block (( ");
      strcat(fex,genexssconct(path));
      strcat(fex," ) ='1' )\nbegin\n");
         for(link=(link_list*)path->DATA;link->NEXT!=NULL;link=link->NEXT) ;
      strcat(fex,"   ");
      strcat(fex,cone->NAME);
      strcat(fex," <= guarded ");
      strcat(fex,((locon_list*)(link->TRANS))->NAME);
      strcat(fex," ;\n end block ;\n");
      }

      if(strlen(fup)>szFup)
      {
      fup=(char*)realloc(fup,8000+(iFup*3000));
         if(fup==NULL)
         {
         d2vFatalError(4,NULL,NULL,NULL,0);
         }
      iFup++;
      szFup+=3000;
      }

      if(strlen(fdw)>szFdw)
      {
      fdw=(char*)realloc(fdw,8000+(iFdw*3000));
         if(fdw==NULL)
         {
         d2vFatalError(4,NULL,NULL,NULL,0);
         }
      iFdw++;
      szFdw+=3000;
      }

      if(strlen(fex)>szFex)
      {
      fex=(char*)realloc(fex,5000+(iFex*3000));
         if(fex==NULL)
         {
         d2vFatalError(4,NULL,NULL,NULL,0);
         }
      iFex++;
      szFex+=3000;
      }

   }

expr=(char*)malloc(strlen(fup)+strlen(fdw)+strlen(fex)+500);
expr[0]='\0';

   if ((flagup+flagdw+flagex)==0) 
   {
   free(fup);
   free(fdw);
   free(fex);
   free(expr);
   return("");
   }
   if(flagup==1)
   {
   fup[strlen(fup)-4]='\0'; /* on eleve le dernier OR */
   strcat(fup," ) ='1' )\nbegin\n");
   strcat(fup,"   ");
   strcat(fup,cone->NAME);
   strcat(fup," <= guarded '1' ;\n");
   strcat(fup,"end block ;\n");
   strcat(expr,fup);
   }
   if(flagdw==1)
   {
   fdw[strlen(fdw)-4]='\0'; /* on eleve le dernier OR */
   strcat(fdw," ) ='1' )\nbegin\n");
   strcat(fdw,"   ");
   strcat(fdw,cone->NAME);
   strcat(fdw," <= guarded '0' ;\n");
   strcat(fdw,"end block ;\n");
   strcat(expr,fdw);
   }
   if(flagex==1) strcat(expr,fex);

res=(char*)mbkalloc(strlen(expr)+1);
strcpy(res,expr);
free(fup);
free(fdw);
free(fex);
free(expr);
return(res);
}

/****************************************************************************
 *                         fonction latchexpr();                            *
 ****************************************************************************/
char * latchexpr(cone)
cone_list * cone;
{
cone_list * slave ;
ptype_list * mastUser;
list_list * path;
char bidon[5];
char * res;
cone_list * com;
list_list * in ;
int szBuff=4000 ;
int iBuff =1 ;

char * buff=(char*)malloc((unsigned)5000);
buff[0]='\0';

   /*--------------------------------------------------------------+
   | Si le latch est le maitre d'un maitre esclave, on genere une  |
   | equation qui attribue a l'esclave la fonctionnalite du maitre |
   +--------------------------------------------------------------*/
   if((cone->TYPE & MAST) == MAST)
   {
   mastUser=getptype(cone->USER,SLAVE);
   slave=(cone_list*)mastUser->DATA;
   }

   for(in=cone->INCONE;in!=NULL;in=in->NEXT)
   {
   chain_list * chUp = NULL ;
   chain_list * chDn = NULL ;
   chain_list * chXt = NULL ;
   cone_list * incone ;
   long        type   ;
   long        ttp ;

      if((in->TYPE & COMMAND)!=COMMAND) continue ;
      else com=(cone_list*)in->DATA ;

      for(path=cone->PATH;path!=NULL;path=path->NEXT)
      {
         if((path->TYPE & BLEEDER)==BLEEDER) continue ;
         if((path->TYPE & PATH_PARA)==PATH_PARA) continue ;

      ttp=comInPath(path,com);
         if(ttp != -1)
         {
         type=ttp;
            if((path->TYPE & VSS)==VSS)
            chDn=addchain(chDn,(void*)prepLatchPath(path,com));
            else if((path->TYPE & VDD)==VDD)
            chUp=addchain(chUp,(void*)prepLatchPath(path,com));
            if((path->TYPE & EXT)==EXT)
            chXt=addchain(chXt,(void*)prepLatchPath(path,com));
         }
      }
            
   sprintf(bidon,"lb%d",LABEL_INDEX++);
   strcat(buff,"\n");
   strcat(buff,bidon);
   strcat(buff," : block ( ");
   strcat(buff,com->NAME);

      if((cone->TYPE & MAST)==MAST)
      {
         if(type==TP)
         {
         strcat(buff," = '1' and not ");
         strcat(buff,com->NAME);
         strcat(buff,"'stable  )\nbegin\n   ");
         }
         else
         {
         strcat(buff," = '0' and not ");
         strcat(buff,com->NAME);
         strcat(buff,"'stable )\nbegin\n   ");
         }
      strcat(buff,slave->NAME);
      }
      else 
      {
         if(type==TP)
         strcat(buff," = '0' )\nbegin\n   ");
         else
         strcat(buff," = '1' )\nbegin\n   ");
      strcat(buff,cone->NAME);
      }
   strcat(buff," <= guarded ");

      /*---------------------------+
      | Traitement des branches UP |
      +----------------------------*/
      if(chUp != NULL)
      {
      chain_list * pchain ;
         for(pchain=chUp;pchain!=NULL;pchain=pchain->NEXT)
         {
         list_list * ppath = (list_list*)pchain->DATA ;
            if(ppath->DATA == NULL)
            {
            /* normalement il n y en pas d'autres */
            strcat(buff,"'1'   ");
            }
            else 
            {
            strcat(buff,genprod(ppath));
            strcat(buff," or ");
            }

            if(strlen(buff)>szBuff)
            {
            if((buff=(char*)realloc(buff,(unsigned)(5000+(iBuff*1000))))
                    ==NULL);
            d2vFatalError(4,NULL,NULL,NULL,0);
            iBuff++;
            szBuff+=1000 ;
            }
         restoreLatchPath(ppath);
         }
      }

      /*---------------------------+
      | Traitement des branches EXT |
      +----------------------------*/
      if(chXt != NULL)
      { 
      chain_list * pchain ;
         for(pchain=chXt;pchain!=NULL;pchain=pchain->NEXT)
         {
         list_list * ppath = (list_list*)pchain->DATA ;
         strcat(buff,genexprod(ppath));
         strcat(buff," or ");
            if(strlen(buff)>szBuff)
            {
            if((buff=(char*)realloc(buff,(unsigned)(5000+(iBuff*1000))))
                    ==NULL);
            d2vFatalError(4,NULL,NULL,NULL,0);
            iBuff++;
            szBuff+=1000 ;
            }
         restoreLatchPath(ppath);
         }
      }

      if((chUp==NULL)&&(chXt==NULL)&&(chDn!=NULL))
      {
      chain_list * pchain ;
      short flag = 0 ;
      list_list * ppath = (list_list*)chDn->DATA ;
         if(ppath->DATA == NULL)
         {
         /* normalement il n y en pas d'autres */
         strcat(buff,"'0'    ");
         }
         else
         {
         strcat(buff," not (");
            for(pchain=chDn;pchain!=NULL;pchain=pchain->NEXT)
            {
            strcat(buff,genprod(ppath));
            strcat(buff," or ");
               if(strlen(buff)>szBuff)
               {
               if((buff=(char*)realloc(buff,(unsigned)(5000+(iBuff*1000))))
                       ==NULL);
               d2vFatalError(4,NULL,NULL,NULL,0);
               iBuff++;
               szBuff+=1000 ;
               }
            }
         /* On enleve le dernier or */
         buff[strlen(buff)-4]='\0';
         strcat(buff,")    ");
         }
      restoreLatchPath(ppath);
      }
   buff[strlen(buff)-4]='\0';
   strcat(buff," ; \nend block ;\n");
   }
res=(char*)mbkalloc(strlen(buff)+1);
strcpy(res,buff);
free(buff);
return(res);
}


/****************************************************************************
 *                         fonction pathIsResist();                         *
 ****************************************************************************/
/*-------------------------------------------------------------------------+
| teste si une branche est essentiellememnt composee de resistances        |
| entree : path Un pointeur de branche                                     |
| retiur : 0 la branche est composee uniquement de resistances             |
|         -1 la branche ne contient pas que des resistances                |
+-------------------------------------------------------------------------*/
static short pathIsResist(path)
list_list * path ;
{
link_list * link ;

   for(link=(link_list*)path->DATA;link!=NULL;link=link->NEXT)
   {
      if((link->TYPE & RESIST)!=RESIST) break ;
   }

   if(link==NULL) return(0);
   else return(-1);
}
/****************************************************************************
 *                         fonction prepLatchPath();                        *
 ****************************************************************************/
static list_list * prepLatchPath(path,com)  
list_list * path ;
cone_list * com  ;
{
link_list * link ;

link = (link_list*)path->DATA ;

   if(com==(cone_list*)link->TRANS->GRID)   
   {
   path->DATA = (void*)(link->NEXT) ;
   path->USER=addptype(path->USER,DSB_LINK,(void*)link);
   }
   else 
   {
      for(link;link!=NULL;link=link->NEXT)
      {
         if(com==(cone_list*)link->NEXT->TRANS->GRID)
         {
         link->NEXT=link->NEXT->NEXT;
         link->USER=addptype(link->USER,DSB_LINK,(void*)link->NEXT);
         break ;
         }
      }
   }
return(path);
}
/****************************************************************************
 *                         fonction restoreLatchPath();                     *
 ****************************************************************************/
static void restoreLatchPath(path)
list_list * path ;
{
ptype_list * user = NULL  ;
link_list * link ;

   if(path->USER!=NULL) user=getptype(path->USER,DSB_LINK);
   if(user!=NULL)
   {
   link=(link_list*)user->DATA ;
   path->DATA=(void*)link ;
   delptype(path->USER,DSB_LINK);
   }

   else 
   {
      for(link=(link_list*)path->DATA;link!=NULL;link=link->NEXT)
      {
         if(link->USER==NULL) continue;
         if((user=getptype(link->USER,DSB_LINK))!=NULL) 
         {
         link->NEXT=(link_list*)user->DATA ;
         delptype(link->USER,DSB_LINK);
         break ;
         }
      }
   }
}
   
/****************************************************************************
 *                         fonction comInPath();                            *
 ****************************************************************************/
 /*-------------------------------------------------------------------------+
 | teste si la branche contient un transistor attaque par le cone 'com'     |
 | Entree : path pointeur de branche                                        |
 |          com un pointeur de cone                                         |
 | Retour : 0 com attaque un trans de path                                  |
 |         -1 dans la cas contraire                                         |
 +-------------------------------------------------------------------------*/
static long comInPath(path,com)
list_list * path ;
cone_list * com  ;
{
link_list * link ;

   for(link=(link_list*)path->DATA;link!=NULL;link=link->NEXT)
   {
      if((link->TYPE & (TP|TN))==0) return(-1);
      if(com==(cone_list*)link->TRANS->GRID) return((link->TYPE & (TP|TN)));
   }

return(-1);
}
      







