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; }
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); }
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; } } }