/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit : DESB  v2.n                                                  */
/*    Fichier : genvhdl.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 : ../../....     */
/*                                                                          */
/****************************************************************************/

#include"head.h"

short D2V_VECTORISE = 0 ;
char  D2V_LANG          ;

static void   addOneZero();

/****************************************************************************
*                             function vhd()                                *
****************************************************************************/
void d2vVhd(desafig,file,vector,supply,version,language)
desafig_list *desafig ;   /* fig pointer                         */
char * file;              /* name of the file to generate        */
int vector ;              /* 1: ports are vectorised, 0 no       */
int supply ;              /* 0: one power supply and ground only */
                          /* 1: all power supplies and grounds   */
char * version;           /* version of libd2v                   */
char language ;

{
FILE *fic ;


   /*--------------+
   | Vectorisation |
   +--------------*/
   if(vector==1) D2V_VECTORISE = 1 ;
 
D2V_LANG = language ;


/*--------------------------------------------------*
 * ouverture du fichier resultat et entete du vhdl  *
 *-------------------------------------------------*/
fic=mbkfopen(file,DSB_VHDSFX,WRITE_TEXT);
   if(fic==NULL)
   {
   char buff[80];
   sprintf(buff,"%s.vbe",file);
   d2vFatalError(2,NULL,buff,NULL,0);
   }


/*-----------------------------------------*
 | Pretraitement sur les noms              |
 | Regularisation des noms a la norme VHDL |
 *----------------------------------------*/
{
cone_list *cone ;
locon_list *locon ;

   for(locon = desafig->LOCON ; locon ; locon = locon->NEXT)
   {
   int i = 0 ;
   char * name = locon->NAME ;
   name=debVectName(name); /* on remet des '[' */

      if(D2V_VECTORISE==1)
      {
         while(name[i]!='\0')
         {
            if(name[i]=='[') name[i]='(' ;
            if(name[i]==']') name[i]=')' ;
         i++;
         }
      }

   locon->NAME=namealloc(vhdlname(name));
   }

   for(cone=desafig->CONE;cone!=NULL;cone=cone->NEXT)
   {
   chain_list * renom ;
   cone->NAME=namealloc(debVectName(cone->NAME));

      /*---------------------------------------+
      | Remplacement eventuelle par du renomage |
      +----------------------------------------*/
      for(renom=INF_RENOM;renom!=NULL;renom=renom->NEXT)
      {
      char * nomOrig ;
      char * nomReno ;
      char * test    ;
      chain_list * couple ;

      couple=(chain_list*)renom->DATA ;
      nomOrig=namealloc((char*)couple->DATA) ;
      nomReno=namealloc((char*)((couple->NEXT)->DATA));

         if((test=d2vJokSubstName(cone->NAME,nomOrig,nomReno))!=NULL)
         {
         cone->NAME=test;
         break ;
         }

         else if(namealloc(cone->NAME)==nomOrig) 
         {
         cone->NAME=nomReno;
         break ;
         }
      }

      if(D2V_VECTORISE==1)
      {
      char * name =cone->NAME ;
      name=d2vVectName(name);
      }

   cone->NAME=namealloc(vhdlname(cone->NAME));
   }
}

/*--------------------------------------------------------------------------*
 * pretraitement des cones externes : si cone et connecteur ont meme signal,*
 * le nom du cone=nom du connecteur. L'ancien nom est garde dans le champ   *
 * USER pour etre remis en place a la fin de vhd()                          *
 *--------------------------------------------------------------------------*/

{
cone_list *cone ;

   for(cone = desafig->CONE ; cone ; cone = cone->NEXT)
   {
      if(((cone->TYPE & EXT) == EXT)&&(cone->PATH!=NULL))
      {
      list_list *incone = cone->INCONE ;
      list_list *outcone ;

         /*-------------------+
         | Si cone connecteur |
         +-------------------*/
         if(((incone->TYPE & EXT) == EXT) &&
         (incone->NEXT == NULL) &&                     
         (cone->PATH->NEXT == NULL) &&                
         ((((link_list *)cone->PATH->DATA)->TYPE & IN) == IN) && 
         (((link_list *)cone->PATH->DATA)->NEXT == NULL))       
         {
         cone->USER = addptype(cone->USER,OLDNAME,cone->NAME) ;
         cone->NAME = ((locon_list *)incone->DATA)->NAME ;
         cone->TYPE |= MARK ;
         }

         else
         {
         /*----------------------------------------------------------------*
         * on cherche, si ce n'est pas un cone connecteur, si il y a un    *
         *  connecteur en sortie. Alors cone->NAME = connect->NAME         *
         *----------------------------------------------------------------*/
         int n_out=0;
         int n_ext=0;
         list_list *savout;
         locon_list * xout;

            for(outcone = cone->OUTCONE ; outcone ; outcone = outcone->NEXT)
            {
            n_out++;
               if((outcone->TYPE & EXT) == EXT)
               {
               n_ext++;
               savout=outcone;
               }
            }
         
            if(n_ext!=0)
            {
            ptype_list * user ;
            chain_list * xRef ;
            int nRef=0;

            xout = (locon_list*) savout->DATA;
            cone->USER = addptype(cone->USER,OLDNAME,cone->NAME) ;
            cone->NAME =xout->NAME ;
            cone->TYPE|=MARK;

            /*------------------------------------------------+
            |  si le cone qui a le connecteur en sortie drive |
            | un autre cone, le connecteur devra etre inout   |
            | au sens vhdl: cone->TYPE |= INTERM              |
            +------------------------------------------------*/ 
               if((xout->DIRECTION=='B')&&(n_out>1))
               {
               cone->TYPE|=INTERM;
               }
            }
         }
      }
   }
}

/*------------------------------------+
| Ecriture de l'interface             |
+------------------------------------*/
fprintf(fic,"-- Generation Desb->Vhdl d2v V%s de %s\n\n",version,desafig->NAME) ;
fprintf(fic,"entity %s is  \n",desafig->NAME) ;
fprintf(fic,"\n");
d2vGenPort(fic,desafig,supply);

/*------------------------------------------------*
| Ecriture de l'architecture fonctionnelle       |
*------------------------------------------------*/
{
cone_list * cone;
vect_list * vect;
short coneVss = 0 ;
short coneVdd = 0 ;

fprintf(fic,"architecture FUNCTIONNAL of %s is \n",desafig->NAME);

  /*-------------------------------------------------------*
   | Liste des signaux internes                           |
   *------------------------------------------------------*/

   for(cone=desafig->CONE; cone != NULL; cone=cone->NEXT)
   {
      if ((cone->TYPE & VDD)==VDD) continue ;
      else if ((cone->TYPE & VSS)==VSS) continue;
      else if((cone->INCONE==NULL)&&(cone->OUTCONE==NULL)) continue ;
      else if ((cone->TYPE & INTERM)==INTERM) continue ;
      else if ((cone->TYPE & INUTIL)==INUTIL) continue ;
      else if((cone->TYPE & EXT)==EXT) continue;
      else if((cone->TYPE & MAST)==MAST ) continue ;

      else if((cone->TYPE & (LATCH | MEMORY))==MEMORY)
      {
         if(d2vAddVectName(cone->NAME,D2V_BIT)==0)
         continue ;
      fprintf(fic,"signal %s : bit ;\n",cone->NAME);
      }

      else if((cone->TYPE & LATCH)==LATCH)
      {
         if(d2vAddVectName(cone->NAME,D2V_REGISTER)==0)
         continue ;
      fprintf(fic,"signal %s : reg_bit register ;\n",cone->NAME);
      }

      else if((cone->TYPE & HZ)!=HZ)
      {
         if(d2vAddVectName(cone->NAME,D2V_BIT)==0)
         continue ;
      fprintf(fic,"signal %s : bit ;\n",cone->NAME);
      }

      else if((cone->TYPE & HZ)==HZ)
      {
         if(d2vAddVectName(cone->NAME,D2V_WOR)==0)
         continue ;
      fprintf(fic,"signal %s : mux_bit bus ;\n",cone->NAME);
      }

      else 
      {
      fprintf(stdout,"*** d2v *** genvhdl : cone %s de type inconnu",cone->NAME);
      fflush(stdout);
      exit(-1);
      }
   }

/* On ajoute dsb_one ou dsb_zero si necessaire */
addOneZero(desafig,fic);

   for(vect=D2V_VECT_LIST;vect!=NULL;vect=vect->NEXT)
   {
      switch(vect->TYPE)
      {
         case(D2V_BIT) :
         {
         fprintf(fic,"signal %s : bit_vector",vect->NAME);
         fprintf(fic,"(%d to %d) ;\n",vect->MINIDX,vect->MAXIDX);
         break ;
         }

         case(D2V_INTERM) :
         {
         fprintf(fic,"signal desb_%s : bit_vector",vect->NAME);
         fprintf(fic,"(%d to %d) ;\n",vect->MINIDX,vect->MAXIDX);
         break ;
         }

         case(D2V_WOR) :
         {
         fprintf(fic,"signal %s : mux_vector",vect->NAME);
         fprintf(fic,"(%d to %d) bus ;\n",vect->MINIDX,vect->MAXIDX);
         break ;
         }

         case(D2V_REGISTER) :
         {
         fprintf(fic,"signal %s : reg_vector",vect->NAME);
         fprintf(fic,"(%d to %d) register ;\n",vect->MINIDX,vect->MAXIDX);
         break ;
         }
      }
   }

fprintf(fic,"\nbegin\n");

d2vGenAssert(fic,D2V_VECTORISE);

   for(cone=desafig->CONE; cone != NULL; cone=cone->NEXT)
   {


      if((cone->TYPE & PATH_PARA)==PATH_PARA) prepParallCone(cone);
      if((cone->TYPE & INUTIL)==INUTIL) continue ;

      else if(((cone->TYPE & VSS)==VSS) && (coneVss ==0))
      {
      fprintf(fic,"dsb_zero <= '0' ;\n");
      coneVss =1;
      }

      else if(((cone->TYPE & VDD)==VDD) && (coneVdd ==0))
      {
      fprintf(fic,"dsb_one <= '1' ;\n");
      coneVdd =1;
      }

      else if ((cone->TYPE & SLAVE)==SLAVE) continue ;

      else if ((cone->TYPE & MAST )==MAST)  
      fprintf(fic,"%s",hashchar_toto(latchexpr(cone))) ;

      else if ((cone->TYPE & LATCH )==LATCH)  
      fprintf(fic,"%s",hashchar_toto(latchexpr(cone))) ;

      else if ((cone->TYPE & MEMORY)==MEMORY)  
      {
      ptype_list * user = getptype(cone->USER,MEMORY) ;
      cone_list * memory = (cone_list *)user->DATA ;
      fprintf(fic,"%s <= not %s ;\n",cone->NAME,memory->NAME);
      }
      
      else if (((cone->TYPE)&HZ)!=HZ) 
      fprintf(fic,"%s",hashchar_toto(dualexpr(cone)));

      else if (((cone->TYPE)&HZ)==HZ) 
      fprintf(fic,"%s",hashchar_toto(hzexpr(cone))); 
   }
fprintf(fic,"end FUNCTIONNAL ;\n");
fclose(fic);
}

{
/*--------------------------------------------------+
| On detruit les champs OLD_NAME                    |
+--------------------------------------------------*/
cone_list * Cone ;
   for(Cone = desafig->CONE ; Cone!=NULL;Cone=Cone->NEXT)
   {
   ptype_list * coneUser = getptype(Cone->USER,OLDNAME);
      if(coneUser != NULL)  Cone->USER = delptype(Cone->USER,OLDNAME) ;
   }
}

}

