/********************************************************************
*                                                                   *
* 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                                 *
*                                                                   *
* Supervision & Modifications : Lotfi BEN AMMAR                     *
*                                                                   *
********************************************************************/
/*********************************************************************************
*                      Fichier: util_R.c                                         *
*       version : 2.2                                                            *
*       date    : 24/09/91                                                       *
*********************************************************************************/
#include "dpr_R.h"

/***************************************************************
**  fonction manorme() : transforme U/D en V et R/L en H      **
**  pour le type d'un segment (a cause des modifs MBK!!!)     **
***************************************************************/
 char manorme(segtype)
 char segtype;

 {
 if ((segtype=='R')||(segtype=='L'))
    {
    return('H');
    }
 else
    {
    if ((segtype=='U')||(segtype=='D'))
       {
       return('V');
       }
    else
       {
       printf("Error: Segment type %c not valid (MBK problem)!!\n",segtype);
       exit(100);
       }
    }
 }

/***************************************************************
**  fonction addvia() : rajoute un via en tete de liste.      **
***************************************************************/
 chain_list *addvia(ptchead,x,y,type)
 chain_list *ptchead;
 long        x,y;
 char        type;

 {
 VIA *ptnewvia;

 ptnewvia = (VIA *)mbkalloc(sizeof(VIA));

 ptnewvia->X    = x;
 ptnewvia->Y    = y;
 ptnewvia->TYPE = type;
 ptnewvia->USER = NULL;

 return addchain(ptchead,(void *)ptnewvia);

 }

/*********************************************************************
**          fonction addseg ();                                     **
*********************************************************************/
 chain_list *addseg(ptchead,ptname,x1,y1,x2,y2,width,type,layer)
 chain_list *ptchead;
 char       *ptname;
 long        x1, y1, x2, y2;
 long        width;
 char        type, layer;
 
 {
 SEGMENT   *ptseg=NULL;

 ptseg = (SEGMENT *)mbkalloc(sizeof(SEGMENT));
 
 ptseg->NAME = ptname ;
 ptseg->X1 = x1 ;
 ptseg->X2 = x2 ;
 ptseg->Y1 = y1 ;
 ptseg->Y2 = y2 ;
 ptseg->WIDTH = width ;
 ptseg->TYPE = type ;
 ptseg->LAYER = layer ;
 ptseg->USER = NULL ;

 return (addchain(ptchead,(void *)ptseg));
 
 }

/*********************************************************************
**     fonction addchannel() : creation de lastructure channel avec **
** ajout de lelement en tete de la liste .                          **
*********************************************************************/
 chain_list *addchannel(ptchead,ptsouth,ptnorth,ptwest,pteast)
 chain_list    *ptchead;
 ConnectorList *ptsouth;
 ConnectorList *ptnorth;
 ConnectorList *ptwest;
 ConnectorList *pteast;

 {
 CHANNEL *ptnewchan;

 ptnewchan = (CHANNEL *)mbkalloc(sizeof(CHANNEL));
 ptnewchan->SOUTHCON = ptsouth ;
 ptnewchan->NORTHCON = ptnorth ;
 ptnewchan->WESTCON  = ptwest ;
 ptnewchan->EASTCON  = pteast ;

 return addchain(ptchead,(void *)ptnewchan);

 }

 void affcon(fsortie,ptcon)
 FILE      *fsortie;
 CONNECTOR *ptcon;
 {
 SIGNAL  *ptsig;
 char    *ps;

 if (ptcon!=NULL)
    {
    if (ptcon->INS)
       ps = ((INSTANCE *)ptcon->INS->DATA)->INSNAME;
    else ps = "$" ;
    fprintf ( fsortie ,
      "|	|__(INSNAME).CON.NAME____________________: (%s), %s \n",ps, ptcon->NAME );
    fprintf ( fsortie ,
      "|	|__CON.(TYPE,NBPOSS)   : ( %c, %ld ) \n", ptcon->TYPE, ptcon->NBPOSS );
    fprintf ( fsortie ,
      "|	|__CON.(MINPOS,MAXPOS) : ( %ld, %ld ) \n", ptcon->MINPOS, ptcon->MAXPOS );
    if (ptcon->SIG)
       {
       ptsig = (SIGNAL *)ptcon->SIG->DATA;
       fprintf ( fsortie ,
        "|	|__CON.Signal.(INDEX,NAME)  :( %ld, %s) \n",ptsig->INDEX, ptsig->NAME );
       }
    else fprintf ( fsortie ,"|	|__CON.Signal         : (vide)  \n");
    fprintf ( fsortie ,"|	|___________________________________\n");
    }
 else fprintf(fsortie ," pointeur VIDE \n");
 }

