// -*- C++ -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC/LIP6 2008-2010, All Rights Reserved // // =================================================================== // // $Id$ // // x-----------------------------------------------------------------x // | | // | C O R I O L I S | // | K a t a b a t i c - Routing Toolbox | // | | // | Author : Jean-Paul CHAPUT | // | E-mail : Jean-Paul.Chaput@asim.lip6.fr | // | =============================================================== | // | C++ Module : "./LoadGrByNet.cpp" | // | *************************************************************** | // | U p d a t e s | // | | // x-----------------------------------------------------------------x #include #include #include "hurricane/Bug.h" #include "hurricane/Error.h" #include "hurricane/Warning.h" #include "hurricane/DebugSession.h" #include "hurricane/Layer.h" #include "hurricane/Technology.h" #include "hurricane/DataBase.h" #include "hurricane/Net.h" #include "hurricane/NetExternalComponents.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/RoutingGauge.h" #include "crlcore/Measures.h" #include "katabatic/AutoContact.h" #include "katabatic/AutoSegment.h" #include "katabatic/GCellGrid.h" #include "katabatic/KatabaticEngine.h" namespace { /*! \defgroup loadGlobalRouting 2. Global Routing Loading (internal) * * This module documents how the global routing built by \c Knik is * loaded into the \c Katabatic data-base. It is intented for developpers * only. */ //! \addtogroup loadGlobalRouting //! \{ /*! \enum GCellConfiguration::Topology * set of flags used to build the topology of a GCell. * \see GCellConfiguration::_topology */ /*! \var GCellConfiguration::GLOBAL_VERTICAL_END * The GCell has exactly one global, which is either from the north * or south side. */ /*! \var GCellConfiguration::GLOBAL_HORIZONTAL_END * The GCell has exactly one global, which is either from the east * or west side. */ /*! \var GCellConfiguration::GLOBAL_HORIZONTAL * The GCell has exactly two global, which are east \& west * (straight horizontal). */ /*! \var GCellConfiguration::GLOBAL_VERTICAL * The GCell has exactly two global, which are north \& south * (straight vertical). */ /*! \var GCellConfiguration::GLOBAL_BEND * The GCell has exactly two global, which are perpandicular. * For example : east \& south. */ /*! \var GCellConfiguration::GLOBAL_FORK * The GCell has three or four globals. */ /*! \var GCellConfiguration::GLOBAL_END * Mask value : the GCell has one global, either vertical or horizontal. */ /*! \var GCellConfiguration::GLOBAL_SPLIT * Mask value used by some functions as a mask argument to * _GCell_GlobalContacts() tell if AutoContact must be splitted or not. * */ /*! \union GCellConfiguration::UState * \brief State of the GCellConfiguration (\b internal). * * This union allows the GCellConfiguration to be accessed as * separate fields : * * And as a unique integer value : * * This implementation mixing \c union and \c struct should be portable, * I've faith in compilers :-) * * \see GCellConfiguration. */ /*! \class GCellConfiguration * \brief Build the wiring for a Net inside a GCell (\b internal). * * \see \ref buildRules. */ /*! \var UState GCellConfiguration::_state; * An integer value summarizing the state of the \c GCell. It counts * global wires, and \c Plug/Pin by layer. */ /*! \var unsigned int GCellConfiguration::_topology; * An integer value summarizing the topology of the globals AutoSegment * of the GCell. * * \see Topology, _GCell_GlobalContacts(). */ /*! \var Net* GCellConfiguration::_net; * The current \c Net we are building (guessed from the \c fromSplitter). */ /*! \var CGell* GCellConfiguration::_gcell; * The \c GCell in which we are (guessed from the \c GCell). */ /*! \var unsigned int GCellConfiguration::_fromHook; * By which side of the \c GCell are we coming in. */ /*! \var AutoContact* GCellConfiguration::_sourceContact; * The AutoContact from the previously processed \c GCell. */ /*! \var AutoContact* GCellConfiguration::_southWestContact; * The South West AutoContact of the current \c GCell. */ /*! \var AutoContact* GCellConfiguration::_northEastContact; * The North East AutoContact of the current \c GCell. * (may be equal to _southWestContact, if there's only one AutoContact). */ /*! \var Hook* GCellConfiguration::_east; * The SplitterContact of the east side of the \c GCell (may be \c NULL * if none is present). */ /*! \var Hook* GCellConfiguration::_west; * The SplitterContact of the west side of the \c GCell (may be \c NULL * if none is present). */ /*! \var Hook* GCellConfiguration::_north; * The SplitterContact of the north side of the \c GCell (may be \c NULL * if none is present). */ /*! \var Hook* GCellConfiguration::_south; * The SplitterContact of the south side of the \c GCell (may be \c NULL * if none is present). */ /*! \var vector GCellConfiguration::_routingPads; * The table of \c RoutingPad associated to \c Plug/Pin. */ /*! \function GCellConfiguration::GCellConfiguration ( GCellGrid* gcellGrid, Hook* fromHook, AutoContact* sourceContact=NULL ) * \param gcellGrid The \c GCell where we are. * \param fromHook From where do we enter the \c GCell. * \param sourceContact The global routing AutoContact from the previously * processed \c GCell. May be \c NULL for the first * \c GCell of a \c Net. * * Constructor (see \ref secUsingGCell). */ /*! \function unsigned int GCellConfiguration::getStateG () const; * \return The composite state value. */ /*! \function void GCellConfiguration::construct ( ForkStack& forks ); * Build the GCell wires (see \ref secUsingGCell). */ /*! \function void GCellConfiguration::_GCell_GlobalContacts ( bool split, AutoContact* southWestContact=NULL, AutoContact* northEastContact=NULL ); * create AutoContact needed for global wiring. If \e split is * \False one contact is created and set into both _southWestContact * _northEastContact. Otherwise two separated contacts are created. * * \see GCellConfiguration::_topology, Topology. */ /*! \function AutoContact* GCellConfiguration::_GCell_rp_L2H ( RoutingPad* rp, AutoContact* target=NULL, bool hcollapse=false ) * \param rp Source RoutingPad. * \param target Ending AutoContact (created if needed). * \param hcollapse collapse the horizontal AutoSegment. * * Draw horizontal AutoSegment from the center of a RoutingPad. * \image html GCellConfiguration-10.png "_GCell_rp_L2H" * \image latex GCellConfiguration-10.pdf "_GCell_rp_L2H" width=0.2\textwidth */ /*! \function AutoContact* GCellConfiguration::_GCell_rp_L2H_L3V ( RoutingPad* rp, AutoContact* target=NULL, bool hcollapse=false, bool vcollapse=false ) * \param rp Source RoutingPad. * \param target Ending AutoContact (created if needed). * \param hcollapse collapse the horizontal AutoSegment. * \param vcollapse collapse the vertical AutoSegment. * * Draw a simple bend from the center of a RoutingPad. The horizontal * AutoSegment comes first (starting from the source). Both AutoSegments * are flagged as \e terminal. * \image html GCellConfiguration-11.png "_GCell_rp_L2H_L3V" * \image latex GCellConfiguration-11.pdf "_GCell_rp_L2H_L3V" width=0.2\textwidth */ /*! \function AutoContact* GCellConfiguration::_GCell_rp_StairCaseH ( RoutingPad* rp1, RoutingPad* rp2 ) * * Draw an horizontal staircase (\b HVH) between two RoutingPad. * \image html GCellConfiguration-12.png "_GCell_rp_StairCaseH" * \image latex GCellConfiguration-12.pdf "_GCell_rp_StairCaseH" width=0.4\textwidth */ /*! \function AutoContact* GCellConfiguration::_GCell_rp_StairCaseV ( RoutingPad* rp1, RoutingPad* rp2 ) * Draw a vertical staircase (\b VHV) between two RoutingPad. * \image html GCellConfiguration-13.png "_GCell_rp_StairCaseV" * \image latex GCellConfiguration-13.pdf "_GCell_rp_StairCaseV" width=0.1\textwidth */ /*! \function AutoContact* GCellConfiguration::_GCell_L3V_L2H ( AutoContact* source, AutoContact* target=NULL, bool hcollapse=false, bool vcollapse=false, bool terminal=false ) * \param source The starting AutoContact. * \param target The ending AutoContact (created if needed). * \param hcollapse collapse the horizontal AutoSegment. * \param vcollapse collapse the vertical AutoSegment. * \param terminal collapse the horizontal AutoSegment. * * Draw a simple bend source to target AutoContact. If target is \e NULL, create * the target. The \e terminal parameter will apply to both horizontal \& vertical * AutoSegment. The horizontal AutoSegment comes first. * \image html GCellConfiguration-15.png "_GCell_L3V_L2H" * \image latex GCellConfiguration-15.pdf "_GCell_L3V_L2H" width=0.2\textwidth */ /*! \function AutoContact* GCellConfiguration::_GCell_L2H_L3V ( AutoContact* source, AutoContact* target=NULL, bool hcollapse=false, bool vcollapse=false, bool terminal=false ) * \param source The starting AutoContact. * \param target The ending AutoContact (created if needed). * \param hcollapse collapse the horizontal AutoSegment. * \param vcollapse collapse the vertical AutoSegment. * \param terminal collapse the horizontal AutoSegment. * * Draw a simple bend source to target AutoContact. If target is \e NULL, create * the target. The \e terminal parameter will apply to both horizontal \& vertical * AutoSegment. The vertical AutoSegment comes first. * \image html GCellConfiguration-16.png "_GCell_L2H_L3V" * \image latex GCellConfiguration-16.pdf "_GCell_L2H_L3V" width=0.2\textwidth */ /*! \function void GCellConfiguration::_GCell_1G_1L1 () * Optimized topology for one \e metal1 terminal and one global AutoSegment. */ /*! \function void GCellConfiguration::_GCell_1G_xL1 () * * Topology for one global AutoSegment and any number of \e metal1 terminals. * \image html GCellConfiguration-3.png "_GCell_1G_xL1" * \image latex GCellConfiguration-3.pdf "_GCell_1G_xL1" width=0.8\textwidth */ /*! \function void GCellConfiguration::_GCell_xG_xL1_xL3 () * * Topology for two or more global AutoSegment and any number of \e metal1 or * \e metal3 terminals. They share the same topology since they are are both * vertical and connected through \e metal2. * * Building rules : *
    *
  • Global AutoContact are always splitted except when in the * \e Bend topology. *
  • Local terminal AutoSegment are always attached to the South * West AutoContact except in the Straight Horizontal * topology or when there is no South global segment. *
