Modularize the global to detail routing converter.

* New: In Anabatic, rename GCellTopology to NetBuilder, expose  the class
    (no longer in a local namespace).
      NetBuilder become a base class performing the walkthrough the Net
    tree. Derived class are tasked to build routing for specific gauge.
      NetBuilderHV is created to manage all gauge with metal2 horizontal
    and metal3 vertical.
      In our terminolgy we consider that the first routing metal is
    metal2. Metal1 is used inside the standard cells.
This commit is contained in:
Jean-Paul Chaput 2017-12-17 00:13:19 +01:00
parent 21ec6fdbad
commit 4c57b0651a
9 changed files with 1307 additions and 1111 deletions

346
anabatic/doc/NetBuilder.dox Normal file
View File

@ -0,0 +1,346 @@
// -*- C++ -*-
namespace Anabatic {
/*! \defgroup LoadGlobalRouting Global Routing Loading
* \brief Translation rules to build detailed routing from global
*
* This module documents how the global routing built by \c Knik is
* loaded into the \c Anabatic data-base. It is intented for developpers
* only.
*/
//! \addtogroup LoadGlobalRouting
//! \{
//! \enum LocalFunctionFlag
//! A set of flags for all functions of the LoadGlobalRouting module.
//! They can be combined to form the \e flags argument of functions.
//! the functions will ignore flags that are not intended to them.
//!
//! For \c HSmall, \c VSmall & \c Punctual see checkRoutingPadSize().
//! \var LocalFunctionFlag::NoFlags
//! A simple alias over zero to explicitly tell that no flag at all is
//! passed to the function.
//! \var LocalFunctionFlag::HAccess
//! The constructed topology will be accessed through an horizontal
//! segment. The absence of this flag tell that the access will be done
//! trough a vertical.
//! \var LocalFunctionFlag::VSmall
//! The RoutingPad vertically covers a very small number of access points,
//! so it is likely overconstrained for direct horizontal connexion.
//! \var LocalFunctionFlag::HSmall
//! The RoutingPad horizontally covers a very small number of access points,
//! so it is likely overconstrained for direct vertical connexion.
//! \var LocalFunctionFlag::Punctual
//! The RoutingPad covers only an access point in either direction.
//! \var LocalFunctionFlag::DoSourceContact
//! When creating Anabatic::AutoContactTerminal on non-punctual RoutingPad, this flag
//! request the creation of a contact <em>on the source point</em>.
//! \var LocalFunctionFlag::DoTargetContact
//! When creating Anabatic::AutoContactTerminal on non-punctual RoutingPad, this flag
//! request the creation of a contact <em>on the target point</em>.
//! \function uint64_t checkRoutingPadSize ( Component* rp );
//!
//! Look at the geometrical size of the Component and assess if
//! it's span is too narrow either horizontally or vertically.
//! Return a combination of flags indicating it's state:
//! - HSmall : less than 3 pitches in horizontal direction.
//! - VSmall : less than 3 pitches in vertical direction.
//! - Punctual : one pitch in either directions.
//!
//! The component can be a RoutingPad, a Vertical or an Horizontal.
//!
//! \image html checkRoutingPadSize.png "checkRoutingPadSize()"
/*! \class NetBuilder
*
* \brief Build the wiring for a Net inside a GCell (\b internal).
*
* As this class is called to initially construct the Anabatic wiring,
* it must build a \b connex wiring. That is without gaps in layer depth,
* because the topology restauration mechanism (AutoContact::updateTopology())
* of the AutoContact cannot work until all AutoSegments are revalidated at
* least once. The topology restauration work by creating doglegs which in turn,
* call the canonization, which needs all the caches to be up to date.
*/
//! \function void NetBuilder::doRp_AutoContacts ( GCell* gcell, Component* rp, AutoContact*& source, AutoContact*& target, uint64_t flags );
//! \param gcell The GCell into which create the AutoContact.
//! \param rp The Component we want to access.
//! \param source The AutoContact created on the \c source (\e returned).
//! \param target The AutoContact created on the \c target (\e returned).
//! \param flags Managed by this function:
//! - LocalFunctionFlag::DoSourceContact
//! - LocalFunctionFlag::DoTargetContact
//!
//! Create the AutoContact directly anchored on the Component (terminal).
//! Three cases are manageds:
//! -# <b>Ordinary (non-punctual) \c METAL1 terminal</b>: an AutoContactTerminal
//! is anchored on the RoutingPad.
//! -# <b>Punctual \c METAL1 terminal</b>, the access must never be blocked
//! by other routing. To ensure it, we create a fixed AutoSegment (anchored
//! on two AutoContactTerminal) to cover it. The \e normal AutoContactTerminal
//! is also created.
//! -# <b>non \c METAL1 terminal</b>, as for the punctual \c METAL1, a
//! fixed protection is added over the RoutingPad. If we access
//! horizontally a vertical RoutingPad or vertically an horizontal
//! one, an extra AutoContactTerminal is added (to allow is displacement
//! along the RoutingPad).
//!
//! To avoid creating a fixed protection over a RoutingPad multiple times,
//! the RoutingPad and it's associated protection is stored in a static
//! \c map : \c __routingPadAutoSegments.
//!
//! Conversely, because an AutoContactTerminal can only be connected to one
//! segment, each time this function is called a new terminal will be created
//! (or maybe two in case of non-punctual terminals). If only one AutoContact
//! is requested, it is created centered on the RoutingPad. The initial
//! position of AutoContact <em>do not prevent them to move afterwards</em>,
//! even those created on source/target on a non-punctual RoutingPad.
//!
//! \remark For clarity we describe the layer management of this function in term
//! of \c METAL, but it is the RoutingGauge depth which is actually used.
//!
//! \image html doRp_AutoContacts.png "doRp_AutoContacts()"
//! \function AutoContact* NetBuilder::doRp_Access ( GCell* gcell, Component* rp, uint64_t flags );
//! \param gcell The GCell into which create the AutoContact.
//! \param rp The Component onto which anchor the access contact.
//! \param flags Relevant flags are:
//! - HAccess, the terminal is to be accessed through an horizontal
//! segment.
//! - VSmall, force the terminal to be considered as small in the
//! vertical direction.
//!
//! If \c HAccess is set, the Component is to be accessed trough an horizontal
//! segment. If unset, the access is done vertically.
//!
//! Create an AutoContact to access a Component (terminal). If the Component
//! is not to be accessed through an horizontal segment, and do not cover a
//! large span in the horizontal direction (flag \c VSmall), a local horizontal
//! AutoSegment is added to slacken the vertical constraints.
//!
//! \image html doRp_Access.png "doRp_Access()"
//! \function AutoContact* NetBuilder::doRp_AccessPad ( RoutingPad* rp, uint64_t flags );
//! \param rp The Component onto which anchor the access contact.
//! \param flags Relevant flags are:
//! - HAccess, the terminal is to be accessed through an horizontal
//! segment.
//! - VSmall, force the terminal to be considered as small in the
//! vertical direction.
//! \return A Anabatic::AutoContactTerminal .
//!
//! The Component \c rp is a RoutingPad which belongs to a pad cell. This case
//! occurs when we are routing a complete chip. This method build, from the
//! \c rp a stack of articulated punctual segments and contacts to reach the
//! default H/V routing layers (usually \c METAL2 & \c METAL3). This may be
//! needed when the pad terminal is in \c METAL5, for instance.
//!
//! The returned AutoContactTerminal is anchored on the last punctual segment
//! build.
//!
//! The GCell into which the AutoContactTerminal is created may be under the
//! pads area. However, it will be right on the border of the GCell.
//! The global router vertexes of GCell under the pad area are marked as
//! blocked so will never be used for routing.
//!
//! \remark The segments and contacts added to ensure the layer connexity are not
//! put into the Anabatic database. They are plain Hurricane objects, invisibles
//! from it.
//! \function void NetBuilder::doRp_StairCaseH ( GCell* gcell, Component* rp1, Component* rp2 );
//!
//! Build the wiring to connect to horizontal Component. Two cases:
//! - The Component are aligneds, then only a straight wire is created.
//! - They are \e not aligned, then a complete dogleg is created.
//!
//! \image html doRp_StairCaseH.png "doRp_StairCaseH()"
//! \function void NetBuilder::doRp_StairCaseV ( GCell* gcell, Component* rp1, Component* rp2 );
//!
//! Build the wiring to connect to vertical Components. Two cases:
//! - The Components are aligneds, then only a straight wire is created.
//! - They are \e not aligned, then a complete dogleg is created.
//!
//! \image html doRp_StairCaseV.png "doRp_StairCaseV()"
//! \function void NetBuilder::_do_xG_1Pad ();
//!
//! Construct the topology, when there is only global wires and one local
//! terminal, but coming from a Pad. As thoses connectors will always be
//! on one border of the GCell they can be considered as a kind of global.
//!
//! So this method mostly calls NetBuilder::doRp_AccessPad() to create
//! the AutoContactTerminal, then calls NetBuilder::_do_xG(), except
//! for straight lines which are managed directly.
//! \function void NetBuilder::_do_xG ();
//!
//! Construct the topology, when there is only global wires (no local terminals).
//!
//! Some topology are not handled because they must not be managed by this
//! function:
//! <ul>
//! <li>One global: nonsensical because there also must be a terminal.
//! <li>Two aligned globals: in that case we do a straight wire whithout
//! any AutoContact (handled by the source/target of the wire).
//! </ul>
//!
//! \image html _do_xG.png "_do_xG()"
//! \function void NetBuilder::_do_1G_1M1 ();
//!
//! Construct a topology where there is \e one global and one RoutingPad
//! in \c METAL1. The \c METAL1 is assumed to be vertical.
//!
//! \remark When accessing the RoutingPad through an horizontal global segment
//! and the vertical extension of the segment is small, the global is
//! still directly attached to the terminal, inducing a high constraint
//! on it. We left to job of slackening it to the router.
//!
//! \image html _do_1G_1M1.png "_do_1G_1M1()"
//! \function void NetBuilder::_do_1G_xM1 ();
//!
//! Construct a topology where there is \e one global and any number of
//! RoutingPad in \c METAL1. The \c METAL1 is assumed to be vertical.
//!
//! The RoutingPads are linked together two by two. If the horizontal
//! segments are not aligned by the router, part of the routage will be
//! done through the RoutingPad itself. The global incoming segment will
//! connected to the leftmost, rightmost or centermost RoutingPad according
//! from wich side it comes from.
//!
//! \image html _do_1G_xM1.png "_do_1G_xM1()"
//! \function void NetBuilder::_do_xG_1M1_1M2 ();
//!
//! Construct a topology where there is at least one global (and up to 4),
//! one \c METAL1 RoutingPad (assumed V) and one \c METAL2 RoutingPad (assumed H).
//!
//! In this topology, we want to try to reuse the \c METAL2 RoutingPad as a
//! feedtrough in the horizontal routage. Thus:
//! - The \c METAL1 and \c METAL2 RoutingPad are connected through a separate wiring.
//! - The south & west global wiring is attached to the leftmost contact of
//! the \c METAL2.
//! - The north & east global wiring is attached to the rightmost contact of
//! the \c METAL2.
//!
//! South/west and north/south can be build independantly. Depending on the number
//! of globals, they can consist of:
//! - Nothing (no south nor west).
//! - An AutoContact (west present).
//! - An horizontal plus a turn (south present).
//! - An horizontal plus a HTee (south & west present).
//!
//! \remark Not all configurations are represented below.
//!
//! \image html _do_xG_1M1_1M2.png "_do_xG_1M1_1M2()"
//! \function void NetBuilder::_do_xG_xM1_xM3 ();
//!
//! Construct a topology where there is at least one global (and up to 4),
//! at least one \c METAL1 RoutingPad (assumed V) and at least one \c METAL3
//! RoutingPad (assumed V).
//!
//! In this topology, we want to try to reuse the \c METAL3 RoutingPad as a
//! feedtrough in the vertical routage. Thus:
//! - The \c METAL1 and \c METAL3 RoutingPad are connected through a separate
//! wiring made of separate horizontals.
//! - The south-west global wiring is attached to the leftmost RoutingPad
//! if there isn't south or to the first \c METAL3 otherwise.
//! - The north-east global wiring is attached to the rightmost RoutingPad
//! if there isn't north or to the first \c METAL3 otherwise.
//!
//! South/west and north/south can be build independantly. Depending on the number
//! of globals, they can consist of:
//! - Nothing (no south nor west).
//! - An AutoContact on the leftmost RoutingPad (west present).
//! - An AutoContact on the first \c METAL3 (only south present).
//! - An AutoContact plus a vertical plus a VTee (south & west present).
//!
//! \image html _do_xG_xM1_xM3.png "_do_xG_xM1_xM3()"
//! \function void NetBuilder::_do_xG_xM2 ();
//!
//! Construct a topology where there is at least one global (and up to 4),
//! and any number of \c METAL2 RoutingPads (assumeds H).
//!
//! In this topology, we want to try to reuse the \c METAL2 RoutingPad as a
//! feedtrough in the horizontal routage. Thus:
//! - The RoutingPad are connecteds trough a separate staircase (or
//! straight wire if aligneds).
//! - The south-west global wiring is attached to the leftmost RoutingPad
//! if there isn't south or to the biggest horizontal RoutingPad otherwise.
//! - The north-east global wiring is attached to the rightmost RoutingPad
//! if there isn't south or to the biggest horizontal RoutingPad otherwise.
//!
//! \image html _do_xG_xM2.png "_do_xG_xM2()"
//! \function void NetBuilder::_do_1G_1M3 ();
//!
//! Construct a topology where there is one global and one \c METAL3 RoutingPad
//! (assumeds V).
//!
//! In this topology, we reuse the \c METAL3 RoutingPad as a feedtrough in the
//! vertical routage. Thus:
//! - If the global is either north or south, we directly connect to the
//! north end or south end of the RoutingPad. \red{The vertical global will}
//! \red{have no slack at all we assume that METAL3 terminals are only from}
//! \red{blocks and are aligneds vertically.}
//! - If the global is east or west \e and the RoutingPad is sufficiently
//! extended in the vertical direction, we connect an horizontal in the
//! normal way.
//! - If the global is not sufficiently extended, we add a turn to give some
//! slack to the global.
//!
//!
//! \image html _do_1G_1M3.png "_do_1G_1M3()"
//! \function void NetBuilder::_do_xG_xM3 ();
//!
//! Construct a topology where there at least one global and two \c METAL3 RoutingPad
//! (assumed V).
//!
//! In this topology, we reuse the \c METAL3 RoutingPad as a feedtrough in the
//! vertical routage. \red{We assume that the most likely relative position}
//! \red{of the RoutingPads is to be aligned vertically}.
//! Thus:
//! - All RoutingPads are linked two by two trough vertical staircases.
//! - The south-west global wiring is attached to the bottommost RoutingPad
//! (without vertical slack). If a misalignment is detected, then a
//! dogleg is added.
//! - The north-east global wiring is attached to the topmost RoutingPad
//! (without vertical slack).
//!
//! South/west and north/south can be build independantly. Depending on the number
//! of globals, they can consist of:
//! - Nothing (no south nor west).
//! - An sliding AutoContact on the bottommost RoutingPad (west present).
//! - An fixed AutoContact on the bottommost RoutingPad (only south present).
//! - An fixed AutoContact plus a vertical plus a VTee (south & west present).
//!
//! \image html _do_xG_xM3.png "_do_xG_xM3()"
//! \function void singleGCell ( AnabaticEngine* anbt, Net* net );
//!
//! All the RoutingPads of the net are concentrated under a single
//! GCell. This function assumes that all the terminals are in
//! \c METAL1 (vertical), and link them two by two by horizontal
//! wires.
//! \}
}