/**************************************************************************************
 
/**************************************************************************************
*existsig
* recherche d'un signal dans une liste chaine de signaux; s'il existe retourne
* le signale dans la liste sinon NULL .
**************************************************************************************/

 chain_list  *existsig(ptcsig_list,ptsig)
 chain_list  *ptcsig_list;
 SIGNAL      *ptsig;
 {
 chain_list *ptcsig=NULL;
  
 for (ptcsig=ptcsig_list;ptcsig;ptcsig=ptcsig->NEXT)
     if (ptsig==(SIGNAL *)ptcsig->DATA)
        return(ptcsig);
 return(NULL);
 }


/************************************************************************ 
*		fonction	Warning()				*
************************************************************************/

 void Warning(index,ps1,ps2)
 int  index;
 char *ps1;
 char *ps2;
 {
 fprintf(FOUT,"Warning DPR message( %ld ) : ",index);
 switch (index)
    {
    case 1  : fprintf(FOUT,"Superposition d'instances (selon X ou Y) entre\
                            %s et %s\n",ps1,ps2);break;
    case 10 : fprintf(FOUT," : %s \n",ps1);affcon(FOUT,(CONNECTOR *)ps2);break;
    default : fprintf(FOUT," : %s , %s .\n",ps1,ps2);break;
    }
 }



/************************************************************************ 
*		fonction	Error()				*
************************************************************************/

 void Error(index,ps,ptinfo)
 int  index;
 char *ps;
 char *ptinfo;
 {
 fprintf(FOUT,"Error DPR message(%ld) : ",index);fprintf(FOUT," %s . \n",ps);
 switch (index)
    {
    case 10 :;
    case 11 :;
    case 12 :;
    case 13 :;
    case 14 : affcon(FOUT,(CONNECTOR *)ptinfo);
    default : break; 
    }
 exit(1);
 }

/************************************************************************
**                fonction strnbr()                                    **
************************************************************************/
 long  strnbr( ptstr)
 char *ptstr;
 {
 long nbr =0;

 while ((*ptstr >='0') && (*ptstr <= '9'))
       nbr = nbr * 10 + *ptstr++ -'0';
 return nbr ;
 }

/************************************************************************
**                fonction nbrstr()                                    **
************************************************************************/
 char  *nbrstr( nbr)
 long nbr;
 {
 char *ptstr;
 long i=19;

 ptstr = mbkalloc(20);
 ptstr[19]='\0';
 while (nbr)
       {
       ptstr[--i]=(char)('0' + nbr % 10) ;
       nbr = nbr / 10 ;
       }
 return(&ptstr[i]) ;
 }

/**************************************************************
**  strrch()
**************************************************************/
 long strrch(ptstr,car)
 char *ptstr;
 char car;
 {
 long i;

 for (i=strlen(ptstr);i>0;i--)
     if(ptstr[i]==car) return(i);
 return 0 ;
 }

/******************************************************************************
**         Bibliotheque de fonctions pour la gestion des orientations        **
**         en fonction du champ TRANSF des instances.                        **
**                                                                           **
******************************************************************************/

