/*
 *  $Id: util_Floorplan.c,v 1.3 2006/06/28 13:25:07 jpc Exp $
 *
 *  /----------------------------------------------------------------\
 *  |                                                                |
 *  |        A l l i a n c e   C A D   S y s t e m                   |
 *  |  S i l i c o n   E n s e m b l e / A l l i a n c e             |
 *  |                                                                |
 *  |  Author    :                      Jean-Paul CHAPUT             |
 *  |  E-mail    :         alliance-users@asim.lip6.fr             |
 *  | ============================================================== |
 *  |  C Module    :         "./util_Floorplan.c"                    |
 *  | ************************************************************** |
 *  |  U p d a t e s                                                 |
 *  |                                                                |
 *  \----------------------------------------------------------------/
 */


# include  "util_Defs.h"
# include  "debugoff.h"


/*  ------------------------------------------------------------------
 *  Local constants.
 */

# define        F_NO_OVERLAP        ((long)(1<<0))
# define        F_OVERLAP           ((long)(1<<1))
# define        F_I1_IN_I2          ((long)(1<<2))
# define        F_I2_IN_I1          ((long)(1<<3))
# define        F_SEG_EXCLUS        ((long)(1<<0))
# define        F_SEG_INCLUS        ((long)(1<<1))
# define        F_SEG_HALFOVER      ((long)(1<<2))
# define        F_SEG_OVER          ((long)(1<<3))
# define        F_TERM_XY           ((long)(1<<0))
# define        F_TERM_LAYER        ((long)(1<<1))
# define        F_TERM_SIDE         ((long)(1<<2))
# define        F_TERM_USER         ((long)(1<<3))

# define        F_SIDE_FULL         ((long)(1<<1))

# define        SIDE_NORTH          0
# define        SIDE_SOUTH          1
# define        SIDE_EAST           2
# define        SIDE_WEST           3
# define        SIDE_ALL            4


/*  ------------------------------------------------------------------
 *  Local structures.
 */

  typedef struct ulocon_s {
    long  flags;
  } ulocon_t;

  typedef struct term_s {
             long  flags;
             char *name;
             char  layer;
             long  XY;
    struct term_s *next;
  } term_t;


  typedef struct side_s {
           char    orient;
           char    layer;
           long    flags;
           long    x;
           long    y;
           long    length;
           long    nbTerm;
           long    maxTerm;
    struct term_s *lTerm;
  } side_t;


/*  ------------------------------------------------------------------
 *  Local variables.
 */

  static         char  routingLayers3[256] = "alu1.alu2.alu3.";
  static         char  routingLayers4[256] =
                        "alu1.alu2.alu3.alu4.";
  static         char  routingLayers6[256] =
                        "alu1.alu2.alu3.alu4.alu5.alu6.";
  static         long  LV_dupTerm;
  static         long  LV_loTerm;


/*  ------------------------------------------------------------------
 *  Local macros.
 */

# define    SNAPGRID(x)  ((x) - ((x) % MBK_X_GRID))


/*  ----------------------------------------------------------------------
 *  Local functions declarations.
 */

  static struct term_s   *newTerm         __FP((struct term_s *apHead,
                                                         long  aFlags,
                                                         char *aName,
                                                         char  aLayer,
                                                         long  aXY));
  static struct term_s   *freeTerm        __FP((struct term_s *apTerm));
  static struct ulocon_s *getUlocon       __FP((struct locon *apLocon));
  static struct ulocon_s *newUlocon       __FP((struct locon *apLocon));
  static void             freeUlocon      __FP((struct locon *apLocon));
  static void             linkTerm        __FP((struct locon *apLocon,
                                                        long  aFlags));
  static void             unlinkTerm      __FP((struct locon *apLocon));
  static struct side_s   *newSide         __FP((char aOrient,
                                                char aLayer,
                                                long aX,
                                                long aY,
                                                long aLength));
  static void             freeSide        __FP((struct side_s *apSide));
  static struct side_s   *buildSide       __FP((struct phfig *apPhfig,
                                                struct lofig *apLofig,
                                                        char  aOrient,
                                                        char  aLayer));
  static            long  countDupTerms   __FP((struct phfig *apPhfig));
  static            long  addLoconUinfo   __FP((struct lofig *apLofig));
  static            void  freeLoconUinfo  __FP((struct lofig *apLofig));
  static            long  computeArea     __FP((struct lofig *apLofig));
# if 0
  static            long  intervalRel     __FP((long  aI1_min,
                                                long  aI1_max,
                                                long  aI2_min,
                                                long  aI2_max));
  static            long  segInArea       __FP((struct phseg *aPhseg,
                                                        long  aX1,
                                                        long  aY1,
                                                        long  aX2,
                                                        long  aY2));
# endif