/****************************************************************************
 *                         fonction d2vGenPort();                           *
 ****************************************************************************/
void  d2vGenPort(fic,desafig,sup)
FILE * fic ;
desafig_list *desafig ;
int sup  ;            /* 0 one supply ; 1 all supplies */
{
locon_list *connect ;
vect_list * vect ;
short vssAlim=0;
short vddAlim=0;
short noVect =0;

fprintf(fic,"   port \n");
fprintf(fic,"     (\n");

   /*----------------------------------------------------------+
   | On n'ecrit le premier connecteur qui n`est pas un vecteur |
   +----------------------------------------------------------*/
   for(connect=desafig->LOCON;connect!=NULL;connect=connect->NEXT)
   {
      switch(connect->DIRECTION)
      {
         case ('X') :   /* transparence et unknown */
         {
            if(d2vAddVectName(connect->NAME,D2V_IN)==0) break ;
         fprintf(fic,"%s : in bit ",connect->NAME);
         noVect++;
         break;
         }

         case ('I') : 
         {
            if(d2vAddVectName(connect->NAME,D2V_IN)==0) break ;
         fprintf(fic,"%s : in bit ",connect->NAME);
         noVect++;
         break;
         }

         case ('O') :
         {
            if(d2vAddVectName(connect->NAME,D2V_OUT)==0) break ;
         fprintf(fic,"%s : out bit ",connect->NAME);
         noVect++;
         break;
         }

         case ('A') : 
         {
            if(test_chainin(connect->NAME,NAME_VDD)==1) 
            {
            vddAlim++ ;
               if(sup==0) fprintf(fic,"%s : in bit ",NAME_VDD);
               else fprintf(fic,"%s : in bit ",connect->NAME);
            }
            else if(test_chainin(connect->NAME,NAME_VSS)==1) 
            {
            vssAlim++;
              if(sup==0) fprintf(fic,"%s : in bit ",NAME_VSS);
              else fprintf(fic,"%s : in bit ",connect->NAME);
            }
         noVect++;
         break ;
         }
      
         case ('B') : 
         {
         ptype_list * user;
         cone_list * cone ;
         cone=(cone_list*)getptype(connect->USER,EXT)->DATA ;

            if((cone->TYPE & INTERM)==INTERM)
            {
               if(d2vAddVectName(connect->NAME,D2V_INOUT)==0) break ;
            fprintf(fic,"%s : inout bit ",connect->NAME);
            noVect++;
            break;
            }
            else
            {
               if(d2vAddVectName(connect->NAME,D2V_OUT)==0) break; 
            fprintf(fic,"%s : out bit ",connect->NAME);
            noVect++;
            break;
            }
         }

         case ('T') : 
         {
            if(d2vAddVectName(connect->NAME,D2V_INOUT_WOR)==0) break ; 
         fprintf(fic,"%s : inout mux_bit bus ",connect->NAME);
         noVect++ ;
         break ;
         }

         case ('Z') : 
         {
            if(d2vAddVectName(connect->NAME,D2V_OUT_WOR)==0) break ; 
         fprintf(fic,"%s : out mux_bit bus ",connect->NAME);
         noVect++ ;
         break ;
         }

         default  :
         {
         printf("*** desb *** genvhdl : connecteur %s ",connect->NAME);
         printf("de direction inconnue\n");
         exit(-1) ;
         break ;
         }
      }
      if(noVect!=0) break ;
   }

   /*------------------------------------+
   | on ecrit les connecteurs suivants   |
   +------------------------------------*/
   for(connect=connect->NEXT;connect != NULL;connect=connect->NEXT)
   {
   short alim=0;

      switch(connect->DIRECTION)
      {
         case ('X') :
         {
            if(d2vAddVectName(connect->NAME,D2V_IN)==0)
            continue ;
         fprintf(fic,";\n%s : in bit ",connect->NAME);
         break;
         }

         case ('I') : 
         {
            if(d2vAddVectName(connect->NAME,D2V_IN)==0)
            continue ;
         fprintf(fic,";\n%s : in bit ",connect->NAME);
         break;
         }

         case ('O') :
         {
            if(d2vAddVectName(connect->NAME,D2V_OUT)==0)
            continue ;
         fprintf(fic,";\n%s : out bit ",connect->NAME);
         break;
         }

         case ('A') : 
         {
            if(test_chainin(connect->NAME,NAME_VDD)==1)
            {
               if  ((vddAlim!=0)&&(sup==0)) continue ;
               else 
               {
               vddAlim++ ;
                  if(sup==0) fprintf(fic,";\n%s : in bit ",NAME_VDD);
                  else fprintf(fic,";\n%s : in bit ",connect->NAME);
               }
            }

            else if(test_chainin(connect->NAME,NAME_VSS)==1)
            {
               if ((vssAlim!=0)&&(sup==0)) continue ;
               else 
               {
               vssAlim++ ;
                  if(sup==0) fprintf(fic,";\n%s : in bit ",NAME_VSS);
                  else fprintf(fic,";\n%s : in bit ",connect->NAME);
               }
            }
         break ;
         }
      
         case ('B') : 
         {
         ptype_list * user ;
         cone_list * cone ;
         cone=(cone_list*)getptype(connect->USER,EXT)->DATA ;

            if((cone->TYPE & INTERM)==INTERM)
            {
               if(d2vAddVectName(connect->NAME,D2V_INOUT)==0)
               continue ;
            fprintf(fic,";\n%s : inout bit ",connect->NAME);
            }
            else
            {
               if(d2vAddVectName(connect->NAME,D2V_OUT)==0)
               continue ;
            fprintf(fic,";\n%s : out bit ",connect->NAME);
            }
         break;
         }

         case ('T') : 
         {
            if(d2vAddVectName(connect->NAME,D2V_INOUT_WOR)==0)
            continue ;
         fprintf(fic,";\n%s : inout mux_bit bus ",connect->NAME);
         break ;
         }

         case ('Z') : 
         {
            if(d2vAddVectName(connect->NAME,D2V_OUT_WOR)==0)
            continue ;
         fprintf(fic,";\n%s : out mux_bit bus ",connect->NAME);
         break ;
         }

         default    :
         {
         printf("*** desb *** genvhdl : connecteur %s ",connect->NAME);
         printf("de direction inconnue\n");
         break ;
         }
      }
   }

   /*-----------------------+
   | Ecriture des Vecteurs  |
   +-----------------------*/
   for(vect=D2V_VECT_LIST;vect!=NULL;vect=vect->NEXT)
   {
      switch (vect->TYPE) 
      {
         case(D2V_IN) :
         {
            if(((vect->MAXIDX-vect->MINIDX)+1)!=vect->COUNT)
            {
            d2vFatalError(3,NULL,vect->NAME,NULL,0);
            }
         fprintf(fic,";\n%s : in bit_vector",vect->NAME);
         fprintf(fic,"(%d to %d)",vect->MINIDX,vect->MAXIDX);
         break ;
         }

         case(D2V_OUT) :
         {
            if(((vect->MAXIDX-vect->MINIDX)+1)!=vect->COUNT)
            {
            d2vFatalError(3,NULL,vect->NAME,NULL,0);
            }
         fprintf(fic,";\n%s : out bit_vector",vect->NAME);
         fprintf(fic,"(%d to %d)",vect->MINIDX,vect->MAXIDX);
         break ;
         }
         
         case(D2V_INOUT) :
         {
            if(((vect->MAXIDX-vect->MINIDX)+1)!=vect->COUNT)
            {
            d2vFatalError(3,NULL,vect->NAME,NULL,0);
            }
         fprintf(fic,";\n%s : inout bit_vector",vect->NAME);
         fprintf(fic,"(%d to %d)",vect->MINIDX,vect->MAXIDX);
         break ;
         }

         case(D2V_OUT_WOR) :
         {
            if(((vect->MAXIDX-vect->MINIDX)+1)!=vect->COUNT)
            {
            d2vFatalError(3,NULL,vect->NAME,NULL,0);
            }
         fprintf(fic,";\n%s : out mux_vector",vect->NAME);
         fprintf(fic,"(%d to %d) bus",vect->MINIDX,vect->MAXIDX);
         break ;
         }

         case(D2V_INOUT_WOR) :
         {
            if(((vect->MAXIDX-vect->MINIDX)+1)!=vect->COUNT)
            {
            d2vFatalError(3,NULL,vect->NAME,NULL,0);
            }
         fprintf(fic,";\n%s : inout mux_vector",vect->NAME);
         fprintf(fic,"(%d to %d) bus",vect->MINIDX,vect->MAXIDX);
         break ;
         }

      }
   }
d2vFreeVectList();
fprintf(fic,"\n     );\n");
fprintf(fic,"   end %s ;\n\n",desafig->NAME);
}