/******************************************************************************
**     Fonction delta_x :  Calcul de la largeur de l'instance en tenant      **
**                        compte de sa transformation.                       **
******************************************************************************/

 long delta_x(xab1,yab1,xab2,yab2,x,y,TRANSF)
 long xab1,yab1,xab2,yab2,x,y;
 int TRANSF;
 {
 long delta;

 switch (TRANSF)
    {
    case (int) NOSYM : delta = x - xab1 ; break;
    case (int) SYM_X : delta = -x + xab2 ; break ;
    case (int) SYM_Y : delta = x - xab1 ; break;
    case (int) SYMXY : delta = -x + xab2 ; break ;
    case (int) ROT_P : delta = yab2 - y ; break;
    case (int) ROT_M : delta = y - yab1 ; break;
    case (int) SY_RM : delta = yab2 - y ; break;
    case (int) SY_RP : delta = y - yab1 ; break;
    };
 return(delta);
 }


/******************************************************************************
**     Fonction delta_y :  Calcul de la hauteur de l'instance en tenant      **
**                        compte de sa transformation.                       **
******************************************************************************/

 long delta_y(xab1,yab1,xab2,yab2,x,y,TRANSF)
 long xab1,yab1,xab2,yab2,x,y;
 int TRANSF;
 {
 long delta;

 switch (TRANSF)
    {
    case (int) NOSYM : delta = y - yab1 ; break;
    case (int) SYM_X : delta = y - yab1 ; break;
    case (int) SYM_Y : delta = yab2 - y ; break;
    case (int) SYMXY : delta = yab2 - y ; break;
    case (int) ROT_P : delta = x - xab1 ; break;
    case (int) ROT_M : delta = xab2 - x ; break;
    case (int) SY_RM : delta = xab2 - x ; break;
    case (int) SY_RP : delta = x - xab1 ; break;
    };
 return(delta);
 }

/******************************************************************************
**     Fonction orient_r :  Calcul de l'orientation reelle d'une reference   **
**      de type RIGHT en tenant compte de la transformation de l'instance.   **
******************************************************************************/
 char orient_r(TRANSF)
 int TRANSF;
 {
 switch (TRANSF)
    {
    case (int) NOSYM : ;
    case (int) SYM_Y : return (EAST);
    case (int) SYM_X : ;
    case (int) SYMXY : return (WEST);
    case (int) ROT_P : ;
    case (int) SY_RP : return (NORTH);
    case (int) ROT_M : ;
    case (int) SY_RM : return (SOUTH);
    };
 }

/******************************************************************************
**     Fonction orient_l :  Calcul de l'orientation reelle d'une reference   **
**      de type LEFT en tenant compte de la transformation de l'instance.    **
******************************************************************************/
 char orient_l(TRANSF)
 int TRANSF;
 {
 switch (TRANSF)
    {
    case (int) NOSYM : ;
    case (int) SYM_Y : return (WEST);
    case (int) SYM_X : ;
    case (int) SYMXY : return (EAST);
    case (int) ROT_P : ;
    case (int) SY_RP : return (SOUTH);
    case (int) ROT_M : ;
    case (int) SY_RM : return (NORTH);
    };
 }

/******************************************************************************
**  Fonction orient_rl :  Calcul de l'orientation reelle d'une reference     **
**  de type RIGHT/LEFT en tenant compte de la transformation de l'instance   **
******************************************************************************/
 char orient_rl(TRANSF)
 int TRANSF;
 {
 switch (TRANSF)
    {
    case (int) NOSYM : ;
    case (int) SYM_Y : ; 
    case (int) SYM_X : ;
    case (int) SYMXY : return ('H');
    case (int) ROT_P : ;
    case (int) SY_RP : ;
    case (int) ROT_M : ;
    case (int) SY_RM : return ('V');
    };
 }