/*
 *  /--------------------------------------------------------------------\
 *  |                     Functions Definitions                          |
 *  \--------------------------------------------------------------------/
 */

/*  ----------------------------------------------------------------------
 *  Function  :  "newTerm()".
 */

static struct term_s *newTerm (apHead, aFlags, aName, aLayer, aXY)
  struct term_s *apHead;
           long  aFlags;
           char *aName;
           char  aLayer;
           long  aXY;
{
  struct term_s *pTerm;


  pTerm = (struct term_s*)mbkalloc (sizeof (struct term_s));

  pTerm->flags = aFlags;
  pTerm->name  = aName;
  pTerm->layer = aLayer;
  pTerm->XY    = aXY;
  pTerm->next  = apHead;

  return (pTerm);
}


/*  ----------------------------------------------------------------------
 *  Function  :  "freeTerm()".
 */

static struct term_s *freeTerm (apTerm)
  struct term_s *apTerm;
{
  struct term_s *pNext;


  pNext = apTerm->next;

  mbkfree (apTerm);

  return (pNext);
}


/*  ----------------------------------------------------------------------
 *  Function  :  "getUlocon()".
 */

static struct ulocon_s *getUlocon (apLocon)
  struct locon *apLocon;
{
  struct ptype    *pType;


  if (!(pType = getptype (apLocon->USER, PTYPE_ULOCON))) return (NULL);

  return ((struct ulocon_s*)pType->DATA);
}


/*  ----------------------------------------------------------------------
 *  Function  :  "newUlocon()".
 */

static struct ulocon_s *newUlocon (apLocon)
  struct locon *apLocon;
{
  struct ulocon_s *pUlocon;


  if (!(pUlocon = getUlocon (apLocon))) {
    pUlocon = (struct ulocon_s*)mbkalloc (sizeof (struct ulocon_s));

    pUlocon->flags = 0L;

    apLocon->USER = addptype (apLocon->USER, PTYPE_ULOCON, (void*)pUlocon);
  }


  return (pUlocon);
}


/*  ----------------------------------------------------------------------
 *  Function  :  "freeUlocon()".
 */

static void  freeUlocon (apLocon)
  struct locon *apLocon;
{
  struct ptype *pType;


  if ((pType = getptype (apLocon->USER, PTYPE_ULOCON))) {
    mbkfree (pType->DATA);

    apLocon->USER = delptype (apLocon->USER, PTYPE_ULOCON);
  }
}


/*  ----------------------------------------------------------------------
 *  Function  :  "linkTerm()".
 */

static void  linkTerm (apLocon, aFlags)
  struct locon  *apLocon;
          long   aFlags;
{
  struct ulocon_s *pUlocon;


  if (!(pUlocon = getUlocon (apLocon)))
    pUlocon = newUlocon (apLocon);

  pUlocon->flags = aFlags;
}


/*  ----------------------------------------------------------------------
 *  Function  :  "unlinkTerm()".
 */

static void  unlinkTerm (apLocon)
  struct locon *apLocon;
{
  freeUlocon (apLocon);
}


/*  ----------------------------------------------------------------------
 *  Function  :  "newSide()".
 */

static struct side_s *newSide (aOrient, aLayer, aX, aY, aLength)
  char  aOrient;
  char  aLayer;
  long  aX;
  long  aY;
  long  aLength;
{
  struct side_s *pSide;


  pSide = (struct side_s*)mbkalloc (sizeof (struct side_s));

  pSide->nbTerm   = 0;
  pSide->maxTerm  = 0;
  pSide->flags    = 0;
  pSide->lTerm    = NULL;
  pSide->orient   = aOrient;
  pSide->layer    = aLayer;
  pSide->x        = aX;
  pSide->y        = aY;
  pSide->length   = aLength;

  return (pSide);
}


/*  ----------------------------------------------------------------------
 *  Function  :  "freeSide()".
 */

static void  freeSide (apSide)
  struct side_s *apSide;
{
  struct term_s *pTerm;


  for (pTerm = apSide->lTerm; pTerm != NULL; pTerm = freeTerm (pTerm));

  mbkfree (apSide);
}


/*  ----------------------------------------------------------------------
 *  Function  :  "buildSide()".
 */

