/********************************************************************
*                                                                   *
* 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: save_R.c                                         *
*       version : 3.0                                                            *
*       date    : 25/04/92                                                       *
*********************************************************************************/

#include "dpr_R.h"
#include "util_R.h"

/********************************************************************************
* recuperer le nom d'un signal a partir de son index                            *
********************************************************************************/
 char *index2name(ptcsig,index)
 chain_list *ptcsig;
 long        index;
 
 {
 chain_list *ptcsig1=NULL;
 SIGNAL     *ptsig1=NULL;

 for (ptcsig1=ptcsig;ptcsig1;ptcsig1=ptcsig1->NEXT)
     {
     ptsig1 = (SIGNAL *)ptcsig1->DATA;
     if (ptsig1->INDEX==index)
        return ptsig1->NAME;
     }
 printf("BUG: Signal index without any corresponding signal name!!\n");
 exit(25);
 }

/*******************************************************************************
* convertion reelle -> symbolique(en x)                                        *
*******************************************************************************/
/* long track_num(track,ptlist_num_track)
 long track;
 NUMTRACK *ptlist_num_track;
 
 {
 NUMTRACK *pt;

 for (pt=ptlist_num_track;pt;pt=pt->NEXT)
     if (pt->TRACK==track)
        return pt->NUM;
 printf("ERROR: bizz, pas de correspondance reel-symbolique\n");
 exit(6);
 }*/

/*******************************************************************************
* convertion symbolique -> reelle(en y)                                        *
*******************************************************************************/
 long num_track_y(num,ptlist_num_track,ptcol)
 long      num;
 NUMTRACK *ptlist_num_track;
 COLUMN   *ptcol;
 
 {
 NUMTRACK *pt;

 if (num==0)
    return (ptcol->Y);
 if (num==ptcol->S_HEIGHT+1)
    return (ptcol->Y + ptcol->HEIGHT);
 for (pt=ptlist_num_track;pt;pt=pt->NEXT)
     if (pt->NUM==num)
        return pt->TRACK;
 printf("BUG: bizz, pas de correspondance symbolique-reel\n");
 exit(26);
 }

/*****************************************
* convertion symbolique -> reelle(en x)  *
*****************************************/
 long num_track_x(num,ptcol)
 long    num;
 COLUMN *ptcol;
 
 {
 long x;

 if (num==0)
    return (0);
 if (num==ptcol->S_WIDTH+1)
    return (ptcol->WIDTH);
 x = (((num-1)*CANAL_INTER_TRACK)+CANAL_BORDER_LEFT)*SCALE_X;
 return x;
 }

/**************************************************************
* testrappel_inbloc()                                         *
* cherche si dans la figure il y a un bloc qui contient       *
* un rappel d'alim interne ayant le nom alimname              *
* retourne 1 si oui, sinon 0.                                 *
**************************************************************/
 int         testrappel_inbloc(alimname,ptfig)
 char       *alimname;
 FIGURE     *ptfig;
 
 {
 chain_list  *ptccol;
 chain_list  *ptcins;
 chain_list  *ptccon;
 COLUMN      *ptcol;
 INSTANCE    *ptins;
 CONNECTOR   *ptcon;

 for (ptccol=ptfig->COL;ptccol;ptccol=ptccol->NEXT)
     {
     ptcol = (COLUMN *)ptccol->DATA;
     for (ptcins=ptcol->INS;ptcins;ptcins=ptcins->NEXT)
         {
         ptins = (INSTANCE *)ptcins->DATA;
         for (ptccon=ptins->RAPPELS;ptccon;ptccon=ptccon->NEXT)
             {
             ptcon = (CONNECTOR *)ptccon->DATA;
             if (!strncmp(ptcon->NAME,alimname,3))
                return(1);
             }
         }
     }
 return(0);
 }