View File

@ -27,7 +27,9 @@
#include "hurricane/DebugSession.h" #include "hurricane/DebugSession.h"
#include "hurricane/UpdateSession.h" #include "hurricane/UpdateSession.h"
#include "crlcore/RoutingGauge.h" #include "crlcore/RoutingGauge.h"
#include "crlcore/Measures.h"
#include "anabatic/GCell.h" #include "anabatic/GCell.h"
#include "anabatic/NetBuilderHV.h"
#include "anabatic/AnabaticEngine.h" #include "anabatic/AnabaticEngine.h"
@ -50,6 +52,8 @@ namespace Anabatic {
using Hurricane::UpdateSession; using Hurricane::UpdateSession;
using CRL::RoutingGauge; using CRL::RoutingGauge;
using CRL::RoutingLayerGauge; using CRL::RoutingLayerGauge;
using CRL::addMeasure;
using CRL::getMeasure;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -718,6 +722,38 @@ namespace Anabatic {
} }
void AnabaticEngine::_loadGrByNet ()
{
cmess1 << " o Building detailed routing from global." << endl;
startMeasures();
openSession();
for ( Net* net : getCell()->getNets() ) {
if (NetRoutingExtension::isAutomaticGlobalRoute(net)) {
DebugSession::open( net, 144, 160 );
AutoSegment::setAnalogMode( NetRoutingExtension::isAnalog(net) );
NetBuilder::load<NetBuilderHV>( this, net );
Session::revalidate();
DebugSession::close();
}
}
AutoSegment::setAnalogMode( false );
#if defined(CHECK_DATABASE)
_check ( "after Anabatic loading" );
#endif
Session::close();
stopMeasures();
printMeasures( "load" );
addMeasure<size_t>( getCell(), "Globals", AutoSegment::getGlobalsCount() );
addMeasure<size_t>( getCell(), "Edges" , AutoSegment::getAllocateds() );
}
void AnabaticEngine::updateNetTopology ( Net* net ) void AnabaticEngine::updateNetTopology ( Net* net )
{ {
DebugSession::open( net, 140, 150 ); DebugSession::open( net, 140, 150 );

View File

@ -29,6 +29,8 @@ endif ( CHECK_DETERMINISM )
anabatic/AutoHorizontal.h anabatic/AutoHorizontal.h
anabatic/AutoVertical.h anabatic/AutoVertical.h
anabatic/Session.h anabatic/Session.h
anabatic/NetBuilder.h
anabatic/NetBuilderHV.h
anabatic/ChipTools.h anabatic/ChipTools.h
) )
set( pyIncludes ) set( pyIncludes )
@ -38,9 +40,7 @@ endif ( CHECK_DETERMINISM )
Edge.cpp Edge.cpp
Edges.cpp Edges.cpp
GCell.cpp GCell.cpp
AnabaticEngine.cpp
Dijkstra.cpp Dijkstra.cpp
AutoContact.cpp AutoContact.cpp
AutoContactTerminal.cpp AutoContactTerminal.cpp
AutoContactTurn.cpp AutoContactTurn.cpp
@ -52,10 +52,12 @@ endif ( CHECK_DETERMINISM )
Session.cpp Session.cpp
NetConstraints.cpp NetConstraints.cpp
NetOptimals.cpp NetOptimals.cpp
LoadGlobalRouting.cpp NetBuilder.cpp
NetBuilderHV.cpp
ChipTools.cpp ChipTools.cpp
LayerAssign.cpp LayerAssign.cpp
PreRouteds.cpp PreRouteds.cpp
AnabaticEngine.cpp
) )
set( pyCpps PyAnabatic.cpp set( pyCpps PyAnabatic.cpp
) )