static struct side_s *buildSide (apPhfig, apLofig, aOrient, aLayer)
  struct phfig *apPhfig;
  struct lofig *apLofig;
          char  aOrient;
          char  aLayer;
{
  struct side_s *pSide;
  struct  phcon *pPhcon;
           long  XSIDE, YSIDE, sideLength;


  switch (aOrient) {
    case WEST:
      XSIDE      = apPhfig->XAB1;
      YSIDE      = apPhfig->YAB1;
      sideLength = apPhfig->YAB2 - apPhfig->YAB1;
      break;
    case EAST:
      XSIDE      = apPhfig->XAB2;
      YSIDE      = apPhfig->YAB1;
      sideLength = apPhfig->YAB2 - apPhfig->YAB1;
      break;
    case NORTH:
      XSIDE      = apPhfig->XAB1;
      YSIDE      = apPhfig->YAB2;
      sideLength = apPhfig->XAB2 - apPhfig->XAB1;
      break;
    default:
    case SOUTH:
      XSIDE      = apPhfig->XAB1;
      YSIDE      = apPhfig->YAB1;
      sideLength = apPhfig->XAB2 - apPhfig->XAB1;
      break;
  }


  pSide = newSide (aOrient, aLayer, XSIDE, YSIDE, sideLength);

  for (pPhcon = apPhfig->PHCON; pPhcon != NULL; pPhcon = pPhcon->NEXT) {
    /* Checking terminal orientation. */
    if (pPhcon->ORIENT == aOrient) {
      switch (aOrient) {
        case EAST:
        case WEST:
          if (XSIDE != pPhcon->XCON) {
            eprinth ("buildSide");
            eprintf ("\n  East/west terminal %s at (%ld,%ld) is not on",
                     pPhcon->NAME,
                     pPhcon->XCON,
                     pPhcon->YCON);
            eprintf ("\n  the abutment-box.\n");
            EXIT (1);
          }

          /* Adding the terminal to the side's list. */
          pSide->nbTerm++;
          pSide->lTerm = newTerm (pSide->lTerm,
                                  F_TERM_XY|F_TERM_LAYER|F_TERM_USER,
                                  pPhcon->NAME,
                                  pPhcon->LAYER,
                                  pPhcon->YCON);
          break;
        case NORTH:
        default:
        case SOUTH:
          if (YSIDE != pPhcon->YCON) {
            eprinth ("buildSide");
            eprintf ("\n  North/south terminal %s at (%ld,%ld) is not on",
                     pPhcon->NAME,
                     pPhcon->XCON,
                     pPhcon->YCON);
            eprintf ("\n  the abutment-box.\n");
            EXIT (1);
          }

          /* Adding the terminal to the side's list. */
          pSide->nbTerm++;
          pSide->lTerm = newTerm (pSide->lTerm,
                                  F_TERM_XY|F_TERM_LAYER|F_TERM_USER,
                                  pPhcon->NAME,
                                  pPhcon->LAYER,
                                  pPhcon->XCON);
          break;
      }

      linkTerm (getlocon (apLofig, pPhcon->NAME),
                F_TERM_XY|F_TERM_LAYER|F_TERM_SIDE);
    }
  }

  return (pSide);
}


/*  ----------------------------------------------------------------------
 *  Function  :  "sortSide()".
 */

static void  sortSide(apSide)
  struct side_s *apSide;
{
  struct term_s *pTerm;
           char *tFilled;
           long  i, spacing, sideOrig;


  tFilled = (char*)mbkalloc (sizeof (char) * apSide->nbTerm);

  switch (apSide->orient) {
    case EAST:
    case WEST:
      sideOrig = apSide->y; break;
    case NORTH:
    case SOUTH:
    default:
      sideOrig = apSide->x; break;
  }

  spacing = apSide->length / apSide->nbTerm;
  for (i = 0; i < apSide->nbTerm; i++) tFilled[i] = '\0';

  for (pTerm = apSide->lTerm; pTerm != NULL; pTerm = pTerm->next) {
    if (pTerm->flags & F_TERM_XY) {
      tFilled[(pTerm->XY - sideOrig) / spacing ] = '\1';
    }
  }

  __DBG( fprintf (stderr, "spacing := %ld\n", spacing); )

  i = 0;
  for (pTerm = apSide->lTerm; pTerm != NULL; pTerm = pTerm->next) {
    __DBG( fprintf (stderr, "i := %ld\n", i); )

    if (!(pTerm->flags & F_TERM_XY)) {
      pTerm->XY    = sideOrig + SNAPGRID((spacing * i) + (spacing >> 1));
      pTerm->layer = apSide->layer;

      __DBG( fprintf (stderr, "pTerm->XY := %ld\n", pTerm->XY); )
    }

    i++;
  }
}


/*  ----------------------------------------------------------------------
 *  Function  :  "countDupTerms()".
 */

static long  countDupTerms (apPhfig)
  struct phfig *apPhfig;
{
  struct     phcon *pPhcon;
  struct authtable *htCon;
  struct  authelem *pElem;


  htCon = createauthtable (1024);

  /* Find the number of duplicated terminals. */
  for (pPhcon = apPhfig->PHCON; pPhcon != NULL; pPhcon = pPhcon->NEXT) {
    pElem = searchauthelem (htCon, pPhcon->NAME);

    if (!pElem) {
      pElem = addauthelem (htCon, pPhcon->NAME, -1);
    }

    pElem->VALUE++; 
  }