/************************************************
* save_chcol                                    *
*  sauvegarde d'un canal de routage             *
************************************************/
 phfig_list  *save_chcol(ptcol,ptlist_num,ptfig_dpr)
 COLUMN      *ptcol;
 NUMTRACK    *ptlist_num;
 FIGURE      *ptfig_dpr;

 {
 phfig_list	*ptfig = NULL;
 chain_list     *ptclin=NULL;
 SegmentList	*ptseg_hor_ch=NULL;
 SegmentList	*ptseg_ver_ch=NULL;
 ViasList	*ptvia_ch=NULL;
 ConnectorList  *ptcon_ch=NULL;
 CHANNEL        *ptchannel=NULL;
 GABARIT        *ptgab=NULL;
 char		*NodeName=NULL;
 long            x1=0,y1=0,x2=0,y2=0;
 long           *ptSymb_Heigth=NULL;
 long            x=0,y=0;
 long            width=0;
 int             indexalim=0;
 int             rappel_vss=0;
 int             rappel_vdd=0;
 char           *vssname=NULL;
 char           *vddname=NULL;
 chain_list     *ptcalim=NULL;
 CONNECTOR      *ptalim=NULL;
 chain_list     *ptccon;
 CONNECTOR      *ptcon;
 SIGNAL         *ptsig;

 ptfig = addphfig(ptcol->NAME);
 ptfig->XAB1 = ptcol->X;
 ptfig->YAB1 = ptcol->Y;
 ptfig->XAB2 = ptcol->X + ptcol->WIDTH;
 ptfig->YAB2 = ptcol->Y + ptcol->HEIGHT;

 /* DEBUG_CHANNEL */
 /*printf("Affichage cannal\n");
 for (ptseg_ver_ch=(SegmentList *)ptcol->SEG->DATA;ptseg_ver_ch;
                    ptseg_ver_ch=ptseg_ver_ch->NextSeg)
     printf("segment vertical: x1=%ld,y1=%ld,x2=%ld,y2=%ld\n",
             ptseg_ver_ch->X1Seg,
             ptseg_ver_ch->Y1Seg,
             ptseg_ver_ch->X2Seg,
             ptseg_ver_ch->Y2Seg);
 for (ptseg_hor_ch=(SegmentList *)ptcol->SEG->NEXT->DATA;ptseg_hor_ch;
      ptseg_hor_ch=ptseg_hor_ch->NextSeg)
     printf("segment horizontal: x1=%ld,y1=%ld,x2=%ld,y2=%ld\n",
             ptseg_hor_ch->X1Seg,
             ptseg_hor_ch->Y1Seg,
             ptseg_hor_ch->X2Seg,
             ptseg_hor_ch->Y2Seg);
 for (ptvia_ch=(ViasList *)ptcol->VIA->DATA;ptvia_ch;ptvia_ch=ptvia_ch->NextVia)
     printf("via: x=%ld,y=%ld\n",ptvia_ch->XVia,ptvia_ch->YVia);*/
 /* Fin de DEBUG_CHANNEL */

 ptchannel = (CHANNEL *)ptcol->DF_CON->DATA;
 
 /* boucle de sauvegarde des connecteurs WEST */
 x = ptcol->X;
 for (ptcon_ch=ptchannel->WESTCON;ptcon_ch;ptcon_ch=ptcon_ch->NextCon)
     {
     NodeName = index2name(ptfig_dpr->SIG,ptcon_ch->ConName);
     y = ptcon_ch->Mark;
     (void)addphcon(ptfig,(char)WEST,NodeName,x,y,ALU2,WTRAN*SCALE_X);
     }
     
 /* boucle de sauvegarde des connecteurs EAST */
 x = ptcol->X + ptcol->WIDTH;
 for (ptcon_ch=ptchannel->EASTCON;ptcon_ch;ptcon_ch=ptcon_ch->NextCon)
     {
     NodeName = index2name(ptfig_dpr->SIG,ptcon_ch->ConName);
     y = ptcon_ch->Mark;
     (void)addphcon(ptfig,(char)EAST,NodeName,x,y,ALU2,WTRAN*SCALE_X);
     }

 /* boucle de sauvegarde des connecteurs SOUTH */
 for (ptcon_ch=ptchannel->SOUTHCON;ptcon_ch;ptcon_ch=ptcon_ch->NextCon)
     {
     x = num_track_x(ptcon_ch->Mark,ptcol) + ptcol->X;
     y = ptcol->Y;
     /* chercher le nom du connecteur externe correspondant */
     for (ptccon=ptfig_dpr->CON;ptccon;ptccon=ptccon->NEXT)
         {
         ptcon = (CONNECTOR *)ptccon->DATA;
         ptsig = (SIGNAL *)ptcon->SIG->DATA;
         if (ptsig->INDEX==ptcon_ch->ConName)
            break;
         }
     if (ptccon)
        (void)addphcon(ptfig,(char)SOUTH,
                       ptcon->NAME,
                       x,y,ALU1,WLAYER1*SCALE_X);
     else
        printf("BIZ: Connecteur externe mal traite!!\n");
     }
 
 /* boucle de sauvegarde des connecteurs NORTH */
 for (ptcon_ch=ptchannel->NORTHCON;ptcon_ch;ptcon_ch=ptcon_ch->NextCon)
     {    
     x = num_track_x(ptcon_ch->Mark,ptcol) + ptcol->X;
     y = ptcol->Y + ptcol->HEIGHT;
     /* chercher le nom du connecteur externe correspondant */
     for (ptccon=ptfig_dpr->CON;ptccon;ptccon=ptccon->NEXT)
         {
         ptcon = (CONNECTOR *)ptccon->DATA;
         ptsig = (SIGNAL *)ptcon->SIG->DATA;
         if (ptsig->INDEX==ptcon_ch->ConName)
            break;
         }
     if (ptccon)
        (void)addphcon(ptfig,(char)NORTH,
                       ptcon->NAME,
                       x,y,ALU1,WLAYER1*SCALE_X);
     else
        printf("BIZ: Connecteur externe mal traite!!\n");
     }

 if (ptcol->WIDTH!=0)
    {
    /* Sauvegarde des Segments Verticaux du cannal */
    NodeName = namealloc("");
    for (ptseg_ver_ch=(SegmentList *)ptcol->SEG->DATA;ptseg_ver_ch;
         ptseg_ver_ch=ptseg_ver_ch->NextSeg)
        {
        x1 = num_track_x(ptseg_ver_ch->X1Seg,ptcol) + ptcol->X;
        y1 = num_track_y(ptseg_ver_ch->Y1Seg,ptlist_num,ptcol);
        x2 = num_track_x(ptseg_ver_ch->X2Seg,ptcol) + ptcol->X;
        y2 = num_track_y(ptseg_ver_ch->Y2Seg,ptlist_num,ptcol);
        addphseg(ptfig,ALU1,WLAYER1*SCALE_X,
                 x1,y1,x2,y2,NodeName);
        }

    /* Sauvegarde des Segments Horisentaux du cannal */
    for (ptseg_hor_ch=(SegmentList *)ptcol->SEG->NEXT->DATA;ptseg_hor_ch;
         ptseg_hor_ch=ptseg_hor_ch->NextSeg)
        {
        x1 = num_track_x(ptseg_hor_ch->X1Seg,ptcol) + ptcol->X;
        y1 = num_track_y(ptseg_hor_ch->Y1Seg,ptlist_num,ptcol);
        x2 = num_track_x(ptseg_hor_ch->X2Seg,ptcol) + ptcol->X;
        y2 = num_track_y(ptseg_hor_ch->Y2Seg,ptlist_num,ptcol);
        addphseg(ptfig,ALU2,WLAYER2*SCALE_X,
                 x1,y1,x2,y2,NodeName);
        }
 
    /* Sauvegarde des Vias du cannal */
    for (ptvia_ch=(ViasList *)ptcol->VIA->DATA;ptvia_ch;ptvia_ch=ptvia_ch->NextVia)
        {
        x = num_track_x(ptvia_ch->XVia,ptcol)+ ptcol->X;
        y = num_track_y(ptvia_ch->YVia,ptlist_num,ptcol);
        addphvia(ptfig,(char)CONT_VIA,x,y);
        }
    }

 /* ajout des connecteurs et segments d'alimentation en fonction des gabarits */
 /* boucle sur les lignes */
 x1 = ptcol->X;
 x2 = x1 + ptcol->WIDTH;
 ptclin = ptfig_dpr->LIN;
 ptgab = ((LINE *)ptclin->DATA)->GAB;
 width = ptgab->WALIM1;
 y1 = ((LINE *)ptclin->DATA)->Y;
 y2 = y1;
 indexalim = 0;
 vssname = namealloc("vss");
 vddname = namealloc("vdd");
 /* chercher s'il y a un bloc avec un rappel vssname dans le circuit */
 rappel_vss = testrappel_inbloc(vssname,ptfig_dpr);
 /* chercher s'il y a un bloc avec un rappel vddname dans le circuit */
 rappel_vdd = testrappel_inbloc(vddname,ptfig_dpr);
 /* traitement de la premiere alimentation */
 if (!strncmp(ptgab->ALIM1,vssname,3))
    {
    for (ptcalim=ptfig_dpr->ALIM;ptcalim;ptcalim=ptcalim->NEXT)
        {
        ptalim = (CONNECTOR *)ptcalim->DATA;
        if (!strncmp(ptalim->NAME,vssname,3))
           break;
        }
    if ((ptcalim)||(rappel_vss==1))
       /*c.a.d rappel d'alim existe dans canal ou dans bloc*/
       NodeName = vssname;
    else /* c.a.d pas de rappel d'alim */
       NodeName = nameindex(vssname,indexalim);
    }
 else
    {
    for (ptcalim=ptfig_dpr->ALIM;ptcalim;ptcalim=ptcalim->NEXT)
        {
        ptalim = (CONNECTOR *)ptcalim->DATA;
        if (!strncmp(ptalim->NAME,vddname,3))
           break;
        }
    if ((ptcalim)||(rappel_vdd==1))
       /*c.a.d rappel d'alim existe dans canal ou dans bloc*/
       NodeName = vddname;
    else /* c.a.d pas de rappel d'alim */
       NodeName = nameindex(vddname,indexalim);
    }
 (void)addphcon(ptfig,WEST,NodeName,x1,y1,ALU2,width);
 (void)addphcon(ptfig,EAST,NodeName,x2,y2,ALU2,width);
 if (ptcol->WIDTH!=0)
    (void)addphseg(ptfig,(char)ALU2,width,x1,y1,x2,y2,NodeName);

 /* boucle de traitement des alimentations suivantes */
 for (ptclin=ptfig_dpr->LIN;ptclin;ptclin=ptclin->NEXT)
     {
     ptgab = ((LINE *)ptclin->DATA)->GAB;
     width = ptgab->WALIM2;
     y1 = ((LINE *)ptclin->DATA)->Y + ptgab->HEIGHT;
     y2 = y1; 
     indexalim = indexalim + 1;
     if (!strncmp(ptgab->ALIM1,vssname,3))
        {
        for (ptcalim=ptfig_dpr->ALIM;ptcalim;ptcalim=ptcalim->NEXT)
            {
            ptalim = (CONNECTOR *)ptcalim->DATA;
            if (!strncmp(ptalim->NAME,vddname,3))
               break;
            }
        if ((ptcalim)||(rappel_vdd==1))
           /*c.a.d rappel d'alim existe dans canal ou dans bloc*/
           NodeName = vddname;
        else /* c.a.d pas de rappel d'alim */
           NodeName = nameindex(vddname,indexalim);
        }
     else
        {
        for (ptcalim=ptfig_dpr->ALIM;ptcalim;ptcalim=ptcalim->NEXT)
            {
            ptalim = (CONNECTOR *)ptcalim->DATA;
            if (!strncmp(ptalim->NAME,vssname,3))
               break;
            }
        if ((ptcalim)||(rappel_vss==1))
           /*c.a.d rappel d'alim existe dans canal ou dans bloc*/
           NodeName = vssname;
        else /* c.a.d pas de rappel d'alim */
           NodeName = nameindex(vssname,indexalim);
        }
     (void)addphcon(ptfig,WEST,NodeName,x1,y1,ALU2,width);
     (void)addphcon(ptfig,EAST,NodeName,x2,y2,ALU2,width);
     if (ptcol->WIDTH!=0)
        (void)addphseg(ptfig,(char)ALU2,width,x1,y1,x2,y2,NodeName);
     }

 return ptfig;
 }