* * \image html GCellConfiguration-14.png "Straight Horizontal" * \image html GCellConfiguration-21.png "Straight Vertical \& Fork (L1 horizontal)" * \image html GCellConfiguration-22.png "Forks (L1 horizontal)" * \image html GCellConfiguration-23.png "Forks (L1 vertical)" * \image html GCellConfiguration-24.png "Bend" * \image latex GCellConfiguration-14.pdf "Straight Horizontal" width=0.4\textwidth * \image latex GCellConfiguration-21.pdf "Straight Vertical (L1 horizontal)" width=0.8\textwidth * \image latex GCellConfiguration-22.pdf "Forks (L1 horizontal)" width=0.8\textwidth * \image latex GCellConfiguration-23.pdf "Forks (L1 vertical)" width=0.8\textwidth * \image latex GCellConfiguration-24.pdf "Bend" width=0.4\textwidth */ /*! \function void GCellConfiguration::_GCell_xG_xL2() * * Topology for any global AutoSegment and any number of \e metal2 terminals. * * Building rules : *
    *
  • Global AutoContact are always splitteds, except for the * \e Bend and \e End topology. *
  • Anchor the local connecting AutoContact on the biggest * \RoutingPad, except for the Straight Horizontal * and the \e End (horizontal) topology. In thoses cases, * uses the leftmost or rightmost \RoutingPad. *
  • Prefers vertical AutoSegment to start from the \RoutingPad, * this needs East and/or West global to be present. *
* * \image html GCellConfiguration-30.png "Straight H/V" * \image html GCellConfiguration-31.png "Forks with East \& West" * \image html GCellConfiguration-32.png "Forks without East or West" * \image html GCellConfiguration-33.png "Complete Fork" * \image html GCellConfiguration-34.png "All Bends" * \image html GCellConfiguration-35.png "East or West End" * \image html GCellConfiguration-36.png "North or South End" * \image latex GCellConfiguration-30.pdf "Straight H/V" width=0.95\textwidth * \image latex GCellConfiguration-31.pdf "Forks with East \& West" width=0.95\textwidth * \image latex GCellConfiguration-32.pdf "Forks without East or West" width=0.95\textwidth * \image latex GCellConfiguration-33.pdf "Complete Fork" width=0.48\textwidth * \image latex GCellConfiguration-34.pdf "All Bends" width=0.48\textwidth * \image latex GCellConfiguration-35.pdf "East or West End" width=0.95\textwidth * \image latex GCellConfiguration-36.pdf "North or South End" width=0.48\textwidth */ /*! \function void GCellConfiguration::_GCell_xG_1L1_1L2 () * * Topology for one or more global AutoSegment, one \e metal1 and one * \e metal2 terminals. * * Building rules : *
    *
  • Global AutoContact are always splitted except when in the * \e Bend or \e End topology. *
  • Local terminal AutoSegment are always attached to an * AutoContact with one vertical global, the South West * whenever possible (South global present). *
* * \image html GCellConfiguration-40.png "End H/V" * \image html GCellConfiguration-41.png "Straight H/V" * \image html GCellConfiguration-42.png "Forks without East or West" * \image html GCellConfiguration-43.png "Forks without North or South" * \image html GCellConfiguration-44.png "Complete Fork" * \image html GCellConfiguration-45.png "Any Bend" * \image latex GCellConfiguration-40.pdf "End H/V" width=0.95\textwidth * \image latex GCellConfiguration-41.pdf "Straight H/V" width=0.95\textwidth * \image latex GCellConfiguration-42.pdf "Forks without East or West" width=0.95\textwidth * \image latex GCellConfiguration-43.pdf "Forks without North or South" width=0.95\textwidth * \image latex GCellConfiguration-44.pdf "Complete Fork" width=0.48\textwidth * \image latex GCellConfiguration-45.pdf "Any Bend" width=0.48\textwidth */ /*! \class SortRpByX * \brief \c RoutingPad \b Compare functor (\b internal) */ /*! \function inline SortRpByX::SortRpByX ( bool decreasing ); * \param decreasing Tells if the sort is done in decreasing order. * * This object is a \c Compare functor for the \c sort \c algorithm * over \c STL container made of \c RoutingPad pointers. If \c decreasing * is false the container elements will be sorted by increasing X * coordinates. Otherwise the sort is decreasing. * * See GCellConfiguration class. */ /*! \class SortRpByY * \brief \c RoutingPad \b Compare functor (\b internal) */ /*! \function inline SortRpByY::SortRpByY ( bool decreasing ); * \param decreasing Tells if the sort is done in decreasing order. * * This object is a \c Compare functor for the \c sort \c algorithm * over \c STL container made of \c RoutingPad pointers. If \c decreasing * is false the container elements will be sorted by increasing Y * coordinates. Otherwise the sort is decreasing. * * See GCellConfiguration class. */ /* \function RoutingPad* lookupOrCreate ( Plug* plug ); * \param plug A net's plug. * \return A RoutingPad associated to the plug. * * create a \RoutingPad for the plug or find an already created * one. To keep track */ /* \function RoutingPad* getRoutingPad ( Plug* plug, const Box& boundingBox ); * \param plug A net's plug. * \param boundingBox An area. * \return A RoutingPad associated to the plug. * * creates a RoutingPad built on plug. Select the best external * component of the master net to uses : the largest component * in the highest layer in the given boundingBox area. * * If no component is found under the boundingBox area a * warning is issued and a component outside the area will be * used. */ /* \function RoutingPad* getRoutingPad ( Pin* pin ); * \param pin A net's pin. * \return A RoutingPad associated to the pin. * * Unlike for the RoutingPad from a plug, there is no choice * for the external component : it's the pin itself. */ /* \function bool arePerpandicular ( unsigned int dir1, unsigned int dir2 ); * \param dir1 First direction. * \param dir2 Second direction. * \return \True if the two direction are perpandiculars. As it proceed * with bits operators first and second direction could contains * other flags than \HORIZONTAL and \VERTICAL. */ /* \function unsigned int areOppositeSPs ( SplitterContact* spc1, SplitterContact* spc2 ); * \param spc1 First SplitterContact. * \param spc2 Second SplitterContact. * \return \True if the two SplitterContact are from the opposites Fences * of a Nimbox. */ /* \function Point getEastPosition ( RoutingPad* rp ); * \return Between the source and target point, the one with the greatest * X coordinate (source, if equal). */ /* \function Point getWestPosition ( RoutingPad* rp ); * \return Between the source and target point, the one with the lowest * X coordinate (target, if equal). */ /* \function Point getNorthPosition ( RoutingPad* rp ); * \return Between the source and target point, the one with the greatest * Y coordinate (source, if equal). */ /* \function Point getSouthPosition ( RoutingPad* rp ); * \return Between the source and target point, the one with the lowest * Y coordinate (target, if equal). */ /*! \function void singleGCell ( KatabaticEngine* ktbt, Net* net ); * \param ktbt A Katabatic \ToolEngine (gives the grid). * \param net The net for which to build the topology. * * This function handle the special case where a whole net * is included inside only one GCell. * * \important For the time being we assumes that the net is a two * terminal net only. If this is not the case the topology * will be incomplete an so the routing. */ /*! \class ForkStack * \brief Stack of \c Hook / AutoContact (\b internal). * * A simple stack of pair of \c Hook / AutoContact. It's used * to handle the recursivity while building a Net's initial wiring in * _loadNetGlobalRouting(). */ /*! \function void ForkStack::push ( Hook* from, AutoContact* contact ); * Stack a new pair of \c Hook / AutoContact. */ /*! \function void ForkStack::pop (); * Pop an element. The popped element is \b not returned, it's contents are lost. */ /*! \function Hook* ForkStack::getFrom () const; * \return The \c Hook on top of the stack. \c NULL if * the stack is empty. */ /*! \function Contact* ForkStack::getContact () const; * \return The \c Contact on top of the stack. \c NULL if * the stack is empty. */ //! \} /*! \defgroup buildRules 1. Rules for building wires (internal) * * * \section secACConf AutoContact configurations. * * In this section we details how an AutoContact resise itself, and * introduce some terminology. * * First we distinguish two kinds of segments attached to an AutoContact, * segments that crosses the GCell boundary are considered as global * and others are locals. * * As globals AutoSegments crosses the GCell boundaries, when their * extention is adjusted by the AutoContact we have the guarantee that * they will span from the border of the GCell to the AutoContact. * The AutoContact relies strongly on this hypothesis. * * The configuration of an AutoContact is computed in two stages : *
    *
  1. We compute the smallest box enclosing all the intersections of * global segments axis, this box is drawn in red in the figures * below. We refers this box as the "Junction Box". * In some cases the enclosing box is not sufficent to make additionnal * connections with the local segments (see figures G2.1 and G3.1), * only in those case we take them in account in the junction box. *
  2. In the second stage we extend the local segments to reach the * skeleton made by globals segments. In most cases, we do not have * choices for the extension, but in G4.3 and G4.4. *
* * orientation meaning : (west, east, south and north) *
    *
  • For global segments, it indicates which side of the GCell it * crosses. *
  • For local segments, it tells it's relative position to the * junction box. An horizontal segment will be south if it's axis * is inferior to the YMin of the junction box and north otherwise. * In the same way a vertical segment will be west if is axis is * inferior to the XMin of the junction box and east otherwise. *
* * \image html AutoContactG1-1.png "One Global Routing" * \image html AutoContactG2-1.png "Two Global Routing" * \image html AutoContactG3-1.png "Three Global Routing" * \image html AutoContactG3-2.png "Three Global Routing" * \image html AutoContactG4-1.png "Four Global Routing" * \image html AutoContactG4-2.png "Four Global Routing" * \image html AutoContactG4-3.png "Four Global Routing" * \image latex AutoContactG1-1.pdf "One Global Routing" width=0.3\textwidth * \image latex AutoContactG2-1.pdf "Two Global Routing" width=0.8\textwidth * \image latex AutoContactG3-1.pdf "Three Global Routing" width=0.8\textwidth * \image latex AutoContactG3-2.pdf "Three Global Routing" width=0.8\textwidth * \image latex AutoContactG4-1.pdf "Four Global Routing" width=0.8\textwidth * \image latex AutoContactG4-2.pdf "Four Global Routing" width=0.8\textwidth * \image latex AutoContactG4-3.pdf "Four Global Routing" width=0.8\textwidth * * * The "four sides" box problem : * * In cases G4.3 and G4.4 we must uses three sides of the junction box * to perform the connection. To minimize wirelength we uses the two small * sides and one of the long size. Which one is the question... For the * moment we systematically choose the lower one (that is west or south). * A problem arises when, by displacing segments, the router change which * side is the shortest one. A Solution to this problem is proposed * in \ref ssecFaultyAutoContact. * * * \section secSegStruct Routing Segments Organisation. * * Router movements : *
    *
  • Horizontal segments : only translated vertically, * extensions are not changed, the segment do not * shrink neither grow. *
  • Vertical segments : only translated horizontally. * Extensions remains the same. *