  LV_dupTerm = 0;

  /* Make the sum. */
  for (pPhcon = apPhfig->PHCON; pPhcon != NULL; pPhcon = pPhcon->NEXT) {
    pElem = searchauthelem (htCon, pPhcon->NAME);

    LV_dupTerm += pElem->VALUE; 

    /* Do not count twice duplicated terminals... */
    pElem->VALUE = 0;
  }

  destroyauthtable (htCon);


  return (LV_dupTerm);
}


/*  ----------------------------------------------------------------------
 *  Function  :  "addLoconUinfo()".
 */

static long  addLoconUinfo (apLofig)
  struct lofig *apLofig;
{
  struct     locon *pLocon;


  LV_loTerm = 0;


  for (pLocon = apLofig->LOCON; pLocon != NULL; pLocon = pLocon->NEXT) {
    LV_loTerm++;

    linkTerm (pLocon, 0);
  }

  return (LV_loTerm);
}


/*  ----------------------------------------------------------------------
 *  Function  :  "freeLoconUinfo()".
 */

static void  freeLoconUinfo (apLofig)
  struct lofig *apLofig;
{
  struct     locon *pLocon;


  for (pLocon = apLofig->LOCON; pLocon != NULL; pLocon = pLocon->NEXT) {
    unlinkTerm (pLocon);
  }
}


/*  ----------------------------------------------------------------------
 *  Function  :  "nextFreeLocon()".
 */

static struct locon *nextFreeLocon (apLocon)
  struct locon *apLocon;
{
  struct ulocon_s *pUlocon;
  struct locon    *pLocon;


  for (pLocon = apLocon; pLocon != NULL; pLocon = pLocon->NEXT) {
    pUlocon = getUlocon (pLocon);

    if (!(pUlocon->flags & F_TERM_SIDE)) return (pLocon);
  }

  return (NULL);
}


/*  ----------------------------------------------------------------------
 *  Function  :  "placeTerms()".
 */

extern void  placeTerms (apLofig, apPhfig)
  struct lofig *apLofig;
  struct phfig *apPhfig;
{
  struct side_s *tSide[4];
  struct term_s *pTerm;
  struct locon  *pLocon;
           long  iSide;
           long  spaceTerm, newSpaceTerm, sideSpaceTerm;
           long  nbPhterm , newNbPhterm;
           long  nbPlacedTerm;
           long  flagLoop;
           long  XCON, YCON;


  addLoconUinfo (apLofig);
  countDupTerms (apPhfig);

  tSide[SIDE_NORTH] = buildSide (apPhfig, apLofig, NORTH, ALU3);
  tSide[SIDE_SOUTH] = buildSide (apPhfig, apLofig, SOUTH, ALU3);
  tSide[SIDE_EAST]  = buildSide (apPhfig, apLofig, EAST , ALU2);
  tSide[SIDE_WEST]  = buildSide (apPhfig, apLofig, WEST , ALU2);


  /* Side allocation for free terminals. */

  nbPhterm     = LV_loTerm + LV_dupTerm;
  spaceTerm    = 0;
  nbPlacedTerm = 0;

  for (iSide = 0; iSide < SIDE_ALL; iSide++) {
    spaceTerm    += tSide[iSide]->length;
    nbPlacedTerm += tSide[iSide]->nbTerm;
  }

  spaceTerm /= (nbPhterm + 1);

  __DBG( fprintf (stderr, "spaceTerm := %ld\n", spaceTerm); )
  __DBG( fprintf (stderr, "nbPhterm  := %ld\n", nbPhterm ); )


  if (nbPlacedTerm < nbPhterm) {
    /* Find sides with free space for terminals. */
    for (flagLoop = TRUE; flagLoop; ) {
      flagLoop = FALSE;

      newSpaceTerm = 0;
      newNbPhterm  = LV_loTerm + LV_dupTerm;

      for (iSide = 0; iSide < SIDE_ALL; iSide++) {
        if (tSide[iSide]->flags & F_SIDE_FULL) {
          newNbPhterm -= tSide[iSide]->nbTerm;
        } else {

          sideSpaceTerm  = tSide[iSide]->length / (tSide[iSide]->nbTerm + 1);
          __DBG( fprintf (stderr, "sideSpaceTerm := %ld\n", sideSpaceTerm); )

          if (sideSpaceTerm <= spaceTerm) {
            __DBG( fprintf (stderr, "side %ld overloaded\n", iSide); )
            /* This side is overloaded : skip it. */
            flagLoop = TRUE;

            tSide[iSide]->flags   |= F_SIDE_FULL;
            tSide[iSide]->maxTerm  = tSide[iSide]->nbTerm;
            newNbPhterm -= tSide[iSide]->nbTerm;
          } else {
            newSpaceTerm  += sideSpaceTerm;
            tSide[iSide]->maxTerm  = tSide[iSide]->length / spaceTerm;
            __DBG( fprintf (stderr,
                            "tSide[%ld]->maxTerm := %ld\n",
                            iSide,
                            tSide[iSide]->maxTerm); )
          }
        }
      }  /* End of 'for(iSide ...)'. */

      spaceTerm = newSpaceTerm / (newNbPhterm + 1);

      __DBG( fprintf (stderr, "spaceTerm := %ld\n", spaceTerm); )
    }  /* End of 'for(flagLoop... )'. */
  }


