// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2008-2018, All Rights Reserved
//
// +-----------------------------------------------------------------+
// |                   C O R I O L I S                               |
// |         A n a b a t i c  -  Routing Toolbox                     |
// |                                                                 |
// |  Author      :                    Jean-Paul CHAPUT              |
// |  E-mail      :            Jean-Paul.Chaput@lip6.fr              |
// | =============================================================== |
// |  C++ Module  :       "./NetBuilderHV.cpp"                       |
// +-----------------------------------------------------------------+


#include <cstdlib>
#include <sstream>
#include "hurricane/Bug.h"
#include "hurricane/Breakpoint.h"
#include "hurricane/Error.h"
#include "hurricane/Warning.h"
#include "hurricane/DebugSession.h"
#include "hurricane/Layer.h"
#include "hurricane/BasicLayer.h"
#include "hurricane/RegularLayer.h"
#include "hurricane/Technology.h"
#include "hurricane/DataBase.h"
#include "hurricane/Net.h"
#include "hurricane/NetExternalComponents.h"
#include "hurricane/NetRoutingProperty.h"
#include "hurricane/RoutingPad.h"
#include "hurricane/RoutingPads.h"
#include "hurricane/Pad.h"
#include "hurricane/Pin.h"
#include "hurricane/Plug.h"
#include "hurricane/Cell.h"
#include "hurricane/Instance.h"
#include "hurricane/Vertical.h"
#include "hurricane/Horizontal.h"
#include "crlcore/AllianceFramework.h"
#include "crlcore/RoutingGauge.h"
#include "crlcore/Measures.h"
#include "anabatic/AutoContactTerminal.h"
#include "anabatic/AutoContactTurn.h"
#include "anabatic/AutoContactHTee.h"
#include "anabatic/AutoContactVTee.h"
#include "anabatic/AutoSegment.h"
#include "anabatic/NetBuilderHV.h"
#include "anabatic/AnabaticEngine.h"


namespace Anabatic {

  using std::swap;
  using Hurricane::Transformation;
  using Hurricane::Warning;
  using Hurricane::Error;
  using Hurricane::Pin;

  
  NetBuilderHV::NetBuilderHV ()
    : NetBuilder()
  { }


  NetBuilderHV::~NetBuilderHV () { }

  
  void  NetBuilderHV::doRp_AutoContacts ( GCell*        gcell
                                        , Component*    rp
                                        , AutoContact*& source
                                        , AutoContact*& target
                                        , uint64_t      flags
                                        )
  {
    cdebug_log(145,1) << getTypeName() << "::doRp_AutoContacts()" << endl;
    cdebug_log(145,0)   << rp << endl;

    RoutingPad* rrp = dynamic_cast<RoutingPad*>( rp );
    if (not rrp) {
      cerr << Warning( "%s::doRp_AutoContacts(): %s is *not* a RoutingPad."
                     , getTypeName().c_str()
                     , getString(rp).c_str() ) << endl;
    }

    source = target = NULL;

    Point        sourcePosition;
    Point        targetPosition;
    const Layer* rpLayer        = rp->getLayer();
    size_t       rpDepth        = Session::getLayerDepth( rp->getLayer() );
    Flags        direction      = Session::getDirection ( rpDepth );
    DbU::Unit    viaSide        = Session::getViaWidth  ( rpDepth );

    getPositions( rp, sourcePosition, targetPosition );

    GCell* sourceGCell = Session::getAnabatic()->getGCellUnder( sourcePosition );
    GCell* targetGCell = Session::getAnabatic()->getGCellUnder( targetPosition );

    if (rpDepth == 0) {
      rpLayer   = Session::getContactLayer(0);
      direction = Flags::Horizontal;
      viaSide   = Session::getViaWidth( rpDepth );
    }

  // Non-M1 terminal or punctual M1 protections.
    if ( ((rpDepth != 0) or (sourcePosition == targetPosition)) and not (flags & NoProtect) ) {
      map<Component*,AutoSegment*>::iterator irp = getRpLookup().find( rp );
      if (irp == getRpLookup().end()) {
        Box rpBb = rp->getBoundingBox();
        if (rpDepth != 0) {
          DbU::Unit hborder = 0;
          DbU::Unit vborder = 0;
          if (direction.contains(Flags::Horizontal)) {
            vborder = Session::getWireWidth(rpDepth) / 2;
            rpBb.inflate( hborder, vborder );
            if (not rpBb.isEmpty()) {
              DbU::Unit trackAxis =  Session::getNearestTrackAxis( rp->getLayer()
                                                                 , sourcePosition.getY()
                                                                 , Constant::Nearest );
              if (trackAxis != sourcePosition.getY()) {
                cerr << Warning( "NetBuilderHV::doRp_AutoContacts(): Adjust Y position to nearest H track of %s\n"
                                 "           (%s -> %s)"
                               , getString(rp).c_str()
                               , DbU::getValueString(sourcePosition.getY()).c_str()
                               , DbU::getValueString(trackAxis).c_str()
                               ) << endl;
                sourcePosition.setY( trackAxis );
                targetPosition.setY( trackAxis );
              }
            } else {
              cdebug_log(145,0) << "rpBb is too narrow to adjust: " << rp->getBoundingBox() << endl;
            }
          } else {
            hborder = Session::getWireWidth(rpDepth) / 2;
            rpBb.inflate( hborder, vborder );
            if (not rpBb.isEmpty()) {
              DbU::Unit trackAxis =  Session::getNearestTrackAxis( rp->getLayer()
                                                                 , sourcePosition.getX()
                                                                 , Constant::Nearest );
              if (trackAxis != sourcePosition.getX()) {
                cerr << Warning( "NetBuilderHV::doRp_AutoContacts(): Adjust X position to nearest V track of %s\n"
                                 "           (%s -> %s)"
                               , getString(rp).c_str()
                               , DbU::getValueString(sourcePosition.getX()).c_str()
                               , DbU::getValueString(trackAxis).c_str()
                               ) << endl;
                sourcePosition.setX( trackAxis );
                targetPosition.setX( trackAxis );
              }
            } else {
              cdebug_log(145,0) << "rpBb is too narrow to adjust: " << rp->getBoundingBox() << endl;
            }
          }
        }
        
        AutoContact* sourceProtect = AutoContactTerminal::create( sourceGCell
                                                                , rp
                                                                , rpLayer
                                                                , sourcePosition
                                                                , viaSide, viaSide
                                                                );
        AutoContact* targetProtect = AutoContactTerminal::create( targetGCell
                                                                , rp
                                                                , rpLayer
                                                                , targetPosition
                                                                , viaSide, viaSide
                                                                );
        sourceProtect->setFlags( CntFixed );
        targetProtect->setFlags( CntFixed );

        AutoSegment* segment = AutoSegment::create( sourceProtect, targetProtect, direction );
        segment->setFlags( AutoSegment::SegFixed );

        getRpLookup().insert( make_pair(rp,segment) );
      }
    }

    if (sourcePosition != targetPosition) {
      if (flags & DoSourceContact)
        source = AutoContactTerminal::create( sourceGCell
                                            , rp
                                            , rpLayer
                                            , sourcePosition
                                            , viaSide, viaSide
                                            );
      if (flags & DoTargetContact)
        target = AutoContactTerminal::create( targetGCell
                                            , rp
                                            , rpLayer
                                            , targetPosition
                                            , viaSide, viaSide
                                            );
    }

    if (not source and not target) {
      source = target = AutoContactTerminal::create( gcell
                                                   , rp
                                                   , rpLayer
                                                   , rp->getCenter()
                                                   , viaSide, viaSide
                                                   );
    }

    cdebug_tabw(145,-1);
    return;
  }