/***************************************************************************
**  Fonction orient :  Calcul de l'orientation reelle d'une reference     **
**   de type quelconque parmis NORTH/SOUTH/EAST/WEST en tenant compte     **
**   de la transformation de l'instance.                                  **
***************************************************************************/
 char Orient(ORIENT,TRANSF)
 char ORIENT;
 char TRANSF;
 {
 if (ORIENT == NORTH)
    switch (TRANSF)
       {
       case (int) NOSYM : return (NORTH);
       case (int) SYM_X : return (NORTH); 
       case (int) SYM_Y : return (SOUTH);
       case (int) SYMXY : return (SOUTH);
       case (int) ROT_P : return (WEST);
       case (int) SY_RP : return (EAST);
       case (int) ROT_M : return (EAST);
       case (int) SY_RM : return (WEST);
       };

 if (ORIENT == SOUTH)
    switch (TRANSF)
       {
       case (int) NOSYM : return (SOUTH);
       case (int) SYM_X : return (SOUTH);
       case (int) SYM_Y : return (NORTH);
       case (int) SYMXY : return (NORTH);
       case (int) ROT_P : return (EAST);
       case (int) SY_RP : return (WEST);
       case (int) ROT_M : return (WEST);
       case (int) SY_RM : return (EAST);
       };

 if (ORIENT == EAST)
    switch (TRANSF)
       {
       case (int) NOSYM : return (EAST);
       case (int) SYM_X : return (WEST);
       case (int) SYM_Y : return (EAST);
       case (int) SYMXY : return (WEST);
       case (int) ROT_P : return (NORTH);
       case (int) SY_RP : return (NORTH);
       case (int) ROT_M : return (SOUTH);
       case (int) SY_RM : return (SOUTH);
       };

 if (ORIENT == WEST)
    switch(TRANSF)
       {
       case (int) NOSYM : return (WEST);
       case (int) SYM_X : return (EAST); 
       case (int) SYM_Y : return (WEST);
       case (int) SYMXY : return (EAST);
       case (int) ROT_P : return (SOUTH);
       case (int) SY_RP : return (SOUTH);
       case (int) ROT_M : return (NORTH);
       case (int) SY_RM : return (NORTH);
       };

 Error(20,"Orientation non standard.","");
 }

/******************************************************************************
**     Fonction deltab_y :  Calcul de la hauteur de l'instance en tenant     **
**                        compte de sa transformation.                       **
******************************************************************************/
 long deltab_y(xab1,yab1,xab2,yab2,TRANSF)
 long xab1,yab1,xab2,yab2;
 int TRANSF;
 {
 long delta;

 switch (TRANSF)
    {
    case (int) NOSYM : ;
    case (int) SYM_X : ;
    case (int) SYM_Y : ;
    case (int) SYMXY : delta = yab2 - yab1 ; break;
    case (int) ROT_P : ;
    case (int) ROT_M : ;
    case (int) SY_RM : ;
    case (int) SY_RP : delta = xab2 - xab1 ; break;
    };
 return(delta);
 }

/******************************************************************************
**     Fonction deltab_x :  Calcul de la largeur de l'instance en tenant     **
**                        compte de sa transformation.                       **
******************************************************************************/
 long deltab_x(xab1,yab1,xab2,yab2,TRANSF)
 long xab1,yab1,xab2,yab2;
 int TRANSF;
 {
 long delta;

 switch (TRANSF)
    {
    case (int) NOSYM : ;
    case (int) SYM_X : ;
    case (int) SYM_Y : ;
    case (int) SYMXY : delta = xab2 - xab1 ; break;
    case (int) ROT_P : ;
    case (int) ROT_M : ;
    case (int) SY_RM : ;
    case (int) SY_RP : delta = yab2 - yab1 ; break;
    };
 return(delta);
 }

/*********************************************************************
**        fonction addconchannel() : ajout un connecteur-signal     **
**    dans la structure Connecteur du Routeur canal...              **
*********************************************************************/
 ConnectorList *addconchannel(ptconsig_CH,indexsig,ycon)
 ConnectorList *ptconsig_CH ;
 long           indexsig;
 long           ycon;

 {
 ConnectorList *ptnewcon;

 ptnewcon = (ConnectorList *)mbkalloc(sizeof(ConnectorList));
 ptnewcon->NextCon = ptconsig_CH ;
 ptnewcon->ConName = indexsig ;
 ptnewcon->Mark = ycon ;

 return ptnewcon ;
 }