  /* Dispatch remaining terminals on non-overloaded sides. */
  iSide = 0;

  for (pLocon = nextFreeLocon (apLofig->LOCON);
       pLocon != NULL; pLocon = nextFreeLocon (pLocon->NEXT)) {
    while (tSide[iSide]->nbTerm >= tSide[iSide]->maxTerm) {
      if (iSide >= SIDE_ALL) {
        eprinth ("placeTerms");
        eprintf ("\n  No more sides to place terminals");
        eprintf (" (this is a bug)\n\n");
        EXIT (1);
      }

      iSide++;
    }

    tSide[iSide]->nbTerm++;
    tSide[iSide]->lTerm = newTerm (tSide[iSide]->lTerm,
                                   0,
                                   pLocon->NAME,
                                   0,
                                   0);

    linkTerm (pLocon, F_TERM_SIDE);
  }


  /* Sets the positions on all sides. */
  for (iSide = 0; iSide < SIDE_ALL; iSide++) {
    __DBG (fprintf (stderr, "sortSide(%ld)\n", iSide); )
    sortSide (tSide[iSide]);
  }


  /* Add the physical terminals. */
  for (iSide = 0; iSide < SIDE_ALL; iSide++) {
    for (pTerm = tSide[iSide]->lTerm; pTerm != NULL; pTerm = pTerm->next) {
      switch (tSide[iSide]->orient) {
        case NORTH:
        case SOUTH:
        default:
          XCON = pTerm->XY;
          YCON = tSide[iSide]->y;
          break;
        case EAST:
        case WEST:
          XCON = tSide[iSide]->x;
          YCON = pTerm->XY;
          break;
      }
      
      addphcon (apPhfig,
                tSide[iSide]->orient,
                pTerm->name,
                XCON,
                YCON,
                pTerm->layer,
                MBKSCALE(2));
    }
  }



  /* Free all the sides structures. */
  for (iSide = 0; iSide < SIDE_ALL; iSide++) freeSide (tSide[iSide]);

  freeLoconUinfo (apLofig);
}


/*  ----------------------------------------------------------------------
 *  Function  :  "computeArea()".
 */

static long  computeArea(apLofig)
  struct lofig *apLofig;
{
  struct loins* pLoins;
  struct phfig* pModel;
          long  area;
          long  AB_width, AB_height;


  area = 0L;

  for (pLoins = apLofig->LOINS; pLoins != NULL; pLoins = pLoins->NEXT) {
    pModel = getphfig (pLoins->FIGNAME, 'P');

    AB_width  = pModel->XAB2 - pModel->XAB1;
    AB_height = pModel->YAB2 - pModel->YAB1;


    if (AB_width <= 0) {
      eprinth (NULL);
      eprintf (
        "Negative or null width (%ld) for abutment box of \"%s\".\n",
        AB_width, pModel->NAME);
      EXIT (1);
    }

    if (AB_height <= 0) {
      eprinth (NULL);
      eprintf (
        "Negative or null height (%ld) for abutment box of \"%s\".\n",
        AB_height, pModel->NAME);
      EXIT (1);
    }

    if (AB_width % MBK_X_GRID) {
      eprinth (NULL);
      eprintf (
        "Unpitched width (%ld) for abutment box of \"%s\".\n",
        AB_width, pModel->NAME);
      EXIT (1);
    }

    if (AB_height % MBK_Y_SLICE) {
      eprinth (NULL);
      eprintf (
        "Unpitched height (%ld) for abutment box of \"%s\".\n",
        AB_height, pModel->NAME);
      EXIT (1);
    }


    AB_width  = AB_width  / MBK_X_GRID;
    AB_height = AB_height / MBK_Y_SLICE;

    area += AB_width * AB_height;
  }


  return (area);
}


/*  ----------------------------------------------------------------------
 *  Function  :  "makeFloorplan()".
 */