View File

@ -0,0 +1,244 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2008-2016, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | A n a b a t i c - Routing Toolbox |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Module : "./LoadGlobalRouting.cpp" |
// +-----------------------------------------------------------------+
#include <cstdlib>
#include <sstream>
#include "hurricane/Bug.h"
#include "hurricane/Breakpoint.h"
#include "hurricane/Error.h"
#include "hurricane/Warning.h"
#include "hurricane/DebugSession.h"
#include "hurricane/Layer.h"
#include "hurricane/BasicLayer.h"
#include "hurricane/RegularLayer.h"
#include "hurricane/Technology.h"
#include "hurricane/DataBase.h"
#include "hurricane/Net.h"
#include "hurricane/NetExternalComponents.h"
#include "hurricane/NetRoutingProperty.h"
#include "hurricane/RoutingPad.h"
#include "hurricane/RoutingPads.h"
#include "hurricane/Pad.h"
#include "hurricane/Plug.h"
#include "hurricane/Cell.h"
#include "hurricane/Instance.h"
#include "hurricane/Vertical.h"
#include "hurricane/Horizontal.h"
#include "crlcore/AllianceFramework.h"
#include "crlcore/RoutingGauge.h"
#include "crlcore/Measures.h"
#include "anabatic/AutoContactTerminal.h"
#include "anabatic/AutoContactTurn.h"
#include "anabatic/AutoContactHTee.h"
#include "anabatic/AutoContactVTee.h"
#include "anabatic/AutoSegment.h"
#include "anabatic/NetBuilderHV.h"
#include "anabatic/AnabaticEngine.h"
namespace Anabatic {
using std::swap;
NetBuilderHV::NetBuilderHV ()
: NetBuilder()
{ }
NetBuilderHV::~NetBuilderHV () { }
void NetBuilderHV::doRp_AutoContacts ( GCell* gcell
, Component* rp
, AutoContact*& source
, AutoContact*& target
, uint64_t flags
)
{
cdebug_log(145,1) << "NetBuilderHV::doRp_AutoContacts()" << endl;
cdebug_log(145,0) << rp << endl;
source = target = NULL;
Point sourcePosition;
Point targetPosition;
const Layer* rpLayer = rp->getLayer();
size_t rpDepth = Session::getLayerDepth( rp->getLayer() );
Flags direction = Session::getDirection ( rpDepth );
DbU::Unit viaSide = Session::getViaWidth ( rpDepth );
getPositions( rp, sourcePosition, targetPosition );
if (sourcePosition.getX() > targetPosition.getX()) swap( sourcePosition, targetPosition );
if (sourcePosition.getY() > targetPosition.getY()) swap( sourcePosition, targetPosition );
GCell* sourceGCell = Session::getAnabatic()->getGCellUnder( sourcePosition );
GCell* targetGCell = Session::getAnabatic()->getGCellUnder( targetPosition );
if (rpDepth == 0) {
rpLayer = Session::getContactLayer(0);
direction = Flags::Horizontal;
viaSide = Session::getViaWidth( rpDepth );
}
// Non-M1 terminal or punctual M1 protections.
if ((rpDepth != 0) or (sourcePosition == targetPosition)) {
map<Component*,AutoSegment*>::iterator irp = getRpLookup().find( rp );
if (irp == getRpLookup().end()) {
AutoContact* sourceProtect = AutoContactTerminal::create( sourceGCell
, rp
, rpLayer
, sourcePosition
, viaSide, viaSide
);
AutoContact* targetProtect = AutoContactTerminal::create( targetGCell
, rp
, rpLayer
, targetPosition
, viaSide, viaSide
);
sourceProtect->setFlags( CntFixed );
targetProtect->setFlags( CntFixed );
AutoSegment* segment = AutoSegment::create( sourceProtect, targetProtect, direction );
segment->setFlags( AutoSegment::SegFixed );
getRpLookup().insert( make_pair(rp,segment) );
}
}
if (sourcePosition != targetPosition) {
if (flags & DoSourceContact)
source = AutoContactTerminal::create( sourceGCell
, rp
, rpLayer
, sourcePosition
, viaSide, viaSide
);
if (flags & DoTargetContact)
target = AutoContactTerminal::create( targetGCell
, rp
, rpLayer
, targetPosition
, viaSide, viaSide
);
}
if (not source and not target) {
source = target = AutoContactTerminal::create( gcell
, rp
, rpLayer
, rp->getCenter()
, viaSide, viaSide
);
}
cdebug_tabw(145,-1);
return;
}
AutoContact* NetBuilderHV::doRp_Access ( GCell* gcell, Component* rp, uint64_t flags )
{
cdebug_log(145,1) << "NetBuilderHV::doRp_Access() - flags:" << flags << endl;
AutoContact* rpContactSource;
AutoContact* rpContactTarget;
flags |= checkRoutingPadSize( rp );
doRp_AutoContacts( gcell, rp, rpContactSource, rpContactTarget, flags );
if (flags & HAccess) {
if (flags & VSmall) {
AutoContact* subContact1 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) );
AutoContact* subContact2 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) );
AutoSegment::create( rpContactSource, subContact1, Flags::Horizontal );
AutoSegment::create( subContact1, subContact2, Flags::Vertical );
rpContactSource = subContact2;
}
} else {
if (flags & HSmall) {
AutoContact* subContact1 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) );
AutoSegment::create( rpContactSource, subContact1, Flags::Horizontal );
rpContactSource = subContact1;
}
}
cdebug_tabw(145,-1);
return rpContactSource;
}
void NetBuilderHV::_do_1G_1M1 ()
{
cdebug_log(145,1) << "NetBuilderHV::_do_1G_1M1() [Managed Configuration - Optimized] " << getTopology() << endl;
uint64_t flags = NoFlags;
if (east() ) { flags |= HAccess; }
else if (west() ) { flags |= HAccess; }
else if (north()) { flags |= VSmall; }
else if (south()) { flags |= VSmall; }
setBothCornerContacts( doRp_Access(getGCell(),getRoutingPads()[0],flags) );
cdebug_tabw(145,-1);
}
void NetBuilderHV::_do_1G_xM1 ()
{
cdebug_log(145,1) << "NetBuilderHV::_do_1G_" << (int)getConnexity().fields.M1 << "M1() [Managed Configuration]" << endl;
sort( getRoutingPads().begin(), getRoutingPads().end(), SortRpByX(NoFlags) ); // increasing X.
for ( size_t i=1 ; i<getRoutingPads().size() ; ++i ) {
AutoContact* leftContact = doRp_Access( getGCell(), getRoutingPads()[i-1], HAccess );
AutoContact* rightContact = doRp_Access( getGCell(), getRoutingPads()[i ], HAccess );
AutoSegment::create( leftContact, rightContact, Flags::Horizontal );
}
Component* globalRp = NULL;
if (east()) globalRp = getRoutingPads()[getRoutingPads().size()-1];
else if (west()) globalRp = getRoutingPads()[0];
else {
globalRp = getRoutingPads()[0];
cdebug_log(145,0) << "| Initial N/S Global RP: " << globalRp << endl;
for ( size_t i=1 ; i<getRoutingPads().size() ; ++i ) {
if (getRoutingPads()[i]->getBoundingBox().getHeight() > globalRp->getBoundingBox().getHeight()) {
cdebug_log(145,0) << "| Better RP: " << globalRp << endl;
globalRp = getRoutingPads()[i];
}
}
}
AutoContact* globalContact = doRp_Access( getGCell(), globalRp, HAccess );
if (north() or south()) {
AutoContact* turn = globalContact;
globalContact = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( globalContact, turn, Flags::Horizontal );
}
setBothCornerContacts( globalContact );
cdebug_tabw(145,-1);
}
} // Anabatic namespace.