/****************************************************
* save_opcol                                        *
*  sauvegarde d'une colonne de type Operator        *
****************************************************/
 phfig_list *save_opcol(ptcol,ptcon_west,ptcon_east,ptlist_num,ptfig_dpr)
 COLUMN          *ptcol;
 ConnectorList *ptcon_west;
 ConnectorList *ptcon_east;
 NUMTRACK      *ptlist_num;
 FIGURE        *ptfig_dpr;
 
 {
 phfig_list   *ptfig=NULL;
 chain_list   *ptcvia=NULL;
 chain_list   *ptclin=NULL;
 chain_list   *ptcseg=NULL;
 chain_list   *ptcsig=NULL;
 chain_list   *ptcsig2=NULL;
 chain_list   *ptcins=NULL;
 chain_list   *ptcinsnex=NULL;
 chain_list   *ptccon=NULL;
 chain_list   *ptcconex=NULL;
 chain_list   *ptcpos=NULL;
 chain_list   *ptcpos2=NULL;
 chain_list   *ptccour=NULL;
 CONNECTOR    *ptconctrl=NULL;
 CONNECTOR    *ptconctrlnex=NULL;
 CONNECTOR    *ptcour=NULL;
 CONNECTOR    *ptconmin=NULL;
 CONNECTOR    *ptconmax=NULL;
 POSSIBILITY  *ptpos=NULL;
 POSSIBILITY  *ptpos2=NULL;
 ConnectorList *ptcon;
 INSTANCE     *ptins=NULL;
 INSTANCE     *ptinsnex=NULL;
 SIGNAL       *ptsig=NULL;
 SIGNAL       *ptsig2=NULL;
 SEGMENT      *ptseg=NULL;
 GABARIT      *ptgab=NULL;
 VIA          *ptvia;
 long          x=0,y=0,y1=0,y2=0,width=0;
 long          x1=0,x2=0;
 long          xminpos=MAXINT,xmaxpos=MININT;
 char         *conname;
 char         *NodeName=NULL;
 int           indexalim=0;
 int           rappel_vss=0;
 int           rappel_vdd=0;
 char         *vssname=NULL;
 char         *vddname=NULL;
 chain_list   *ptcalim=NULL;
 CONNECTOR    *ptalim=NULL;
 chain_list   *ptccontmp;
 CONNECTOR    *ptcontmp;
 SIGNAL       *ptsigtmp;

 ptfig = addphfig(ptcol->NAME);
 ptfig->XAB1 = ptcol->X;
 ptfig->YAB1 = ptcol->Y;
 ptfig->XAB2 = ptcol->X + ptcol->WIDTH;
 ptfig->YAB2 = ptcol->Y + ptcol->HEIGHT;
 
 /* boucle de sauvegarde des connecteurs WEST */
 x = ptcol->X;
 for (ptcon=ptcon_west;ptcon;ptcon=ptcon->NextCon)
     {
     conname = index2name(ptfig_dpr->SIG,ptcon->ConName);
     y = ptcon->Mark;
     if (ptcol->TYPE=='O') /* Operateur */
        (void)addphcon(ptfig,(char)WEST,conname,x,y,ALU2,WTRAN*SCALE_X);
     else /* Left */
        {
        /* chercher le nom du connecteur externe correspondant */
        for (ptccontmp=ptfig_dpr->CON;ptccontmp;ptccontmp=ptccontmp->NEXT)
            {
            ptcontmp = (CONNECTOR *)ptccontmp->DATA;
            ptsigtmp = (SIGNAL *)ptcontmp->SIG->DATA;
            if (ptsigtmp->INDEX==ptcon->ConName)
               break;
            }
        if (ptccontmp)
           (void)addphcon(ptfig,(char)WEST,
                          ptcontmp->NAME,
                          x,y,ALU2,WTRAN*SCALE_X);
        else
           printf("BIZ: Connecteur externe mal traite!!\n");
        }
     }
     
 /* boucle de sauvegarde des connecteurs EAST */
 x = ptcol->X + ptcol->WIDTH;
 for (ptcon=ptcon_east;ptcon;ptcon=ptcon->NextCon)
     {
     conname = index2name(ptfig_dpr->SIG,ptcon->ConName);
     y = ptcon->Mark;
     if (ptcol->TYPE=='O') /* Operateur */
        (void)addphcon(ptfig,(char)EAST,conname,x,y,ALU2,WTRAN*SCALE_X);
     else /* Right */
        {
        /* chercher le nom du connecteur externe correspondant */
        for (ptccontmp=ptfig_dpr->CON;ptccontmp;ptccontmp=ptccontmp->NEXT)
            {
            ptcontmp = (CONNECTOR *)ptccontmp->DATA;
            ptsigtmp = (SIGNAL *)ptcontmp->SIG->DATA;
            if (ptsigtmp->INDEX==ptcon->ConName)
               break;
            }
        if (ptccontmp)
           (void)addphcon(ptfig,(char)EAST,
                          ptcontmp->NAME,
                          x,y,ALU2,WTRAN*SCALE_X);
        else
           printf("BIZ: Connecteur externe mal traite!!\n");
        }
     }

 /* boucle de sauvegarde des connecteurs N/S avec verification de la continuite*/
 /* des segments verticaux pour les lignes de type Operator */
 if (ptcol->TYPE=='O')
    {
    /* prolonger d'eventuels signaux externes SOUTH avec leurs connecteurs */
    ptcins = ptcol->INS;
    ptins = (INSTANCE *)ptcins->DATA;
    /* traitement des rappels d'alim SOUTH des blocs generes */
    for (ptccon=ptins->RAPPELS;ptccon;ptccon=ptccon->NEXT)
        {
        ptconctrl = (CONNECTOR *)ptccon->DATA;
        for (ptcpos=ptconctrl->POS;ptcpos;ptcpos=ptcpos->NEXT)
            {
            ptpos = (POSSIBILITY *)ptcpos->DATA;
            if (ptpos->ACCES==SOUTH)
               {
               x1 = ptpos->X + ptcol->X;
               y1 = ptcol->Y;
               x2 = x1;
               y2 = ptpos->Y;
               /* ajouter connecteur SOUTH */
               (void)addphcon(ptfig,SOUTH,ptconctrl->NAME,x1,y1,
                              ptpos->LAYER,ptpos->WIDTH);
               /* ajouter segment vertical avec le bon nom si necessaire */
               if (y2>y1)
                  {
                  (void)addphseg(ptfig,ptpos->LAYER,ptpos->WIDTH,
                                 x1,y1,x2,y2,ptconctrl->NAME);
                  /* Il faut rajouter les vias correspondants */
                  for (ptclin=ptfig_dpr->LIN;ptclin;ptclin=ptclin->NEXT)
                      {
                      y = ((LINE *)ptclin->DATA)->Y;
                      if (y>=y2)
                         break;
                      ptgab = ((LINE *)ptclin->DATA)->GAB;
                      if (!strncmp(ptgab->ALIM1,ptconctrl->NAME,3))
                         addphvia(ptfig,CONT_VIA,x1,y);
                      }
                  }
               }
            }
        }
    /* traitement des signaux de controle externe SOUTH */
    for (ptccon=ptins->CT_CON;ptccon;ptccon=ptccon->NEXT)
        {
        if (!ptccon->DATA)
           break;
        ptconctrl = (CONNECTOR *)ptccon->DATA;
        ptcsig = ptconctrl->SIG;
        ptsig = (SIGNAL *)ptcsig->DATA;
        if (ptsig->TYPE=='E')
           {
           for (ptcpos=ptconctrl->POS;ptcpos;ptcpos=ptcpos->NEXT)
               {
               ptpos = (POSSIBILITY *)ptcpos->DATA;
               if (ptpos->ACCES==SOUTH)
                  {
                  x1 = ptpos->X + ptcol->X;
                  y1 = ptcol->Y;
                  x2 = x1;
                  y2 = ptpos->Y;
                  /* chercher s'il lui correspond un con place par le concepteur */
                  for (ptccour=ptcol->CT_CON;ptccour;ptccour=ptccour->NEXT)
                      {
                      if (!ptccour->DATA)
                         continue;
                      ptcour = (CONNECTOR *)ptccour->DATA;
                      if ((ptcour->TYPE=='E')&&(ptcsig==ptcour->SIG))
                         {
                         /* marquer le connecteur externe */
                         ptcour->USER = NULL;
                         ptcour->USER = addchain(NULL,(void *)NULL);
                         break;
                         }
                      }
                  /* ajouter segment vertical avec le bon nom si necessaire */
                  if (y2>y1)
                     (void)addphseg(ptfig,ALU1,WLAYER1*SCALE_X,
                                    x1,y1,x2,y2,ptsig->NAME);
                  /* ajouter connecteur SOUTH avec le bon nom */
                  if (ptccour) /* c.a.d con correspondant trouve place */
                     (void)addphcon(ptfig,SOUTH,ptcour->NAME,x1,y1,
                                    ALU1,WLAYER1*SCALE_X);
                  else /* c.a.d pas con correspondant place */
                     {
                     /* chercher le nom du connecteur externe correspondant */
                     for (ptccour=ptfig_dpr->CON;ptccour;ptccour=ptccour->NEXT)
                         {
                         ptcour = (CONNECTOR *)ptccour->DATA;
                         if (ptcour->SIG==ptcsig)
                            break;
                         }
                     if (ptccour)
                        (void)addphcon(ptfig,SOUTH,ptcour->NAME,x1,y1,
                                       ALU1,WLAYER1*SCALE_X);
                     else
                        printf("BIZ: Connecteur externe mal traite!!\n");
                     }
                  }
               }
           }
        }
      
    /* prolonger d'eventuels signaux externes NORTH avec leurs connecteurs */
    for (ptcins=ptcol->INS;ptcins->NEXT;ptcins=ptcins->NEXT);
    ptins = (INSTANCE *)ptcins->DATA;
    /* traitement des rappels d'alim NORTH des blocs generes */
    for (ptccon=ptins->RAPPELS;ptccon;ptccon=ptccon->NEXT)
        {
        ptconctrl = (CONNECTOR *)ptccon->DATA;
        for (ptcpos=ptconctrl->POS;ptcpos;ptcpos=ptcpos->NEXT)
            {
            ptpos = (POSSIBILITY *)ptcpos->DATA;
            if (ptpos->ACCES==NORTH)
               {
               x1 = ptpos->X + ptcol->X;
               y1 = ptpos->Y;
               x2 = x1;
               y2 = ptcol->Y + ptcol->HEIGHT;
               /* ajouter connecteur NORTH */
               (void)addphcon(ptfig,NORTH,ptconctrl->NAME,x2,y2,
                              ptpos->LAYER,ptpos->WIDTH);
               /* ajouter segment vertical avec le bon nom si necessaire */
               if (y2>y1)
                  {
                  (void)addphseg(ptfig,ptpos->LAYER,ptpos->WIDTH,
                                 x1,y1,x2,y2,ptconctrl->NAME);
                  /* Il faut rajouter les vias correspondants */
                  for (ptclin=ptfig_dpr->LIN;ptclin;ptclin=ptclin->NEXT)
                      {
                      ptgab = ((LINE *)ptclin->DATA)->GAB;
                      y = ((LINE *)ptclin->DATA)->Y + ptgab->HEIGHT;
                      if (y>y1)
                         {
                         if (strncmp(ptgab->ALIM1,ptconctrl->NAME,3))
                            addphvia(ptfig,CONT_VIA,x1,y);
                         }
                      }
                  }
               }
            }
        }
    /* traitement des signaux de controle externe NORTH */
    for (ptccon=ptins->CT_CON;ptccon;ptccon=ptccon->NEXT)
        {
        if (!ptccon->DATA)
           break;
        ptconctrl = (CONNECTOR *)ptccon->DATA;
        ptcsig = ptconctrl->SIG;
        ptsig = (SIGNAL *)ptcsig->DATA;
        if (ptsig->TYPE=='E')
           {
           for (ptcpos=ptconctrl->POS;ptcpos;ptcpos=ptcpos->NEXT)
               {
               ptpos = (POSSIBILITY *)ptcpos->DATA;
               if (ptpos->ACCES==NORTH)
                  {
                  x1 = ptpos->X + ptcol->X;
                  y1 = ptpos->Y;
                  x2 = x1;
                  y2 = ptcol->Y + ptcol->HEIGHT;
                  /* chercher s'il lui correspond un con place par le concepteur */
                  for (ptccour=ptcol->CT_CON;ptccour;ptccour=ptccour->NEXT)
                      {
                      if (!ptccour->DATA)
                         continue;
                      ptcour = (CONNECTOR *)ptccour->DATA;
                      if ((ptcour->TYPE=='E')&&(ptcsig==ptcour->SIG))
                         {
                         /* marquer le connecteur externe */
                         ptcour->USER = NULL;
                         ptcour->USER = addchain(NULL,(void *)NULL);
                         break;
                         }
                      }
                  /* ajouter segment vertical avec le bon nom si necessaire */
                  if (y2>y1)
                     (void)addphseg(ptfig,ALU1,WLAYER1*SCALE_X,
                                    x1,y1,x2,y2,ptsig->NAME);
                  /* ajouter connecteur NORTH avec le bon nom */
                  if (ptccour) /* c.a.d con correspondant trouve place */
                     (void)addphcon(ptfig,NORTH,ptcour->NAME,x2,y2,
                                    ALU1,WLAYER1*SCALE_X);
                  else /* c.a.d pas con correspondant place */
                     {
                     /* chercher le nom du connecteur externe correspondant */
                     for (ptccour=ptfig_dpr->CON;ptccour;ptccour=ptccour->NEXT)
                         {
                         ptcour = (CONNECTOR *)ptccour->DATA;
                         if (ptcour->SIG==ptcsig)
                            break;
                         }
                     if (ptccour)
                        (void)addphcon(ptfig,NORTH,ptcour->NAME,x2,y2,
                                       ALU1,WLAYER1*SCALE_X);
                     else
                        printf("BIZ: Connecteur externe mal traite!!\n");
                     }
                  }
               }
           }
        }

    /* verifier que tous les con place ont chacun un correspondant */
    for (ptccour=ptcol->CT_CON;ptccour;ptccour=ptccour->NEXT)
        {
        if (!ptccour->DATA)
           continue;
        ptcour = (CONNECTOR *)ptccour->DATA;
        if ((ptcour->TYPE=='E')&&(!ptcour->USER))
           {
           printf("Warning: Terminal %s with no corresponding signal in column!!\n",
                  ptcour->NAME);
           }
        }

    /* verifier et assurer la continuite des signaux de controle */
    for (ptcins=ptcol->INS,ptcinsnex=ptcins->NEXT;ptcinsnex;
         ptcins=ptcins->NEXT,ptcinsnex=ptcinsnex->NEXT)
        {
        ptins = (INSTANCE *)ptcins->DATA;
        ptinsnex = (INSTANCE *)ptcinsnex->DATA;
        for (ptccon=ptins->CT_CON;ptccon;ptccon=ptccon->NEXT)
            {
            if (!ptccon->DATA)
               break;
            ptconctrl = (CONNECTOR *)ptccon->DATA;
            ptcsig = ptconctrl->SIG;
            ptsig = (SIGNAL *)ptcsig->DATA;
            for (ptcpos=ptconctrl->POS;ptcpos;ptcpos=ptcpos->NEXT)
                {
                ptpos = (POSSIBILITY *)ptcpos->DATA;
                if (ptpos->ACCES==NORTH)
                   {
                   x1 = ptpos->X + ptcol->X;
                   y1 = ptpos->Y;
                   for (ptcconex=ptinsnex->CT_CON;ptcconex;
                        ptcconex=ptcconex->NEXT)
                       {
                       if (!ptcconex->DATA)
                          break;
                       ptconctrlnex = (CONNECTOR *)ptcconex->DATA;
                       ptcsig2 = ptconctrlnex->SIG;
                       ptsig2 = (SIGNAL *)ptcsig2->DATA;
                       for (ptcpos2=ptconctrlnex->POS;ptcpos2;
                            ptcpos2=ptcpos2->NEXT)
                           {
                           ptpos2 = (POSSIBILITY *)ptcpos2->DATA;
                           if (ptpos2->ACCES==SOUTH)
                              {
                              x2 = ptpos2->X + ptcol->X;
                              y2 = ptpos2->Y;
                              if (x1==x2)
                                 {
                                 if (y1==y2)
                                    {
                                    if (ptsig==ptsig2)
                                       {
                                       /* marquer les deux connecteurs vis a vis */
                                       ptpos->USER = NULL;
                                       ptpos->USER = addchain(NULL,(void *)NULL);
                                       ptpos2->USER = NULL;
                                       ptpos2->USER = addchain(NULL,(void *)NULL);
                                       }
                                    else
                                       {
                                       printf("WARNING: Be careful, abutability problem for signal %s between %s and %s\n",ptsig->NAME,ptins->INSNAME,ptinsnex->INSNAME);
                                       }
                                    }
                                 else /* c.a.d y1!=y2 */
                                    {
                                    if (ptsig==ptsig2)
                                       {
                                       /* marquer les deux connecteurs vis a vis */
                                       ptpos->USER = NULL;
                                       ptpos->USER = addchain(NULL,(void *)NULL);
                                       ptpos2->USER = NULL;
                                       ptpos2->USER = addchain(NULL,(void *)NULL);
                                       /* ajouter un segment vertical en ALU1 */
                                       (void)addphseg(ptfig,ALU1,WLAYER1*SCALE_X,
                                                      x1,y1,x2,y2,ptsig->NAME);
                                       }
                                    else
                                       {
                                       if ((y2-y1)<ALU1_ALU1)
                                          printf("WARNING: Be careful, DRC problem between %s and %s\n",ptins->INSNAME,ptinsnex->INSNAME);
                                       else
                                          {
                                          /* marquer les deux cons vis a vis */
                                          ptpos->USER = NULL;
                                          ptpos->USER = addchain(NULL,(void *)NULL);
                                          ptpos2->USER = NULL;
                                          ptpos2->USER =addchain(NULL,(void *)NULL);
                                          }
                                       }
                                    }
                                 }
                              }
                           }
                       }
                   }
                }
            }
        for (ptccon=ptins->CT_CON;ptccon;ptccon=ptccon->NEXT)
            {
            if (!ptccon->DATA)
               break;
            ptconctrl = (CONNECTOR *)ptccon->DATA;
            ptcsig = ptconctrl->SIG;
            ptsig = (SIGNAL *)ptcsig->DATA;
            for (ptcpos=ptconctrl->POS;ptcpos;ptcpos=ptcpos->NEXT)
                {
                ptpos = (POSSIBILITY *)ptcpos->DATA;
                if ((ptpos->ACCES==NORTH)&&(!ptpos->USER))
                   {
                   printf("WARNING: Be careful, continuity problem for signal %s between %s and %s\n",ptsig->NAME,ptins->INSNAME,ptinsnex->INSNAME);
                   }
                }
            }
        for (ptccon=ptinsnex->CT_CON;ptccon;ptccon=ptccon->NEXT)
            {
            if (!ptccon->DATA)
               break;
            ptconctrl = (CONNECTOR *)ptccon->DATA;
            ptcsig = ptconctrl->SIG;
            ptsig = (SIGNAL *)ptcsig->DATA;
            for (ptcpos=ptconctrl->POS;ptcpos;ptcpos=ptcpos->NEXT)
                {
                ptpos = (POSSIBILITY *)ptcpos->DATA;
                if ((ptpos->ACCES==SOUTH)&&(!ptpos->USER))
                   {
                   printf("WARNING: Be careful, continuity problem for signal %s between %s and %s\n",ptsig->NAME,ptins->INSNAME,ptinsnex->INSNAME);
                   }
                }
            }
        }
    }
 
 /* boucle de sauvegarde des VIAS */
 for (ptcvia=ptcol->VIA;ptcvia;ptcvia=ptcvia->NEXT)
     {
     ptvia = (VIA *)ptcvia->DATA;
     x = ptcol->X + ptvia->X;
     y = ptvia->Y;
     (void)addphvia(ptfig,CONT_VIA,x,y);
     }

 /* boucle de sauvegarde des SEGMENTS */
 for (ptcseg=ptcol->SEG;ptcseg;ptcseg=ptcseg->NEXT)
     {
     ptseg = (SEGMENT *)ptcseg->DATA;
     x1 = ptcol->X + ptseg->X1;
     y1 = ptseg->Y1;
     x2 = ptcol->X + ptseg->X2;
     y2 = ptseg->Y2;
     (void)addphseg(ptfig,ptseg->LAYER,ptseg->WIDTH*SCALE_X,
                    x1,y1,x2,y2,ptseg->NAME);
     }

 /* boucle de sauvegarde des INSTANCES */
 for (ptcins=ptcol->INS;ptcins;ptcins=ptcins->NEXT)
     {
     ptins = (INSTANCE *)ptcins->DATA;
     x = ptcol->X + ptins->X;
     y = ptins->Y;
     (void)addphins(ptfig,ptins->FIGNAME,ptins->INSNAME,ptins->TRANSF,x,y);
     }

 /* ajout des connecteurs et segments d'alimentation en fonction des gabarits */
 /* boucle sur les lignes */
 x1 = ptcol->X;
 x2 = x1 + ptcol->WIDTH;
 ptclin = ptfig_dpr->LIN;
 ptgab = ((LINE *)ptclin->DATA)->GAB;
 width = ptgab->WALIM1;
 y1 = ((LINE *)ptclin->DATA)->Y;
 y2 = y1;
 indexalim = 0;
 vssname = namealloc("vss");
 vddname = namealloc("vdd");
 /* chercher s'il y a un bloc avec un rappel vssname dans le circuit */
 rappel_vss = testrappel_inbloc(vssname,ptfig_dpr);
 /* chercher s'il y a un bloc avec un rappel vddname dans le circuit */
 rappel_vdd = testrappel_inbloc(vddname,ptfig_dpr);
 /* traitement de la premiere alimentation */
 if (!strncmp(ptgab->ALIM1,vssname,3))
    {
    for (ptcalim=ptfig_dpr->ALIM;ptcalim;ptcalim=ptcalim->NEXT)
        {
        ptalim = (CONNECTOR *)ptcalim->DATA;
        if (!strncmp(ptalim->NAME,vssname,3))
           break;
        }
    if ((ptcalim)||(rappel_vss==1))
       /*c.a.d rappel d'alim existe dans canal ou dans bloc*/
       NodeName = vssname;
    else /* c.a.d pas de rappel d'alim */
       NodeName = nameindex(vssname,indexalim);
    }
 else
    {
    for (ptcalim=ptfig_dpr->ALIM;ptcalim;ptcalim=ptcalim->NEXT)
        {
        ptalim = (CONNECTOR *)ptcalim->DATA;
        if (!strncmp(ptalim->NAME,vddname,3))
           break;
        }
    if ((ptcalim)||(rappel_vdd==1))
       /* c.a.d rappel d'alim existe dans canal ou dans bloc*/
       NodeName = vddname;
    else /* c.a.d pas de rappel d'alim */
       NodeName = nameindex(vddname,indexalim);
    }
 if (x2>x1)
    {
    (void)addphcon(ptfig,WEST,NodeName,x1,y1,ALU2,width);
    (void)addphcon(ptfig,EAST,NodeName,x2,y2,ALU2,width);
    (void)addphseg(ptfig,(char)ALU2,width,x1,y1,x2,y2,NodeName);
    }
 else
    if (ptcol->TYPE=='L')
       (void)addphcon(ptfig,EAST,NodeName,x1,y1,ALU2,width);
    else
       (void)addphcon(ptfig,WEST,NodeName,x1,y1,ALU2,width);

 /* boucle de traitement des alimentations suivante */
 for (ptclin=ptfig_dpr->LIN;ptclin;ptclin=ptclin->NEXT)
     {
     ptgab = ((LINE *)ptclin->DATA)->GAB;
     width = ptgab->WALIM2;
     y1 = ((LINE *)ptclin->DATA)->Y + ptgab->HEIGHT;
     y2 = y1; 
     indexalim = indexalim + 1;
     if (!strncmp(ptgab->ALIM1,vssname,3))
        {
        for (ptcalim=ptfig_dpr->ALIM;ptcalim;ptcalim=ptcalim->NEXT)
            {
            ptalim = (CONNECTOR *)ptcalim->DATA;
            if (!strncmp(ptalim->NAME,vddname,3))
               break;
            }
        if ((ptcalim)||(rappel_vdd==1))
           /*c.a.d rappel d'alim existe dans canal ou dans bloc*/
           NodeName = vddname;
        else /* c.a.d pas de rappel d'alim */
           NodeName = nameindex(vddname,indexalim);
        }
     else
        {
        for (ptcalim=ptfig_dpr->ALIM;ptcalim;ptcalim=ptcalim->NEXT)
            {
            ptalim = (CONNECTOR *)ptcalim->DATA;
            if (!strncmp(ptalim->NAME,vssname,3))
               break;
            }
        if ((ptcalim)||(rappel_vss==1))
           /* c.a.d rappel d'alim existe danscanal ou dans bloc*/
           NodeName = vssname;
        else /* c.a.d pas de rappel d'alim */
           NodeName = nameindex(vssname,indexalim);
        }
     if (x2>x1)
        {
        (void)addphcon(ptfig,WEST,NodeName,x1,y1,ALU2,width);
        (void)addphcon(ptfig,EAST,NodeName,x2,y2,ALU2,width);
        (void)addphseg(ptfig,(char)ALU2,width,x1,y1,x2,y2,NodeName);
        }
     else
        if (ptcol->TYPE=='L')
           (void)addphcon(ptfig,EAST,NodeName,x1,y1,ALU2,width);
        else
           (void)addphcon(ptfig,WEST,NodeName,x1,y1,ALU2,width);
     }

 return ptfig;
 }