extern struct phfig *makeFloorplan(apLofig,
                                   aMargin,
                                   aXSize,
                                   aYSize,
                                   aAspectRatio,
                                   aPower,
                                   aFlags)
  struct lofig *apLofig;
          long  aMargin;
          long  aXSize;
          long  aYSize;
        double  aAspectRatio;
          long  aPower;
          long  aFlags;
{
  struct phfig *pPhfig;
          long  specCount, i;
          long  area;
          long  xSize, ySize;
          long  XAB1, YAB1, XAB2, YAB2;
          char  row_name[1024], row_type[1024];
          char *routingLayers;


  specCount  = (aFlags & F_FLOOR_X_SIZE) ? 1 : 0;
  specCount += (aFlags & F_FLOOR_Y_SIZE) ? 1 : 0;
  specCount += (aFlags & F_FLOOR_ASPECT_RATIO) ? 1 : 0;

  if (specCount != 1) {
    errMBK  ("makeFloorplan");
    eprintf ("\n  One, and only one argument among aXSize, aYSize and");
    eprintf (   " aAspectRatio must\n   be non zero.\n");
    EXIT (1);
  }

  pPhfig = addphfig (apLofig->NAME);

  area = computeArea (apLofig);
  area = (long)((1.0 + (double)aMargin / 100.0) * (double)area);

  /* Shut up GCC. */
  xSize = 0;
  ySize = 0;

  if (aFlags & F_FLOOR_X_SIZE) {
    xSize = aXSize;
    ySize =    area / (xSize - 7 * aPower)
           + ((area % (xSize - 7 * aPower)) ? 1 : 0);
  }

  if (aFlags & F_FLOOR_Y_SIZE) {
    ySize = aYSize;
    xSize = (7 * aPower) + (area / aYSize) + ((area / aYSize) ? 1 : 0);
  }

  if (aFlags & F_FLOOR_ASPECT_RATIO) {
    double  x, r, b, xy;

    xy = (double)(Y_SLICE / X_GRID);

    b = ((double)(7 * aPower)) / xy;
    x = (b + sqrt (pow (b, 2.0) + 4 * xy * (double)(area) * aAspectRatio))
      / (2 * xy * aAspectRatio);

    ySize = (long)floor (x * aAspectRatio);

    /* Compute missing area (as ySize is rounded down).
     * The unit the number of horizontal sites.
     */ 
    r = ((double)(area + 7 * aPower * ySize) - pow ((double)ySize, 2.0) * xy)
      /  (double)(ySize);

    xSize = ((long)ceil ((double)ySize * xy + r));
  }


  XAB1 = 0L;
  YAB1 = 0L;
  XAB2 = xSize * MBK_X_GRID;
  YAB2 = ySize * MBK_Y_SLICE;


  /* Build the floorplan. */

  /* The Abutment-box. */
  defab (pPhfig, XAB1, YAB1, XAB2, YAB2);

  /* The row matrix. */
  strcpy (row_type, "core");
  for (i = 0; i < ySize; i++) {
    sprintf (row_name, "row_%ld", i);

    DEF2MBK_row (pPhfig,
                 row_name,
                 row_type,
                 (i % 2) ? DEF_FS : DEF_N,
                 xSize,
                 1L,
                 DEF_X_GRID,
                 DEF_Y_SLICE,
                 XAB1,
                 YAB1 + i * MBK_Y_SLICE);
  }

  /* The tracks matrix. */
  routingLayers = routingLayers6;

  if (aFlags & F_FLOOR_LAYERS_3) {
    routingLayers = routingLayers3;
  }

  if (aFlags & F_FLOOR_LAYERS_4) {
    routingLayers = routingLayers4;
  }

  /* Horizontal tracks. */
  DEF2MBK_track (pPhfig,
                 "Y",
                 MBK2DEF_length (YAB1 + MBK_X_GRID),
                 ySize * (Y_SLICE / X_GRID) - 1,
                 DEF_X_GRID,
                 routingLayers,
                 XAB1,
                 YAB1 + MBK_X_GRID);

  /* Vertical tracks. */
  DEF2MBK_track (pPhfig,
                 "X",
                 MBK2DEF_length (XAB1 + MBK_X_GRID),
                 xSize - 1,
                 DEF_X_GRID,
                 routingLayers,
                 XAB1 + MBK_X_GRID,
                 YAB1);


  return (pPhfig);
}


/*  ----------------------------------------------------------------------
 *  Function  :  "expandFloorplan()".
 */

extern void  expandFloorplan(apPhfig)
  struct phfig *apPhfig;
{
  struct phseg *pPhseg;
  struct phcon *pPhcon;
          long  XAB1, YAB1, XAB2, YAB2;


  XAB1 = apPhfig->XAB1;
  YAB1 = apPhfig->YAB1;
  XAB2 = apPhfig->XAB2;
  YAB2 = apPhfig->YAB2;


  apPhfig->XAB1 -= FLOOR_XY_EXPAND;
  apPhfig->YAB1 -= FLOOR_XY_EXPAND;
  apPhfig->XAB2 += FLOOR_XY_EXPAND;
  apPhfig->YAB2 += FLOOR_XY_EXPAND;