View File

@ -256,7 +256,6 @@ namespace Anabatic {
AutoContact* _lookup ( Contact* ) const; AutoContact* _lookup ( Contact* ) const;
AutoSegment* _lookup ( Segment* ) const; AutoSegment* _lookup ( Segment* ) const;
void _loadGrByNet (); void _loadGrByNet ();
void _loadNetGlobalRouting ( Net* );
void _computeNetOptimals ( Net* ); void _computeNetOptimals ( Net* );
void _computeNetTerminals ( Net* ); void _computeNetTerminals ( Net* );
void _alignate ( Net* ); void _alignate ( Net* );

View File

@ -0,0 +1,441 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2008-2016, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | A n a b a t i c - Routing Toolbox |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Header : "./anabatic/NetBuilder.h" |
// +-----------------------------------------------------------------+
#ifndef ANABATIC_NET_BUILDER_H
#define ANABATIC_NET_BUILDER_H
#include <vector>
#include <map>
namespace Hurricane {
class Hook;
class Net;
class RoutingPad;
class Component;
}
namespace Anabatic {
using std::vector;
using std::map;
using std::endl;
using Hurricane::Hook;
using Hurricane::Net;
using Hurricane::RoutingPad;
using Hurricane::Component;
class GCell;
class AutoContact;
class AutoSegment;
class AnabaticEngine;
// -------------------------------------------------------------------
// Class : "ForkStack".
class ForkStack {
public:
inline void push ( Hook* from, AutoContact* contact );
inline void pop ();
inline Hook* getFrom () const;
inline AutoContact* getContact () const;
private:
struct Element {
Hook* _from;
AutoContact* _contact;
inline Element ( Hook* from, AutoContact* contact );
};
private:
list<Element> _stack;
};
inline ForkStack::Element::Element ( Hook* from, AutoContact* contact ) : _from(from), _contact(contact) {}
inline void ForkStack::pop () { if (not _stack.empty()) _stack.pop_back(); }
inline Hook* ForkStack::getFrom () const { return _stack.empty() ? NULL : _stack.back()._from; }
inline AutoContact* ForkStack::getContact () const { return _stack.empty() ? NULL : _stack.back()._contact; }
inline void ForkStack::push ( Hook* from, AutoContact* contact )
{
cdebug_log(145,0) << " Stacking " << from << " + " << contact << endl;
_stack.push_back( Element(from,contact) );
}
// -------------------------------------------------------------------
// Class : "NetBuilder".
class NetBuilder {
public:
enum FunctionFlags { NoFlags = (1 << 0)
, SortDecreasing = (1 << 1)
, HAccess = (1 << 2)
, VSmall = (1 << 3)
, HSmall = (1 << 4)
, Punctual = (1 << 5)
, HCollapse = (1 << 6)
, VCollapse = (1 << 7)
, Terminal = (1 << 8)
, DoSourceContact = (1 << 9)
, DoTargetContact = (1 << 10)
, SouthBound = (1 << 11)
, NorthBound = (1 << 12)
, WestBound = (1 << 13)
, EastBound = (1 << 14)
, Middle = (1 << 15)
, SouthWest = SouthBound|WestBound
, NorthEast = NorthBound|EastBound
};
// Connexity Union Type.
enum ConnexityBits { GlobalBSize = 8
, Metal1BSize = 4
, Metal2BSize = 4
, Metal3BSize = 4
, PadsBSize = 4
, PinsBSize = 4
};
union UConnexity {
uint64_t connexity;
struct {
unsigned int globals : GlobalBSize;
unsigned int M1 : Metal1BSize;
unsigned int M2 : Metal2BSize;
unsigned int M3 : Metal3BSize;
unsigned int Pad : PadsBSize;
unsigned int Pin : PinsBSize;
} fields;
};
public:
template< typename BuilderT >
static void load ( AnabaticEngine*, Net* );
static void init ( unsigned int degree );
static void fixSegments ();
static void getPositions ( Component* anchor, Point& source, Point& target );
static uint64_t checkRoutingPadSize ( Component* anchor );
static Hook* getSegmentOppositeHook ( Hook* hook );
static uint64_t getSegmentHookType ( Hook* hook );
public:
NetBuilder ();
virtual ~NetBuilder ();
void clear ();
NetBuilder& startFrom ( AnabaticEngine*
, Hook* fromHook
, AutoContact* sourceContact=NULL );
void construct ();
inline unsigned int getStateG () const;
inline UConnexity getConnexity () const;
inline Net* getNet () const;
inline GCell* getGCell () const;
inline ForkStack& getForks ();
inline vector<RoutingPad*>& getRoutingPads ();
static map<Component*,AutoSegment*>& getRpLookup ();
inline unsigned int getTopology () const;
inline Hook* north ( size_t i=0 ) const;
inline Hook* south ( size_t i=0 ) const;
inline Hook* east ( size_t i=0 ) const;
inline Hook* west ( size_t i=0 ) const;
inline void setBothCornerContacts ( AutoContact* );
static void clearRpLookup ();
bool push ( Hook* to, AutoContact* contact, uint64_t flags=0 );
virtual void doRp_AutoContacts ( GCell*, Component*, AutoContact*& source, AutoContact*& target, uint64_t flags ) = 0;
virtual AutoContact* doRp_Access ( GCell*, Component*, uint64_t flags ) = 0;
virtual AutoContact* doRp_AccessPad ( RoutingPad*, uint64_t flags );
virtual AutoContact* doRp_AccessAnalog ( GCell*, RoutingPad*, uint64_t flags );
AutoContact* doRp_2m_Access ( GCell*, RoutingPad*, uint64_t flags );
void doRp_StairCaseH ( GCell*, Component* rp1, Component* rp2 );
void doRp_StairCaseV ( GCell*, Component* rp1, Component* rp2 );
void singleGCell ( AnabaticEngine*, Net* );
void _load ( AnabaticEngine*, Net* );
private:
void _do_2m_1G_1M1 ();
void _do_2m_2G_1M1 ();
void _do_2m_xG ();
void _do_xG ();
void _do_2G ();
virtual void _do_xG_1Pad ();
virtual void _do_1G_1PinM2 ();
virtual void _do_1G_1M1 () = 0;
virtual void _do_1G_xM1 () = 0;
virtual void _do_xG_xM1_xM3 ();
virtual void _do_xG_1M1_1M2 ();
virtual void _do_4G_1M2 ();
virtual void _do_xG_xM2 ();
virtual void _do_1G_1M3 ();
virtual void _do_xG_xM3 ();
AutoContact* _doHChannel ();
AutoContact* _doVChannel ();
AutoContact* _doStrut ();
AutoContact* _doDevice ();
AutoContact* _doHRail ();
AutoContact* _doVRail ();
void _doIoPad ();
unsigned int getNumberGlobals ();
unsigned int getDeviceNeighbourBound();
private:
#define CONNEXITY_VALUE( Gs, M1s, M2s, M3s, pads, pins ) \
Gs + ((M1s ) << GlobalBSize) \
+ ((M2s ) << (GlobalBSize+Metal1BSize)) \
+ ((M3s ) << (GlobalBSize+Metal1BSize+Metal2BSize)) \
+ ((pads) << (GlobalBSize+Metal1BSize+Metal2BSize+Metal3BSize)) \
+ ((pins) << (GlobalBSize+Metal1BSize+Metal2BSize+Metal3BSize+PadsBSize))
// Connexity Name | G|M1|M2|M2|Pad|Pin|
enum ConnexityFlag { Conn_0G = CONNEXITY_VALUE( 0, 0, 0, 0, 0 , 0 )
, Conn_2G = CONNEXITY_VALUE( 2, 0, 0, 0, 0 , 0 )
, Conn_3G = CONNEXITY_VALUE( 3, 0, 0, 0, 0 , 0 )
, Conn_4G = CONNEXITY_VALUE( 4, 0, 0, 0, 0 , 0 )
, Conn_0G_2M1 = CONNEXITY_VALUE( 0, 2, 0, 0, 0 , 0 )
, Conn_1G_1M1 = CONNEXITY_VALUE( 1, 1, 0, 0, 0 , 0 )
, Conn_1G_2M1 = CONNEXITY_VALUE( 1, 2, 0, 0, 0 , 0 )
, Conn_1G_3M1 = CONNEXITY_VALUE( 1, 3, 0, 0, 0 , 0 )
, Conn_1G_4M1 = CONNEXITY_VALUE( 1, 4, 0, 0, 0 , 0 )
, Conn_1G_5M1 = CONNEXITY_VALUE( 1, 5, 0, 0, 0 , 0 )
, Conn_1G_1M2 = CONNEXITY_VALUE( 1, 0, 1, 0, 0 , 0 )
, Conn_1G_2M2 = CONNEXITY_VALUE( 1, 0, 2, 0, 0 , 0 )
, Conn_1G_3M2 = CONNEXITY_VALUE( 1, 0, 3, 0, 0 , 0 )
, Conn_1G_4M2 = CONNEXITY_VALUE( 1, 0, 4, 0, 0 , 0 )
, Conn_1G_1M3 = CONNEXITY_VALUE( 1, 0, 0, 1, 0 , 0 )
, Conn_1G_2M3 = CONNEXITY_VALUE( 1, 0, 0, 2, 0 , 0 )
, Conn_1G_3M3 = CONNEXITY_VALUE( 1, 0, 0, 3, 0 , 0 )
, Conn_1G_4M3 = CONNEXITY_VALUE( 1, 0, 0, 4, 0 , 0 )
, Conn_1G_1M1_1M2 = CONNEXITY_VALUE( 1, 1, 1, 0, 0 , 0 )
, Conn_1G_1M1_1M3 = CONNEXITY_VALUE( 1, 1, 0, 1, 0 , 0 )
// Connexity Name | G|M1|M2|M2|Pad|Pin|
, Conn_2G_1M1 = CONNEXITY_VALUE( 2, 1, 0, 0, 0 , 0 )
, Conn_2G_2M1 = CONNEXITY_VALUE( 2, 2, 0, 0, 0 , 0 )
, Conn_2G_3M1 = CONNEXITY_VALUE( 2, 3, 0, 0, 0 , 0 )
, Conn_2G_4M1 = CONNEXITY_VALUE( 2, 4, 0, 0, 0 , 0 )
, Conn_2G_5M1 = CONNEXITY_VALUE( 2, 5, 0, 0, 0 , 0 )
, Conn_2G_1M2 = CONNEXITY_VALUE( 2, 0, 1, 0, 0 , 0 )
, Conn_2G_2M2 = CONNEXITY_VALUE( 2, 0, 2, 0, 0 , 0 )
, Conn_2G_3M2 = CONNEXITY_VALUE( 2, 0, 3, 0, 0 , 0 )
, Conn_2G_4M2 = CONNEXITY_VALUE( 2, 0, 4, 0, 0 , 0 )
, Conn_2G_1M3 = CONNEXITY_VALUE( 2, 0, 0, 1, 0 , 0 )
, Conn_2G_2M3 = CONNEXITY_VALUE( 2, 0, 0, 2, 0 , 0 )
, Conn_2G_3M3 = CONNEXITY_VALUE( 2, 0, 0, 3, 0 , 0 )
, Conn_2G_4M3 = CONNEXITY_VALUE( 2, 0, 0, 4, 0 , 0 )
, Conn_2G_1M1_1M2 = CONNEXITY_VALUE( 2, 1, 1, 0, 0 , 0 )
// Connexity Name | G|M1|M2|M2|Pad|Pin|
, Conn_3G_1M1 = CONNEXITY_VALUE( 3, 1, 0, 0, 0 , 0 )
, Conn_3G_2M1 = CONNEXITY_VALUE( 3, 2, 0, 0, 0 , 0 )
, Conn_3G_3M1 = CONNEXITY_VALUE( 3, 3, 0, 0, 0 , 0 )
, Conn_3G_4M1 = CONNEXITY_VALUE( 3, 4, 0, 0, 0 , 0 )
, Conn_3G_1M2 = CONNEXITY_VALUE( 3, 0, 1, 0, 0 , 0 )
, Conn_3G_2M2 = CONNEXITY_VALUE( 3, 0, 2, 0, 0 , 0 )
, Conn_3G_1M3 = CONNEXITY_VALUE( 3, 0, 0, 1, 0 , 0 )
, Conn_3G_2M3 = CONNEXITY_VALUE( 3, 0, 0, 2, 0 , 0 )
, Conn_3G_3M3 = CONNEXITY_VALUE( 3, 0, 0, 3, 0 , 0 )
, Conn_3G_4M3 = CONNEXITY_VALUE( 3, 0, 0, 4, 0 , 0 )
// Connexity Name | G|M1|M2|M2|Pad|Pin|
, Conn_4G_1M1 = CONNEXITY_VALUE( 4, 1, 0, 0, 0 , 0 )
, Conn_4G_2M1 = CONNEXITY_VALUE( 4, 2, 0, 0, 0 , 0 )
, Conn_4G_3M1 = CONNEXITY_VALUE( 4, 3, 0, 0, 0 , 0 )
, Conn_4G_4M1 = CONNEXITY_VALUE( 4, 4, 0, 0, 0 , 0 )
, Conn_4G_1M2 = CONNEXITY_VALUE( 4, 0, 1, 0, 0 , 0 )
, Conn_4G_1M3 = CONNEXITY_VALUE( 4, 0, 0, 1, 0 , 0 )
, Conn_1G_1Pad = CONNEXITY_VALUE( 1, 0, 0, 0, 1 , 0 )
, Conn_2G_1Pad = CONNEXITY_VALUE( 2, 0, 0, 0, 1 , 0 )
, Conn_3G_1Pad = CONNEXITY_VALUE( 3, 0, 0, 0, 1 , 0 )
, Conn_1G_1PinM2 = CONNEXITY_VALUE( 1, 0, 1, 0, 0 , 1 )
, Conn_2G_1PinM2 = CONNEXITY_VALUE( 2, 0, 1, 0, 0 , 1 )
};
#undef CONNEXITY_VALUE
enum TopologyFlag { Global_Vertical_End = 0x00000001
, Global_Horizontal_End = 0x00000002
, Global_Horizontal = 0x00000004
, Global_Vertical = 0x00000008
, Global_Turn = 0x00000010
, Global_Fork = 0x00000020
, Global_Fixed = 0x00000040
, Global_End = Global_Vertical_End | Global_Horizontal_End
, Global_Split = Global_Horizontal | Global_Vertical | Global_Fork
};
// Attributes.
private:
static map<Component*,AutoSegment*> _routingPadAutoSegments;
static vector<AutoSegment*> _toFixSegments;
static unsigned int _degree;
ForkStack _forks;
UConnexity _connexity;
unsigned int _topology;
Net* _net;
GCell* _gcell;
AutoContact* _sourceContact;
AutoContact* _southWestContact;
AutoContact* _northEastContact;
Hook* _fromHook;
vector<Hook*> _easts;
vector<Hook*> _wests;
vector<Hook*> _norths;
vector<Hook*> _souths;
vector<RoutingPad*> _routingPads;
// Sort classes.
public:
class SortHookByX {
public:
inline SortHookByX ( uint64_t flags );
inline bool operator() ( Hook* h1, Hook* h2 );
protected:
uint64_t _flags;
};
class SortHookByY {
public:
inline SortHookByY ( uint64_t flags );
inline bool operator() ( Hook* h1, Hook* h2 );
protected:
uint64_t _flags;
};
class SortRpByX {
public:
inline SortRpByX ( uint64_t flags );
inline bool operator() ( Component* rp1, Component* rp2 );
private:
uint64_t _flags;
};
class SortRpByY {
public:
inline SortRpByY ( uint64_t flags );
inline bool operator() ( Component* rp1, Component* rp2 );
protected:
uint64_t _flags;
};
};
inline NetBuilder::UConnexity NetBuilder::getConnexity () const { return _connexity; }
inline ForkStack& NetBuilder::getForks () { return _forks; }
inline unsigned int NetBuilder::getStateG () const { return _connexity.fields.globals; }
inline GCell* NetBuilder::getGCell () const { return _gcell; }
inline Net* NetBuilder::getNet () const { return _net; }
inline unsigned int NetBuilder::getTopology () const { return _topology; }
inline vector<RoutingPad*>& NetBuilder::getRoutingPads () { return _routingPads; }
inline Hook* NetBuilder::north ( size_t i ) const { return (i<_norths.size()) ? _norths[i] : NULL; }
inline Hook* NetBuilder::south ( size_t i ) const { return (i<_souths.size()) ? _souths[i] : NULL; }
inline Hook* NetBuilder::east ( size_t i ) const { return (i<_easts .size()) ? _easts [i] : NULL; }
inline Hook* NetBuilder::west ( size_t i ) const { return (i<_wests .size()) ? _wests [i] : NULL; }
inline void NetBuilder::setBothCornerContacts ( AutoContact* ac ) { _southWestContact = _northEastContact = ac; }
template< typename BuilderT >
void NetBuilder::load ( AnabaticEngine* engine, Net* net ) { BuilderT()._load(engine,net); }
// -------------------------------------------------------------------
// Class : "NetBuilder::SortRpByX".
inline NetBuilder::SortRpByX::SortRpByX ( uint64_t flags )
: _flags(flags)
{ }
inline bool NetBuilder::SortRpByX::operator() ( Component* rp1, Component* rp2 )
{
DbU::Unit x1 = rp1->getCenter().getX();
DbU::Unit x2 = rp2->getCenter().getX();
if (x1 == x2) return false;
return (_flags & NetBuilder::SortDecreasing) xor (x1 < x2);
}
// -------------------------------------------------------------------
// Class : "NetBuilder::SortRpByY".
inline NetBuilder::SortRpByY::SortRpByY ( uint64_t flags )
: _flags(flags)
{ }
inline bool NetBuilder::SortRpByY::operator() ( Component* rp1, Component* rp2 )
{
DbU::Unit y1 = rp1->getCenter().getY();
DbU::Unit y2 = rp2->getCenter().getY();
if (y1 == y2) return false;
return (_flags & NetBuilder::SortDecreasing) xor (y1 < y2);
}
// -------------------------------------------------------------------
// Class : "NetBuilder::SortHookByX".
inline NetBuilder::SortHookByX::SortHookByX ( uint64_t flags )
: _flags(flags)
{ }
inline bool NetBuilder::SortHookByX::operator() ( Hook* h1, Hook* h2 )
{
DbU::Unit x1 = 0;
DbU::Unit x2 = 0;
Horizontal* hh1 = dynamic_cast<Horizontal*>(h1->getComponent());
Horizontal* hh2 = dynamic_cast<Horizontal*>(h2->getComponent());
Vertical* vv1 = dynamic_cast<Vertical*> (h1->getComponent());
Vertical* vv2 = dynamic_cast<Vertical*> (h2->getComponent());
if (hh1) x1 = std::min( hh1->getSource()->getX(), hh1->getTarget()->getX() );
else if (vv1) x1 = vv1->getX();
else x1 = h1->getComponent()->getCenter().getX();
if (hh2) x2 = std::min( hh2->getSource()->getX(), hh2->getTarget()->getX() );
else if (vv2) x2 = vv2->getX();
else x2 = h2->getComponent()->getCenter().getX();
if (x1 == x2) return false;
return (_flags & NetBuilder::SortDecreasing) xor (x1 < x2);
}
// -------------------------------------------------------------------
// Class : "NetBuilder::SortHookByY".
inline NetBuilder::SortHookByY::SortHookByY ( uint64_t flags )
: _flags(flags)
{ }
inline bool NetBuilder::SortHookByY::operator() ( Hook* h1, Hook* h2 )
{
DbU::Unit y1 = 0;
DbU::Unit y2 = 0;
Horizontal* hh1 = dynamic_cast<Horizontal*>(h1->getComponent());
Horizontal* hh2 = dynamic_cast<Horizontal*>(h2->getComponent());
Vertical* vv1 = dynamic_cast<Vertical*> (h1->getComponent());
Vertical* vv2 = dynamic_cast<Vertical*> (h2->getComponent());
if (vv1) y1 = std::min( vv1->getSource()->getY(), vv1->getTarget()->getY() );
else if (hh1) y1 = hh1->getY();
else y1 = h1->getComponent()->getCenter().getX();
if (vv2) y2 = std::min( vv2->getSource()->getY(), vv2->getTarget()->getY() );
else if (hh2) y2 = hh2->getY();
else y2 = h2->getComponent()->getCenter().getY();
if (y1 == y2) return false;
return (_flags & NetBuilder::SortDecreasing) xor (y1 < y2);
}
}
#endif // ANABATIC_NET_BUILDER_H

View File

@ -0,0 +1,42 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2008-2016, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | A n a b a t i c - Routing Toolbox |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Header : "./anabatic/NetBuilderHV.h" |
// +-----------------------------------------------------------------+
#ifndef ANABATIC_NET_BUILDER_HV_H
#define ANABATIC_NET_BUILDER_HV_H
#include "anabatic/NetBuilder.h"
namespace Anabatic {
// -----------------------------------------------------------------
// Class : "NetBuilderHV".
class NetBuilderHV : public NetBuilder {
public:
NetBuilderHV ();
virtual ~NetBuilderHV ();
virtual void doRp_AutoContacts ( GCell*, Component*, AutoContact*& source, AutoContact*& target, uint64_t flags );
virtual AutoContact* doRp_Access ( GCell*, Component*, uint64_t flags );
private:
virtual void _do_1G_1M1 ();
virtual void _do_1G_xM1 ();
};
} // Anabatic namespace.
#endif // ANABATIC_NET_BUILDER_HV_H

View File

@ -260,6 +260,10 @@ class Net : public Entity {
public: void _setNextOfCellNetMap(Net* net) {_nextOfCellNetMap = net;}; public: void _setNextOfCellNetMap(Net* net) {_nextOfCellNetMap = net;};
public: struct CompareByName {
inline bool operator() ( const Net* lhs, const Net* rhs ) const { return lhs->getName() < rhs->getName(); }
};
}; };