* * Autocontact adjustements : * * When an horizontal segment is vertically moved, vertical ones * that are linked to it through AutoContact must have their * extension adapted : either shrinked or elongated. * * \image html AutoContact-2.png "Segment Structure" * \image html AutoContact-3.png "Segment Displacement" * \image latex AutoContact-2.pdf "Segment Structure" width=0.5\textwidth * \image latex AutoContact-3.pdf "Segment Displacement" width=0.5\textwidth * * * \subsection ssecFaultyAutoContact AutoContact Geometry restrictions. * * \important The property we want to emphasis here is that whenever a * segment is moved by the router the size of it's * source or target extensions must not change. Only the * extensions of segments perpandicularly connected to it will * change. * Unfortunatly, not all topologies will ensure that property. * The following figures shows all those invalid topologies, and * their correct counterparts. We are looking here from an AutoContact * point of view : how does the AutoContact resizes when an AutoSegment * moves. * * First case * * Three globals (\b G1, \b G2, \b G3) and one local * (\b L1). \b L1 is perpandicular to \b G1 and \b G3. According to the * AutoContact sizing specification, \b L1 will be extended to reach * either \b G1 or \b G3, according to it's relative position from * \b G2. Problem arises when the router moves \b L1 and crosses the * position of \b G2. In the figure below, \b L1 is moved up so it * will extend to \b G3 instead of \b G1. So \b L1 horizontal size * will change as it is moved. * * \image html AutoContactG3-3.png "Three Globals : Problem" * \image latex AutoContactG3-3.pdf "Three Globals : Problem" width=0.8\textwidth * * To avoid the problem, simply split \b AC1 in two AutoContact (\b AC-SW \& * \b AC-NE). This way, \b L1 will always be extented to reach the same * global AutoSegment (here : \b G1). * * \image html AutoContactG3-4.png "Three Globals : Solution" * \image latex AutoContactG3-4.pdf "Three Globals : Solution" width=0.8\textwidth * * Second case * * Four globals (\b G1 to \b G4). This is the * four side box problem (see \ref secACConf). To minimize wirelength, * the \b AC1 AutoContact will uses only three side of the junction box : * the two shortest and one of the longest. The problem shows when \b G3 * is moved to the right changing shortest and longest sides. * \b G2 is then shrinked (which is not a problem because it's perpandicular * to \b G3), and \b G3 is extended, which is the problem. * * \image html AutoContactG4-4.png "Four Globals : Problem" * \image latex AutoContactG4-4.pdf "Four Globals : Problem" width=0.8\textwidth * * As for the first case, we choose to split the \b AC1 AutoContact in two * (\b AC-SW \& \b AC-NE) and link them with one local AutoSegment (horizontal). * We arbitrarily group the globals in a South West AutoContact * (\b AC-SW) and North East AutoContact (\b AC-NE). The connexion * between them is horizontal because there is slighly more horizontal * resources. * * \image html AutoContactG4-5.png "Four Globals : Solution" * \image latex AutoContactG4-5.pdf "Four Globals : Solution" width=0.8\textwidth * * \important We now can express a more synthetic building rule : an AutoContact * must never contain more than two global segments. * This rule allow a simpler managment mechanism for the AutoContact * self sizing procedure (i.e. : speedup). * * * \subsection ssecFaultyTopologies Topologies Leading to Gaps. * * First Case * * The figure "incomplete AutoContact 1" shows how two contiguous local * AutoSegments could lead to a gap in the AutoContact generated * geometry. The local AutoSegment \b L2 is the only vertical component of * the red AutoContact, thus it's source point will be moved to ensure * the vertical connection between \b G1 and \b G2. In the other hand, * the target of \b L2 is bound by the horizontal position of \b L1. * So, if \b G2 (or \b G1) is moved above \b L1 a gap will appear whithin the * AutoContact geometry. * * \image html GCellConfiguration-1.png "incomplete AutoContact 1" * \image latex GCellConfiguration-1.pdf "incomplete AutoContact 1" width=0.8\textwidth * * To avoid this problem, the red AutoContact have to be split in two * AutoContacts linked together though a third local AutoSegment \b L3, * as shown on figure "Correct topology". Note that, in this figure we * present an unlikely case : most of the time \b L3 will have a zero * size, and if not, would uses the same track as \b L2. The \b L3 AutoSegment * will have the correct length because is source moves with \b G2 and it's * target with \b G1 (or the other way around, according to the relative * horizontal positions of \b G1 and \b G2). Another point to note is that * there can only be (at most) two global horizontal AutoSegment, one on * left and one on the right. And finally, one say that we could have * suppressed the \b L2 AutoSegment, but in this case it would forces * the alignement of either \b G1 or \b G2 with \b L1, which could be a * severe constraint. * * \image html GCellConfiguration-2.png "Correct Topology 1" * \image latex GCellConfiguration-2.pdf "Correct Topology 1" width=0.8\textwidth * * Second Case * * The following figure "Invalid Configuration 2" illustrate the problem * that arises when a local AutoSegment is used to connect more than two * vertical AutoSegments. In other words, is not a mere "dog leg" (double bend). * This implies that on a least one supporting AutoContact there is more * than one vertical AutoSegment attached (\e AC2 in our case). * * As per definition, the \e L4 AutoSegment has it's source X position sets * by \e AC1 and it's target X position sets by \e AC2. On \e AC1 there will * be no problems : the X position is given by \e L3 and we always can * extend \e L4 to reach it. On the other end, for \e AC2, as the connexity * is ensured only by extending/shrinking the AutoSegment target X position * we will never be able to reach both \e L7 \& L6 as they are on either * side of \e L3. Only one of them will be reached, \e L6 or \e L7 * depending on how the AutoContact will expand. * * To avoid this problem, we introduce the AutoContact horizontal and/or * vertical locking. For instance, when an AutoContact is vertically * locked (says \e AC2), then \e L6 \& \e L7 will be kept at the same * X coordinate. Note that this is not done by the AutoContact itself * but rather by declaring \e L6 \& \e L7 as collapsed (as if they where * connected through a collapsed horizontal AutoSegment). * * \image html GCellConfiguration-20.png "incomplete Topology 2 (detail)" * \image latex GCellConfiguration-20.pdf "incomplete Topology 2 (detail)" width=0.8\textwidth * * \image html GCellConfiguration-18.png "incomplete Topology 2 (context)" * \image latex GCellConfiguration-18.pdf "incomplete Topology 2 (context)" width=0.8\textwidth * * \image html GCellConfiguration-19.png "Correct Topology 2" * \image latex GCellConfiguration-19.pdf "Correct Topology 2" width=0.8\textwidth * * For more details about the AutoSegment collapsing whereabouts, see * \ref collapseCanonical. * * * \section secLegalCatalog Catalog of Legal Topologies. * * Summarize the set of legal topologies regarding the following * rules : *
    *
  • Rule 1 : An AutoContact must have at least one * horizontal and one vertical attached to it. With the only * expeption of those anchored on RoutingPad. *
  • Rule 2 : An AutoContact must never have more than * two global AutoSegment. With the only exception of * AutoContacts with exactly three globals (and no locals). *
  • Rule 3 : When the side of a Junction Box is made * of a local AutoSegment, perpandicular AutoSegments must be * locked together. *
  • Rule 4 : AutoContact with two globals and any number * of local must be lockeds in at least one direction. *
* * Topologies for Dog-Leg (no-fork). * * First figure illustrate why rule 1 is needed. Second, the dog * leg general case, and the latest how to circumvent rule 1 by * collapsing \b L2. * * \image html LegalConstruct-1.png "Legal Construct : dog leg" * \image latex LegalConstruct-1.pdf "Legal Construct : dog leg" width=0.8\textwidth * * Topologies for Elementary Local Fork. * * Illustrate how to build local fork, according to the number of global * AutoSegments part of the fork. First and second case with the side of * the Junction Box made of a global AutoSegment : no constraint. * Third case : the side of the Junction Box is made of a local * AutoSegment, then perpandicular AutoSegment on \b AC2 must be * linked (here : vertical link) in compliance with Rule 3. * * \image html LegalConstruct-2.png "Legal Construct : elementary local fork" * \image latex LegalConstruct-2.pdf "Legal Construct : elementary local fork" width=0.8\textwidth * * Topologies for Global Fork (3 branches). * * To comply with Rule 2, we must split the AutoContact in two : * the South West (\b AC-SW) and North East (\b AC-NE). Whenever it's possible * we join them through an horizontal AutoSegment. It's not possible if either * \b G2 or \b G3 is missing. * * \image html LegalConstruct-4.png "Legal Construct : Global fork (3 branches, 1)" * \image html LegalConstruct-5.png "Legal Construct : Global fork (3 branches, 2)" * \image latex LegalConstruct-4.pdf "Legal Construct : Global fork (3 branches, 1)" width=0.8\textwidth * \image latex LegalConstruct-5.pdf "Legal Construct : Global fork (3 branches, 2)" width=0.8\textwidth * * Topology for Global Fork (4 branches). * * Only one possibility, as shown in the figure below. Two AutoContact * \b AC-SW \& \b AC-NE, and one horizontal AutoSegment. * * \image html LegalConstruct-6.png "Legal Construct : Global fork (4 branches)" * \image latex LegalConstruct-6.pdf "Legal Construct : Global fork (4 branches)" width=0.8\textwidth * * \important If there are local connections inside a global fork, the local * AutoSegment \b L1 will be replaced by a more complex topology. * * * \section secGCellConfiguration Using GCellConfiguration * * After the global routing stage, the final router needs to achieve * the routing topology in each GCell, for each Net. * This wiring must connect the global wires (that crosses the * GCell boundary) with any number of local terminals. * * This object is the atomic action of a recursive walk through * the \c GCells of a \c Net. The recursivity is handled through * a stack : see \c ForkStack. * * This classes uses a dictionnary of pre-defined shapes to build * the interconnect. The dictionnary relies on the following * hypothesis : *
    *
  1. The GCell is one slice height. This implies * that in almost all cases, internal terminals in the same * layer can be ordered form left to right. *
  2. If there is two or more horizontal terminals, they are * most likely aligned. *
  3. If there is two or more vertical terminals they are * not on top of each other, but rather side by side *
  4. If there are terminals in layer other than M1, we must * route through it. *
* * * \section secUsingGCell Using a GCellConfiguration object * * Obviously, we need the Nimbus global routing structure to be present, as we * uses \c Splitter to progress through the global routing. Using a * GCellConfiguration is simple enough : * *
    *
  • create a new GCellConfiguration. At this time we must * supply the \c GCell to be processed, the \Splitter from which the * \c GCell is entered and optionally a source AutoContact (from the * previously processed \c GCell). The constructor go through the * Net's ring inside the \GCell, finding \SplitterContact, \Plug and * \Pin. Location of \SplitterContact are stored according to * their positions (east/west/north/south), \RoutingPad are created * for each \c Plug/Pin and stored into a \vector. The \c _state and * \c _topology values are also computed, summarizing respectively * the number of globals and locals (by layers) and the geometry of * globals (end, straight, bend, fork) * *
  • The second step is to call the construct() method. \c construct() * works in three steps : * *
      *
    1. Draw the internal wiring of the \c GCell, using the appropriate * \c _GCell_xG_xLx() fonction. * * Calls \c _GCell_GlobalContacts(), which create the south west * (\c _southWestContact ) AutoContact and, if needed the north east * one (\c _northEastContact ). If only \c _southWestContact is created, * \c _northEastContact is set to the same value (i.e. is never \NULL). * Those AutoContacts will supply the support for global \c AutoSegment * (AutoSegment that goes to and from this \c GCell ). * * If the \c GCell has no internal terminal, then only global wiring * has to be created, and no \c _GCell_xG_xLx() function is * to be call. All we have to do is to call the \c _GCell_GlobalContacts(). * function. And in the case we go through the GCell in straight line * (aligned \c Splitter) we don't even do that. * *
    2. Draw the global routing from to previous \c GCell to the * current one. That is from \c _sourceContact to \c _southWestContact * or \c _northEastContact according to where we came from. * *
    3. Stack the pair of \c SplitterContact/AutoContact into * the forks stack, except the one we come from (tagged by * the \c _fromSP ). Here again, we stack either \c _southWestContact * or \c _northEastContact according to where we came from. *
    *
*/ using namespace std; using namespace CRL; using namespace Hurricane; using namespace Katabatic; // --------------------------------------------------------------- // Local Enum/Types. enum SegmentSide { SegmentSouth = (1<<0) , SegmentNorth = (1<<1) , SegmentWest = (1<<2) , SegmentEast = (1<<3) }; // --------------------------------------------------------------- // Local Variables. const char* invalidGCell = "Katabatic::GCellConfiguration () :\n\n" " No GCell under point.\n"; const char* mismatchGCell = "Katabatic::GCellConfiguration () :\n\n" " Contacts under two different GCells.\n"; const char* missingGCell = "Katabatic::GCellConfiguration () :\n\n" " No Contact in GCell.\n"; map __routingPadAutoSegments; // --------------------------------------------------------------- // LoadGrByNet Local Classes. struct NetCompareByName { inline bool operator() ( const Net* lhs, const Net* rhs ) const; }; inline bool NetCompareByName::operator() ( const Net* lhs, const Net* rhs ) const { return lhs->getName() < rhs->getName(); } // --------------------------------------------------------------- // LoadGrByNet Local Functions. void lookupClear () { __routingPadAutoSegments.clear (); } void setIsRoutingPadSmall ( RoutingPad* rp, bool& hsmall, bool& vsmall, bool& punctual ) { Point source = rp->getSourcePosition(); Point target = rp->getTargetPosition(); DbU::Unit width = abs ( target.getX() - source.getX() ); DbU::Unit height = abs ( target.getY() - source.getY() ); hsmall = ( width < DbU::lambda(15.0)); vsmall = ( height < DbU::lambda(15.0)); punctual = (width == 0) && (height == 0); } Hook* getSegmentOppositeHook ( Hook* hook ) { Segment* segment = static_cast( hook->getComponent() ); return segment->getOppositeHook ( hook ); } unsigned int getSegmentHookType ( Hook* hook ) { Horizontal* horizontal = dynamic_cast( hook->getComponent() ); if ( horizontal ) { if ( horizontal->getSourceX() > horizontal->getTargetX() ) cerr << Warning("Bad orientation of %s",getString(horizontal).c_str()) << endl; if ( dynamic_cast(hook) ) return SegmentEast; return SegmentWest; } Vertical* vertical = dynamic_cast( hook->getComponent() ); if ( vertical->getSourceY() > vertical->getTargetY() ) cerr << Warning("Bad orientation of %s",getString(vertical).c_str()) << endl; if ( dynamic_cast(hook) ) return SegmentNorth; return SegmentSouth; } // --------------------------------------------------------------- // Class : "SortRpByX". class SortRpByX { public: inline SortRpByX ( bool decreasing ); inline bool operator() ( RoutingPad* rp1, RoutingPad* rp2 ); protected: bool _decreasing; }; inline SortRpByX::SortRpByX ( bool decreasing ) : _decreasing(decreasing) { } inline bool SortRpByX::operator() ( RoutingPad* rp1, RoutingPad* rp2 ) { DbU::Unit x1 = rp1->getCenter().getX(); DbU::Unit x2 = rp2->getCenter().getX(); if ( x1 == x2 ) return false; return _decreasing xor ( x1 < x2 ); } // --------------------------------------------------------------- // Class : "SortRpByY". class SortRpByY { public: inline SortRpByY ( bool decreasing ); inline bool operator() ( RoutingPad* rp1, RoutingPad* rp2 ); protected: bool _decreasing; }; inline SortRpByY::SortRpByY ( bool decreasing ) : _decreasing(decreasing) { } inline bool SortRpByY::operator() ( RoutingPad* rp1, RoutingPad* rp2 ) { DbU::Unit y1 = rp1->getCenter().getY(); DbU::Unit y2 = rp2->getCenter().getY(); if ( y1 == y2 ) return false; return _decreasing xor ( y1 < y2 ); } // --------------------------------------------------------------- // 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 _stack; }; inline ForkStack::Element::Element ( Hook* from, AutoContact* contact ) : _from(from), _contact(contact) {} inline void ForkStack::pop () { if ( !_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 ) { ltrace(80) << " Stacking " << (void*)from << " " << from << " + " << contact << endl; _stack.push_back(Element(from,contact)); } // --------------------------------------------------------------- // Class : "GGellConfiguration". class GCellConfiguration { public: // Methods. GCellConfiguration ( GCellGrid* gcellGrid , Hook* fromHook , AutoContact* sourceContact=NULL ); void construct ( ForkStack& forks ); inline unsigned int getStateG () const; inline GCell* getGCell () const; static bool _GCell_rp_AutoContacts ( GCell* gcell , RoutingPad* rp , AutoContact*& source , AutoContact*& target , bool haccess ); static AutoContact* _GCell_rp_Access ( GCell* gcell , RoutingPad* rp , bool haccess , bool forceVSmall ); static AutoContact* _GCell_rp_L2H ( GCell* gcell , RoutingPad* rp , AutoContact* target =NULL , bool hcollapse=false ); static AutoContact* _GCell_rp_L2H_L3V ( GCell* gcell , RoutingPad* rp , AutoContact* target =NULL , bool hcollapse=false , bool vcollapse=false ); static void _GCell_rp_StairCaseH ( GCell* gcell , RoutingPad* rp1 , RoutingPad* rp2 ); static void _GCell_rp_StairCaseV ( GCell* gcell , RoutingPad* rp1 , RoutingPad* rp2 ); static AutoContact* _GCell_L3V_L2H ( GCell* gcell , Net* net , AutoContact* source , AutoContact* target =NULL , bool hcollapse=false , bool vcollapse=false , bool terminal =false ); static AutoContact* _GCell_L2H_L3V ( GCell* gcell , Net* net , AutoContact* source , AutoContact* target =NULL , bool hcollapse=false , bool vcollapse=false , bool terminal =false ); protected: // Internal Methods. void _GCell_GlobalContacts ( bool split , AutoContact* southWestContact=NULL , AutoContact* northEastContact=NULL ); void _GCell_1G_1L1 (); void _GCell_1G_xL1 (); void _GCell_xG_xL1_xL3 (); void _GCell_xG_1L1_1L2 (); void _GCell_xG_xL2 (); void _GCell_1G_1L3 (); void _GCell_xG_xL3 (); protected: // State Values. enum State { GCELL_0G = 0 , GCELL_2G = 2 , GCELL_3G = 3 , GCELL_4G = 4 , GCELL_0G_2L1 = 0+(2<<3) , GCELL_1G_1L1 = 1+(1<<3) , GCELL_1G_2L1 = 1+(2<<3) , GCELL_1G_3L1 = 1+(3<<3) , GCELL_1G_4L1 = 1+(4<<3) , GCELL_1G_1L2 = 1+(1<<6) , GCELL_1G_2L2 = 1+(2<<6) , GCELL_1G_3L2 = 1+(3<<6) , GCELL_1G_4L2 = 1+(4<<6) , GCELL_1G_1L3 = 1+(1<<9) , GCELL_1G_2L3 = 1+(2<<9) , GCELL_1G_3L3 = 1+(3<<9) , GCELL_1G_4L3 = 1+(4<<9) , GCELL_1G_1L1_1L2 = 1+(1<<3)+(1<<6) , GCELL_1G_1L1_1L3 = 1+(1<<3)+(1<<9) , GCELL_2G_1L1 = 2+(1<<3) , GCELL_2G_2L1 = 2+(2<<3) , GCELL_2G_3L1 = 2+(3<<3) , GCELL_2G_4L1 = 2+(4<<3) , GCELL_2G_1L2 = 2+(1<<6) , GCELL_2G_2L2 = 2+(2<<6) , GCELL_2G_3L2 = 2+(3<<6) , GCELL_2G_4L2 = 2+(4<<6) , GCELL_2G_1L3 = 2+(1<<9) , GCELL_2G_2L3 = 2+(2<<9) , GCELL_2G_3L3 = 2+(3<<9) , GCELL_2G_4L3 = 2+(4<<9) , GCELL_2G_1L1_1L2 = 2+(1<<3)+(1<<6) , GCELL_3G_1L1 = 3+(1<<3) , GCELL_3G_2L1 = 3+(2<<3) , GCELL_3G_3L1 = 3+(3<<3) , GCELL_3G_4L1 = 3+(4<<3) , GCELL_3G_1L2 = 3+(1<<6) , GCELL_3G_1L3 = 3+(1<<9) , GCELL_3G_2L3 = 3+(2<<9) , GCELL_3G_3L3 = 3+(3<<9) , GCELL_3G_4L3 = 3+(4<<9) , GCELL_4G_1L1 = 4+(1<<3) , GCELL_4G_2L1 = 4+(2<<3) , GCELL_4G_3L1 = 4+(3<<3) , GCELL_4G_4L1 = 4+(4<<3) , GCELL_4G_1L3 = 4+(1<<9) }; protected: // Topologies Flags/Values. enum Topology { GLOBAL_VERTICAL_END = (1<<0) , GLOBAL_HORIZONTAL_END = (1<<1) , GLOBAL_HORIZONTAL = (1<<2) , GLOBAL_VERTICAL = (1<<3) , GLOBAL_BEND = (1<<4) , GLOBAL_FORK = (1<<5) , GLOBAL_END = GLOBAL_VERTICAL_END | GLOBAL_HORIZONTAL_END , GLOBAL_SPLIT = GLOBAL_HORIZONTAL | GLOBAL_VERTICAL | GLOBAL_FORK }; protected: // State Attribute. union UState { unsigned int state; struct { unsigned int globals : 3; unsigned int L1 : 3; unsigned int L2 : 3; unsigned int L3 : 3; } fields; }; // Attributes. protected: UState _state; unsigned int _topology; Net* _net; GCell* _gcell; AutoContact* _sourceContact; AutoContact* _southWestContact; AutoContact* _northEastContact; Hook* _fromHook; Hook* _east; Hook* _west; Hook* _north; Hook* _south; vector _routingPads; }; inline unsigned int GCellConfiguration::getStateG () const { return _state.fields.globals; } inline GCell* GCellConfiguration::getGCell () const { return _gcell; } GCellConfiguration::GCellConfiguration ( GCellGrid* gcellGrid , Hook* fromHook , AutoContact* sourceContact ) : _state() , _topology(0) , _gcell(NULL) , _sourceContact(sourceContact) , _southWestContact(NULL) , _northEastContact(NULL) , _fromHook(fromHook) , _east(NULL) , _west(NULL) , _north(NULL) , _south(NULL) , _routingPads() { ltrace(99) << "GCellConfiguration::GCellConfiguration ()" << endl; ltracein(99); ltrace(99) << getString(fromHook) << endl; ltrace(99) << sourceContact << endl; Segment* fromSegment = static_cast ( _fromHook->getComponent() ); _net = fromSegment->getNet (); _state.state = 0; forEach ( Hook*, hook, fromHook->getHooks() ) { Segment* toSegment = dynamic_cast(hook->getComponent()); if ( toSegment ) { switch ( getSegmentHookType(*hook) ) { case SegmentWest: _west = *hook; break; case SegmentEast: _east = *hook; break; case SegmentSouth: _south = *hook; break; case SegmentNorth: _north = *hook; break; } _state.fields.globals++; } else { RoutingPad* rp = dynamic_cast(hook->getComponent()); if ( rp ) { const Layer* layer = rp->getLayer(); if ( layer == Session::getRoutingLayer(0) ) _state.fields.L1++; // M1 V else if ( layer == Session::getRoutingLayer(1) ) _state.fields.L2++; // M2 H else if ( layer == Session::getRoutingLayer(2) ) _state.fields.L3++; // M3 V else if ( layer == Session::getRoutingLayer(3) ) _state.fields.L2++; // M4 H else if ( layer == Session::getRoutingLayer(4) ) _state.fields.L3++; // M5 V else { cerr << Warning ( "Terminal layer %s of %s is not managed yet (ignored)." , getString(layer->getName()).c_str() , getString(rp).c_str() ) << endl; continue; } ltrace(99) << "RoutingPad " << rp << endl; _routingPads.push_back ( rp ); } else { Contact* contact = dynamic_cast(hook->getComponent()); if ( contact ) { GCell* gcell = gcellGrid->getGCell ( contact->getCenter() ); ltrace(99) << gcell << " guessed from " << contact << endl; if ( !gcell ) throw Error ( invalidGCell ); if ( !_gcell ) _gcell = gcell; else if ( _gcell != gcell ) { throw Error ( mismatchGCell ); } } } } } if (_state.fields.globals == 1) { if ( _north || _south ) _topology |= GLOBAL_VERTICAL_END; else _topology |= GLOBAL_HORIZONTAL_END; } else if (_state.fields.globals == 2) { if ( _east && _west ) _topology |= GLOBAL_HORIZONTAL; else if ( _north && _south ) _topology |= GLOBAL_VERTICAL; else _topology |= GLOBAL_BEND; } else { _topology |= GLOBAL_FORK; } ltraceout(99); if ( !_gcell ) throw Error ( missingGCell ); } void GCellConfiguration::construct ( ForkStack& forks ) { ltrace(99) << "GCellConfiguration::construct () [" << _state.state << "] in " << _gcell << endl; ltracein(99); bool straightLine = false; switch ( _state.state ) { case GCELL_1G_1L1: _GCell_1G_1L1 (); break; case GCELL_1G_2L1: case GCELL_1G_3L1: case GCELL_1G_4L1: _GCell_1G_xL1 (); break; case GCELL_1G_1L2: case GCELL_1G_2L2: case GCELL_1G_3L2: case GCELL_1G_4L2: _GCell_xG_xL2 (); break; case GCELL_1G_1L3: _GCell_1G_1L3 (); break; case GCELL_1G_2L3: case GCELL_1G_3L3: case GCELL_1G_4L3: _GCell_xG_xL3 (); break; case GCELL_1G_1L1_1L2: _GCell_xG_1L1_1L2 (); break; case GCELL_1G_1L1_1L3: _GCell_1G_xL1 (); break; case GCELL_2G_1L1: case GCELL_2G_2L1: case GCELL_2G_3L1: case GCELL_2G_4L1: case GCELL_3G_1L1: case GCELL_3G_2L1: case GCELL_3G_3L1: case GCELL_3G_4L1: case GCELL_3G_2L3: case GCELL_3G_3L3: case GCELL_3G_4L3: case GCELL_4G_1L1: case GCELL_4G_2L1: case GCELL_4G_3L1: case GCELL_4G_4L1: _GCell_xG_xL1_xL3 (); break; case GCELL_2G_1L2: case GCELL_2G_2L2: case GCELL_2G_3L2: case GCELL_2G_4L2: case GCELL_3G_1L2: _GCell_xG_xL2 (); break; case GCELL_2G_1L3: case GCELL_2G_2L3: case GCELL_2G_3L3: case GCELL_2G_4L3: case GCELL_3G_1L3: _GCell_xG_xL3 (); break; case GCELL_2G_1L1_1L2: _GCell_xG_1L1_1L2 (); break; case GCELL_2G: if ( (_east && _west) || (_north && _south) ) { straightLine = true; break; } case GCELL_3G: _GCell_GlobalContacts ( false ); break; case GCELL_4G: _GCell_GlobalContacts ( true ); AutoSegment::create ( _southWestContact , _northEastContact , Constant::Horizontal , AutoSegment::Local , false , false ); break; default: cerr << Bug("Unmanaged Configuration [%d] = [%d+%d+%d+%d] %s" ,_state.state ,_state.fields.globals ,_state.fields.L1 ,_state.fields.L2 ,_state.fields.L3 ,_net->_getString().c_str() ) << endl; _GCell_GlobalContacts ( false ); } if ( straightLine ) { cerr << Error("Straight aligned segments (ignored)") << endl; ltraceout(99); return; } if ( _sourceContact ) { AutoContact* targetContact = ( getSegmentHookType(_fromHook) & (SegmentNorth|SegmentEast) ) ? _northEastContact : _southWestContact ; AutoSegment* globalSegment = AutoSegment::create ( _sourceContact , targetContact , static_cast( _fromHook->getComponent() ) ); if ( globalSegment->isHorizontal() and ( (Session::getRoutingGauge()->getLayerDepth(_sourceContact->getLayer()->getBottom()) > 1) or (Session::getRoutingGauge()->getLayerDepth(targetContact ->getLayer()->getBottom()) > 1)) ) { globalSegment->setLayer ( Session::getRoutingLayer(3) ); ltrace(99) << "Source:" << _sourceContact << endl; ltrace(99) << "Target:" << targetContact << endl; ltrace(99) << "Moving up global:" << globalSegment << endl; } if ( _state.fields.globals < 2 ) { ltraceout(99); return; } } else _fromHook = NULL; if ( _east && (_fromHook != _east) ) { Hook* toHook = getSegmentOppositeHook ( _east ); ltrace(99) << "Pushing " << getString(toHook) << endl; ltrace(99) << "Pushing " << _northEastContact << endl; forks.push ( toHook, _northEastContact ); } if ( _west && (_fromHook != _west) ) { Hook* toHook = getSegmentOppositeHook ( _west ); ltrace(99) << "Pushing " << getString(toHook) << endl; ltrace(99) << "Pushing " << _southWestContact << endl; forks.push ( toHook, _southWestContact ); } if ( _north && (_fromHook != _north) ) { Hook* toHook = getSegmentOppositeHook ( _north ); ltrace(99) << "Pushing " << getString(toHook) << endl; ltrace(99) << "Pushing " << _northEastContact << endl; forks.push ( toHook, _northEastContact ); } if ( _south && (_fromHook != _south) ) { Hook* toHook = getSegmentOppositeHook ( _south ); ltrace(99) << "Pushing " << getString(toHook) << endl; ltrace(99) << "Pushing " << _southWestContact << endl; forks.push ( toHook, _southWestContact ); } ltraceout(99); } void GCellConfiguration::_GCell_GlobalContacts ( bool split , AutoContact* southWestContact , AutoContact* northEastContact ) { ltrace(99) << "GlobalContacts(" << split << ")" << endl; if ( southWestContact ) _southWestContact = southWestContact; else { _southWestContact = AutoContact::create ( _gcell, _net, Session::getContactLayer(1) ); } if ( split ) { if ( northEastContact ) _northEastContact = northEastContact; else { _northEastContact = AutoContact::create ( _gcell, _net, Session::getContactLayer(1) ); } } else _northEastContact = _southWestContact; } bool GCellConfiguration::_GCell_rp_AutoContacts ( GCell* gcell , RoutingPad* rp , AutoContact*& source , AutoContact*& target , bool haccess ) { ltrace(99) << "_GCell_rp_AutoContacts()" << endl; ltracein(99); const Layer* rpLayer = Session::getContactLayer(0); Point sourcePosition = rp->getSourcePosition(); Point targetPosition = rp->getTargetPosition(); unsigned int direction = Session::getRoutingGauge()->getLayerDirection(rp->getLayer()); source = target = NULL; // Non-M1 terminal. if ( rp->getLayer() != Session::getRoutingLayer(0) ) { map::iterator irp = __routingPadAutoSegments.find ( rp ); if ( irp != __routingPadAutoSegments.end() ) { source = irp->second->getAutoSource(); target = irp->second->getAutoTarget(); } else { // Non-M1 Fixed protection. if ( sourcePosition.getX() > targetPosition.getX() ) swap ( sourcePosition, targetPosition ); if ( sourcePosition.getY() > targetPosition.getY() ) swap ( sourcePosition, targetPosition ); GCell* sourceGCell = Session::getKatabatic()->getGCellGrid()->getGCell ( sourcePosition ); GCell* targetGCell = Session::getKatabatic()->getGCellGrid()->getGCell ( targetPosition ); source = AutoContact::fromRp ( sourceGCell , rp , rp->getLayer() , sourcePosition , DbU::lambda(1.0), DbU::lambda(1.0) , true ); target = AutoContact::fromRp ( targetGCell , rp , rp->getLayer() , targetPosition , DbU::lambda(1.0), DbU::lambda(1.0) , true ); unsigned int segmentType = (sourceGCell == targetGCell) ? AutoSegment::Local : AutoSegment::Global; AutoSegment* segment = AutoSegment::create ( source , target , direction , segmentType , true , false ); segment->setFixed ( true ); __routingPadAutoSegments.insert ( make_pair(rp,segment) ); // Associate a M2 fixed protection to punctual M3 terminals. if ( ( rp->getLayer() == Session::getRoutingLayer(2) ) and ( sourcePosition == targetPosition ) ) { AutoContact* sourceM2 = AutoContact::fromRp ( sourceGCell , rp , Session::getContactLayer(1) , sourcePosition , DbU::lambda(1.0), DbU::lambda(1.0) , true ); AutoContact* targetM2 = AutoContact::fromRp ( sourceGCell , rp , Session::getContactLayer(1) , targetPosition , DbU::lambda(1.0), DbU::lambda(1.0) , true ); AutoSegment* segmentM2 = AutoSegment::create ( sourceM2 , targetM2 , Constant::Horizontal , AutoSegment::Local , true , false ); segmentM2->setFixed ( true ); } } if ( not (haccess xor (direction == Constant::Horizontal)) ) { ltraceout(99); return true; } } // Punctual M1. if ( ( rp->getLayer() == Session::getRoutingLayer(0) ) and ( sourcePosition == targetPosition ) ) { map::iterator irp = __routingPadAutoSegments.find ( rp ); if ( irp == __routingPadAutoSegments.end() ) { GCell* sourceGCell = Session::getKatabatic()->getGCellGrid()->getGCell ( sourcePosition ); source = AutoContact::fromRp ( sourceGCell , rp , Session::getContactLayer(0) , sourcePosition , DbU::lambda(1.0), DbU::lambda(1.0) , true ); target = AutoContact::fromRp ( sourceGCell , rp , Session::getContactLayer(0) , targetPosition , DbU::lambda(1.0), DbU::lambda(1.0) , true ); AutoSegment* segment = AutoSegment::create ( source , target , Constant::Horizontal , AutoSegment::Local , true , false ); segment->setFixed ( true ); __routingPadAutoSegments.insert ( make_pair(rp,segment) ); } } if ( rp->getLayer() != Session::getRoutingLayer(0) ) rpLayer = Session::getContactLayer(1); source = target = AutoContact::fromRp ( gcell , rp , rpLayer , rp->getCenter() , DbU::lambda(1.0), DbU::lambda(1.0) ); ltraceout(99); return false; } AutoContact* GCellConfiguration::_GCell_rp_Access ( GCell* gcell, RoutingPad* rp, bool haccess, bool forceVSmall ) { ltrace(99) << "_GCell_rp_Access()" << endl; ltracein(99); AutoContact* rpContactSource; AutoContact* rpContactTarget; bool hsmall; bool vsmall; bool punctual; setIsRoutingPadSmall ( rp, hsmall, vsmall, punctual ); vsmall = vsmall || forceVSmall; _GCell_rp_AutoContacts ( gcell, rp, rpContactSource, rpContactTarget, haccess ); if ( not haccess and hsmall ) { AutoContact* subContact1 = AutoContact::create ( gcell, rp->getNet(), Session::getContactLayer(1) ); AutoSegment::create ( rpContactSource , subContact1 , Constant::Horizontal , AutoSegment::Local , true , false ); rpContactSource = subContact1; } ltraceout(99); return rpContactSource; } AutoContact* GCellConfiguration::_GCell_rp_L2H ( GCell* gcell, RoutingPad* rp, AutoContact* target, bool hcollapse ) { ltrace(99) << "rp_L2H " << rp << endl; AutoContact* rpContactSource; AutoContact* rpContactTarget; unsigned int segmentType = AutoSegment::Local; if ( _GCell_rp_AutoContacts(gcell,rp,rpContactSource,rpContactTarget,true) ) { if ( gcell->getIndex() > rpContactSource->getGCell()->getIndex() ) swap ( rpContactSource, rpContactTarget ); if ( gcell->getIndex() != rpContactSource->getGCell()->getIndex() ) segmentType = AutoSegment::Global; } if ( !target ) target = AutoContact::create ( gcell, rp->getNet(), Session::getContactLayer(1) ); AutoSegment::create ( rpContactSource, target, Constant::Horizontal, segmentType, true, hcollapse ); return target; } AutoContact* GCellConfiguration::_GCell_rp_L2H_L3V ( GCell* gcell, RoutingPad* rp, AutoContact* target, bool hcollapse, bool vcollapse ) { ltrace(99) << "rp_L2H+L3V " << rp << endl; ltracein(99); AutoContact* source = _GCell_rp_L2H ( gcell, rp, NULL, hcollapse ); if ( !target ) { target = AutoContact::create ( gcell, rp->getNet(), Session::getContactLayer(1) ); } AutoSegment::create ( source, target, Constant::Vertical, AutoSegment::Local, true, vcollapse ); ltraceout(99); return target; } void GCellConfiguration::_GCell_rp_StairCaseH ( GCell* gcell, RoutingPad* rp1, RoutingPad* rp2 ) { ltrace(99) << "_GCell_rp_StairCaseH()" << endl; if ( rp1->getCenter().getX() > rp2->getCenter().getX() ) swap ( rp1, rp2 ); AutoContact* rp1ContactSource; AutoContact* rp1ContactTarget; AutoContact* rp2ContactSource; AutoContact* rp2ContactTarget; const Layer* viaLayer; _GCell_rp_AutoContacts ( gcell, rp1, rp1ContactSource, rp1ContactTarget, true ); _GCell_rp_AutoContacts ( gcell, rp2, rp2ContactSource, rp2ContactTarget, true ); if ( rp1ContactTarget->getY() == rp2ContactSource->getY() ) { ltrace(99) << "Aligned horizontal routing pads : straight wire" << endl; viaLayer = rp1->getLayer (); AutoSegment::create ( rp1ContactTarget , rp2ContactSource , Constant::Horizontal , AutoSegment::Local , true ); return; } viaLayer = Session::getContactLayer(1); AutoContact* subContact1 = AutoContact::create ( gcell, rp1->getNet(), Session::getContactLayer(1) ); AutoContact* subContact2 = AutoContact::create ( gcell, rp1->getNet(), Session::getContactLayer(1) ); AutoSegment::create ( rp1ContactTarget, subContact1 , Constant::Vertical , AutoSegment::Local, true ); AutoSegment::create ( subContact1 , subContact2 , Constant::Horizontal, AutoSegment::Local, true ); AutoSegment::create ( subContact1 , rp2ContactSource, Constant::Vertical , AutoSegment::Local, true ); } void GCellConfiguration::_GCell_rp_StairCaseV ( GCell* gcell, RoutingPad* rp1, RoutingPad* rp2 ) { ltrace(99) << "_GCell_rp_StairCaseV()" << endl; if ( rp1->getCenter().getY() > rp2->getCenter().getY() ) swap ( rp1, rp2 ); AutoContact* rp1ContactSource; AutoContact* rp1ContactTarget; AutoContact* rp2ContactSource; AutoContact* rp2ContactTarget; const Layer* viaLayer; _GCell_rp_AutoContacts ( gcell, rp1, rp1ContactSource, rp1ContactTarget, false ); _GCell_rp_AutoContacts ( gcell, rp2, rp2ContactSource, rp2ContactTarget, false ); if ( rp1ContactTarget->getX() == rp2ContactSource->getX() ) { ltrace(99) << "Aligned vertical routing pads : straight wire" << endl; viaLayer = rp1->getLayer (); AutoSegment::create ( rp1ContactTarget , rp2ContactSource , Constant::Vertical , AutoSegment::Local , true ); return; } viaLayer = Session::getContactLayer(1); AutoContact* subContact1 = AutoContact::create ( gcell, rp1->getNet(), Session::getContactLayer(1) ); AutoContact* subContact2 = AutoContact::create ( gcell, rp1->getNet(), Session::getContactLayer(1) ); AutoSegment::create ( rp1ContactTarget, subContact1 , Constant::Horizontal, AutoSegment::Local, true ); AutoSegment::create ( subContact1 , subContact2 , Constant::Vertical , AutoSegment::Local, true ); AutoSegment::create ( subContact2 , rp2ContactSource, Constant::Horizontal, AutoSegment::Local, true ); } AutoContact* GCellConfiguration::_GCell_L3V_L2H ( GCell* gcell , Net* net , AutoContact* source , AutoContact* target , bool hcollapse , bool vcollapse , bool terminal ) { AutoContact* subContact = AutoContact::create ( gcell, net, Session::getContactLayer(1) ); AutoSegment::create ( source, subContact, Constant::Vertical, AutoSegment::Local, terminal, vcollapse ); if ( !target ) target = AutoContact::create ( gcell, net, Session::getContactLayer(1) ); AutoSegment::create ( subContact, target, Constant::Horizontal, AutoSegment::Local, terminal, hcollapse ); return target; } AutoContact* GCellConfiguration::_GCell_L2H_L3V ( GCell* gcell , Net* net , AutoContact* source , AutoContact* target , bool hcollapse , bool vcollapse , bool terminal ) { AutoContact* subContact = AutoContact::create ( gcell, net, Session::getContactLayer(1) ); AutoSegment::create ( source, subContact, Constant::Horizontal, AutoSegment::Local, terminal, hcollapse ); if ( !target ) { target = AutoContact::create ( gcell, net, Session::getContactLayer(1) ); } AutoSegment::create ( subContact, target, Constant::Vertical, AutoSegment::Local, terminal, vcollapse ); return target; } void GCellConfiguration::_GCell_1G_1L1 () { ltrace(99) << "_GCell_1G_1L1() [Managed Configuration - Optimized] " << _topology << endl; ltracein(99); bool haccess = false; Hook* globalHook = NULL; if ( _east ) { globalHook = _east; haccess = true; } else if ( _west ) { globalHook = _west; haccess = true; } else if ( _north ) { globalHook = _north; } else if ( _south ) { globalHook = _south; } //Segment* globalSegment = dynamic_cast(globalHook->getComponent()); //DbU::Unit length = (globalSegment) ? globalSegment->getLength() : 0; AutoContact* rpContact = _GCell_rp_Access ( _gcell , _routingPads[0] , (_topology & GLOBAL_HORIZONTAL_END) , haccess //(length > DbU::lambda(50.0*2)) ); _GCell_GlobalContacts ( false, rpContact ); ltraceout(99); } void GCellConfiguration::_GCell_1G_xL1 () { ltrace(99) << "_GCell_1G_" << _state.fields.L1 << "L1() [Managed Configuration]" << endl; ltracein(99); AutoContact* subContact = NULL; if ( _topology & GLOBAL_VERTICAL_END ) { ltrace(99) << "Global Vertical End" << endl; _southWestContact = AutoContact::create ( _gcell, _net, Session::getContactLayer(1) ); //_southWestContact->setHAlignate ( true ); sort ( _routingPads.begin(), _routingPads.end(), SortRpByX(false) ); // increasing X. for ( unsigned int i = 0 ; i < _routingPads.size() ; i++ ) { subContact = _GCell_rp_Access ( _gcell, _routingPads[i], true, false ); AutoSegment::create ( _southWestContact, subContact, Constant::Horizontal, AutoSegment::Local, true, false ); } } else { ltrace(99) << "Global Horizontal End" << endl; if ( _east ) sort ( _routingPads.begin(), _routingPads.end(), SortRpByX(false) ); // increasing X. else sort ( _routingPads.begin(), _routingPads.end(), SortRpByX(true ) ); // decreasing X. for ( unsigned int i = 0 ; i < _routingPads.size() ; i++ ) { _southWestContact = _GCell_rp_Access ( _gcell, _routingPads[i], true, false ); _southWestContact->setHAlignate ( true ); if ( i ) AutoSegment::create ( subContact, _southWestContact, Constant::Horizontal, AutoSegment::Local, true, false ); subContact = _southWestContact; } } _northEastContact = _southWestContact; ltraceout(99); } void GCellConfiguration::_GCell_xG_1L1_1L2 () { ltrace(99) << "_GCell_xG_1L1_1L2() [Managed Configuration]" << endl; ltracein(99); RoutingPad* rpL1; RoutingPad* rpL2; if ( _routingPads[0]->getLayer() == Session::getRoutingLayer(0) ) { rpL1 = _routingPads[0]; rpL2 = _routingPads[1]; } else { rpL1 = _routingPads[1]; rpL2 = _routingPads[0]; } ltrace(99) << "rpL1 := " << rpL1 << endl; ltrace(99) << "rpL2 := " << rpL2 << endl; AutoContact* rpL1ContactSource; AutoContact* rpL1ContactTarget; AutoContact* rpL2ContactSource; AutoContact* rpL2ContactTarget; _GCell_rp_AutoContacts ( _gcell, rpL1, rpL1ContactSource, rpL1ContactTarget, true ); AutoContact* subContact = AutoContact::create ( _gcell, _net, Session::getContactLayer(1) ); AutoSegment::create ( rpL1ContactSource, subContact, Constant::Horizontal, AutoSegment::Local, true ); _GCell_rp_AutoContacts ( _gcell, rpL2, rpL2ContactSource, rpL2ContactTarget, false ); AutoSegment::create ( rpL2ContactSource, subContact, Constant::Vertical, AutoSegment::Local, true ); if ( _state.fields.globals > 0 ) { _GCell_rp_AutoContacts ( _gcell, rpL2, _southWestContact, subContact, (_south == NULL) ); if ( _state.fields.globals > 2 ) { _GCell_rp_AutoContacts ( _gcell, rpL2, _northEastContact, subContact, (_north == NULL) ); } else _northEastContact = _southWestContact; } ltraceout(99); } void GCellConfiguration::_GCell_xG_xL1_xL3 () { ltrace(99) << "_GCell_xG_" << _state.fields.L1 << "L1_" << _state.fields.L3 << "L3() [G:" << _state.fields.globals << " Managed Configuration]" << endl; ltracein(99); ltrace(99) << "_topology: " << _topology << endl; ltrace(99) << "_north: " << _north << endl; ltrace(99) << "_south: " << _south << endl; ltrace(99) << "_east: " << _east << endl; ltrace(99) << "_west: " << _west << endl; bool hsmall = false; bool vsmall = false; bool punctual = false; AutoSegment* segment = NULL; sort ( _routingPads.begin(), _routingPads.end(), SortRpByX(false) ); // increasing X. if ( _topology & GLOBAL_HORIZONTAL ) { AutoContact* subContact1 = NULL; AutoContact* subContact2 = NULL; for ( unsigned int i = 0 ; i < _routingPads.size() ; i++ ) { subContact1 = _GCell_rp_Access ( _gcell, _routingPads[i], true, false ); subContact1->setHAlignate ( true ); if ( i ) { segment = AutoSegment::create ( subContact1 , subContact2 , Constant::Horizontal , AutoSegment::Local , true , false ); segment->setStrap ( true ); } else _southWestContact = subContact1; subContact2 = subContact1; } _northEastContact = subContact1; } else { ltrace(99) << "Not straight horizontal " << _south << endl; _GCell_GlobalContacts ( _topology & GLOBAL_SPLIT ); AutoContact* localContact = (_south) ? _southWestContact : _northEastContact; //localContact->setHAlignate ( true ); bool doTurn = (_topology & GLOBAL_SPLIT) and (_routingPads.size() == 1); for ( unsigned int i = 0 ; i < _routingPads.size() ; i++ ) { AutoContact* rpContact = _GCell_rp_Access ( _gcell, _routingPads[i], true, false ); AutoContact* turn1 = (doTurn) ? AutoContact::create(_gcell,_net,Session::getContactLayer(1)) : localContact; segment = AutoSegment::create ( rpContact , turn1 , Constant::Horizontal , AutoSegment::Local , true , false ); setIsRoutingPadSmall ( _routingPads[i], hsmall, vsmall, punctual ); if ( not vsmall ) segment->setStrap ( true ); if ( doTurn ) { AutoContact* turn2 = AutoContact::create ( _gcell, _net, Session::getContactLayer(1) ); segment = AutoSegment::create ( turn1 , turn2 , Constant::Vertical , AutoSegment::Local , true , false ); segment->setStrap ( true ); segment = AutoSegment::create ( turn2 , localContact , Constant::Horizontal , AutoSegment::Local , true , false ); segment->setStrap ( true ); } } if ( _topology & (GLOBAL_VERTICAL|GLOBAL_FORK) ) { ltrace(99) << "Global Vertical/Global fork " << _south << endl; unsigned int direction = (not _south or not _north) ? Constant::Vertical : Constant::Horizontal; segment = AutoSegment::create ( _southWestContact , _northEastContact , direction , AutoSegment::Local , false , false ); segment->setStrap ( true ); if ( direction == Constant::Vertical ) { if ( !_south ) _northEastContact->setVAlignate ( true ); else _southWestContact->setVAlignate ( true ); } } } ltraceout(99); } void GCellConfiguration::_GCell_xG_xL2 () { ltrace(99) << "_GCell_" << _state.fields.globals << "G_" << _state.fields.L2 << "L2() [Managed Configuration - x]" << endl; ltracein(99); unsigned int lastRP = _routingPads.size() - 1; RoutingPad* biggestRP = _routingPads[lastRP]; sort ( _routingPads.begin(), _routingPads.end(), SortRpByX(false) ); // increasing X. for ( unsigned int i = 0 ; i < lastRP ; i++ ) { _GCell_rp_StairCaseH ( _gcell, _routingPads[i], _routingPads[i+1] ); if ( _routingPads[i]->getBoundingBox().getWidth() > biggestRP->getBoundingBox().getWidth() ) biggestRP = _routingPads[i]; } RoutingPad* leftRP = biggestRP; RoutingPad* rightRP = biggestRP; switch ( _topology ) { case GLOBAL_VERTICAL_END: break; case GLOBAL_HORIZONTAL_END: if ( _west ) leftRP = _routingPads[0]; if ( _east ) leftRP = _routingPads[lastRP]; rightRP = leftRP; break; case GLOBAL_HORIZONTAL: leftRP = _routingPads[0]; rightRP = _routingPads[lastRP]; break; case GLOBAL_VERTICAL: break; case GLOBAL_BEND: break; case GLOBAL_FORK: break; } AutoContact* subContact; if ( leftRP == rightRP ) { _GCell_rp_AutoContacts ( _gcell, leftRP, _southWestContact, _northEastContact, (_south == NULL) && (_north == NULL) ); //_northEastContact = _southWestContact; } else { ltrace(99) << "Using separate global contacts" << endl; _GCell_rp_AutoContacts ( _gcell, leftRP , _southWestContact, subContact, (_south == NULL) ); _GCell_rp_AutoContacts ( _gcell, rightRP, subContact, _northEastContact, (_north == NULL) ); ltrace(99) << "leftRp: " << leftRP->getCenter() << " " << leftRP << endl; ltrace(99) << "rightRp: " << rightRP->getCenter() << " " << rightRP << endl; } ltraceout(99); } void GCellConfiguration::_GCell_1G_1L3 () { ltrace(99) << "_GCell_1G_1L3() [Optimised Configuration]" << endl; ltracein(99); bool useEnds = (_north != NULL) or (_south != NULL); _GCell_rp_AutoContacts ( _gcell , _routingPads[0] , _southWestContact , _northEastContact , not useEnds ); ltrace(99) << "_southWest: " << _southWestContact << endl; ltrace(99) << "_northEast: " << _northEastContact << endl; if ( useEnds ) { ltrace(99) << "Using Ends" << endl; if ( _north != NULL ) { ltrace(99) << _gcell << endl; ltrace(99) << "Using _northEast, _north: " << _north << endl; ltrace(99) << " _south: " << _south << endl; _southWestContact = _northEastContact; } //AutoContact* subContact = AutoContact::create ( _gcell, _net, Session::getContactLayer(1) ); //AutoSegment::create ( _southWestContact, subContact, Constant::Horizontal, AutoSegment::Local, true ); //_southWestContact = _northEastContact = subContact; } else { if ( _routingPads[0]->getBoundingBox().getHeight() < DbU::lambda(15) ) { AutoContact* subContact = AutoContact::create ( _gcell, _net, Session::getContactLayer(1) ); AutoSegment::create ( _southWestContact, subContact, Constant::Vertical, AutoSegment::Local, true ); _southWestContact = _northEastContact = subContact; } } ltraceout(99); } void GCellConfiguration::_GCell_xG_xL3 () { ltrace(99) << "_GCell_xG_" << _state.fields.L3 << "L3() [Managed Configuration]" << endl; ltracein(99); AutoContact* unusedContact; if ( _south ) sort ( _routingPads.begin(), _routingPads.end(), SortRpByY(false) ); // increasing Y. else sort ( _routingPads.begin(), _routingPads.end(), SortRpByY(true ) ); // decreasing Y. for ( unsigned int i = 1 ; i < _routingPads.size() ; i++ ) { _GCell_rp_StairCaseV ( _gcell, _routingPads[i-1], _routingPads[i] ); } if ( _west or _south ) { _GCell_rp_AutoContacts ( _gcell, _routingPads[0], _southWestContact, unusedContact, false ); // _southWestContact = AutoContact::fromRp ( _gcell // , _routingPads[0] // , Session::getContactLayer(1) // , _routingPads[0]->getCenter() // , DbU::lambda(1.0), DbU::lambda(1.0) // ); } if ( _west and not _south ) { AutoContact* subContact = AutoContact::create ( _gcell, _net, Session::getContactLayer(1) ); AutoSegment::create ( subContact, _southWestContact, Constant::Vertical, AutoSegment::Local, true ); _southWestContact = subContact; } if ( _east or _north ) { _GCell_rp_AutoContacts ( _gcell, _routingPads[0], unusedContact, _northEastContact, false ); // _northEastContact = AutoContact::fromRp ( _gcell // , _routingPads[_routingPads.size()-1] // , Session::getContactLayer(1) // , _routingPads[_routingPads.size()-1]->getCenter() // , DbU::lambda(1.0), DbU::lambda(1.0) // ); } if ( _east and not _north ) { AutoContact* subContact = AutoContact::create ( _gcell, _net, Session::getContactLayer(1) ); AutoSegment::create ( subContact, _northEastContact, Constant::Vertical, AutoSegment::Local, true ); _northEastContact = subContact; } if ( !_southWestContact ) _southWestContact = _northEastContact; if ( !_northEastContact ) _northEastContact = _southWestContact; ltraceout(99); } void singleGCell ( KatabaticEngine* ktbt, Net* net ) { ltrace(99) << "singleGCell () " << net << endl; ltracein(99); vector routingPads; forEach ( RoutingPad*, irp, net->getRoutingPads() ) { routingPads.push_back ( *irp ); } if ( routingPads.size() < 2 ) { cerr << Error("For %s, less than two Plugs/Pins (%d)." ,getString(net).c_str() ,routingPads.size()) << endl; ltraceout(99); return; } // if ( routingPads.size() > 2 ) { // cerr << Error("For %s, more than two Plugs/Pins (%d) in single GCell." // ,getString(net).c_str() // ,routingPads.size()) << endl; // ltraceout(99); // return; // } sort ( routingPads.begin(), routingPads.end(), SortRpByX(false) ); // increasing X. GCell* gcell = ktbt->getGCellGrid()->getGCell ( (*routingPads.begin ())->getCenter() , (*routingPads.rbegin())->getCenter() ); if ( !gcell ) { cerr << Error("No GCell under %s.",getString(routingPads[0]).c_str()) << endl; ltraceout(99); return; } ltrace(80) << "singleGCell " << gcell << endl; AutoContact* dummy = NULL; AutoContact* source = NULL; AutoContact* target = NULL; for ( size_t irp=1 ; irpgetNativeConstraintBox (); // Box targetBox = target->getNativeConstraintBox (); // if ( ( sourceBox.getYMax() < targetBox.getYMin() ) // || ( sourceBox.getYMin() > targetBox.getYMax() ) ) { // AutoContact* subContact1 = AutoContact::create ( gcell, net, Session::getContactLayer(1) ); // AutoSegment::create ( source, subContact1, Constant::Vertical, AutoSegment::Local, true ); // AutoContact* subContact2 = AutoContact::create ( gcell, net, Session::getContactLayer(1) ); // AutoSegment::create ( target, subContact2, Constant::Vertical, AutoSegment::Local, true ); // AutoSegment::create ( subContact1, subContact2, Constant::Horizontal, AutoSegment::Local, false ); // } else // AutoSegment::create ( source, target, Constant::Horizontal, AutoSegment::Local, true ); ltraceout(99); } } // End of anonymous namespace. namespace Katabatic { using Hurricane::Name; using Hurricane::DebugSession; using Hurricane::Error; using Hurricane::Warning; using Hurricane::Bug; using CRL::addMeasure; void KatabaticEngine::_loadGrByNet () { cmess1 << " o Loading Nets global routing from Knik." << endl; cout << Dots::asDouble(" - Saturation",getMeasure(getCell(),"Sat.")->getData()) << endl; startMeasures (); Session::open ( this ); //sort ( _routingNets.begin(), _routingNets.end(), NetCompareByName() ); NetSet::iterator inet = _routingNets.begin(); while ( inet != _routingNets.end() ) { _loadNetGlobalRouting ( *(inet++) ); } Session::revalidate (); for ( inet=_routingNets.begin() ; inet != _routingNets.end() ; ++inet ) _toOptimals ( *inet ); Session::revalidate (); #if defined(CHECK_DATABASE) _check ( "after Katabatic loading" ); #endif _print (); //_gcellGrid->checkEdgeSaturation ( 0.60 ); Session::close (); stopMeasures (); printMeasures ( "load" ); addMeasure ( getCell(), "Globals", AutoSegment::getGlobalsCount() ); addMeasure ( getCell(), "Edges" , AutoSegment::getAllocateds() ); } void KatabaticEngine::_loadNetGlobalRouting ( Net* net ) { DebugSession::open ( net, 80 ); ltrace(100) << "Katabatic::_loadNetGlobalRouting ( " << net << " )" << endl; ltracein(99); //cmess2 << " - " << net << endl; ForkStack forks; Hook* sourceHook = NULL; AutoContact* sourceContact = NULL; lookupClear (); RoutingPads routingPads = net->getRoutingPads (); if ( routingPads.getSize() < 2 ) { #if 0 if ( !getDemoMode() ) cmess2 << Warning("Net \"%s\" have less than 2 plugs/pins (ignored)." ,getString(net->getName()).c_str()) << endl; #endif ltraceout(99); return; } ltracein(99); Hook* startHook = NULL; GCell* lowestGCell = NULL; size_t unconnecteds = 0; size_t connecteds = 0; ltrace(99) << "Start RoutingPad Ring" << endl; forEach ( RoutingPad*, startRp, routingPads ) { bool segmentFound = false; forEach ( Hook*, ihook, startRp->getBodyHook()->getHooks() ) { ltrace(99) << "Component " << ihook->getComponent() << endl; Segment* segment = dynamic_cast(ihook->getComponent()); if ( segment ) { ++connecteds; segmentFound = true; GCellConfiguration gcellConf ( getGCellGrid(), *ihook, NULL ); if ( gcellConf.getStateG() == 1 ) { if ( (lowestGCell == NULL) or (lowestGCell->getIndex() > gcellConf.getGCell()->getIndex()) ) { ltrace(99) << "Starting from GCell " << gcellConf.getGCell() << endl; lowestGCell = gcellConf.getGCell(); startHook = *ihook; } break; } } } unconnecteds += (segmentFound) ? 0 : 1; if ( (unconnecteds > 10) and (connecteds == 0) ) { cerr << Warning("More than 10 unconnected RoutingPads (%u) on %s, missing global routing?" ,unconnecteds, getString(net->getName()).c_str() ) << endl; _routingNets.erase ( net ); ltraceout(99); DebugSession::close (); return; } // Comment the next line to enable the lowest GCell search. //if ( startHook ) break; } ltraceout(99); if ( startHook == NULL ) { singleGCell ( this, net ); ltraceout(99); return; } GCellConfiguration startGCellConf ( getGCellGrid(), startHook, NULL ); startGCellConf.construct ( forks ); sourceHook = forks.getFrom (); sourceContact = forks.getContact (); forks.pop (); while ( sourceHook ) { GCellConfiguration gcellConf ( getGCellGrid(), sourceHook, sourceContact ); gcellConf.construct ( forks ); sourceHook = forks.getFrom (); sourceContact = forks.getContact (); forks.pop (); } lookupClear (); set overconstraineds; _computeNetConstraints ( net, overconstraineds ); Session::revalidate (); set::iterator iover = overconstraineds.begin(); for ( ; iover != overconstraineds.end() ; ++iover ) { (*iover)->makeDogLeg ( (*iover)->getAutoSource()->getGCell(), true ); } Session::revalidate (); ltraceout(99); DebugSession::close (); } } // End of Katabatic namespace.