  /* Move terminals to the new AB. */
  for (pPhcon = apPhfig->PHCON; pPhcon != NULL; pPhcon = pPhcon->NEXT) {
    if (pPhcon->XCON == XAB1) pPhcon->XCON = apPhfig->XAB1;
    if (pPhcon->XCON == XAB2) pPhcon->XCON = apPhfig->XAB2;
    if (pPhcon->YCON == YAB1) pPhcon->YCON = apPhfig->YAB1;
    if (pPhcon->YCON == YAB2) pPhcon->YCON = apPhfig->YAB2;
  }


  /* Shrink segments to fit in the new AB. */
  for (pPhseg = apPhfig->PHSEG; pPhseg != NULL; pPhseg = pPhseg->NEXT) {
    if (pPhseg->X1 == XAB1) pPhseg->X1 = apPhfig->XAB1;
    if (pPhseg->X2 == XAB2) pPhseg->X2 = apPhfig->XAB2;
    if (pPhseg->Y1 == YAB1) pPhseg->Y1 = apPhfig->YAB1;
    if (pPhseg->Y2 == YAB2) pPhseg->Y2 = apPhfig->YAB2;
  }


# if 0
  DEF2MBK_blockage (apPhfig,
                    MBK2DEF_length (apPhfig->XAB1),
                    MBK2DEF_length (apPhfig->YAB1),
                    MBK2DEF_length (FLOOR_XY_EXPAND),
                    MBK2DEF_length (FLOOR_XY_EXPAND)
                    );

  DEF2MBK_blockage (apPhfig,
                    MBK2DEF_length (apPhfig->XAB1),
                    MBK2DEF_length (apPhfig->YAB2 - FLOOR_XY_EXPAND),
                    MBK2DEF_length (FLOOR_XY_EXPAND),
                    MBK2DEF_length (FLOOR_XY_EXPAND)
                    );

  DEF2MBK_blockage (apPhfig,
                    MBK2DEF_length (apPhfig->XAB2 - FLOOR_XY_EXPAND),
                    MBK2DEF_length (apPhfig->YAB1),
                    MBK2DEF_length (FLOOR_XY_EXPAND),
                    MBK2DEF_length (FLOOR_XY_EXPAND)
                    );

  DEF2MBK_blockage (apPhfig,
                    MBK2DEF_length (apPhfig->XAB2 - FLOOR_XY_EXPAND),
                    MBK2DEF_length (apPhfig->YAB2 - FLOOR_XY_EXPAND),
                    MBK2DEF_length (FLOOR_XY_EXPAND),
                    MBK2DEF_length (FLOOR_XY_EXPAND)
                    );
# endif
}


# if 0
/*  ----------------------------------------------------------------------
 *  Function  :  "intervalRel()".
 */

static long  intervalRel(aI1_min, aI1_max, aI2_min, aI2_max)
  long  aI1_min, aI1_max, aI2_min, aI2_max;
{
  long  flag;


  if (aI1_min > aI1_max) {
    errMBK  ("intervalRel");
    eprintf (" I1_min(%ld) > I1_max(%ld) !\n", aI1_min, aI1_max);
    EXIT (1);
  }
  if (aI2_min > aI2_max) {
    errMBK  ("intervalRel");
    eprintf (" I2_min(%ld) > I2_max(%ld) !\n", aI2_min, aI2_max);
    EXIT (1);
  }


  flag = 2;

  if ((aI1_min < aI2_min) || (aI1_min > aI2_max)) flag--;
  if ((aI1_max < aI2_min) || (aI1_max > aI2_max)) flag--;
  if ((aI1_min < aI2_min) && (aI1_max > aI2_max)) flag = 3;


  switch (flag) {
    default:
    case 3: flag = F_I2_IN_I1;   break;
    case 2: flag = F_I1_IN_I2;   break;
    case 1: flag = F_OVERLAP;    break;
    case 0: flag = F_NO_OVERLAP; break;
  }

  return (flag);
}


/*  ----------------------------------------------------------------------
 *  Function  :  "segInArea()".
 */

static long  segInArea(aPhseg, aX1, aY1, aX2, aY2)
  struct phseg *aPhseg;
          long  aX1, aY1, aX2, aY2;
{
  long  flagX, flagY;


  if (aX1 > aX2) {
    errMBK  ("segInArea");
    eprintf ("Bad area X1(%ld) > X2(%ld) !\n", aX1, aX2);
    EXIT (1);
  }
  if (aY1 > aY2) {
    errMBK  ("segInArea");
    eprintf ("Bad area Y1(%ld) > Y2(%ld) !\n", aY1, aY2);
    EXIT (1);
  }


  flagX = intervalRel (aPhseg->X1, aPhseg->X2, aX1, aX2);
  flagY = intervalRel (aPhseg->Y1, aPhseg->Y2, aY1, aY2);


  if ((flagX == F_NO_OVERLAP) || (flagY == F_NO_OVERLAP))
    return (F_SEG_EXCLUS);

  if ((flagX == F_I1_IN_I2) && (flagY == F_I1_IN_I2))
    return (F_SEG_INCLUS);

  if ((flagX == F_I2_IN_I1) && (flagY == F_I2_IN_I1))
    return (F_SEG_HALFOVER);

  return (F_SEG_OVER);
}
# endif


