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 += ":"; }
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); }
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); }
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); }
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 (); }
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); }
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; }
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; } } }
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); }