  AutoContact* NetBuilderHV::doRp_Access ( GCell* gcell, Component* rp, uint64_t flags )
  {
    cdebug_log(145,1) << getTypeName() << "::doRp_Access() - flags:" << flags << endl;

    size_t       rpDepth         = Session::getLayerDepth( rp->getLayer() );
    AutoContact* rpSourceContact = NULL;
    AutoContact* rpContactTarget = NULL;

    Flags useNonPref = Flags::NoFlags;
    if (flags & UseNonPref) useNonPref |= Flags::UseNonPref;
    
    flags |= checkRoutingPadSize( rp );

    doRp_AutoContacts( gcell, rp, rpSourceContact, rpContactTarget, flags );

    cdebug_log(145,0) << "flags: " << flags << endl;
    if ((rpDepth == 0) or (rpDepth == 2)) {
      cdebug_log(145,0) << "case: METAL1 or METAL3 RoutingPad." << endl;

      if (flags & HAccess) {
        cdebug_log(145,0) << "case: HAccess" << endl;
  
        if ( ((flags & VSmall) and not ((flags & UseNonPref))) or (flags & Punctual) ) {
          cdebug_log(145,0) << "case: VSmall and *not* UseNonPref" << endl;
  
          AutoContact* subContact1 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) );
          AutoSegment::create( rpSourceContact, subContact1, Flags::Horizontal );
          rpSourceContact = subContact1;

          flags &= ~UseNonPref;
          useNonPref.reset( Flags::UseNonPref );
        }

        if (flags & (VSmall|UseNonPref)) {
          cdebug_log(145,0) << "case: UseNonPref" << endl;
  
          AutoContact* subContact1 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) );
          AutoSegment::create( rpSourceContact, subContact1, Flags::Vertical|useNonPref );
          rpSourceContact = subContact1;
        }
      } else {
        if (flags & HSmall) {
          cdebug_log(145,0) << "case: HSmall" << endl;
  
          AutoContact* subContact1 = rpSourceContact;
          AutoContact* subContact2 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) );
          AutoSegment::create( subContact1, subContact2, Flags::Horizontal );
          rpSourceContact = subContact2;
  
          if (flags & Punctual) {
            cdebug_log(145,0) << "case: HSmall + Punctual" << endl;
            subContact1 = subContact2;
            subContact2 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) );
            AutoSegment::create( subContact1, subContact2, Flags::Vertical );
  
            subContact1 = subContact2;
            subContact2 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) );
            AutoSegment::create( subContact1, subContact2, Flags::Horizontal );
  
            rpSourceContact = subContact2;
          }
        }
      }
    } else {
      cdebug_log(145,0) << "case: METAL2." << endl;
      AutoContact* subContact1 = NULL;

      if (flags & HAccess) {
        if (flags & HAccessEW)
          subContact1 = AutoContactHTee::create( gcell, rp->getNet(), Session::getContactLayer(1) );
        else
          subContact1 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) );

        AutoSegment::create( rpSourceContact, subContact1, Flags::Vertical );
      } else {
#if OFFGRID_M2_DISABLED
        Box                cellAb    = getAnabatic()->getCell()->getAbutmentBox();
        RoutingLayerGauge* lgM2      = Session::getLayerGauge( 1 );
        DbU::Unit          trackAxis = lgM2->getTrackPosition( cellAb.getYMin()
                                                             , cellAb.getYMax()
                                                             , rp->getY()
                                                             , Constant::Nearest );
        bool offGrid = (trackAxis != rp->getY());
        if (offGrid) {
          cdebug_log(145,0) << "Off grid, Misaligned M2 RoutingPad, add vertical strap" << endl;
          subContact1 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
          AutoSegment::create( rpSourceContact, subContact1, Flags::Vertical );
          rpSourceContact = subContact1;
        }
#endif

        subContact1 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) );
        AutoSegment::create( rpSourceContact, subContact1, Flags::Horizontal );
      }
      rpSourceContact = subContact1;
    }

    cdebug_tabw(145,-1);

    return rpSourceContact;
  }


  AutoContact* NetBuilderHV::doRp_AccessNorthPin ( GCell* gcell, RoutingPad* rp )
  {
    cdebug_log(145,1) << getTypeName() << "::doRp_AccessNorthPin() " << rp << endl;

    AutoContact* rpSourceContact = NULL;
    AutoContact* rpContactTarget = NULL;
    AutoContact* turn            = NULL;

    doRp_AutoContacts( gcell, rp, rpSourceContact, rpContactTarget, NoProtect );

    Net* net = rp->getNet();
    Pin* pin = dynamic_cast<Pin*>( rp->getOccurrence().getEntity() );
    Pin::AccessDirection pinDir = pin->getAccessDirection();
    if (pinDir == Pin::AccessDirection::NORTH) {
      turn = AutoContactTurn::create( gcell, net, Session::getRoutingLayer(1) );
      AutoSegment* segment = AutoSegment::create( rpSourceContact, turn, Flags::Vertical );
      segment->setAxis( rp->getX(), Flags::Force );
      segment->setFlags( AutoSegment::SegFixed|AutoSegment::SegFixedAxis );
      rpSourceContact = turn;

      turn    = AutoContactTurn::create( gcell, net, Session::getContactLayer(1) );
      segment = AutoSegment::create( rpSourceContact, turn, Flags::Horizontal );
      rpSourceContact = turn;

      DbU::Unit axis = gcell->getYMax() - Session::getDHorizontalPitch();
      cdebug_log(145,0) << "axis:" << DbU::getValueString(axis) << endl;
      
      segment->setAxis( axis, Flags::Force );
    //segment->setFlags( AutoSegment::SegFixed|AutoSegment::SegFixedAxis );
      cdebug_log(145,0) << segment << endl;
    } else {
      turn = rpSourceContact;
    }

    cdebug_tabw(145,-1);
    return turn;
  }


  AutoContact* NetBuilderHV::doRp_AccessEastWestPin ( GCell* gcell, RoutingPad* rp )
  {
    cdebug_log(145,1) << getTypeName() << "::doRp_AccessNorthPin() " << rp << endl;

    Net*         net             = rp->getNet();
    Pin*         pin             = dynamic_cast<Pin*>( rp->getOccurrence().getEntity() );
    Pin::AccessDirection pinDir  = pin->getAccessDirection();
    AutoContact* rpSourceContact = NULL;
    AutoContact* rpContactTarget = NULL;
    AutoContact* turn            = NULL;
    AutoSegment* segment         = NULL;

    doRp_AutoContacts( gcell, rp, rpSourceContact, rpContactTarget, NoProtect );

    turn    = AutoContactTurn::create( gcell, net, Session::getContactLayer(1) );
    segment = AutoSegment::create( rpSourceContact, turn, Flags::Horizontal );
    segment->setAxis( pin->getCenter().getY(), Flags::Force );

    rpSourceContact = turn;
    turn    = AutoContactTurn::create( gcell, net, Session::getContactLayer(1) );
    segment = AutoSegment::create( rpSourceContact, turn, Flags::Vertical );

    DbU::Unit axis = 0;
    if (pinDir == Pin::AccessDirection::EAST)
      axis = gcell->getXMax() - Session::getDVerticalPitch();
    else
      axis = gcell->getXMin() + Session::getDVerticalPitch();
    segment->setAxis( axis );

    cdebug_tabw(145,-1);
    return turn;
  }


  bool  NetBuilderHV::_do_1G_1M1 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_1G_1M1() [Managed Configuration - Optimized] " << getTopology() << endl;

#if THIS_IS_DISABLED
    uint64_t  flags = NoFlags;
    if      (east() ) { flags |= HAccess; }
    else if (west() ) { flags |= HAccess; }
    else if (north()) { flags |= VSmall; }
    else if (south()) { flags |= VSmall; }

    setBothCornerContacts( doRp_Access(getGCell(),getRoutingPads()[0],flags) );