/****************************************************************************
 *                         fonction hashchar();                             *
 ****************************************************************************/
char* hashchar_titi(chaine)
char * chaine ;
{
int i =0;
int j=0;
char * res ;

char *buff =(char*)mbkalloc(strlen(chaine)+1);


   for (i=0; chaine[i] != '\0' ; i++)
   {
   buff[j++]=chaine[i];
      if(((i%240)==0)&&(i!=0))
         {
         i++;
         while((chaine[i]!='\0')&&(chaine[i]!= ' ')) buff[j++]=chaine[i++] ;

         if(chaine[i]!='\0') buff[j++]='\n';
         else break;
         }
   }
   buff[j]='\0';
res=(char*)mbkalloc(strlen(buff)+1);
strcpy(res,buff);
return(res);
}

/****************************************************************************
 *                         fonction hashchar();                             *
 ****************************************************************************/
char* hashchar_toto(chaine)
char * chaine ;
{
int i =0;
int j=0;
int k = 0 ;
char * res ;

char *buff =(char*)mbkalloc(strlen(chaine)+1);


   for (i=0; chaine[i] != '\0' ; i++)
   {
   buff[j++]=chaine[i];
   k++;
      if(chaine[i]=='\n') k=1 ;
      if((k%70)==0)
         {
         i++;
            while((chaine[i]!='\0')&&(chaine[i]!= ' ')) buff[j++]=chaine[i++] ;

            if(chaine[i]!='\0') 
            {
            buff[j++]='\n';
            k=1;
            }
            else break;
         }
   }
   buff[j]='\0';
res=(char*)mbkalloc(strlen(buff)+1);
strcpy(res,buff);
return(res);
}


