// -*- C++ -*- namespace Kite { // ------------------------------------------------------------------- // Class : "SegmentAction". /*! \class SegmentAction * \brief Store request for an event to be generated on a TrackElement * * When an event on a Kite::TrackElement is being processed (with the * SegmentFsm helper), it may generate events on TrackElement already * placed and belonging either to the same net or other ones. * Those events are not generated and queued immediatly but * instead SegmentAction, requesting the event generation are created * and stored into a simple vector in SegmentFsm. The last operation of * the SegmentFsm object is to call the SegmentAction::doAction() method * on all the action to actually generate and queue the events. */ //! \enum SegmentAction::Type //! Indicates the kind of action to be performed on the segment. In the following //! \b flags and \b masks descriptions, we uses the term reference segment //! for the TrackElement which is associated with the currently processed RoutingEvent //! (also referenced in SegmentFsm). //! //! Here is the list of the availables actions that can be performed when (re)scheduling //! a RoutingEvent. It is here that we uses the RoutingEvent level feature to perform //! a local reordering of the top of the queue. Reordering is used to allows //! perpandiculars to be routed \e before the reference segment (instead of after) //! or \e other segments in conflict. //! //! - SegmentAction::SelfInsert
//! Action: The reference segment is to be inserted in a Track (placed).
//! Event Level: Unchanged. //! //! - SegmentAction::SelfRipup
//! Action: The reference segment is to be ripped up.
//! Event Level: Unchanged. //! //! - SegmentAction::SelfRipupPerpand
//! Action: Ripup a segment which is a perpandicular to the reference //! segment. Ordering considerations: this perpandicular will be put back into //! the RoutingEvent queue with a lower level (priority) than the reference //! segment, so it will be processed again \e after the reference segment.
//! Event Level: Unchanged. //! //! - SegmentAction::SelfRipupPerpandWithAxisHint
//! Action: Ripup a segment which is a perpandicular to the reference //! segment, supplies an axis hint and put it back into the RoutingEvent queue so //! that it will be processed \e before the reference segment.
//! Event Level: Increased to SegmentAction::EventLevel4. //! //! - SegmentAction::OtherRipup
//! Action: Ripping up a segment from another net and in the same direction //! as the reference segment.
//! Event Level: Unchanged. //! //! - SegmentAction::OtherRipupPerpandAndPushAside
//! Action: Ripping up a segment from another net and in perpandicular //! direction. The level is elevated so it's priority is greater than the //! reference segment this it will be reprocessed first. An axis hint is also //! supplied in order to make room for the reference segment.
//! Event Level: Increased to SegmentAction::EventLevel3. //! //! - SegmentAction::OtherRipupPerpandAndPacking
//! Action: Ripping up a segment from another net and in perpandicular //! direction. The level is elevated so it's priority is greater than the //! reference segment this it will be reprocessed first. The generated event //! is in packing mode only.
//! Event Level: Increased to SegmentAction::EventLevel4. //! \var SegmentAction::Self //! [Flag] The segment associated to the action is the reference segment //! or segments from the same net. //! \var SegmentAction::Other //! [Flag] The segment associated to the action is \b not from the same //! net as the reference segment. //! \var SegmentAction::Perpandicular //! [Flag] The action concern a perpandicular to the reference segment. //! \var SegmentAction::Ripup //! [Flag] Request that the segment is to be ripped up. //! \var SegmentAction::RipedByLocal //! [Flag] Indicate that the segment has been ripped up by a local one. //! \var SegmentAction::ResetRipup //! [Flag] The ripup count is to be reset. //! \var SegmentAction::ToRipupLimit //! [Flag] The ripup count is directly increased to the ripup limit, //! triggering a state change the next time the segment will be processed. //! \var SegmentAction::Insert //! [Flag] Request that the segment is to be inserted in the given track. //! It is the task of SegmentFsm to determine that there is sufficent space to do so. //! \var SegmentAction::AxisHint //! [Flag] An axis hint has been supplied, and is to be passed to //! the generated RoutingEvent. //! \var SegmentAction::PackingMode //! [Flag] Whether the RoutingEvent should be processed in \e packing //! mode or \e negociated mode (transmitted to the RoutingEvent). //! \var SegmentAction::ToState //! [Flag] Force the change of state of the RoutingEvent //! (i.e. DataNegociate). Normally the state change is done through the //! increase of the ripup count in DataNegociate. //! \var SegmentAction::EventLevel1 //! [Flag] Increase the level to at least \b 1. //! \var SegmentAction::EventLevel2 //! [Flag] Increase the level to at least \b 2. //! \var SegmentAction::EventLevel3 //! [Flag] Increase the level to at least \b 3. //! \var SegmentAction::EventLevel4 //! [Flag] Increase the level to at least \b 4. //! \var SegmentAction::EventLevel5 //! [Flag] Increase the level to at least \b 5. //! \var SegmentAction::SelfInsert //! [Mask], see SegmentAction::Type. //! \var SegmentAction::SelfRipup //! [Mask], see SegmentAction::Type. //! \var SegmentAction::SelfRipupPerpand //! [Mask], see SegmentAction::Type. //! \var SegmentAction::SelfRipupPerpandWithAxisHint //! [Mask], see SegmentAction::Type. //! \var SegmentAction::OtherRipup //! [Mask], see SegmentAction::Type. //! \var SegmentAction::OtherRipupPerpandAndPushAside //! [Mask], see SegmentAction::Type. //! \var SegmentAction::OtherRipupPerpandAndPacking //! [Mask], see SegmentAction::Type. //! \function SegmentAction::SegmentAction ( TrackElement* segment, unsigned int type, DbU::Unit axisHint=0, unsigned int toState =0 ); //! \param segment On what the action is to be performed. //! \param type Defines the type of action, see SegmentAction::Type. //! \param axisHint Specifies a preferred axis. //! \param toState The DataNegociate::SlackState into which the segment is to be set. //! //! Create segment action. //! \function TrackElement* SegmentAction::getSegment () const; //! \sreturn The associated \c segment. //! \function SegmentAction::Type SegmentAction::getType () const; //! \sreturn The action to be performed. //! \function void SegmentAction::setAxisHint ( DbU::Unit axis ); //! The axis preferred position to be transmitted to the generated event. //! The transmition will be effective \e only if the SegmentAction::Type::AxisHint //! flag is set. //! \function unsigned int SegmentAction::setFlag ( unsigned int flags ); //! Allow to change the action type by indivually setting up the flags. //! \function void SegmentAction::doAction ( RoutingEventQueue& queue ); //! Actually perform the action. That is, build and queue the appropriate //! event for the segment. // ------------------------------------------------------------------- // Class : "SegmentFsm". /*! \class SegmentFsm * \brief Pseudo-decorator to process a RoutingEvent * * The SegmentFsm class actually perform the placement of the Kite::TrackElement * of the Kite::RoutingEvent. It structured around three goals: * - Implement the finite state machine for the Kite::DataNegociate state. * - Provide a kind of decoration on the RoutingEvent/TrackElement * (it do not abide by the definition from Design Patterns). * - Cache a lot of on-the-fly computed datas needed during the * SegmentFsm lifetime and the Manipulator(s) it may uses. * * * \section secUpdate Update Mechanism * * The constructor of SegmentFsm triggers the update of the RoutingEvent * and through it DataNegociate. * * * \section secSlackening Slackening / FSM Transitions * * A transition occurs in the FSM whenener all the availables ripup methods * for a segment have failed. Failure means that the topology of the net * itself must be altered to allow a greater level of flexibility. * Modifying the net topology means to give the current segment some * more slack. * * Availables slackening operations: * -# DataNegociate::RipupPerpandiculars (Manipulator) place the segments before any of * it's perpandiculars are placed to allow a maximum track choice. * -# DataNegociate::Minimize (Manipulator) try to fit the segment in a hole in a track, * perform a hole detection. * -# DataNegociate::Dogleg (Manipulator) create a dogleg matching the first track * candidate with a non-nul overlap. * -# DataNegociate::Slacken (Manipulator) \red{to be reviewed.} * -# DataNegociate::ConflictSolveByHistory (SegmentFsm) try to find a break point on * the segment, based on the ripup history. * -# DataNegociate::ConflictSolveByPlaceds (SegmentFsm) try to find a break point on * the segment, based on the current position of segments on the * candidate tracks. * -# DataNegociate::MoveUp (Manipulator) try to move up the segment. * * Simple slackening operations are defined in Manipulator and complex ones * directly in SegmentFsm. * * * \section secNonSlackening Non-Slackening Operations * * In addition, some operation that do not modifies the topology are * availables: * -# Manipulator::forceOverLocals() mostly for global segments to ripup * a track from all it's locals. * -# SegmentFsm::insertInTrack() automates the three subsequent ripup * trials. */ //! \enum SegmentFsm::State //! Indicates what the SegmentFsm has done the processed TrackElement, //! possible values are: //! - SegmentFsm::MissingData, this is an error condition, the TrackElement //! do not have associated DataNegociate structure. Nothing is done. //! //! - SegmentFsm::EmptyTrackList, no Track is available for placement //! (free or used). //! //! - SegmentFsm::SelfInserted, the TrackElement can be successfully //! inserted in a Track (i.e. without overlap). //! //! - SegmentFsm::SelfMaximumSlack, nothing can be done to further slacken //! the TrackElement, it is at maximum ripup of the last possible state //! (no more topological modifications are possibles). //! //! - SegmentFsm::OtherRipup, the TrackElement can be inserted but it //! needs the ripup of some others. //! \var SegmentFsm::MissingData //! [Flag], see SegmentFsm::SegmentFsmValue. //! \var SegmentFsm::EmptyTrackList //! [Flag], see SegmentFsm::SegmentFsmValue. //! \var SegmentFsm::Inserted //! [Flag], the TrackElement can be inserted in a Track. //! \var SegmentFsm::Self //! [Flag], the action is related to the processed TrackSegment. //! \var SegmentFsm::Other //! [Flag], the action is \b not related to the processed TrackSegment, //! that is, others are being topologically modificated or riped up. //! \var SegmentFsm::Ripup //! [Flag], segement, that are not the processed one are being ripped up. //! \var SegmentFsm::MaximumSlack //! [Flag], the processed segment as reached it's maximum ripup count on //! the last possible slackening state. //! \var SegmentFsm::SelfInserted //! [Mask], see SegmentFsm::SegmentFsmValue. //! \var SegmentFsm::OtherRipup //! [Mask], see SegmentFsm::SegmentFsmValue. //! \var SegmentFsm::SelfMaximumSlack //! [Mask], see SegmentFsm::SegmentFsmValue. //! \function SegmentFsm::SegmentFsm ( RoutingEvent* event, RoutingEventQueue& queue, RoutingEventHistory& history ); //! \param event The RoutingEvent to be processed. //! \param queue The RoutingEvent queue. //! \param history The complete history of RoutingEvent. //! //! Construct a SegmentFsm from a RoutingEvent. The constructor is in charge of //! computing all the cached values. //! \function bool SegmentFsm::isFullBlocked () const; //! \sreturn \true if there are Tracks avalaibles but the constraints are such that none //! is actually usable. //! \function RoutingEvent* SegmentFsm::getEvent () const; //! \sreturn The currently processed RoutingEvent (\e cached). //! \function RoutingEventQueue& SegmentFsm::getQueue () const; //! \sreturn The RoutingEvent queue (\e cached). //! \function RoutingEventHistory& SegmentFsm::getHistory () const; //! \sreturn The RoutingEvent history (\e cached). //! \function DataNegociate* SegmentFsm::getData (); //! \sreturn The DataNegociate of the TrackElement (\e cached). //! \function unsigned int SegmentFsm::getState () const; //! \sreturn The state (SegmentFsm::SegmentFsmValues) which the SegmentFsm has computed for the //! RoutingEvent. This is \b not the state of the DataNegociate //! \function Interval& SegmentFsm::getConstraint (); //! \sreturn The interval into which the segment axis can be set (computed from //! the topological constraints and the placement constraints on the //! already placed perpandiculars). //! \function Interval& SegmentFsm::getOptimal (); //! \sreturn The interval for an optimal placement of the segment axis. //! \function vector& SegmentFsm::getCosts (); //! \sreturn The table of cost for all the candidates Tracks of the segment. //! The table is sorted in increasing cost order (see TrackCost). //! \function TrackCost& SegmentFsm::getCost ( size_t i ); //! \sreturn The cost at index \c i in the table. //! \function Track* SegmentFsm::getTrack ( size_t i ); //! \sreturn The Track for cost at index \c i in the table. //! \function size_t SegmentFsm::getBegin ( size_t i ); //! \sreturn The overlapping \e begin index in Track for cost at index \c i in the table. //! \function size_t SegmentFsm::getEnd ( size_t i ); //! \sreturn The overlapping \e end index in Track for cost at index \c i in the table. //! \function vector& SegmentFsm::getActions (); //! \sreturn The table of SegmentAction, that is the delayed requests for RoutingEvent //! creation. //! \function unsigned int SegmentFsm::setState ( unsigned int state ); //! \sreturn Sets the state of the state... //! \function void SegmentFsm::addAction ( TrackElement* segment, unsigned int type, DbU::Unit axisHint=0, unsigned int toState=0 ); //! Request the creation of a new delayed RoutingEvent, for the meaning of //! the parameters, see SegmentAction::SegmentAction. //! \function bool SegmentFsm::doActions (); //! Actually generate RoutingEvent(s) from the SegmentAction(s). //! \function void SegmentFsm::clearActions (); //! Clear the the table of requested actions, whithout generating them. //! \function void SegmentFsm::clearActions (); //! Clear the the table of requested actions, whithout generating them. //! \function bool SegmentFsm::insertInTrack ( size_t i ); //! Try to insert the TrackElement in the Track at index \c i (in the //! cost table). Return \true if the insertion is possible. //! //! The insertion is not done at this stage, but a set of ripup actions is //! emitted to allow insertion the next time the segment will be processed. //! //! Three subsequent trials are done before giving up on inserting //! the segment: //! -# Manipulator::insertInTrack(), try to push asides the neighbors. //! -# Manipulator::shrinkToTrack(), try squeeze the segment in an existing //! free space. //! -# Manipulator::forceToTrack(), perform a complete ripup of all the //! neighbors and their perpandiculars. //! //! The event keeps track of the insertion attempt step (see RoutingEvent::getInsertState()). //! \function bool SegmentFsm::conflictSolveByHistory (); //! \sreturn \true if a suitable dogleg has been created in the segment. //! //! Initially, global segments may be very long, and a placement solution //! in which each one is placed on a track of it's own may not be realisable. //! In that case, at least one of the global segment must be broken. //! The figure below illustrate the case: (a), (b), (c) form a //! first cluster and (d), (e), (f) form a second one. Due to the //! constraints of the segments the remaining free track cannot be the same //! in both clusters. The only solution to place (g) is to break it into //! two sub-globals. The whole point of the conflict solve is to correctly //! detect the cluster and choose the breaking point. //! //! \image html ConflictSolve-1.png "Conflict Between Globals" //! //! This variant of the conflict solve method try to guess the track span //! for which there is a conflict by looking at the event history. //! //! \image html ConflictSolveByHistory-1.png "Building Conflicting Intervals" //! //! Dislodger Definition: //! //! A segment is said to be a dislodger if it matches the two following criterions: //! - It's span intersect the to be inserted segment span. //! - It has been placed on a track inside the perpandicular span of the //! to be placed segment. //! //! For the time beeing we limit the search to the last three dislodgers, to not //! waste too much time looking back the event history. We merge overlapping //! intervals into one (see the undocumented class \c UnionIntervals and //! \c RipupHistory in \c SegmentFsm.cpp). //! //! \red{For the time beeing we only look on the track into which} //! \red{the to be inserted segment wants to be placed.} //! //! Then we try to break the to be placed segment, first under the lower bound //! (source) of the conflicting interval then, in case of failure under //! the upper bound (target). //! //! \image html ConflictSolveByHistory-2.png "Interval Breaking" //! \function bool SegmentFsm::conflictSolveByPlaceds (); //! \sreturn \true if a suitable dogleg has been created in the segment \e or a //! dislodger has been moved up. //! //! This methods achieve the same goal as SegmentFsm::conflictSolveByHistory() //! but uses a different strategy. //! //! Instead of looking through the history to find dislodgers it analyses //! the placed segments in all the candidates tracks for the to be placed //! segment. Unlike it's sibling method, which creates only one dogleg, as //! it uses the Manipulator::relax() method, it may creates up to two doglegs. //! //! Synthetic Description //! //! -# For each track, find the dislodgers, merge the overlaps into one //! interval and store the length of the longuest overlap (aka conflict). //! -# Sort the tracks according to decreasing longuest overlap/confict. //! -# For each track in the sorted list, look for a dislodger under the middle //! of the to be placed segment. If no dislodger is present at this place //! go to the next track. Otherwise: //! - The dislodger is local, then try to relax the to placed //! segment around the dislodger. //! - The dislodger is global, try to move it up, if it is not //! possible, fallback to the relax approach. //! -# Quit on the first successful move up or relax. //! -# If there is no candidate tracks, this means the vertical constraints //! are too tight, in that case, ripup the perpandiculars (fallback plan). //! //! Interval Accounting //! //! Only global conflicting segments are took into account. Local segments //! may be took into account if they overlap global ones (all part of the //! same net). All overlapping segments are merged into one big conflict //! interval. The whole length of a conflict interval is took into account //! event if it's overlap with the to be placed segment is only partial. //! //! Track Ordering (lexicographic) //! //! -# The longuest (in one interval) conflict length. //! -# The longuest cumulative conflict length (all interval summed up). //! //! Interval accounting and Track ordering is managed through the undocumented //! \c Cs1Candidate class implemented in \c SegmentFsm.cpp. //! //! \image html ConflictSolveByPlaceds-1.png "Candidates Track Ordering" //! \function bool SegmentFsm::desaturate (); //! Try to create a suitable empty space in a cost Track by moving up //! TrackElement in conflict. //! \function bool SegmentFsm::slackenTopology ( unsigned int flags=0 ); //! Modificate the topology of the TrackElement to slacken it. //! It is the implementation of the slakening finite state machine. //! \function bool SegmentFsm::solveFullBlockages (); //! Try to solve a fully blocked configuration. }