/**********************************************************************************
* putvias()                                                                       *
* rajouter les vias necessaires pour un y donne                                   *
**********************************************************************************/
 void           putvias(ptfig_col,x,y,width)
 phfig_list    *ptfig_col;
 long           x;
 long           y;
 long           width;

 {
 long       xcour=0;

 for (xcour=x-SCALE_X*(((width/SCALE_X)/2)-NOTCHE_LAYER1);
      (xcour+NOTCHE_LAYER1*SCALE_X)<=(x+SCALE_X*((width/SCALE_X)/2));
      xcour=xcour+VIA_VIA*SCALE_X)
     addphvia(ptfig_col,CONT_VIA,xcour,y);
 }

/**********************************************************************************
* rappelalim()                                                                    *
* rajouter des alimentations verticales, les vias correspondant, mettre a jour    *
* les x2 des segments horizontaux existants et mettre a jour les position et les  *
* largeurs des colonnes concernees                                                *
**********************************************************************************/
 void           rappelalim(ptccol,ptfig_col)
 chain_list    *ptccol;
 phfig_list    *ptfig_col;

 {
 COLUMN      *ptcol=NULL;
 long         xmax=MINLONG;
 long         width=0;
 long         deltax=0;
 long         widthprev=MINLONG;
 long         x1=0,x2=0,y1=0,y2=0;
 phseg_list  *ptsegmbk=NULL;
 phcon_list  *ptconmbk=NULL;
 chain_list  *ptcalim=NULL;
 CONNECTOR   *ptalim=NULL;
 POSSIBILITY *ptpos=NULL;
 chain_list  *ptccol1=NULL;
 COLUMN      *ptcol1=NULL;
 char        *vdd=NULL;
 char        *vss=NULL;

 vdd = namealloc("vdd");
 vss = namealloc("vss");

 for (ptsegmbk=ptfig_col->PHSEG;ptsegmbk;ptsegmbk=ptsegmbk->NEXT)
     {
     if ((manorme(ptsegmbk->TYPE)=='V')&&(ptsegmbk->X1>xmax))
        {
        xmax = ptsegmbk->X1;
        }
     }
 ptcol = (COLUMN *)ptccol->DATA;
 for (ptcalim=ptcol->ALIMS;ptcalim;ptcalim=ptcalim->NEXT)
     {
     ptalim = (CONNECTOR *)ptcalim->DATA;
     ptpos = (POSSIBILITY *)ptalim->POS->DATA;
     width = ptpos->WIDTH;
     if (xmax==MINLONG) /* c.a.d pas de segs VER dans le canal */
        if (widthprev==MINLONG) /* c.a.d premier rappel */
           x1 = ptcol->X + SCALE_X*((ALU1_ALU1-WLAYER1+1)/2 + (width/SCALE_X+1)/2);
        else
           x1 = x1 + SCALE_X*((widthprev/SCALE_X + 1)/2 + (ALU1_ALU1-WLAYER1) +
                (width/SCALE_X + 1)/2);
     else /* c.a.d existent des segments verticaux */
        if (widthprev==MINLONG) /* c.a.d premier rappel */
           x1 = xmax + SCALE_X*((ALU1_ALU1) + (width/SCALE_X + 1)/2);
        else
           x1 = x1 + SCALE_X*((widthprev/SCALE_X + 1)/2 + (ALU1_ALU1-WLAYER1) +
                (width/SCALE_X + 1)/2);
     x2 = x1;
     y1 = ptcol->Y;
     y2 = ptcol->Y + ptcol->HEIGHT;
     deltax = x2 - (ptcol->X + ptcol->WIDTH);
     ptfig_col->XAB2 = ptfig_col->XAB2 + deltax;
     (void)addphcon(ptfig_col,SOUTH,ptalim->NAME,x1,y1,ALU1,width);
     (void)addphcon(ptfig_col,NORTH,ptalim->NAME,x2,y2,ALU1,width);
     (void)addphseg(ptfig_col,ALU1,width,x1,y1-SCALE_X*(NOTCHE_LAYER1),
                    x2,y2+SCALE_X*(NOTCHE_LAYER1),ptalim->NAME);
     /* rajouter les vias a chaque alimentation horizontale */
     for (ptconmbk=ptfig_col->PHCON;ptconmbk;ptconmbk=ptconmbk->NEXT)
         {
         if (ptconmbk->ORIENT==EAST)
            {
            if (((!strncmp(ptconmbk->NAME,vdd,3))&&(!strncmp(ptalim->NAME,vdd,3)))||
                ((!strncmp(ptconmbk->NAME,vss,3))&&(!strncmp(ptalim->NAME,vss,3))))
               {
               putvias(ptfig_col,x1,ptconmbk->YCON,width);
               }
            }
         }
     widthprev = width;
     }
 /* mises a jour eventuelles */
 x2 = x1 + SCALE_X*(((width/SCALE_X +1)/2) + ((ALU1_ALU1 + 1)/2));
 deltax = x2 - (ptcol->X + ptcol->WIDTH);
 if (deltax>0)
    {
    ptcol->WIDTH = ptcol->WIDTH + deltax;
    ptfig_col->XAB2 = ptfig_col->XAB2 + deltax;
    /* mise a jour des x2 des segments HOR du canal */
    for (ptsegmbk=ptfig_col->PHSEG;ptsegmbk;ptsegmbk=ptsegmbk->NEXT)
        {
        if ((manorme(ptsegmbk->TYPE)=='H')&&(ptsegmbk->X2==(ptcol->X+ptcol->WIDTH-deltax)))
           {
           ptsegmbk->X2 = ptsegmbk->X2 + deltax;
           }
        }
    /* mise a jour des x des connecteurs EAST du canal */
    for (ptconmbk=ptfig_col->PHCON;ptconmbk;ptconmbk=ptconmbk->NEXT)
        {
        if (ptconmbk->ORIENT==EAST)
           {
           ptconmbk->XCON = ptconmbk->XCON + deltax;
           }
        }
    /* ajouter des segments horizontaux si le canal a une largeur initiale nulle */
    if (ptcol->WIDTH-deltax==0)
       {
       for (ptconmbk=ptfig_col->PHCON;ptconmbk;ptconmbk=ptconmbk->NEXT)
           {
           if (ptconmbk->ORIENT==WEST)
              {
              (void)addphseg(ptfig_col,ALU2,ptconmbk->WIDTH,ptcol->X,
              ptconmbk->YCON,ptcol->X+ptcol->WIDTH,ptconmbk->YCON,ptconmbk->NAME);
              }
           }
       }
    /* mise a jour des positions des colonnes suivantes */
    for (ptccol1=ptccol->NEXT;ptccol1;ptccol1=ptccol1->NEXT)
        {
        ptcol1 = (COLUMN *)ptccol1->DATA;
        ptcol1->X = ptcol1->X + deltax;
        }
    }
 }