#endif

    if (north() or south()) {
      setBothCornerContacts( doRp_Access(getGCell(),getRoutingPads()[0],VSmall) );
    } else {
      setBothCornerContacts( doRp_Access( getGCell(), getRoutingPads()[0], UseNonPref|HAccess ) );
    }

    cdebug_tabw(145,-1);

    return true;
  }


  bool  NetBuilderHV::_do_1G_xM1 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_1G_" << (int)getConnexity().fields.M1 << "M1() [Managed Configuration]" << endl;

    sortRpByX( getRoutingPads(), NoFlags ); // increasing X.
    for ( size_t i=1 ; i<getRoutingPads().size() ; ++i ) {
      AutoContact* leftContact  = doRp_Access( getGCell(), getRoutingPads()[i-1], HAccess|UseNonPref );
      AutoContact* rightContact = doRp_Access( getGCell(), getRoutingPads()[i  ], HAccess|UseNonPref );
      AutoSegment::create( leftContact, rightContact, Flags::Horizontal );
    }

    Component* globalRp = NULL;
    if      (east()) globalRp = getRoutingPads()[getRoutingPads().size()-1];
    else if (west()) globalRp = getRoutingPads()[0];
    else {
      globalRp = getRoutingPads()[0];

      cdebug_log(145,0) << "| Initial N/S Global RP: " << globalRp << endl;
      for ( size_t i=1 ; i<getRoutingPads().size() ; ++i ) {
        if (getRoutingPads()[i]->getBoundingBox().getHeight() > globalRp->getBoundingBox().getHeight()) {
          cdebug_log(145,0) << "| Better RP: " << globalRp << endl;
          globalRp = getRoutingPads()[i];
        }
      }
    }
    
    AutoContact* globalContact = doRp_Access( getGCell(), globalRp, HAccess );

    if (north() or south()) {
      AutoContact* turn = globalContact;
      globalContact = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment::create( globalContact, turn, Flags::Horizontal );
    }

    setBothCornerContacts( globalContact );

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_xG ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_xG()" << endl;

    const Layer* viaLayer = Session::getDContactLayer();

    if (getConnexity().fields.globals == 2) {
      setBothCornerContacts( AutoContactTurn::create( getGCell(), getNet(), viaLayer ) );
    } else if (getConnexity().fields.globals == 3) {
      if (east() and west()) {
        setSouthWestContact( AutoContactTurn::create( getGCell(), getNet(), viaLayer ) );
        setNorthEastContact( AutoContactVTee::create( getGCell(), getNet(), viaLayer ) );
        if (south()) swapCornerContacts();

        AutoSegment::create( getSouthWestContact(), getNorthEastContact(), Flags::Vertical );
      } else {
        setSouthWestContact( AutoContactTurn::create( getGCell(), getNet(), viaLayer ) );
        setNorthEastContact( AutoContactHTee::create( getGCell(), getNet(), viaLayer ) );
        if (west()) swapCornerContacts();

        AutoSegment::create( getSouthWestContact(), getNorthEastContact(), Flags::Horizontal );
      }
    } else { // fields.globals == 4.
      AutoContact* turn = AutoContactTurn::create( getGCell(), getNet(), viaLayer );
      setSouthWestContact( AutoContactHTee::create( getGCell(), getNet(), viaLayer ) );
      setNorthEastContact( AutoContactVTee::create( getGCell(), getNet(), viaLayer ) );
      AutoSegment::create( getSouthWestContact(), turn, Flags::Horizontal );
      AutoSegment::create( turn, getNorthEastContact(), Flags::Vertical   );
    } 
    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_2G ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_2G()" << endl;

    const Layer* viaLayer = Session::getDContactLayer();

    if (east() and west()) {
      setSouthWestContact( AutoContactTurn::create( getGCell(), getNet(), viaLayer ) );
      setNorthEastContact( AutoContactTurn::create( getGCell(), getNet(), viaLayer ) );
      AutoSegment::create( getSouthWestContact(), getNorthEastContact(), Flags::Vertical );
    } else if (south() and north()) {
      setSouthWestContact( AutoContactTurn::create( getGCell(), getNet(), viaLayer ) );
      setNorthEastContact( AutoContactTurn::create( getGCell(), getNet(), viaLayer ) );
      AutoSegment::create( getSouthWestContact(), getNorthEastContact(), Flags::Horizontal );
    } else {
      setBothCornerContacts( AutoContactTurn::create( getGCell(), getNet(), viaLayer ) );
    }

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_xG_1Pad ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_xG_1Pad() [Managed Configuration - Optimized] " << getTopology() << endl;
    cdebug_log(145,0) << "getConnexity().globals:" << (int)getConnexity().fields.globals << endl;

    uint64_t  flags       = NoFlags;
    bool      eastPad     = false;
    bool      westPad     = false;
    bool      northPad    = false;
    bool      southPad    = false;
    Instance* padInstance = getRoutingPads()[0]->getOccurrence().getPath().getHeadInstance();

    switch ( padInstance->getTransformation().getOrientation() ) {
      case Transformation::Orientation::ID: northPad = true; break;
      case Transformation::Orientation::MY: southPad = true; break;
      case Transformation::Orientation::YR:
      case Transformation::Orientation::R3: eastPad  = true; flags |= HAccess; break;
      case Transformation::Orientation::R1: westPad  = true; flags |= HAccess; break;
      default:
        cerr << Warning( "Unmanaged orientation %s for pad <%s>."
                       , getString(padInstance->getTransformation().getOrientation()).c_str()
                       , getString(padInstance).c_str() ) << endl;
        break;
    }
    cdebug_log(145,0) << "eastPad:"  << eastPad  << ", "
                      << "westPad:"  << westPad  << ", "
                      << "northPad:" << northPad << ", "
                      << "southPad:" << southPad
                      << endl;

    AutoContact* source = doRp_AccessPad( getRoutingPads()[0], flags );
    // Point        position     = getRoutingPads()[0]->getCenter();
    // AutoContact* source       = NULL;
    // GCell*       gcell        = Session::getAnabatic()->getGCellGrid()->getGCell(position);

    // source = AutoContactTerminal::create ( gcell
    //                                      , getRoutingPads()[0]
    //                                      , Session::getContactLayer(3)
    //                                      , position
    //                                      , Session::getViaWidth(3), Session::getViaWidth(3)
    //                                      );
    // source->setFlags( CntFixed );

    // if (northPad or eastPad) {
    //   getSouthWestContact() = getNorthEastContact() = source;
    //   cdebug_tabw(145,-1);
    //   return;
    // }

  // Check for straight lines, which are not managed by _do_xG().
    if (getConnexity().fields.globals == 1) {
      if (  (westPad and (east() != NULL))
         or (eastPad and (west() != NULL)) ) {
        AutoContact* turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
        setBothCornerContacts( AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) ) );
        AutoSegment::create( source, turn, Flags::Horizontal );
        AutoSegment::create( turn, getNorthEastContact(), Flags::Vertical );
        cdebug_tabw(145,-1);
        return true;
      } else if (  (southPad and (north() != NULL))
                or (northPad and (south() != NULL)) ) {
        AutoContact* turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
        setBothCornerContacts( AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) ) );
        AutoSegment::create( source, turn, Flags::Vertical );
        AutoSegment::create( turn, getNorthEastContact(), Flags::Horizontal );
        cdebug_tabw(145,-1);
        return true;
      }
    }

    ++getConnexity().fields.globals;
    --getConnexity().fields.Pad;

    if (westPad ) addToWests ( source->getBodyHook() );
    if (eastPad ) addToEasts ( source->getBodyHook() );
    if (southPad) addToSouths( source->getBodyHook() );
    if (northPad) addToNorths( source->getBodyHook() );

    _do_xG();

    if (westPad) {
      AutoSegment::create( source, getSouthWestContact(), Flags::Horizontal );
      clearWests();
    }
    if (eastPad) {
      AutoSegment::create( source, getNorthEastContact(), Flags::Horizontal );
      clearEasts();
    }
    if (southPad) {
      AutoSegment::create( source, getSouthWestContact(), Flags::Vertical );
      clearSouths();
    }
    if (northPad) {
      AutoSegment::create( source, getNorthEastContact(), Flags::Vertical );
      clearNorths();
    }
    --(getConnexity().fields.globals);

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_1G_1PinM2 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_1G_1PinM2() [Managed Configuration - Optimized] " << getTopology() << endl;

    AutoContact* rpSourceContact = NULL;
    AutoContact* rpContactTarget = NULL;

    doRp_AutoContacts( getGCell(), getRoutingPads()[0], rpSourceContact, rpContactTarget, NoFlags );

    AutoContact* turn1   = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
    AutoSegment::create( rpSourceContact, turn1, Flags::Horizontal );

    if (east() or west()) {
      AutoContact* turn2 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment::create( turn1, turn2, Flags::Vertical );
      turn1 = turn2;
    }
    setBothCornerContacts( turn1 );

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_1G_1PinM1 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_1G_1PinM1() [Managed Configuration - Optimized] " << getTopology() << endl;

    AutoContact* rpSourceContact = NULL;
    AutoContact* rpContactTarget = NULL;
    AutoContact* turn            = NULL;

    doRp_AutoContacts( getGCell(), getRoutingPads()[0], rpSourceContact, rpContactTarget, NoProtect );

    Pin* pin = dynamic_cast<Pin*>( getRoutingPads()[0]->getOccurrence().getEntity() );
    Pin::AccessDirection pinDir = pin->getAccessDirection();
    if (  (pinDir == Pin::AccessDirection::NORTH)
       or (pinDir == Pin::AccessDirection::SOUTH) ) {
      turn = AutoContactTurn::create( getGCell(), getNet(), Session::getRoutingLayer(1) );
      AutoSegment::create( rpSourceContact, turn, Flags::Vertical|Flags::UseNonPref );
      rpSourceContact = turn;

      turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment* horizontal = AutoSegment::create( rpSourceContact, turn, Flags::Horizontal );
      rpSourceContact = turn;

      DbU::Unit axis = getGCell()->getYMax() - Session::getDHorizontalPitch();
      if (pinDir == Pin::AccessDirection::SOUTH)
        axis = getGCell()->getYMin() + Session::getDHorizontalPitch();
      cdebug_log(145,0) << "axis:" << DbU::getValueString(axis) << endl;
      
      horizontal->setAxis( axis, Flags::Force );
      horizontal->setFlags( AutoSegment::SegFixed|AutoSegment::SegFixedAxis );
      cdebug_log(145,0) << horizontal << endl;

      turn = AutoContactTurn::create( getGCell(), getNet(), Session::getRoutingLayer(1) );
      AutoSegment* vertical = AutoSegment::create( rpSourceContact, turn, Flags::Vertical );
      rpSourceContact = turn;
      vertical->setAxis( pin->getX(), Flags::Force );
      vertical->setFlags( AutoSegment::SegFixed|AutoSegment::SegFixedAxis );
      cdebug_log(145,0) << vertical << endl;

      turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
      horizontal = AutoSegment::create( rpSourceContact, turn, Flags::Horizontal );
      horizontal->setAxis( axis, Flags::Force );
      rpSourceContact = turn;
    } else {
      turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment::create( rpSourceContact, turn, Flags::Horizontal );
      rpSourceContact = turn;
    }

    if (east() or west()) {
      rpSourceContact = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment* vertical = AutoSegment::create( turn, rpSourceContact, Flags::Vertical );

      DbU::Unit axis = getGCell()->getXMax() - Session::getDVerticalPitch();
      if (pinDir == Pin::AccessDirection::WEST)
        axis = getGCell()->getXMin() + Session::getDVerticalPitch();
      cdebug_log(145,0) << "axis:" << DbU::getValueString(axis) << endl;
      
      vertical->setAxis( axis, Flags::Force );
      vertical->setFlags( AutoSegment::SegFixed|AutoSegment::SegFixedAxis );

      turn = rpSourceContact;
    }
    setBothCornerContacts( turn );

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_2G_1PinM1 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_2G_1PinM1() [Managed Configuration - Optimized] " << getTopology() << endl;

    AutoContact* rpSourceContact = NULL;
    AutoContact* rpContactTarget = NULL;
    AutoContact* tee             = NULL;
    AutoContact* turn            = NULL;

    doRp_AutoContacts( getGCell(), getRoutingPads()[0], rpSourceContact, rpContactTarget, NoProtect );

    Pin* pin = dynamic_cast<Pin*>( getRoutingPads()[0]->getOccurrence().getEntity() );
    Pin::AccessDirection pinDir = pin->getAccessDirection();
    if (  (pinDir == Pin::AccessDirection::NORTH)
       or (pinDir == Pin::AccessDirection::SOUTH) ) {
      turn = AutoContactTurn::create( getGCell(), getNet(), Session::getRoutingLayer(1) );
      AutoSegment::create( rpSourceContact, turn, Flags::Vertical|Flags::UseNonPref );
      rpSourceContact = turn;

      turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment* horizontal = AutoSegment::create( rpSourceContact, turn, Flags::Horizontal );
      rpSourceContact = turn;

      DbU::Unit axis = getGCell()->getYMax() - Session::getDHorizontalPitch();
      if (pinDir == Pin::AccessDirection::SOUTH)
        axis = getGCell()->getYMin() + Session::getDHorizontalPitch();
      horizontal->setAxis( axis, Flags::Force );
      horizontal->setFlags( AutoSegment::SegFixed );

      turn = AutoContactTurn::create( getGCell(), getNet(), Session::getRoutingLayer(1) );
      AutoSegment* vertical = AutoSegment::create( rpSourceContact, turn, Flags::Vertical );
      rpSourceContact = turn;
      vertical->setFlags( AutoSegment::SegFixed );

      turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
      horizontal = AutoSegment::create( rpSourceContact, turn, Flags::Horizontal );
      horizontal->setAxis( axis, Flags::Force );
      rpSourceContact = turn;
      turn            = NULL;
    }

    if (east() and west()) {
    // Pin must be North or South.
      tee = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment::create( rpSourceContact, tee, Flags::Vertical );
    } else if (north() and south()) {
    // Pin must be East or West.
      tee = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment::create( rpSourceContact, tee, Flags::Horizontal );
    } else {
      if (  (pinDir == Pin::AccessDirection::EAST)
         or (pinDir == Pin::AccessDirection::WEST) ) {
        turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( rpSourceContact, turn, Flags::Horizontal );
        rpSourceContact = turn;
      }

      tee = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment* vertical = AutoSegment::create( rpSourceContact, tee, Flags::Vertical );

      if (  (pinDir == Pin::AccessDirection::EAST)
         or (pinDir == Pin::AccessDirection::WEST) ) {
        DbU::Unit axis = getGCell()->getXMax() - Session::getDVerticalPitch();
        if (pinDir == Pin::AccessDirection::WEST)
          axis = getGCell()->getXMin() + Session::getDVerticalPitch();
        cdebug_log(145,0) << "axis:" << DbU::getValueString(axis) << endl;
      
        vertical->setAxis( axis, Flags::Force );
        vertical->setFlags( AutoSegment::SegFixed|AutoSegment::SegFixedAxis );
      }
    }

    setBothCornerContacts( tee );

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_xG_1PinM2 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_xG_1PinM2() [Managed Configuration - Optimized] " << getTopology() << endl;

    AutoContact* rpSourceContact = NULL;
    AutoContact* rpContactTarget = NULL;
    AutoContact* turn            = NULL;

    doRp_AutoContacts( getGCell(), getRoutingPads()[0], rpSourceContact, rpContactTarget, NoFlags );

    Pin* pin = dynamic_cast<Pin*>( getRoutingPads()[0]->getOccurrence().getEntity() );
    Pin::AccessDirection pinDir = pin->getAccessDirection();
    if (  (pinDir == Pin::AccessDirection::EAST)
       or (pinDir == Pin::AccessDirection::WEST) ) {
      turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment::create( rpSourceContact, turn, Flags::Horizontal );
      rpSourceContact = turn;

      turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment* vertical = AutoSegment::create( rpSourceContact, turn, Flags::Vertical );
      rpSourceContact = turn;

      Box                cellAb = getAnabatic()->getCell()->getAbutmentBox();
      RoutingLayerGauge* lgM3   = Session::getLayerGauge( 2 );
      DbU::Unit axis = lgM3->getTrackPosition( cellAb.getXMin()
                                             , cellAb.getXMax()
                                             , getGCell()->getXMax() - Session::getDVerticalPitch()
                                             , Constant::Superior );
      if (pinDir == Pin::AccessDirection::WEST)
        axis = lgM3->getTrackPosition( cellAb.getXMin()
                                     , cellAb.getXMax()
                                     , getGCell()->getXMin() + Session::getDVerticalPitch()
                                     , Constant::Inferior );
      cdebug_log(145,0) << "axis:" << DbU::getValueString(axis) << endl;
      
      vertical->setAxis( axis, Flags::Force );
      vertical->setFlags( AutoSegment::SegFixed|AutoSegment::SegFixedAxis );
    }

    if (getConnexity().fields.globals == 2) {
      if (west() and south()) {
        AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( rpSourceContact, turn1, Flags::Horizontal );

        AutoContact* vtee1 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( turn1, vtee1, Flags::Vertical );

        setBothCornerContacts( vtee1 );
      } else if (west() and north()) {
        AutoContact* vtee1 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( rpSourceContact, vtee1, Flags::Horizontal );

        AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( vtee1, turn1, Flags::Vertical );

        setSouthWestContact( turn1 );
        setNorthEastContact( vtee1 );
      } else if (south() and north()) {
        AutoContact* vtee1 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( rpSourceContact, vtee1, Flags::Horizontal );

        setBothCornerContacts( vtee1 );
      } else if (east() and north()) {
        AutoContact* htee1 = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( rpSourceContact, htee1, Flags::Horizontal );

        setBothCornerContacts( htee1 );
      } else if (east() and south()) {
        AutoContact* htee1 = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( rpSourceContact, htee1, Flags::Horizontal );

        setBothCornerContacts( htee1 );
      } else if (east() and west()) {
        AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( rpSourceContact, turn1, Flags::Horizontal );

        AutoContact* htee1 = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( turn1, htee1, Flags::Vertical );

        setBothCornerContacts( htee1 );
      }
    } else {
      AutoContact* htee1 = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment::create( rpSourceContact, htee1, Flags::Horizontal );

      AutoContact* htee2 = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment::create( htee1, htee2, Flags::Horizontal );
      
      if (pinDir == Pin::AccessDirection::EAST)
        std::swap( htee1, htee2 );

      setSouthWestContact( htee1 );
      setNorthEastContact( htee2 );
    }

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_1G_1PinM3 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_1G_1PinM3() [Managed Configuration - Optimized] " << getTopology() << endl;

    AutoContact* rpSourceContact = NULL;

    rpSourceContact = doRp_AccessNorthPin( getGCell(), getRoutingPads()[0] );

    AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
    AutoSegment::create( rpSourceContact, turn1, Flags::Vertical );

    if (north() or south()) {
      AutoContact* turn2 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment::create( turn1, turn2, Flags::Horizontal );
      turn1 = turn2;
    }
    setBothCornerContacts( turn1 );

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_xG_1PinM3 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_xG_1PinM3() [Managed Configuration - Optimized] " << getTopology() << endl;

    AutoContact* rpSourceContact = NULL;
    AutoContact* rpContactTarget = NULL;

    doRp_AutoContacts( getGCell(), getRoutingPads()[0], rpSourceContact, rpContactTarget, NoFlags );

    if (getConnexity().fields.globals == 2) {
      if (west() and south()) {
        AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( rpSourceContact, turn1, Flags::Vertical );

        AutoContact* htee1 = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( turn1, htee1, Flags::Horizontal );

        setBothCornerContacts( htee1 );
      } else if (west() and north()) {
        AutoContact* htee1 = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( rpSourceContact, htee1, Flags::Vertical );

        AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( turn1, htee1, Flags::Horizontal );

        setSouthWestContact( htee1 );
        setNorthEastContact( turn1 );
      } else if (east() and north()) {
        AutoContact* vtee1 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( rpSourceContact, vtee1, Flags::Vertical );

        setBothCornerContacts( vtee1 );
      } else if (east() and south()) {
        AutoContact* htee1 = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( rpSourceContact, htee1, Flags::Vertical );

        AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( htee1, turn1, Flags::Horizontal );

        setSouthWestContact( turn1 );
        setNorthEastContact( htee1 );
      } else if (north() and south()) {
        AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( rpSourceContact, turn1, Flags::Vertical );

        AutoContact* vtee1 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( turn1, vtee1, Flags::Horizontal );

        setBothCornerContacts( vtee1 );
      } else {  // Remaining case is East & West.
        AutoContact* htee1 = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
        AutoSegment::create( rpSourceContact, htee1, Flags::Vertical );

        setBothCornerContacts( htee1 );
      }
    } else {
      AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoContact* turn2 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment::create( rpSourceContact, turn1, Flags::Vertical );
      AutoSegment::create( turn1, turn2, Flags::Horizontal );

      AutoContact* vtee1 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment::create( turn2, vtee1, Flags::Vertical );

      AutoContact* vtee2 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment::create( vtee1, vtee2, Flags::Vertical );
      
      setSouthWestContact( vtee1 );
      setNorthEastContact( vtee2 );
    }

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_2G_xM1_1PinM3 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_2G_xM1_1PinM3() [Managed Configuration - Optimized] " << getTopology() << endl;

    RoutingPad*  pinM3      = NULL;
    AutoContact* pinContact = NULL;
    AutoContact* dummy      = NULL;

    sortRpByX( getRoutingPads(), NoFlags ); // increasing X.

    vector<RoutingPad*> rpsM1;
    for ( RoutingPad* rp : getRoutingPads() ) {
      if (dynamic_cast<Pin*>(rp->getOccurrence().getEntity())) pinM3 = rp;
      else rpsM1.push_back( rp );
    }
    
    for ( size_t i=1 ; i<rpsM1.size() ; ++i ) {
      AutoContact* leftContact  = doRp_Access( getGCell(), getRoutingPads()[i-1], HAccess );
      AutoContact* rightContact = doRp_Access( getGCell(), getRoutingPads()[i  ], HAccess );
      AutoSegment::create( leftContact, rightContact, Flags::Horizontal );
    }

    doRp_AutoContacts( getGCell(), pinM3, pinContact, dummy, NoFlags );

    AutoContact* m1contact  = doRp_Access( getGCell(), rpsM1.back(), HAccess );

    AutoContact* vtee1 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
    AutoSegment::create( m1contact , vtee1, Flags::Horizontal );
    AutoSegment::create( pinContact, vtee1, Flags::Vertical );

    AutoContact* vtee2 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
    AutoSegment::create( vtee1, vtee2, Flags::Vertical );

    setBothCornerContacts( vtee2 );

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_3G_xM1_1PinM3 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_3G_1M1_1PinM3() [Managed Configuration - Optimized] " << getTopology() << endl;

    RoutingPad*  pinM3      = NULL;
    AutoContact* pinContact = NULL;
    AutoContact* dummy      = NULL;

    sortRpByX( getRoutingPads(), NoFlags ); // increasing X.

    vector<RoutingPad*> rpsM1;
    for ( RoutingPad* rp : getRoutingPads() ) {
      if (dynamic_cast<Pin*>(rp->getOccurrence().getEntity())) pinM3 = rp;
      else rpsM1.push_back( rp );
    }
    
    for ( size_t i=1 ; i<rpsM1.size() ; ++i ) {
      AutoContact* leftContact  = doRp_Access( getGCell(), getRoutingPads()[i-1], HAccess );
      AutoContact* rightContact = doRp_Access( getGCell(), getRoutingPads()[i  ], HAccess );
      AutoSegment::create( leftContact, rightContact, Flags::Horizontal );
    }

    doRp_AutoContacts( getGCell(), pinM3, pinContact, dummy, NoFlags );

    AutoContact* m1contact  = doRp_Access( getGCell(), rpsM1.back(), HAccess );

    AutoContact* vtee1 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
    AutoSegment::create( m1contact , vtee1, Flags::Horizontal );

    AutoContact* vtee2 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
    AutoSegment::create( vtee1, vtee2, Flags::Vertical );

    AutoContact* vtee3 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
    AutoSegment::create( vtee2, vtee3, Flags::Vertical );
      
    if (not south() or not north()) {
      AutoSegment::create( pinContact, vtee1, Flags::Vertical );
    }
      
    if (not east() or not west()) {
      AutoSegment::create( pinContact, vtee2, Flags::Horizontal );
    }

    if (not south()) {
      setSouthWestContact( vtee2 );
      setNorthEastContact( vtee3 );
    } else if (not north()) {
      setSouthWestContact( vtee3 );
      setNorthEastContact( vtee2 );
    } else if (not east()) {
      setSouthWestContact( vtee3 );
      setNorthEastContact( vtee1 );
    } else if (not west()) {
      setSouthWestContact( vtee1 );
      setNorthEastContact( vtee3 );
    }

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_1G_xM1_1PinM2 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_1G_xM1_1PinM2() [Managed Configuration - Optimized] " << getTopology() << endl;

    sortRpByX( getRoutingPads(), NoFlags ); // increasing X.

    vector<RoutingPad*> rpsM1;
    RoutingPad*         pinM2 = NULL;
    for ( RoutingPad* rp : getRoutingPads() ) {
      if (dynamic_cast<Pin*>(rp->getOccurrence().getEntity())) pinM2 = rp;
      else rpsM1.push_back( rp );
    }
    
    for ( size_t i=1 ; i<rpsM1.size() ; ++i ) {
      AutoContact* leftContact  = doRp_Access( getGCell(), getRoutingPads()[i-1], HAccess );
      AutoContact* rightContact = doRp_Access( getGCell(), getRoutingPads()[i  ], HAccess );
      AutoSegment::create( leftContact, rightContact, Flags::Horizontal );
    }

    AutoContact* turn         = NULL;
    AutoContact* tee          = NULL;
    AutoContact* pinM2Contact = NULL;
    AutoContact* rpM1Contact  = NULL;
    doRp_AutoContacts( getGCell(), pinM2, pinM2Contact, rpM1Contact, NoProtect );
    rpM1Contact = doRp_Access( getGCell(), rpsM1[0], (north() or south()) ? HAccess : NoFlags );

    if (north() or south()) {
      turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
      tee  = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );

      AutoSegment::create( rpM1Contact , tee , Flags::Horizontal );
      AutoSegment::create( pinM2Contact, turn, Flags::Horizontal );
      AutoSegment::create( tee         , turn, Flags::Vertical );

      setBothCornerContacts( tee );
    } else {
      turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
      tee  = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );

      AutoSegment::create( rpM1Contact , tee , Flags::Vertical );
      AutoSegment::create( pinM2Contact, tee , Flags::Horizontal );
      AutoSegment::create( tee         , turn, Flags::Vertical );

      setBothCornerContacts( turn );
    }
    
    for ( size_t i=1 ; i<rpsM1.size() ; ++i ) {
      AutoContact* leftContact  = doRp_Access( getGCell(), getRoutingPads()[i-1], HAccess );
      AutoContact* rightContact = doRp_Access( getGCell(), getRoutingPads()[i  ], HAccess );
      AutoSegment::create( leftContact, rightContact, Flags::Horizontal );
    }

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_2G_xM1_1PinM2 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_2G_xM1_1PinM2() [Managed Configuration - Optimized] " << getTopology() << endl;

    sortRpByX( getRoutingPads(), NoFlags ); // increasing X.

    vector<RoutingPad*> rpsM1;
    RoutingPad*         pinM2 = NULL;
    for ( RoutingPad* rp : getRoutingPads() ) {
      if (dynamic_cast<Pin*>(rp->getOccurrence().getEntity())) pinM2 = rp;
      else rpsM1.push_back( rp );
    }

    AutoContact* pinM2Contact = NULL;
    AutoContact* rpM1Contact  = NULL;
    doRp_AutoContacts( getGCell(), pinM2, pinM2Contact, rpM1Contact, NoFlags );
    rpM1Contact = doRp_Access( getGCell(), rpsM1[0], NoFlags );

    if (north() and south()) {
      cdebug_log(145,0) << "Case north & south." << endl;
      AutoContact* htee = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoContact* vtee = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );

      AutoSegment::create( pinM2Contact, htee, Flags::Horizontal );
      AutoSegment::create( rpM1Contact , htee, Flags::Vertical   );
      AutoSegment::create( htee        , vtee, Flags::Horizontal );
      setBothCornerContacts( vtee );
    } else if (east() and west()) {
      cdebug_log(145,0) << "Case east & west." << endl;
      AutoContact* htee1 = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoContact* htee2 = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoContact* turn  = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );

      AutoSegment::create( pinM2Contact, htee1, Flags::Horizontal );
      AutoSegment::create( rpM1Contact , htee1, Flags::Vertical   );
      AutoSegment::create( htee1       , turn , Flags::Horizontal );
      AutoSegment::create( htee2       , turn , Flags::Vertical   );
      setBothCornerContacts( htee2 );
    } else {
      cdebug_log(145,0) << "Case bend." << endl;
      AutoContact* vtee1 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoContact* htee2 = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );

      AutoSegment::create( pinM2Contact, vtee1, Flags::Horizontal );
      AutoSegment::create( rpM1Contact , vtee1, Flags::Vertical   );
      AutoSegment::create( vtee1       , turn1, Flags::Vertical   );
      AutoSegment::create( turn1       , htee2, Flags::Horizontal );
      setBothCornerContacts( htee2 );
    }

    cdebug_log(145,0) << "Wiring all M1 together." << endl;
    for ( size_t i=1 ; i<rpsM1.size() ; ++i ) {
      AutoContact* leftContact  = doRp_Access( getGCell(), getRoutingPads()[i-1], HAccess );
      AutoContact* rightContact = doRp_Access( getGCell(), getRoutingPads()[i  ], HAccess );
      AutoSegment::create( leftContact, rightContact, Flags::Horizontal );
    }

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_1G_1M1_1PinM3 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_1G_1M1_1PinM3() [Managed Configuration - Optimized] " << getTopology() << endl;

    AutoContact* rpSourceContact = NULL;

    RoutingPad* pinM3 = getRoutingPads()[0];
    RoutingPad* rpM1  = getRoutingPads()[1];
    if (dynamic_cast<Pin*>(rpM1->getOccurrence().getEntity())) std::swap( rpM1, pinM3 );

    AutoContact* contact1 = doRp_Access( getGCell(), rpM1, HAccess );
    AutoContact* htee     = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
    AutoSegment::create( contact1, htee, Flags::Horizontal );

    rpSourceContact = doRp_AccessNorthPin( getGCell(), pinM3 );

    if (north() or south()) {
      AutoContact* turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
      AutoSegment::create( rpSourceContact, turn, Flags::Vertical   );
      AutoSegment::create( turn           , htee, Flags::Horizontal );
    } else {
      AutoSegment::create( rpSourceContact, htee, Flags::Vertical );
    }
    setBothCornerContacts( htee );

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_2G_1M1 ()
  {
    return _do_xG_1M1();
  }


  bool  NetBuilderHV::_do_xG_1M1 ()
  {
    if ((int)getConnexity().fields.M1 != 1) return false;
    
    cdebug_log(145,1) << getTypeName()
                      << "::_do_xG_"  << (int)getConnexity().fields.M1
                      << "M1() [G:"   << (int)getConnexity().fields.globals << " Managed Configuration]" << endl;
    cdebug_log(145,0) << "getConnexity(): " << getConnexity().connexity << endl;
    cdebug_log(145,0) << "north:     " << north() << endl;
    cdebug_log(145,0) << "south:     " << south() << endl;
    cdebug_log(145,0) << "east:      " << east () << endl;
    cdebug_log(145,0) << "west:      " << west () << endl;

    const Layer* viaLayer1 = Session::getContactLayer(1);

    if (getConnexity().fields.globals == 2) {
      if (north() and south()) {
        AutoContact* contact1 = doRp_Access( getGCell(), getRoutingPads()[0], HAccess );
        AutoContact* contact2 = AutoContactHTee::create( getGCell(), getNet(), viaLayer1 );
        AutoSegment::create( contact1, contact2, Flags::Horizontal );
        contact1 = AutoContactTurn::create( getGCell(), getNet(), viaLayer1 );
        AutoSegment::create( contact1, contact2, Flags::Horizontal );
        setNorthEastContact( contact1 );
        setSouthWestContact( contact2 );
      } else if (east() and west()) {
        // AutoContact* contact1 = doRp_Access( getGCell(), getRoutingPads()[0], NoFlags );
        // AutoContact* contact2 = AutoContactHTee::create( getGCell(), getNet(), viaLayer1 );
        // AutoSegment::create( contact1, contact2, Flags::Vertical );
        // setBothCornerContacts( contact2 );
        AutoContact* contact1  = NULL;
        AutoContact* contact2  = NULL;
        uint64_t     flags     = checkRoutingPadSize( getRoutingPads()[0] );

        if (flags & VSmall) {
          doRp_AutoContacts( getGCell(), getRoutingPads()[0], contact1, contact2, NoFlags );
          contact2 = AutoContactHTee::create( getGCell(), getNet(), viaLayer1 );
          AutoSegment::create( contact1, contact2, Flags::Vertical );

          setBothCornerContacts( contact2 );
        } else {
          doRp_AutoContacts( getGCell(), getRoutingPads()[0], contact1, contact2, NoFlags );
          setSouthWestContact( contact1 );

          doRp_AutoContacts( getGCell(), getRoutingPads()[0], contact1, contact2, NoFlags );
          setNorthEastContact( contact1 );
        }
      } else {
        AutoContact* contact1 = doRp_Access( getGCell(), getRoutingPads()[0], HAccess );
        AutoContact* contact2 = AutoContactTurn::create( getGCell(), getNet(), viaLayer1 );
        AutoSegment::create( contact1, contact2, Flags::Horizontal );

        contact1 = AutoContactVTee::create( getGCell(), getNet(), viaLayer1 );
        AutoSegment::create( contact1, contact2, Flags::Vertical );
        setBothCornerContacts( contact1 );
      }
    } else if (getConnexity().fields.globals == 3) {
      if (not west() or not east()) {
        AutoContact* contact1 = doRp_Access( getGCell(), getRoutingPads()[0], HAccess );
        AutoContact* contact2 = AutoContactVTee::create( getGCell(), getNet(), viaLayer1 );
        AutoSegment::create( contact1, contact2, Flags::Horizontal );
        AutoContact* contact3 = AutoContactVTee::create( getGCell(), getNet(), viaLayer1 );
        AutoSegment::create( contact2, contact3, Flags::Vertical );

        setSouthWestContact( (east()) ? contact2 : contact3 );
        setNorthEastContact( (east()) ? contact3 : contact2 );
      } else {
        AutoContact* contact1 = doRp_Access( getGCell(), getRoutingPads()[0], NoFlags );
        AutoContact* contact2 = AutoContactVTee::create( getGCell(), getNet(), viaLayer1 );
        AutoSegment::create( contact1, contact2, Flags::Vertical );
        AutoContact* contact3 = AutoContactVTee::create( getGCell(), getNet(), viaLayer1 );
        AutoSegment::create( contact2, contact3, Flags::Vertical );

        setSouthWestContact( (north()) ? contact2 : contact3 );
        setNorthEastContact( (north()) ? contact3 : contact2 );
      }
    } else {
      AutoContact* contact1 = doRp_Access( getGCell(), getRoutingPads()[0], HAccess );
      AutoContact* contact2 = AutoContactVTee::create( getGCell(), getNet(), viaLayer1 );
      AutoSegment::create( contact1, contact2, Flags::Horizontal );
      AutoContact* contact3 = AutoContactVTee::create( getGCell(), getNet(), viaLayer1 );
      AutoSegment::create( contact2, contact3, Flags::Vertical );
      AutoContact* contact4 = AutoContactVTee::create( getGCell(), getNet(), viaLayer1 );
      AutoSegment::create( contact2, contact4, Flags::Vertical );

      setSouthWestContact( contact3 );
      setNorthEastContact( contact4 );
    }

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_xG_1M1_1M2 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_xG_1M1_1M2() [Managed Configuration]" << endl;

    Component* rpL1;
    Component* rpL2;
    if (getRoutingPads()[0]->getLayer() == Session::getRoutingLayer(0)) {
      rpL1 = getRoutingPads()[0];
      rpL2 = getRoutingPads()[1];
    } else {
      rpL1 = getRoutingPads()[1];
      rpL2 = getRoutingPads()[0];
    }
    cdebug_log(145,0) << "rpL1 := " << rpL1 << endl;
    cdebug_log(145,0) << "rpL2 := " << rpL2 << endl;

    AutoContact* rpL1ContactSource = NULL;
    AutoContact* rpL1ContactTarget = NULL;
    AutoContact* rpL2ContactSource = NULL;
    AutoContact* rpL2ContactTarget = NULL;

    doRp_AutoContacts( getGCell(), rpL1, rpL1ContactSource, rpL1ContactTarget, NoFlags );
    doRp_AutoContacts( getGCell(), rpL2, rpL2ContactSource, rpL2ContactTarget, NoFlags );

    const Layer* viaLayer1 = Session::getContactLayer(1);
    const Layer* viaLayer2 = Session::getContactLayer(2);

    AutoContact* subContact = AutoContactTurn::create( getGCell(), getNet(), viaLayer1 );
    AutoSegment::create( rpL1ContactSource, subContact, Flags::Horizontal );
    AutoSegment::create( rpL2ContactSource, subContact, Flags::Vertical );

    if (south() or west()) {
      doRp_AutoContacts( getGCell(), rpL2, rpL2ContactSource, rpL2ContactTarget, DoSourceContact );
      if (south() and west()) {
        setSouthWestContact( AutoContactHTee::create( getGCell(), getNet(), viaLayer2 ) );
        AutoSegment::create( rpL2ContactSource, getSouthWestContact(), Flags::Horizontal );
      } else {
        if (south()) {
          setSouthWestContact( AutoContactTurn::create( getGCell(), getNet(), viaLayer2 ) );
          AutoSegment::create( rpL2ContactSource, getSouthWestContact(), Flags::Horizontal );
        } else {
          setSouthWestContact( rpL2ContactSource );
        }
      }
    }

    if (north() or east()) {
      doRp_AutoContacts( getGCell(), rpL2, rpL2ContactSource, rpL2ContactTarget, DoTargetContact );
      if (north() and east()) {
        setNorthEastContact( AutoContactHTee::create( getGCell(), getNet(), viaLayer2 ) );
        AutoSegment::create( rpL2ContactTarget, getNorthEastContact(), Flags::Horizontal );
      } else {
        if (north()) {
          setNorthEastContact( AutoContactTurn::create( getGCell(), getNet(), viaLayer2 ) );
          AutoSegment::create( rpL2ContactTarget, getNorthEastContact(), Flags::Horizontal );
        } else {
          setNorthEastContact( rpL2ContactTarget );
        }
      }
    }

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_xG_xM1_xM3 ()
  {
    cdebug_log(145,1) << getTypeName()
                      << "::_do_xG_"  << (int)getConnexity().fields.M1
                      << "M1_"        << (int)getConnexity().fields.M3
                      << "M3() [G:"   << (int)getConnexity().fields.globals << " Managed Configuration]" << endl;
    cdebug_log(145,0) << "getConnexity(): " << getConnexity().connexity << endl;
    cdebug_log(145,0) << "north:     " << north() << endl;
    cdebug_log(145,0) << "south:     " << south() << endl;
    cdebug_log(145,0) << "east:      " << east() << endl;
    cdebug_log(145,0) << "west:      " << west() << endl;

    Component* rpM3 = NULL;
    if (getRoutingPads()[0]->getLayer() == Session::getRoutingLayer(2))
      rpM3 = getRoutingPads()[0];

    sortRpByX( getRoutingPads(), NoFlags ); // increasing X.
    for ( size_t i=1 ; i<getRoutingPads().size() ; ++i ) {
      AutoContact* leftContact  = doRp_Access( getGCell(), getRoutingPads()[i-1], HAccess );
      AutoContact* rightContact = doRp_Access( getGCell(), getRoutingPads()[i  ], HAccess );
      AutoSegment::create( leftContact, rightContact, Flags::Horizontal );

      if (not rpM3 and (getRoutingPads()[i]->getLayer() == Session::getRoutingLayer(2)))
        rpM3 = getRoutingPads()[i];
    }

    const Layer* viaLayer1   = Session::getContactLayer(1);
    AutoContact* subContact1 = NULL;

    if (rpM3) {
    // At least one M3 RoutingPad is present: use it.
      if (west() and not south()) {
        setSouthWestContact( doRp_Access( getGCell(), getRoutingPads()[0], HAccess ) );
      } else if (not west() and south()) {
        doRp_AutoContacts( getGCell(), rpM3, getSouthWestContact(), subContact1, DoSourceContact );
      } else if (west() and south()) {
        AutoContact* rpContact = NULL;
        doRp_AutoContacts( getGCell(), rpM3, rpContact, subContact1, DoSourceContact );
        setSouthWestContact( AutoContactVTee::create( getGCell(), getNet(), viaLayer1 ) );
        AutoSegment::create( rpContact, getSouthWestContact(), Flags::Vertical );
      }

      if (east() and not north()) {
        setNorthEastContact( doRp_Access( getGCell(), getRoutingPads()[getRoutingPads().size()-1], HAccess ) );
      } else if (not east() and north()) {
        doRp_AutoContacts( getGCell(), rpM3, subContact1, getNorthEastContact(), DoTargetContact );
      } else if (east() and north()) {
        AutoContact* rpContact = NULL;
        doRp_AutoContacts( getGCell(), rpM3, subContact1, rpContact, DoTargetContact );
        setNorthEastContact( AutoContactVTee::create( getGCell(), getNet(), viaLayer1 ) );
        AutoSegment::create( rpContact, getNorthEastContact(), Flags::Vertical );
      }
    } else {
      cdebug_log(145,0) << "getRoutingPads().size():" << getRoutingPads().size()<< endl;

      if (getRoutingPads().size() == 1) {
        if (   ((east () != NULL) xor (west () != NULL))
           and ((north() != NULL) xor (south() != NULL)) ) {
          cdebug_log(145,0) << "case: One M1, with global turn." << endl;
          
          AutoContact* rpContact = doRp_Access( getGCell(), getRoutingPads()[0], HAccess );
          subContact1 = AutoContactTurn::create( getGCell(), getNet(), viaLayer1 );
          AutoSegment::create( rpContact, subContact1, Flags::Horizontal );

          rpContact   = subContact1;
          subContact1 = AutoContactVTee::create( getGCell(), getNet(), viaLayer1 );
          AutoSegment::create( rpContact, subContact1, Flags::Vertical );

          setBothCornerContacts( subContact1 );
        
          cdebug_tabw(145,-1);
          return true;
        }
      }
      
    // All RoutingPad are M1.
      Component* southWestRp = getRoutingPads()[0];
      cdebug_log(145,0) << "| Initial S-W Global RP: " << southWestRp << endl;
      // for ( size_t i=1 ; i<getRoutingPads().size() ; ++i ) {
      //   if (southWestRp->getBoundingBox().getHeight() >= 4*Session::getPitch(1)) break;
      //   if (getRoutingPads()[i]->getBoundingBox().getHeight() > southWestRp->getBoundingBox().getHeight()) {
      //     southWestRp = getRoutingPads()[i];
      //     cdebug_log(145,0) << "| Better RP: " << southWestRp << endl;
      //   }
      // }

      if (west() and not south()) {
        setSouthWestContact( doRp_Access( getGCell(), southWestRp, HAccess ) );
      } else if (not west() and south()) {
        AutoContact* rpContact = doRp_Access( getGCell(), southWestRp, HAccess );
        setSouthWestContact( AutoContactTurn::create( getGCell(), getNet(), viaLayer1 ) );
        AutoSegment::create( rpContact, getSouthWestContact(), Flags::Horizontal );
      } else if (west() and south()) {
        AutoContact* rpContact = doRp_Access( getGCell(), southWestRp, HAccess );
        setSouthWestContact( AutoContactHTee::create( getGCell(), getNet(), viaLayer1 ) );
        AutoSegment::create( rpContact, getSouthWestContact(), Flags::Horizontal );
      }

      Component* northEastRp = getRoutingPads()[getRoutingPads().size()-1];
      cdebug_log(145,0) << "| Initial N-E Global RP: " << northEastRp << endl;

      if (getRoutingPads().size() > 1) {
        for ( size_t i=getRoutingPads().size()-1; i != 0 ; ) {
          i -= 1;
          if (northEastRp->getBoundingBox().getHeight() >= 4*Session::getPitch(1)) break;
          if (getRoutingPads()[i]->getBoundingBox().getHeight() > northEastRp->getBoundingBox().getHeight()) {
            cdebug_log(145,0) << "| Better RP: " << northEastRp << endl;
            northEastRp = getRoutingPads()[i];
          }
        } 
      }

      if (east() and not north()) {
        setNorthEastContact( doRp_Access( getGCell(), northEastRp, HAccess ) );
      } else if (not east() and north()) {
        AutoContact* rpContact = doRp_Access( getGCell(), northEastRp, HAccess );
        setNorthEastContact( AutoContactTurn::create( getGCell(), getNet(), viaLayer1 ) );
        AutoSegment::create( rpContact, getNorthEastContact(), Flags::Horizontal );
      } else if (east() and north()) {
        AutoContact* rpContact = doRp_Access( getGCell(), northEastRp, HAccess );
        setNorthEastContact( AutoContactHTee::create( getGCell(), getNet(), viaLayer1 ) );
        AutoSegment::create( rpContact, getNorthEastContact(), Flags::Horizontal );
      }
    }

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_4G_1M2 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_4G_1M2() [Managed Configuration]" << endl;

    Component* rpL2 = getRoutingPads()[0];
    cdebug_log(145,0) << "rpL2 := " << rpL2 << endl;

    AutoContact* rpL2ContactSource = NULL;
    AutoContact* rpL2ContactTarget = NULL;

    doRp_AutoContacts( getGCell(), rpL2, rpL2ContactSource, rpL2ContactTarget, DoSourceContact|DoTargetContact );

    const Layer* viaLayer2 = Session::getContactLayer(2);

    setSouthWestContact( AutoContactHTee::create( getGCell(), getNet(), viaLayer2 ) );
    setNorthEastContact( AutoContactHTee::create( getGCell(), getNet(), viaLayer2 ) );

    AutoSegment::create( getSouthWestContact(), rpL2ContactSource, Flags::Horizontal );
    AutoSegment::create( rpL2ContactTarget, getNorthEastContact(), Flags::Horizontal );

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_xG_xM2 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_"
                      << (int)getConnexity().fields.globals << "G_"
                      << (int)getConnexity().fields.M2 << "M2() [Managed Configuration - x]" << endl;

    Component* biggestRp = getRoutingPads()[0];
    for ( size_t i=1 ; i<getRoutingPads().size() ; ++i ) {
      doRp_StairCaseH( getGCell(), getRoutingPads()[i-1], getRoutingPads()[i] );
      if (getRoutingPads()[i]->getBoundingBox().getWidth() > biggestRp->getBoundingBox().getWidth())
        biggestRp = getRoutingPads()[i];
    }

    const Layer* viaLayer1     = Session::getContactLayer(1);

    if (east() and west() and not south() and not north()) {
      AutoContact* rpContact = doRp_Access( getGCell(), biggestRp, HBothAccess );
      setBothCornerContacts( rpContact );
      cdebug_tabw(145,-1);
      return true;
    }

    if (west() and not south()) {
      setSouthWestContact( doRp_Access( getGCell(), getRoutingPads()[0], HAccess ) );
    } else if (not west() and south()) {
      setSouthWestContact( doRp_Access( getGCell(), biggestRp, NoFlags ) );
    } else if (west() and south()) {
      AutoContact* rpContact = doRp_Access( getGCell(), biggestRp, NoFlags );
      setSouthWestContact( AutoContactVTee::create( getGCell(), getNet(), viaLayer1 ) );
      AutoSegment::create( rpContact, getSouthWestContact(), Flags::Vertical );
    }

    if (east() and not north()) {
      setNorthEastContact( doRp_Access( getGCell(), getRoutingPads()[getRoutingPads().size()-1], HAccess ) );
    } else if (not east() and north()) {
      setNorthEastContact( doRp_Access( getGCell(), biggestRp, NoFlags ) );
    } else if (east() and north()) {
      AutoContact* rpContact = doRp_Access( getGCell(), biggestRp, NoFlags );
      setNorthEastContact( AutoContactVTee::create( getGCell(), getNet(), viaLayer1 ) );
      AutoSegment::create( rpContact, getNorthEastContact(), Flags::Vertical );
    }

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_1G_1M3 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_1G_1M3() [Optimised Configuration]" << endl;

    uint64_t flags = (east() or west()) ? HAccess : NoFlags;
    flags |= (north()) ? DoTargetContact : NoFlags;
    flags |= (south()) ? DoSourceContact : NoFlags;

    doRp_AutoContacts( getGCell()
                     , getRoutingPads()[0]
                     , getSouthWestContact()
                     , getNorthEastContact()
                     , flags
                     );
    if (not getSouthWestContact()) setSouthWestContact( getNorthEastContact() );
    if (not getNorthEastContact()) setNorthEastContact( getSouthWestContact() );

    cdebug_log(145,0) << "_southWest: " << getSouthWestContact() << endl;
    cdebug_log(145,0) << "_northEast: " << getNorthEastContact() << endl;

    const Layer* viaLayer1 = Session::getContactLayer(1);

    Box                cellAb    = getAnabatic()->getCell()->getAbutmentBox();
    RoutingLayerGauge* lgM3      = Session::getLayerGauge( 2 );
    DbU::Unit          trackAxis = lgM3->getTrackPosition( cellAb.getXMin()
                                                         , cellAb.getXMax()
                                                         , getRoutingPads()[0]->getX()
                                                         , Constant::Nearest );
    bool offGrid = (trackAxis != getRoutingPads()[0]->getX());
    if (offGrid) {
      cdebug_log(145,0) << "Off grid, Misaligned M3, add horizontal strap" << endl;
      AutoContactTurn* turn1 = AutoContactTurn::create( getGCell(), getNet(), viaLayer1 );
      AutoSegment::create( getSouthWestContact(), turn1, Flags::Horizontal );
      setBothCornerContacts( turn1 );
    }

    if (flags & HAccess) {
    // HARDCODED VALUE.
      if (getRoutingPads()[0]->getBoundingBox().getHeight() < 3*Session::getPitch(1)) {
        AutoContact* subContact = AutoContactTurn::create( getGCell(), getNet(), viaLayer1 );
        AutoSegment::create( getSouthWestContact(), subContact, Flags::Vertical );

        setBothCornerContacts( subContact );
      }
    } else {
      if (getSourceContact() and (getSourceContact()->getX() != getSouthWestContact()->getX())) {
        cdebug_log(145,0) << "On grid, Misaligned M3, add dogleg" << endl;
        AutoContactTurn* turn1 = AutoContactTurn::create( getGCell(), getNet(), viaLayer1 );
        AutoContactTurn* turn2 = AutoContactTurn::create( getGCell(), getNet(), viaLayer1 );
        AutoSegment*     v1    = AutoSegment::create( getSouthWestContact(), turn1, Flags::Vertical   );
        AutoSegment::create( turn1, turn2, Flags::Horizontal );
        v1->setAxis( getSouthWestContact()->getX(), Flags::Force );
        v1->setFlags( AutoSegment::SegFixed|AutoSegment::SegFixedAxis );
        setBothCornerContacts( turn2 );
      }
    }
    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_xG_xM3 ()
  {
    cdebug_log(145,1) << getTypeName()
                      << "::_do_xG_" << (int)getConnexity().fields.M3
                      << "M3() [Managed Configuration]" << endl;
    cdebug_log(145,0) << "west:"  << west()  << endl;
    cdebug_log(145,0) << "east:"  << east()  << endl;
    cdebug_log(145,0) << "south:" << south() << endl;
    cdebug_log(145,0) << "north:" << north() << endl;

    sortRpByY( getRoutingPads(), NoFlags ); // increasing Y.
    for ( size_t i=1 ; i<getRoutingPads().size() ; i++ ) {
      doRp_StairCaseV( getGCell(), getRoutingPads()[i-1], getRoutingPads()[i] );
    }

    const Layer* viaLayer1     = Session::getContactLayer(1);
    AutoContact* unusedContact = NULL;
    Component*   rp            = getRoutingPads()[0];

    if (west() and not south()) {
      setSouthWestContact( doRp_Access( getGCell(), rp, HAccess ) );
    } else if (not west() and south()) {
      doRp_AutoContacts( getGCell(), rp, getSouthWestContact(), unusedContact, DoSourceContact );
      if (getSourceContact()) {
        if (getSourceContact()->getX() != getSouthWestContact()->getX()) {
          cdebug_log(149,0) << "Misaligned South: _source:" << DbU::getValueString(getSourceContact()->getX())
                            << "_southWest:"                << DbU::getValueString(getSouthWestContact()->getX()) << endl;

          AutoContactTurn* turn1 = AutoContactTurn::create( getGCell(), getNet(), viaLayer1 );
          AutoContactTurn* turn2 = AutoContactTurn::create( getGCell(), getNet(), viaLayer1 );
          AutoSegment::create( getSouthWestContact(), turn1, Flags::Vertical );
          AutoSegment::create( turn1            , turn2, Flags::Horizontal );
          setSouthWestContact( turn2 );
        }
      }
    } else if (west() and south()) {
      AutoContact* rpContact = NULL;
      doRp_AutoContacts( getGCell(), rp, rpContact, unusedContact, DoSourceContact );
      setSouthWestContact( AutoContactVTee::create( getGCell(), getNet(), viaLayer1 ) );
      AutoSegment::create( rpContact, getSouthWestContact(), Flags::Vertical );
    }

    rp = getRoutingPads()[getRoutingPads().size()-1];
    if (east() and not north()) {
      setNorthEastContact( doRp_Access( getGCell(), rp, HAccess ) );
    } else if (not east() and north()) {
      doRp_AutoContacts( getGCell(), rp, unusedContact, getNorthEastContact(), DoTargetContact );
      if (getSourceContact()) {
        if (getSourceContact()->getX() != getNorthEastContact()->getX()) {
          cdebug_log(149,0) << "Misaligned North: _source:" << DbU::getValueString(getSourceContact()->getX())
                            << "_southWest:"                << DbU::getValueString(getNorthEastContact()->getX()) << endl;

          AutoContactTurn* turn1 = AutoContactTurn::create( getGCell(), getNet(), viaLayer1 );
          AutoContactTurn* turn2 = AutoContactTurn::create( getGCell(), getNet(), viaLayer1 );
          AutoSegment::create( getNorthEastContact(), turn1, Flags::Vertical   );
          AutoSegment::create( turn1            , turn2, Flags::Horizontal );
          setNorthEastContact( turn2 );
        }
      }
    } else if (east() and north()) {
      AutoContact* rpContact = NULL;
      doRp_AutoContacts( getGCell(), rp, unusedContact, rpContact, DoTargetContact );
      setNorthEastContact( AutoContactVTee::create( getGCell(), getNet(), viaLayer1 ) );
      AutoSegment::create( rpContact, getNorthEastContact(), Flags::Vertical );
    }

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderHV::_do_globalSegment ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_globalSegment()" << endl;

    if (getSourceContact()) {
      AutoContact* targetContact
        = ( getSegmentHookType(getFromHook()) & (NorthBound|EastBound) )
        ? getNorthEastContact() : getSouthWestContact() ;
      if (not getFromHook()) cerr << "getFromHook() is NULL !" << endl;

      Segment*     baseSegment   = static_cast<Segment*>( getFromHook()->getComponent() );
      AutoSegment* globalSegment = AutoSegment::create( getSourceContact()
                                                      , targetContact
                                                      , baseSegment
                                                      );
      globalSegment->setFlags( (getDegree() == 2) ? AutoSegment::SegBipoint : 0 );
      if (getNetData() and getNetData()->isNoMoveUp(baseSegment)) {
        globalSegment->setFlags( AutoSegment::SegNoMoveUp );
      }
      cdebug_log(145,0) << "Create global segment: " << globalSegment << endl;
  
    // HARDCODED VALUE.
      if ( (getTopology() & Global_Fixed) and (globalSegment->getAnchoredLength() < 2*Session::getSliceHeight()) )
        addToFixSegments( globalSegment );
        
      if (getConnexity().fields.globals < 2) {
        cdebug_tabw(145,-1);
        return false;
      }
    } else
      setFromHook( NULL );
    
    push( east (), getNorthEastContact() );
    push( west (), getSouthWestContact() );
    push( north(), getNorthEastContact() );
    push( south(), getSouthWestContact() );

    cdebug_tabw(145,-1);
    return true;
  }


  void  NetBuilderHV::singleGCell ( AnabaticEngine* anbt, Net* net )
  {
    cdebug_log(145,1) << "NetBuilderHV::singleGCell() " << net << endl;

    vector<RoutingPad*>  rpM1s;
    Component*           rpM2  = NULL;
    RoutingPad*          rpPin = NULL;

    for ( RoutingPad* rp : net->getRoutingPads() ) {
      if (dynamic_cast<Pin*>(rp->getOccurrence().getEntity())) {
        rpPin = rp;
        continue;
      }
      
      if (Session::getRoutingGauge()->getLayerDepth(rp->getLayer()) == 1)
        rpM2 = rp;
      else
        rpM1s.push_back( rp );
    }

    if ( (rpM1s.size() < 2) and not (rpM2 or rpPin) ) {
      cerr << Error( "For %s, less than two Plugs/Pins (%d)."
                   , getString(net).c_str()
                   , rpM1s.size() ) << endl;
      cdebug_tabw(145,-1);
      return;
    }

    if (rpM1s.empty()) {
      cerr << Error( "No METAL1 in Single GCell for Net \"%s\".", getString(net->getName()).c_str() ) << endl;
      cdebug_tabw(145,-1);
      return;
    }

    sortRpByX( rpM1s, NetBuilder::NoFlags ); // increasing X.

    GCell* gcell1 = anbt->getGCellUnder( (*rpM1s.begin ())->getCenter() );
    GCell* gcell2 = anbt->getGCellUnder( (*rpM1s.rbegin())->getCenter() );

    if (not gcell1) {
      cerr << Error( "No GCell under %s.", getString(*(rpM1s.begin())).c_str() ) << endl;
      cdebug_tabw(145,-1);
      return;
    }
    if (gcell1 != gcell2) {
      cerr << Error( "Not under a single GCell %s.", getString(*(rpM1s.rbegin())).c_str() ) << endl;
      cdebug_tabw(145,-1);
      return;
    }

    cdebug_log(145,0) << "singleGCell " << gcell1 << endl;

    AutoContact* turn1  = NULL;
    AutoContact* turn2  = NULL;
    AutoContact* source = NULL;
    AutoContact* target = NULL;

    for ( size_t irp=1 ; irp<rpM1s.size() ; ++irp ) {
      doRp_AutoContacts( gcell1, rpM1s[irp-1], source, turn1, DoSourceContact );
      doRp_AutoContacts( gcell1, rpM1s[irp  ], target, turn1, DoSourceContact );

      if (source->getUConstraints(Flags::Vertical).intersect(target->getUConstraints(Flags::Vertical))) {
        uint64_t flags = checkRoutingPadSize( rpM1s[irp-1] );
        if ((flags & VSmall) or Session::getConfiguration()->isVH()) {
          if (Session::getConfiguration()->isHV()) {
            turn1  = AutoContactTurn::create( gcell1, rpM1s[irp]->getNet(), Session::getDContactLayer() );
            AutoSegment::create( source, turn1, Flags::Horizontal   );
            source = turn1;
          }
          turn1  = AutoContactTurn::create( gcell1, rpM1s[irp]->getNet(), Session::getDContactLayer() );
          AutoSegment::create( source, turn1 , Flags::Vertical   );
          source = turn1;
        }
        flags = checkRoutingPadSize( rpM1s[irp] );
        if ((flags & VSmall) or Session::getConfiguration()->isVH()) {
          if (Session::getConfiguration()->isHV()) {
            turn1  = AutoContactTurn::create( gcell1, rpM1s[irp]->getNet(), Session::getDContactLayer() );
            AutoSegment::create( target, turn1, Flags::Horizontal   );
            target = turn1;
          }
          turn1  = AutoContactTurn::create( gcell1, rpM1s[irp]->getNet(), Session::getDContactLayer() );
          AutoSegment::create( target, turn1 , Flags::Vertical   );
          target = turn1;
        }
        AutoSegment::create( source, target, Flags::Horizontal );
      } else {
        turn1 = AutoContactTurn::create( gcell1, rpM1s[irp]->getNet(), Session::getDContactLayer() );
        turn2 = AutoContactTurn::create( gcell1, rpM1s[irp]->getNet(), Session::getDContactLayer() );
        AutoSegment::create( source, turn1 , Flags::Horizontal );
        AutoSegment::create( turn1 , turn2 , Flags::Vertical   );
        AutoSegment::create( turn2 , target, Flags::Horizontal );
      }
    }

    if (rpM2) {
      doRp_AutoContacts( gcell1, rpM1s[0], source, turn1, DoSourceContact );
      doRp_AutoContacts( gcell1, rpM2    , target, turn1, DoSourceContact );
      turn1 = AutoContactTurn::create( gcell1, rpM2->getNet(), Session::getContactLayer(1) );
      AutoSegment::create( source, turn1 , Flags::Horizontal );
      AutoSegment::create( turn1 , target, Flags::Vertical );
    }

    if (rpPin) {
      Pin*                 pin    = dynamic_cast<Pin*>( rpPin->getOccurrence().getEntity() );
      Pin::AccessDirection pinDir = pin->getAccessDirection();

      if (  (pinDir == Pin::AccessDirection::NORTH)
         or (pinDir == Pin::AccessDirection::SOUTH) ) {
        doRp_AutoContacts( gcell1, rpM1s[0], source, turn1, DoSourceContact );
        target = doRp_AccessNorthPin( gcell1, rpPin );
        turn1  = AutoContactTurn::create( gcell1, rpPin->getNet(), Session::getContactLayer(1) );
        AutoSegment::create( source, turn1 , Flags::Horizontal );
        AutoSegment::create( turn1 , target, Flags::Vertical );
      } else {
        RoutingPad* closest = NULL;
        
        if (pinDir == Pin::AccessDirection::EAST) closest = rpM1s.back();
        else                                      closest = rpM1s.front();

        doRp_AutoContacts( gcell1, closest, source, turn1, DoSourceContact );
        target = doRp_AccessEastWestPin( gcell1, rpPin );
        AutoSegment::create( source, target , Flags::Horizontal );
      }
    }

    cdebug_tabw(145,-1);
  }


  string  NetBuilderHV::getTypeName () const
  { return "NetBuilderHV"; }


}  // Anabatic namespace.