/****************************************************************************
 *                         fonction addOneZero();                           *
 ****************************************************************************/
/*-------------------------------------------------------------------------+
| renome tous les cone alimentation en dsb_one ou desb_zero selon le cas   |
| Si necessaire, ajoute dsb_one et dsb_zero dans la declaration des signaux|
+-------------------------------------------------------------------------*/
static void addOneZero(fig,fic)
desafig_list * fig ;  /* la figure desb */
FILE         * fic ;  /* le fichier vbe */
{
cone_list * cone ;
short addOne = 0 ;
short addZero = 0 ;

   for(cone=fig->CONE;cone!=NULL;cone = cone->NEXT)
   {
      if((cone->TYPE & VSS)==VSS) 
      {
      cone->NAME = namealloc("dsb_zero");
         if(addZero ==0)
         {
         fprintf(fic,"signal dsb_zero : bit ;\n");
         addZero++;
         }
      }
      else if((cone->TYPE & VDD)==VDD) 
      {
      cone->NAME = namealloc("dsb_one");
         if(addOne == 0 )
         {
         fprintf(fic,"signal dsb_one : bit ;\n");
         addOne++;
         }
      }
   }
}
   
/****************************************************************************
 *                         fonction prepParallCone();                       *
 ****************************************************************************/
void  prepParallCone(cone)
cone_list * cone ;
{
list_list * path ;
ptype_list * user ;
chain_list * chain ;
chain_list * chainAux ;

user = getptype(cone->USER,PATH_PARA);

   for(chain=(chain_list*)user->DATA ; chain!=NULL;chain=chain->NEXT)
   {
      for(chainAux=((chain_list*)chain->DATA)->NEXT;
          chainAux!=NULL;
          chainAux=chainAux->NEXT )
      {
      path=(list_list*)chainAux->DATA ;
      path->TYPE |= PATH_PARA ;
      }
   }
}
      