/**********************************************************************************
* save_nwell()                                                                    *
* sauvegarde des NWELLs du canal                                                  *
**********************************************************************************/
 void        save_nwell(ptfig_col,ptcoll,ptcolr)
 phfig_list *ptfig_col;
 COLUMN     *ptcoll;
 COLUMN     *ptcolr;

 {
 chain_list *ptcinsl=NULL;
 chain_list *ptcinsr=NULL;
 chain_list *ptcnwell=NULL;
 chain_list *ptcnwelr=NULL;
 INSTANCE   *ptinsl=NULL;
 INSTANCE   *ptinsr=NULL;
 NWELLREF   *ptnwell=NULL;
 NWELLREF   *ptnwelr=NULL;
 long        y1l,y2l,y1r,y2r;
 long        x1,y1,x2,y2;
 long        ymin,ymax;
 long        width;

 for (ptcinsl=ptcoll->INS;ptcinsl;ptcinsl=ptcinsl->NEXT)
     {
     ptinsl = (INSTANCE *)ptcinsl->DATA;
     x1 = ptcoll->X + ptinsl->X + ptinsl->WIDTH;
     if ((ptcoll->X+ptcoll->WIDTH-x1)<SCALE_X*NWELL_NWELL)
        {
        for (ptcnwell=ptinsl->N_WELL;ptcnwell;ptcnwell=ptcnwell->NEXT)
            {
            ptnwell = (NWELLREF *)ptcnwell->DATA;
            if (ptnwell->X!=ptinsl->X) /* c.a.d nwell cote est de la cellule */
               {
               for (ptcinsr=ptcolr->INS;ptcinsr;ptcinsr=ptcinsr->NEXT)
                   {
                   ptinsr = (INSTANCE *)ptcinsr->DATA;
                   x2 = ptcolr->X + ptinsr->X;
                   if ((x2-x1)<SCALE_X*NWELL_NWELL)
                      {
                      for (ptcnwelr=ptinsr->N_WELL;ptcnwelr;ptcnwelr=ptcnwelr->NEXT)
                          {
                          ptnwelr = (NWELLREF *)ptcnwelr->DATA;
                          if (ptnwelr->X!=(ptinsr->X+ptinsr->WIDTH)) /*c.a.d west*/
                             {
                             y1l = ptnwell->Y - SCALE_X*(ptnwell->WIDTH/SCALE_X/2);
                             y2l = ptnwell->Y + SCALE_X*(ptnwell->WIDTH/SCALE_X/2);
                             y1r = ptnwelr->Y - SCALE_X*(ptnwelr->WIDTH/SCALE_X/2);
                             y2r = ptnwelr->Y + SCALE_X*(ptnwelr->WIDTH/SCALE_X/2);
                             if ((y1l<y2r)&&(y1r<y2l)) /*c.a.d intersection*/
                                {
                                if (y1l>y1r)
                                   ymin = y1l;
                                else
                                   ymin = y1r;
                                if (y2l<y2r)
                                   ymax = y2l;
                                else
                                   ymax = y2r;
                                if ((ymax-ymin)>=MIN_NWELL)
                                   {
                                   width = ymax - ymin;
                                   y1 = ymin + width/2;
                                   y2 = y1;
                                   if (x1!=x2)
                                      addphseg(ptfig_col,NWELL,width,x1,y1,x2,y2,"");
                                   }
                                }
                             }
                          }
                      }
                   }
               }
            }
        }
     }
 }