/*  ----------------------------------------------------------------------
 *  Function  :  "shrinkFloorplan()".
 */

extern void  shrinkFloorplan(apPhfig)
  struct phfig *apPhfig;
{
  struct phseg *pPhseg;
  struct phcon *pPhcon;
  struct phref *pPhref;
          long  XAB1, YAB1, XAB2, YAB2;


  XAB1 = apPhfig->XAB1;
  YAB1 = apPhfig->YAB1;
  XAB2 = apPhfig->XAB2;
  YAB2 = apPhfig->YAB2;

  /* Shrink the abutment-box. */
  apPhfig->XAB1 += FLOOR_XY_EXPAND;
  apPhfig->YAB1 += FLOOR_XY_EXPAND;
  apPhfig->XAB2 -= FLOOR_XY_EXPAND;
  apPhfig->YAB2 -= FLOOR_XY_EXPAND;


  /* Move terminals to the new AB. */
  for (pPhcon = apPhfig->PHCON; pPhcon != NULL; pPhcon = pPhcon->NEXT) {
    if (pPhcon->XCON == XAB1) pPhcon->XCON = apPhfig->XAB1;
    if (pPhcon->XCON == XAB2) pPhcon->XCON = apPhfig->XAB2;
    if (pPhcon->YCON == YAB1) pPhcon->YCON = apPhfig->YAB1;
    if (pPhcon->YCON == YAB2) pPhcon->YCON = apPhfig->YAB2;
  }


  /* Shrink segments to fit in the new AB. */
  for (pPhseg = apPhfig->PHSEG; pPhseg != NULL; pPhseg = pPhseg->NEXT) {
    if (pPhseg->X1 == XAB1) pPhseg->X1 = apPhfig->XAB1;
    if (pPhseg->X2 == XAB2) pPhseg->X2 = apPhfig->XAB2;
    if (pPhseg->Y1 == YAB1) pPhseg->Y1 = apPhfig->YAB1;
    if (pPhseg->Y2 == YAB2) pPhseg->Y2 = apPhfig->YAB2;
  }


  /* Move references to the new AB. */
  for (pPhref = apPhfig->PHREF; pPhref != NULL; pPhref = pPhref->NEXT) {
    if (pPhref->XREF == XAB1) pPhref->XREF = apPhfig->XAB1;
    if (pPhref->XREF == XAB2) pPhref->XREF = apPhfig->XAB2;
    if (pPhref->YREF == YAB1) pPhref->YREF = apPhfig->YAB1;
    if (pPhref->YREF == YAB2) pPhref->YREF = apPhfig->YAB2;
  }
}


/*  ----------------------------------------------------------------------
 *  Function  :  "protectPowmid()".
 */

extern void  protectPowmid(apPhfig)
  struct phfig *apPhfig;
{
# if 0
  struct phins *pIns;
  struct phfig *pModel;
          char *powmidName;
          long  width, height, expand;


  expand = FLOOR_XY_EXPAND;

  powmidName = namealloc ("powmid_x0");
  pModel = getphfig ("powmid_x0", 'A');
  width  = pModel->XAB2 - pModel->XAB1;
  height = pModel->YAB2 - pModel->YAB1;

  for (pIns = apPhfig->PHINS; pIns != NULL; pIns = pIns->NEXT) {
    if (pIns->FIGNAME == powmidName) {
      if (pIns->YINS == apPhfig->YAB1 + expand) {
        DEF2MBK_blockage (apPhfig,
                          MBK2DEF_length (pIns->XINS),
                          MBK2DEF_length (apPhfig->YAB1),
                          MBK2DEF_length (width),
                          MBK2DEF_length ((MBK_X_GRID << 1) + expand)
                          );
      }

      if (pIns->YINS + height == apPhfig->YAB2 - expand) {
        DEF2MBK_blockage (apPhfig,
                          MBK2DEF_length (pIns->XINS),
                          MBK2DEF_length (apPhfig->YAB2
                                          - (MBK_X_GRID << 1) - expand),
                          MBK2DEF_length (width),
                          MBK2DEF_length ((MBK_X_GRID << 1) + expand)
                          );
      }
    }
  }
# endif
}
