void COpts::add ( string key_short
                     , string key_long
                     , bool   arg
                     , string val
                     ) throw (except_done)
{
  long  key_index;


  // Coherency checks.
  if (key_short.size() != 1) {
    cerr << herr (" COpts::add() :\n")
         << "  Bad short argument : \"" << key_short << "\",\n"
         << "  Short arguments must be excatly one character long.\n"
         << "\n\n";
    throw except_done();
  }

  if (key_long.size() < 2) {
    cerr << herr (" COpts::add() :\n")
         << "  Bad long argument : \"" << key_long << "\",\n"
         << "  Long arguments must be more than one character long.\n"
         << "\n\n";
    throw except_done();
  }

  if ((*this)[key_short] != NULL) {
    cerr << herr (" COpts::add() :\n")
         << "  Duplicate short argument : \"" << key_short << "\".\n"
         << "\n\n";
    throw except_done();
  }

  if ((*this)[key_long] != NULL) {
    cerr << herr (" COpts::add() :\n")
         << "  Duplicate long argument : \"" << key_long << "\".\n"
         << "\n\n";
    throw except_done();
  }


  // Add to the option list & dictionnary.
  tList.push_back (new COpt (arg, val));
  key_index = tList.size() - 1;

  tDict[key_short] = key_index;
  tDict[key_long ] = key_index;

  // Add to the short option string.
  tShort += key_short;
  if (arg) tShort += ":";
}
Ejemplo n.º 2
0
long  CEnv::layer2z (char layer) throw (except_done)
{
  MLayer::iterator  itLayer;


  if ((itLayer = ALU2Z.find (layer)) == ALU2Z.end ()) {
    cerr << herr ("CEnv::layer2z ():\n");
    cerr << "  Layer id " << (int)layer << " is not supported.\n";
    throw except_done ();
  }
    
  return (itLayer->second);
}
Ejemplo n.º 3
0
char  CEnv::z2calu (int z) throw (except_done)
{
  MLayer::iterator  itLayer, endLayer;


  endLayer = ALU2Z.end ();
  for (itLayer = ALU2Z.begin(); itLayer != endLayer; itLayer++) {
    if (isCALU(itLayer->first) && (itLayer->second == z))
      return (itLayer->first);
  }

  cerr << herr ("CEnv::z2calu ():\n");
  cerr << "  Z index " << z << " is out of bound.\n";

  throw except_done ();
}
void COpts::getopts (int argc, char *argv[]) throw (except_done)
{
  extern        int  opterr;
  extern        int  optopt;
  extern        int  optind;
  extern       char *optarg;
                int  key; 
               long  key_index; 
             string  key_string; 
         const char *short_format;


  opterr = 0;

  short_format = tShort.c_str();

  // Loop over getopt.
  while (true) {
    key = getopt (argc, argv, short_format);

    if (key == -1) break;

    if (key == (int)'?') {
        cerr << herr (" COpts::getopts() :\n")
             << "  Unrecognized short argument : \"-"
             << (char)optopt << "\".\n"
             << "\n\n";
        throw except_done ();
    }

    // Update the option status.
    key_string = (char)key;
    key_index = (*this)(key_string);
    tList[key_index]->parsed = true;

    // Get any optionnal argument.
    if (tList[key_index]->has_arg) {
      tList[key_index]->value = optarg;
    }
  }


  // Store non options arguments into "tArg".
  for (key = optind; key < argc; key++) {
    tVals.push_back (argv[key]);
  }
}
long  COpts::operator() (string key) throw (except_done)
{
            long  key_index;
  MOpt::iterator  iter;


  iter = tDict.find (key);

  if (iter == tDict.end ()) {
    cerr << herr (" COpts::operator() :\n")
         << "  Option not found : \"" << key << "\".\n"
         << "\n\n";
    throw except_done ();
  }

  return ((*iter).second);
}
Ejemplo n.º 6
0
char  CEnv::z2via (int z) throw (except_done)
{
  char viaType;


  switch (z) {
    case 1: viaType = CONT_VIA;  break;
    case 2: viaType = CONT_VIA2; break;
    case 3: viaType = CONT_VIA3; break;
    case 4: viaType = CONT_VIA4; break;
    case 5: viaType = CONT_VIA5; break;
    case 6: viaType = CONT_VIA6; break;
    default:
      cerr << herr ("CEnv::z2via ():\n");
      cerr << "  Z index " << z << " is out of bound.\n";
      throw except_done ();
  }

  return (viaType);
}
Ejemplo n.º 7
0
CFig::CFig (string &nameLofig, string &namePhfig) throw (except_done):
  lofig (nameLofig), phfig (namePhfig)
{
  MLoins::iterator  itLoins, endLoins;
  MPhins::iterator  itPhins, endPhins;
  long              errors;


  // Flatten both views & build dual representation.
  phfig.rflatten ();
  lofig.rflatten ();
  lofig.chain ();

  cmess2 << "  o  Binding logical & physical views...\n";

  errors   = 0;
  endLoins = lofig.instances.end ();
  endPhins = phfig.instances.end ();

  // Match loins with phins.
  for (itLoins = lofig.instances.begin(); itLoins != endLoins; itLoins++) {
    // Find the matched phins.
    itPhins = phfig.instances.find (itLoins->first);

    if (itPhins == endPhins) {
      errors += 1;

      cerr << herr ("");
      cerr << " logical instance \"" << itLoins->second->INSNAME << "\"";
      cerr << " of model \"" << itLoins->second->FIGNAME << "\"";
      cerr << " doesn't appear in physical view.\n";
      continue;
    }

    instances[itLoins->first] = new CIns ( itLoins->second
                                         , itPhins->second
                                         , NULL
                                         , phfig.fig
                                         );
  }

  // If the match is not complete, do a reverse one to find
  // unmatched phins (mostly feedthrough cells).
  if (   (errors > 0)
      || ( lofig.instances.size() != phfig.instances.size() ) ) {
    for (itPhins = phfig.instances.begin(); itPhins != endPhins; itPhins++) {
      // Add feedthrough cells to the orphan list.
      if (incatalogfeed (itPhins->second->FIGNAME) != 0) {
        orphans[itPhins->first] = new CIns ( NULL
                                           , itPhins->second
                                           , NULL
                                           , this->phfig.fig
                                           );

        continue;
      }

      // Find the matched loins.
      itLoins = lofig.instances.find (itPhins->first);

      if (itLoins == endLoins) {
        errors += 1;

        cerr << herr ("");
        cerr << " physical instance \"" << itPhins->second->INSNAME << "\"";
        cerr << " of model \"" << itPhins->second->FIGNAME << "\"";
        cerr << " doesn't appear in logical view.";
        continue;
      }
    }
  }

  // The nelist and lofig doesn't match.
  if (errors > 0) throw except_done ();
}
Ejemplo n.º 8
0
  void  CRBox::mbksave (string &name) throw (except_done)
{
                int  x, y, z, mX, mY, mZ, pitch, spaceVIA;
               bool  inseg;
              CRect  rect;
  CDRGrid::iterator  coord;
              CNode *node;
               CNet *pNextNet, *pNet, *pNetTop, *pNetBot;
    MBK::phseg_list  seg;
    MBK::phvia_list  via;
    MNet::iterator   itNet, endNet;


  if (!loaded) {
    cerr << hwarn ("")
         << "\n  The MBK figure has not been loaded into the grid yet, nothing"
         << "\n  to save at this point.\n";
      
    return;
  }

  if (insave) throw except_done ();

  insave = true;

  cmess2 << "\n";
  cmess1 << "  o  Dumping routing grid.\n";

  mX = drgrid->X;
  mY = drgrid->Y;
  mZ = drgrid->Z;
  coord = drgrid->origin;


  // A reference to show the grid real origin.
  MBK::phref_list  ref;
  ref.FIGNAME = MBK::namealloc("ref_ref");
  ref.NAME    = MBK::namealloc("nero.grid.origin");
  ref.XREF    = xoffsetgrid;
  ref.YREF    = yoffsetgrid;
  ref.USER    = NULL;
  ref.NEXT    = NULL;
  fig->addphref ( ref );

  ref.NAME    = MBK::namealloc("nero.grid.limit");
  ref.XREF   += D::X_GRID * (mX-1);
  ref.YREF   += D::Y_GRID * (mY-1);
  fig->addphref ( ref );
  

  // Horizontal planes loop in both directions.
  for (z = 1; z < mZ; z++) {

    // Loop for horizontal segments.
    for (y = 0; y < mY; y++) {

      inseg = false;
      pNet  = NULL;

      for (x = 0; x < mX; x++) {
        node     = & ( coord.set(x,y,z).node() );
        pNextNet = node->data.owner;

        if (inseg && (pNextNet != pNet)) {
          // We are changing of segment owner.
          // Dump the current one.
          if (seg.X1 < seg.X2) {
            // This is not a "dot" segment (i.e a VIA).
            fig->addphseg (seg,pNet->external,ischip);
          } else if (z % 2) {
            char layer = seg.LAYER;
            seg.LAYER = MBK::layer2TALU (seg.LAYER);
            fig->addphseg (seg,false,ischip);
            seg.LAYER = layer;
          }

          // Force segment restarting.
          inseg = false;
        }

        pNet = pNextNet;

        if (pNet) {
          if (!inseg) {
            // We encounter the left edge of a segment.
            inseg = true;

            seg.X1    = xoffsetgrid + x * D::X_GRID;
            seg.Y1    = yoffsetgrid + y * D::Y_GRID;
            seg.Y2    = yoffsetgrid + y * D::Y_GRID;
            seg.NAME  = MBK::namealloc(pNet->name.c_str ());
            seg.WIDTH = MBK::env.z2width (z);

            if (pNet->external && !ischip) seg.LAYER = MBK::env.z2calu (z);
            else                           seg.LAYER = MBK::env.z2alu (z);
          }

          // Update the right edge.
          seg.X2 = xoffsetgrid + x * D::X_GRID;
        } else {
          if (inseg) {
            // Dump the current one.
            if (seg.X1 < seg.X2) {
              // This is not a "dot" segment (i.e a VIA).
              fig->addphseg (seg,pNet->external,ischip);
            } else if (z % 2) {
              char layer = seg.LAYER;
              seg.LAYER = MBK::layer2TALU (seg.LAYER);
              fig->addphseg (seg,false,ischip);
              seg.LAYER = layer;
            }
          }

          // We encounter the right edge of a segment.
          inseg = false;
        }
      } // End of "x" loop.

      if (inseg) {
        // This segment touch the AB.
        if (seg.X1 < seg.X2) {
          // This is not a "dot" segment (i.e a VIA).
          fig->addphseg (seg,pNet->external,ischip);
        } else if (z % 2 ) {
          char layer = seg.LAYER;
          seg.LAYER = MBK::layer2TALU (seg.LAYER);
          fig->addphseg (seg,false,ischip);
          seg.LAYER = layer;
        }
      }

    } // End of "y" loop (horizontal segments).

    // Loop for vertical segments.
    for (x = 0; x < mX; x++) {

      inseg = false;
      pNet  = NULL;

      for (y = 0; y < mY; y++) {
        node     = & ( coord.set(x,y,z).node() );
        pNextNet = node->data.owner;

        if (inseg && (pNextNet != pNet)) {
          // We are changing of segment owner.
          // Dump the current one.
          if (seg.Y1 < seg.Y2) {
            // This is not a "dot" segment (i.e a VIA).
            fig->addphseg (seg,pNet->external,ischip);
          } else if (! (z % 2)) {
            char layer = seg.LAYER;
            seg.LAYER = MBK::layer2TALU (seg.LAYER);
            fig->addphseg (seg,false,ischip);
            seg.LAYER = layer;
          }

          // Force segment restarting.
          inseg = false;
        }

        pNet = pNextNet;

        if (pNet) {
          if (!inseg) {
            // We encounter the left edge of a segment.
            inseg = true;

            seg.X1    = xoffsetgrid + x * D::X_GRID;
            seg.X2    = xoffsetgrid + x * D::X_GRID;
            seg.Y1    = yoffsetgrid + y * D::Y_GRID;
            seg.NAME  = MBK::namealloc(pNet->name.c_str ());
            seg.WIDTH = MBK::env.z2width (z);

            if (pNet->external && !ischip) seg.LAYER = MBK::env.z2calu (z);
            else                           seg.LAYER = MBK::env.z2alu (z);

          }

          // Update the right edge.
          seg.Y2 = yoffsetgrid + y * D::Y_GRID;
        } else {
          if (inseg) {
            // Dump the current one.
            if (seg.Y1 < seg.Y2) {
              // This is not a "dot" segment (i.e a VIA).
              fig->addphseg (seg,pNet->external,ischip);
            } else if (! (z % 2)) {
              char layer = seg.LAYER;
              seg.LAYER = MBK::layer2TALU (seg.LAYER);
              fig->addphseg (seg,false,ischip);
              seg.LAYER = layer;
            }
          }

          // We encounter the right edge of a segment.
          inseg = false;
        }
      } // End of "y" loop.

      if (inseg) {
        // This segment touch the AB.
        if (seg.Y1 < seg.Y2) {
          // This is not a "dot" segment (i.e a VIA).
          fig->addphseg (seg,pNet->external,ischip);
        } else if (! (z % 2)) {
          char layer = seg.LAYER;
          seg.LAYER = MBK::layer2TALU (seg.LAYER);
          fig->addphseg (seg,false,ischip);
          seg.LAYER = layer;
        }
      }

    } // End of "x" loop (vertical segments).

  } // End of "z" loop (planes).


  via.DX = 0;
  via.DY = 0;

  // Plane loop for VIAs.
  for (z = 1; z < mZ; z++) {
    // Track loop for VIAs.
    if (z >= drgrid->zupper) pitch = 1;
    else                     pitch = 1;

    if (z % 2) {
      // z=1 (ALU2) : horizontal tracks.
      for (y = 1; y < mY; y += pitch) {
        for (x = 0, spaceVIA = 2; x < mX; x++, spaceVIA++) {
          // Bottom node.
          pNetBot = NULL;
          node = & ( coord.set(x,y,z-1).node() );
          if ( !coord.isnodehole() && coord.inside() )
            pNetBot = node->data.owner;

          // Top node.
          pNetTop = NULL;
          node = & ( coord.set(x,y,z).node() );
          if ( !coord.isnodehole() && coord.inside() )
            pNetTop = node->data.owner;

          // Are the top & bottom nodes belonging to the same net ?
          if ( (pNetBot != NULL) && (pNetBot == pNetTop) ) {
            if (spaceVIA < pitch) continue;

            via.TYPE = MBK::env.z2via (z);
            via.XVIA = xoffsetgrid + x * D::X_GRID;
            via.YVIA = yoffsetgrid + y * D::Y_GRID;
            via.NAME = MBK::namealloc(pNetTop->name.c_str ());

            fig->addphvia (via);

            spaceVIA = 0;
          }
        }
      }
    } else {
      // z=2 (ALU3) : vertical tracks.
      for (x = 1; x < mX; x += pitch) {
        for (y = 0, spaceVIA = 2; y < mY; y++, spaceVIA++) {
          // Bottom node.
          pNetBot = NULL;
          node = & ( coord.set(x,y,z-1).node() );
          if ( !coord.isnodehole() && coord.inside() )
            pNetBot = node->data.owner;

          // Top node.
          pNetTop = NULL;
          node = & ( coord.set(x,y,z).node() );
          if ( !coord.isnodehole() && coord.inside() )
            pNetTop = node->data.owner;

          // Are the top & bottom nodes belonging to the same net ?
          if ( (pNetBot != NULL) && (pNetBot == pNetTop) ) {
            if (spaceVIA < pitch) continue;

            via.TYPE = MBK::env.z2via (z);
            via.XVIA = xoffsetgrid + x * D::X_GRID;
            via.YVIA = yoffsetgrid + y * D::Y_GRID;
            via.NAME = MBK::namealloc(pNetTop->name.c_str ());

            fig->addphvia (via);

            spaceVIA = 0;
          }
        }
      }
    }
  }


  // Special case of nets with only one terminal.
  endNet = nets.end ();
  for (itNet = nets.begin(); itNet != endNet; itNet++) {
    if (!itNet->second->external) continue;
    if (itNet->second->size != 1) continue;
    if (itNet->second->terms[0]->rects.size() < 1) continue;

    rect = itNet->second->terms[0]->rects.front ();

    seg.X1    = xoffsetgrid + rect.x1 * D::X_GRID;
    seg.X2    = xoffsetgrid + rect.x2 * D::X_GRID;
    seg.Y1    = yoffsetgrid + rect.y1 * D::Y_GRID;
    seg.Y2    = yoffsetgrid + rect.y2 * D::Y_GRID;
    seg.NAME  = MBK::namealloc(itNet->second->name.c_str ());
    seg.WIDTH = MBK::env.z2width (0);
    seg.LAYER = MBK::env.z2calu (0);

    fig->addphseg (seg,itNet->second->external,ischip);
  }


  // Add powers lines.
  if ( !ischip ) powers[MBK::CALU1]->dump (fig);
  

  cmess1 << "  o  Saving MBK figure \"" << name << "\".\n";
  fig->phfig.saveas (name);
}
Ejemplo n.º 9
0
void  CRBox::mbkload (MBK::CFig *mbkfig
                     , int z
                     , int zup
                     , int rtype
                     , bool halfpitch
                     , bool xhalfpitch
                     , bool yhalfpitch
                     , bool rotate
                     , set<string>* subNetList )
{
    MBK::MIns::iterator   itIns, endInstances, endOrphans;
  MBK::MLosig::iterator   endSig;
  MBK::MLosig::iterator   sig;
                   long   mX, mY, mZ, x, y, zz, xadjust, yadjust, yoffsetslice;
                   long   XRW1, YRW1, XRW2, YRW2;
                   bool   use_global;
                   long   northPad, southPad, eastPad, westPad;
                   long   xoffsettrack, yoffsettrack;
        MBK::chain_list  *pChain;
        MBK::locon_list  *pLocon;
        MBK::phcon_list  *pPhcon;
        MBK::losig_list  *pSig;
        MBK::phseg_list  *pSeg, flatSeg;
        MBK::phvia_list  *pVIA;
        MBK::phfig_list  *pModel;
            MBK::CXRect  *rect;
              MBK::CIns  *pIns;
                   CNet  *pNet;
                 string   sig_name, term_name, ins_name;
      CDRGrid::iterator   coord;
                  CNode  *node;


  cmess1 << "\n";
  cmess1 << "  o  Loading design into grid...\n";

  ischip       = false;
  fig          = mbkfig;
  endInstances = fig->instances.end ();
  endOrphans   = fig->orphans.end   ();
  endSig       = fig->lofig.signals.end ();

  northPad     = 0;
  southPad     = 0;
  westPad      = 0;
  eastPad      = 0;
  xoffsettrack = 0;
  yoffsettrack = 0;

  // Half pitch offset.
  if ( halfpitch ) {
    xoffsettrack = D::X_GRID / 2;
    yoffsettrack = D::Y_GRID / 2;
  }
  else if ( xhalfpitch ) {
    xoffsettrack = D::X_GRID / 2;
  }
  else if ( yhalfpitch ) {
    yoffsettrack = D::Y_GRID / 2;
  }

  // Search for pads.
  for (itIns = fig->instances.begin(); itIns != endInstances; itIns++) {
    pModel = itIns->second->getmodel ();

    if ( MBK::IsPxLib(pModel) ) {
      switch ( itIns->second->phins->TRANSF ) {
        case NOSYM:
          ischip = true;
          if ( northPad == 0 ) {
            cmess2 << "     o  North pad found.\n";
            northPad = pModel->YAB2 - pModel->YAB1 - MBK::SCALE(15);
          }
          break;
        case SYM_Y:
          ischip = true;
          if ( southPad == 0 ) {
            cmess2 << "     o  South pad found.\n";
            southPad = pModel->YAB2 - pModel->YAB1 - MBK::SCALE(15);
          }
          break;
        case ROT_P:
          ischip = true;
          if ( eastPad == 0 ) {
            cmess2 << "     o  East pad found.\n";
            eastPad = pModel->YAB2 - pModel->YAB1 - MBK::SCALE(15);
          }
          break;
        case SY_RP:
          ischip = true;
          if ( westPad == 0 ) {
            cmess2 << "     o  West pad found.\n";
            westPad = pModel->YAB2 - pModel->YAB1 - MBK::SCALE(15);
          }
          break;
        default:
          cerr << hwarn ("")
               << "  Pad " << itIns->second->phins->INSNAME
               << " have an invalid orientation.\n";
          break;
      }
    }
  }


  //southPad = northPad = westPad = eastPad = MBK::SCALE(50);
  //westPad = MBK::SCALE(100);


  // Default Routing Widow size : the AB.
  XRW1 = fig->XAB1 () + westPad;
  YRW1 = fig->YAB1 () + southPad;
  XRW2 = fig->XAB2 () - eastPad;
  YRW2 = fig->YAB2 () - northPad;

  // Find the a seed cell (one either from sxlib or dp_sxlib to
  // track adjust the grid).
  for (itIns = fig->instances.begin(); ; itIns++) {
    if (itIns == endInstances) {
      xadjust      = xoffsettrack;
      yadjust      = yoffsettrack;
      yoffsetslice = 0;
      cout << hwarn ("")
           << "  Unable to found a seed cell (i.e. belonging to either\n"
           << "  sxlib or dp_sxlib) grid could be misplaced.\n";
      break;
    }

    pModel = itIns->second->getmodel ();

    if ( !MBK::IsPxLib(pModel) ) {
      cmess2 << "     o  Using seed cell \"" << itIns->first
             << "\" (model \"" << pModel->NAME << "\").\n";
      xadjust      = abs((itIns->second->phins->XINS - XRW1) % D::X_GRID ) + xoffsettrack;
      yadjust      = abs((itIns->second->phins->YINS - YRW1) % D::Y_GRID ) + yoffsettrack;
      yoffsetslice = abs((itIns->second->phins->YINS - YRW1) % D::Y_SLICE) + YRW1;

      break;
    }
  }
  
  xoffsetgrid = XRW1 + xadjust;
  yoffsetgrid = YRW1 + yadjust;

  cmess2 << "     o  Grid offset : ("
         << MBK::UNSCALE(xoffsetgrid) << ","
         << MBK::UNSCALE(yoffsetgrid) << ")"
         << " [adjust ("
         << MBK::UNSCALE(xadjust) << ","
         << MBK::UNSCALE(yadjust) << ")]\n";

  // Compute the routing grid size.
  mX = (XRW2 - XRW1) / D::X_GRID + ((xadjust==0)?1:0);
  mY = (YRW2 - YRW1) / D::Y_GRID + ((yadjust==0)?1:0);
  mZ = z;


  // Is the design a complete chip.
  if (ischip)
    cmess2 << "     o  Design have pads, treated as a complete chip.\n";


  // Selecting the whether to use global routing.
  use_global = (mX + mY) > (2 * D::GLOBAL_HP);
  if (rtype == D::ROUTING_CHOOSE) {
    if (use_global) {
      cmess2 << "     o  Big design, global routing enabled.\n";
      rglobal = true;

      if (z < 5) {
        cmess2 << "        - Forcing 4 routing layers.\n";
        mZ = 5;
      }
    } else {
      cmess2 << "     o  Small design, global routing disabled.\n";
      rglobal = false;
    }
  } else {
    if (rtype == D::ROUTING_GLOBAL) {
      rglobal = true;
      if (!use_global) {
        cout << hwarn ("")
             << "  You have enabled global routing on a small design,\n"
             << "  this will waste upper routing layers.\n";
      }
    }
    if (rtype == D::ROUTING_LOCAL ) {
      rglobal = false;
      if (use_global) {
        cout << hwarn ("")
             << "  You have disabled global routing on a big design,\n"
             << "  this will slow down the routing.\n";
      }
    }
  }


  cmess2 << "     o  Allocating grid size ["
         << mX << "," << mY << "," << mZ << "].\n";

  float  mXf      = mX;
  float  mYf      = mY;
  float  mZf      = mZ;
  float  overflow = INT_MAX;

  if ( mXf * mYf * mZf >= overflow ) {
    cerr << herr("")
         << "  Internal routing grid capacity exceeded :\n"
         << "  More than " << INT_MAX << "nodes (INT_MAX).\n";
    throw except_done();
  }

  // Allocating the routing grid.
  drgrid = new CDRGrid (xoffsetgrid, yoffsetgrid, mX, mY, mZ, zup);


  rect = new MBK::CXRect (drgrid);


  cmess2 << "     o  Loading external terminals.\n";

  // Browse layout for terminals.
  for (pPhcon = fig->phfig.fig->PHCON; pPhcon != NULL; pPhcon = pPhcon->NEXT) {
    if (fig->lofig.signals.find(pPhcon->NAME) == endSig) {
      cerr << hwarn ("")
           << "  The terminal \"" << pPhcon->NAME << "\" at ("
           << MBK::UNSCALE (pPhcon->XCON) << ","
           << MBK::UNSCALE (pPhcon->YCON) << ") layer "
           << MBK::layer2a (pPhcon->LAYER) << "\n"
           << "  do not not belong to any logical signal : ignored.\n";

      continue;
    }

    pNet = getnet (pPhcon->NAME);

    term_name  = "external.";
    term_name += pPhcon->NAME;

    flatSeg.X1    = pPhcon->XCON;
    flatSeg.Y1    = pPhcon->YCON;
    flatSeg.X2    = pPhcon->XCON;
    flatSeg.Y2    = pPhcon->YCON;
    flatSeg.WIDTH = MBK::env.layer2width (pPhcon->LAYER);
    flatSeg.LAYER = pPhcon->LAYER;
    flatSeg.NAME  = pPhcon->NAME;

    rect->setSeg  (flatSeg);

    if ( rect->isInGrid() ) {
      pNet->newaccess ( term_name
                      , rect->grid
                      , MBK::env.layer2z (pPhcon->LAYER)
                      );
    } else {
      cerr << hwarn ("")
           << "  The terminal \"" << pPhcon->NAME << "\" at ("
           << MBK::UNSCALE (pPhcon->XCON) << ","
           << MBK::UNSCALE (pPhcon->YCON) << ") layer "
           << MBK::layer2a (pPhcon->LAYER) << "\n"
           << "  is outside the routing grid : ignored.\n";
    }

  }


  cmess2 << "     o  Finding obstacles.\n";


  // Browse father for obstacles (powers are obstacles) and already
  // routed or partially routed signals.
  for (pSeg = fig->phfig.fig->PHSEG; pSeg != NULL; pSeg = pSeg->NEXT) {
    // There must not be obstacle in the father!
    if (MBK::isobs (pSeg->LAYER)) {
      cerr << hwarn ("")
           << "  An obstacle has been found at design top level, ignored.\n";

      continue;
    }

    // Power grid.
    if (MBK::ISVDD (pSeg->NAME) || MBK::ISVSS (pSeg->NAME)) {
      if (pSeg->LAYER != MBK::CALU1) {
        rect->setSeg (*pSeg);
        
        //cerr << "+ Top power obstacle\n" << rect;

        if ( rect->isInGrid() )
          drgrid->nodes->obstacle (rect->grid, MBK::env.layer2z (pSeg->LAYER));
      }

      continue;
    }

    // Unnamed signals : ignored.
    if (pSeg->NAME == NULL) {
      cerr << hwarn ("")
           << "  An unnamed segment has been found at design top level, ignored.\n";

      continue;
    }

    // Partially routed signals.
    sig = fig->lofig.signals.find(pSeg->NAME);
    if ( sig == endSig) {
      cerr << hwarn ("")
           << "  The segment \"" << pSeg->NAME << "\" at ("
           << MBK::UNSCALE (pSeg->X1) << ","
           << MBK::UNSCALE (pSeg->Y1) << ") ("
           << MBK::UNSCALE (pSeg->X2) << ","
           << MBK::UNSCALE (pSeg->Y2) << ") layer "
           << MBK::layer2a (pSeg->LAYER) << "\n"
           << "  do not not belong to any logical signal : ignored.";

      continue;
    }

    pNet = getnet (getsigname(sig->second));
    if ( !pNet->fixed ) {
      cmess2 << "     o  Signal " << pNet->name << " is assumed to be routed.\n";
      pNet->fixed = true;
    }

    rect->setSeg  (*pSeg);

    if ( rect->isInGrid() ) {
      //pNet->newaccess ( pSeg->NAME
      //                , rect->grid
      //                , MBK::env.layer2z (pSeg->LAYER)
      //                );
      //cerr << "+ Net obstacle\n" << rect;
      drgrid->nodes->obstacle (rect->grid, MBK::env.layer2z (pSeg->LAYER));
    } else {
      cerr << hwarn ("")
           << "  The segment \"" << pSeg->NAME << "\" at ("
           << MBK::UNSCALE (pSeg->X1) << ","
           << MBK::UNSCALE (pSeg->Y1) << ") ("
           << MBK::UNSCALE (pSeg->X2) << ","
           << MBK::UNSCALE (pSeg->Y2) << ") layer "
           << MBK::layer2a (pSeg->LAYER) << "\n"
           << "  is outside the routing grid : ignored.";
    }
  }


  // Browse for obstacle VIAs.
  for (pVIA = fig->phfig.fig->PHVIA; pVIA != NULL; pVIA = pVIA->NEXT) {
    // Only power VIAs must be obstacles.
    if ( (! MBK::ISVDD (pVIA->NAME)) && (! MBK::ISVSS (pVIA->NAME))) {
      pNet = getnet (pVIA->NAME);
      if ( pNet && !pNet->fixed ) continue;
    }

    for (x = 0; x < 2; x++) {
      switch (x) {
        case 0: flatSeg.LAYER = MBK::topVIALayer    (pVIA->TYPE); break;
        case 1: flatSeg.LAYER = MBK::bottomVIALayer (pVIA->TYPE); break;
      }

      if (flatSeg.LAYER == MBK::CALU1) continue;

      long  xVIAshrink = 0;
      if (pVIA->DX) { xVIAshrink = (pVIA->DX - MBK::SCALE(3)) / 2; }
      flatSeg.X1    = pVIA->XVIA - xVIAshrink;
      flatSeg.X2    = pVIA->XVIA + xVIAshrink;
      flatSeg.Y1    = pVIA->YVIA;
      flatSeg.Y2    = pVIA->YVIA;
      flatSeg.WIDTH = pVIA->DY;

      rect->setSeg (flatSeg);

      //cerr << "+ Top VIA obstacle ("
      //     << MBK::UNSCALE(pVIA->XVIA) << ","
      //     << MBK::UNSCALE(pVIA->YVIA) << ") "
      //     << MBK::layer2a(flatSeg.LAYER) << endl;
      //cerr << rect;

      if ( rect->isInGrid() )
        drgrid->nodes->obstacle (rect->grid, MBK::env.layer2z (flatSeg.LAYER));
    }
  }


  // Browse instances & orphans for obstacles.
  for (itIns = fig->instances.begin(); ; itIns++) {
    if (itIns == endInstances) itIns = fig->orphans.begin ();
    if (itIns == endOrphans  ) break;

    pModel = itIns->second->getmodel ();

    cdebug << "+          - \"" << itIns->first
           << "\" (model \"" << pModel->NAME << "\").\n";


    // Find the obstacles in the current instance :
    // 1. - TALUx segments.
    // 2. - Power Terminals (vdd & vss), in CALUx layers & not CALU1.
    for (pSeg = pModel->PHSEG; pSeg != NULL; pSeg = pSeg->NEXT) {
      if (   MBK::isobs (pSeg->LAYER)
          || ((   MBK::ISVDD (pSeg->NAME)
               || MBK::ISVSS (pSeg->NAME)) && MBK::isCALU (pSeg->LAYER)
                                           && (pSeg->LAYER != MBK::CALU1))) {
        itIns->second->flatseg (flatSeg, *pSeg);
        rect->setSeg (flatSeg);

        //cerr << "+ Instance obstacle (" << flatSeg.X1 << "," << flatSeg.Y1 << ")"
        //     << MBK::layer2a(flatSeg.LAYER) << endl;

        if ( rect->isInGrid() )
          drgrid->nodes->obstacle (rect->grid, MBK::env.layer2z (pSeg->LAYER));

        if ( !MBK::ISVDD (pSeg->NAME) && !MBK::ISVSS (pSeg->NAME) )
          fig->addphseg ( flatSeg, true, ischip );
      }
    }
  }


  cmess2 << "     o  Loading nets into grid.\n";

  // Process the signals.
  for (pSig = fig->LOSIG (); pSig != NULL; pSig = pSig->NEXT) {
    sig_name = MBK::getsigname (pSig);

    cdebug << "+          - Signal \"" << sig_name << "\".\n";

    // Do not process power nets.
    // Temporary disabled.
    //if (   (MBK::ISVDD ((char*)sig_name.c_str ()) != 0)
    //    || (MBK::ISVSS ((char*)sig_name.c_str ()) != 0)) continue;

    // In the case of external terminals, override the signal name by
    // the terminal name.
    pChain = (MBK::chain_list*)(MBK::getptype (pSig->USER, LOFIGCHAIN)->DATA);
    for (; pChain != NULL; pChain = pChain->NEXT) {
      pLocon = (MBK::locon_list *)(pChain->DATA);

      if (pLocon->TYPE == EXTERNAL) {
        sig_name = pLocon->NAME;
        break;;
      }
    }

    pNet = getnet (sig_name);

    // Process each terminal of the signal.
    pChain = (MBK::chain_list*)(MBK::getptype (pSig->USER, LOFIGCHAIN)->DATA);

    for (; pChain != NULL; pChain = pChain->NEXT) {
      pLocon = (MBK::locon_list *)(pChain->DATA);

      if (pLocon->TYPE == EXTERNAL) {
        pNet->external = true;

        continue;
      }

      ins_name  = ((MBK::loins_list*)(pLocon->ROOT))->INSNAME;
      pIns      = fig->instances[ins_name];

      term_name = ins_name + "." + pLocon->NAME;
      cdebug << "+             I.T : " << term_name << " " << pIns->model->NAME << ".\n";

      // Find physical segments / CA of the terminal.
      for (pSeg = pIns->model->PHSEG; pSeg != NULL; pSeg = pSeg->NEXT) {
        if (!MBK::isCALU (pSeg->LAYER)) continue;
        if (pLocon->NAME != pSeg->NAME) continue;

        pIns->flatseg (flatSeg, *pSeg);
        rect->setSeg  (flatSeg);

        if ( MBK::IsPxLib(pIns->model) &&
             ( (pLocon->NAME == MBK::namealloc("pad" )) ||
               (pLocon->NAME == MBK::namealloc("vddi")) || 
               (pLocon->NAME == MBK::namealloc("vssi")) || 
               (pLocon->NAME == MBK::namealloc("vdde")) || 
               (pLocon->NAME == MBK::namealloc("vsse")) ) ) {
          flatSeg.NAME = (char*)sig_name.c_str();
          fig->addphseg (flatSeg,true,false);
          continue;
        }

        if (   (MBK::ISVDD ((char*)sig_name.c_str ()) != 0)
            || (MBK::ISVSS ((char*)sig_name.c_str ()) != 0)) continue;

        if (rect->isInGrid()) {
          if ( pNet->fixed ) {
            drgrid->nodes->obstacle (rect->grid, MBK::env.layer2z (pSeg->LAYER));
          } else {
            pNet->newaccess ( term_name
                            , rect->grid
                            , MBK::env.layer2z (pSeg->LAYER)
                            );
          }
        } else {
          //if ( MBK::IsPxLib(pModel) ) {
          //  flatSeg.NAME = (char*)sig_name.c_str();
          //  fig->addphseg (flatSeg,true,false);
          //} else {
            cerr << hwarn ("")
                 << "  The connector segment \"" << pSeg->NAME << "\" at ("
                 << MBK::UNSCALE (pSeg->X1) << ","
                 << MBK::UNSCALE (pSeg->Y1) << ") ("
                 << MBK::UNSCALE (pSeg->X2) << ","
                 << MBK::UNSCALE (pSeg->Y2) << ") layer "
                 << MBK::layer2a (pSeg->LAYER) << "\n"
                 << "  is outside of the grid : ignored.";
          }
        //}
      }
    } // End of "pChain" (terminal) loop.

    // Reorder terminals (nearest).
    pNet->order     ();
    pNet->lockalone (rglobal);
    
    cdebug << "+            " << pNet->bb << ".\n";
  } // End of "pSig" (signal) loop.

  // Restrict routed nets to the subNetList.
  if ( subNetList ) {
    for ( MNet::iterator it=nets.begin() ; it != nets.end() ; it++ ) {
      if ( subNetList->find(it->first) != subNetList->end() ) {
        cmess2 << "     o  Restricting nets to route.\n";
        cmess2 << "        - \"" << it->first << "\".\n";
      } else
        it->second->fixed = true;
    }
  }


  // Allocate the net scheduler.
  cmess2 << "     o  Allocating the net scheduler.\n";
  netsched  = new CASimple (&nets, drgrid);


  // Rebuild the power grid from the instances.
  if ( !ischip ) {
    cmess2 << "     o  Reading power grid.\n";
    powers[MBK::CALU1] = new MBK::CPowers ( fig
                                          , xadjust - xoffsettrack
                                          , yoffsetslice
                                          , C_HORIZONTAL
                                          , MBK::ALU1
                                          , D::WIDTH_VDD
                                          );
  }


  // Forbid the use of the edges of the routing box (only allow
  // peripheral terminals).
  coord = drgrid->origin;

  // Left & Right vertical edges.
  if ( xadjust == 0 ) {
    for (x = 0; x < mX; x += mX - 1) {
      for (y = 0; y < mY; y++) {
        for (zz = 1; zz < mZ; zz++) {
          node = &( coord.set(x,y,zz).node() );
          
          if ( !node->terminal() ) node->data.obstacle = true;
        }
      }
    }
  }

  // Bottom & top horizontal edges.
  if ( yadjust == 0 ) {
    for (y = 0; y < mY; y += mY - 1) {
      for (x = 0; x < mX; x++) {
        for (zz = 1; zz < mZ; zz++) {
          node = &( coord.set(x,y,zz).node() );
          
          if ( !node->terminal() ) node->data.obstacle = true;
        }
      }
    }
  }

  // On routing level above zupper (ALU4), use only half of the tracks.
  for (zz = zup; zz < mZ; zz++) {
    switch ((zz+rotate) % 2) {
      case 0:
        // Vertical tracks.
        for (x = 2; x < mX; x += 2) {
          for (y = 1; y < mY - 1; y++) {
            node = &( coord.set(x,y,zz).node() );

            if ( !node->terminal() ) node->data.obstacle = true;
          }
        }
        break;
      case 1:
        // Horizontal tracks.
        for (y = 2; y < mY; y += 2) {
          for (x = 1; x < mX; x++) {
            node = &( coord.set(x,y,zz).node() );
            if ( !node->terminal() ) node->data.obstacle = true;
          }
        }
        break;
    }
  }


  // This flag ensure that a figure has been successfully loaded.
  loaded = true;


  delete rect;
}
Ejemplo n.º 10
0
CPowers::CPowers ( CFig *fig
                   , long  xoff
                   , long  yoff
                   , char  atype
                   , int   alayer
                   , long  awidth
                 ) throw (except_done)
    : xoffset(xoff)
    , yoffset(yoff)
{
    LPower::iterator  itLine, beginLine, endLine;
    phins_list       *ins;
    phfig_list       *model;
    phseg_list       *seg, flatSeg;
    string            mess1,  mess2;
    char              ORIENT1, ORIENT2;
    char              segType;
    long              lbound, rbound, key;


    type  = atype;
    width = awidth;
    layer = layer2CALU (alayer);

    switch (type) {
    default:
    case C_HORIZONTAL:
        mess1   = "horizontal";
        mess2   = "EAST/WEST";
        ORIENT1 = EAST;
        ORIENT2 = WEST;

        AB1 = fig->XAB1 ();
        AB2 = fig->XAB2 ();
        break;
    case C_VERTICAL:
        mess1   = "vertical";
        mess2   = "NORTH/SOUTH";
        ORIENT1 = NORTH;
        ORIENT2 = SOUTH;

        AB1 = fig->YAB1 ();
        AB2 = fig->YAB2 ();
        break;
    }


    // Loop over all the instances.
    for (ins = fig->phfig.fig->PHINS; ins != NULL; ins = ins->NEXT) {
        model = getphfig (ins->FIGNAME, 'A');

        // Find the power segments (CALUx).
        for (seg = model->PHSEG; seg != NULL; seg = seg->NEXT) {

            // Skip no power segments.
            if (!(cmpALU (alayer, seg->LAYER) & F_CALU)) continue;
            segType = C_POWER_NONE;
            if (ISVDD (seg->NAME)) segType = C_POWER_VDD;
            if (ISVSS (seg->NAME)) segType = C_POWER_VSS;
            if (segType == C_POWER_NONE) continue;

            xyflat ( &(flatSeg.X1), &(flatSeg.Y1)
                     ,       seg->X1, seg->Y1
                     ,     ins->XINS, ins->YINS
                     ,   model->XAB1, model->YAB1
                     ,   model->XAB2, model->YAB2
                     ,   ins->TRANSF
                   );

            xyflat ( &(flatSeg.X2), &(flatSeg.Y2)
                     ,       seg->X2, seg->Y2
                     ,     ins->XINS, ins->YINS
                     ,   model->XAB1, model->YAB1
                     ,   model->XAB2, model->YAB2
                     ,   ins->TRANSF
                   );

            // Check the segment width.
            if (seg->WIDTH != width) {
                cerr << hwarn ("");
                cerr << "  " << layer2a (layer) << " \"" << seg->NAME
                     <<"\" segment at ("
                     << UNSCALE (seg->X1) << ","
                     << UNSCALE (seg->Y1) << ") doesn't have the rigth witdth :"
                     << UNSCALE (seg->WIDTH) << " instead of "
                     << UNSCALE (width) << ".\n";
                cerr << "  (instance \"" << ins->INSNAME << "\" of model \""
                     << model->NAME << "\")\n";

                continue;
            }

            // Check the segment direction & position.
            switch (type) {
            default:
            case C_HORIZONTAL:
                lbound = flatSeg.X1;
                rbound = flatSeg.X2;
                key = flatSeg.Y1;

                if (flatSeg.Y1 != flatSeg.Y2) {
                    cerr << hwarn ("");
                    cerr << "  " << layer2a (layer) << " \"" << seg->NAME
                         <<"\" segment at ("
                         << UNSCALE (seg->X1) << ","
                         << UNSCALE (seg->Y1) << ") is not " << mess1;
                    cerr << "  (instance \"" << ins->INSNAME << "\" of model \""
                         << model->NAME << "\")\n";

                    continue;
                }

                if (   (cmpALU (alayer, CALU1) & F_CALU)
                        && !fig->phfig.onslice (flatSeg.Y1,yoffset)) {
                    cerr << hwarn ("");
                    cerr << "  " << layer2a (layer) << " \"" << seg->NAME
                         <<"\" segment at ("
                         << UNSCALE (seg->X1) << ","
                         << UNSCALE (seg->Y1) << ") is not on a slice boundary.\n";
                    cerr << "  (instance \"" << ins->INSNAME << "\" of model \""
                         << model->NAME << "\")\n";
                    cerr << "  (valide slices boundaries are"
                         << " ((n * " << D::Y_SLICE << ") - " << D::WIDTH_VSS / 2 << ") or"
                         << " ((n * " << D::Y_SLICE << ") + " << D::WIDTH_VSS / 2 << ") )\n";

                    continue;
                }
                break;

            case C_VERTICAL:
                lbound = flatSeg.Y1;
                rbound = flatSeg.Y2;
                key = flatSeg.X1;

                if (flatSeg.X1 != flatSeg.X2) {
                    cerr << hwarn ("");
                    cerr << "  " << layer2a (layer) << " \"" << seg->NAME
                         <<"\" segment at ("
                         << UNSCALE (seg->X1) << ","
                         << UNSCALE (seg->Y1) << ") is not " << mess1;
                    cerr << "  (instance \"" << ins->INSNAME << "\" of model \""
                         << model->NAME << "\")\n";

                    continue;
                }
                break;
            }


            beginLine = powerLines.begin ();
            endLine = powerLines.end ();


            // Check if the power line is of the same type.
            // (no short circuits between VDD & VSS.
            itLine = powerLines.find (key);
            if (itLine != endLine) {
                if (itLine->second.type != segType) {
                    cerr << herr ("");
                    cerr << "  " << layer2a (layer) << " \"" << seg->NAME
                         <<"\" segment at ("
                         << UNSCALE (seg->X1) << ","
                         << UNSCALE (seg->Y1) << ") conflict with power line at"
                         << UNSCALE (key) << ".\n";

                    throw except_done ();
                }
            }


            // Merge the segment with the power line (at long last...).
            powerLines[key].add (lbound, rbound);
            powerLines[key].type = segType;
        }
    }
}
Ejemplo n.º 11
0
int  main (int argc, char *argv[])
{
  COpts        options;
  MBK::CFig   *fig;
  string       name_lofig, name_placed, name_routed;
  int          layers, global;
  set<string>* netSet = NULL;


  try {
    options.add ("v", "verbose");
    options.add ("V", "very-verbose");
    options.add ("h", "help");
    options.add ("c", "coredump");
    options.add ("H", "half-pitch");
    options.add ("R", "rotate");
    options.add ("2", "layers-2");
    options.add ("3", "layers-3");
    options.add ("4", "layers-4");
    options.add ("5", "layers-5");
    options.add ("6", "layers-6");
    options.add ("G", "global");
    options.add ("L", "local");
    options.add ("p", "place", true);
    options.add ("N", "netset", true);
    options.getopts (argc, argv);

    if (options["c"]->parsed) interrupt.coredump = true;

    cmess0.setVL (0);
    if (options["v"]->parsed) cmess0.setVL (1);
    if (options["V"]->parsed) cmess0.setVL (2);

    MBK::alliancebanner ( "NeRo"
                        , VERSION
                        , "Negotiating Router"
                        , "2002"
                        , ALLIANCE_VERSION
                        );
    if ((cmess0.getVL () > 0) || options["h"]->parsed ) {
      serial ();
      cmess1 << "\n";
    }

    if (options["h"]->parsed) {
      help ();
      exit (0);
    }

    if (options.tVals.size() < 2) {
      cerr << herr ("nero:\n");
      cerr << "  Missing mandatory argument <netlist> or <routed> (or both)\n";
      cerr << "\n";

      help ();

      throw except_done ();
    }

    name_lofig  = options.tVals[0];
    name_routed = options.tVals[1];

    if (options["p"]->parsed) {
      name_placed = options["p"]->value;
    } else {
      name_placed = name_lofig;
    }

    if (options["N"]->parsed) {
      string fileNetSet = options["N"]->value;
      cout << "File: " << fileNetSet << endl;
      FILE* file = fopen ( fileNetSet.c_str(), "r" );
      if ( file ) {
        cout << "File Sucessfully opened." << endl;
        netSet = new set<string>();
        char buffer[2048];
        while ( !feof(file) ) {
          fgets ( buffer, 2048, file );
          size_t length = strlen(buffer);
          if ( buffer[length-1] == '\n' )
            buffer[length-1] = '\0';
          netSet->insert ( buffer );
        }
        fclose ( file );
      }
    }

    layers = 3;
    if (options["2"]->parsed) layers = 3;
    if (options["3"]->parsed) layers = 4;
    if (options["4"]->parsed) layers = 5;
    if (options["5"]->parsed) layers = 6;
    if (options["6"]->parsed) layers = 7;

    global = D::ROUTING_CHOOSE;
    if (options["L"]->parsed) { global = D::ROUTING_LOCAL; }
    if (options["G"]->parsed) {
      global = D::ROUTING_GLOBAL;

      if (layers < 5) layers = 5;
    }

    cmess1 << MBK::env;

    fig   = new MBK::CFig (name_lofig, name_placed);
    crbox = new CRBox ();
    //crbox = new CRBox (global, true);
    //cdebug.on ();
    crbox->mbkload ( fig
                   , layers
                   , 4
                   , global
                   , options["H"]->parsed
                   , options["R"]->parsed
                   , netSet );
    //cdebug.off ();
    crbox->route ();
    crbox->mbksave (name_routed);

    if ( netSet ) delete netSet;
  }


  catch (e_zupper &e) {
    cerr << "\n\n"
         << "  First \"double pitch\" layer must be at least equal to ALU5 "
         << "(here : " << MBK::env.z2alu (e.zupper) << ").\n\n"
         << endl;

    exit (1);
  }
  catch (bad_grab &e) {
    cerr << herr ("\n");
    cerr << "  Net \"" << e.netName << "\" attempt to grab node ("
         << e.x << "," << e.y << "," << e.z << "),\n"
         << "  which belongs to net \"" << e.ownerName << "\".\n" << endl;
    cerr << "  (nodepri := " << e.nodepri
         << "  , pri := " << e.pri << ", terminal := " << e.terminal
         << ", ident := " << e.ident << ")\n" << endl;

    emergency ();
    exit (1);
  }
  //catch (coord_outbound &e) {
  //  cerr << herr ("\n");
  //  cerr << "  Atempt to use outbound coordinates := ("
  //       << e.x << "," << e.y << "," << e.z << ") real := ("
  //       << MBK::UNSCALE (crbox->fig->XAB1() + e.x * D::X_GRID) << ","
  //       << MBK::UNSCALE (crbox->fig->YAB1() + e.y * D::Y_GRID) << ","
  //       << MBK::layer2a (MBK::env.z2alu (e.z)) << ")\n"
  //       << endl;
  //
  //  emergency ();
  //  exit (1);
  //}
  // Case of exceptions that have already been processed.
  catch (dup_term &e) {
    cerr << "  Duplicated terminal node for " << e.name
         << " at " << e.node << endl;

    exit (1);
  }
  catch (reach_max_pri &e) {
    cerr << "\n\n"
         << "  Negotiation algorithm failed, NeRo was unable to route this"
         << "  design.\n  Maximum priority reached for net " 
         << "\"" << e.net->name << "\".\n\n";

    emergency ();
    exit (1);
  }
  catch (except_done &e) {
    cerr << e.what () << endl;

    emergency ();
    exit (1);
  }

  // Case of unexpected (undefined) exceptions.
  catch (...) {
    cerr << herr ("\n");
    cerr << "  An unexpected exception have occurs.\n\n";
    cerr << "  This is a bug. Please e-mail to \"[email protected]\".\n\n";

    exit (1);
  }


  // This is the End.
  cmess1 << "\n\n";
                                                              
  exit (0);
}