/*********************************************
* dprsave                                    *
*  Procedure principale de sauvegarde de la  *
*  figure routee au format MBK.              *
*   les differents types de canaux sont      *
*  Sauvegardes sur disque puis instancies    *
*  dans la figure routee, a laquelle on      *
*  ajoute  les connecteurs externes.         *
*   Enfin la figure est eventuellement       *
*  mise a plat avant la sauvegarde.          *
*********************************************/

/************************************
* dprsave                           *
*    |-(MBK)-addphfig               *
*    |-------save_chcol             *
*    |          |-(MBK)-namealoc    *
*    |          |-------track_num   *
*    |          |-------num_track   *
*    |          |-------num_track_y *
*    |          |-(MBK)-addphfig    *
*    |          |-(MBK)-addphseg    *
*    |          |-(MBK)-addphvia    *
*    |          +-(MBK)-savephfig   *
*    |-------save_opcol             *
*    |          |-(MBK)-addphfig    *
*    |          |-(MBK)-addphcon    *
*    |          |-(MBK)-addphvia    *
*    |          |-(MBK)-addphseg    *
*    |          |-(MBK)-addphins    *
*    |          +-(MBK)-savephfig   *
*    |-(MBK)-addphcon               *
*    |-(MBK)-rflattenphfig          *
*    +-(MBK)-savephfig              *
*                                   *
************************************/