/*********************************************************************
** fonction insertcon_inchan() : ajout un connecteur-signal selon   **
** son orientation dans la liste correspondante.                    **
*********************************************************************/
 ConnectorList *insertcon_inchan(ptchannel,orient,index,y)
 CHANNEL *ptchannel;
 char     orient;
 long     index;
 long     y;
 {
 
 ConnectorList *ptcon_ch=NULL;
 ConnectorList *ptcon_save=NULL;

 switch(orient)
    {
    case NORTH : ptcon_ch = ptchannel->NORTHCON;break;
    case SOUTH : ptcon_ch = ptchannel->SOUTHCON;break;
    case WEST  : ptcon_ch = ptchannel->EASTCON ;break;
    case EAST  : ptcon_ch = ptchannel->WESTCON ;break;
    }
 for (ptcon_save=NULL;ptcon_ch;ptcon_ch=ptcon_ch->NextCon)
     if (ptcon_ch->Mark > y)
        break;
     else
        ptcon_save = ptcon_ch;
 
 if (ptcon_save)
    {
    if ((orient==WEST)||(orient==EAST))
       {
       if (ptcon_save->Mark!=y)
          {
          ptcon_save->NextCon = addconchannel(ptcon_save->NextCon,index,y);
          return ptcon_save->NextCon;
          }
       else
          if (ptcon_save->ConName!=index)
             {
             printf("BUG: Different signals on the same Y in channel!!\n");
             exit(10);
             }
          else
             return NULL;
       }
    else
       {
       ptcon_save->NextCon = addconchannel(ptcon_save->NextCon,index,y);
       return ptcon_save->NextCon;
       }
    }
 else
    switch(orient)
      {
      case NORTH : ptchannel->NORTHCON = addconchannel(ptchannel->NORTHCON,index,y);
                   return ptchannel->NORTHCON;
      case SOUTH : ptchannel->SOUTHCON = addconchannel(ptchannel->SOUTHCON,index,y);
                   return ptchannel->SOUTHCON;
      case WEST  : ptchannel->EASTCON = addconchannel(ptchannel->EASTCON,index,y);
                   return ptchannel->EASTCON;
      case EAST  : ptchannel->WESTCON = addconchannel(ptchannel->WESTCON,index,y);
                   return ptchannel->WESTCON;
      }
 }

/********************************************************************
**        fonction addnwell()                                      **
**     rajoute un nwell a une liste pointe par pthead              **
********************************************************************/
 chain_list *addnwell(pthead,x,y,width,ptccell,ptccol)
 chain_list *pthead;
 long        x,y;
 long        width;
 chain_list *ptccell;
 chain_list *ptccol;

 {
 NWELLREF *ptnwell=NULL;

 ptnwell        = (NWELLREF *)mbkalloc(sizeof(NWELLREF));
 ptnwell->X     = x;
 ptnwell->Y     = y;
 ptnwell->WIDTH = width;
 ptnwell->INS   = ptccell;
 ptnwell->COL   = ptccol;
 ptnwell->USER  = NULL;

 return(addchain(pthead,(void *)ptnwell));

 }

/********************************************************************
**        fonction addpos()                                        **
**     rajoute une possibilite a un connecteur                     **
********************************************************************/
 chain_list *addpos(pthead,x,y,layer,orient,type,track,width,ptcon)
 chain_list *pthead;
 long        x,y;
 char        layer;
 char        orient;
 char        type;
 long        track;
 long        width;
 CONNECTOR  *ptcon;

 {
 POSSIBILITY *ptpos=NULL;

 ptpos = (POSSIBILITY *)mbkalloc(sizeof(POSSIBILITY));
 ptpos->X = x;
 ptpos->Y = y;
 ptpos->LAYER = layer;
 ptpos->ACCES = orient;
 ptpos->TYPE  = type;
 ptpos->TRACK = track;
 ptpos->WIDTH = width;
 ptpos->CON   = ptcon;
 ptpos->USER  = NULL;

 return(addchain(pthead,(void *)ptpos));

 }

/*********************************************************************************
*     addtrack                                                                   *
* insertion d'une piste dans la liste des pistes en tete de la structure.        *
*********************************************************************************/
 TRACK  *addtrack(pthead,y)
 TRACK  *pthead;
 long    y;

 {
 TRACK  *pttrack=NULL;
  
 pttrack = (TRACK *)mbkalloc(sizeof(TRACK));
 pttrack->NEXT = pthead ;
 pttrack->Y = y;
 
 return pttrack ;
 }