/**********************************************************************************
* sauvegarde de la figure routee:  DPR->MBK                                       *
**********************************************************************************/
 void      dprsave(ptfig_dpr,ptfigname,ptlist_num,flatten)
 FIGURE   *ptfig_dpr;
 char     *ptfigname;
 NUMTRACK *ptlist_num;
 int       flatten;
 
 {
 phfig_list    *ptfig_ph=NULL;
 chain_list    *ptccol=NULL;
 COLUMN        *ptcol=NULL;
 chain_list    *ptccolnwell=NULL;
 COLUMN        *ptcolnwell=NULL;
 chain_list    *ptccolnext=NULL;
 COLUMN        *ptcolnext=NULL;
 COLUMN        *ptcolprev=NULL;
 char          *ptcolname=NULL;
 long           x,y;
 long           x1,y1,x2,y2;
 phfig_list    *ptfig_col=NULL;
 ConnectorList *ptlist_conwest=NULL;
 ConnectorList *ptlist_coneast=NULL;
 phcon_list    *ptmbkcon=NULL;
 chain_list    *ptcallow=NULL;
 chain_list    *ptcallowtmp=NULL;
 SEGMENT       *ptallow=NULL;
 phseg_list    *ptsegmbk=NULL;
 chain_list    *ptcins=NULL;
 INSTANCE      *ptins=NULL;
 chain_list    *ptcnwell=NULL;
 NWELLREF      *ptnwell=NULL;
 
 /* ouverture du fichier resultat */
 ptfig_ph = addphfig(ptfigname);

 /* recuperation des valeurs de l'abutment box de la figure mere */
 ptccol = ptfig_dpr->COL;
 ptcol = (COLUMN *)ptccol->DATA;
 ptfig_ph->XAB1 = ptcol->X;
 ptfig_ph->YAB1 = ptcol->Y;
 ptfig_ph->XAB2 = ptcol->X + ptcol->WIDTH;
 ptfig_ph->YAB2 = ptcol->Y + ptcol->HEIGHT;

 /* sauvegarde de la premiere colonne LEFT */
 ptccol = ptfig_dpr->COL;
 ptcol = (COLUMN *)ptccol->DATA;
 ptcolprev = ptcol;
 ptccolnext = ptccol->NEXT;
 ptcolnext = (COLUMN *)ptccolnext->DATA;
 ptcolname = ptcol->NAME;
 x = ptcol->X;
 y = ptcol->Y;
 ptlist_coneast = ((CHANNEL *)ptcolnext->DF_CON->DATA)->WESTCON;
 ptlist_conwest = ((CHANNEL *)ptcolnext->DF_CON->DATA)->EASTCON;
 ptfig_col = save_opcol(ptcol,NULL,ptlist_coneast,ptlist_num,ptfig_dpr);
 /* Save NWELL that may exist in the first channel */
 if (ptcol->WIDTH<SCALE_X*NWELL_NWELL)
    {
    ptccolnwell = ptccolnext->NEXT;
    ptcolnwell = (COLUMN *)ptccolnwell->DATA;
    for (ptcins=ptcolnwell->INS;ptcins;ptcins=ptcins->NEXT)
        {
        ptins = (INSTANCE *)ptcins->DATA;
        x2 = ptcolnwell->X + ptins->X;
        if ((x2-ptcolnwell->X)<SCALE_X*NWELL_NWELL)
           {
           for (ptcnwell=ptins->N_WELL;ptcnwell;ptcnwell=ptcnwell->NEXT)
               {
               ptnwell = (NWELLREF *)ptcnwell->DATA;
               if (ptnwell->X!=(ptins->X+ptins->WIDTH))
                  {
                  x1 = ptfig_ph->XAB1;
                  if ((x2-x1)<SCALE_X*NWELL_NWELL)
                     {
                     if ((x2-x1)!=0)
                        addphseg(ptfig_col,NWELL,ptnwell->WIDTH,
                                 x1,ptnwell->Y,x2,ptnwell->Y,"");
                     }
                  }
               }
           }
        }
    }
 if (flatten)
    savephfig(ptfig_col);
 (void *)addphins(ptfig_ph,ptcolname,ptcolname,NOSYM,x,y);

 /* sauvegarde des connecteurs WEST de la figure mere */
 ptfig_ph->XAB2 = ptcol->X + ptcol->WIDTH;
 for (ptmbkcon=ptfig_col->PHCON;ptmbkcon;ptmbkcon=ptmbkcon->NEXT)
     {
     addphcon(ptfig_ph,WEST,ptmbkcon->NAME,ptmbkcon->XCON,ptmbkcon->YCON,
              ptmbkcon->LAYER,ptmbkcon->WIDTH);
     }

 /* boucle de sauvegarde des colonnes Operator ou Channel*/
 for (ptccol=ptfig_dpr->COL->NEXT;ptccol->NEXT;ptccol=ptccol->NEXT)
     {
     ptcol = (COLUMN *)ptccol->DATA;
     ptccolnext = ptccol->NEXT;
     ptcolnext = (COLUMN *)ptccolnext->DATA;
     ptcolname = ptcol->NAME;
     x = ptcol->X;
     y = ptcol->Y;
     if (ptcol->TYPE=='O')
        {
        /* sauvegarde des colonnes de type Operator */
        ptlist_coneast = ((CHANNEL *)ptcolnext->DF_CON->DATA)->WESTCON;
        ptfig_col = save_opcol(ptcol,ptlist_conwest,ptlist_coneast,
                               ptlist_num,ptfig_dpr);
        ptcolprev = ptcol;
        }
     else /* sauvegarde des colonnes de type Channel: canaux de routage */
        {
        ptlist_conwest = ((CHANNEL *)ptcol->DF_CON->DATA)->EASTCON;
        ptfig_col = save_chcol(ptcol,ptlist_num,ptfig_dpr);
        if (ptcol->ALIMS)
           rappelalim(ptccol,ptfig_col);
        /* sauvegarde des NWELLs du canal s'il n'est pas assez large */
        if (ptcol->WIDTH<SCALE_X*NWELL_NWELL)
           save_nwell(ptfig_col,ptcolprev,ptcolnext);
        }
     if ((ptcol->TYPE=='C')&&(ptcol->S_WIDTH))
        {
        /* deleter les transp inhibees par les segments HOR et ALU2 du canal */
        for (ptsegmbk=ptfig_col->PHSEG;ptsegmbk;ptsegmbk=ptsegmbk->NEXT)
            {
            if ((manorme(ptsegmbk->TYPE)=='H')&&(ptsegmbk->LAYER==ALU2))
               {
               for (ptcallow=ptfig_dpr->ALLOW;ptcallow;ptcallow=ptcallowtmp)
                   {
                   ptcallowtmp = ptcallow->NEXT;
                   ptallow = (SEGMENT *)ptcallow->DATA;
                   if (ptallow->Y1==ptsegmbk->Y1)
                      {
                      ptfig_dpr->ALLOW = delchain(ptfig_dpr->ALLOW,ptcallow);
                      break;
                      }
                   }
               }
            }
        }
     if (flatten)
        savephfig(ptfig_col);
     (void *)addphins(ptfig_ph,ptcolname,ptcolname,NOSYM,x,y);
     /* sauvegarde des connecteurs NORTH/SOUTH de la figure mere */
     ptfig_ph->XAB2 = ptcol->X + ptcol->WIDTH;
     for (ptmbkcon=ptfig_col->PHCON;ptmbkcon;ptmbkcon=ptmbkcon->NEXT)
         {
         if ((ptmbkcon->ORIENT==NORTH)||(ptmbkcon->ORIENT==SOUTH))
            addphcon(ptfig_ph,ptmbkcon->ORIENT,ptmbkcon->NAME,ptmbkcon->XCON,
                     ptmbkcon->YCON,ptmbkcon->LAYER,ptmbkcon->WIDTH);
         }
     }
  
 /* sauvegarde de la derniere colonne RIGHT */
 ptcol = (COLUMN *)ptccol->DATA;
 ptcolname = ptcol->NAME;
 x = ptcol->X;
 y = ptcol->Y;
 ptfig_col = save_opcol(ptcol,ptlist_conwest,NULL,ptlist_num,ptfig_dpr);
 /* Save NWELL wires that may exist in the last channel */
 if (ptcol->WIDTH<SCALE_X*NWELL_NWELL)
    {
    for (ptcins=ptcolprev->INS;ptcins;ptcins=ptcins->NEXT)
        {
        ptins = (INSTANCE *)ptcins->DATA;
        x1 = ptcolprev->X + ptins->X + ptins->WIDTH;
        if ((ptcolprev->X+ptcolprev->WIDTH-x1)<SCALE_X*NWELL_NWELL)
           {
           for (ptcnwell=ptins->N_WELL;ptcnwell;ptcnwell=ptcnwell->NEXT)
               {
               ptnwell = (NWELLREF *)ptcnwell->DATA;
               if (ptnwell->X!=ptins->X)
                  {
                  x2 = ptfig_ph->XAB2;
                  if ((x2-x1)<SCALE_X*NWELL_NWELL)
                     {
                     if ((x2-x1)!=0)
                        addphseg(ptfig_col,NWELL,ptnwell->WIDTH,x1,ptnwell->Y,
                                 x2,ptnwell->Y,"");
                     }
                  }
               }
           }
        }
    }
 if (flatten)
    savephfig(ptfig_col);
 (void *)addphins(ptfig_ph,ptcolname,ptcolname,NOSYM,x,y);
 
/* sauvegarde des connecteurs EAST de la figure mere */
 ptfig_ph->XAB2 = ptcol->X + ptcol->WIDTH;
 for (ptmbkcon=ptfig_col->PHCON;ptmbkcon;ptmbkcon=ptmbkcon->NEXT)
     {
     addphcon(ptfig_ph,EAST,ptmbkcon->NAME,ptmbkcon->XCON,ptmbkcon->YCON,
              ptmbkcon->LAYER,ptmbkcon->WIDTH);
     }

 /* sauvegarde des transparences pas inhibees par les canaux de routage */
 for (ptcallow=ptfig_dpr->ALLOW;ptcallow;ptcallow=ptcallow->NEXT)
     {
     ptallow = (SEGMENT *)ptcallow->DATA;
     addphseg(ptfig_ph,TALU2,WLAYER2*SCALE_X,
              ptfig_ph->XAB1,ptallow->Y1,ptfig_ph->XAB2,ptallow->Y2,"");
     }
 
 if (!flatten)
    rflattenphfig(ptfig_ph,'N','Y');
 savephfig(ptfig_ph);
 }
