Compare commits

..

7 Commits

Author SHA1 Message Date
Staf Verhaegen f32188fe2d [gf180mcu]Update pin names
For gf180mcu there are only two rings named vdd and vss.
2022-12-05 17:13:40 +01:00
Staf Verhaegen 6eab01950c [gf180mcu]Reduce inner size when removing drawn polygons.
For gf180mcu the rings are drawn inside the inner area at top
and right of the cell.
2022-12-05 17:13:09 +01:00
Staf Verhaegen 7b04a76fae Add core2chip file for gf180mcu
This is a copy of the sky130 one.
2022-12-01 16:28:01 +01:00
Staf Verhaegen 1262f65eec Hack left/right pin drawing
This is assumed to only fix symptoms, not the real problem.
2022-12-01 16:27:34 +01:00
Staf Verhaegen 8ebd0954e5 Fix left/right pin connection.
Made code look like North/South pins.
I am not sure these are needed anyway.
2022-11-29 12:02:16 +01:00
Staf Verhaegen 047eb4cc78 Also mark gf180mcu process as Sky130 2022-11-29 12:02:16 +01:00
Staf Verhaegen 0ee4542d57 Allow StdCellLib* names for standard cells. 2022-11-29 12:02:16 +01:00
3770 changed files with 63725 additions and 375889 deletions

View File

@ -1,54 +0,0 @@
linux:
image: python:3.8
# make a docker daemon available for cibuildwheel to use
services:
- name: docker:dind
entrypoint: ["env", "-u", "DOCKER_HOST"]
command: ["dockerd-entrypoint.sh"]
variables:
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2
# See https://github.com/docker-library/docker/pull/166
DOCKER_TLS_CERTDIR: ""
script:
- curl -sSL https://get.docker.com/ | sh
- python -m pip install cibuildwheel==2.11.3
- cibuildwheel --output-dir wheelhouse
parallel:
matrix:
- CIBW_BUILD: [cp38-manylinux*, cp39-manylinux*, cp310-manylinux*, cp311-manylinux*]
CIBW_ARCHS_LINUX: [auto64]
artifacts:
paths:
- wheelhouse/
dist:
image: python:3.8
needs:
- job: linux
artifacts: true
except:
- merge_requests
variables:
TWINE_PASSWORD: '${CI_JOB_TOKEN}'
TWINE_USERNAME: 'gitlab-ci-token'
TWINE_REPOSITORY_URL: 'https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/packages/pypi'
script:
- python -m pip install --upgrade build twine
- python -m twine check --strict wheelhouse/*
- python -m twine upload --verbose wheelhouse/*
#windows:
# image: mcr.microsoft.com/windows/servercore:1809
# before_script:
# - choco install python -y --version 3.8.6
# - choco install git.install -y
# - py -m pip install cibuildwheel==2.11.3
# script:
# - py -m cibuildwheel --output-dir wheelhouse --platform windows
# artifacts:
# paths:
# - wheelhouse/
# tags:
# - windows

6
.gitmodules vendored
View File

@ -1,6 +0,0 @@
[submodule "coloquinte"]
path = coloquinte
# url = git@github.com:Coloquinte/PlaceRoute.git
url = https://github.com/Coloquinte/PlaceRoute.git
branch = coriolis-submodule
update = merge

View File

@ -1,35 +0,0 @@
#This is needed for poetry to recognise the top level module
import os
import sys
import subprocess
__version__ = "0.0.0"
#TODO not PEP302 complient -probably a big porting job
coriolis_package_dir = os.path.abspath(os.path.dirname(__file__))
os.environ["CORIOLIS_TOP"] = coriolis_package_dir
CORIOLIS_DATA = os.path.join(os.path.dirname(__file__), 'data')
CORIOLIS_BIN = os.path.join(CORIOLIS_DATA,"bin")
def _program(name, args):
return subprocess.call([os.path.join(CORIOLIS_BIN, name)] + args, close_fds=False)
def blif2vst():
raise SystemExit(_program("blif2vst.py", sys.argv[1:]))
def cx2y():
raise SystemExit(_program("cx2y", sys.argv[1:]))
def cyclop():
raise SystemExit(_program("cyclop", sys.argv[1:]))
def tutorial():
raise SystemExit(_program("tutorial", sys.argv[1:]))
def unittests():
raise SystemExit(_program("unittests", sys.argv[1:]))
def yosys_coriolis():
raise SystemExit(_program("yosys.py", sys.argv[1:]))

View File

@ -40,20 +40,23 @@ Building Coriolis
To build Coriolis, ensure the following prerequisites are met:
* Python 3,
* cmake,
* boost,
* bison & flex,
* Qt 4 or 5,
* libxml2,
* RapidJSON,
* Python 3.
* cmake.
* boost.
* bison & flex.
* Qt 4 or 5.
* libxml2.
* RapidJSON
* A C++11 compliant compiler.
The build system relies on a fixed directory tree from the root
of the user currently building it. Thus first step is to get a clone of
the repository in the right place. Proceed as follow: ::
ego@home:~$ mkdir -p ~/coriolis-2.x/src/
ego@home:~$ mkdir -p ~/coriolis-2.x/src/support
ego@home:~$ cd ~/coriolis-2.x/src/support
ego@home:~$ git clone http://github.com/miloyip/rapidjson
ego@home:~$ git checkout ec322005072076ef53984462fb4a1075c27c7dfd
ego@home:~$ cd ~/coriolis-2.x/src
ego@home:src$ git clone https://gitlab.lip6.fr/vlsi-eda/coriolis.git
ego@home:src$ cd coriolis
@ -82,7 +85,7 @@ The ``coriolis`` script detects its location and setups the UNIX
environment appropriately, then lauches ``cgt`` (or *any* command, with the
``--run=<COMMAND>`` option).
Conversely, you can setup the current shell environment for Coriolis by
Conversely, you can setup the current shell environement for Coriolis by
using the helper ``coriolisEnv.py``, then run any Coriolis tool: ::
ego@home:~$ eval `~/coriolis-2.x/src/coriolis/bootstrap/coriolisEnv.py`

View File

@ -7,7 +7,7 @@
option(CHECK_DATABASE "Run database in full check mode (very slow)" OFF)
option(USE_LIBBFD "Link with BFD libraries to print stack traces" OFF)
cmake_minimum_required(VERSION 3.16)
cmake_minimum_required(VERSION 2.8.9)
set(ignoreVariables "${BUILD_DOC} ${CMAKE_INSTALL_DIR}")
@ -18,9 +18,9 @@
set_cmake_policies()
setup_boost(program_options)
setup_qt()
setup_python()
find_package(Libexecinfo REQUIRED)
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development)
find_package(PythonSitePackages REQUIRED)
find_package(LEFDEF REQUIRED)
find_package(FLUTE REQUIRED)

View File

@ -50,13 +50,13 @@
${QtX_LIBRARIES}
${Boost_LIBRARIES}
${LIBXML2_LIBRARIES}
-lutil
${Python_LIBRARIES} -lutil
${LIBEXECINFO_LIBRARIES}
)
add_library( Seabreeze ${cpps} ${mocCpps} ${pyCpps} )
set_target_properties( Seabreeze PROPERTIES VERSION 1.0 SOVERSION 1 )
target_link_libraries( Seabreeze ${depLibs} )
#target_link_libraries( Seabreeze ${depLibs} )
add_python_module( "${pyCpps}"
"${pyIncludes}"

View File

@ -9,7 +9,7 @@
option(CHECK_DATABASE "Run database in full check mode (very slow)" OFF)
option(USE_LIBBFD "Link with BFD libraries to print stack traces" OFF)
cmake_minimum_required(VERSION 3.16)
cmake_minimum_required(VERSION 2.8.9)
list(INSERT CMAKE_MODULE_PATH 0 "${DESTDIR}$ENV{CORIOLIS_TOP}/share/cmake/Modules/")
find_package(Bootstrap REQUIRED)
@ -18,8 +18,8 @@
set_cmake_policies()
setup_boost()
setup_qt()
setup_python()
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development)
find_package(PythonSitePackages REQUIRED)
find_package(FLUTE REQUIRED)
find_package(HURRICANE REQUIRED)

View File

@ -34,7 +34,6 @@
#include "crlcore/Histogram.h"
#include "anabatic/GCell.h"
#include "anabatic/AutoContactTerminal.h"
#include "anabatic/NetBuilderHybridVH.h"
#include "anabatic/NetBuilderM2.h"
#include "anabatic/NetBuilderHV.h"
#include "anabatic/NetBuilderVH.h"
@ -244,6 +243,7 @@ namespace Anabatic {
cerr << Error( "RawGCellsUnder::commonCtor(): Points are neither horizontally nor vertically aligneds (ignored)."
) << endl;
cdebug_tabw(112,-1);
DebugSession::close();
return;
}
@ -261,6 +261,7 @@ namespace Anabatic {
, DbU::getValueString(target.getY()).c_str()
) << endl;
cdebug_tabw(112,-1);
DebugSession::close();
return;
}
@ -279,18 +280,21 @@ namespace Anabatic {
cerr << Bug( "RawGCellsUnder::RawGCellsUnder(): Source not under a GCell (ignored)."
) << endl;
cdebug_tabw(112,-1);
DebugSession::close();
return;
}
if (not gtarget) {
cerr << Bug( "RawGCellsUnder::RawGCellsUnder(): Target not under a GCell (ignored)."
) << endl;
cdebug_tabw(112,-1);
DebugSession::close();
return;
}
if (gsource == gtarget) {
_elements.push_back( Element(gsource,NULL) );
cdebug_tabw(112,-1);
DebugSession::close();
return;
}
@ -379,27 +383,25 @@ namespace Anabatic {
, _edgeCapacitiesLut()
, _blockageNet (cell->getNet("blockagenet"))
, _diodeCell (NULL)
{ }
{
_matrix.setCell( cell, _configuration->getSliceHeight() );
Edge::unity = _configuration->getSliceHeight();
if (not _blockageNet) {
_blockageNet = Net::create( cell, "blockagenet" );
_blockageNet->setType( Net::Type::BLOCKAGE );
}
}
void AnabaticEngine::_postCreate ()
{
Super::_postCreate();
_configuration = _createConfiguration();
setupNetBuilder();
_matrix.setCell( getCell(), _configuration->getSliceHeight() );
Edge::unity = _configuration->getSliceHeight();
if (not _blockageNet) {
_blockageNet = Net::create( getCell(), "blockagenet" );
_blockageNet->setType( Net::Type::BLOCKAGE );
}
_diodeCell = DataBase::getDB()->getCell( _configuration->getDiodeName() );;
_diodeCell = DataBase::getDB()->getCell( getConfiguration()->getDiodeName() );;
if (not _diodeCell) {
cerr << Warning( "AnabaticEngine::_postCreate() Unable to find \"%s\" diode cell."
, _configuration->getDiodeName().c_str()
, getConfiguration()->getDiodeName().c_str()
) << endl;
}
@ -410,10 +412,6 @@ namespace Anabatic {
}
Configuration* AnabaticEngine::_createConfiguration ()
{ return new Configuration(); }
AnabaticEngine* AnabaticEngine::create ( Cell* cell )
{
if (not cell) throw Error( "AnabaticEngine::create(): NULL cell argument." );
@ -625,7 +623,7 @@ namespace Anabatic {
}
}
RoutingGauge* rg = _configuration->getRoutingGauge();
RoutingGauge* rg = getConfiguration()->getRoutingGauge();
size_t errorCount = 0;
ostringstream errors;
errors << "AnabaticEngine::checkPlacement():\n";
@ -854,7 +852,7 @@ namespace Anabatic {
if (horizontal) {
splitted = Horizontal::create( breakContact
, targetContact
, _configuration->getGHorizontalLayer()
, getConfiguration()->getGHorizontalLayer()
, horizontal->getY()
, DbU::fromLambda(2.0)
);
@ -863,7 +861,7 @@ namespace Anabatic {
if (vertical) {
splitted = Vertical::create( breakContact
, targetContact
, _configuration->getGVerticalLayer()
, getConfiguration()->getGVerticalLayer()
, vertical->getX()
, DbU::fromLambda(2.0)
);
@ -1099,7 +1097,7 @@ namespace Anabatic {
for ( Net* net : getCell()->getNets() ) {
for ( Component* component : net->getComponents() ) {
if (_configuration->isGLayer(component->getLayer())) {
if (getConfiguration()->isGLayer(component->getLayer())) {
cerr << Error( "AnabaticEngine::cleanupGlobal(): Remaining global routing,\n"
" %s"
, getString(component).c_str()
@ -1126,7 +1124,7 @@ namespace Anabatic {
}
cleanupGlobal();
if (not _configuration->isTwoMetals()) relaxOverConstraineds();
if (not getConfiguration()->isTwoMetals()) relaxOverConstraineds();
_state = EngineActive;
}
@ -1243,64 +1241,6 @@ namespace Anabatic {
}
void AnabaticEngine::setupNetBuilder ()
{
uint32_t gaugeKind = 4;
if (NetBuilderHybridVH::getStyle() == getNetBuilderStyle()) gaugeKind = 0;
else if (NetBuilderM2 ::getStyle() == getNetBuilderStyle()) gaugeKind = 1;
else if (NetBuilderVH ::getStyle() == getNetBuilderStyle()) gaugeKind = 2;
else if (NetBuilderHV ::getStyle() == getNetBuilderStyle()) gaugeKind = 3;
if (gaugeKind == 0) {
if (not _configuration->isVH())
throw Error( "AnabaticEngine::_loadGrByNet(): Incoherency between routing gauge \"%s\" and NetBuilder style \"%s\"."
, getString(_configuration->getRoutingGauge()->getName()).c_str()
, getNetBuilderStyle().c_str() );
if (getRoutingStyle() == StyleFlags::NoStyle) {
_configuration->setRoutingStyle( StyleFlags::VH
| StyleFlags::Channel
| StyleFlags::Hybrid );
}
}
else if (gaugeKind == 1) {
if (getRoutingStyle() == StyleFlags::NoStyle) {
_configuration->setRoutingStyle( StyleFlags::Channel );
}
}
else if (gaugeKind == 2) {
if (not _configuration->isVH())
throw Error( "AnabaticEngine::_loadGrByNet(): Incoherency between routing gauge \"%s\" and NetBuilder style \"%s\"."
, getString(_configuration->getRoutingGauge()->getName()).c_str()
, getNetBuilderStyle().c_str() );
if (_configuration->getRoutingGauge()->getUsableLayers() < 3)
throw Error( "AnabaticEngine::_loadGrByNet(): Incoherency between routing gauge \"%s\" and NetBuilder style \"%s\"."
, getString(_configuration->getRoutingGauge()->getName()).c_str()
, getNetBuilderStyle().c_str() );
if (getRoutingStyle() == StyleFlags::NoStyle) {
_configuration->setRoutingStyle( StyleFlags::VH
| StyleFlags::OTH );
}
}
else if (gaugeKind == 3) {
if (not _configuration->isHV())
throw Error( "AnabaticEngine::_loadGrByNet(): Incoherency between routing gauge \"%s\" and NetBuilder style \"%s\"."
, getString(_configuration->getRoutingGauge()->getName()).c_str()
, getNetBuilderStyle().c_str() );
if (_configuration->getRoutingGauge()->getUsableLayers() < 3)
throw Error( "AnabaticEngine::_loadGrByNet(): Incoherency between routing gauge \"%s\" and NetBuilder style \"%s\"."
, getString(_configuration->getRoutingGauge()->getName()).c_str()
, getNetBuilderStyle().c_str() );
if (getRoutingStyle() == StyleFlags::NoStyle) {
_configuration->setRoutingStyle( StyleFlags::HV
| StyleFlags::OTH );
}
}
if (gaugeKind == 4) {
throw Error( "AnabaticEngine::_loadGrByNet(): Unsupported kind of routing auge style \"%s\"."
, getNetBuilderStyle().c_str() );
}
}
void AnabaticEngine::_loadGrByNet ()
{
cmess1 << " o Building detailed routing from global. " << endl;
@ -1310,13 +1250,12 @@ namespace Anabatic {
startMeasures();
openSession();
uint32_t gaugeKind = 4;
if (NetBuilderHybridVH::getStyle() == getNetBuilderStyle()) gaugeKind = 0;
else if (NetBuilderM2 ::getStyle() == getNetBuilderStyle()) gaugeKind = 1;
else if (NetBuilderVH ::getStyle() == getNetBuilderStyle()) gaugeKind = 2;
else if (NetBuilderHV ::getStyle() == getNetBuilderStyle()) gaugeKind = 3;
int gaugeKind = 3;
if (getConfiguration()->isTwoMetals()) gaugeKind = 0;
if (getConfiguration()->isHV ()) gaugeKind = 1;
if (getConfiguration()->isVH ()) gaugeKind = 2;
if (gaugeKind < 4) {
if (gaugeKind < 3) {
for ( Net* net : getCell()->getNets() ) {
if (NetRoutingExtension::isShortNet(net)) {
//AutoSegment::setShortNetMode( true );
@ -1330,10 +1269,9 @@ namespace Anabatic {
AutoSegment::setAnalogMode( NetRoutingExtension::isAnalog(net) );
switch ( gaugeKind ) {
case 0: NetBuilder::load<NetBuilderHybridVH>( this, net ); break;
case 1: NetBuilder::load<NetBuilderM2> ( this, net ); break;
case 2: NetBuilder::load<NetBuilderVH> ( this, net ); break;
case 3: NetBuilder::load<NetBuilderHV> ( this, net ); break;
case 0: NetBuilder::load<NetBuilderM2>( this, net ); break;
case 1: NetBuilder::load<NetBuilderHV>( this, net ); break;
case 2: NetBuilder::load<NetBuilderVH>( this, net ); break;
}
Session::revalidate();
@ -1353,6 +1291,11 @@ namespace Anabatic {
cmess2 << Dots::asSizet(" - Short nets",shortNets) << endl;
if (gaugeKind > 2) {
throw Error( "AnabaticEngine::_loadGrByNet(): Unsupported kind of routing gauge \"%s\"."
, getString(getConfiguration()->getRoutingGauge()->getName()).c_str() );
}
printMeasures( "load" );
addMeasure<size_t>( "Globals", AutoSegment::getGlobalsCount() );
@ -1683,7 +1626,7 @@ namespace Anabatic {
EdgeCapacity* AnabaticEngine::_createCapacity ( Flags flags, Interval span )
{
size_t depth = _configuration->getAllowedDepth();
size_t depth = getConfiguration()->getAllowedDepth();
EdgeCapacity* edgeCapacity = NULL;
flags &= Flags::EdgeCapacityMask;
@ -1725,7 +1668,7 @@ namespace Anabatic {
UpdateSession::open();
for ( auto rp : rps ) {
if (not _configuration->selectRpComponent(rp))
if (not getConfiguration()->selectRpComponent(rp))
cerr << Warning( "AnabaticEngine::computeEdgeCapacities(): %s has no components on grid.", getString(rp).c_str() ) << endl;
Point center = rp->getBoundingBox().getCenter();

View File

@ -406,8 +406,8 @@ namespace Anabatic {
if (horizontals[1] != NULL) ++count;
if (verticals [0] != NULL) ++count;
if (verticals [1] != NULL) ++count;
if (count != 1) {
showTopologyError( "Terminal has not *exactly* one segment." );
if (count > 1) {
showTopologyError( "Terminal has more than one segment." );
}
if (horizontals[0] != NULL ) {
_segment = Session::lookup( horizontals[0] );

View File

@ -875,7 +875,7 @@ namespace Anabatic {
bool upLayer = true;
if (Session::getRoutingGauge()->isTwoMetals()) {
upLayer = (not Session::getRoutingGauge()->isVH());
upLayer = (depth == 0);
} else if (Session::getRoutingGauge()->isVH()) {
upLayer = (depth < 2);
} else {

View File

@ -1808,7 +1808,7 @@ namespace Anabatic {
return false;
}
if (not Session::getAnabatic()->isChannelStyle()
if (not Session::getAnabatic()->isChannelMode()
and (getDepth() == 1) and isSpinBottom()) return false;
if ((flags & Flags::WithPerpands) and _reduceds) return false;
@ -3069,7 +3069,6 @@ namespace Anabatic {
if (wPitch > 1) segment->setFlags( SegWide );
if (source->canDrag() or target->canDrag()) segment->setFlags( SegDrag );
if (dir & Flags::UseNonPref) segment->setFlags( SegNonPref );
if (dir.contains(Flags::UseNonPref|Flags::OnVSmall)) segment->setFlags( SegOnVSmall );
return segment;
}
@ -3285,7 +3284,7 @@ namespace Anabatic {
Flags perpandFlags = (currentSegment->getAutoSource() == sourceContact)
? Flags::Source : Flags::Target;
perpandiculars.push_back( make_tuple( currentSegment, perpandFlags ));
if (Session::getAnabatic()->isChannelStyle()) {
if (Session::getAnabatic()->isChannelMode()) {
if (currentSegment->isNonPref() and currentSegment->isFixed()) {
if (perpandFlags & Flags::Source) isSourceBoundToChannel = true;
else isTargetBoundToChannel = true;

View File

@ -736,7 +736,7 @@ namespace Anabatic {
bool upLayer = true;
if (Session::getRoutingGauge()->isTwoMetals()) {
upLayer = (Session::getRoutingGauge()->isVH());
upLayer = (depth == 0);
} else if (Session::getRoutingGauge()->isVH()) {
upLayer = (depth < 2);
} else {

View File

@ -36,10 +36,9 @@ endif ( CHECK_DETERMINISM )
anabatic/NetBuilderM2.h
anabatic/NetBuilderHV.h
anabatic/NetBuilderVH.h
anabatic/NetBuilderHybridVH.h
anabatic/ChipTools.h
)
set( pyIncludes anabatic/PyStyleFlags.h )
set( pyIncludes )
set( cpps Constants.cpp
Configuration.cpp
Matrix.cpp
@ -63,15 +62,13 @@ endif ( CHECK_DETERMINISM )
NetBuilderM2.cpp
NetBuilderHV.cpp
NetBuilderVH.cpp
NetBuilderHybridVH.cpp
ChipTools.cpp
LayerAssign.cpp
AntennaProtect.cpp
PreRouteds.cpp
AnabaticEngine.cpp
)
set( pyCpps PyStyleFlags.cpp
PyAnabatic.cpp
set( pyCpps PyAnabatic.cpp
)
set( depLibs ${ETESIAN_LIBRARIES}
@ -90,13 +87,12 @@ endif ( CHECK_DETERMINISM )
${QtX_LIBRARIES}
${Boost_LIBRARIES}
${LIBXML2_LIBRARIES}
${Python3_LIBRARIES}
-lutil
${Python_LIBRARIES} -lutil
)
add_library( anabatic ${cpps} )
set_target_properties( anabatic PROPERTIES VERSION 1.0 SOVERSION 1 )
target_link_libraries( anabatic ${depLibs} )
#target_link_libraries( anabatic ${depLibs} )
add_python_module( "${pyCpps}"
"${pyIncludes}"

View File

@ -1,7 +1,7 @@
// -*- mode: C++; explicit-buffer-name: "Configuration.cpp<anabatic>" -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) Sorbonne Université 2016-2022, All Rights Reserved
// Copyright (c) UPMC 2016-2018, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
@ -78,8 +78,6 @@ namespace Anabatic {
, _ddepthv (ndepth)
, _ddepthh (ndepth)
, _ddepthc (ndepth)
, _netBuilderStyle (Cfg::getParamString("anabatic.netBuilderStyle","HV,3RL+")->asString() )
, _routingStyle (Cfg::getParamInt ("anabatic.routingStyle" ,StyleFlags::NoStyle)->asInt() )
, _cg (NULL)
, _rg (NULL)
, _extensionCaps ()
@ -189,8 +187,6 @@ namespace Anabatic {
, _ddepthv (other._ddepthv)
, _ddepthh (other._ddepthh)
, _ddepthc (other._ddepthc)
, _netBuilderStyle (other._netBuilderStyle)
, _routingStyle (other._routingStyle)
, _cg (NULL)
, _rg (NULL)
, _extensionCaps (other._extensionCaps)
@ -229,10 +225,6 @@ namespace Anabatic {
{ return _rg->isTwoMetals(); }
bool Configuration::isHybrid () const
{ return _routingStyle & StyleFlags::Hybrid; }
bool Configuration::isHV () const
{ return _rg->isHV(); }

View File

@ -14,22 +14,16 @@
// +-----------------------------------------------------------------+
#include "hurricane/Error.h"
#include "anabatic/Constants.h"
namespace Anabatic {
using std::hex;
using std::string;
using std::ostringstream;
using Hurricane::BaseFlags;
using Hurricane::Error;
// -------------------------------------------------------------------
// Class : "Anabatic::Flags".
const BaseFlags Flags::NoFlags = 0;
// Flags used for both objects states & functions arguments.
const BaseFlags Flags::Horizontal = (1L << 0);
@ -132,7 +126,6 @@ namespace Anabatic {
const BaseFlags Flags::NoMinLength = (1L << 37);
const BaseFlags Flags::NoSegExt = (1L << 38);
const BaseFlags Flags::NullLength = (1L << 39);
const BaseFlags Flags::OnVSmall = (1L << 40);
Flags::~Flags ()
@ -218,69 +211,4 @@ namespace Anabatic {
}
// -------------------------------------------------------------------
// Class : "Anabatic::StyleFlags".
const BaseFlags StyleFlags::NoStyle = 0;
const BaseFlags StyleFlags::HV = (1L << 0);
const BaseFlags StyleFlags::VH = (1L << 1);
const BaseFlags StyleFlags::OTH = (1L << 2);
const BaseFlags StyleFlags::Channel = (1L << 3);
const BaseFlags StyleFlags::Hybrid = (1L << 4);
StyleFlags::~StyleFlags ()
{ }
StyleFlags StyleFlags::toFlag ( std::string textFlag )
{
if (textFlag == "HV") return HV;
if (textFlag == "VH") return VH;
if (textFlag == "OTH") return OTH;
if (textFlag == "Channel") return Channel;
if (textFlag == "Hybrid") return Hybrid;
if (textFlag == "NoStyle") return NoStyle;
std::cerr << Error( "StyleFlags::toFlag(): Unknown flag value \"%s\"", textFlag.c_str() ) << std::endl;
return NoStyle;
}
StyleFlags StyleFlags::from ( std::string textFlags )
{
size_t start = 0;
size_t stop = textFlags.find( '|' );
while ( stop != string::npos ) {
*this |= toFlag( textFlags.substr( start, stop-start-1 ));
start = stop + 1;
stop = textFlags.find( '|', start );
}
*this |= toFlag( textFlags.substr( stop+1 ));
return *this;
}
string StyleFlags::asString () const
{
ostringstream s;
if (_flags & (uint64_t)HV) { s << (s.tellp() ? "|" : "") << "HV"; }
if (_flags & (uint64_t)VH) { s << (s.tellp() ? "|" : "") << "VH"; }
if (_flags & (uint64_t)OTH) { s << (s.tellp() ? "|" : "") << "OTH"; }
if (_flags & (uint64_t)Channel) { s << (s.tellp() ? "|" : "") << "Channel"; }
if (_flags & (uint64_t)Hybrid ) { s << (s.tellp() ? "|" : "") << "Hybrid"; }
s << " (0x" << hex << _flags << ")";
return s.str();
}
string StyleFlags::_getTypeName () const
{ return "Anabatic::StyleFlags"; }
string StyleFlags::_getString () const
{ return asString(); }
} // Anabatic namespace.

View File

@ -285,7 +285,7 @@ namespace Anabatic {
: Super(anabatic->getCell())
, _observable ()
, _anabatic (anabatic)
, _flags (Flags::Invalidated)
, _flags (Flags::HChannelGCell|Flags::Invalidated)
, _westEdges ()
, _eastEdges ()
, _southEdges ()
@ -1557,8 +1557,7 @@ namespace Anabatic {
int contiguousNonSaturated = 0;
for ( size_t i=0 ; i<_depth ; i++ ) {
uLengths2[i] += _blockages[i];
if (Session::getLayerGauge(i)->getType() & Constant::PinOnly)
continue;
if (not i) continue;
if (Session::getLayerGauge(i)->getType() & Constant::PowerSupply)
continue;
if ((float)(_blockages[i] * Session::getPitch(i)) > 0.60*(float)(width*height))

View File

@ -218,11 +218,10 @@ namespace {
cdebug_log(149,0) << "Slacken from: " << rp << endl;
if (rp->getLayer()) {
if (_anabatic->getConfiguration()->getLayerDepth(rp->getLayer()) == 1) {
if (_anabatic->getConfiguration()->getLayerDepth(rp->getLayer()) == 1)
cdebug_log(149,0) << "In METAL2, skiping" << endl;
continue;
}
}
for ( Component* component : rp->getSlaveComponents() ) {
AutoContact* rpContact = Session::lookup( dynamic_cast<Contact*>(component) );

View File

@ -368,7 +368,7 @@ namespace Anabatic {
, _routingPadAutoSegments()
, _toFixSegments ()
, _degree (0)
, _isStrictChannel (false)
, _isTwoMetals (false)
, _sourceFlags (0)
, _flags (0)
{ }
@ -396,8 +396,8 @@ namespace Anabatic {
_norths .clear();
_souths .clear();
_routingPads .clear();
_routingPadAutoSegments.clear();
_toFixSegments .clear();
_routingPadAutoSegments.clear();
}
@ -416,7 +416,7 @@ namespace Anabatic {
{
clear();
_isStrictChannel = anbt->isChannelStyle() and not anbt->isHybridStyle();
_isTwoMetals = anbt->getConfiguration()->isTwoMetals();
_sourceFlags = sourceFlags;
_sourceContact = sourceContact;
_fromHook = fromHook;
@ -424,7 +424,6 @@ namespace Anabatic {
cdebug_log(145,1) << "NetBuilder::setStartHook()" << endl;
cdebug_log(145,0) << "* _fromHook: " << fromHook << endl;
cdebug_log(145,0) << "* _sourceContact:" << sourceContact << endl;
cdebug_log(145,0) << "_isStrictChannel:" << _isStrictChannel << endl;
if (not _fromHook) {
cdebug_tabw(145,-1);
@ -514,13 +513,6 @@ namespace Anabatic {
break;
}
}
if (rpDepth >= Session::getRoutingGauge()->getFirstRoutingLayer())
rpDepth -= Session::getRoutingGauge()->getFirstRoutingLayer();
else
cerr << Error( "Terminal layer \"%s\" of %s is below first usable routing layer."
, getString(layer->getName()).c_str()
, getString(anchor).c_str() )
<< endl;
if ((rpDepth > 0) and not isPin
and not Session::getRoutingGauge()->isSuperPitched()) {
_flags |= ToUpperRouting;
@ -581,6 +573,7 @@ namespace Anabatic {
<< "+" << (int)_connexity.fields.Pad
<< "] " << _gcell
<< endl;
return *this;
}
@ -678,16 +671,13 @@ namespace Anabatic {
cdebug_log(145,0) << "getSourceFlags():" << getSourceFlags()
<< " getFlags():" << getFlags() << endl;
if (not isStrictChannel()) {
if (not isTwoMetals()) {
_southWestContact = NULL;
_northEastContact = NULL;
}
if (not _gcell->isAnalog()) {
if (isStrictChannel() and not _sourceContact) {
cdebug_log(145,0) << "No _sourceContact, resetting _fromHook" << endl;
_fromHook = NULL;
}
if (isTwoMetals() and not _sourceContact) _fromHook = NULL;
switch ( _connexity.connexity ) {
case Conn_1G_1Pad:
@ -726,7 +716,7 @@ namespace Anabatic {
case Conn_2G_6M1:
case Conn_2G_7M1:
case Conn_2G_8M1:
case Conn_2G_9M1: _do_xG_xM1_xM3(); break;
case Conn_2G_9M1:
case Conn_3G_1M1: if (_do_xG_1M1()) break;
case Conn_3G_2M1:
case Conn_3G_3M1:
@ -738,7 +728,7 @@ namespace Anabatic {
case Conn_3G_9M1:
case Conn_3G_2M3:
case Conn_3G_3M3:
case Conn_3G_4M3: _do_xG_xM1_xM3(); break;
case Conn_3G_4M3:
case Conn_4G_1M1: if (_do_xG_1M1()) break;
case Conn_4G_2M1:
case Conn_4G_3M1:
@ -779,7 +769,6 @@ namespace Anabatic {
case Conn_1G_1PinM3: _do_1G_1PinM3 (); break;
case Conn_2G_1PinM3:
case Conn_3G_1PinM3: _do_xG_1PinM3 (); break;
case Conn_1G_2M1_1PinM1: _do_1G_xM1_1PinM1(); break;
case Conn_1G_1M1_1PinM3: _do_1G_1M1_1PinM3(); break;
case Conn_1G_1M1_1PinM2:
case Conn_1G_2M1_1PinM2:
@ -798,7 +787,7 @@ namespace Anabatic {
case Conn_1G_1M1_1M3: _do_1G_xM1 (); break;
case Conn_2G_1M1_1M2: _do_xG_1M1_1M2 (); break;
default:
//if (not isStrictChannel())
if (not isTwoMetals())
throw Bug( "Unmanaged Configuration [%d] = [%d+%d+%d+%d,%d+%d] %s in %s\n"
" The global routing seems to be defective."
, _connexity.connexity
@ -814,9 +803,6 @@ namespace Anabatic {
_do_xG();
}
cdebug_log(145,0) << "SouthWest: " << _southWestContact << endl;
cdebug_log(145,0) << "NorthEast: " << _northEastContact << endl;
if (not _do_globalSegment()) {
cdebug_log(145,0) << "No global generated, finish." << endl;
cdebug_tabw(145,-1);
@ -1157,9 +1143,7 @@ namespace Anabatic {
bool NetBuilder::_do_xG_1PinM2 ()
{
throw Error( "%s::_do_xG_1PinM2() method *not* reimplemented from base class.\n"
" On %s"
, getTypeName().c_str(), getString(getNet()).c_str() );
throw Error ( "%s::_do_xG_1PinM2() method *not* reimplemented from base class.", getTypeName().c_str() );
return false;
}
@ -1276,13 +1260,6 @@ namespace Anabatic {
}
bool NetBuilder::_do_1G_xM1_1PinM1 ()
{
throw Error ( "%s::_do_1G_xM1_1PinM1() method *not* reimplemented from base class.", getTypeName().c_str() );
return false;
}
bool NetBuilder::_do_3G_xM1_1PinM3 ()
{
throw Error ( "%s::_do_3G_xM1_1PinM3() method *not* reimplemented from base class.", getTypeName().c_str() );
@ -1304,12 +1281,11 @@ namespace Anabatic {
vector<RoutingPad*> rpM1s;
Component* rpM2 = NULL;
for ( RoutingPad* rp : net->getRoutingPads() ) {
if ( Session::getRoutingGauge()->getLayerDepth(rp->getLayer())
== 1 + Session::getRoutingGauge()->getFirstRoutingLayer())
rpM2 = rp;
forEach ( RoutingPad*, irp, net->getRoutingPads() ) {
if (Session::getRoutingGauge()->getLayerDepth(irp->getLayer()) == 1)
rpM2 = *irp;
else
rpM1s.push_back( rp );
rpM1s.push_back( *irp );
}
if ((rpM1s.size() < 2) and not rpM2) {

View File

@ -1,7 +1,7 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) Sorbonne Université 2008-2022, All Rights Reserved
// Copyright (c) UPMC 2008-2018, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
@ -67,10 +67,6 @@ namespace Anabatic {
NetBuilderHV::~NetBuilderHV () { }
string NetBuilderHV::getStyle ()
{ return "HV,3RL+"; }
void NetBuilderHV::doRp_AutoContacts ( GCell* gcell
, Component* rp
, AutoContact*& source
@ -103,7 +99,7 @@ namespace Anabatic {
GCell* targetGCell = Session::getAnabatic()->getGCellUnder( targetPosition );
if (rpDepth == 0) {
rpLayer = Session::getBuildContactLayer(0);
rpLayer = Session::getContactLayer(0);
direction = Flags::Horizontal;
viaSide = Session::getViaWidth( rpDepth );
}
@ -267,7 +263,7 @@ namespace Anabatic {
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::getBuildContactLayer(1) );
AutoContact* subContact1 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) );
AutoSegment::create( rpSourceContact, subContact1, Flags::Horizontal );
rpSourceContact = subContact1;
@ -278,9 +274,7 @@ namespace Anabatic {
if (flags & (VSmall|UseNonPref)) {
cdebug_log(145,0) << "case: UseNonPref" << endl;
if (flags & VSmall)
useNonPref.reset( Flags::UseNonPref );
AutoContact* subContact1 = AutoContactTurn::create( gcell, rp->getNet(), Session::getBuildContactLayer(rpDepth+1) );
AutoContact* subContact1 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(rpDepth+1) );
AutoSegment::create( rpSourceContact, subContact1, Flags::Vertical|useNonPref );
rpSourceContact = subContact1;
}
@ -289,18 +283,18 @@ namespace Anabatic {
cdebug_log(145,0) << "case: HSmall" << endl;
AutoContact* subContact1 = rpSourceContact;
AutoContact* subContact2 = AutoContactTurn::create( gcell, rp->getNet(), Session::getBuildContactLayer(rpDepth+1) );
AutoContact* subContact2 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(rpDepth+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::getBuildContactLayer(rpDepth+1) );
subContact2 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(rpDepth+1) );
AutoSegment::create( subContact1, subContact2, Flags::Vertical, rpDepth+2 );
subContact1 = subContact2;
subContact2 = AutoContactTurn::create( gcell, rp->getNet(), Session::getBuildContactLayer(rpDepth+1) );
subContact2 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(rpDepth+1) );
AutoSegment::create( subContact1, subContact2, Flags::Horizontal, rpDepth+1 );
rpSourceContact = subContact2;
@ -315,9 +309,9 @@ namespace Anabatic {
cdebug_log(145,0) << "HAccess" << endl;
if (flags & HAccessEW) {
cdebug_log(145,0) << "HAccessEW" << endl;
subContact1 = AutoContactHTee::create( gcell, rp->getNet(), Session::getBuildContactLayer(rpDepth+1) );
subContact1 = AutoContactHTee::create( gcell, rp->getNet(), Session::getContactLayer(rpDepth+1) );
} else
subContact1 = AutoContactTurn::create( gcell, rp->getNet(), Session::getBuildContactLayer(rpDepth+1) );
subContact1 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(rpDepth+1) );
AutoSegment::create( rpSourceContact, subContact1, Flags::Vertical, rpDepth+1 );
} else {
@ -331,14 +325,14 @@ namespace Anabatic {
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::getBuildContactLayer(1) );
subContact1 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( rpSourceContact, subContact1, Flags::Vertical );
rpSourceContact = subContact1;
}
#endif
if (Session::getRoutingGauge()->isSuperPitched()) {
cdebug_log(145,0) << "Vertical access & super-pitched" << endl;
subContact1 = AutoContactTurn::create( gcell, rp->getNet(), Session::getBuildContactLayer(1) );
subContact1 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) );
AutoSegment::create( rpSourceContact, subContact1, Flags::Horizontal );
} else {
cdebug_log(145,0) << "Vertical access" << endl;
@ -354,9 +348,9 @@ namespace Anabatic {
}
AutoContact* NetBuilderHV::doRp_AccessNorthSouthPin ( GCell* gcell, RoutingPad* rp )
AutoContact* NetBuilderHV::doRp_AccessNorthPin ( GCell* gcell, RoutingPad* rp )
{
cdebug_log(145,1) << getTypeName() << "::doRp_AccessNorthSouthPin() " << rp << endl;
cdebug_log(145,1) << getTypeName() << "::doRp_AccessNorthPin() " << rp << endl;
AutoContact* rpSourceContact = NULL;
AutoContact* rpContactTarget = NULL;
@ -368,13 +362,13 @@ namespace Anabatic {
Pin* pin = dynamic_cast<Pin*>( rp->getOccurrence().getEntity() );
Pin::AccessDirection pinDir = pin->getAccessDirection();
if (pinDir == Pin::AccessDirection::NORTH) {
turn = AutoContactTurn::create( gcell, net, Session::getBuildRoutingLayer(1) );
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::getBuildContactLayer(1) );
turn = AutoContactTurn::create( gcell, net, Session::getContactLayer(1) );
segment = AutoSegment::create( rpSourceContact, turn, Flags::Horizontal );
rpSourceContact = turn;
@ -395,7 +389,7 @@ namespace Anabatic {
AutoContact* NetBuilderHV::doRp_AccessEastWestPin ( GCell* gcell, RoutingPad* rp )
{
cdebug_log(145,1) << getTypeName() << "::doRp_AccessEastWestPin() " << rp << endl;
cdebug_log(145,1) << getTypeName() << "::doRp_AccessNorthPin() " << rp << endl;
Net* net = rp->getNet();
Pin* pin = dynamic_cast<Pin*>( rp->getOccurrence().getEntity() );
@ -407,12 +401,12 @@ namespace Anabatic {
doRp_AutoContacts( gcell, rp, rpSourceContact, rpContactTarget, NoProtect );
turn = AutoContactTurn::create( gcell, net, Session::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
turn = AutoContactTurn::create( gcell, net, Session::getContactLayer(1) );
segment = AutoSegment::create( rpSourceContact, turn, Flags::Vertical );
DbU::Unit axis = 0;
@ -483,7 +477,7 @@ namespace Anabatic {
if (north() or south()) {
AutoContact* turn = globalContact;
globalContact = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
globalContact = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( globalContact, turn, Flags::Horizontal );
}
@ -506,7 +500,7 @@ namespace Anabatic {
vDepth += 2;
cDepth += 2;
}
const Layer* viaLayer = Session::getBuildContactLayer( cDepth );
const Layer* viaLayer = Session::getContactLayer( cDepth );
if (getConnexity().fields.globals == 2) {
setBothCornerContacts( AutoContactTurn::create( getGCell(), getNet(), viaLayer ) );
@ -548,7 +542,7 @@ namespace Anabatic {
vDepth += 2;
cDepth += 2;
}
const Layer* viaLayer = Session::getBuildContactLayer( cDepth );
const Layer* viaLayer = Session::getContactLayer( cDepth );
if (east() and west()) {
setSouthWestContact( AutoContactTurn::create( getGCell(), getNet(), viaLayer ) );
@ -604,7 +598,7 @@ namespace Anabatic {
// source = AutoContactTerminal::create ( gcell
// , getRoutingPads()[0]
// , Session::getBuildContactLayer(3)
// , Session::getContactLayer(3)
// , position
// , Session::getViaWidth(3), Session::getViaWidth(3)
// );
@ -620,16 +614,16 @@ namespace Anabatic {
if (getConnexity().fields.globals == 1) {
if ( (westPad and (east() != NULL))
or (eastPad and (west() != NULL)) ) {
AutoContact* turn = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
setBothCornerContacts( AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) ) );
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::getBuildContactLayer(1) );
setBothCornerContacts( AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) ) );
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);
@ -679,11 +673,11 @@ namespace Anabatic {
doRp_AutoContacts( getGCell(), getRoutingPads()[0], rpSourceContact, rpContactTarget, NoFlags );
AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
AutoContact* turn2 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( turn1, turn2, Flags::Vertical );
turn1 = turn2;
}
@ -708,11 +702,11 @@ namespace Anabatic {
Pin::AccessDirection pinDir = pin->getAccessDirection();
if ( (pinDir == Pin::AccessDirection::NORTH)
or (pinDir == Pin::AccessDirection::SOUTH) ) {
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildRoutingLayer(1) );
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getRoutingLayer(1) );
AutoSegment::create( rpSourceContact, turn, Flags::Vertical|Flags::UseNonPref );
rpSourceContact = turn;
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment* horizontal = AutoSegment::create( rpSourceContact, turn, Flags::Horizontal );
rpSourceContact = turn;
@ -725,25 +719,25 @@ namespace Anabatic {
horizontal->setFlags( AutoSegment::SegFixed|AutoSegment::SegFixedAxis );
cdebug_log(145,0) << horizontal << endl;
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildRoutingLayer(1) );
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::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
rpSourceContact = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment* vertical = AutoSegment::create( turn, rpSourceContact, Flags::Vertical );
DbU::Unit axis = getGCell()->getXMax() - Session::getDVerticalPitch();
@ -778,11 +772,11 @@ namespace Anabatic {
Pin::AccessDirection pinDir = pin->getAccessDirection();
if ( (pinDir == Pin::AccessDirection::NORTH)
or (pinDir == Pin::AccessDirection::SOUTH) ) {
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildRoutingLayer(1) );
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getRoutingLayer(1) );
AutoSegment::create( rpSourceContact, turn, Flags::Vertical|Flags::UseNonPref );
rpSourceContact = turn;
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment* horizontal = AutoSegment::create( rpSourceContact, turn, Flags::Horizontal );
rpSourceContact = turn;
@ -792,12 +786,12 @@ namespace Anabatic {
horizontal->setAxis( axis, Flags::Force );
horizontal->setFlags( AutoSegment::SegFixed );
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildRoutingLayer(1) );
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::getBuildContactLayer(1) );
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
horizontal = AutoSegment::create( rpSourceContact, turn, Flags::Horizontal );
horizontal->setAxis( axis, Flags::Force );
rpSourceContact = turn;
@ -806,21 +800,21 @@ namespace Anabatic {
if (east() and west()) {
// Pin must be North or South.
tee = AutoContactHTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( rpSourceContact, turn, Flags::Horizontal );
rpSourceContact = turn;
}
tee = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
tee = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment* vertical = AutoSegment::create( rpSourceContact, tee, Flags::Vertical );
if ( (pinDir == Pin::AccessDirection::EAST)
@ -856,11 +850,11 @@ namespace Anabatic {
Pin::AccessDirection pinDir = pin->getAccessDirection();
if ( (pinDir == Pin::AccessDirection::EAST)
or (pinDir == Pin::AccessDirection::WEST) ) {
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( rpSourceContact, turn, Flags::Horizontal );
rpSourceContact = turn;
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment* vertical = AutoSegment::create( rpSourceContact, turn, Flags::Vertical );
rpSourceContact = turn;
@ -883,51 +877,51 @@ namespace Anabatic {
if (getConnexity().fields.globals == 2) {
if (west() and south()) {
AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( rpSourceContact, turn1, Flags::Horizontal );
AutoContact* vtee1 = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
AutoContact* vtee1 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( rpSourceContact, vtee1, Flags::Horizontal );
AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( rpSourceContact, turn1, Flags::Horizontal );
AutoContact* htee1 = AutoContactHTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
AutoContact* htee1 = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( rpSourceContact, htee1, Flags::Horizontal );
AutoContact* htee2 = AutoContactHTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
AutoContact* htee2 = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( htee1, htee2, Flags::Horizontal );
if (pinDir == Pin::AccessDirection::EAST)
@ -948,13 +942,13 @@ namespace Anabatic {
AutoContact* rpSourceContact = NULL;
rpSourceContact = doRp_AccessNorthSouthPin( getGCell(), getRoutingPads()[0] );
rpSourceContact = doRp_AccessNorthPin( getGCell(), getRoutingPads()[0] );
AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(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::getBuildContactLayer(1) );
AutoContact* turn2 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( turn1, turn2, Flags::Horizontal );
turn1 = turn2;
}
@ -976,60 +970,60 @@ namespace Anabatic {
if (getConnexity().fields.globals == 2) {
if (west() and south()) {
AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( rpSourceContact, turn1, Flags::Vertical );
AutoContact* htee1 = AutoContactHTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
AutoContact* htee1 = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( rpSourceContact, htee1, Flags::Vertical );
AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
AutoContact* htee1 = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( rpSourceContact, htee1, Flags::Vertical );
AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( rpSourceContact, turn1, Flags::Vertical );
AutoContact* vtee1 = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
AutoContact* turn2 = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
AutoContact* vtee1 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( turn2, vtee1, Flags::Vertical );
AutoContact* vtee2 = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
AutoContact* vtee2 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( vtee1, vtee2, Flags::Vertical );
setSouthWestContact( vtee1 );
@ -1067,11 +1061,11 @@ namespace Anabatic {
AutoContact* m1contact = doRp_Access( getGCell(), rpsM1.back(), HAccess );
AutoContact* vtee1 = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
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::getBuildContactLayer(1) );
AutoContact* vtee2 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( vtee1, vtee2, Flags::Vertical );
setBothCornerContacts( vtee2 );
@ -1107,13 +1101,13 @@ namespace Anabatic {
AutoContact* m1contact = doRp_Access( getGCell(), rpsM1.back(), HAccess );
AutoContact* vtee1 = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
AutoContact* vtee1 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( m1contact , vtee1, Flags::Horizontal );
AutoContact* vtee2 = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
AutoContact* vtee2 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( vtee1, vtee2, Flags::Vertical );
AutoContact* vtee3 = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
AutoContact* vtee3 = AutoContactVTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( vtee2, vtee3, Flags::Vertical );
if (not south() or not north()) {
@ -1157,8 +1151,8 @@ namespace Anabatic {
}
for ( size_t i=1 ; i<rpsM1.size() ; ++i ) {
AutoContact* leftContact = doRp_Access( getGCell(), rpsM1[i-1], HAccess );
AutoContact* rightContact = doRp_Access( getGCell(), rpsM1[i ], HAccess );
AutoContact* leftContact = doRp_Access( getGCell(), getRoutingPads()[i-1], HAccess );
AutoContact* rightContact = doRp_Access( getGCell(), getRoutingPads()[i ], HAccess );
AutoSegment::create( leftContact, rightContact, Flags::Horizontal );
}
@ -1170,8 +1164,8 @@ namespace Anabatic {
rpM1Contact = doRp_Access( getGCell(), rpsM1[0], (north() or south()) ? HAccess : NoFlags );
if (north() or south()) {
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
tee = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
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 );
@ -1179,8 +1173,8 @@ namespace Anabatic {
setBothCornerContacts( tee );
} else {
turn = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
tee = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
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 );
@ -1189,6 +1183,12 @@ namespace Anabatic {
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;
}
@ -1214,8 +1214,8 @@ namespace Anabatic {
if (north() and south()) {
cdebug_log(145,0) << "Case north & south." << endl;
AutoContact* htee = AutoContactHTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
AutoContact* vtee = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
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 );
@ -1223,9 +1223,9 @@ namespace Anabatic {
setBothCornerContacts( vtee );
} else if (east() and west()) {
cdebug_log(145,0) << "Case east & west." << endl;
AutoContact* htee1 = AutoContactHTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
AutoContact* htee2 = AutoContactHTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
AutoContact* turn = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
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 );
@ -1234,9 +1234,9 @@ namespace Anabatic {
setBothCornerContacts( htee2 );
} else {
cdebug_log(145,0) << "Case bend." << endl;
AutoContact* vtee1 = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
AutoContact* htee2 = AutoContactHTee::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
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 );
@ -1268,13 +1268,13 @@ namespace Anabatic {
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::getBuildContactLayer(1) );
AutoContact* htee = AutoContactHTee::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( contact1, htee, Flags::Horizontal );
rpSourceContact = doRp_AccessNorthSouthPin( getGCell(), pinM3 );
rpSourceContact = doRp_AccessNorthPin( getGCell(), pinM3 );
if (north() or south()) {
AutoContact* turn = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(1) );
AutoContact* turn = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer(1) );
AutoSegment::create( rpSourceContact, turn, Flags::Vertical );
AutoSegment::create( turn , htee, Flags::Horizontal );
} else {
@ -1306,7 +1306,7 @@ namespace Anabatic {
cdebug_log(145,0) << "east: " << east () << endl;
cdebug_log(145,0) << "west: " << west () << endl;
const Layer* viaLayer1 = Session::getBuildContactLayer(1);
const Layer* viaLayer1 = Session::getContactLayer(1);
if (getConnexity().fields.globals == 2) {
if (north() and south()) {
@ -1392,7 +1392,7 @@ namespace Anabatic {
Component* rpL1;
Component* rpL2;
if (getRoutingPads()[0]->getLayer() == Session::getBuildRoutingLayer(0)) {
if (getRoutingPads()[0]->getLayer() == Session::getRoutingLayer(0)) {
rpL1 = getRoutingPads()[0];
rpL2 = getRoutingPads()[1];
} else {
@ -1410,8 +1410,8 @@ namespace Anabatic {
doRp_AutoContacts( getGCell(), rpL1, rpL1ContactSource, rpL1ContactTarget, NoFlags );
doRp_AutoContacts( getGCell(), rpL2, rpL2ContactSource, rpL2ContactTarget, NoFlags );
const Layer* viaLayer1 = Session::getBuildContactLayer(1);
const Layer* viaLayer2 = Session::getBuildContactLayer(2);
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 );
@ -1465,7 +1465,7 @@ namespace Anabatic {
cdebug_log(145,0) << "west: " << west() << endl;
Component* rpM3 = NULL;
if (getRoutingPads()[0]->getLayer() == Session::getBuildRoutingLayer(2))
if (getRoutingPads()[0]->getLayer() == Session::getRoutingLayer(2))
rpM3 = getRoutingPads()[0];
sortRpByX( getRoutingPads(), NoFlags ); // increasing X.
@ -1474,11 +1474,11 @@ namespace Anabatic {
AutoContact* rightContact = doRp_Access( getGCell(), getRoutingPads()[i ], HAccess );
AutoSegment::create( leftContact, rightContact, Flags::Horizontal );
if (not rpM3 and (getRoutingPads()[i]->getLayer() == Session::getBuildRoutingLayer(2)))
if (not rpM3 and (getRoutingPads()[i]->getLayer() == Session::getRoutingLayer(2)))
rpM3 = getRoutingPads()[i];
}
const Layer* viaLayer1 = Session::getBuildContactLayer(1);
const Layer* viaLayer1 = Session::getContactLayer(1);
AutoContact* subContact1 = NULL;
if (rpM3) {
@ -1594,7 +1594,7 @@ namespace Anabatic {
doRp_AutoContacts( getGCell(), rpL2, rpL2ContactSource, rpL2ContactTarget, DoSourceContact|DoTargetContact );
const Layer* viaLayer2 = Session::getBuildContactLayer(2);
const Layer* viaLayer2 = Session::getContactLayer(2);
setSouthWestContact( AutoContactHTee::create( getGCell(), getNet(), viaLayer2 ) );
setNorthEastContact( AutoContactHTee::create( getGCell(), getNet(), viaLayer2 ) );
@ -1620,7 +1620,7 @@ namespace Anabatic {
biggestRp = getRoutingPads()[i];
}
const Layer* viaLayer1 = Session::getBuildContactLayer(1);
const Layer* viaLayer1 = Session::getContactLayer(1);
if (east() and west() and not south() and not north()) {
AutoContact* rpContact = doRp_Access( getGCell(), biggestRp, HBothAccess );
@ -1678,13 +1678,13 @@ namespace Anabatic {
cdebug_log(145,0) << "_northEast: " << getNorthEastContact() << endl;
if (not (east() or west())) {
AutoContact* subContact = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer((rpDepth)) );
AutoContact* subContact = AutoContactTurn::create( getGCell(), getNet(), Session::getContactLayer((rpDepth)) );
AutoSegment::create( getSouthWestContact(), subContact, Flags::Horizontal, rpDepth+1 );
setBothCornerContacts( subContact );
}
#if THIS_IS_DISABLED
const Layer* viaLayer1 = Session::getBuildContactLayer(1);
const Layer* viaLayer1 = Session::getContactLayer(1);
Box cellAb = getAnabatic()->getCell()->getAbutmentBox();
RoutingLayerGauge* lgM3 = Session::getLayerGauge( 2 );
@ -1740,9 +1740,9 @@ namespace Anabatic {
size_t rpDepth = Session::getLayerDepth( getRoutingPads()[0]->getLayer() );
size_t vDepth = rpDepth + 2;
size_t hDepth = rpDepth + 1;
const Layer* viaLayer = Session::getBuildContactLayer( rpDepth );
const Layer* viaLayer = Session::getContactLayer( rpDepth );
if (Session::getRoutingGauge()->isSuperPitched()) {
viaLayer = Session::getBuildContactLayer( 1 );
viaLayer = Session::getContactLayer( 1 );
vDepth = 2;
hDepth = 1;
}
@ -1834,7 +1834,7 @@ namespace Anabatic {
if ((int)getConnexity().fields.M3 != 1) return false;
const Layer* viaLayer2 = Session::getBuildContactLayer(rpDepth);
const Layer* viaLayer2 = Session::getContactLayer(rpDepth);
if (getConnexity().fields.globals == 2) {
if (north() and south()) {
@ -1917,7 +1917,7 @@ namespace Anabatic {
size_t gdepth = Session::getGHorizontalDepth();
if (dynamic_cast<Vertical*>(baseSegment))
gdepth = Session::getGVerticalDepth();
baseSegment->setLayer( Session::getBuildRoutingLayer( gdepth+2 ));
baseSegment->setLayer( Session::getRoutingLayer( gdepth+2 ));
baseSegment->setWidth( Session::getWireWidth( gdepth+2 ));
}
@ -1966,8 +1966,7 @@ namespace Anabatic {
continue;
}
if ( Session::getRoutingGauge()->getLayerDepth(rp->getLayer())
== 1 + Session::getRoutingGauge()->getFirstRoutingLayer())
if (Session::getRoutingGauge()->getLayerDepth(rp->getLayer()) == 1)
rpM2 = rp;
else
rpM1s.push_back( rp );
@ -2050,7 +2049,7 @@ namespace Anabatic {
if (rpM2) {
doRp_AutoContacts( gcell1, rpM1s[0], source, turn1, DoSourceContact );
doRp_AutoContacts( gcell1, rpM2 , target, turn1, DoSourceContact );
turn1 = AutoContactTurn::create( gcell1, rpM2->getNet(), Session::getBuildContactLayer(1) );
turn1 = AutoContactTurn::create( gcell1, rpM2->getNet(), Session::getContactLayer(1) );
AutoSegment::create( source, turn1 , Flags::Horizontal );
AutoSegment::create( turn1 , target, Flags::Vertical );
}
@ -2062,8 +2061,8 @@ namespace Anabatic {
if ( (pinDir == Pin::AccessDirection::NORTH)
or (pinDir == Pin::AccessDirection::SOUTH) ) {
doRp_AutoContacts( gcell1, rpM1s[0], source, turn1, DoSourceContact );
target = doRp_AccessNorthSouthPin( gcell1, rpPin );
turn1 = AutoContactTurn::create( gcell1, rpPin->getNet(), Session::getBuildContactLayer(1) );
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 {

View File

@ -1,643 +0,0 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) Sorbonne Université 2022-2022, 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 : "./NetBuilderHybridVH.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/Pin.h"
#include "hurricane/Pad.h"
#include "hurricane/Plug.h"
#include "hurricane/Cell.h"
#include "hurricane/Instance.h"
#include "hurricane/Vertical.h"
#include "hurricane/Horizontal.h"
#include "crlcore/AllianceFramework.h"
#include "crlcore/RoutingGauge.h"
#include "crlcore/Measures.h"
#include "anabatic/AutoContactTerminal.h"
#include "anabatic/AutoContactTurn.h"
#include "anabatic/AutoContactHTee.h"
#include "anabatic/AutoContactVTee.h"
#include "anabatic/AutoSegment.h"
#include "anabatic/NetBuilderHybridVH.h"
#include "anabatic/AnabaticEngine.h"
namespace Anabatic {
using std::swap;
using Hurricane::Error;
using Hurricane::Pin;
NetBuilderHybridVH::NetBuilderHybridVH ()
: NetBuilder()
{ }
NetBuilderHybridVH::~NetBuilderHybridVH () { }
string NetBuilderHybridVH::getStyle ()
{ return "VH,2RL"; }
void NetBuilderHybridVH::doRp_AutoContacts ( GCell* gcell
, Component* rp
, AutoContact*& source
, AutoContact*& target
, uint64_t flags
)
{
throw Error ( "%s::dpRp_AutoContacts() method must never be called.", getTypeName().c_str() );
}
AutoContact* NetBuilderHybridVH::doRp_Access ( GCell* gcell, Component* rp, uint64_t flags )
{
cdebug_log(145,1) << getTypeName() << "::doRp_Access()" << endl;
cdebug_log(145,0) << rp << endl;
const Layer* rpLayer = rp->getLayer();
//const Layer* viaLayer = Session::getDContactLayer();
DbU::Unit viaSide = Session::getDContactWidth();
Point position = rp->getCenter();
AutoContact* rpContact = AutoContactTerminal::create( gcell, rp, rpLayer, position, viaSide, viaSide );
cdebug_tabw(145,-1);
return rpContact;
}
AutoContact* NetBuilderHybridVH::doRp_AccessNorthSouthPin ( GCell* gcell, RoutingPad* rp )
{
cdebug_log(145,1) << getTypeName() << "::doRp_AccessNorthSouthPin() " << rp << endl;
AutoContact* rpContact = doRp_Access( gcell, rp, NoFlags );
AutoContact* turn = NULL;
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::getBuildRoutingLayer(0) );
AutoSegment* segment = AutoSegment::create( rpContact, turn, Flags::Vertical );
segment->setAxis( rp->getX(), Flags::Force );
segment->setFlags( AutoSegment::SegFixed|AutoSegment::SegFixedAxis );
rpContact = turn;
turn = AutoContactTurn::create( gcell, net, Session::getBuildContactLayer(0) );
segment = AutoSegment::create( rpContact, turn, Flags::Horizontal );
rpContact = 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 = rpContact;
}
cdebug_tabw(145,-1);
return turn;
}
AutoContact* NetBuilderHybridVH::doRp_AccessEastWestPin ( GCell* gcell, RoutingPad* rp )
{
cdebug_log(145,1) << getTypeName() << "::doRp_AccessEastWestPin() " << rp << endl;
Net* net = rp->getNet();
Pin* pin = dynamic_cast<Pin*>( rp->getOccurrence().getEntity() );
Pin::AccessDirection pinDir = pin->getAccessDirection();
AutoContact* rpContact = doRp_Access( gcell, rp, NoFlags );
AutoContact* turn = NULL;
AutoSegment* segment = NULL;
turn = AutoContactTurn::create( gcell, net, Session::getBuildContactLayer(0) );
segment = AutoSegment::create( rpContact, turn, Flags::Horizontal );
segment->setAxis( pin->getCenter().getY(), Flags::Force );
rpContact = turn;
turn = AutoContactTurn::create( gcell, net, Session::getBuildContactLayer(0) );
segment = AutoSegment::create( rpContact, 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 NetBuilderHybridVH::doRp_xG_1M1 ( RoutingPad* rp )
{
cdebug_log(145,1) << getTypeName() << "::doRp_xG_1M1()" << endl;
AutoContact* swContact = nullptr;
if (west() or south()) {
AutoContact* termContact = doRp_Access( getGCell(), rp, NoFlags );
if (west() and south()) {
swContact = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
AutoSegment::create( termContact, swContact, Flags::Vertical );
} else {
if (west()) {
swContact = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
AutoSegment::create( termContact, swContact, Flags::Vertical );
} else
swContact = termContact;
}
setSouthWestContact( swContact );
}
AutoContact* neContact = nullptr;
if (east() or north()) {
AutoContact* termContact = doRp_Access( getGCell(), rp, NoFlags );
if (east() and north()) {
neContact = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
AutoSegment::create( termContact, neContact, Flags::Vertical );
} else {
if (east()) {
neContact = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
AutoSegment::create( termContact, neContact, Flags::Vertical );
} else
neContact = termContact;
}
setNorthEastContact( neContact );
}
cdebug_tabw(145,-1);
return true;
}
bool NetBuilderHybridVH::_do_xG_1M1 ()
{
cdebug_log(145,1) << getTypeName() << "::_do_xG_1M1()" << endl;
doRp_xG_1M1( getRoutingPads()[0] );
cdebug_tabw(145,-1);
return true;
}
bool NetBuilderHybridVH::_do_2G_1M1 ()
{
cdebug_log(145,1) << getTypeName() << "::_do_2G_1M1()" << endl;
doRp_xG_1M1( getRoutingPads()[0] );
cdebug_tabw(145,-1);
return true;
}
bool NetBuilderHybridVH::doRp_xG_xM1_xM3 ( const vector<RoutingPad*>& rps )
{
cdebug_log(145,1) << getTypeName() << "::doRp_xG_xM1()" << endl;
AutoContact* prevContact = nullptr;
AutoContact* currContact = nullptr;
for ( size_t i=0 ; i<rps.size() ; ++i ) {
prevContact = currContact;
AutoContact* currTerm = doRp_Access( getGCell(), rps[i], NoFlags );
if (i == 0) {
if (west() or south()) {
AutoContact* swContact = nullptr;
currContact = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
if (west() and south()) {
swContact = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
} else {
if (west())
swContact = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
else
swContact = currContact;
}
if (swContact != currContact)
AutoSegment::create( currContact, swContact, Flags::Vertical );
setSouthWestContact( swContact );
} else {
currContact = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
}
AutoSegment::create( currTerm, currContact, Flags::Vertical );
continue;
}
if (i+1 == rps.size()) {
if (east() or north()) {
AutoContact* neContact = nullptr;
currContact = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
if (east() and north()) {
neContact = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
} else {
if (east())
neContact = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
else
neContact = currContact;
}
if (neContact != currContact)
AutoSegment::create( currContact, neContact, Flags::Vertical );
setNorthEastContact( neContact );
} else {
currContact = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
}
} else {
currContact = AutoContactHTee::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
}
AutoSegment::create( currTerm , currContact, Flags::Vertical );
AutoSegment::create( prevContact, currContact, Flags::Horizontal );
}
cdebug_tabw(145,-1);
return true;
}
bool NetBuilderHybridVH::_do_xG_xM1_xM3 ()
{
cdebug_log(145,1) << getTypeName() << "::_do_xG_xM1()" << endl;
sortRpByX( getRoutingPads(), NoFlags ); // increasing X.
doRp_xG_xM1_xM3( getRoutingPads() );
cdebug_tabw(145,-1);
return true;
}
bool NetBuilderHybridVH::_do_1G_xM1 ()
{
cdebug_log(145,1) << getTypeName() << "::_do_1G_xM1()" << endl;
if (getConnexity().fields.M1 == 1)
_do_xG_1M1();
else
_do_xG_xM1_xM3();
cdebug_tabw(145,-1);
return true;
}
bool NetBuilderHybridVH::_do_xG ()
{
cdebug_log(145,1) << getTypeName() << "::_do_xG()" << endl;
const Layer* viaLayer = Session::getBuildContactLayer( 0 );
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 NetBuilderHybridVH::_do_1G_1PinM1 ()
{
cdebug_log(145,1) << getTypeName() << "::_do_1G_1PinM1() [Managed Configuration - Optimized] " << getTopology() << endl;
AutoContact* rpContact = doRp_AccessNorthSouthPin( getGCell(), getRoutingPads()[0] );
AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
AutoSegment::create( rpContact, turn1, Flags::Vertical );
if (north() or south()) {
AutoContact* turn2 = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
AutoSegment::create( turn1, turn2, Flags::Horizontal );
turn1 = turn2;
}
setBothCornerContacts( turn1 );
cdebug_tabw(145,-1);
return true;
}
bool NetBuilderHybridVH::_do_2G_1PinM1 ()
{
cdebug_log(145,1) << getTypeName() << "::_do_2G_1PinM1() [Managed Configuration - Optimized] " << getTopology() << endl;
AutoContact* rpContact = doRp_AccessNorthSouthPin( getGCell(), getRoutingPads()[0] );
AutoContact* tee = nullptr;
if (east() and west()) {
tee = AutoContactHTee::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
} else {
tee = AutoContactVTee::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
}
AutoSegment::create( rpContact, tee, Flags::Vertical );
setBothCornerContacts( tee );
cdebug_tabw(145,-1);
return true;
}
bool NetBuilderHybridVH::_do_1G_xM1_1PinM1 ()
{
cdebug_log(145,1) << getTypeName() << "::_do_1G_xM1_1PinM1() [Managed Configuration - Optimized] " << getTopology() << endl;
sortRpByX( getRoutingPads(), NoFlags ); // increasing X.
vector<RoutingPad*> rpsM1;
RoutingPad* rpM2 = nullptr;
for ( RoutingPad* rp : getRoutingPads() ) {
if (dynamic_cast<Pin*>(rp->getOccurrence().getEntity())) rpM2 = rp;
else rpsM1.push_back( rp );
}
if (rpsM1.size() > 1)
doRp_xG_xM1_xM3( rpsM1 );
else
doRp_xG_1M1( rpsM1[0] );
AutoContact* rpContact = doRp_AccessNorthSouthPin( getGCell(), rpM2 );
AutoContact* rpM1Contact = doRp_Access( getGCell(), rpsM1.front(), NoFlags );
AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
AutoContact* turn2 = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
AutoSegment::create( rpM1Contact, turn1, Flags::Vertical );
AutoSegment::create( rpContact , turn2, Flags::Vertical );
AutoSegment::create( turn1 , turn2, Flags::Horizontal );
cdebug_tabw(145,-1);
return true;
}
bool NetBuilderHybridVH::doRp_1G_1PinM2 ( RoutingPad* rp )
{
cdebug_log(145,1) << getTypeName() << "::doRp_1G_1PinM2() [Managed Configuration - Optimized] " << getTopology() << endl;
AutoContact* rpContact = doRp_AccessEastWestPin( getGCell(), rp );
AutoContact* turn1 = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
AutoSegment::create( rpContact, turn1, Flags::Horizontal );
if (east() or west()) {
AutoContact* turn2 = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
AutoSegment::create( turn1, turn2, Flags::Vertical );
turn1 = turn2;
}
setBothCornerContacts( turn1 );
cdebug_tabw(145,-1);
return true;
}
bool NetBuilderHybridVH::_do_1G_1PinM2 ()
{
cdebug_log(145,1) << getTypeName() << "::_do_1G_1PinM2() [Managed Configuration - Optimized] " << getTopology() << endl;
doRp_1G_1PinM2( getRoutingPads()[0] );
cdebug_tabw(145,-1);
return true;
}
bool NetBuilderHybridVH::_do_xG_1PinM2 ()
{
cdebug_log(145,1) << getTypeName() << "::_do_xG_1PinM2()" << endl;
AutoContact* rpContact = doRp_AccessEastWestPin( getGCell(), getRoutingPads()[0] );
AutoContact* neContact = nullptr;
AutoContact* swContact = nullptr;
const Layer* viaLayer = Session::getBuildContactLayer( 0 );
if (getConnexity().fields.globals == 2) {
if (north() and south())
neContact = AutoContactVTee::create( getGCell(), getNet(), viaLayer );
else
neContact = AutoContactHTee::create( getGCell(), getNet(), viaLayer );
AutoSegment::create( rpContact, neContact, Flags::Horizontal );
setBothCornerContacts( neContact );
} else if (getConnexity().fields.globals == 3) {
swContact = AutoContactVTee::create( getGCell(), getNet(), viaLayer );
neContact = AutoContactVTee::create( getGCell(), getNet(), viaLayer );
if (west())
AutoSegment::create( rpContact, neContact, Flags::Horizontal );
else
AutoSegment::create( rpContact, swContact, Flags::Horizontal );
AutoSegment::create( swContact, neContact, Flags::Vertical );
setNorthEastContact( neContact );
setSouthWestContact( swContact );
}
cdebug_tabw(145,-1);
return true;
}
bool NetBuilderHybridVH::_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* rpM2 = nullptr;
for ( RoutingPad* rp : getRoutingPads() ) {
if (dynamic_cast<Pin*>(rp->getOccurrence().getEntity())) rpM2 = rp;
else rpsM1.push_back( rp );
}
if (rpsM1.size() > 1)
doRp_xG_xM1_xM3( rpsM1 );
else
doRp_xG_1M1( rpsM1[0] );
Pin* pin = dynamic_cast<Pin*>( rpM2->getOccurrence().getEntity() );
Pin::AccessDirection pinDir = pin->getAccessDirection();
AutoContact* rpContact = doRp_AccessEastWestPin( getGCell(), rpM2 );
AutoContact* rpM1Contact = nullptr;
if (pinDir == Pin::AccessDirection::EAST)
rpM1Contact = doRp_Access( getGCell(), rpsM1.back(), NoFlags );
else
rpM1Contact = doRp_Access( getGCell(), rpsM1.front(), NoFlags );
AutoContact* turn = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
AutoSegment::create( rpM1Contact, turn, Flags::Vertical );
AutoSegment::create( rpContact , turn, Flags::Horizontal );
cdebug_tabw(145,-1);
return true;
}
bool NetBuilderHybridVH::_do_1G_1M1 () { return false; }
// bool NetBuilderHybridVH::_do_xG_1Pad () { return false; }
// bool NetBuilderHybridVH::_do_xG_xM2 () { return false; }
// bool NetBuilderHybridVH::_do_1G_1M3 () { return false; }
// bool NetBuilderHybridVH::_do_xG_xM3 () { return false; }
// bool NetBuilderHybridVH::_do_xG_1M1_1M2 () { return false; }
// bool NetBuilderHybridVH::_do_4G_1M2 () { return false; }
bool NetBuilderHybridVH::_do_2G () { return false; }
bool NetBuilderHybridVH::_do_globalSegment ()
{
cdebug_log(145,1) << getTypeName() << "::_do_globalSegment()" << endl;
cdebug_log(145,0) << "getSourceFlags():" << getSourceFlags()
<< " getFlags():" << getFlags() << endl;
if (getSourceContact()) {
uint64_t segmentBound = getSegmentHookType( getFromHook() );
AutoContact* targetContact
= (segmentBound & (NorthBound|EastBound)) ? getNorthEastContact() : getSouthWestContact() ;
if (not getFromHook()) cerr << "getFromHook() is NULL !" << endl;
AutoContact* sourceContact = getSourceContact();
if (segmentBound & (NorthBound|SouthBound)) {
AutoContact* turn = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
AutoSegment::create( sourceContact, turn, Flags::Vertical );
sourceContact = AutoContactTurn::create( getGCell(), getNet(), Session::getBuildContactLayer(0) );
AutoSegment::create( sourceContact, turn, Flags::Horizontal );
}
Segment* baseSegment = static_cast<Segment*>( getFromHook()->getComponent() );
AutoSegment* globalSegment = AutoSegment::create( sourceContact
, targetContact
, baseSegment
);
globalSegment->setFlags( (getDegree() == 2) ? AutoSegment::SegBipoint : 0 );
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 NetBuilderHybridVH::singleGCell ( AnabaticEngine* anbt, Net* net )
{
cdebug_log(145,1) << getTypeName() << "::singleGCell() " << net << endl;
vector<RoutingPad*> rps;
for ( RoutingPad* irp : net->getRoutingPads() )
rps.push_back( irp );
if (rps.size() < 2) {
cerr << Error( "%s::singleGCell(): For %s, less than two Plugs/Pins (%d)."
, getTypeName().c_str()
, getString(net).c_str()
, rps.size() ) << endl;
cdebug_tabw(145,-1);
return;
}
sortRpByX( rps, NetBuilder::NoFlags ); // increasing X.
GCell* gcell1 = anbt->getGCellUnder( rps.front()->getCenter() );
GCell* gcell2 = anbt->getGCellUnder( rps.back ()->getCenter() );
if (not gcell1) {
cerr << Error( "No GCell under %s.", getString(rps.front()).c_str() ) << endl;
cdebug_tabw(145,-1);
return;
}
if (gcell1 != gcell2) {
cerr << Error( "Not under a single GCell %s.", getString(rps.back()).c_str() ) << endl;
cdebug_tabw(145,-1);
return;
}
AutoContact* prevContact = nullptr;
AutoContact* currContact = nullptr;
for ( size_t i=0 ; i<rps.size() ; ++i ) {
prevContact = currContact;
AutoContact* currTerm = doRp_Access( gcell1, rps[i], NoFlags );
if (i == 0) {
currContact = AutoContactTurn::create( gcell1, net, Session::getBuildContactLayer(0) );
AutoSegment::create( currTerm, currContact, Flags::Vertical );
continue;
}
if (i+1 == rps.size()) {
currContact = AutoContactTurn::create( gcell1, net, Session::getBuildContactLayer(0) );
} else {
currContact = AutoContactHTee::create( gcell1, net, Session::getBuildContactLayer(0) );
}
AutoSegment::create( currTerm , currContact, Flags::Vertical );
AutoSegment::create( prevContact, currContact, Flags::Horizontal );
}
cdebug_tabw(145,-1);
}
string NetBuilderHybridVH::getTypeName () const
{ return "NetBuilderHybridVH"; }
} // Anabatic namespace.

View File

@ -62,10 +62,6 @@ namespace Anabatic {
NetBuilderM2::~NetBuilderM2 () { }
string NetBuilderM2::getStyle ()
{ return "2RL-"; }
void NetBuilderM2::doRp_AutoContacts ( GCell* gcell
, Component* rp
, AutoContact*& source

View File

@ -67,10 +67,6 @@ namespace Anabatic {
NetBuilderVH::~NetBuilderVH () { }
string NetBuilderVH::getStyle ()
{ return "VH,3RL+"; }
void NetBuilderVH::doRp_AutoContacts ( GCell* gcell
, Component* rp
, AutoContact*& source

View File

@ -16,7 +16,7 @@
#include "hurricane/isobar/PyHurricane.h"
#include "hurricane/isobar/PyCell.h"
#include "anabatic/PyStyleFlags.h"
#include "anabatic/Constants.h"
namespace Anabatic {
@ -76,10 +76,6 @@ extern "C" {
{
cdebug_log(32,0) << "PyInit_Anabatic()" << endl;
PyStyleFlags_LinkPyType();
PYTYPE_READY( StyleFlags );
PyObject* module = PyModule_Create( &PyAnabatic_ModuleDef );
if (module == NULL) {
cerr << "[ERROR]\n"
@ -87,9 +83,6 @@ extern "C" {
return NULL;
}
Py_INCREF( &PyTypeStyleFlags );
PyModule_AddObject( module, "StyleFlags", (PyObject*)&PyTypeStyleFlags );
PyObject* dictionnary = PyModule_GetDict(module);
PyObject* constant;
@ -100,7 +93,6 @@ extern "C" {
LoadObjectConstant( dictionnary,EngineLayerAssignNoGlobalM2V,"EngineLayerAssignNoGlobalM2V" );
LoadObjectConstant( dictionnary,EngineNoNetLayerAssign ,"EngineNoNetLayerAssign" );
PyStyleFlags_postModuleInit();
return module;
}

View File

@ -1,123 +0,0 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) Sorbonne Université 2022-2022, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | A n a b a t i c - Global Routing Toolbox |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Module : "./PyStyleFlags.h" |
// +-----------------------------------------------------------------+
#include "anabatic/PyStyleFlags.h"
namespace Anabatic {
using std::cerr;
using std::endl;
using std::hex;
using std::ostringstream;
using Hurricane::tab;
using Hurricane::Error;
using Hurricane::Warning;
using Isobar::ProxyProperty;
using Isobar::ProxyError;
using Isobar::ConstructorError;
using Isobar::HurricaneError;
using Isobar::HurricaneWarning;
using Isobar::ParseOneArg;
using Isobar::ParseTwoArg;
using Isobar::getPyHash;
extern "C" {
#define METHOD_HEAD(function) GENERIC_METHOD_HEAD(StyleFlags,status,function)
// +=================================================================+
// | "PyStyleFlags" Python Module Code Part |
// +=================================================================+
#if defined(__PYTHON_MODULE__)
PyMethodDef PyStyleFlags_Methods[] =
{ {NULL, NULL, 0, NULL} /* sentinel */
};
PythonOnlyDeleteMethod(StyleFlags)
DirectReprMethod (PyStyleFlags_Repr, PyStyleFlags, StyleFlags)
DirectStrMethod (PyStyleFlags_Str, PyStyleFlags, StyleFlags)
DirectCmpByValueMethod(PyStyleFlags_Cmp, IsPyStyleFlags, PyStyleFlags)
DirectHashMethod (PyStyleFlags_Hash, StyleFlags)
extern void PyStyleFlags_LinkPyType() {
cdebug_log(20,0) << "PyStyleFlags_LinkType()" << endl;
PyTypeStyleFlags.tp_dealloc = (destructor) PyStyleFlags_DeAlloc;
PyTypeStyleFlags.tp_richcompare = (richcmpfunc)PyStyleFlags_Cmp;
PyTypeStyleFlags.tp_repr = (reprfunc) PyStyleFlags_Repr;
PyTypeStyleFlags.tp_str = (reprfunc) PyStyleFlags_Str;
PyTypeStyleFlags.tp_hash = (hashfunc) PyStyleFlags_Hash;
PyTypeStyleFlags.tp_methods = PyStyleFlags_Methods;
}
#else // End of Python Module Code Part.
// +=================================================================+
// | "PyStyleFlags" Shared Library Code Part |
// +=================================================================+
// Link/Creation Method.
PyTypeObjectDefinitions(StyleFlags)
extern void PyStyleFlags_postModuleInit ()
{
PyObject* constant = NULL;
LoadObjectConstant( PyTypeStyleFlags.tp_dict, (uint64_t)StyleFlags::NoStyle, "NoStyle" );
LoadObjectConstant( PyTypeStyleFlags.tp_dict, (uint64_t)StyleFlags::HV , "HV" );
LoadObjectConstant( PyTypeStyleFlags.tp_dict, (uint64_t)StyleFlags::VH , "VH" );
LoadObjectConstant( PyTypeStyleFlags.tp_dict, (uint64_t)StyleFlags::OTH , "OTH" );
LoadObjectConstant( PyTypeStyleFlags.tp_dict, (uint64_t)StyleFlags::Channel, "Channel" );
LoadObjectConstant( PyTypeStyleFlags.tp_dict, (uint64_t)StyleFlags::Hybrid , "Hybrid" );
}
#endif // Shared Library Code Part.
} // extern "C".
#if !defined(__PYTHON_MODULE__)
extern StyleFlags PyInt_AsStyleFlags ( PyObject* object )
{
uint64_t value = (uint64_t)Isobar::PyAny_AsLong( object );
if ( (value == (uint64_t)StyleFlags::NoStyle)
or (value == (uint64_t)StyleFlags::HV)
or (value == (uint64_t)StyleFlags::VH)
or (value == (uint64_t)StyleFlags::OTH)
or (value == (uint64_t)StyleFlags::Channel)
or (value == (uint64_t)StyleFlags::Hybrid))
return value;
return StyleFlags::NoStyle;
}
#endif
} // Isobar namespace.

View File

@ -419,16 +419,12 @@ namespace Anabatic {
}
StyleFlags Session::getRoutingStyle ()
{ return get("getRoutingStyle()")->_anabatic->getRoutingStyle(); }
bool Session::isInDemoMode ()
{ return get("isInDemoMode()")->_anabatic->isInDemoMode(); }
bool Session::isChannelStyle ()
{ return get("isChannelStyle()")->_anabatic->isChannelStyle(); }
bool Session::isChannelMode ()
{ return get("isChannelMode()")->_anabatic->isChannelMode(); }
float Session::getSaturateRatio ()

646
anabatic/src/anabatic/: Normal file
View File

@ -0,0 +1,646 @@
// -*- 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++ Header : "./anabatic/AutoSegment.h" |
// +-----------------------------------------------------------------+
#ifndef ANABATIC_AUTOSEGMENT_H
#define ANABATIC_AUTOSEGMENT_H
#include <set>
#include <iostream>
#include <functional>
#include "hurricane/Interval.h"
#include "hurricane/Segment.h"
#include "hurricane/Components.h"
#include "hurricane/Contact.h"
namespace Hurricane {
class Layer;
class Horizontal;
class Vertical;
class Cell;
}
#include "crlcore/RoutingGauge.h"
#include "anabatic/Constants.h"
#include "anabatic/GCell.h"
#include "anabatic/AutoSegments.h"
#include "anabatic/Session.h"
namespace Anabatic {
using std::array;
using std::set;
using std::cerr;
using std::endl;
using std::binary_function;
using Hurricane::StaticObservable;
using Hurricane::BaseObserver;
using Hurricane::tab;
using Hurricane::Interval;
using Hurricane::Layer;
using Hurricane::Components;
using Hurricane::Horizontal;
using Hurricane::Vertical;
using Hurricane::Cell;
using CRL::RoutingGauge;
class AutoHorizontal;
class AutoVertical;
// -------------------------------------------------------------------
// Class : "AutoSegment".
class AutoSegment {
friend class AutoHorizontal;
friend class AutoVertical;
public:
static const uint64_t SegNoFlags = 0L;
static const uint64_t SegHorizontal = (1L<< 0);
static const uint64_t SegFixed = (1L<< 1);
static const uint64_t SegFixedAxis = (1L<< 2);
static const uint64_t SegGlobal = (1L<< 3);
static const uint64_t SegWeakGlobal = (1L<< 4);
static const uint64_t SegLongLocal = (1L<< 5);
static const uint64_t SegCanonical = (1L<< 6);
static const uint64_t SegBipoint = (1L<< 7);
static const uint64_t SegDogleg = (1L<< 8);
static const uint64_t SegStrap = (1L<< 9);
static const uint64_t SegSourceTop = (1L<<10);
static const uint64_t SegSourceBottom = (1L<<11);
static const uint64_t SegTargetTop = (1L<<12);
static const uint64_t SegTargetBottom = (1L<<13);
static const uint64_t SegIsReduced = (1L<<14);
static const uint64_t SegDrag = (1L<<15);
static const uint64_t SegLayerChange = (1L<<16);
static const uint64_t SegSourceTerminal = (1L<<17); // Replace Terminal.
static const uint64_t SegTargetTerminal = (1L<<18); // Replace Terminal.
static const uint64_t SegStrongTerminal = SegSourceTerminal|SegTargetTerminal;
static const uint64_t SegWeakTerminal1 = (1L<<19); // Replace TopologicalEnd.
static const uint64_t SegWeakTerminal2 = (1L<<20); // Replace TopologicalEnd.
static const uint64_t SegNotSourceAligned = (1L<<21);
static const uint64_t SegNotTargetAligned = (1L<<22);
static const uint64_t SegUnbound = (1L<<23);
static const uint64_t SegHalfSlackened = (1L<<24);
static const uint64_t SegSlackened = (1L<<25);
static const uint64_t SegAxisSet = (1L<<26);
static const uint64_t SegInvalidated = (1L<<27);
static const uint64_t SegInvalidatedSource = (1L<<28);
static const uint64_t SegInvalidatedTarget = (1L<<29);
static const uint64_t SegInvalidatedLayer = (1L<<30);
static const uint64_t SegCreated = (1L<<31);
static const uint64_t SegUserDefined = (1L<<32);
static const uint64_t SegAnalog = (1L<<33);
static const uint64_t SegWide = (1L<<34);
// Masks.
static const uint64_t SegWeakTerminal = SegStrongTerminal|SegWeakTerminal1|SegWeakTerminal2;
static const uint64_t SegNotAligned = SegNotSourceAligned|SegNotTargetAligned;
static const uint64_t SegSpinTop = SegSourceTop |SegTargetTop;
static const uint64_t SegSpinBottom = SegSourceBottom |SegTargetBottom;
static const uint64_t SegDepthSpin = SegSpinTop |SegSpinBottom;
public:
class Observable : public StaticObservable<1> {
public:
enum Indexes { TrackSegment = 0
};
public:
inline Observable ();
private:
Observable ( const StaticObservable& );
Observable& operator= ( const StaticObservable& );
};
public:
enum ObserverFlag { Create = (1 << 0)
, Destroy = (1 << 1)
, Invalidate = (1 << 2)
, Revalidate = (1 << 3)
, RevalidatePPitch = (1 << 4)
};
public:
typedef std::function< void(AutoSegment*) > RevalidateCb_t;
public:
static void setAnalogMode ( bool );
static bool getAnalogMode ();
inline static DbU::Unit getViaToTopCap ( size_t depth );
inline static DbU::Unit getViaToBottomCap ( size_t depth );
inline static DbU::Unit getViaToSameCap ( size_t depth );
static AutoSegment* create ( AutoContact* source
, AutoContact* target
, Segment* hurricaneSegment
);
static AutoSegment* create ( AutoContact* source
, AutoContact* target
, Flags dir
, size_t depth=RoutingGauge::nlayerdepth
);
void destroy ();
// Wrapped Segment Functions.
virtual Segment* base () const = 0;
virtual Segment* base () = 0;
virtual Horizontal* getHorizontal () { return NULL; };
virtual Vertical* getVertical () { return NULL; };
inline Cell* getCell () const;
inline Net* getNet () const;
inline const Layer* getLayer () const;
inline Box getBoundingBox () const;
inline Hook* getSourceHook ();
inline Hook* getTargetHook ();
inline Contact* getSource () const;
inline Contact* getTarget () const;
inline Component* getOppositeAnchor ( Component* ) const;
inline Components getAnchors () const;
virtual DbU::Unit getX () const;
virtual DbU::Unit getY () const;
inline DbU::Unit getWidth () const;
inline DbU::Unit getContactWidth () const;
inline DbU::Unit getLength () const;
inline DbU::Unit getSourcePosition () const;
inline DbU::Unit getTargetPosition () const;
inline DbU::Unit getSourceX () const;
inline DbU::Unit getSourceY () const;
inline DbU::Unit getTargetX () const;
inline DbU::Unit getTargetY () const;
inline void invert ();
inline void setLayer ( const Layer* );
// Predicates.
inline bool isHorizontal () const;
inline bool isVertical () const;
inline bool isGlobal () const;
inline bool isWeakGlobal () const;
inline bool isLongLocal () const;
inline bool isLocal () const;
inline bool isFixed () const;
inline bool isFixedAxis () const;
inline bool isBipoint () const;
inline bool isWeakTerminal () const;
inline bool isWeakTerminal1 () const;
inline bool isWeakTerminal2 () const;
inline bool isTerminal () const;
inline bool isDrag () const;
inline bool isNotSourceAligned () const;
inline bool isNotTargetAligned () const;
inline bool isNotAligned () const;
bool isStrongTerminal ( Flags flags=Flags::NoFlags ) const;
inline bool isSourceTerminal () const;
inline bool isTargetTerminal () const;
inline bool isLayerChange () const;
inline bool isSpinTop () const;
inline bool isSpinBottom () const;
inline bool isSpinTopOrBottom () const;
inline bool isReduced () const;
inline bool isStrap () const;
inline bool isDogleg () const;
inline bool isUnbound () const;
inline bool isInvalidated () const;
inline bool isInvalidatedLayer () const;
inline bool isCreated () const;
inline bool isCanonical () const;
inline bool isUnsetAxis () const;
inline bool isSlackened () const;
inline bool isUserDefined () const;
bool isReduceCandidate () const;
bool isUTurn () const;
inline bool isAnalog () const;
inline bool isWide () const;
virtual bool _canSlacken () const = 0;
bool canReduce () const;
bool mustRaise () const;
Flags canDogleg ( Interval );
virtual bool canMoveULeft ( float reserve=0.0 ) const = 0;
virtual bool canMoveURight ( float reserve=0.0 ) const = 0;
bool canMoveUp ( float reserve=0.0, Flags flags=Flags::NoFlags ) const;
bool canPivotUp ( float reserve=0.0, Flags flags=Flags::NoFlags ) const;
bool canPivotDown ( float reserve=0.0, Flags flags=Flags::NoFlags ) const;
bool canSlacken ( Flags flags=Flags::NoFlags ) const;
virtual bool checkPositions () const = 0;
virtual bool checkConstraints () const = 0;
bool checkDepthSpin () const;
// Accessors.
inline unsigned long getId () const;
inline uint64_t getFlags () const;
virtual Flags getDirection () const = 0;
inline GCell* getGCell () const;
virtual bool getGCells ( vector<GCell*>& ) const = 0;
inline AutoContact* getAutoSource () const;
inline AutoContact* getAutoTarget () const;
AutoContact* getOppositeAnchor ( AutoContact* ) const;
size_t getPerpandicularsBound ( set<AutoSegment*>& );
inline AutoSegment* getParent () const;
inline unsigned int getDepth () const;
inline DbU::Unit getPitch () const;
DbU::Unit getPPitch () const;
#if DISABLED
DbU::Unit getExtensionCap () const;
#endif
DbU::Unit getExtensionCap ( Flags ) const;
inline DbU::Unit getAxis () const;
void getEndAxes ( DbU::Unit& sourceAxis, DbU::Unit& targetAxis ) const;
virtual DbU::Unit getSourceU () const = 0;
virtual DbU::Unit getTargetU () const = 0;
virtual DbU::Unit getDuSource () const = 0;
virtual DbU::Unit getDuTarget () const = 0;
inline DbU::Unit getOrigin () const;
inline DbU::Unit getExtremity () const;
virtual Interval getSpanU () const = 0;
Interval getMinSpanU () const;
virtual Interval getSourceConstraints ( Flags flags=Flags::NoFlags ) const = 0;
virtual Interval getTargetConstraints ( Flags flags=Flags::NoFlags ) const = 0;
virtual bool getConstraints ( DbU::Unit& min, DbU::Unit& max ) const = 0;
inline bool getConstraints ( Interval& i ) const;
inline const Interval& getUserConstraints () const;
inline const Interval& getNativeConstraints () const;
virtual DbU::Unit getSlack () const;
inline DbU::Unit getOptimalMin () const;
inline DbU::Unit getOptimalMax () const;
inline DbU::Unit getNativeMin () const;
inline DbU::Unit getNativeMax () const;
Interval& getOptimal ( Interval& i ) const;
virtual DbU::Unit getCost ( DbU::Unit axis ) const;
virtual AutoSegment* getCanonical ( DbU::Unit& min , DbU::Unit& max );
inline AutoSegment* getCanonical ( Interval& i );
float getMaxUnderDensity ( Flags flags );
// Modifiers.
inline void unsetFlags ( uint64_t );
inline void setFlags ( uint64_t );
void setFlagsOnAligneds ( uint64_t );
inline void incReduceds ();
inline void decReduceds ();
virtual void setDuSource ( DbU::Unit du ) = 0;
virtual void setDuTarget ( DbU::Unit du ) = 0;
void computeTerminal ();
virtual void updateOrient () = 0;
virtual void updatePositions () = 0;
virtual void updateNativeConstraints () = 0;
void updateSourceSpin ();
void updateTargetSpin ();
void sourceDetach ();
void targetDetach ();
void sourceAttach ( AutoContact* );
void targetAttach ( AutoContact* );
//inline void mergeUserConstraints ( const Interval& );
void mergeUserConstraints ( const Interval& );
inline void resetUserConstraints ();
inline void setOptimalMin ( DbU::Unit min );
inline void setOptimalMax ( DbU::Unit max );
inline void mergeNativeMin ( DbU::Unit min );
inline void mergeNativeMax ( DbU::Unit max );
inline void resetNativeConstraints ( DbU::Unit min, DbU::Unit max );
bool checkNotInvalidated () const;
inline void setParent ( AutoSegment* );
void revalidate ();
AutoSegment* makeDogleg ( AutoContact* );
Flags makeDogleg ( Interval, Flags flags=Flags::NoFlags );
Flags makeDogleg ( GCell* , Flags flags=Flags::NoFlags );
virtual Flags _makeDogleg ( GCell* , Flags flags ) = 0;
virtual bool moveULeft () = 0;
virtual bool moveURight () = 0;
bool slacken ( Flags flags );
virtual bool _slacken ( Flags flags ) = 0;
void _changeDepth ( unsigned int depth, Flags flags );
void changeDepth ( unsigned int depth, Flags flags );
bool moveUp ( Flags flags=Flags::NoFlags );
bool moveDown ( Flags flags=Flags::NoFlags );
bool reduceDoglegLayer ();
bool reduce ();
bool raise ();
// Canonical Modifiers.
AutoSegment* canonize ( Flags flags=Flags::NoFlags );
virtual void invalidate ( Flags flags=Flags::Propagate );
void invalidate ( AutoContact* );
void computeOptimal ( set<AutoSegment*>& processeds );
void setAxis ( DbU::Unit, Flags flags=Flags::NoFlags );
bool toConstraintAxis ( Flags flags=Flags::Realignate );
bool toOptimalAxis ( Flags flags=Flags::Realignate );
// Collections & Filters.
AutoSegments getOnSourceContact ( Flags direction );
AutoSegments getOnTargetContact ( Flags direction );
AutoSegments getCachedOnSourceContact ( Flags direction );
AutoSegments getCachedOnTargetContact ( Flags direction );
AutoSegments getAligneds ( Flags flags=Flags::NoFlags );
AutoSegments getConnecteds ( Flags flags=Flags::NoFlags );
AutoSegments getPerpandiculars ( Flags flags=Flags::NoFlags );
size_t getAlignedContacts ( map<AutoContact*,int>& ) const ;
// Observers.
template< typename OwnerT >
inline OwnerT* getObserver ( size_t slot );
inline void setObserver ( size_t slot, BaseObserver* );
inline void notify ( unsigned int flags );
// Inspector Management.
virtual Record* _getRecord () const = 0;
virtual string _getString () const = 0;
virtual string _getTypeName () const = 0;
// Non-reviewed atomic modifiers.
bool _check () const;
#if THIS_IS_DISABLED
virtual void desalignate ( AutoContact* ) = 0;
bool shearUp ( GCell*
, AutoSegment*& movedUp
, float reserve
, Flags flags );
#endif
protected:
// Internal: Static Attributes.
static size_t _allocateds;
static size_t _globalsCount;
static bool _analogMode;
static bool _initialized;
static vector< array<DbU::Unit*,3> > _extensionCaps;
// Internal: Attributes.
const unsigned long _id;
GCell* _gcell;
uint64_t _flags;
unsigned int _depth : 8;
unsigned int _optimalMin :16;
unsigned int _optimalMax :16;
unsigned int _reduceds : 2;
DbU::Unit _sourcePosition;
DbU::Unit _targetPosition;
Interval _userConstraints;
Interval _nativeConstraints;
AutoSegment* _parent;
Observable _observers;
// Internal: Constructors & Destructors.
protected:
AutoSegment ( Segment* segment );
virtual ~AutoSegment ();
static void _preCreate ( AutoContact* source, AutoContact* target );
virtual void _postCreate ();
virtual void _preDestroy ();
static void _initialize ();
private:
AutoSegment ( const AutoSegment& );
AutoSegment& operator= ( const AutoSegment& );
protected:
void _invalidate ();
inline uint64_t _getFlags () const;
std::string _getStringFlags () const;
virtual void _setAxis ( DbU::Unit ) = 0;
public:
struct CompareId : public binary_function<AutoSegment*,AutoSegment*,bool> {
inline bool operator() ( const AutoSegment* lhs, const AutoSegment* rhs ) const;
};
public:
struct CompareByDepthLength : public binary_function<AutoSegment*,AutoSegment*,bool> {
bool operator() ( AutoSegment* lhs, AutoSegment* rhs ) const;
};
public:
struct CompareByDepthAxis : public binary_function<AutoSegment*,AutoSegment*,bool> {
bool operator() ( AutoSegment* lhs, AutoSegment* rhs ) const;
};
public:
typedef std::set<AutoSegment*,CompareByDepthLength> DepthLengthSet;
typedef std::set<AutoSegment*,CompareId> IdSet;
// Static Utilities.
public:
static inline uint64_t swapSourceTargetFlags ( AutoSegment* );
static inline bool areAlignedsAndDiffLayer ( AutoSegment*, AutoSegment* );
static AutoSegment* getGlobalThroughDogleg ( AutoSegment* dogleg, AutoContact* from );
static bool isTopologicalBound ( AutoSegment* seed, Flags flags );
static inline bool arePerpandiculars ( AutoSegment* a, AutoSegment* b );
static inline bool arePerpandiculars ( bool isHorizontalA, AutoSegment* b );
static inline bool areAligneds ( AutoSegment* a, AutoSegment* b );
static Flags getPerpandicularState ( AutoContact* contact
, AutoSegment* source
, AutoSegment* current
, bool isHorizontalMaster
, const Layer* masterLayer=NULL
);
static inline Flags getPerpandicularState ( AutoContact* contact
, AutoSegment* source
, AutoSegment* current
, AutoSegment* master
);
static void getTopologicalInfos ( AutoSegment* seed
, vector<AutoSegment*>& collapseds
, vector<AutoSegment*>& perpandiculars
, DbU::Unit& leftBound
, DbU::Unit& rightBound
);
static int getTerminalCount ( AutoSegment* seed
, vector<AutoSegment*>& collapseds
);
static inline int getTerminalCount ( AutoSegment* seed );
static inline size_t getGlobalsCount ();
static inline size_t getAllocateds ();
static inline unsigned long getMaxId ();
};
// Inline Functions.
inline DbU::Unit AutoSegment::getViaToTopCap ( size_t depth ) { return (depth < _extensionCaps.size()) ? *(_extensionCaps[depth][0]) : 0; }
inline DbU::Unit AutoSegment::getViaToBottomCap ( size_t depth ) { return (depth < _extensionCaps.size()) ? *(_extensionCaps[depth][1]) : 0; }
inline DbU::Unit AutoSegment::getViaToSameCap ( size_t depth ) { return (depth < _extensionCaps.size()) ? *(_extensionCaps[depth][2]) : 0; }
inline unsigned long AutoSegment::getId () const { return _id; }
inline Cell* AutoSegment::getCell () const { return base()->getCell(); }
inline Net* AutoSegment::getNet () const { return base()->getNet(); }
inline const Layer* AutoSegment::getLayer () const { return base()->getLayer(); }
inline Box AutoSegment::getBoundingBox () const { return base()->getBoundingBox(); }
inline Hook* AutoSegment::getSourceHook () { return base()->getSourceHook(); }
inline Hook* AutoSegment::getTargetHook () { return base()->getTargetHook(); }
inline Contact* AutoSegment::getSource () const { return static_cast<Contact*>(base()->getSource()); }
inline Contact* AutoSegment::getTarget () const { return static_cast<Contact*>(base()->getTarget()); }
inline Component* AutoSegment::getOppositeAnchor ( Component* anchor ) const { return base()->getOppositeAnchor(anchor); };
inline AutoSegment* AutoSegment::getParent () const { return _parent; }
inline DbU::Unit AutoSegment::getSourcePosition () const { return _sourcePosition; }
inline DbU::Unit AutoSegment::getTargetPosition () const { return _targetPosition; }
inline DbU::Unit AutoSegment::getSourceX () const { return base()->getSourceX(); }
inline DbU::Unit AutoSegment::getSourceY () const { return base()->getSourceY(); }
inline DbU::Unit AutoSegment::getTargetX () const { return base()->getTargetX(); }
inline DbU::Unit AutoSegment::getTargetY () const { return base()->getTargetY(); }
inline DbU::Unit AutoSegment::getWidth () const { return base()->getWidth(); }
inline DbU::Unit AutoSegment::getLength () const { return base()->getLength(); }
inline void AutoSegment::invert () { base()->invert(); }
inline GCell* AutoSegment::getGCell () const { return _gcell; }
inline AutoContact* AutoSegment::getAutoSource () const { return Session::lookup(getSource()); }
inline AutoContact* AutoSegment::getAutoTarget () const { return Session::lookup(getTarget()); }
inline bool AutoSegment::getConstraints ( Interval& i ) const { return getConstraints(i.getVMin(),i.getVMax()); }
inline AutoSegment* AutoSegment::getCanonical ( Interval& i ) { return getCanonical(i.getVMin(),i.getVMax()); }
inline unsigned int AutoSegment::getDepth () const { return _depth; }
inline DbU::Unit AutoSegment::getPitch () const { return Session::getPitch(getDepth(),Flags::NoFlags); }
inline DbU::Unit AutoSegment::getAxis () const { return isHorizontal()?base()->getY():base()->getX(); }
inline DbU::Unit AutoSegment::getOrigin () const { return isHorizontal()?_gcell->getYMin():_gcell->getXMin(); }
inline DbU::Unit AutoSegment::getExtremity () const { return isHorizontal()?_gcell->getYMax():_gcell->getXMax(); }
inline DbU::Unit AutoSegment::getOptimalMin () const { return DbU::lambda(_optimalMin) + getOrigin(); }
inline DbU::Unit AutoSegment::getOptimalMax () const { return DbU::lambda(_optimalMax) + getOrigin(); }
inline DbU::Unit AutoSegment::getNativeMin () const { return _nativeConstraints.getVMin(); }
inline DbU::Unit AutoSegment::getNativeMax () const { return _nativeConstraints.getVMax(); }
inline const Interval& AutoSegment::getUserConstraints () const { return _userConstraints; }
inline const Interval& AutoSegment::getNativeConstraints () const { return _nativeConstraints; }
inline bool AutoSegment::isHorizontal () const { return _flags & SegHorizontal; }
inline bool AutoSegment::isVertical () const { return not (_flags & SegHorizontal); }
inline bool AutoSegment::isFixed () const { return _flags & SegFixed; }
inline bool AutoSegment::isFixedAxis () const { return _flags & SegFixedAxis; }
inline bool AutoSegment::isGlobal () const { return _flags & SegGlobal; }
inline bool AutoSegment::isWeakGlobal () const { return _flags & SegWeakGlobal; }
inline bool AutoSegment::isLongLocal () const { return _flags & SegLongLocal; }
inline bool AutoSegment::isLocal () const { return not (_flags & SegGlobal); }
inline bool AutoSegment::isBipoint () const { return _flags & SegBipoint; }
inline bool AutoSegment::isWeakTerminal () const { return _flags & SegWeakTerminal; }
inline bool AutoSegment::isWeakTerminal1 () const { return _flags & SegWeakTerminal1; }
inline bool AutoSegment::isWeakTerminal2 () const { return _flags & SegWeakTerminal2; }
inline bool AutoSegment::isSourceTerminal () const { return _flags & SegSourceTerminal; }
inline bool AutoSegment::isTargetTerminal () const { return _flags & SegTargetTerminal; }
inline bool AutoSegment::isTerminal () const { return _flags & SegStrongTerminal; }
inline bool AutoSegment::isDrag () const { return _flags & SegDrag; }
inline bool AutoSegment::isNotSourceAligned () const { return _flags & SegNotSourceAligned; }
inline bool AutoSegment::isNotTargetAligned () const { return _flags & SegNotTargetAligned; }
inline bool AutoSegment::isNotAligned () const { return (_flags & SegNotAligned) == SegNotAligned; }
inline bool AutoSegment::isDogleg () const { return _flags & SegDogleg ; }
inline bool AutoSegment::isUnbound () const { return _flags & SegUnbound ; }
inline bool AutoSegment::isStrap () const { return _flags & SegStrap; }
inline bool AutoSegment::isLayerChange () const { return _flags & SegLayerChange; }
inline bool AutoSegment::isSpinTop () const { return ((_flags & SegSpinTop ) == SegSpinTop); }
inline bool AutoSegment::isSpinBottom () const { return ((_flags & SegSpinBottom) == SegSpinBottom); }
inline bool AutoSegment::isSpinTopOrBottom () const { return isSpinTop() or isSpinBottom(); }
inline bool AutoSegment::isReduced () const { return _flags & SegIsReduced; }
inline bool AutoSegment::isSlackened () const { return _flags & SegSlackened; }
inline bool AutoSegment::isCanonical () const { return _flags & SegCanonical; }
inline bool AutoSegment::isUnsetAxis () const { return not (_flags & SegAxisSet); }
inline bool AutoSegment::isInvalidated () const { return _flags & SegInvalidated; }
inline bool AutoSegment::isInvalidatedLayer () const { return _flags & SegInvalidatedLayer; }
inline bool AutoSegment::isCreated () const { return _flags & SegCreated; }
inline bool AutoSegment::isUserDefined () const { return _flags & SegUserDefined; }
inline bool AutoSegment::isAnalog () const { return _flags & SegAnalog; }
inline bool AutoSegment::isWide () const { return _flags & SegWide; }
inline void AutoSegment::setFlags ( uint64_t flags ) { _flags |= flags; }
inline void AutoSegment::unsetFlags ( uint64_t flags ) { _flags &= ~flags; }
inline uint64_t AutoSegment::getFlags () const { return _flags; }
inline uint64_t AutoSegment::_getFlags () const { return _flags; }
inline void AutoSegment::incReduceds () { if (_reduceds<3) ++_reduceds; }
inline void AutoSegment::decReduceds () { if (_reduceds>0) --_reduceds; }
inline void AutoSegment::setLayer ( const Layer* layer ) { base()->setLayer(layer); _depth=Session::getLayerDepth(layer); _flags|=SegInvalidatedLayer; }
inline void AutoSegment::setOptimalMin ( DbU::Unit min ) { _optimalMin = (unsigned int)DbU::getLambda(min-getOrigin()); }
inline void AutoSegment::setOptimalMax ( DbU::Unit max ) { _optimalMax = (unsigned int)DbU::getLambda(max-getOrigin()); }
inline void AutoSegment::mergeNativeMin ( DbU::Unit min ) { _nativeConstraints.getVMin() = std::max( min, _nativeConstraints.getVMin() ); }
inline void AutoSegment::mergeNativeMax ( DbU::Unit max ) { _nativeConstraints.getVMax() = std::min( max, _nativeConstraints.getVMax() ); }
inline void AutoSegment::resetNativeConstraints ( DbU::Unit min, DbU::Unit max ) { _nativeConstraints = Interval( min, max ); }
//inline void AutoSegment::mergeUserConstraints ( const Interval& constraints ) { _userConstraints.intersection(constraints); }
inline void AutoSegment::resetUserConstraints () { _userConstraints = Interval(false); }
inline DbU::Unit AutoSegment::getContactWidth () const
{ return getWidth() + Session::getViaWidth(getLayer()) - Session::getWireWidth(getLayer()); }
inline void AutoSegment::setParent ( AutoSegment* parent )
{
if ( parent == this ) {
cerr << "Parentage Looping: " << parent->_getString() << endl;
}
_parent = parent;
}
inline bool AutoSegment::CompareId::operator() ( const AutoSegment* lhs, const AutoSegment* rhs ) const
{ return lhs->getId() < rhs->getId(); }
inline uint64_t AutoSegment::swapSourceTargetFlags ( AutoSegment* segment )
{
uint64_t segFlags = segment->getFlags();
uint64_t swapFlags = segment->getFlags() & ~(SegSourceTop |SegTargetTop
|SegSourceBottom |SegTargetBottom
|SegSourceTerminal |SegTargetTerminal
|SegNotSourceAligned |SegNotTargetAligned
|SegInvalidatedSource|SegInvalidatedTarget
);
swapFlags |= (segFlags & SegSourceTop ) ? SegTargetTop : SegNoFlags;
swapFlags |= (segFlags & SegSourceBottom ) ? SegTargetBottom : SegNoFlags;
swapFlags |= (segFlags & SegSourceTerminal ) ? SegTargetTerminal : SegNoFlags;
swapFlags |= (segFlags & SegNotSourceAligned ) ? SegNotTargetAligned : SegNoFlags;
swapFlags |= (segFlags & SegInvalidatedSource) ? SegInvalidatedTarget : SegNoFlags;
swapFlags |= (segFlags & SegTargetTop ) ? SegSourceTop : SegNoFlags;
swapFlags |= (segFlags & SegTargetBottom ) ? SegSourceBottom : SegNoFlags;
swapFlags |= (segFlags & SegTargetTerminal ) ? SegSourceTerminal : SegNoFlags;
swapFlags |= (segFlags & SegNotTargetAligned ) ? SegNotSourceAligned : SegNoFlags;
swapFlags |= (segFlags & SegInvalidatedTarget) ? SegInvalidatedSource : SegNoFlags;
return swapFlags;
}
inline bool AutoSegment::areAlignedsAndDiffLayer ( AutoSegment* s1, AutoSegment* s2 )
{ return s1 and s2
and (s1->isHorizontal() == s2->isHorizontal())
and (s1->getLayer() != s2->getLayer()); }
inline bool AutoSegment::arePerpandiculars ( AutoSegment* a, AutoSegment* b )
{ return a and b and (a->isHorizontal() != b->isHorizontal()); }
inline bool AutoSegment::arePerpandiculars ( bool isHorizontalA, AutoSegment* b )
{ return b and (isHorizontalA != b->isHorizontal()); }
inline bool AutoSegment::areAligneds ( AutoSegment* a, AutoSegment* b )
{ return a and b and (a->isHorizontal() == b->isHorizontal()); }
inline Flags AutoSegment::getPerpandicularState ( AutoContact* contact
, AutoSegment* source
, AutoSegment* current
, AutoSegment* master )
{
return getPerpandicularState ( contact, source, current, master->isHorizontal(), master->getLayer() );
}
inline int AutoSegment::getTerminalCount ( AutoSegment* seed )
{
cdebug_log(145,0) << "getTerminalCount() - " << seed << endl;
vector<AutoSegment*> collapseds;
vector<AutoSegment*> perpandiculars;
DbU::Unit leftBound;
DbU::Unit rightBound;
getTopologicalInfos ( seed
, collapseds
, perpandiculars
, leftBound
, rightBound
);
return getTerminalCount ( seed, collapseds );
}
inline size_t AutoSegment::getGlobalsCount () { return _globalsCount; }
inline size_t AutoSegment::getAllocateds () { return _allocateds; }
inline void AutoSegment::setObserver ( size_t slot, BaseObserver* observer )
{ _observers.setObserver( slot, observer ); }
template<typename OwnerT>
inline OwnerT* AutoSegment::getObserver ( size_t slot )
{ return _observers.getObserver<OwnerT>(slot); }
inline void AutoSegment::notify ( unsigned int flags )
{ _observers.notify( flags ); }
inline AutoSegment::Observable::Observable () : StaticObservable<1>() { }
} // End of Anabatic namespace.
INSPECTOR_P_SUPPORT(Anabatic::AutoSegment);
# endif // ANABATIC_AUTOSEGMENT_H

View File

@ -45,7 +45,6 @@ namespace Anabatic {
using Hurricane::NetRoutingState;
using CRL::ToolEngine;
class NetBuilder;
class AnabaticEngine;
@ -195,6 +194,7 @@ namespace Anabatic {
static const uint32_t DigitalMode = (1 << 0);
static const uint32_t AnalogMode = (1 << 1);
static const uint32_t MixedMode = (1 << 2);
static const uint32_t ChannelMode = (1 << 3);
static const uint32_t AverageHVDensity = 1; // Average between all densities.
static const uint32_t AverageHDensity = 2; // Average between all H densities.
static const uint32_t AverageVDensity = 3; // Average between all V densities.
@ -211,14 +211,11 @@ namespace Anabatic {
inline bool isDigitalMode () const;
inline bool isAnalogMode () const;
inline bool isMixedMode () const;
inline bool isChannelStyle () const;
inline bool isHybridStyle () const;
inline bool isChannelMode () const;
static const Name& staticGetName ();
virtual const Name& getName () const;
virtual Configuration* getConfiguration ();
virtual const Configuration* getConfiguration () const;
inline std::string getNetBuilderStyle () const;
inline StyleFlags getRoutingStyle () const;
inline uint64_t getDensityMode () const;
inline CellViewer* getViewer () const;
inline void setViewer ( CellViewer* );
@ -279,7 +276,6 @@ namespace Anabatic {
void invalidateRoutingPads ();
void updateDensity ();
size_t checkGCellDensities ();
void setupNetBuilder ();
inline void setRoutingMode ( uint32_t );
inline void resetRoutingMode ( uint32_t );
inline void setGlobalThreshold ( DbU::Unit );
@ -347,15 +343,12 @@ namespace Anabatic {
virtual void _postCreate ();
virtual void _preDestroy ();
void _gutAnabatic ();
virtual Configuration* _createConfiguration ();
private:
AnabaticEngine ( const AnabaticEngine& );
AnabaticEngine& operator= ( const AnabaticEngine& );
private:
static Name _toolName;
protected:
Configuration* _configuration;
private:
ChipTools _chipTools;
EngineState _state;
Matrix _matrix;
@ -379,8 +372,7 @@ namespace Anabatic {
inline bool AnabaticEngine::isDigitalMode () const { return (_routingMode & DigitalMode); };
inline bool AnabaticEngine::isAnalogMode () const { return (_routingMode & AnalogMode); };
inline bool AnabaticEngine::isMixedMode () const { return (_routingMode & MixedMode); };
inline bool AnabaticEngine::isChannelStyle () const { return (_configuration->getRoutingStyle() & StyleFlags::Channel); };
inline bool AnabaticEngine::isHybridStyle () const { return (_configuration->getRoutingStyle() & StyleFlags::Hybrid); };
inline bool AnabaticEngine::isChannelMode () const { return (_routingMode & ChannelMode); };
inline void AnabaticEngine::setRoutingMode ( uint32_t mode ) { _routingMode |= mode; };
inline void AnabaticEngine::resetRoutingMode ( uint32_t mode ) { _routingMode &= ~mode; };
inline EngineState AnabaticEngine::getState () const { return _state; }
@ -410,10 +402,8 @@ namespace Anabatic {
inline bool AnabaticEngine::isCanonizeDisabled () const { return _flags & Flags::DisableCanonize; }
inline bool AnabaticEngine::isInDemoMode () const { return _flags & Flags::DemoMode; }
inline bool AnabaticEngine::isChip () const { return _chipTools.isChip(); }
inline std::string AnabaticEngine::getNetBuilderStyle () const { return _configuration->getNetBuilderStyle(); }
inline StyleFlags AnabaticEngine::getRoutingStyle () const { return _configuration->getRoutingStyle(); }
inline DbU::Unit AnabaticEngine::getAntennaGateMaxWL () const { return _configuration->getAntennaGateMaxWL(); }
inline DbU::Unit AnabaticEngine::getAntennaDiodeMaxWL () const { return _configuration->getAntennaDiodeMaxWL(); }
inline DbU::Unit AnabaticEngine::getAntennaGateMaxWL () const { return getConfiguration()->getAntennaGateMaxWL(); }
inline DbU::Unit AnabaticEngine::getAntennaDiodeMaxWL () const { return getConfiguration()->getAntennaDiodeMaxWL(); }
inline DbU::Unit AnabaticEngine::getGlobalThreshold () const { return _configuration->getGlobalThreshold(); }
inline float AnabaticEngine::getSaturateRatio () const { return _configuration->getSaturateRatio(); }
inline size_t AnabaticEngine::getSaturateRp () const { return _configuration->getSaturateRp(); }

View File

@ -109,7 +109,6 @@ namespace Anabatic {
static const uint64_t SegNonPref = (1L<<37);
static const uint64_t SegAtMinArea = (1L<<38);
static const uint64_t SegNoMoveUp = (1L<<39);
static const uint64_t SegOnVSmall = (1L<<40);
// Masks.
static const uint64_t SegWeakTerminal = SegStrongTerminal|SegWeakTerminal1|SegWeakTerminal2;
static const uint64_t SegNotAligned = SegNotSourceAligned|SegNotTargetAligned;
@ -203,7 +202,6 @@ namespace Anabatic {
inline bool isTerminal () const;
inline bool isUnbreakable () const;
inline bool isNonPref () const;
inline bool isNonPrefOnVSmall () const;
inline bool isDrag () const;
inline bool isAtMinArea () const;
inline bool isNotSourceAligned () const;
@ -538,7 +536,6 @@ namespace Anabatic {
inline bool AutoSegment::isLocal () const { return not (_flags & SegGlobal); }
inline bool AutoSegment::isUnbreakable () const { return _flags & SegUnbreakable; }
inline bool AutoSegment::isNonPref () const { return _flags & SegNonPref; }
inline bool AutoSegment::isNonPrefOnVSmall () const { return (_flags & SegNonPref) and (_flags & SegOnVSmall); }
inline bool AutoSegment::isBipoint () const { return _flags & SegBipoint; }
inline bool AutoSegment::isWeakTerminal () const { return (_rpDistance < 2); }
inline bool AutoSegment::isWeakTerminal1 () const { return (_rpDistance == 1); }

View File

@ -1,7 +1,7 @@
// -*- mode: C++; explicit-buffer-name: "Configuration.h<anabatic>" -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) Sorbonne Université 2016-2022, All Rights Reserved
// Copyright (c) UPMC 2016-2018, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
@ -66,11 +66,8 @@ namespace Anabatic {
bool isGMetal ( const Layer* ) const;
bool isGContact ( const Layer* ) const;
bool isTwoMetals () const;
bool isHybrid () const;
bool isHV () const;
bool isVH () const;
inline std::string getNetBuilderStyle () const;
inline StyleFlags getRoutingStyle () const;
const Layer* getGContactLayer () const;
const Layer* getGHorizontalLayer () const;
const Layer* getGVerticalLayer () const;
@ -135,8 +132,6 @@ namespace Anabatic {
int getGlobalIterations () const;
DbU::Unit isOnRoutingGrid ( RoutingPad* ) const;
bool selectRpComponent ( RoutingPad* ) const;
inline void setRoutingStyle ( StyleFlags );
inline void resetRoutingStyle ( StyleFlags );
virtual void print ( Cell* ) const;
virtual Record* _getRecord () const;
virtual string _getString () const;
@ -151,8 +146,6 @@ namespace Anabatic {
size_t _ddepthv;
size_t _ddepthh;
size_t _ddepthc;
std::string _netBuilderStyle;
StyleFlags _routingStyle;
CellGauge* _cg;
RoutingGauge* _rg;
std::vector<DbU::Unit> _extensionCaps;
@ -176,8 +169,6 @@ namespace Anabatic {
};
inline std::string Configuration::getNetBuilderStyle () const { return _netBuilderStyle; }
inline StyleFlags Configuration::getRoutingStyle () const { return _routingStyle; }
inline bool Configuration::isGLayer ( const Layer* layer ) const { return isGMetal(layer) or isGContact(layer); }
inline size_t Configuration::getGHorizontalDepth () const { return _gdepthh; }
inline size_t Configuration::getGVerticalDepth () const { return _gdepthv; }
@ -202,8 +193,6 @@ namespace Anabatic {
inline std::string Configuration::getDiodeName () const { return _diodeName; }
inline DbU::Unit Configuration::getAntennaGateMaxWL () const { return _antennaGateMaxWL; }
inline DbU::Unit Configuration::getAntennaDiodeMaxWL () const { return _antennaDiodeMaxWL; }
inline void Configuration::setRoutingStyle ( StyleFlags flags ) { _routingStyle = flags; }
inline void Configuration::resetRoutingStyle ( StyleFlags flags ) { _routingStyle &= ~flags; }
} // Anabatic namespace.

View File

@ -20,9 +20,6 @@
namespace Anabatic {
// -------------------------------------------------------------------
// Class : "Anabatic::Flags".
class Flags : public Hurricane::BaseFlags {
public:
static const BaseFlags NoFlags ; // = 0;
@ -110,7 +107,6 @@ namespace Anabatic {
static const BaseFlags NoMinLength ;
static const BaseFlags NoSegExt ;
static const BaseFlags NullLength ;
static const BaseFlags OnVSmall ;
public:
inline Flags ( uint64_t flags = NoFlags );
inline Flags ( const Hurricane::BaseFlags& );
@ -125,39 +121,6 @@ namespace Anabatic {
Flags::Flags ( const Hurricane::BaseFlags& flags ) : BaseFlags(flags) { }
// -------------------------------------------------------------------
// Class : "Anabatic::StyleFlags".
class StyleFlags : public Hurricane::BaseFlags {
public:
static const BaseFlags NoStyle; // = 0;
static const BaseFlags HV ; // = (1 << 0);
static const BaseFlags VH ; // = (1 << 1);
static const BaseFlags OTH ; // = (1 << 2);
static const BaseFlags Channel; // = (1 << 3);
static const BaseFlags Hybrid ; // = (1 << 4);
public:
inline StyleFlags ( std::string );
inline StyleFlags ( uint64_t flags = NoStyle );
inline StyleFlags ( const Hurricane::BaseFlags& );
virtual ~StyleFlags ();
static StyleFlags toFlag ( std::string );
StyleFlags from ( std::string );
virtual std::string asString () const;
virtual std::string _getTypeName () const;
virtual std::string _getString () const;
};
StyleFlags::StyleFlags ( std::string textFlags ) : BaseFlags(NoStyle) { from(textFlags); }
StyleFlags::StyleFlags ( uint64_t flags ) : BaseFlags(flags) { }
StyleFlags::StyleFlags ( const Hurricane::BaseFlags& flags ) : BaseFlags(flags) { }
// -------------------------------------------------------------------
// Misc. enums.
enum FlagsMode { FlagsFunction = 1
};

View File

@ -112,13 +112,13 @@ namespace Anabatic {
, SouthWest = SouthBound|WestBound
, NorthEast = NorthBound|EastBound
};
enum TopologyFlag { Global_Vertical_End = (1 << 0)
, Global_Horizontal_End = (1 << 1)
, Global_Horizontal = (1 << 2)
, Global_Vertical = (1 << 3)
, Global_Turn = (1 << 4)
, Global_Fork = (1 << 5)
, Global_Fixed = (1 << 6)
enum TopologyFlag { Global_Vertical_End = 0x00000001
, Global_Horizontal_End = 0x00000002
, Global_Horizontal = 0x00000004
, Global_Vertical = 0x00000008
, Global_Turn = 0x00000010
, Global_Fork = 0x00000020
, Global_Fixed = 0x00000040
, Global_End = Global_Vertical_End | Global_Horizontal_End
, Global_Split = Global_Horizontal | Global_Vertical | Global_Fork
};
@ -157,7 +157,7 @@ namespace Anabatic {
NetBuilder ();
virtual ~NetBuilder ();
void clear ();
inline bool isStrictChannel () const;
inline bool isTwoMetals () const;
inline bool isUpperMetalRp () const;
inline AnabaticEngine* getAnabatic () const;
inline unsigned int getDegree () const;
@ -236,7 +236,6 @@ namespace Anabatic {
virtual bool _do_xG_xM2 ();
virtual bool _do_1G_1M3 ();
virtual bool _do_xG_xM3 ();
virtual bool _do_1G_xM1_1PinM1 ();
virtual bool _do_1G_xM1_1PinM2 ();
virtual bool _do_2G_xM1_1PinM2 ();
virtual bool _do_1G_1M1_1PinM3 ();
@ -345,8 +344,6 @@ namespace Anabatic {
, Conn_1G_1PinM2 = CONNEXITY_VALUE( 1, 0, 1, 0, 0 , 1 )
, Conn_2G_1PinM2 = CONNEXITY_VALUE( 2, 0, 1, 0, 0 , 1 )
, Conn_3G_1PinM2 = CONNEXITY_VALUE( 3, 0, 1, 0, 0 , 1 )
, Conn_1G_1M1_1PinM1 = CONNEXITY_VALUE( 1, 1, 0, 0, 0 , 1 )
, Conn_1G_2M1_1PinM1 = CONNEXITY_VALUE( 1, 2, 0, 0, 0 , 1 )
, Conn_1G_1M1_1PinM2 = CONNEXITY_VALUE( 1, 1, 1, 0, 0 , 1 )
, Conn_1G_2M1_1PinM2 = CONNEXITY_VALUE( 1, 2, 1, 0, 0 , 1 )
, Conn_1G_3M1_1PinM2 = CONNEXITY_VALUE( 1, 3, 1, 0, 0 , 1 )
@ -389,13 +386,13 @@ namespace Anabatic {
map<Component*,AutoSegment*> _routingPadAutoSegments;
vector<AutoSegment*> _toFixSegments;
unsigned int _degree;
bool _isStrictChannel;
bool _isTwoMetals;
uint64_t _sourceFlags;
uint64_t _flags;
};
inline bool NetBuilder::isStrictChannel () const { return _isStrictChannel; }
inline bool NetBuilder::isTwoMetals () const { return _isTwoMetals; }
inline AnabaticEngine* NetBuilder::getAnabatic () const { return _anabatic; }
inline unsigned int NetBuilder::getDegree () const { return _degree; }
inline NetBuilder::UConnexity NetBuilder::getConnexity () const { return _connexity; }

View File

@ -1,7 +1,7 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) Sorbonne Université 2008-2022, All Rights Reserved
// Copyright (c) UPMC 2008-2018, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
@ -28,10 +28,9 @@ namespace Anabatic {
public:
NetBuilderHV ();
virtual ~NetBuilderHV ();
static std::string getStyle ();
virtual void doRp_AutoContacts ( GCell*, Component*, AutoContact*& source, AutoContact*& target, uint64_t flags );
virtual AutoContact* doRp_Access ( GCell*, Component*, uint64_t flags );
AutoContact* doRp_AccessNorthSouthPin ( GCell*, RoutingPad* );
AutoContact* doRp_AccessNorthPin ( GCell*, RoutingPad* );
AutoContact* doRp_AccessEastWestPin ( GCell*, RoutingPad* );
private:
virtual bool _do_1G_1M1 ();

View File

@ -1,68 +0,0 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) Sorbonne Université 2022-2022, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | A n a b a t i c - Routing Toolbox |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Header : "./anabatic/NetBuilderHybridVH.h" |
// +-----------------------------------------------------------------+
#pragma once
#include "anabatic/NetBuilder.h"
namespace Anabatic {
// -----------------------------------------------------------------
// Class : "NetBuilderHybridVH".
class NetBuilderHybridVH : public NetBuilder {
public:
NetBuilderHybridVH ();
virtual ~NetBuilderHybridVH ();
static std::string getStyle ();
virtual void doRp_AutoContacts ( GCell*, Component*, AutoContact*& source, AutoContact*& target, uint64_t flags );
virtual AutoContact* doRp_Access ( GCell*, Component*, uint64_t flags );
AutoContact* doRp_AccessEastWestPin ( GCell* , RoutingPad* );
AutoContact* doRp_AccessNorthSouthPin ( GCell* , RoutingPad* );
private:
bool doRp_xG_1M1 ( RoutingPad* );
bool doRp_1G_1PinM2 ( RoutingPad* );
bool doRp_xG_xM1_xM3 ( const std::vector<RoutingPad*>& );
virtual bool _do_1G_1M1 ();
virtual bool _do_2G_1M1 ();
virtual bool _do_xG_1M1 ();
virtual bool _do_xG ();
bool _do_xG_xM1 ();
virtual bool _do_globalSegment ();
// Should never occur, so just return false.
// virtual bool _do_xG_1Pad ();
// virtual bool _do_1G_1PinM2 ();
virtual bool _do_1G_xM1 ();
// virtual bool _do_xG_xM2 ();
// virtual bool _do_1G_1M3 ();
// virtual bool _do_xG_xM3 ();
// virtual bool _do_xG_1M1_1M2 ();
virtual bool _do_xG_xM1_xM3 ();
virtual bool _do_1G_xM1_1PinM1 ();
virtual bool _do_1G_xM1_1PinM2 ();
// virtual bool _do_4G_1M2 ();
virtual bool _do_2G ();
virtual bool _do_2G_1PinM1 ();
virtual bool _do_1G_1PinM1 ();
virtual bool _do_1G_1PinM2 ();
virtual bool _do_xG_1PinM2 ();
virtual void singleGCell ( AnabaticEngine*, Net* );
public:
virtual string getTypeName () const;
};
} // Anabatic namespace.

View File

@ -1,7 +1,7 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) Sorbonne Université 2008-2022, All Rights Reserved
// Copyright (c) UPMC 2008-2018, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
@ -13,7 +13,9 @@
// | C++ Header : "./anabatic/NetBuilderM2.h" |
// +-----------------------------------------------------------------+
#pragma once
#ifndef ANABATIC_NET_BUILDER_M2_H
#define ANABATIC_NET_BUILDER_M2_H
#include "anabatic/NetBuilder.h"
@ -27,7 +29,6 @@ namespace Anabatic {
public:
NetBuilderM2 ();
virtual ~NetBuilderM2 ();
static std::string getStyle ();
virtual void doRp_AutoContacts ( GCell*, Component*, AutoContact*& source, AutoContact*& target, uint64_t flags );
virtual AutoContact* doRp_Access ( GCell*, Component*, uint64_t flags );
private:
@ -52,3 +53,5 @@ namespace Anabatic {
} // Anabatic namespace.
#endif // ANABATIC_NET_BUILDER_M2_H

View File

@ -1,7 +1,7 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) Sorbonne Université 2017-2022, All Rights Reserved
// Copyright (c) UPMC 2017-2018, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
@ -27,7 +27,6 @@ namespace Anabatic {
public:
NetBuilderVH ();
virtual ~NetBuilderVH ();
static std::string getStyle ();
virtual void doRp_AutoContacts ( GCell*, Component*, AutoContact*& source, AutoContact*& target, uint64_t flags );
virtual AutoContact* doRp_Access ( GCell*, Component*, uint64_t flags );
private:

View File

@ -1,52 +0,0 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) Sorbonne Université 2022-2022, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | A n a b a t i c - Global Routing Toolbox |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Header : "./hurricane/isobar/PyStyleFlags.h" |
// +-----------------------------------------------------------------+
#pragma once
#include "hurricane/isobar/PyHurricane.h"
#include "anabatic/Constants.h"
namespace Anabatic {
extern "C" {
// -------------------------------------------------------------------
// Python Object : "PyStyleFlags".
typedef struct {
PyObject_HEAD
StyleFlags* _object;
} PyStyleFlags;
extern PyTypeObject PyTypeStyleFlags;
extern PyMethodDef PyStyleFlags_Methods[];
extern PyObject* PyStyleFlags_Link ( StyleFlags* );
extern void PyStyleFlags_LinkPyType ();
extern void PyStyleFlags_postModuleInit ();
#define IsPyStyleFlags(v) ( (v)->ob_type == &PyTypeStyleFlags )
#define PYSTYLEFLAGS(v) ( (PyStyleFlags*)(v) )
#define PYSTYLEFLAGS_O(v) ( PYSTYLEFLAGS(v)->_object )
} // extern "C".
extern Anabatic::StyleFlags PyInt_AsStyleFlags ( PyObject* );
} // Anabatic namespace.

View File

@ -76,12 +76,11 @@ namespace Anabatic {
static inline bool doDestroyBaseSegment ();
static inline bool doDestroyTool ();
static bool isInDemoMode ();
static bool isChannelStyle ();
static bool isChannelMode ();
static bool doWarnGCellOverload ();
static Session* get ( const char* message=NULL );
static inline Technology* getTechnology ();
static inline AnabaticEngine* getAnabatic ();
static StyleFlags getRoutingStyle ();
static inline const Configuration* getConfiguration ();
static float getSaturateRatio ();
static size_t getSaturateRp ();
@ -122,8 +121,6 @@ namespace Anabatic {
static inline size_t getLayerDepth ( const Layer* layer );
static inline const Layer* getRoutingLayer ( size_t );
static inline const Layer* getContactLayer ( size_t );
static inline const Layer* getBuildRoutingLayer ( size_t );
static inline const Layer* getBuildContactLayer ( size_t );
static Flags getDirection ( size_t depth );
static inline DbU::Unit getPitch ( size_t depth, Flags flags );
static inline DbU::Unit getOffset ( size_t depth );
@ -271,8 +268,6 @@ namespace Anabatic {
inline size_t Session::getLayerDepth ( const Layer* layer ) { return getRoutingGauge()->getLayerDepth(layer); }
inline const Layer* Session::getRoutingLayer ( size_t depth ) { return getRoutingGauge()->getRoutingLayer(depth); }
inline const Layer* Session::getContactLayer ( size_t depth ) { return getRoutingGauge()->getContactLayer(depth); }
inline const Layer* Session::getBuildRoutingLayer ( size_t depth ) { return getRoutingGauge()->getRoutingLayer(depth+getRoutingGauge()->getFirstRoutingLayer()); }
inline const Layer* Session::getBuildContactLayer ( size_t depth ) { return getRoutingGauge()->getContactLayer(depth+getRoutingGauge()->getFirstRoutingLayer()); }
inline DbU::Unit Session::getPitch ( size_t depth, Flags flags=Flags::NoFlags ) { return get("getPitch(depth,flags)")->_getPitch( depth, flags ); }
inline DbU::Unit Session::getOffset ( size_t depth ) { return getRoutingGauge()->getLayerOffset(depth); }
inline DbU::Unit Session::getWireWidth ( size_t depth ) { return getRoutingGauge()->getLayerWireWidth(depth); }

View File

@ -3,7 +3,7 @@
set(CMAKE_LEGACY_CYGWIN_WIN32 0)
project(Bootstrap)
cmake_minimum_required(VERSION 3.16)
cmake_minimum_required(VERSION 2.8.0)
set(ignoreVariables USE_LIBBFD "${BUILD_DOC} ${CMAKE_INSTALL_DIR}")
@ -11,7 +11,7 @@
list(INSERT CMAKE_MODULE_PATH 0 "${Bootstrap_SOURCE_DIR}/cmake_modules/")
find_package(Bootstrap REQUIRED)
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development.Module )
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development )
find_package(PythonSitePackages REQUIRED)
print_cmake_module_path()
@ -32,10 +32,3 @@
PERMISSIONS OWNER_WRITE
OWNER_READ GROUP_READ WORLD_READ
OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE)
install(FILES crlenv.py
DESTINATION bin
RENAME crlenv
PERMISSIONS OWNER_WRITE
OWNER_READ GROUP_READ WORLD_READ
OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE)

View File

@ -1,26 +1,7 @@
#!/bin/bash
#. /etc/*-release
#arch="Linux.el9"
#if [ "`echo ${VERSION} | cut -c 1`" == "7" ]; then
# echo "Building for RHEL 7"
# arch="Linux.el7_64"
#fi
arch="Linux.el9"
if [ "`hostname -s`" == "bop" ]; then
echo "Building for RHEL 7"
arch="Linux.el7_64"
fi
nightly=""
if [[ "`pwd`" =~ /nightly/ ]]; then
nightly="/nightly"
fi
srcDir=${HOME}${nightly}/coriolis-2.x/src/alliance/alliance/src
commonRoot=${HOME}${nightly}/coriolis-2.x/${arch}/Release.Shared
#commonRoot=${HOME}${nightly}/coriolis-2.x/${arch}/Debug.Shared
srcDir=${HOME}/coriolis-2.x/src/alliance/alliance/src
commonRoot=${HOME}/coriolis-2.x/Linux.el9/Release.Shared
buildDir=${commonRoot}/build
installDir=${commonRoot}/install

View File

@ -21,12 +21,11 @@ projects = [
, "etesian"
, "anabatic"
, "katana"
#, "knik"
#, "katabatic"
#, "kite"
#, "equinox"
#, "solstice"
, "tramontana"
, "knik"
, "katabatic"
, "kite"
, "equinox"
, "solstice"
, "oroshi"
, "bora"
, "karakaze"

View File

@ -35,13 +35,12 @@ class Builder:
self._noCache = False
self._ninja = False
self._clang = False
self._manylinux = False
self._noSystemBoost = False
self._macports = False
self._devtoolset = 0
self._llvmtoolset = 0
self._bfd = "OFF"
self._qt4 = False
self._qt5 = False
self._openmp = False
self._enableShared = "ON"
self._enableDoc = "OFF"
@ -63,7 +62,6 @@ class Builder:
elif attribute == "noCache": self._noCache = value
elif attribute == "ninja": self._ninja = value
elif attribute == "clang": self._clang = value
elif attribute == "manylinux": self._manylinux = value
elif attribute == "macports":
self._macports = value
if value: self._noSystemBoost = True
@ -73,7 +71,7 @@ class Builder:
elif attribute == "llvmtoolset":
self._llvmtoolset = value
elif attribute == "bfd": self._bfd = value
elif attribute == "qt4": self._qt4 = value
elif attribute == "qt5": self._qt5 = value
elif attribute == "openmp": self._openmp = value
elif attribute == "enableDoc": self._enableDoc = value
elif attribute == "enableShared": self._enableShared = value
@ -177,9 +175,8 @@ class Builder:
#, "-D", "BOOST_LIBRARYDIR:STRING=/usr/lib64/boost169"
]
if self._bfd: command += [ "-D", "USE_LIBBFD:STRING=%s" % self._bfd ]
if self._qt4: command += [ "-D", "WITH_QT4:STRING=TRUE" ]
if self._qt5: command += [ "-D", "WITH_QT5:STRING=TRUE" ]
if self._openmp: command += [ "-D", "WITH_OPENMP:STRING=TRUE" ]
if self._manylinux: command += [ "-D", "USE_MANYLINUX:STRING=TRUE" ]
command += [ "-D", "CMAKE_BUILD_TYPE:STRING=%s" % self.buildMode
#, "-D", "BUILD_SHARED_LIBS:STRING=%s" % self.enableShared
, "-D", "CMAKE_INSTALL_PREFIX:STRING=%s" % self.installDir

View File

@ -2,7 +2,7 @@
# -*- mode:Python -*-
#
# This file is part of the Coriolis Software.
# Copyright (c) Sorbonne Université 2012-2023, All Rights Reserved
# Copyright (c) Sorbonne Université 2012-2021, All Rights Reserved
#
# +-----------------------------------------------------------------+
# | C O R I O L I S |
@ -122,7 +122,7 @@ class CompileWidget ( QWidget ):
#if self.options.svnStatus: command += [ '--svn-update' ]
if self.options.enableDoc: command += [ '--doc' ]
if self.options.devtoolset: command += [ '--devtoolset-8' ]
if self.options.qt4: command += [ '--qt4' ]
if self.options.qt5: command += [ '--qt5' ]
if self.options.noCache: command += [ '--no-cache' ]
if self.options.rmBuild: command += [ '--rm-build' ]
if self.options.verbose: command += [ '--verbose' ]

View File

@ -57,7 +57,7 @@ class OptionsWidget ( QWidget ):
self._make = QCheckBox( 'Build' )
self._enableDoc = QCheckBox( 'Build Documentation' )
self._devtoolset = QCheckBox( 'Build with devtoolset 8' )
self._qt4 = QCheckBox( 'Build with Qt 4 (Qt 5 default)' )
self._qt5 = QCheckBox( 'Build with Qt 5 (Qt 4 default)' )
self._noCache = QCheckBox( 'Remove previous CMake cache' )
self._rmBuild = QCheckBox( 'Cleanup Build Directory' )
self._verbose = QCheckBox( 'Display Compiler Commands' )
@ -83,7 +83,7 @@ class OptionsWidget ( QWidget ):
vLayout.addWidget( self._buildMode )
vLayout.addWidget( self._enableDoc )
vLayout.addWidget( self._devtoolset )
vLayout.addWidget( self._qt4 )
vLayout.addWidget( self._qt5 )
vLayout.addWidget( self._noCache )
vLayout.addWidget( self._rmBuild )
vLayout.addStretch()
@ -121,7 +121,7 @@ class OptionsWidget ( QWidget ):
def _getMake ( self ): return self._make.isChecked()
def _getEnableDoc ( self ): return self._enableDoc.isChecked()
def _getDevtoolset ( self ): return self._devtoolset.isChecked()
def _getQt4 ( self ): return self._qt4.isChecked()
def _getQt5 ( self ): return self._qt5.isChecked()
def _getNoCache ( self ): return self._noCache.isChecked()
def _getRmBuild ( self ): return self._rmBuild.isChecked()
def _getVerbose ( self ): return self._verbose.isChecked()
@ -134,7 +134,7 @@ class OptionsWidget ( QWidget ):
make = property( _getMake )
enableDoc = property( _getEnableDoc )
devtoolset = property( _getDevtoolset )
qt4 = property( _getQt4 )
qt5 = property( _getQt5 )
noCache = property( _getNoCache )
rmBuild = property( _getRmBuild )
verbose = property( _getVerbose )
@ -146,7 +146,7 @@ class OptionsWidget ( QWidget ):
self._make .setChecked( bool(settings.value('builder/make' )) )
self._enableDoc .setChecked( bool(settings.value('builder/enableDoc' )) )
self._devtoolset .setChecked( bool(settings.value('builder/devtoolset')) )
self._qt4 .setChecked( bool(settings.value('builder/qt4' )) )
self._qt5 .setChecked( bool(settings.value('builder/qt5' )) )
self._noCache .setChecked( bool(settings.value('builder/noCache' )) )
self._rmBuild .setChecked( bool(settings.value('builder/rmBuild' )) )
self._verbose .setChecked( bool(settings.value('builder/verbose' )) )
@ -169,7 +169,7 @@ class OptionsWidget ( QWidget ):
settings.setValue('builder/make' , self._make .isChecked() )
settings.setValue('builder/enableDoc' , self._enableDoc .isChecked() )
settings.setValue('builder/devtoolset', self._devtoolset.isChecked() )
settings.setValue('builder/qt4' , self._qt4 .isChecked() )
settings.setValue('builder/qt5' , self._qt5 .isChecked() )
settings.setValue('builder/buildMode' , self._buildMode .currentText() )
settings.setValue('builder/noCache' , self._noCache .isChecked() )
settings.setValue('builder/rmBuild' , self._rmBuild .isChecked() )

View File

@ -206,12 +206,11 @@ parser.add_option ( "--rm-build" , action="store_true" ,
parser.add_option ( "--macports" , action="store_true" , dest="macports" , help="Build against MacPorts." )
parser.add_option ( "--devtoolset" , action="store" , type="int" , dest="devtoolset" , help="Build against TUV Dev Toolset N." )
parser.add_option ( "--llvm-toolset" , action="store" , type="int" , dest="llvmtoolset" , help="Build against TUV Dev LLVM Toolset N." )
parser.add_option ( "--qt4" , action="store_true" , dest="qt4" , help="Build against Qt 4 (default: Qt 5)." )
parser.add_option ( "--bfd" , action="store_true" , dest="bfd" , help="Link against BFD to enable stack trace display." )
parser.add_option ( "--qt5" , action="store_true" , dest="qt5" , help="Build against Qt 5 (default: Qt 4)." )
parser.add_option ( "--bfd" , action="store_true" , dest="bfd" , help="Build against Qt 5 (default: Qt 4)." )
parser.add_option ( "--openmp" , action="store_true" , dest="openmp" , help="Enable the use of OpenMP in Gcc." )
parser.add_option ( "--ninja" , action="store_true" , dest="ninja" , help="Use Ninja instead of UNIX Makefile." )
parser.add_option ( "--clang" , action="store_true" , dest="clang" , help="Force use of Clang C/C++ compiler instead of system default." )
parser.add_option ( "--manylinux" , action="store_true" , dest="manylinux" , help="Build target is manylinux (PyPY)." )
parser.add_option ( "--make" , action="store" , type="string", dest="makeArguments" , help="Arguments to pass to make (ex: \"-j4 install\")." )
parser.add_option ( "--project" , action="append" , type="string", dest="projects" , help="The name of a project to build (may appears any number of time)." )
parser.add_option ( "-t", "--tool" , action="append" , type="string", dest="tools" , help="The name of a tool to build (may appears any number of time)." )
@ -282,8 +281,7 @@ else:
if options.devtoolset: builder.devtoolset = options.devtoolset
if options.llvmtoolset: builder.llvmtoolset = options.llvmtoolset
if options.bfd: builder.bfd = "ON"
if options.qt4: builder.qt4 = True
if options.manylinux: builder.manylinux = True
if options.qt5: builder.qt5 = True
if options.openmp: builder.openmp = True
if options.makeArguments: builder.makeArguments = options.makeArguments
#if options.svnMethod: builder.svnMethod = options.svnMethod

View File

@ -9,7 +9,6 @@
FindQwt.cmake
FindSphinx.cmake
FindPelican.cmake
FindCOLOQUINTE.cmake
GetGitRevisionDescription.cmake
GetGitRevisionDescription.cmake.in
)

View File

@ -7,10 +7,6 @@
if(COMMAND CMAKE_POLICY)
cmake_policy(SET CMP0003 NEW)
cmake_policy(SET CMP0005 NEW)
cmake_policy(SET CMP0079 NEW)
cmake_policy(SET CMP0022 NEW)
cmake_policy(SET CMP0060 NEW)
cmake_policy(SET CMP0095 NEW)
#if(NOT (CMAKE_VERSION VERSION_LESS 2.8.0))
# cmake_policy(SET CMP0014 OLD)
#endif()
@ -83,27 +79,22 @@
#set(DEBUG_FLAGS "-g -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC")
set(DEBUG_FLAGS "-g")
if(CYGWIN)
set(ADDITIONAL_FLAGS "-D_GLIBCXX_USE_C99")
set(CXX_STANDARD "gnu++17")
set(ADDTIONAL_FLAGS "-D_GLIBCXX_USE_C99")
set(CXX_STANDARD "gnu++11")
else()
set(ADDITIONAL_FLAGS "-Wl,--no-undefined")
set(CXX_STANDARD "c++17")
set(ADDTIONAL_FLAGS "")
set(CXX_STANDARD "c++11")
endif()
#set(CMAKE_C_FLAGS_DEBUG " -Wall -fsanitize=address ${ADDITIONAL_FLAGS} ${DEBUG_FLAGS}" CACHE STRING "C Compiler Debug options." FORCE)
set(CMAKE_C_FLAGS_DEBUG " -Wall ${ADDITIONAL_FLAGS} ${DEBUG_FLAGS}" CACHE STRING "C Compiler Debug options." FORCE)
set(CMAKE_C_FLAGS_RELEASE " -Wall -O2 ${ADDITIONAL_FLAGS} -DNDEBUG" CACHE STRING "C Compiler Release options." FORCE)
#set(CMAKE_C_FLAGS_RELEASE " -Wall -fsanitize=address ${ADDITIONAL_FLAGS} -DNDEBUG" CACHE STRING "C Compiler Release options." FORCE)
#set(CMAKE_CXX_FLAGS_DEBUG "-std=${CXX_STANDARD} -Wall -fsanitize=address ${ADDITIONAL_FLAGS} ${DEBUG_FLAGS}" CACHE STRING "C++ Compiler Debug options." FORCE)
set(CMAKE_CXX_FLAGS_DEBUG "-std=${CXX_STANDARD} -Wall ${ADDITIONAL_FLAGS} ${DEBUG_FLAGS}" CACHE STRING "C++ Compiler Debug options." FORCE)
set(CMAKE_CXX_FLAGS_RELEASE "-std=${CXX_STANDARD} -Wall -O2 ${ADDITIONAL_FLAGS} -DNDEBUG" CACHE STRING "C++ Compiler Release options." FORCE)
#set(CMAKE_CXX_FLAGS_RELEASE "-std=${CXX_STANDARD} -Wall -fsanitize=address ${ADDITIONAL_FLAGS} -DNDEBUG" CACHE STRING "C++ Compiler Release options." FORCE)
#set(CMAKE_C_FLAGS_DEBUG " -Wall -fsanitize=address ${ADDTIONAL_FLAGS} ${DEBUG_FLAGS}" CACHE STRING "C Compiler Debug options." FORCE)
set(CMAKE_C_FLAGS_DEBUG " -Wall ${ADDTIONAL_FLAGS} ${DEBUG_FLAGS}" CACHE STRING "C Compiler Debug options." FORCE)
set(CMAKE_C_FLAGS_RELEASE " -Wall -O2 ${ADDTIONAL_FLAGS} -DNDEBUG" CACHE STRING "C Compiler Release options." FORCE)
#set(CMAKE_C_FLAGS_RELEASE " -Wall -fsanitize=address ${ADDTIONAL_FLAGS} -DNDEBUG" CACHE STRING "C Compiler Release options." FORCE)
#set(CMAKE_CXX_FLAGS_DEBUG "-std=${CXX_STANDARD} -Wall -fsanitize=address ${ADDTIONAL_FLAGS} ${DEBUG_FLAGS}" CACHE STRING "C++ Compiler Debug options." FORCE)
set(CMAKE_CXX_FLAGS_DEBUG "-std=${CXX_STANDARD} -Wall ${ADDTIONAL_FLAGS} ${DEBUG_FLAGS}" CACHE STRING "C++ Compiler Debug options." FORCE)
set(CMAKE_CXX_FLAGS_RELEASE "-std=${CXX_STANDARD} -Wall -O2 ${ADDTIONAL_FLAGS} -DNDEBUG" CACHE STRING "C++ Compiler Release options." FORCE)
#set(CMAKE_CXX_FLAGS_RELEASE "-std=${CXX_STANDARD} -Wall -fsanitize=address ${ADDTIONAL_FLAGS} -DNDEBUG" CACHE STRING "C++ Compiler Release options." FORCE)
if ( NOT CMAKE_BUILD_TYPE )
message( "Build Type not set, defaulting to Debug..." )
set( CMAKE_BUILD_TYPE Debug )
endif()
#
# Adds to the CMAKE_MODULE_PATH directories guesseds from project
# environment variables <PROJECT>_USER_TOP and <PROJECT>_TOP.
@ -140,7 +131,7 @@ endif()
# Build <PROJECT>_INCLUDE_DIR & <PROJECT>_LIBRARIES and sets up <PROJECT>_FOUND
# Usage: set_library_path(<PROJECT> <library>)
#
#PYTHON_NEW May be used any number of time on the same <PROJECT> to create a list of
# May be used any number of time on the same <PROJECT> to create a list of
# <library>.
#
macro(set_libraries_path configname library)
@ -157,14 +148,7 @@ endif()
set(${configname}_FOUND "NOTFOUND")
endif()
endmacro()
#
# sets that a library is expected to have unresolved symbols
# Usage: set_library_unresolved_symbols(<PROJECT>)
#
# Should be used before set_libraries_path.
macro(set_has_unresolved_symbols configname)
set(${configname}_LIBRARIES "-Wl,--unresolved-symbols=ignore-all" ${${configname}_LIBRARIES})
endmacro()
#
# Checks if a set of libraries has been found, could be blocking or not.
@ -223,35 +207,11 @@ endif()
endmacro(setup_boost)
#
# Setup Python, select detection depending on USE_MANYLINUX.
#
macro(setup_python)
set(pydevelArg "Development")
if (USE_MANYLINUX)
message(STATUS "Build for manylinux")
set(pydevelArg "Development.Module")
endif()
find_package(Python 3 REQUIRED COMPONENTS Interpreter ${pydevelArg} )
endmacro()
#
# Find Qt, the union of all the modules we need for the whole project.
#
macro(setup_qt)
if(WITH_QT4)
message(STATUS "Attempt to find Qt 4...")
# For Qt4.
#set(QT_USE_QTXML "true")
set(QT_USE_QTSVG "true")
find_package(Qt4 REQUIRED)
include(${QT_USE_FILE})
# ${QT_QTSVG_LIBRARY}
set(QtX_INCLUDE_DIRS ${QT_INCLUDE_DIR})
set(QtX_LIBRARIES ${QT_LIBRARIES})
else()
if(WITH_QT5)
message(STATUS "Attempt to find Qt 5...")
# For Qt5
find_package(Qt5Core REQUIRED)
@ -271,22 +231,32 @@ endif()
${Qt5Core_LIBRARIES} )
#message(STATUS "QtX_INCLUDE_DIRS: ${QtX_INCLUDE_DIRS}")
#message(STATUS "QtX_LIBRARIES: ${QtX_LIBRARIES}")
else()
message(STATUS "Attempt to find Qt 4...")
# For Qt4.
#set(QT_USE_QTXML "true")
set(QT_USE_QTSVG "true")
find_package(Qt4 REQUIRED)
include(${QT_USE_FILE})
# ${QT_QTSVG_LIBRARY}
set(QtX_INCLUDE_DIRS ${QT_INCLUDE_DIR})
set(QtX_LIBRARIES ${QT_LIBRARIES})
endif()
endmacro()
macro(qtX_wrap_cpp variable)
if (WITH_QT4)
qt4_wrap_cpp(${variable} ${ARGN})
else()
if (WITH_QT5)
qt5_wrap_cpp(${variable} ${ARGN})
else()
qt4_wrap_cpp(${variable} ${ARGN})
endif()
endmacro()
macro(qtX_add_resources variable)
if (WITH_QT4)
qt4_add_resources(${variable} ${ARGN})
else()
if (WITH_QT5)
qt5_add_resources(${variable} ${ARGN})
else()
qt4_add_resources(${variable} ${ARGN})
endif()
endmacro()
@ -295,7 +265,15 @@ endif()
# Find Qwt, correlated to the Qt version.
#
macro(setup_qwt)
if(WITH_QT4)
if(WITH_QT5)
find_path(QWT_INCLUDE_DIR NAMES qwt.h
PATHS /usr/include/qt5
/usr/include
PATH_SUFFIXES qwt )
find_library(QWT_LIBRARY NAMES qwt-qt5 qwt
PATHS /usr/lib64
/usr/lib )
else()
find_path(QWT_INCLUDE_DIR NAMES qwt.h
PATHS /usr/include/qwt-qt4
/opt/local/libexec/qt4/include
@ -306,14 +284,6 @@ endif()
PATHS /opt/local/libexec/qt4/lib
/usr/lib64
/usr/lib )
else()
find_path(QWT_INCLUDE_DIR NAMES qwt.h
PATHS /usr/include/qt5
/usr/include
PATH_SUFFIXES qwt )
find_library(QWT_LIBRARY NAMES qwt-qt5 qwt
PATHS /usr/lib64
/usr/lib )
endif()
if( QWT_INCLUDE_DIR AND QWT_LIBRARY)
@ -426,11 +396,9 @@ endif()
set( pyDeplibs ${clib} ${deplibs} )
add_library( ${clib} ${pyCpps} )
set_target_properties( ${clib} PROPERTIES VERSION ${version} SOVERSION ${soversion})
#target_compile_definitions( ${clib} PUBLIC Py_LIMITED_API=1)
set_target_properties( ${clib} PROPERTIES VERSION ${version} SOVERSION ${soversion} )
target_link_libraries( ${clib} ${deplibs} )
install( TARGETS ${clib} DESTINATION lib${LIB_SUFFIX} )
target_link_options( ${clib} PRIVATE "LINKER:--unresolved-symbols=ignore-all")
endif()
set( pytarget "${pymodule}_target" )
@ -441,9 +409,7 @@ endif()
PREFIX ""
OUTPUT_NAME ${pymodule}
)
#target_compile_definitions( ${pytarget} PUBLIC Py_LIMITED_API=1)
target_link_libraries( ${pytarget} ${pyDeplibs} )
target_link_options( ${pytarget} PRIVATE "LINKER:--unresolved-symbols=ignore-all")
install( TARGETS ${pytarget} DESTINATION ${Python_CORIOLISARCH} )
if( NOT ("${pyIncludes}" STREQUAL "None") )
@ -466,7 +432,6 @@ endif()
add_library( ${pymodule} MODULE ${pyCpps} )
set_target_properties( ${pymodule} PROPERTIES PREFIX "" )
target_link_libraries( ${pymodule} ${deplibs} )
#target_compile_definitions( ${pymodule} PUBLIC Py_LIMITED_API=1)
install( TARGETS ${pymodule} DESTINATION ${Python_CORIOLISARCH} )
if( NOT ("${pyIncludes}" STREQUAL "None") )

View File

@ -1,4 +1,5 @@
if(UNIX AND NOT POETRY)
if(UNIX)
if(NOT Python_FOUND)
message(FATAL_ERROR "Python has not been found, maybe forgot to call find_package(Python). ")
endif()
@ -9,7 +10,7 @@ if(UNIX AND NOT POETRY)
execute_process(COMMAND "${Python_EXECUTABLE}" "-c" "${SCRIPT}"
RESULT_VARIABLE RETURN_CODE
OUTPUT_VARIABLE Python_SITEARCH
OUTPUT_VARIABLE Python_CORIOLISARCH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
@ -19,7 +20,7 @@ if(UNIX AND NOT POETRY)
execute_process(COMMAND "${Python_EXECUTABLE}" "-c" "${SCRIPT}"
RESULT_VARIABLE RETURN_CODE
OUTPUT_VARIABLE Python_SITELIB
OUTPUT_VARIABLE Python_CORIOLISLIB
OUTPUT_STRIP_TRAILING_WHITESPACE
)
@ -29,15 +30,12 @@ if(UNIX AND NOT POETRY)
set(FindPythonSitePackages_FOUND FALSE)
endif(RETURN_CODE EQUAL 0)
set(Python_CORIOLISARCH "lib${LIB_SUFFIX}/${Python_SITEARCH}/coriolis"
CACHE STRING "Python platform dependent install directory (Coriolis modules)." FORCE)
set(Python_SITELIB "lib${LIB_SUFFIX}/${Python_SITELIB}"
set(Python_CORIOLISARCH "lib${LIB_SUFFIX}/${Python_CORIOLISARCH}"
CACHE STRING "Python platform dependent install directory." FORCE)
set(Python_CORIOLISLIB "lib${LIB_SUFFIX}/${Python_CORIOLISLIB}"
CACHE STRING "Python platform independent install directory." FORCE)
set(Python_CORIOLISLIB "${Python_SITELIB}/coriolis"
CACHE STRING "Python platform independent install directory (Coriolis modules)." FORCE)
mark_as_advanced(Python_CORIOLISARCH)
mark_as_advanced(Python_CORIOLISLIB)
mark_as_advanced(Python_SITELIB)
if(FindPythonSitePackages_FOUND)
if(NOT FindPythonSitePackages_FIND_QUIETLY)
@ -48,4 +46,4 @@ if(UNIX AND NOT POETRY)
else(FindPythonSitePackages_FOUND)
message ( FATAL_ERROR "Python site packages directory was not found (pythonV.R/site-packages/)." )
endif(FindPythonSitePackages_FOUND)
endif(UNIX AND NOT POETRY)
endif(UNIX)

View File

@ -119,7 +119,7 @@ Development files for the Coriolis 2 package.
%dir %{coriolisTop}/%{_lib}
%dir %{coriolisTop}/%{python_sitedir}
%dir %{coriolisTop}/%{python_sitedir}/crlcore
%dir %{coriolisTop}/%{python_sitedir}/helpers
%dir %{coriolisTop}/%{python_sitedir}/crlcore/helpers
%dir %{coriolisTop}/%{python_sitedir}/cumulus
%dir %{coriolisTop}/%{python_sitedir}/stratus
%{coriolisTop}/bin/*
@ -130,7 +130,7 @@ Development files for the Coriolis 2 package.
%{coriolisTop}/%{python_sitedir}/cumulus/plugins/*/*.py*
%{coriolisTop}/%{python_sitedir}/stratus/*.py*
%{coriolisTop}/%{python_sitedir}/crlcore/*.py*
%{coriolisTop}/%{python_sitedir}/helpers/*.py*
%{coriolisTop}/%{python_sitedir}/crlcore/helpers/*.py*
%{coriolisTop}/%{python_sitedir}/kite/*.py*
%{coriolisTop}/%{python_sitedir}/unicorn/*.py*
%{_sysconfdir}/coriolis2/*.py
@ -180,7 +180,7 @@ Development files for the Coriolis 2 package.
%{coriolisTop}/include/vlsisapd/configuration/*.h
%{coriolisTop}/include/vlsisapd/dtr/*.h
%{coriolisTop}/include/vlsisapd/openChams/*.h
%{coriolisTop}/include/coriolis2/coloquinte/*.hpp
%{coriolisTop}/include/coriolis2/coloquinte/*.hxx
%{coriolisTop}/include/coriolis2/hurricane/*.h
%{coriolisTop}/include/coriolis2/hurricane/viewer/*.h
%{coriolisTop}/include/coriolis2/hurricane/isobar/*.h

View File

@ -17,10 +17,6 @@ reDebugStaticPattern = re.compile( r".*Debug\.Static.*" )
def scrubPath ( pathName ):
"""
Remove any previous path elements pointing to Coriolis,
so we don't get multiple installed versions tangled together.
"""
pathEnv = os.getenv( pathName )
if not pathEnv: return ""
pathList = pathEnv.split( ':' )
@ -40,31 +36,7 @@ def scrubPath ( pathName ):
return scrubbedEnv
def readLdconfig ():
"""
Read the default paths setup by ldconfig.
.. note:: Disabled now, as it was not the root cause of the
linking problem. Keep as a code example...
"""
ldpath = ''
uname = subprocess.Popen ( ["ldconfig", "-vXN"]
, stdout=subprocess.PIPE
, stderr=subprocess.PIPE )
lines = uname.stdout.readlines()
for rawline in lines:
line = rawline.decode('ascii')
if line[0] != '/': continue
if len(ldpath) > 0: ldpath += ':'
ldpath += line.split(':')[0]
return ldpath
def guessOs ():
"""
Try to guess under which OS we are running by calling uname.
Also guess if we are using software collections *devtoolset*.
"""
useDevtoolset = False
osEL9 = re.compile (".*Linux.*el9.*x86_64.*")
osSlsoc7x_64 = re.compile (".*Linux.*el7.*x86_64.*")
@ -130,18 +102,7 @@ def guessOs ():
return ( osType, useDevtoolset )
def guessShell ( defaultShell, osType ):
"""
Try to guess the kind shell we are running under, Bourne-like shells
(sh, bash, ksh, zsh) or C-shell likes (csh, tcsh).
Identifies the parent process we are running into, which should be
the shell, and compares to know ones.
.. note:: The SHELL nvironment variable cannot be trusted, it seems
to be set once the user logs in, and if it change afterwards,
it's not updated.
"""
def guessShell ( forcedShell ):
# This environement variable cannot be trusted as it is set once when
# the user logs in. If aftewards it changes it that variable is *not*
# affected :-(.
@ -157,27 +118,14 @@ def guessShell ( defaultShell, osType ):
, u'/usr/local/bin/csh'
]
if shellName is None:
psCommand = ['ps', '-o', 'comm', '-p', str(os.getppid()) ]
cmdField = 0
if osType.startswith('Cygwin'):
psCommand = ['ps', '-p', str(os.getppid()) ]
cmdField = 7
try:
psResult = subprocess.run( psCommand, capture_output=True, check=True )
shell = psResult.stdout.splitlines()[1].decode('utf8').split()[cmdField].lstrip('-')
if shell[0] != '/':
whichCommand = subprocess.run( ['which', shell ], capture_output=True, check=True )
shellPath = whichCommand.stdout.splitlines()[0].decode('utf8')
psCommand = subprocess.Popen ( ['ps', '-p', str(os.getppid()) ], stdout=subprocess.PIPE )
shell = psCommand.stdout.readlines()[1].decode('utf8')[:-1].split()[3].lstrip('-')
whichCommand = subprocess.Popen ( ['which', shell ], stdout=subprocess.PIPE )
shellPath = whichCommand.stdout.readlines()[0][:-1].decode('utf8')
#print( 'GUESSED shellPath={}'.format(shellPath) )
else:
shellPath = shell
if not options.queryISysRoot and not options.queryInstRoot:
print( 'echo "[GUESSED] shellPath={}";'.format(shellPath) )
except Exception:
shellPath = u'/bin/bash'
print( 'echo "[ERROR] \\"ps\\" command failure, using {}";'.format(shellPath) )
else:
shellPath = defaultShell
print( 'echo "Defaulting to shell {}";'.format(shellPath) )
shellPath = forcedShell
#print( 'FORCED shellPath={}'.format(shellPath) )
if shellPath in cshBins:
#print( 'Matched C-Shell' )
isBourneShell = False
@ -186,6 +134,7 @@ def guessShell ( defaultShell, osType ):
if __name__ == "__main__":
osType,useDevtoolset = guessOs()
buildType = "Release"
linkType = "Shared"
@ -214,7 +163,7 @@ if __name__ == "__main__":
if options.shared: linkType = "Shared"
if options.rootDir: rootDir = options.rootDir
if options.shell: shellName = options.shell
shellBin, isBourneShell = guessShell( shellName, osType )
shellBin, isBourneShell = guessShell( shellName )
scriptPath = os.path.abspath( os.path.dirname( sys.argv[0] ))
if 'Debug.' in scriptPath: buildType = 'Debug'
@ -310,7 +259,7 @@ if __name__ == "__main__":
shellMessage = "Using script location Coriolis 2 (%s)" % rootDir
if osType.startswith("Cygwin"):
strippedPath = "%s/lib:%s" % ( coriolisTop, strippedPath )
strippedPath = "%s/lib:%s" % ( coriolisTop, libDir, strippedPath )
if not os.path.exists(coriolisTop):
print( 'echo "[ERROR] coriolisEnv.py, top directory "{}" do not exists."'.format( coriolisTop ))
sys.exit( 1 )
@ -320,7 +269,6 @@ if __name__ == "__main__":
if os.path.isdir(absLibDir): break
libDir = None
if libDir is None:
if not options.queryISysRoot and not options.queryInstRoot:
print( 'echo "[ERROR] coriolisEnv.py, library directory not found."' )
sys.exit( 1 )
@ -340,12 +288,12 @@ if __name__ == "__main__":
if os.path.isdir(pyPackageDir):
sitePackagesDir = pyPackageDir
break
strippedPythonPath = "%s" % (sitePackagesDir) + strippedPythonPath
#strippedPythonPath = "%s/crlcore:" % (sitePackagesDir) + strippedPythonPath
#strippedPythonPath = "%s/cumulus:" % (sitePackagesDir) + strippedPythonPath
#strippedPythonPath = "%s/cumulus/plugins:" % (sitePackagesDir) + strippedPythonPath
#strippedPythonPath = "%s/stratus:" % (sitePackagesDir) + strippedPythonPath
#strippedPythonPath = "%s:" % (sysconfDir) + strippedPythonPath
strippedPythonPath = "%s:" % (sitePackagesDir) + strippedPythonPath
strippedPythonPath = "%s/crlcore:" % (sitePackagesDir) + strippedPythonPath
strippedPythonPath = "%s/cumulus:" % (sitePackagesDir) + strippedPythonPath
strippedPythonPath = "%s/cumulus/plugins:" % (sitePackagesDir) + strippedPythonPath
strippedPythonPath = "%s/stratus:" % (sitePackagesDir) + strippedPythonPath
strippedPythonPath = "%s:" % (sysconfDir) + strippedPythonPath
shellScriptSh += 'PYTHONPATH="%(PYTHONPATH)s";' \
'export PYTHONPATH;'
shellScriptCsh += 'setenv PYTHONPATH "%(PYTHONPATH)s";'

View File

@ -1,275 +0,0 @@
#!/usr/bin/env python3
import sys
import os
import os.path
from pathlib import Path
import socket
import subprocess
import re
import argparse
reCoriolisPattern = re.compile( r".*coriolis.*" )
reReleaseSharedPattern = re.compile( r".*Release\.Shared.*" )
reReleaseStaticPattern = re.compile( r".*Release\.Static.*" )
reDebugSharedPattern = re.compile( r".*Debug\.Shared.*" )
reDebugStaticPattern = re.compile( r".*Debug\.Static.*" )
def scrubPath ( pathName ):
"""
Remove from the PATH like environment variable ``pathName`` any
previous path item referring to a Coriolis location.
"""
if not pathName in os.environ: return ''
value = os.environ[ pathName ]
elements = value.split( ':' )
scrubbed = []
for element in elements:
if element == '': continue
if reCoriolisPattern .match(element) \
or reReleaseSharedPattern.match(element) \
or reReleaseStaticPattern.match(element) \
or reDebugSharedPattern .match(element) \
or reDebugStaticPattern .match(element):
continue
scrubbed.append( element )
if len(scrubbed) == 0: return ''
return ':'.join( scrubbed )
def envWriteBack ( pathName, pathValue ):
"""
Add to the environment PATH like variable ``pathName`` the components
given in ``pathValue`` and export it back. To avoid having multiple
Coriolis in the path, it is scrubbed beforehand.
"""
if pathName in os.environ:
scrubbed = scrubPath( pathName )
if scrubbed != '':
pathValue += ':' + scrubbed
os.environ[ pathName ] = pathValue
return pathValue
def setupPaths ( verbose, debug=False ):
"""
Guess and setup the main variables to use Coriolis:
* ``PATH``, to find the binaries.
* ``LD_LIBRARY_PATH``, to access the dynamic libraries.
* ``DYLD_LIBRARY_PATH``, same as above under MacOS.
* ``PYTHONPATH``, to access the various Python modules provided
by Coriolis.
:param verbose: Self explanatory.
:param debug: Use the version compiled with debugging support.
Be aware that it is roughly 4 times slower...
It's the tree rooted at ``Debug.Shared/install``
instead of ``Release.Shared/install``.
"""
# Setup CORIOLIS_TOP.
osEL9 = re.compile (".*Linux.*el9.*x86_64.*")
osSlsoc7x_64 = re.compile (".*Linux.*el7.*x86_64.*")
osSlsoc6x_64 = re.compile (".*Linux.*el6.*x86_64.*")
osSlsoc6x = re.compile (".*Linux.*(el|slsoc)6.*")
osSLSoC5x_64 = re.compile (".*Linux.*el5.*x86_64.*")
osSLSoC5x = re.compile (".*Linux.*(el5|2.6.23.13.*SoC).*")
osFedora_64 = re.compile (".*Linux.*fc.*x86_64.*")
osFedora = re.compile (".*Linux.*fc.*")
osLinux_64 = re.compile (".*Linux.*x86_64.*")
osLinux = re.compile (".*Linux.*")
osDarwin = re.compile (".*Darwin.*")
osUbuntu1004 = re.compile (".*Linux.*ubuntu.*")
osUbuntu1004_64 = re.compile (".*Linux.*ubuntu.*x86_64.*")
osFreeBSD8x_amd64 = re.compile (".*FreeBSD 8.*amd64.*")
osFreeBSD8x_64 = re.compile (".*FreeBSD 8.*x86_64.*")
osFreeBSD8x = re.compile (".*FreeBSD 8.*")
osCygwinW7_64 = re.compile (".*CYGWIN_NT-6\.1.*x86_64.*")
osCygwinW7 = re.compile (".*CYGWIN_NT-6\.1.*i686.*")
osCygwinW8_64 = re.compile (".*CYGWIN_NT-6\.[2-3].*x86_64.*")
osCygwinW8 = re.compile (".*CYGWIN_NT-6\.[2-3].*i686.*")
osCygwinW10_64 = re.compile (".*CYGWIN_NT-10\.[0-3].*x86_64.*")
osCygwinW10 = re.compile (".*CYGWIN_NT-10\.[0-3].*i686.*")
uname = subprocess.Popen( ["uname", "-srm"], stdout=subprocess.PIPE )
lines = uname.stdout.readlines()
line = lines[0].decode( 'ascii' )
if osSlsoc7x_64 .match(line): osDir = "Linux.el7_64"
elif osEL9 .match(line): osDir = "Linux.el9"
elif osSlsoc6x_64 .match(line): osDir = "Linux.slsoc6x_64"
elif osSlsoc6x .match(line): osDir = "Linux.slsoc6x"
elif osSLSoC5x_64 .match(line): osDir = "Linux.SLSoC5x_64"
elif osSLSoC5x .match(line): osDir = "Linux.SLSoC5x"
elif osFedora_64 .match(line): osDir = "Linux.fc_64"
elif osFedora .match(line): osDir = "Linux.fc"
elif osUbuntu1004 .match(line): osDir = "Linux.Ubuntu1004"
elif osUbuntu1004_64 .match(line): osDir = "Linux.Ubuntu1004_64"
elif osLinux_64 .match(line): osDir = "Linux.x86_64"
elif osLinux .match(line): osDir = "Linux.i386"
elif osFreeBSD8x_64 .match(line): osDir = "FreeBSD.8x.x86_64"
elif osFreeBSD8x_amd64.match(line): osDir = "FreeBSD.8x.amd64"
elif osFreeBSD8x .match(line): osDir = "FreeBSD.8x.i386"
elif osDarwin .match(line): osDir = "Darwin"
elif osCygwinW7_64 .match(line): osDir = "Cygwin.W7_64"
elif osCygwinW7 .match(line): osDir = "Cygwin.W7"
elif osCygwinW8_64 .match(line): osDir = "Cygwin.W8_64"
elif osCygwinW8 .match(line): osDir = "Cygwin.W8"
elif osCygwinW10_64 .match(line): osDir = "Cygwin.W10_64"
elif osCygwinW10 .match(line): osDir = "Cygwin.W10"
else:
uname = subprocess.Popen( ["uname", "-sr"], stdout=subprocess.PIPE )
osDir = uname.stdout.readlines()[0][:-1]
print( '[WARNING] environment.setupPaths(): Unrecognized OS: "{}".'.format( line[:-1] ))
print( ' (using: "{}")'.format( osDir ))
osDir = Path( osDir )
homeDir = Path( os.environ['HOME'] )
buildType = Path( 'Debug.Shared' if debug else 'Release.Shared' )
scriptPath = Path( __file__ ).resolve()
topDirs = []
topDirs += [ homeDir / 'coriolis-2.x' / osDir / buildType / 'install'
, Path( '/soc/coriolis2' )
, Path( '/usr' )
]
if not debug and 'CORIOLIS_TOP' in os.environ:
topDirs.insert( 0, Path( os.environ['CORIOLIS_TOP'] ))
for part in scriptPath.parts:
if part == 'nightly':
topDirs.insert( 0, homeDir / 'nightly' / 'coriolis-2.x' / osDir / buildType / 'install' )
break
if verbose:
print( ' o Self locating Coriolis:' )
coriolisTop = None
for topDir in topDirs:
if coriolisTop or not (topDir / 'bin' / 'cgt').is_file():
if verbose: print( ' - {}'.format(topDir) )
continue
if verbose: print( ' - {} *'.format(topDir) )
coriolisTop = topDir
if not coriolisTop:
print( '[ERROR] environment.setupPaths(): Unable to locate Coriolis.' )
return False
os.environ[ 'CORIOLIS_TOP' ] = coriolisTop.as_posix()
#if coriolisTop == '/usr': sysconfDir = Path( 'etc', 'coriolis2' )
#else: sysconfDir = coriolisTop / 'etc' / 'coriolis2'
if coriolisTop == '/usr': sysconfDir = Path( 'etc' )
else: sysconfDir = coriolisTop / 'etc'
# Setup PATH.
binPath = envWriteBack( 'PATH', (coriolisTop/'bin').as_posix() )
# Setup LD_LIBRARY_PATH.
libDirs = []
for lib in [ Path('lib'), Path('lib64') ]:
libDir = lib
absLibDir = coriolisTop / lib
if absLibDir.is_dir():
libDirs.append( absLibDir )
libDir = None
if not len(libDirs):
print( '[ERROR] environment.setupPaths(): Library directory not found.' )
return False
libraryPath = ''
ldPathName = 'LD_LIBRARY_PATH'
if osDir.as_posix().startswith( 'Darwin' ):
ldPathName = 'DYLD_LIBRARY_PATH'
for libDir in libDirs:
if len(libraryPath): libraryPath = libraryPath + ':'
libraryPath = libraryPath + libDir.as_posix()
libraryPath = envWriteBack( ldPathName, libraryPath )
# Setup PYTHONPATH.
v = sys.version_info
sitePackagesDir = None
for pyPackageDir in [ Path('python{}.{}'.format(v.major,v.minor)) / 'site-packages'
, Path('python{}.{}'.format(v.major,v.minor)) / 'dist-packages'
, Path('{}.{}'.format(v.major,v.minor)) / 'site-packages'
, Path('python{}'.format(v.major)) / 'site-packages'
, Path('python{}'.format(v.major)) / 'dist-packages'
, Path('{}'.format(v.major)) / 'site-packages'
]:
sitePackagesDir = libDirs[-1] / pyPackageDir
if sitePackagesDir.is_dir():
if verbose:
print( ' - {} *'.format(sitePackagesDir) )
break
if verbose:
print( ' - {}'.format(sitePackagesDir) )
sitePackagesDir = None
if sitePackagesDir is None:
print( '[ERROR] environment.setupPaths(): Python {site,dist}-packages directory not found.' )
return False
pythonPath = ''
for packageDir in [ sitePackagesDir
#, sitePackagesDir / 'crlcore'
#, sitePackagesDir / 'cumulus'
#, sitePackagesDir / 'cumulus/plugins'
#, sitePackagesDir / 'status'
#, sysconfDir
]:
sys.path.append( str(packageDir) )
if len(pythonPath): pythonPath += ':'
pythonPath += str(packageDir)
pythonPath = envWriteBack( 'PYTHONPATH', pythonPath )
return True
def printVariable ( name ):
if not name in os.environ:
print( '{}:'.format( name ))
print( '- variable_not_set' )
return
values = os.environ[ name ].split( ':' )
print( '{}:'.format( name ))
for value in values:
print( '- {}'.format( value ))
def printEnvironment ():
"""
Display the environment setup, using YAML formatting.
"""
print( '# crlenv.py: Alliance/Coriolis finder, guessed values.' )
print( '---' )
for name in ('CORIOLIS_TOP', 'PATH', 'DYLD_LIBRARY_PATH'
, 'LD_LIBRARY_PATH', 'PYTHONPATH'):
printVariable( name )
if __name__ == '__main__':
"""
Run any script in a environmnent set for Coriolis.
Example:
.. code:: bash
ego@home:~> crlenv.py -- doit clean_flow
b2v Run <blif2vst arlet6502 depends=[Arlet6502.blif]>.
cgt Run plain CGT (no loaded design)
clean_flow Clean all generated (targets) files.
gds Run <Alias "gds" for "pnr">.
pnr Run <pnr arlet6502_cts_r.gds depends=[arlet6502.vst,Arlet6502.spi]>.
yosys Run <yosys Arlet6502.v top=Arlet6502 blackboxes=[] flattens=[]>.
ego@home:~> crlenv.py -- bash
[ego@home]$ echo $CORIOLIS_TOP
/home/ego/coriolis-2.x/Linux.el9/Release.Shared/install
[ego@home]$ exit
ego@home:~>
"""
parser = argparse.ArgumentParser()
parser.add_argument( '-v', '--verbose', action='store_true', dest='verbose' )
parser.add_argument( '-d', '--debug' , action='store_true', dest='debug' )
parser.add_argument( 'command', nargs='*' )
args = parser.parse_args()
setupPaths( args.verbose, args.debug )
if not len(args.command):
printEnvironment()
sys.exit( 0 )
state = subprocess.run( args.command )
sys.exit( state.returncode )

View File

@ -234,13 +234,6 @@ class BenchsCommand ( CommandArg ):
return
class PyBenchsCommand ( CommandArg ):
def __init__ ( self, benchsDir, fdLog=None ):
CommandArg.__init__ ( self, [ '../bin/gopy.sh' ], wd=benchsDir, fdLog=fdLog )
return
class GitRepository ( object ):
@ -284,16 +277,6 @@ class GitRepository ( object ):
Command( [ 'git', 'checkout', branch ], self.fdLog ).execute()
return
def submoduleInit ( self ):
os.chdir( self.localRepoDir )
Command( [ 'git', 'submodule', 'init' ], self.fdLog ).execute()
return
def submoduleUpdate ( self ):
os.chdir( self.localRepoDir )
Command( [ 'git', 'submodule', 'update' ], self.fdLog ).execute()
return
class Configuration ( object ):
@ -303,7 +286,7 @@ class Configuration ( object ):
, 'homeDir' , 'masterHost'
, 'debugArg' , 'nightlyMode', 'dockerMode', 'chrootMode'
, 'rmSource' , 'rmBuild'
, 'doGit' , 'doAlliance' , 'doCoriolis', 'doBenchs', 'doPyBenchs', 'doSendReport'
, 'doGit' , 'doAlliance' , 'doCoriolis', 'doBenchs', 'doSendReport'
, 'success' , 'rcode'
]
SecondaryNames = \
@ -313,7 +296,7 @@ class Configuration ( object ):
def __init__ ( self ):
self._sender = 'Jean-Paul.Chaput@soc.lip6.fr'
self._receivers = [ 'Jean-Paul.Chaput@lip6.fr', ]
self._supportRepos = [ 'https://github.com/Tencent/rapidjson.git' ]
self._supportRepos = [ 'http://github.com/miloyip/rapidjson' ]
self._allianceRepo = 'https://gitlab.lip6.fr/jpc/alliance.git'
self._coriolisRepo = 'https://gitlab.lip6.fr/jpc/coriolis.git'
self._benchsRepo = 'https://gitlab.lip6.fr/jpc/alliance-check-toolkit.git'
@ -326,7 +309,6 @@ class Configuration ( object ):
self._doAlliance = False
self._doCoriolis = False
self._doBenchs = False
self._doPyBenchs = False
self._doSendReport = False
self._nightlyMode = False
self._dockerMode = False
@ -450,26 +432,25 @@ class Configuration ( object ):
raise ErrorMessage( 1, [ 'Cannot find <ccb.py>, should be here:'
, ' "{}"'.format(self.ccbBin)
] )
otherArgs = []
otherArgs = [ '--qt5' ]
if self.debugArg: otherArgs.append( self.debugArg )
if target == 'EL9':
#otherArgs.append( '--project=support' )
otherArgs.append( '--project=support' )
commands.append( CoriolisCommand( self.ccbBin, self.rootDir, 3, otherArgs , fdLog=self.fds['coriolis'] ) )
#commands.append( CoriolisCommand( self.ccbBin, self.rootDir, 1, otherArgs+['--doc'], fdLog=self.fds['coriolis'] ) )
if target == 'SL7_64':
otherArgs += [ '--project=support', '--qt4' ]
otherArgs.append( '--project=support' )
commands.append( CoriolisCommand( self.ccbBin, self.rootDir, 3, otherArgs , fdLog=self.fds['coriolis'] ) )
commands.append( CoriolisCommand( self.ccbBin, self.rootDir, 1, otherArgs+['--doc'], fdLog=self.fds['coriolis'] ) )
elif target == 'SL6_64' or target == 'SL6':
otherArgs += [ '--project=support', '--devtoolset=8', '--qt4' ]
otherArgs.append( '--project=support' )
otherArgs.append( '--devtoolset=8' )
commands.append( CoriolisCommand( self.ccbBin, self.rootDir, 6, otherArgs , fdLog=self.fds['coriolis'] ) )
commands.append( CoriolisCommand( self.ccbBin, self.rootDir, 1, otherArgs+['--doc'], fdLog=self.fds['coriolis'] ) )
elif target == 'Ubuntu18' or target == 'Debian9' or target == 'Debian10':
commands.append( CoriolisCommand( self.ccbBin, self.rootDir, 3, otherArgs, fdLog=self.fds['coriolis'] ) )
if self.doBenchs:
commands.append( BenchsCommand( self.benchsDir, fdLog=self.fds['benchs'] ) )
if self.doPyBenchs:
commands.append( PyBenchsCommand( self.benchsDir, fdLog=self.fds['benchs'] ) )
return commands
@ -551,8 +532,7 @@ parser.add_option ( "--do-report" , action="store_true" , dest=
parser.add_option ( "--nightly" , action="store_true" , dest="nightly" , help="Perform a nighly build." )
parser.add_option ( "--docker" , action="store_true" , dest="docker" , help="Perform a build inside a docker container." )
parser.add_option ( "--chroot" , action="store_true" , dest="chroot" , help="Perform a build inside a chrooted environment." )
parser.add_option ( "--benchs" , action="store_true" , dest="benchs" , help="Run the <alliance-checker-toolkit> sanity benchs (make)." )
parser.add_option ( "--pybenchs" , action="store_true" , dest="pybenchs" , help="Run the <alliance-checker-toolkit> sanity benchs (doit)." )
parser.add_option ( "--benchs" , action="store_true" , dest="benchs" , help="Run the <alliance-checker-toolkit> sanity benchs." )
parser.add_option ( "--rm-build" , action="store_true" , dest="rmBuild" , help="Remove the build/install directories." )
parser.add_option ( "--rm-source" , action="store_true" , dest="rmSource" , help="Remove the Git source repositories." )
parser.add_option ( "--rm-all" , action="store_true" , dest="rmAll" , help="Remove everything (source+build+install)." )
@ -573,7 +553,6 @@ try:
if options.doAlliance: conf.doAlliance = True
if options.doCoriolis: conf.doCoriolis = True
if options.benchs: conf.doBenchs = True
if options.pybenchs: conf.doPyBenchs = True
if options.doReport: conf.doSendReport = True
if options.rmSource or options.rmAll: conf.rmSource = True
if options.rmBuild or options.rmAll: conf.rmBuild = True
@ -583,7 +562,6 @@ try:
if conf.doAlliance: conf.openLog( 'alliance' )
if conf.doCoriolis: conf.openLog( 'coriolis' )
if conf.doBenchs: conf.openLog( 'benchs' )
if conf.doPyBenchs: conf.openLog( 'benchs' )
if conf.dockerMode: os.environ['USER'] = 'root'
gitSupports = []
@ -611,8 +589,6 @@ try:
if conf.rmSource: gitCoriolis.removeLocalRepo()
gitCoriolis.clone ()
gitCoriolis.checkout( 'devel' )
gitCoriolis.submoduleInit()
gitCoriolis.submoduleUpdate()
if conf.rmSource: gitBenchs.removeLocalRepo()
gitBenchs.clone()

View File

@ -6,7 +6,7 @@
option(BUILD_DOC "Build the documentation (doxygen)" OFF)
option(USE_LIBBFD "Link with BFD libraries to print stack traces" OFF)
cmake_minimum_required(VERSION 3.16)
cmake_minimum_required(VERSION 2.8.9)
set(ignoreVariables "${BUILD_DOC} ${CMAKE_INSTALL_DIR}")
@ -18,9 +18,9 @@
setup_boost(program_options)
setup_qt()
setup_qwt()
setup_python()
find_package(Libexecinfo REQUIRED)
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development)
find_package(PythonSitePackages REQUIRED)
find_package(LEFDEF REQUIRED)
find_package(FLUTE REQUIRED)

View File

@ -1,2 +1,2 @@
install ( FILES initHook.py DESTINATION ${Python_CORIOLISLIB}/bora )
install ( FILES boraInit.py DESTINATION ${Python_CORIOLISLIB}/bora )

View File

@ -2,10 +2,12 @@
try:
import sys
import os.path
from coriolis.helpers.io import ErrorMessage, WarningMessage, catch
import coriolis.Viewer
import helpers.io
from helpers.io import ErrorMessage
from helpers.io import WarningMessage
import Viewer
except Exception as e:
catch( e )
helpers.io.catch( e )
sys.exit( 1 )
@ -14,12 +16,12 @@ def boraHook ( **kw ):
if 'bora' in kw:
bora = kw['bora']
else:
print( ErrorMessage( 3, 'bora.initHook(): Must be run from a BoraEngine.' ))
print( ErrorMessage( 3, 'boraHook(): Must be run from a BoraEngine.' ))
return
try:
userInit = os.path.join( os.getcwd(), 'coriolis2/bora.py' )
if (os.path.exists(userInit)):
exec( open(userInit).read() )
except Exception as e:
catch( e )
helpers.io.catch( e )
return

View File

@ -111,17 +111,17 @@ namespace Bora {
void BoraEngine::_runBoraInit ()
{
Utilities::Path pythonSitePackages = System::getPath("pythonSitePackages");
Utilities::Path confFile = "coriolis/bora/initHook.py";
Utilities::Path systemConfFile = pythonSitePackages / confFile;
Utilities::Path systemConfDir = pythonSitePackages / "bora";
Utilities::Path systemConfFile = systemConfDir / "boraInit.py";
if (systemConfFile.exists()) {
//Isobar::Script::addPath( systemConfDir.toString() );
Isobar::Script::addPath( systemConfDir.toString() );
dbo_ptr<Isobar::Script> script = Isobar::Script::create( confFile.toPyModPath() );
dbo_ptr<Isobar::Script> script = Isobar::Script::create( systemConfFile.stem().toString() );
script->addKwArgument( "bora" , (PyObject*)PyBoraEngine_Link(this) );
script->runFunction ( "boraHook", getCell() );
//Isobar::Script::removePath( systemConfDir.toString() );
Isobar::Script::removePath( systemConfDir.toString() );
} else {
cerr << Warning( "Bora system configuration file:\n <%s> not found."
, systemConfFile.toString().c_str() ) << endl;

View File

@ -101,12 +101,12 @@
${QWT_LIBRARY}
${QtX_LIBRARIES}
${Boost_LIBRARIES}
-lutil
${Python_LIBRARIES} -lutil
)
add_library( bora ${cpps} ${mocCpps} ${pyCpps} )
set_target_properties( bora PROPERTIES VERSION 1.0 SOVERSION 1 )
target_link_libraries( bora ${depLibs} )
#target_link_libraries( bora ${depLibs} )
add_python_module( "${pyCpps}"
"${pyIncludes}"

View File

@ -1,7 +1,7 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) Sorbonne Université 2015-2023, All Rights Reserved
// Copyright (c) UPMC 2015-2018, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
@ -21,13 +21,6 @@
#include <QFrame>
#include <QHBoxLayout>
#include <QVBoxLayout>
//Work sround for older qwt releases
#include <QtGlobal>
#if QT_VERSION >= 0x050400
#define QT_STATIC_CONST static const
#endif
#include <qwt_scale_draw.h>
#include <qwt_scale_map.h>
#include <qwt_scale_widget.h>
@ -81,20 +74,11 @@ namespace Bora {
: QWidget (parent)
, _viewer (NULL)
, _plot (new QwtPlot ())
#if QWT_VERSION < 0x060000
, _picker (new QwtPlotPicker( QwtPlot::xBottom // X Axis id.
, QwtPlot::yLeft // Y Axis id.
, QwtPicker::PointSelection
, QwtPicker::CrossRubberBand
, QwtPicker::ActiveOnly
, _plot->canvas()) )
#else
, _picker (new QwtPlotPicker( QwtPlot::xBottom // X Axis id.
, QwtPlot::yLeft // Y Axis id.
, QwtPicker::CrossRubberBand
, QwtPicker::ActiveOnly
, _plot->canvas()) )
#endif
, _gridDisplay (new QGridLayout())
, _gridLabel () // Label line 2: text
, _widths (NULL) // Coordinates X for STreeCurve
@ -106,9 +90,7 @@ namespace Bora {
, _paretoCurve (new QwtPlotCurve("Pareto")) // Black curve: pareto curve
, _selectedPoint (new QwtPlotCurve("Selected")) // Red dot : selected placement
{
#if QWT_VERSION >= 0x060000
_picker->setStateMachine(new QwtPickerClickPointMachine());
#endif
setStyleSheet ( "border: 0px" );
int ptSize = Graphics::isHighDpi() ? 2 : 2;
@ -145,11 +127,7 @@ namespace Bora {
symbol->setStyle( QwtSymbol::Triangle );
symbol->setSize ( 6 );
symbol->setPen ( dotPen );
#if QWT_VERSION < 0x060000
_STreeCurve->setSymbol( *symbol );
#else
_STreeCurve->setSymbol( symbol );
#endif
QPen selectPen ( Qt::red );
selectPen.setWidth( ptSize+2 );
@ -157,11 +135,7 @@ namespace Bora {
_selectedPoint->setPen ( selectPen );
_selectedPoint->attach ( _plot );
#if QWT_VERSION < 0x060000
connect( _picker, SIGNAL(selected(const QwtDoublePoint&)), this, SLOT(onPointSelect(const QwtDoublePoint&)) );
#else
connect( _picker, SIGNAL(selected(const QPointF&)), this, SLOT(onPointSelect(const QPointF&)) );
#endif
QVBoxLayout* vLayout = new QVBoxLayout();
vLayout->addWidget ( _plot );
@ -289,13 +263,8 @@ namespace Bora {
i++;
}
#if QWT_VERSION < 0x060000
_STreeCurve->setData ( _widths , _heights , nodeSets->size() );
_paretoCurve->setData( _pareto.xs(), _pareto.ys(), _pareto.size() );
#else
_STreeCurve->setSamples ( _widths , _heights , nodeSets->size() );
_paretoCurve->setSamples( _pareto.xs(), _pareto.ys(), _pareto.size() );
#endif
_STreeCurve->show();
_paretoCurve->show();
_plot->replot();
@ -336,11 +305,7 @@ namespace Bora {
}
#if QWT_VERSION < 0x060000
void SlicingPlotWidget::onPointSelect ( const QwtDoublePoint& point )
#else
void SlicingPlotWidget::onPointSelect ( const QPointF& point )
#endif
{
// Clicking on SlicingTree's Pareto Graph:
// 1) Update slicing tree
@ -357,13 +322,8 @@ namespace Bora {
cdebug.log(539) << " Selection: [" << point.x() << " " << point.y() << "]" << endl;
if ( (iclosest >= 0) and (iclosest < dataSize) ) {
#if QWT_VERSION < 0x060000
double x = _STreeCurve->x( iclosest );
double y = _STreeCurve->y( iclosest );
#else
double x = _STreeCurve->sample( iclosest ).x();
double y = _STreeCurve->sample( iclosest ).y();
#endif
ostringstream message;
message << "(" << DbU::getValueString(x) << "," << DbU::getValueString(y) << ")";
@ -406,11 +366,7 @@ namespace Bora {
_widthSelected [0] = x;
_heightSelected[0] = y;
#if QWT_VERSION < 0x060000
_selectedPoint->setData ( _widthSelected, _heightSelected, 1 );
#else
_selectedPoint->setSamples ( _widthSelected, _heightSelected, 1 );
#endif
_selectedPoint->show();
_plot->replot();

View File

@ -1,7 +1,7 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) Sorbonne Université 2015-2023, All Rights Reserved
// Copyright (c) UPMC 2015-2018, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
@ -10,16 +10,12 @@
// | Authors : Jean-Paul Chaput, Eric LAO |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Header : "./bora/SlicingPlotWidget.h" |
// | C++ Header : "./bora/DSlicingNode.h" |
// +-----------------------------------------------------------------+
#pragma once
//Work sround for older qwt releases
#include <QtGlobal>
#if QT_VERSION >= 0x050400
#define QT_STATIC_CONST static const
#endif
#ifndef BORA_SLICING_PLOT_WIDGET_H
#define BORA_SLICING_PLOT_WIDGET_H
#include <vector>
#include <qwt_plot.h>
@ -53,11 +49,7 @@ namespace Bora {
void setViewer ( CellViewer* );
void setDatas ();
public slots:
#if QWT_VERSION < 0x060000
void onPointSelect ( const QwtDoublePoint& );
#else
void onPointSelect ( const QPointF& );
#endif
void updateSelectedPoint ( double x, double y );
signals:
void updatePlacement ( BoxSet* );
@ -80,3 +72,5 @@ namespace Bora {
} // Bora namespace.
#endif // BORA_SLICING_PLOT_WIDGET_H

View File

@ -1,147 +0,0 @@
import io
import glob
import ninja
import os
import platform
import re
import subprocess
import sys
from distutils.version import LooseVersion
from distutils.dir_util import copy_tree, remove_tree
from distutils.sysconfig import get_python_inc
from distutils import sysconfig
from typing import Any, Dict
from setuptools.command.build_ext import build_ext
from setuptools.extension import Extension
class CMakeExtension(Extension):
name: str # exists, even though IDE doesn't find it
def __init__(self, name: str, sourcedir: str="") -> None:
super().__init__(name, sources=[])
self.sourcedir = os.path.abspath(sourcedir)
self.sourcedir_rel = sourcedir
class ExtensionBuilder(build_ext):
def run(self) -> None:
self.validate_cmake()
super().run()
def build_extension(self, ext: Extension) -> None:
if isinstance(ext, CMakeExtension):
self.build_cmake_extension(ext)
else:
super().build_extension(ext)
def validate_cmake(self) -> None:
cmake_extensions = [x for x in self.extensions if isinstance(x, CMakeExtension)]
if len(cmake_extensions) > 0:
try:
out = subprocess.check_output(["cmake", "--version"])
except OSError:
raise RuntimeError(
"CMake must be installed to build the following extensions: "
+ ", ".join(e.name for e in cmake_extensions)
)
if platform.system() == "Windows":
cmake_version = LooseVersion(re.search(r"version\s*([\d.]+)", out.decode()).group(1)) # type: ignore
if cmake_version < "3.1.0":
raise RuntimeError("CMake >= 3.1.0 is required on Windows")
def build_cmake_extension(self, ext: CMakeExtension) -> None:
extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))
cmake_args = []
ninja_executable_path = os.path.join(ninja.BIN_DIR, "ninja")
cmake_args += ["-GNinja","-DCMAKE_MAKE_PROGRAM:FILEPATH=" + ninja_executable_path]
cfg = "Debug" if self.debug else "Release"
# cfg = 'Debug'
build_args = ["--config", cfg]
install_args = ["--config", cfg]
cmake_args += ["-DCMAKE_BUILD_TYPE=" + cfg]
if platform.system() == "Windows":
if sys.maxsize > 2 ** 32:
cmake_args += ["-A", "x64"]
env = os.environ.copy()
env["CXXFLAGS"] = '{} -DVERSION_INFO=\\"{}\\"'.format(env.get("CXXFLAGS", ""), self.distribution.get_version())
build_dir = os.path.join(self.build_temp, ext.sourcedir_rel)
install_dir = os.path.join(extdir, 'Coriolis')
os.makedirs(build_dir,exist_ok=True)
cmake_args += [f"-DCMAKE_MODULE_PATH={os.path.abspath('bootstrap/cmake_modules')};"
f"{os.path.join(install_dir, 'share/cmake/Modules')}"]
cmake_args += [f"-DCMAKE_INSTALL_PREFIX={install_dir}"]
cmake_args += [f"-DPython_CORIOLISLIB={install_dir}"]
cmake_args += [f"-DPython_CORIOLISARCH={install_dir}"]
cmake_args += [f"-DSYS_CONF_DIR={install_dir}"]
cmake_args += [f"-DCORIOLIS_TOP={install_dir}"]
cmake_args += [f"-DCORIOLIS_USER_TOP={install_dir}"]
cmake_args += [f"-DPython_EXECUTABLE={sys.executable}"]
cmake_args += ["-DPOETRY=1"]
cmake_args += ["-DWITH_QT5=1"]
cmake_args += ["-DCMAKE_BUILD_RPATH_USE_ORIGIN=1"]
cmake_args += ["-DCMAKE_SKIP_BUILD_RPATH=FALSE"]
cmake_args += ["-DCMAKE_BUILD_WITH_INSTALL_RPATH=FALSE"]
cmake_args += ["-DCMAKE_INSTALL_RPATH='$ORIGIN/lib:$ORIGIN'"]
cmake_args += ["-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=TRUE"]
print(f"Using cmake args: {cmake_args}")
subprocess.check_call(["cmake", "--trace-redirect=build.cmake.trace", "--trace-expand", ext.sourcedir] + cmake_args, cwd=build_dir, env=env)
subprocess.check_call(["cmake", "--build", "."] + build_args, cwd=build_dir)
subprocess.check_call(["cmake", "--install", ".", "--prefix", install_dir] + install_args, cwd=build_dir)
if os.path.exists(os.path.join(install_dir, "bin")):
copy_tree(os.path.join(install_dir, "bin"), os.path.join(install_dir,"data/bin"))
remove_tree(os.path.join(install_dir, "bin"))
proc = subprocess.Popen(['file'] + glob.glob(os.path.join(install_dir,"data/bin/*")), stdout=subprocess.PIPE)
for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"):
if 'ELF' in line: #TODO support other OSs
f = line.split(':')[0]
print(f"fixing up {f}")
subprocess.check_call(["patchelf", "--set-rpath", '$ORIGIN/../../lib', f])
# Remove docs
if os.path.exists(os.path.join(install_dir, "share", "doc")):
remove_tree(os.path.join(install_dir, "share", "doc"))
def build(setup_kwargs: Dict[str, Any]) -> None:
cmake_modules = [
CMakeExtension("coloquinte", sourcedir="coloquinte"),
CMakeExtension("Hurricane", sourcedir="hurricane"),
CMakeExtension("crlcore", sourcedir="crlcore"),
CMakeExtension("flute", sourcedir="flute"),
CMakeExtension("etesian", sourcedir="etesian"),
CMakeExtension("anabatic", sourcedir="anabatic"),
CMakeExtension("katana", sourcedir="katana"),
CMakeExtension("equinox", sourcedir="equinox"),
CMakeExtension("solstice", sourcedir="solstice"),
CMakeExtension("oroshi", sourcedir="oroshi"),
CMakeExtension("bora", sourcedir="bora"),
CMakeExtension("karakaze", sourcedir="karakaze"),
#CMakeExtension("knik", sourcedir="knik"),
#CMakeExtension("unicorn", sourcedir="unicorn"),
CMakeExtension("tutorial", sourcedir="tutorial"),
CMakeExtension("cumulus", sourcedir="cumulus"),
CMakeExtension("stratus1", sourcedir="stratus1"),
CMakeExtension("documentation", sourcedir="documentation"),
CMakeExtension("unittests", sourcedir="unittests")
]
ext_modules = cmake_modules
setup_kwargs.update(
{
"ext_modules": ext_modules,
"cmdclass": dict(build_ext=ExtensionBuilder),
"zip_safe": False,
}
)

@ -1 +0,0 @@
Subproject commit 97bb781ba363303fd6b7254c717f621b137b89e3

34
coloquinte/CMakeLists.txt Normal file
View File

@ -0,0 +1,34 @@
# -*- explicit-buffer-name: "CMakeLists.txt<coloquinte>" -*-
set(CMAKE_LEGACY_CYGWIN_WIN32 0)
project(COLOQUINTE)
set(ignoreVariables "${CMAKE_INSTALL_DIR}" "${BUILD_DOC}")
#option(BUILD_DOC "Build the documentation (doxygen)" OFF)
option(USE_LIBBFD "Link with BFD libraries to print stack traces" OFF)
cmake_minimum_required(VERSION 2.8.9)
list(INSERT CMAKE_MODULE_PATH 0 "${DESTDIR}$ENV{CORIOLIS_TOP}/share/cmake/Modules/")
find_package(Bootstrap REQUIRED)
setup_project_paths(CORIOLIS)
setup_qt()
set_cmake_policies()
setup_boost()
find_package(Libexecinfo REQUIRED)
find_package(Doxygen)
if(WITH_OPENMP)
find_package(OpenMP REQUIRED)
add_definitions(${OpenMP_CXX_FLAGS})
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${OpenMP_CXX_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${OpenMP_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_CXX_FLAGS}")
endif()
add_subdirectory(src)
add_subdirectory(cmake_modules)
#add_subdirectory(doc)

View File

@ -0,0 +1,2 @@
install ( FILES FindCOLOQUINTE.cmake DESTINATION share/cmake/Modules )

View File

@ -15,14 +15,13 @@ IF(UNIX)
#
# Look for an installation.
#
FIND_PATH(COLOQUINTE_INCLUDE_PATH NAMES coloquinte/coloquinte.hpp PATHS
FIND_PATH(COLOQUINTE_INCLUDE_PATH NAMES coloquinte/netlist.hxx PATHS
# Look in other places.
${CORIOLIS_DIR_SEARCH}
PATH_SUFFIXES include/coriolis2
# Help the user find it if we cannot.
DOC "The ${COLOQUINTE_INCLUDE_PATH_DESCRIPTION}"
)
MESSAGE( "COL ${COLOQUINTE_INCLUDE_PATH}" )
FIND_LIBRARY(COLOQUINTE_LIBRARY_PATH
NAMES coloquinte

View File

@ -0,0 +1,39 @@
# -*- explicit-buffer-name: "CMakeLists.txt<coloquinte/src>" -*-
include_directories( ${COLOQUINTE_SOURCE_DIR}/src
)
set ( includes coloquinte/circuit.hxx
coloquinte/circuit_helper.hxx
coloquinte/common.hxx
coloquinte/netlist.hxx
coloquinte/solvers.hxx
coloquinte/rough_legalizers.hxx
coloquinte/legalizer.hxx
coloquinte/detailed.hxx
coloquinte/topologies.hxx
coloquinte/optimization_subproblems.hxx
coloquinte/piecewise_linear.hxx
)
set ( cpps circuit.cxx
checkers.cxx
rough_legalizers.cxx
solvers.cxx
optimization_subproblems.cxx
piecewise_linear.cxx
orientation.cxx
detailed.cxx
cell_swapping.cxx
#MCF_opt.cxx
row_opt.cxx
topologies.cxx
lookup_table.cxx
legalizer.cxx
)
add_library ( coloquinte ${cpps} )
set_target_properties( coloquinte PROPERTIES VERSION 1.0 SOVERSION 1 )
install( TARGETS coloquinte DESTINATION lib${LIB_SUFFIX} )
install( FILES ${includes} DESTINATION include/coriolis2/coloquinte )

View File

@ -0,0 +1,185 @@
#include "coloquinte/detailed.hxx"
#include "coloquinte/circuit_helper.hxx"
#include <functional>
namespace coloquinte{
namespace dp{
namespace{
// Tries to swap two cells;
inline bool try_swap(netlist const & circuit, detailed_placement & pl, index_t c1, index_t c2, bool try_flip,
std::function<std::int64_t(netlist const &, detailed_placement const &, std::vector<index_t> const &)> get_nets_cost){
assert(pl.cell_height(c1) == 1 and pl.cell_height(c2) == 1);
assert( (circuit.get_cell(c1).attributes & XMovable) != 0 and (circuit.get_cell(c1).attributes & YMovable) != 0);
assert( (circuit.get_cell(c2).attributes & XMovable) != 0 and (circuit.get_cell(c2).attributes & YMovable) != 0);
auto c1_bnds = pl.get_limit_positions(circuit, c1),
c2_bnds = pl.get_limit_positions(circuit, c2);
// Get the possible positions for a swap
int_t swp_min_c1 = c2_bnds.first,
swp_min_c2 = c1_bnds.first,
swp_max_c1 = c2_bnds.second - circuit.get_cell(c1).size.x,
swp_max_c2 = c1_bnds.second - circuit.get_cell(c2).size.x;
if(swp_max_c1 >= swp_min_c1 and swp_max_c2 >= swp_min_c2){
// Check both orientations of the cell
// Get all the nets involved and uniquify them (nets with more than one pin on the cells)
std::vector<index_t> involved_nets;
for(netlist::pin_t p : circuit.get_cell(c1)){
involved_nets.push_back(p.net_ind);
}
for(netlist::pin_t p : circuit.get_cell(c2)){
involved_nets.push_back(p.net_ind);
}
std::sort(involved_nets.begin(), involved_nets.end());
involved_nets.resize(std::distance(involved_nets.begin(), std::unique(involved_nets.begin(), involved_nets.end())));
// Test the cost for the old position and the cost swapping the cells
std::int64_t old_cost = get_nets_cost(circuit, pl, involved_nets);
// Save the old values
point<int_t> p1 = pl.plt_.positions_[c1];
point<int_t> p2 = pl.plt_.positions_[c2];
point<bool> o1 = pl.plt_.orientations_[c1];
point<bool> o2 = pl.plt_.orientations_[c2];
// Warning: won't work if the two cells don't have the same height
pl.plt_.positions_[c1].x = (swp_min_c1 + swp_max_c1) / 2;
pl.plt_.positions_[c2].x = (swp_min_c2 + swp_max_c2) / 2;
pl.plt_.positions_[c1].y = p2.y;
pl.plt_.positions_[c2].y = p1.y;
// For standard cell placement, we want all the rows to be aligned in the same way
if( (circuit.get_cell(c1).attributes & YFlippable) != 0 and (circuit.get_cell(c2).attributes & YFlippable) != 0)
std::swap(pl.plt_.orientations_[c1].y, pl.plt_.orientations_[c2].y);
if(try_flip and (circuit.get_cell(c1).attributes & XFlippable) != 0 and (circuit.get_cell(c2).attributes & XFlippable) != 0){
index_t bst_ind = 4;
for(index_t i=0; i<4; ++i){
pl.plt_.orientations_[c1].x = i % 2;
pl.plt_.orientations_[c2].x = i / 2;
std::int64_t new_cost = get_nets_cost(circuit, pl, involved_nets);
if(new_cost < old_cost){
old_cost = new_cost;
bst_ind = i;
}
}
// One of the orientations with the new positions was better
if(bst_ind < 4){
pl.swap_standard_cell_topologies(c1, c2);
pl.plt_.orientations_[c1].x = bst_ind % 2;
pl.plt_.orientations_[c2].x = bst_ind / 2;
// We kept the swap
return true;
}
else{
pl.plt_.positions_[c1] = p1;
pl.plt_.positions_[c2] = p2;
pl.plt_.orientations_[c1] = o1;
pl.plt_.orientations_[c2] = o2;
return false;
}
}
else if(get_nets_cost(circuit, pl, involved_nets) < old_cost){
pl.swap_standard_cell_topologies(c1, c2);
return true;
}
else{
// Reset the old values since we didn't swap anything
pl.plt_.positions_[c1] = p1;
pl.plt_.positions_[c2] = p2;
pl.plt_.orientations_[c1] = o1;
pl.plt_.orientations_[c2] = o2;
return false;
}
// A better solution would be
// Check the cost on y depending on the position (extremely simple: two positions for each cell)
// Check the cost on x depending on the position: piecewise linear and relatively complex
// * Get all external pins
// * Get all nets involving only one of the cells: piecewise linear cost for each of them
// * For nets involving the two cells, we have an additional cost
}
else{ // We just cannot swap those two cells without pushing anything
return false;
}
}
inline void generic_swaps_global(netlist const & circuit, detailed_placement & pl, index_t row_extent, index_t cell_extent, bool try_flip,
std::function<std::int64_t(netlist const &, detailed_placement const &, std::vector<index_t> const &)> get_nets_cost){
for(index_t main_row = 0; main_row < pl.row_cnt(); ++main_row){
for(index_t other_row = main_row+1; other_row <= std::min(pl.row_cnt()-1, main_row+row_extent) ; ++other_row){
index_t first_oc = pl.get_first_standard_cell_on_row(other_row); // The first candidate cell to be examined
for(index_t c = pl.get_first_standard_cell_on_row(main_row); c != null_ind; c = pl.get_next_standard_cell_on_row(c, main_row)){
assert(pl.cell_rows_[c] == main_row);
if( (circuit.get_cell(c).attributes & XMovable) == 0) continue; // Don't touch fixed cells
// Number of cells after/before the end of the cell
index_t nb_after = 0;
index_t nb_before = 0;
int_t pos_low = pl.plt_.positions_[c].x - circuit.get_cell(c).size.x,
pos_hgh = pl.plt_.positions_[c].x + 2*circuit.get_cell(c).size.x;
for(index_t oc=first_oc; oc != null_ind and nb_after <= row_extent; oc = pl.get_next_standard_cell_on_row(oc, other_row)){
assert(pl.cell_rows_[oc] == other_row);
if( (circuit.get_cell(oc).attributes & XMovable) == 0) continue; // Don't touche fixed cells
// Count the cells which should trigger stop or shouldn't be used at the next iteration
if(pl.plt_.positions_[oc].x >= pos_hgh) ++nb_after;
if(pl.plt_.positions_[oc].x + circuit.get_cell(oc).size.x <= pos_low) ++ nb_before;
if(try_swap(circuit, pl, c, oc, try_flip, get_nets_cost)){
std::swap(c, oc);
if(c == first_oc) first_oc = oc;
}
}
while(nb_before > cell_extent){
nb_before--;
first_oc = pl.get_next_standard_cell_on_row(first_oc, other_row);
}
}
}
}
pl.selfcheck();
}
} // End anonymous namespace
void swaps_global_HPWL(netlist const & circuit, detailed_placement & pl, index_t row_extent, index_t cell_extent, bool try_flip){
generic_swaps_global(circuit, pl, row_extent, cell_extent, try_flip,
[](netlist const & circuit, detailed_placement const & pl, std::vector<index_t> const & involved_nets) -> std::int64_t{
std::int64_t sum = 0;
for(index_t n : involved_nets){
if(circuit.get_net(n).pin_cnt <= 1) continue;
sum += get_HPWL_length(circuit, pl.plt_, n);
}
return sum;
});
}
void swaps_global_RSMT(netlist const & circuit, detailed_placement & pl, index_t row_extent, index_t cell_extent, bool try_flip){
generic_swaps_global(circuit, pl, row_extent, cell_extent, try_flip,
[](netlist const & circuit, detailed_placement const & pl, std::vector<index_t> const & involved_nets) -> std::int64_t{
std::int64_t sum = 0;
for(index_t n : involved_nets){
if(circuit.get_net(n).pin_cnt <= 1) continue;
sum += get_RSMT_length(circuit, pl.plt_, n);
}
return sum;
});
}
} // namespace dp
} // namespace coloquinte

View File

@ -0,0 +1,96 @@
#include "coloquinte/circuit.hxx"
#include <map>
namespace coloquinte{
void netlist::selfcheck() const{
index_t cell_cnt = cell_areas_.size();
assert(cell_cnt+1 == cell_limits_.size());
assert(cell_cnt == cell_sizes_.size());
assert(cell_cnt == cell_attributes_.size());
assert(cell_cnt == cell_internal_mapping_.size());
index_t net_cnt = net_weights_.size();
assert(net_cnt+1 == net_limits_.size());
assert(net_cnt == net_internal_mapping_.size());
index_t pin_cnt = pin_offsets_.size();
assert(pin_cnt == cell_indexes_.size());
assert(pin_cnt == pin_indexes_.size());
assert(pin_cnt == net_indexes_.size());
for(auto const p : pin_offsets_){
assert(std::isfinite(p.x) and std::isfinite(p.y));
}
}
// For compatibility reasons
void placement_t::selfcheck() const{
}
void verify_placement_legality(netlist const & circuit, placement_t const & pl, box<int_t> surface){
std::vector<box<int_t> > cells;
for(index_t i=0; i<circuit.cell_cnt(); ++i){
auto S = circuit.get_cell(i).size;
cells.push_back(box<int_t>(pl.positions_[i], pl.positions_[i] + S));
// Verify that they are within the placement surface; doesn't take fixed macros into account
if( (circuit.get_cell(i).attributes & XMovable) != 0 or (circuit.get_cell(i).attributes & YMovable) != 0){
assert(cells[i].in(surface));
}
}
// Simple sweepline algorithm to verify that there is no overlap
struct event{
int_t x_min, x_max, y;
index_t cell;
bool removal;
bool operator<(event const o) const{
return y < o.y
or (y == o.y and removal and not o.removal); // Remove before inserting
}
};
std::vector<event> all_events;
for(index_t i=0; i<circuit.cell_cnt(); ++i){
event b, e;
b.cell = i; e.cell = i;
b.x_min = cells[i].x_min; e.x_min = cells[i].x_min;
b.x_max = cells[i].x_max; e.x_max = cells[i].x_max;
b.y = cells[i].y_min; b.removal = false;
e.y = cells[i].y_max; e.removal = true;
if(b.x_max > b.x_min and e.y != b.y){
all_events.push_back(b);
all_events.push_back(e);
}
}
std::sort(all_events.begin(), all_events.end());
// Indexed by beginning of interval, with end of interval and cell within
std::map<int_t, std::pair<int_t, index_t> > active_rectangles;
for(event E : all_events){
if(E.removal){
auto it = active_rectangles.find(E.x_min);
assert(it != active_rectangles.end());
active_rectangles.erase(it);
}
else{ // Find anything that intersects with E; if not, add it
auto it = active_rectangles.lower_bound(E.x_min); // First interval after
if(it != active_rectangles.end()){
assert(it->first >= E.x_max); //Intersection between E.cell and it->second->second
}
if(it != active_rectangles.begin()){
--it;
assert(it->second.first <= E.x_min); //Intersection between E.cell and it->second->second
}
active_rectangles.insert(std::pair<int_t, std::pair<int_t, index_t> >(E.x_min, std::pair<int_t, index_t>(E.x_max, E.cell)));
}
}
}
} // namespace coloquinte

408
coloquinte/src/circuit.cxx Normal file
View File

@ -0,0 +1,408 @@
#include "coloquinte/circuit_helper.hxx"
#include "coloquinte/circuit.hxx"
#include <cmath>
namespace coloquinte{
std::int64_t get_HPWL_length(netlist const & circuit, placement_t const & pl, index_t net_ind){
if(circuit.get_net(net_ind).pin_cnt <= 1) return 0;
auto pins = get_pins_1D(circuit, pl, net_ind);
auto minmaxX = std::minmax_element(pins.x.begin(), pins.x.end()), minmaxY = std::minmax_element(pins.y.begin(), pins.y.end());
return ((minmaxX.second->pos - minmaxX.first->pos) + (minmaxY.second->pos - minmaxY.first->pos));
}
std::int64_t get_RSMT_length(netlist const & circuit, placement_t const & pl, index_t net_ind){
if(circuit.get_net(net_ind).pin_cnt <= 1) return 0;
auto pins = get_pins_2D(circuit, pl, net_ind);
std::vector<point<int_t> > points;
for(pin_2D const p : pins){
points.push_back(p.pos);
}
return RSMT_length(points, 8);
}
namespace gp{
void add_force(pin_1D const p1, pin_1D const p2, linear_system & L, float_t force){
if(p1.movable && p2.movable){
L.add_force(
force,
p1.cell_ind, p2.cell_ind,
p1.offs, p2.offs
);
}
else if(p1.movable){
L.add_fixed_force(
force,
p1.cell_ind,
p2.pos,
p1.offs
);
}
else if(p2.movable){
L.add_fixed_force(
force,
p2.cell_ind,
p1.pos,
p2.offs
);
}
}
void add_force(pin_1D const p1, pin_1D const p2, linear_system & L, float_t tol, float_t scale){
add_force(p1, p2, L, scale/std::max(tol, static_cast<float_t>(std::abs((float)(p2.pos-p1.pos)))));
}
point<linear_system> empty_linear_systems(netlist const & circuit, placement_t const & pl){
point<linear_system> ret = point<linear_system>(linear_system(circuit.cell_cnt()), linear_system(circuit.cell_cnt()));
for(index_t i=0; i<circuit.cell_cnt(); ++i){
bool found_true_net=false;
for(auto p : circuit.get_cell(i)){
if(circuit.get_net(p.net_ind).pin_cnt > 1){
found_true_net = true;
break;
}
}
if( (XMovable & circuit.get_cell(i).attributes) == 0 or not found_true_net){
ret.x.add_triplet(i, i, 1.0f);
ret.x.add_doublet(i, pl.positions_[i].x);
}
if( (YMovable & circuit.get_cell(i).attributes) == 0 or not found_true_net){
ret.y.add_triplet(i, i, 1.0f);
ret.y.add_doublet(i, pl.positions_[i].y);
}
}
return ret;
}
namespace{ // Anonymous namespace for helper functions
void get_HPWLF(std::vector<pin_1D> const & pins, linear_system & L, float_t tol){
if(pins.size() >= 2){
auto min_elt = std::min_element(pins.begin(), pins.end()), max_elt = std::max_element(pins.begin(), pins.end());
for(auto it = pins.begin(); it != pins.end(); ++it){
// Just comparing the iterator is poorer due to redundancies in the benchmarks!
if(it != min_elt){
add_force(*it, *min_elt, L, tol, 1.0f/(pins.size()-1));
if(it != max_elt){ // Hopefully only one connexion between the min and max pins
add_force(*it, *max_elt, L, tol, 1.0f/(pins.size()-1));
}
}
}
}
}
void get_HPWLR(std::vector<pin_1D> const & pins, linear_system & L, float_t tol){
std::vector<pin_1D> sorted_pins = pins;
std::sort(sorted_pins.begin(), sorted_pins.end());
// Pins are connected to the pin two places away
for(index_t i=0; i+2<sorted_pins.size(); ++i){
add_force(sorted_pins[i], sorted_pins[i+2], L, tol, 0.5f);
}
// The extreme pins are connected with their direct neighbour too
if(sorted_pins.size() > 1){
add_force(sorted_pins[0], sorted_pins[1], L, tol, 0.5f);
add_force(sorted_pins[sorted_pins.size()-1], sorted_pins[sorted_pins.size()-2], L, tol, 0.5f);
}
}
void get_star(std::vector<pin_1D> const & pins, linear_system & L, float_t tol, index_t star_index){
// The net is empty, but we still populate the diagonal to avoid divide by zeros
if(pins.size() < 2){
L.add_triplet(star_index, star_index, 1.0f);
return;
}
for(pin_1D p : pins){
pin_1D star_pin = pin_1D(star_index, 0, 0, true);
add_force(p, star_pin, L, 1.0/pins.size());
}
}
void get_clique(std::vector<pin_1D> const & pins, linear_system & L, float_t tol){
// Pins are connected to the pin two places away
for(index_t i=0; i+1<pins.size(); ++i){
for(index_t j=i+1; j<pins.size(); ++j){
add_force(pins[i], pins[j], L, tol, 1.0f/(pins.size()-1));
}
}
}
} // End anonymous namespace
point<linear_system> get_HPWLF_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){
point<linear_system> L = empty_linear_systems(circuit, pl);
for(index_t i=0; i<circuit.net_cnt(); ++i){
// Has the net the right pin count?
index_t pin_cnt = circuit.get_net(i).pin_cnt;
if(pin_cnt < min_s or pin_cnt >= max_s) continue;
auto pins = get_pins_1D(circuit, pl, i);
get_HPWLF(pins.x, L.x, tol);
get_HPWLF(pins.y, L.y, tol);
}
return L;
}
point<linear_system> get_HPWLR_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){
point<linear_system> L = empty_linear_systems(circuit, pl);
for(index_t i=0; i<circuit.net_cnt(); ++i){
// Has the net the right pin count?
index_t pin_cnt = circuit.get_net(i).pin_cnt;
if(pin_cnt < min_s or pin_cnt >= max_s) continue;
auto pins = get_pins_1D(circuit, pl, i);
get_HPWLR(pins.x, L.x, tol);
get_HPWLR(pins.y, L.y, tol);
}
return L;
}
point<linear_system> get_star_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){
point<linear_system> L = empty_linear_systems(circuit, pl);
L.x.add_variables(circuit.net_cnt());
L.y.add_variables(circuit.net_cnt());
for(index_t i=0; i<circuit.net_cnt(); ++i){
// Has the net the right pin count?
index_t pin_cnt = circuit.get_net(i).pin_cnt;
if(pin_cnt < min_s or pin_cnt >= max_s){
// Put a one in the intermediate variable in order to avoid non-invertible matrices
L.x.add_triplet(i+circuit.cell_cnt(), i+circuit.cell_cnt(), 1.0f);
L.y.add_triplet(i+circuit.cell_cnt(), i+circuit.cell_cnt(), 1.0f);
continue;
}
auto pins = get_pins_1D(circuit, pl, i);
// Provide the index of the star's central pin in the linear system
get_star(pins.x, L.x, tol, i+circuit.cell_cnt());
get_star(pins.y, L.y, tol, i+circuit.cell_cnt());
}
return L;
}
point<linear_system> get_clique_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){
point<linear_system> L = empty_linear_systems(circuit, pl);
for(index_t i=0; i<circuit.net_cnt(); ++i){
// Has the net the right pin count?
index_t pin_cnt = circuit.get_net(i).pin_cnt;
if(pin_cnt < min_s or pin_cnt >= max_s) continue;
auto pins = get_pins_1D(circuit, pl, i);
get_clique(pins.x, L.x, tol);
get_clique(pins.y, L.y, tol);
}
return L;
}
point<linear_system> get_MST_linear_system(netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){
point<linear_system> L = empty_linear_systems(circuit, pl);
for(index_t i=0; i<circuit.net_cnt(); ++i){
// Has the net the right pin count?
index_t pin_cnt = circuit.get_net(i).pin_cnt;
if(pin_cnt < min_s or pin_cnt >= max_s or pin_cnt <= 1) continue;
auto pins = get_pins_2D(circuit, pl, i);
std::vector<point<int_t> > points;
for(pin_2D const p : pins){
points.push_back(p.pos);
}
auto const edges = get_MST_topology(points);
for(auto E : edges){
add_force(pins[E.first].x(), pins[E.second].x(), L.x, tol, 1.0f);
add_force(pins[E.first].y(), pins[E.second].y(), L.y, tol, 1.0f);
}
}
return L;
}
point<linear_system> get_RSMT_linear_system(netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){
point<linear_system> L = empty_linear_systems(circuit, pl);
for(index_t i=0; i<circuit.net_cnt(); ++i){
// Has the net the right pin count?
index_t pin_cnt = circuit.get_net(i).pin_cnt;
if(pin_cnt < min_s or pin_cnt >= max_s or pin_cnt <= 1) continue;
auto pins = get_pins_2D(circuit, pl, i);
std::vector<point<int_t> > points;
for(pin_2D const p : pins){
points.push_back(p.pos);
}
auto const edges = get_RSMT_topology(points, 8);
for(auto E : edges.x){
add_force(pins[E.first].x(), pins[E.second].x(), L.x, tol, 1.0f);
}
for(auto E : edges.y){
add_force(pins[E.first].y(), pins[E.second].y(), L.y, tol, 1.0f);
}
}
return L;
}
std::int64_t get_HPWL_wirelength(netlist const & circuit, placement_t const & pl){
std::int64_t sum = 0;
for(index_t i=0; i<circuit.net_cnt(); ++i){
sum += get_HPWL_length(circuit, pl, i);
}
return sum;
}
// The true wirelength with minimum spanning trees, except for very small nets (<= 3) where we have HPWL == true WL
std::int64_t get_MST_wirelength(netlist const & circuit, placement_t const & pl){
std::int64_t sum = 0;
for(index_t i=0; i<circuit.net_cnt(); ++i){
auto pins = get_pins_2D(circuit, pl, i);
std::vector<point<int_t> > points;
for(pin_2D const p : pins){
points.push_back(p.pos);
}
sum += MST_length(points);
}
return sum;
}
std::int64_t get_RSMT_wirelength(netlist const & circuit, placement_t const & pl){
std::int64_t sum = 0;
for(index_t i=0; i<circuit.net_cnt(); ++i){
sum += get_RSMT_length(circuit, pl, i);
}
return sum;
}
void solve_linear_system(netlist const & circuit, placement_t & pl, point<linear_system> & L, index_t nbr_iter){
std::vector<float_t> x_sol, y_sol;
std::vector<float_t> x_guess(pl.cell_cnt()), y_guess(pl.cell_cnt());
assert(L.x.internal_size() == x_guess.size());
assert(L.y.internal_size() == y_guess.size());
for(index_t i=0; i<pl.cell_cnt(); ++i){
x_guess[i] = static_cast<float_t>(pl.positions_[i].x);
y_guess[i] = static_cast<float_t>(pl.positions_[i].y);
}
#pragma omp parallel sections num_threads(2)
{
#pragma omp section
x_sol = L.x.solve_CG(x_guess, nbr_iter);
#pragma omp section
y_sol = L.y.solve_CG(y_guess, nbr_iter);
}
for(index_t i=0; i<pl.cell_cnt(); ++i){
if( (circuit.get_cell(i).attributes & XMovable) != 0){
assert(std::isfinite(x_sol[i]));
pl.positions_[i].x = static_cast<int_t>(x_sol[i]);
}
if( (circuit.get_cell(i).attributes & YMovable) != 0){
assert(std::isfinite(y_sol[i]));
pl.positions_[i].y = static_cast<int_t>(y_sol[i]);
}
}
}
// Intended to be used by pulling forces to adapt the forces to the cell's areas
std::vector<float_t> get_area_scales(netlist const & circuit){
std::vector<float_t> ret(circuit.cell_cnt());
capacity_t int_tot_area = 0;
for(index_t i=0; i<circuit.cell_cnt(); ++i){
capacity_t A = circuit.get_cell(i).area;
ret[i] = static_cast<float_t>(A);
int_tot_area += A;
}
float_t inv_average_area = circuit.cell_cnt() / static_cast<float_t>(int_tot_area);
for(index_t i=0; i<circuit.cell_cnt(); ++i){
ret[i] *= inv_average_area;
}
return ret;
}
point<linear_system> get_pulling_forces (netlist const & circuit, placement_t const & pl, float_t typical_distance){
point<linear_system> L = empty_linear_systems(circuit, pl);
float_t typical_force = 1.0f / typical_distance;
std::vector<float_t> scaling = get_area_scales(circuit);
for(index_t i=0; i<pl.cell_cnt(); ++i){
L.x.add_anchor(
typical_force * scaling[i],
i, pl.positions_[i].x
);
L.y.add_anchor(
typical_force * scaling[i],
i, pl.positions_[i].y
);
}
return L;
}
point<linear_system> get_linear_pulling_forces (netlist const & circuit, placement_t const & UB_pl, placement_t const & LB_pl, float_t force, float_t min_distance){
point<linear_system> L = empty_linear_systems(circuit, UB_pl);
assert(LB_pl.cell_cnt() == UB_pl.cell_cnt());
std::vector<float_t> scaling = get_area_scales(circuit);
for(index_t i=0; i<LB_pl.cell_cnt(); ++i){
L.x.add_anchor(
force * scaling[i] / (std::max(static_cast<float_t>(std::abs((float)(UB_pl.positions_[i].x - LB_pl.positions_[i].x))), min_distance)),
i, UB_pl.positions_[i].x
);
L.y.add_anchor(
force * scaling[i] / (std::max(static_cast<float_t>(std::abs((float)(UB_pl.positions_[i].y - LB_pl.positions_[i].y))), min_distance)),
i, UB_pl.positions_[i].y
);
}
return L;
}
region_distribution get_rough_legalizer(netlist const & circuit, placement_t const & pl, box<int_t> surface){
return region_distribution::uniform_density_distribution(surface, circuit, pl);
}
void get_rough_legalization(netlist const & circuit, placement_t & pl, region_distribution const & legalizer){
auto exportation = legalizer.export_spread_positions_linear();
for(auto const C : exportation){
pl.positions_[C.index_in_placement_] = static_cast<point<int_t> >(C.pos_ - 0.5f * static_cast<point<float_t> >(circuit.get_cell(C.index_in_placement_).size));
}
}
float_t get_mean_linear_disruption(netlist const & circuit, placement_t const & LB_pl, placement_t const & UB_pl){
float_t tot_cost = 0.0;
float_t tot_area = 0.0;
for(index_t i=0; i<circuit.cell_cnt(); ++i){
float_t area = static_cast<float_t>(circuit.get_cell(i).area);
point<int_t> diff = LB_pl.positions_[i] - UB_pl.positions_[i];
if( (circuit.get_cell(i).attributes & XMovable) == 0) assert(diff.x == 0);
if( (circuit.get_cell(i).attributes & YMovable) == 0) assert(diff.y == 0);
tot_cost += area * (std::abs((float)diff.x) + std::abs((float)diff.y));
tot_area += area;
}
return tot_cost / tot_area;
}
float_t get_mean_quadratic_disruption(netlist const & circuit, placement_t const & LB_pl, placement_t const & UB_pl){
float_t tot_cost = 0.0;
float_t tot_area = 0.0;
for(index_t i=0; i<circuit.cell_cnt(); ++i){
float_t area = static_cast<float_t>(circuit.get_cell(i).area);
point<int_t> diff = LB_pl.positions_[i] - UB_pl.positions_[i];
if( (circuit.get_cell(i).attributes & XMovable) == 0) assert(diff.x == 0);
if( (circuit.get_cell(i).attributes & YMovable) == 0) assert(diff.y == 0);
float_t manhattan = (std::abs((float)diff.x) + std::abs((float)diff.y));
tot_cost += area * manhattan * manhattan;
tot_area += area;
}
return std::sqrt(tot_cost / tot_area);
}
} // namespace gp
} // namespace coloquinte

View File

@ -0,0 +1,59 @@
#ifndef COLOQUINTE_GP_CIRCUIT
#define COLOQUINTE_GP_CIRCUIT
#include "common.hxx"
#include "solvers.hxx"
#include "netlist.hxx"
#include "rough_legalizers.hxx"
#include <vector>
#include <cassert>
namespace coloquinte{
void verify_placement_legality(netlist const & circuit, placement_t const & pl, box<int_t> surface);
namespace gp{
point<linear_system> empty_linear_systems(netlist const & circuit, placement_t const & pl);
// Net models stuff
point<linear_system> get_HPWLF_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s);
point<linear_system> get_HPWLR_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s);
point<linear_system> get_star_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s);
point<linear_system> get_clique_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s);
point<linear_system> get_MST_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s);
point<linear_system> get_RSMT_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s);
// Additional forces
point<linear_system> get_pulling_forces (netlist const & circuit, placement_t const & pl, float_t typical_distance);
point<linear_system> get_linear_pulling_forces (netlist const & circuit, placement_t const & UB_pl, placement_t const & LB_pl, float_t force, float_t min_distance);
// Solve the final linear system
void solve_linear_system(netlist const & circuit, placement_t & pl, point<linear_system> & L, index_t nbr_iter);
// Cost-related stuff, whether wirelength or disruption
std::int64_t get_HPWL_wirelength (netlist const & circuit, placement_t const & pl);
std::int64_t get_MST_wirelength (netlist const & circuit, placement_t const & pl);
std::int64_t get_RSMT_wirelength (netlist const & circuit, placement_t const & pl);
float_t get_mean_linear_disruption(netlist const & circuit, placement_t const & LB_pl, placement_t const & UB_pl);
float_t get_mean_quadratic_disruption(netlist const & circuit, placement_t const & LB_pl, placement_t const & UB_pl);
// Legalizer-related stuff
region_distribution get_rough_legalizer(netlist const & circuit, placement_t const & pl, box<int_t> surface);
void get_rough_legalization(netlist const & circuit, placement_t & pl, region_distribution const & legalizer);
// Cell orientation optimization
void optimize_x_orientations(netlist const & circuit, placement_t & pl);
void optimize_y_orientations(netlist const & circuit, placement_t & pl);
void optimize_exact_orientations(netlist const & circuit, placement_t & pl);
//void spread_orientations(netlist const & circuit, placement_t & pl);
} // namespace gp
} // namespace coloquinte
#endif

View File

@ -0,0 +1,92 @@
#ifndef COLOQUINTE_GP_HELPERCIRCUIT
#define COLOQUINTE_GP_HELPERCIRCUIT
#include "common.hxx"
#include "netlist.hxx"
#include <cmath>
namespace coloquinte{
struct pin_1D{
index_t cell_ind;
int_t pos;
int_t offs;
bool movable;
bool operator<(pin_1D const o) const { return pos < o.pos; }
pin_1D(index_t c, int_t p, int_t o, bool m) : cell_ind(c), pos(p), offs(o), movable(m){}
};
struct pin_2D{
index_t cell_ind;
point<int_t> pos;
point<int_t> offs;
bool movable;
pin_2D(index_t c, point<int_t> p, point<int_t> o, bool m) : cell_ind(c), pos(p), offs(o), movable(m){}
pin_1D x() const{ return pin_1D(cell_ind, pos.x, offs.x, movable); }
pin_1D y() const{ return pin_1D(cell_ind, pos.y, offs.y, movable); }
};
inline int_t dist(pin_2D const a, pin_2D const b){
point<int_t> diff = a.pos - b.pos;
return std::abs((float)diff.x) + std::abs((float)diff.y);
}
inline std::vector<pin_2D> get_pins_2D(netlist const & circuit, placement_t const & pl, index_t net_ind){
std::vector<pin_2D> ret;
for(auto p : circuit.get_net(net_ind)){
assert(std::isfinite(pl.positions_[p.cell_ind].x) and std::isfinite(pl.positions_[p.cell_ind].y));
assert(std::isfinite(pl.orientations_[p.cell_ind].x) and std::isfinite(pl.orientations_[p.cell_ind].y));
point<int_t> offs;
offs.x = pl.orientations_[p.cell_ind].x ? p.offset.x : circuit.get_cell(p.cell_ind).size.x - p.offset.x;
offs.y = pl.orientations_[p.cell_ind].y ? p.offset.y : circuit.get_cell(p.cell_ind).size.y - p.offset.y;
point<int_t> pos = offs + pl.positions_[p.cell_ind];
assert(std::isfinite(offs.x) and std::isfinite(offs.y));
assert(std::isfinite(pos.x) and std::isfinite(pos.y));
bool movable = (circuit.get_cell(p.cell_ind).attributes & XMovable) != 0 and (circuit.get_cell(p.cell_ind).attributes & YMovable) != 0;
ret.push_back(pin_2D(p.cell_ind, pos, offs, movable));
}
return ret;
}
inline point<std::vector<pin_1D> > get_pins_1D(netlist const & circuit, placement_t const & pl, index_t net_ind){
point<std::vector<pin_1D> > ret;
for(auto p : circuit.get_net(net_ind)){
assert(std::isfinite(pl.positions_[p.cell_ind].x) and std::isfinite(pl.positions_[p.cell_ind].y));
assert(std::isfinite(pl.orientations_[p.cell_ind].x) and std::isfinite(pl.orientations_[p.cell_ind].y));
point<int_t> offs;
offs.x = pl.orientations_[p.cell_ind].x ? p.offset.x : circuit.get_cell(p.cell_ind).size.x - p.offset.x;
offs.y = pl.orientations_[p.cell_ind].y ? p.offset.y : circuit.get_cell(p.cell_ind).size.y - p.offset.y;
point<int_t> pos = offs + pl.positions_[p.cell_ind];
assert(std::isfinite(offs.x) and std::isfinite(offs.y));
assert(std::isfinite(pos.x) and std::isfinite(pos.y));
bool x_movable = (circuit.get_cell(p.cell_ind).attributes & XMovable) != 0;
bool y_movable = (circuit.get_cell(p.cell_ind).attributes & YMovable) != 0;
ret.x.push_back(pin_1D(p.cell_ind, pos.x, offs.x, x_movable));
ret.y.push_back(pin_1D(p.cell_ind, pos.y, offs.y, y_movable));
}
return ret;
}
std::int64_t MST_length(std::vector<point<int_t> > const & pins);
std::int64_t RSMT_length(std::vector<point<int_t> > const & pins, index_t exactitude_limit);
std::int64_t get_HPWL_length(netlist const & circuit, placement_t const & pl, index_t net_ind);
std::int64_t get_RSMT_length(netlist const & circuit, placement_t const & pl, index_t net_ind);
std::vector<std::pair<index_t, index_t> > get_MST_topology(std::vector<point<int_t> > const & pins);
std::vector<std::pair<index_t, index_t> > get_RSMT_horizontal_topology(std::vector<point<int_t> > const & pins, index_t exactitude_limits);
point<std::vector<std::pair<index_t, index_t> > > get_RSMT_topology(std::vector<point<int_t> > const & pins, index_t exactitude_limit);
} // namespace coloquinte
#endif

View File

@ -0,0 +1,118 @@
#ifndef COLOQUINTE_GP_COMMON
#define COLOQUINTE_GP_COMMON
#include <cstdint>
#include <algorithm>
namespace coloquinte{
using float_t = float;
using int_t = std::int32_t;
using index_t = std::uint32_t;
using capacity_t = std::int64_t;
using mask_t = std::uint32_t;
using ext_object = std::uint64_t;
enum PlacementType{
Optimist = 0,
Pessimist = 1
};
enum Movability{
XMovable = 1 ,
YMovable = 1 << 1,
XFlippable = 1 << 2,
YFlippable = 1 << 3,
SoftMacro = 1 << 4
};
template<typename T>
struct point{
T x, y;
point(){}
point(T x, T y): x(x), y(y){}
template<typename S>
operator point<S>() const{
return point<S>(static_cast<S>(x), static_cast<S>(y));
}
void operator+=(point<T> const o){
x += o.x;
y += o.y;
}
};
template<typename T>
point<T> operator+(point<T> const a, point<T> const b){
return point<T>(a.x+b.x, a.y+b.y);
}
template<typename T>
point<T> operator-(point<T> const a, point<T> const b){
return point<T>(a.x-b.x, a.y-b.y);
}
template<typename T>
point<T> operator*(T lambda, point<T> const p){
return point<T>(lambda * p.x, lambda * p.y);
}
template<typename T>
point<T> operator*(point<T> const a, point<T> const b){
return point<T>(a.x*b.x, a.y*b.y);
}
template<typename T>
struct box{
T x_min, x_max, y_min, y_max;
box(){}
box(T x_mn, T x_mx, T y_mn, T y_mx) : x_min(x_mn), x_max(x_mx), y_min(y_mn), y_max(y_mx){}
box(point<T> mn, point<T> mx) : x_min(mn.x), x_max(mx.x), y_min(mn.y), y_max(mx.y){}
bool in(box<T> const o) const{
return x_max <= o.x_max
&& y_max <= o.y_max
&& x_min >= o.x_min
&& y_min >= o.y_min;
}
bool intersects(box<T> const o) const{
return x_min < o.x_max
&& y_min < o.y_max
&& o.x_min < x_max
&& o.y_min < y_max;
}
box<T> intersection(box<T> const o) const{
return box<T>(
std::max(x_min, o.x_min),
std::min(x_max, o.x_max),
std::max(y_min, o.y_min),
std::min(y_max, o.y_max)
);
}
box<T> bounding_box(box<T> const o) const{
return box<T>(
std::min(x_min, o.x_min),
std::max(x_max, o.x_max),
std::min(y_min, o.y_min),
std::max(y_max, o.y_max)
);
}
point<T> dimensions() const{
return point<T>(x_max-x_min, y_max-y_min);
}
bool empty() const{
return dimensions().x <= 0 or dimensions().y <= 0;
}
template<typename S>
operator box<S>() const{
return box<S>(static_cast<S>(x_min), static_cast<S>(x_max), static_cast<S>(y_min), static_cast<S>(y_max));
}
};
using orientation_t = point<bool>;
} // Namespace coloquinte
#endif

View File

@ -0,0 +1,89 @@
#ifndef COLOQUINTE_DETAILED
#define COLOQUINTE_DETAILED
#include "common.hxx"
#include "netlist.hxx"
#include <vector>
#include <limits>
namespace coloquinte{
namespace dp{
const index_t null_ind = std::numeric_limits<index_t>::max();
struct detailed_placement{
// All position and orientation stuff
placement_t plt_;
std::vector<index_t> cell_rows_;
// The placement region
int_t min_x_, max_x_;
int_t y_origin_;
int_t row_height_;
// Encode the topological state of the circuit: which cells are near each other
// Makes extracting part of the circuit or optimizing positions at fixed topology easy
std::vector<std::pair<index_t, index_t> > neighbours_; // The cells before and after on each row; cells spanning multiple columns use several positions
// In order to get the neighbours in the detailed placement
std::vector<index_t> neighbours_limits_;
std::vector<index_t> row_first_cells_, row_last_cells_; // For each row, which cells are the on the boundaries
// Tests the coherency between positions, widths and topological representation
void selfcheck() const;
detailed_placement(
placement_t pl,
std::vector<index_t> placement_rows,
std::vector<index_t> cell_heights,
std::vector<std::vector<index_t> > rows,
int_t min_x, int_t max_x,
int_t y_origin,
index_t nbr_rows, int_t row_height
);
index_t cell_height(index_t c) const{ return neighbours_limits_[c+1] - neighbours_limits_[c]; }
index_t cell_cnt() const{ return cell_rows_.size(); }
index_t row_cnt() const{ return row_first_cells_.size(); }
index_t neighbour_index(index_t c, index_t r) const{
assert(r - cell_rows_[c] < cell_height(c));
return neighbours_limits_[c] + r - cell_rows_[c];
}
void swap_standard_cell_topologies(index_t c1, index_t c2);
std::pair<int_t, int_t> get_limit_positions(netlist const & circuit, index_t c) const;
index_t get_first_cell_on_row(index_t r);
index_t get_next_cell_on_row(index_t c, index_t r);
index_t get_prev_cell_on_row(index_t c, index_t r);
index_t get_first_standard_cell_on_row(index_t r);
index_t get_next_standard_cell_on_row(index_t c, index_t r);
void reorder_standard_cells(std::vector<index_t> const old_order, std::vector<index_t> const new_order);
void reorder_cells(std::vector<index_t> const old_order, std::vector<index_t> const new_order, index_t row);
};
void swaps_global_HPWL(netlist const & circuit, detailed_placement & pl, index_t row_extent, index_t cell_extent, bool try_flip = false);
void swaps_global_RSMT(netlist const & circuit, detailed_placement & pl, index_t row_extent, index_t cell_extent, bool try_flip = false);
void swaps_row_convex_HPWL(netlist const & circuit, detailed_placement & pl, index_t range);
void swaps_row_convex_RSMT(netlist const & circuit, detailed_placement & pl, index_t range);
void swaps_row_noncvx_HPWL(netlist const & circuit, detailed_placement & pl, index_t range);
void swaps_row_noncvx_RSMT(netlist const & circuit, detailed_placement & pl, index_t range);
void OSRP_convex_HPWL(netlist const & circuit, detailed_placement & pl);
void OSRP_convex_RSMT(netlist const & circuit, detailed_placement & pl);
void OSRP_noncvx_HPWL(netlist const & circuit, detailed_placement & pl);
void OSRP_noncvx_RSMT(netlist const & circuit, detailed_placement & pl);
void row_compatible_orientation(netlist const & circuit, detailed_placement & pl, bool first_row_orient);
} // namespace dp
} // namespace coloquinte
#endif

View File

@ -0,0 +1,12 @@
#include "circuit.hxx"
#include "detailed.hxx"
namespace coloquinte{
namespace dp{
detailed_placement legalize(netlist const & circuit, placement_t const & pl, box<int_t> surface, int_t row_height);
void get_result(netlist const & circuit, detailed_placement const & dpl, placement_t & pl);
} // namespace dp
} // namespace coloquinte

View File

@ -0,0 +1,251 @@
#ifndef COLOQUINTE_NETLIST
#define COLOQUINTE_NETLIST
#include "common.hxx"
#include <vector>
#include <cassert>
namespace coloquinte{
// Structures for construction and circuit_loader
struct temporary_pin{
point<int_t> offset;
index_t cell_ind, net_ind;
temporary_pin(){}
temporary_pin(point<int_t> offs, index_t c, index_t n) : offset(offs), cell_ind(c), net_ind(n){}
};
struct temporary_cell{
point<int_t> size;
capacity_t area;
mask_t attributes;
index_t list_index;
temporary_cell(){}
temporary_cell(point<int_t> s, mask_t attr, index_t ind) : size(s), attributes(attr), list_index(ind){ area = static_cast<capacity_t>(s.x) * static_cast<capacity_t>(s.y);}
};
struct temporary_net{
int_t weight;
index_t list_index;
temporary_net(){}
temporary_net(index_t ind, int_t wght) : weight(wght), list_index(ind){}
};
// Main class
class netlist{
std::vector<int_t> net_weights_;
std::vector<capacity_t> cell_areas_;
std::vector<point<int_t> > cell_sizes_;
std::vector<mask_t> cell_attributes_;
// Mapping of the order given at construction time to the internal representation
std::vector<index_t> cell_internal_mapping_;
std::vector<index_t> net_internal_mapping_;
// Optimized sparse storage for nets
std::vector<index_t> net_limits_;
std::vector<index_t> cell_indexes_;
std::vector<point<int_t> > pin_offsets_;
// Sparse storage from cell to net appartenance
std::vector<index_t> cell_limits_;
std::vector<index_t> net_indexes_;
std::vector<index_t> pin_indexes_;
public:
netlist(std::vector<temporary_cell> cells, std::vector<temporary_net> nets, std::vector<temporary_pin> all_pins);
netlist(){}
void selfcheck() const;
struct pin_t{
point<int_t> offset;
index_t cell_ind, net_ind;
pin_t(point<int_t> offs, index_t c, index_t n) : offset(offs), cell_ind(c), net_ind(n){}
};
class net_pin_iterator{
index_t pin_ind, net_ind;
netlist const & N;
public:
pin_t operator*() const{
return pin_t(N.pin_offsets_[pin_ind], N.cell_indexes_[pin_ind], net_ind);
}
net_pin_iterator & operator++(){
pin_ind++;
return *this;
}
bool operator!=(net_pin_iterator const o) const{
return pin_ind != o.pin_ind;
}
net_pin_iterator(index_t net_index, index_t pin_index, netlist const & orig) : pin_ind(pin_index), net_ind(net_index), N(orig){}
};
class cell_pin_iterator{
index_t pin_ind, cell_ind;
netlist const & N;
public:
pin_t operator*() const{
return pin_t(N.pin_offsets_[N.pin_indexes_[pin_ind]], cell_ind, N.net_indexes_[pin_ind]);
}
cell_pin_iterator & operator++(){
pin_ind++;
return *this;
}
bool operator!=(cell_pin_iterator const o) const{
return pin_ind != o.pin_ind;
}
cell_pin_iterator(index_t cell_index, index_t pin_index, netlist const & orig) : pin_ind(pin_index), cell_ind(cell_index), N(orig){}
};
struct internal_cell{
point<int_t> size;
capacity_t area;
mask_t attributes;
netlist const & N;
index_t index;
index_t pin_cnt;
internal_cell(index_t ind, netlist const & orig) :
size(orig.cell_sizes_[ind]),
area(orig.cell_areas_[ind]),
attributes(orig.cell_attributes_[ind]),
N(orig),
index(ind),
pin_cnt(N.cell_limits_[ind+1] - N.cell_limits_[ind])
{}
cell_pin_iterator begin(){ return cell_pin_iterator(index, N.cell_limits_[index], N); }
cell_pin_iterator end(){ return cell_pin_iterator(index, N.cell_limits_[index+1], N); }
};
struct internal_net{
int_t weight;
netlist const & N;
index_t index;
index_t pin_cnt;
internal_net(index_t ind, netlist const & orig) :
weight(orig.net_weights_[ind]),
N(orig),
index(ind),
pin_cnt(N.net_limits_[ind+1] - N.net_limits_[ind])
{}
net_pin_iterator begin(){ return net_pin_iterator(index, N.net_limits_[index], N); }
net_pin_iterator end(){ return net_pin_iterator(index, N.net_limits_[index+1], N); }
};
internal_cell get_cell(index_t ind) const{
return internal_cell(ind, *this);
}
internal_net get_net(index_t ind) const{
return internal_net(ind, *this);
}
index_t cell_cnt() const{ return cell_internal_mapping_.size(); }
index_t net_cnt() const{ return net_internal_mapping_.size(); }
index_t pin_cnt() const{ return pin_offsets_.size(); }
index_t get_cell_ind(index_t external_ind) const{ return cell_internal_mapping_[external_ind]; }
index_t get_net_ind(index_t external_ind) const{ return net_internal_mapping_[external_ind]; }
point<int_t> get_cell_size(index_t external_ind){
return cell_sizes_[ cell_internal_mapping_[external_ind] ];
}
void set_cell_size(index_t external_ind,point<int_t> cell_size){
cell_sizes_[cell_internal_mapping_[external_ind]] = cell_size;
}
};
inline netlist::netlist(std::vector<temporary_cell> cells, std::vector<temporary_net> nets, std::vector<temporary_pin> all_pins){
struct extended_pin : public temporary_pin{
index_t pin_index;
extended_pin(temporary_pin const p) : temporary_pin(p){}
};
std::vector<extended_pin> pins;
for(temporary_pin const p : all_pins){
pins.push_back(extended_pin(p));
}
cell_limits_.resize(cells.size()+1);
net_limits_.resize(nets.size()+1);
net_weights_.resize(nets.size());
cell_areas_.resize(cells.size());
cell_sizes_.resize(cells.size());
cell_attributes_.resize(cells.size());
cell_internal_mapping_.resize(cells.size());
net_internal_mapping_.resize(nets.size());
cell_indexes_.resize(pins.size());
pin_offsets_.resize(pins.size());
net_indexes_.resize(pins.size());
pin_indexes_.resize(pins.size());
for(index_t i=0; i<nets.size(); ++i){
net_internal_mapping_[i] = i;
}
for(index_t i=0; i<cells.size(); ++i){
cell_internal_mapping_[i] = i;
}
std::sort(pins.begin(), pins.end(), [](extended_pin const a, extended_pin const b){ return a.net_ind < b.net_ind; });
for(index_t n=0, p=0; n<nets.size(); ++n){
net_weights_[n] = nets[n].weight;
net_limits_[n] = p;
while(p<pins.size() && pins[p].net_ind == n){
cell_indexes_[p] = pins[p].cell_ind;
pin_offsets_[p] = pins[p].offset;
pins[p].pin_index = p;
++p;
}
}
net_limits_.back() = pins.size();
std::sort(pins.begin(), pins.end(), [](extended_pin const a, extended_pin const b){ return a.cell_ind < b.cell_ind; });
for(index_t c=0, p=0; c<cells.size(); ++c){
cell_areas_[c] = cells[c].area;
cell_attributes_[c] = cells[c].attributes;
cell_sizes_[c] = cells[c].size;
cell_limits_[c] = p;
while(p<pins.size() && pins[p].cell_ind == c){
net_indexes_[p] = pins[p].net_ind;
pin_indexes_[p] = pins[p].pin_index;
++p;
}
}
cell_limits_.back() = pins.size();
}
struct placement_t{
std::vector<point<int_t> > positions_;
std::vector<point<bool> > orientations_;
index_t cell_cnt() const{
assert(positions_.size() == orientations_.size());
return positions_.size();
}
void selfcheck() const;
};
} // namespace coloquinte
#endif

View File

@ -0,0 +1,161 @@
#ifndef COLOQUINTE_GP_OPTSUBPROBLEMS
#define COLOQUINTE_GP_OPTSUBPROBLEMS
#include "common.hxx"
#include <queue>
#include <vector>
#include <cassert>
#include <numeric>
#include <cmath>
#include <limits>
namespace coloquinte{
typedef std::pair<int_t, capacity_t> t1D_elt;
std::vector<capacity_t> transport_1D(std::vector<t1D_elt> sources, std::vector<t1D_elt> sinks);
std::vector<std::vector<capacity_t> > transport_convex(std::vector<capacity_t> const & capacities, std::vector<capacity_t> const & demands, std::vector<std::vector<float_t> > const & costs);
std::vector<std::vector<capacity_t> > transport_generic(std::vector<capacity_t> const & capacities, std::vector<capacity_t> const & demands, std::vector<std::vector<float_t> > const & costs);
template<typename T>
struct legalizable_task{
T width;
T target_pos;
index_t ind;
legalizable_task(T w, T p, index_t i) : width(w), target_pos(p), ind(i){}
bool operator<(legalizable_task<T> const o) const{ return target_pos < o.target_pos; }
};
// A class to obtain the optimal positions minimizing total weighted displacement along a row
// It is an ordered single row problem/fixed order single machine scheduling problem, solved by the clumping/specialized cascading descent algorithm
// The cost is linear in the distance to the target position, weighted by the width of the cells
template<typename T>
class OSRP_leg{
struct OSRP_bound{
T absolute_pos; // Will be the target absolute position of the cell
T weight; // Will be the width of the cell
bool operator<(OSRP_bound const o) const{ return absolute_pos < o.absolute_pos; }
OSRP_bound(T w, T abs_pos) : absolute_pos(abs_pos), weight(w) {}
};
T begin, end;
std::vector<index_t> cells; // The indexes in the circuit
std::vector<T> constraining_pos; // Where the cells have been pushed and constrain the positions of preceding cells
std::vector<T> prev_width; // Cumulative width of the cells: calculates the absolute position of new cells
std::priority_queue<OSRP_bound> bounds;
// Get the cost of pushing a cell on the row
T get_displacement(legalizable_task<T> const newly_pushed, bool update);
public:
T current_width() const{ return prev_width.back(); }
T remaining_space() const{ return end - begin - current_width(); }
T last_available_pos() const{ return constraining_pos.back() + current_width(); }
T get_cost(legalizable_task<T> const task){ return get_displacement(task, false); }
void push(legalizable_task<T> const task){ get_displacement(task, true); }
// Initialize
OSRP_leg(T b, T e) : begin(b), end(e), prev_width(1, 0) {}
OSRP_leg(){}
typedef std::pair<index_t, T> result_t;
// Get the resulting placement
std::vector<result_t> get_placement() const;
};
struct cell_bound{
index_t c;
int_t pos;
int_t slope;
bool operator<(cell_bound const o) const{ return c < o.c; }
cell_bound(index_t order, int_t p, int_t s) : c(order), pos(p), slope(s) {}
};
bool place_convex_single_row(std::vector<int_t> const & widths, std::vector<std::pair<int_t, int_t> > const & ranges, std::vector<cell_bound> bounds, std::vector<int_t> const & const_slopes, std::vector<int_t> & positions);
bool place_noncvx_single_row(std::vector<int_t> const & widths, std::vector<std::pair<int_t, int_t> > const & ranges, std::vector<int> const & flippables, std::vector<cell_bound> bounds, std::vector<int_t> const & const_slopes, std::vector<int_t> & positions, std::vector<int> & flippings);
template<typename T>
inline T OSRP_leg<T>::get_displacement(legalizable_task<T> const newly_pushed, bool update){
T target_abs_pos = newly_pushed.target_pos - current_width();
T width = newly_pushed.width;
T slope = - width;
T cur_pos = end;
T cur_cost = 0;
std::vector<OSRP_bound> passed_bounds;
while( not bounds.empty() and
((slope < 0 and bounds.top().absolute_pos > target_abs_pos) // Not reached equilibrium
or bounds.top().absolute_pos > end - current_width() - width) // Still not a legal position
){
T old_pos = cur_pos;
cur_pos = bounds.top().absolute_pos;
cur_cost += (old_pos - cur_pos) * (slope + width); // The additional cost for the other cells encountered
slope += bounds.top().weight;
// Remember which bounds we encountered in order to reset the object to its initial state
if(not update)
passed_bounds.push_back(bounds.top());
bounds.pop();
}
T final_abs_pos = std::min(end - current_width() - width, // Always before the end and after the beginning
std::max(begin, slope >= 0 ? cur_pos : target_abs_pos) // but did we stop before reaching the target position?
);
cur_cost += (cur_pos - final_abs_pos) * (slope + width); // The additional cost for the other cells encountered
if(std::numeric_limits<T>::is_integer){
assert(final_abs_pos >= begin);
assert(final_abs_pos <= end - current_width() - width);
}
if(update){
prev_width.push_back(width + current_width());
cells.push_back(newly_pushed.ind);
constraining_pos.push_back(final_abs_pos);
if(slope > 0){ // Remaining capacity of an encountered bound
bounds.push(OSRP_bound(slope, cur_pos));
}
// The new bound, minus what it absorbs of the remaining slope
if(target_abs_pos > begin){
bounds.push(OSRP_bound(2*width + std::min(slope, static_cast<T>(0) ), target_abs_pos));
}
}
else{
for(OSRP_bound b : passed_bounds){
bounds.push(b);
}
}
return cur_cost + width * std::abs((float)(final_abs_pos - target_abs_pos)); // Add the cost of the new cell
}
template<typename T>
inline std::vector<std::pair<index_t, T> > OSRP_leg<T>::get_placement() const{
auto final_abs_pos = constraining_pos;
std::partial_sum(final_abs_pos.rbegin(), final_abs_pos.rend(), final_abs_pos.rbegin(), [](T a, T b)->T{ return std::min(a,b); });
std::vector<result_t> ret(cells.size());
for(index_t i=0; i<cells.size(); ++i){
ret[i] = result_t(cells[i], final_abs_pos[i] + prev_width[i]);
if(std::numeric_limits<T>::is_integer){
assert(final_abs_pos[i] >= begin);
assert(final_abs_pos[i] + prev_width[i+1] <= end);
}
}
return ret;
}
}
#endif

View File

@ -0,0 +1,29 @@
#include "common.hxx"
#include <vector>
namespace coloquinte{
typedef std::pair<int_t, int_t> p_v;
struct piecewise_linear_function{
std::vector<p_v> point_values;
static piecewise_linear_function minimum(piecewise_linear_function const & a, piecewise_linear_function const & b);
piecewise_linear_function previous_min_of_sum(piecewise_linear_function const & o, int_t added_cell_width) const;
piecewise_linear_function previous_min() const;
int_t value_at(int_t pos) const;
int_t last_before(int_t pos) const;
void add_monotone(int_t slope, int_t offset);
void add_bislope(int_t s_l, int_t s_r, int_t pos);
piecewise_linear_function(){}
piecewise_linear_function(int_t min_def, int_t max_def);
};
} // End namespace coloquinte

View File

@ -0,0 +1,263 @@
#ifndef COLOQUINTE_GP_ROUGH_LEGALIZER
#define COLOQUINTE_GP_ROUGH_LEGALIZER
#include "common.hxx"
#include "netlist.hxx"
#include <vector>
#include <cassert>
#include <cmath>
#include <functional>
/*
* A simple class to perform approximate legalization with extreme efficiency
*
* To be called during global placement or before an exact legalization
*
*/
namespace coloquinte{
struct density_limit{
box<int_t> box_;
float_t density_; // from 0.0 for a macro to 1.0 if it does nothing
};
typedef std::vector<density_limit> density_restrictions;
namespace gp{
class region_distribution{
/*
* Coordinates are mostly float but obstacles and areas are integers for correctness
*/
public:
struct movable_cell{
capacity_t demand_; // == area; No FP!!!
point<float_t> pos_; // Target position, determining the cost to allocate it
// int_t x_size, y_size; // May split cells
index_t index_in_placement_;
movable_cell();
movable_cell(capacity_t demand, point<float_t> p, index_t ind);
};
// Specifies a maximum density of movable cells per usable area
// Representing either a macroblock or a routing congestion
private:
struct region;
struct cell_ref{
capacity_t allocated_capacity_;
point<float_t> pos_;
index_t index_in_list_;
cell_ref(){}
cell_ref(capacity_t demand, point<float_t> p, index_t ind) : allocated_capacity_(demand), pos_(p), index_in_list_(ind){}
friend region;
};
struct region{
public:
// Data members
capacity_t capacity_; // ==area; No floating point!!!
point<float_t> pos_;
std::vector<cell_ref> cell_references_;
// Constructors
region(){} // Necessary if we want to resize vectors
region(capacity_t cap, point<float_t> pos, std::vector<cell_ref> cells);
// Helper functions for bipartitioning
private:
static void distribute_new_cells(region & a, region & b, std::vector<cell_ref> cells); // Called by the other two to do the dirty work
public:
void distribute_cells(region & a, region & b) const; // Distribute the cells from one region to two
static void redistribute_cells(region & a, region & b); // Optimizes the distribution between two regions
// Helper functions for multipartitioning
private:
static void distribute_new_cells(std::vector<std::reference_wrapper<region_distribution::region> > regions, std::vector<cell_ref> cells);
public:
void distribute_cells(std::vector<std::reference_wrapper<region_distribution::region> > regions) const;
static void redistribute_cells(std::vector<std::reference_wrapper<region_distribution::region> > regions);
// Helper functions for 1D transportation
public:
static void distribute_new_cells(std::vector<std::reference_wrapper<region_distribution::region> > regions, std::vector<cell_ref> cells, std::function<float_t (point<float_t>)> coord);
static void redistribute_cells(std::vector<std::reference_wrapper<region_distribution::region> > & regions, std::function<float_t (point<float_t>)> coord);
public:
void uniquify_references();
void selfcheck() const;
// Accessors
capacity_t capacity() const;
capacity_t allocated_capacity() const;
capacity_t unused_capacity() const;
index_t cell_cnt() const;
float_t distance(cell_ref const & C) const;
float_t cost() const;
};
private:
// Members
index_t x_regions_cnt_, y_regions_cnt_;
std::vector<movable_cell> cell_list_;
std::vector<region> placement_regions_;
box<int_t> placement_area_;
std::vector<density_limit> density_map_;
const capacity_t full_density_mul; // Multiplicator giving the grain for fractional areas for the surface
capacity_t cell_density_mul; // ANd for the cells
float_t density_scaling_factor_;
private:
// Helper functions
region & get_region(index_t x_coord, index_t y_coord);
region const & get_region(index_t x_coord, index_t y_coord) const;
box<int_t> get_box(index_t x, index_t y, index_t x_cnt, index_t y_cnt) const;
static void sort_uniquify(std::vector<cell_ref> & cell_references);
static void just_uniquify(std::vector<cell_ref> & cell_references);
// Prepare regions with the right positions and capacities; different levels of nesting are compatible
std::vector<region> prepare_regions(index_t x_cnt, index_t y_cnt) const;
public:
inline box<int_t> placement_area() const;
inline point<float_t> region_dimensions() const;
inline index_t x_regions_cnt() const;
inline index_t y_regions_cnt() const;
inline index_t regions_cnt() const;
inline index_t cell_cnt() const;
inline index_t fractional_cell_cnt() const;
/*
* Two types of export
* Region center : upper bound of legalization cost
* 1D quadratic optimization : lower bound of legalization cost
*/
std::vector<movable_cell> export_positions() const;
std::vector<movable_cell> export_spread_positions_quadratic() const;
std::vector<movable_cell> export_spread_positions_linear() const;
// The cost as seen by the partitioning algorithms (but not the export)
float_t cost() const;
/*
* Further partitions
*/
void x_bipartition();
void y_bipartition();
void x_resize(index_t sz);
void y_resize(index_t sz);
void multipartition(index_t x_width, index_t y_width);
void multipartition(index_t width){ multipartition(width, width); }
/*
* Optimization functions
*/
// Bipartitioning: only two regions are considered at a time
void redo_adjacent_bipartitions();
void redo_diagonal_bipartitions();
void redo_bipartitions();
// Line partitioning: optimal on coordinate axis with Manhattan distance (Euclidean distance could use it in any direction)
void redo_line_partitions();
// Multipartitioning: several regions considered, slow runtimes
void redo_diag_partitions(index_t len);
void redo_multipartitions(index_t x_width, index_t y_width);
void redo_multipartitions(index_t width){ redo_multipartitions(width, width); }
// Try to remove duplicate fractional cells
void fractions_minimization();
// Verify
void selfcheck() const;
private:
region_distribution(box<int_t> placement_area, netlist const & circuit, placement_t const & pl, std::vector<density_limit> const & density_map, bool full_density);
public:
/*
* Obtain a region_distribution from a placement
*
* Full density: the object tries to pack the cells as much as possible while still respecting the density limits
* Uniform density: not only are the density limits respected, the allocated capacities are proportional to the allowed densities
*
*/
static region_distribution full_density_distribution(box<int_t> placement_area, netlist const & circuit, placement_t const & pl, std::vector<density_limit> const & density_map = std::vector<density_limit>());
static region_distribution uniform_density_distribution(box<int_t> placement_area, netlist const & circuit, placement_t const & pl, std::vector<density_limit> const & density_map = std::vector<density_limit>());
void update(netlist const & circuit, placement_t const & pl);
};
inline region_distribution::movable_cell::movable_cell(){}
inline region_distribution::movable_cell::movable_cell(capacity_t demand, point<float_t> p, index_t ind) : demand_(demand), pos_(p), index_in_placement_(ind){}
inline box<int_t> region_distribution::placement_area() const { return placement_area_; }
inline point<float_t> region_distribution::region_dimensions() const {
point<int_t> s = static_cast<point<float_t> >(placement_area().dimensions());
return point<float_t>(s.x/x_regions_cnt(), s.y/y_regions_cnt());
}
inline index_t region_distribution::x_regions_cnt() const { return x_regions_cnt_; }
inline index_t region_distribution::y_regions_cnt() const { return y_regions_cnt_; }
inline index_t region_distribution::regions_cnt() const { index_t ret = x_regions_cnt() * y_regions_cnt(); assert(placement_regions_.size() == ret); return ret; }
inline region_distribution::region & region_distribution::get_region(index_t x_coord, index_t y_coord){
return placement_regions_[y_coord * x_regions_cnt() + x_coord];
}
inline region_distribution::region const & region_distribution::get_region(index_t x_coord, index_t y_coord) const{
return placement_regions_[y_coord * x_regions_cnt() + x_coord];
}
inline index_t region_distribution::cell_cnt() const{ return cell_list_.size(); }
inline index_t region_distribution::fractional_cell_cnt() const{
index_t tot_cnt = 0;
for(auto const & R : placement_regions_){
tot_cnt += R.cell_cnt();
}
return tot_cnt;
}
inline capacity_t region_distribution::region::capacity() const{ return capacity_; }
inline capacity_t region_distribution::region::unused_capacity() const{ return capacity() - allocated_capacity(); }
inline capacity_t region_distribution::region::allocated_capacity() const{
capacity_t ret = 0;
for(cell_ref const C : cell_references_){
ret += C.allocated_capacity_;
}
return ret;
}
inline index_t region_distribution::region::cell_cnt() const{ return cell_references_.size(); }
inline float_t region_distribution::region::distance(region_distribution::cell_ref const & C) const{
return std::abs(pos_.x - C.pos_.x) + std::abs(pos_.y - C.pos_.y);
/*
float_t manhattan = std::max(static_cast<float_t>(0.0), std::max(C.pos_.x - surface_.x_max, surface_.x_min - C.pos_.x))
+ std::max(static_cast<float_t>(0.0), std::max(C.pos_.y - surface_.y_max, surface_.y_min - C.pos_.y));
return manhattan * (1.0 + manhattan * 0.0001);
*/
}
} // Namespace gp
} // Namespace coloquinte
#endif

View File

@ -0,0 +1,88 @@
#ifndef COLOQUINE_GP_SOLVERS
#define COLOQUINE_GP_SOLVERS
#include "common.hxx"
#include <vector>
namespace coloquinte{
namespace gp{
struct matrix_doublet{
index_t c_;
float val_;
bool operator<(matrix_doublet const o) const{ return c_ < o.c_; }
matrix_doublet(){}
matrix_doublet(index_t c, float v) : c_(c), val_(v){}
};
struct matrix_triplet{
index_t r_, c_;
float_t val_;
matrix_triplet(index_t ri, index_t ci, float_t v) : r_(ri), c_(ci), val_(v){}
bool operator<(matrix_triplet const o){ return r_ < o.r_ || (r_ == o.r_ && c_ < o.c_); }
};
class linear_system{
std::vector<matrix_triplet> matrix_;
std::vector<float_t> target_;
index_t internal_size_;
public:
void add_triplet(index_t row, index_t col, float_t val){ matrix_.push_back(matrix_triplet(row, col, val)); }
linear_system operator+(linear_system const & o) const;
void add_doublet(index_t row, float_t val){
target_[row] += val;
}
void add_force(
float_t force,
index_t c1, index_t c2,
float_t offs1, float_t offs2
){
add_triplet(c1, c1, force);
add_triplet(c2, c2, force);
add_triplet(c1, c2, -force);
add_triplet(c2, c1, -force);
add_doublet(c1, force * (offs2-offs1));
add_doublet(c2, force * (offs1-offs2));
}
void add_fixed_force(
float_t force,
index_t c,
float_t fixed_pos,
float_t offs
){
add_triplet(c, c, force);
add_doublet(c, force * (fixed_pos-offs));
}
void add_anchor(
float_t scale,
index_t c,
float_t pos
){
add_triplet(c, c, scale);
add_doublet(c, scale*pos);
}
linear_system(index_t s) : target_(s, 0.0), internal_size_(s){}
linear_system(index_t s, index_t i) : target_(s, 0.0), internal_size_(i){}
index_t size() const{ return target_.size(); }
index_t internal_size() const{ return internal_size_; }
void add_variables(index_t cnt){ target_.resize(target_.size() + cnt, 0.0); }
std::vector<float_t> solve_CG(std::vector<float_t> guess, index_t nbr_iter);
};
} // namespace gp
} // namespace coloquinte
#endif

View File

@ -0,0 +1,35 @@
#include "common.hxx"
#include <array>
#ifndef COLOQUINTE_TOPOLOGIES
#define COLOQUINTE_TOPOLOGIES
namespace coloquinte{
namespace steiner_lookup{
template<int pin_cnt>
struct Hconnectivity{
// The edges and the couple of pins connected to the extreme ones are represented by one char each
// The first 4 bits represent the first pin minus one, the next 4 bits the second pin minus one
std::uint8_t connexions[pin_cnt-3];
std::uint8_t extremes;
int_t get_wirelength(std::array<point<int_t>, pin_cnt> const sorted_points) const;
std::array<std::pair<index_t, index_t>, pin_cnt-1> get_x_topology(std::array<point<int_t>, pin_cnt> const sorted_points) const;
};
extern std::array<Hconnectivity<4>, 2> const topologies_4;
extern std::array<Hconnectivity<5>, 6> const topologies_5;
extern std::array<Hconnectivity<6>, 23> const topologies_6;
extern std::array<Hconnectivity<7>, 111> const topologies_7;
extern std::array<Hconnectivity<8>, 642> const topologies_8;
extern std::array<Hconnectivity<9>, 4334> const topologies_9;
extern std::array<Hconnectivity<10>, 33510> const topologies_10;
}
}
#endif

View File

@ -0,0 +1,47 @@
#ifndef COLOQUINTE_UNION_FIND
#define COLOQUINTE_UNION_FIND
#include "common.hxx"
#include <vector>
namespace coloquinte{
class union_find{
std::vector<index_t> connex_representants;
public:
index_t size() const { return connex_representants.size(); }
void merge(index_t a, index_t b){
connex_representants[find(a)] = b;
}
index_t find(index_t ind){
if(connex_representants[ind] != ind){
connex_representants[ind] = find(connex_representants[ind]);
}
return connex_representants[ind];
}
union_find(index_t s) : connex_representants(s){
for(index_t i=0; i<size(); ++i){
connex_representants[i] = i;
}
}
bool is_connex(){
bool connex = true;
for(index_t i=0; i+1<size(); ++i){
connex = connex && (find(i) == find(i+1));
}
return connex;
}
};
} // End namespace coloquinte
#endif

261
coloquinte/src/detailed.cxx Normal file
View File

@ -0,0 +1,261 @@
#include "coloquinte/detailed.hxx"
#include "coloquinte/circuit_helper.hxx"
#include <cassert>
namespace coloquinte{
namespace dp{
detailed_placement::detailed_placement(
placement_t pl,
std::vector<index_t> placement_rows,
std::vector<index_t> cell_heights,
std::vector<std::vector<index_t> > rows,
int_t min_x, int_t max_x,
int_t y_origin,
index_t nbr_rows, int_t row_height
)
:
plt_(pl),
cell_rows_(placement_rows),
min_x_(min_x), max_x_(max_x),
y_origin_(y_origin),
row_height_(row_height)
{
assert(row_height > 0);
assert(min_x < max_x);
assert(rows.size() == nbr_rows);
neighbours_limits_.push_back(0);
for(index_t h : cell_heights){
neighbours_limits_.push_back(neighbours_limits_.back() + h);
}
neighbours_ .resize(neighbours_limits_.back(), std::pair<index_t, index_t>(null_ind, null_ind) );
row_first_cells_ .resize(nbr_rows, null_ind);
row_last_cells_ .resize(nbr_rows, null_ind);
std::vector<bool> explored(neighbours_limits_.back(), false);
// Now we extract the dependencies
for(index_t r=0; r<rows.size(); ++r){
if(not rows[r].empty()){
row_first_cells_[r] = rows[r].front();
row_last_cells_[r] = rows[r].back();
}
for(index_t c : rows[r]){
// Has this row of the cell already been visited?
assert(not explored[neighbour_index(c, r)]);
explored[neighbour_index(c, r)] = true;
}
for(index_t i=0; i+1<rows[r].size(); ++i){
index_t c1 = rows[r][i], c2 = rows[r][i+1];
// Save in the internal format
neighbours_[neighbour_index(c1, r)].second = c2;
neighbours_[neighbour_index(c2, r)].first = c1;
// The positions are correct
}
}
// Every level of every cell must have been visited
for(bool o : explored)
assert(o);
// Verify that we haven't made any obvious mistake
selfcheck();
}
void detailed_placement::selfcheck() const{
assert(row_first_cells_.size() == row_last_cells_.size());
for(index_t i=0; i<cell_cnt(); ++i){
for(index_t l=0; l<cell_height(i); ++l){
// not verified now since we don't modify the position for the obstacles
// : assert(c.position.x >= min_x_ and c.position.x + c.width <= max_x_);
index_t n_ind = l + neighbours_limits_[i];
assert(cell_rows_[i] + cell_height(i) <= row_cnt());
if(neighbours_[n_ind].first != null_ind){
index_t oi = neighbours_[n_ind].first;
// Correct neighbour position
assert(neighbours_[neighbour_index(oi, cell_rows_[i]+l)].second == i);
}
else{
// Beginning of a row
assert(row_first_cells_[cell_rows_[i] + l] == i);
}
if(neighbours_[n_ind].second != null_ind){
index_t oi = neighbours_[n_ind].second;
// Correct neighbour position
assert(neighbours_[neighbour_index(oi, cell_rows_[i]+l)].first == i);
}
else{
// End of a row
assert(row_last_cells_[cell_rows_[i] + l] == i);
}
}
}
}
void detailed_placement::swap_standard_cell_topologies(index_t c1, index_t c2){
assert(cell_height(c1) == cell_height(c2));
assert(cell_height(c1) == 1 and cell_height(c2) == 1);
index_t row_c1 = cell_rows_[c1],
row_c2 = cell_rows_[c2];
index_t b_c1 = neighbours_[neighbours_limits_[c1]].first;
index_t b_c2 = neighbours_[neighbours_limits_[c2]].first;
index_t a_c1 = neighbours_[neighbours_limits_[c1]].second;
index_t a_c2 = neighbours_[neighbours_limits_[c2]].second;
// Two cases: they were adjacent or they were not
// Luckily updating in the neighbours first then swapping the recorded neighbours works in both cases for standard cells
// Update the pointers in the cells' neighbours
if(b_c1 != null_ind) neighbours_[neighbour_index(b_c1, row_c1)].second = c2;
else row_first_cells_[row_c1] = c2;
if(b_c2 != null_ind) neighbours_[neighbour_index(b_c2, row_c2)].second = c1;
else row_first_cells_[row_c2] = c1;
if(a_c1 != null_ind) neighbours_[neighbour_index(a_c1, row_c1)].first = c2;
else row_last_cells_[row_c1] = c2;
if(a_c2 != null_ind) neighbours_[neighbour_index(a_c2, row_c2)].first = c1;
else row_last_cells_[row_c2] = c1;
// Swap the properties in both cells
std::swap(neighbours_[neighbours_limits_[c1]], neighbours_[neighbours_limits_[c2]]);
std::swap(cell_rows_[c1], cell_rows_[c2]);
}
std::pair<int_t, int_t> detailed_placement::get_limit_positions(netlist const & circuit, index_t c) const{
auto ret = std::pair<int_t, int_t>(min_x_, max_x_);
for(index_t l=neighbours_limits_[c]; l<neighbours_limits_[c+1]; ++l){
index_t b_i = neighbours_[l].first,
a_i = neighbours_[l].second;
if(b_i != null_ind){
ret.first = std::max(ret.first, plt_.positions_[b_i].x + circuit.get_cell(b_i).size.x);
}
if(a_i != null_ind){
ret.second = std::min(ret.second, plt_.positions_[a_i].x);
}
}
return ret;
}
index_t detailed_placement::get_first_cell_on_row(index_t r){
return row_first_cells_[r];
}
index_t detailed_placement::get_first_standard_cell_on_row(index_t r){
index_t c = get_first_cell_on_row(r);
while(c != null_ind and cell_height(c) != 1){
index_t next_c = get_next_cell_on_row(c, r);
assert(c != next_c);
c = next_c;
}
assert(c == null_ind or cell_rows_[c] == r);
return c;
}
index_t detailed_placement::get_next_cell_on_row(index_t c, index_t r){
return neighbours_[neighbour_index(c, r)].second;
}
index_t detailed_placement::get_prev_cell_on_row(index_t c, index_t r){
return neighbours_[neighbour_index(c, r)].first;
}
index_t detailed_placement::get_next_standard_cell_on_row(index_t c, index_t r){
do{
index_t next_c = get_next_cell_on_row(c, r);
assert(c != next_c);
c = next_c;
}while(c != null_ind and cell_height(c) != 1);
assert(c == null_ind or cell_rows_[c] == r);
return c;
}
void detailed_placement::reorder_cells(std::vector<index_t> const old_order, std::vector<index_t> const new_order, index_t r){
assert(old_order.size() == new_order.size());
assert(not old_order.empty());
index_t before_row = get_prev_cell_on_row(old_order.front(), r);
index_t after_row = get_next_cell_on_row(old_order.back(), r);
for(index_t i=0; i<new_order.size(); ++i){
auto & nghs = neighbours_[neighbour_index(new_order[i], r)];
if(i > 0){
nghs.first = new_order[i-1];
}
else{
nghs.first = before_row;
}
if(i+1 < new_order.size()){
nghs.second = new_order[i+1];
}
else{
nghs.second = after_row;
}
}
if(before_row != null_ind) neighbours_[neighbour_index(before_row, r)].second = new_order.front();
else row_first_cells_[r] = new_order.front();
if(after_row != null_ind) neighbours_[neighbour_index(after_row, r)].first = new_order.back();
else row_last_cells_[r] = new_order.back();
}
void detailed_placement::reorder_standard_cells(std::vector<index_t> const old_order, std::vector<index_t> const new_order){
assert(old_order.size() == new_order.size());
assert(not old_order.empty());
index_t before_row = neighbours_[neighbours_limits_[old_order.front()]].first;
index_t after_row = neighbours_[neighbours_limits_[old_order.back() ]].second;
index_t r = cell_rows_[new_order.front()];
for(index_t i=0; i<new_order.size(); ++i){
assert(cell_height(new_order[i]) == 1);
assert(cell_rows_[new_order[i]] == r);
auto & nghs = neighbours_[neighbours_limits_[new_order[i]]];
if(i > 0){
nghs.first = new_order[i-1];
}
else{
nghs.first = before_row;
}
if(i+1 < new_order.size()){
nghs.second = new_order[i+1];
}
else{
nghs.second = after_row;
}
}
if(before_row != null_ind) neighbours_[neighbour_index(before_row, r)].second = new_order.front();
else row_first_cells_[r] = new_order.front();
if(after_row != null_ind) neighbours_[neighbour_index(after_row, r)].first = new_order.back();
else row_last_cells_[r] = new_order.back();
}
void row_compatible_orientation(netlist const & circuit, detailed_placement & pl, bool first_row_orient){
for(index_t c=0; c<circuit.cell_cnt(); ++c){
if( (circuit.get_cell(c).attributes & YFlippable) != 0 and pl.cell_height(c) == 1){
pl.plt_.orientations_[c].y = (pl.cell_rows_[c] % 2 != 0) ^ first_row_orient;
}
}
}
} // namespace dp
} // namespace coloquinte

View File

@ -0,0 +1,452 @@
#include "coloquinte/legalizer.hxx"
#include "coloquinte/optimization_subproblems.hxx"
#include <iostream>
#include <sstream>
#include <algorithm>
#include <cmath>
#include <queue>
namespace coloquinte{
namespace dp{
void get_result(netlist const & circuit, detailed_placement const & dpl, placement_t & gpl){
for(index_t c=0; c<circuit.cell_cnt(); ++c){
if( (circuit.get_cell(c).attributes & XMovable) != 0)
gpl.positions_[c].x = dpl.plt_.positions_[c].x;
if( (circuit.get_cell(c).attributes & YMovable) != 0)
gpl.positions_[c].y = dpl.plt_.positions_[c].y;
if( (circuit.get_cell(c).attributes & XFlippable) != 0)
gpl.orientations_[c].x = dpl.plt_.orientations_[c].x;
if( (circuit.get_cell(c).attributes & YFlippable) != 0)
gpl.orientations_[c].y = dpl.plt_.orientations_[c].y;
}
}
struct cell_to_leg{
int_t x_pos, y_pos;
index_t original_cell;
int_t width;
index_t nbr_rows;
bool operator<(cell_to_leg const o) const{ return x_pos < o.x_pos; }
cell_to_leg(int_t x, int_t y, index_t ind, int_t w, index_t rows)
: x_pos(x), y_pos(y),
original_cell(ind),
width(w),
nbr_rows(rows)
{}
legalizable_task<int_t> task() const{ return legalizable_task<int_t>(width, x_pos, original_cell); }
};
struct fixed_cell_interval{
int_t min_x, max_x;
index_t cell_ind;
bool operator<(fixed_cell_interval const o) const{ return min_x > o.min_x; }
fixed_cell_interval(int_t mn, int_t mx, index_t ind) : min_x(mn), max_x(mx), cell_ind(ind){}
};
struct cell_leg_properties{
int_t x_pos;
index_t row_pos;
index_t ind;
cell_leg_properties(){}
cell_leg_properties(int_t x, int_t r, index_t i) : x_pos(x), row_pos(r), ind(i){}
};
std::vector<cell_leg_properties> simple_legalize(
std::vector<std::vector<fixed_cell_interval> > obstacles, std::vector<cell_to_leg> cells,
std::vector<std::vector<index_t> > & rows,
int_t x_min, int_t x_max, int_t y_orig,
int_t row_height, index_t nbr_rows
){
std::vector<int_t> first_available_position(nbr_rows, x_min);
rows.resize(nbr_rows);
// Sort the cells by x position
std::sort(cells.begin(), cells.end());
std::vector<cell_leg_properties> ret;
for(cell_to_leg C : cells){
// Dumb, quick and dirty best-fit legalization
bool found_location = false;
// Properties of the current best solution
int_t best_x=0;
int_t best_cost=0;
index_t best_row=0;
// Helper function
auto check_row_cost = [&](index_t r, cell_to_leg const cell, int_t additional_cost){
// Find where to put the cell in these rows
// Simple method: get a range where we can put the cell
assert(r + cell.nbr_rows <= nbr_rows);
assert(additional_cost >= 0);
// First position where we can put it
int_t cur_pos = *std::max_element(first_available_position.begin() + r, first_available_position.begin() + r + cell.nbr_rows);
int_t max_lim = x_max - cell.width;
int_t interval_lim;
do{
interval_lim = max_lim;
// For each row, test if obstacles prevent us from putting a cell here
// Until we find a correct position or are beyond the maximum position
for(index_t i = 0; i<cell.nbr_rows; ++i){
// Find the first obstacle which is after this position
// TODO: use lower/upper bound
auto it=obstacles[r+i].rbegin();
for(; it != obstacles[r+i].rend() && it->max_x <= cur_pos; ++it){
}
if(it != obstacles[r+i].rend()){ // There is an obstacle on the right
assert(it->min_x < it->max_x);
int_t cur_lim = it->min_x - cell.width; // Where the obstacles contrains us
interval_lim = std::min(cur_lim, interval_lim); // Constraint
if(cur_lim < cur_pos){ // If this particular obstacle constrained us so that it is not possible to make it here, we increment the position
cur_pos = std::max(it->max_x, cur_pos);
}
}
}
// Do it again until we find a solution
// TODO: continue until we can't find a better solution (currently sticks before the first obstacle if there is enough whitespace)
}while(interval_lim < cur_pos and interval_lim < max_lim and cur_pos < max_lim); // Not admissible and we encountered an obstacle and there is still hope
if(interval_lim >= cur_pos){ // An admissible solution is found (and if cell.x_pos is between cur_pos and interval_lim it is optimal)
int_t row_best_x = std::min(interval_lim, std::max(cur_pos, cell.x_pos));
int_t row_cost_x = std::abs((float)(row_best_x - cell.x_pos));
if(not found_location or row_cost_x + additional_cost < best_cost){
found_location = true;
best_cost = row_cost_x + additional_cost;
best_x = row_best_x;
best_row = r;
}
}
};
// The row where we would prefer the cell to go
if(C.nbr_rows > nbr_rows) throw std::runtime_error("Impossible to legalize a cell spanning more rows than are available\n");
index_t central_row = std::min( (index_t) std::max( (C.y_pos - y_orig) / row_height, 0), nbr_rows-C.nbr_rows);
// Try every possible row from the best one, until we can't improve the cost
for(index_t row_dist = 0;
(central_row + row_dist < nbr_rows or central_row >= row_dist)
and (not found_location or (int_t) row_dist * row_height * C.width < (int_t) row_height + best_cost);
++row_dist
){
if(central_row + row_dist < nbr_rows - C.nbr_rows){
int_t add_cost = C.width * std::abs((float)static_cast<int_t>(central_row + row_dist) * static_cast<int_t>(row_height) + y_orig - C.y_pos);
check_row_cost(central_row + row_dist, C, add_cost);
}
if(central_row >= row_dist){
int_t add_cost = C.width * std::abs((float)static_cast<int_t>(central_row - row_dist) * static_cast<int_t>(row_height) + y_orig - C.y_pos);
check_row_cost(central_row - row_dist, C, add_cost);
}
}
if(not found_location){ // We didn't find any whitespace to put the cell in
throw std::runtime_error("Didn't manage to pack a cell due to dumb algorithm\n");
}
else{
assert(best_x + C.width <= x_max and best_x >= x_min);
// Update the occupied rows
for(index_t r = best_row; r < best_row + C.nbr_rows; ++r){
// Include the obstacles
while(not obstacles[r].empty()
and obstacles[r].back().max_x <= best_x){
rows[r].push_back(obstacles[r].back().cell_ind);
obstacles[r].pop_back();
}
assert(obstacles[r].empty() or obstacles[r].back().min_x >= best_x + C.width);
rows[r].push_back(C.original_cell);
first_available_position[r] = best_x + C.width;
}
ret.push_back(cell_leg_properties(best_x, best_row, C.original_cell));
}
}
// Finally, push the remaining fixed cells
for(index_t r=0; r<nbr_rows; ++r){
while(not obstacles[r].empty()){
rows[r].push_back(obstacles[r].back().cell_ind);
obstacles[r].pop_back();
}
}
return ret;
}
// A better legalization function which is able to push already legalized cells
std::vector<cell_leg_properties> good_legalize(
std::vector<std::vector<fixed_cell_interval> > obstacles, std::vector<cell_to_leg> cells,
std::vector<std::vector<index_t> > & rows,
int_t x_min, int_t x_max, int_t y_orig,
int_t row_height, index_t nbr_rows
){
// Two possibilities:
// * Single OSRP (group of movable cells) at the current end of the row of standard cells
// * Multiple OSRPs, between each pair of obstacles
// -> allows pushing cells past obstacles
// -> tricky with multiple standard cell heights
// Therefore I chose single OSRP, which gets cleared and pushed to the final state whenever
// * we encounter a multiple-rows cell
// * a new standard cell gets past an obstacle
// The current group of standard cells on the right of the row
std::vector<OSRP_leg<int_t> > single_row_problems(nbr_rows);
for(index_t r=0; r<nbr_rows; ++r){
single_row_problems[r] = OSRP_leg<int_t>(x_min, obstacles[r].empty() ? x_max : obstacles[r].back().min_x);
}
rows.resize(nbr_rows);
// Sort the cells by x position
std::sort(cells.begin(), cells.end());
std::vector<cell_leg_properties> ret;
for(cell_to_leg C : cells){
// Dumb, quick and dirty best-fit legalization
bool found_location = false;
// Properties of the current best solution
int_t best_cost=0;
index_t best_row=0;
index_t obstacles_passed = 0;
// Helper function
auto check_row_cost = [&](index_t r, cell_to_leg const cell, int_t additional_cost){
// Find where to put the cell in these rows
// Check if we can put it in the current ranges and at what cost; if not or if the optimal position is beyond an obstacle, try after this obstacle too
assert(cell.nbr_rows > 0);
assert(r + cell.nbr_rows <= nbr_rows);
assert(additional_cost >= 0);
// Where can we put a standard cell if we allow to move the cells?
if(cell.nbr_rows == 1){
int_t cur_cost = 0;
// Can we simply add it to the single row problem?
bool found_here = single_row_problems[r].remaining_space() >= cell.width;
int_t loc_obstacles_passed = 0;
if(found_here){
// Check the cost of pushing it here with possible displacement
cur_cost = single_row_problems[r].get_cost(cell.task()); // Don't update the row
}
// Other positions where we can put it, without moving other cells this time
if(not found_here or cur_cost > 0){
index_t obstacles_to_throw = 0;
auto it = obstacles[r].rbegin();
while(it != obstacles[r].rend()){
++ obstacles_to_throw;
auto prev_it = it++;
int_t region_end = it != obstacles[r].rend() ? it->min_x : x_max;
if(region_end >= prev_it->max_x + cell.width){
int_t loc_x = std::min(region_end - cell.width, std::max(prev_it->max_x, cell.x_pos));
int_t loc_cost = cell.width * std::abs((float)(cell.x_pos - loc_x));
if(not found_here or cur_cost > loc_cost){
found_here = true;
cur_cost = loc_cost;
loc_obstacles_passed = obstacles_to_throw;
}
}
}
}
if(found_here and (not found_location or cur_cost + additional_cost < best_cost)){
found_location = true;
//std::cout << "Found with displacement cost " << cur_cost << " and total cost " << cur_cost + additional_cost << std::endl;
best_cost = cur_cost + additional_cost;
best_row = r;
obstacles_passed = loc_obstacles_passed;
if(loc_obstacles_passed > 0) assert(not obstacles[r].empty());
}
}
else{
// If it is a fixed cell, we use fixed locations
std::cerr << "cell.nbr_rows:" << cell.nbr_rows << std::endl;
throw std::runtime_error("I don't handle fucking macros (good_legalize)\n");
}
};
// The row where we would prefer the cell to go
if(C.nbr_rows > nbr_rows) throw std::runtime_error("Impossible to legalize a cell spanning more rows than are available\n");
index_t central_row = std::min( (index_t) std::max( (C.y_pos - y_orig) / row_height, 0), nbr_rows-C.nbr_rows);
// Try every possible row from the best one, until we can't improve the cost
for(index_t row_dist = 0;
(central_row + row_dist < nbr_rows or central_row >= row_dist)
and (not found_location or (int_t) row_dist * row_height * C.width < (int_t) row_height + best_cost);
++row_dist
){
if(central_row + row_dist < nbr_rows - C.nbr_rows){
int_t add_cost = C.width * std::abs((float)static_cast<int_t>(central_row + row_dist) * static_cast<int_t>(row_height) + y_orig - C.y_pos);
check_row_cost(central_row + row_dist, C, add_cost);
}
if(central_row >= row_dist){
int_t add_cost = C.width * std::abs((float)static_cast<int_t>(central_row - row_dist) * static_cast<int_t>(row_height) + y_orig - C.y_pos);
check_row_cost(central_row - row_dist, C, add_cost);
}
}
if(not found_location){ // We didn't find any whitespace to put the cell in
throw std::runtime_error("Didn't manage to pack a cell: leave more whitespace and avoid macros near the right side\n");
}
else{
//std::cout << "Cell " << C.original_cell << " of width " << C.width << " targetting row " << central_row << " and position " << C.x_pos << " put at row " << best_row << " with displacement " << best_cost / C.width << " with " << obstacles_passed << " obstacles passed" << std::endl;
// If the cell spans multiple rows, it becomes fixed
// In this case or if the cell goes after an obstacle, push everything before the cell to the fixed state
if(C.nbr_rows == 1){
if(obstacles_passed == 0){ // Ok; just update the old single row problem
single_row_problems[best_row].push(C.task()); // Push it to the row
}
else{
assert(obstacles_passed > 0);
// Empty the single row problem
for(auto p : single_row_problems[best_row].get_placement()){
rows[best_row].push_back(p.first);
ret.push_back(cell_leg_properties(p.second, best_row, p.first));
}
// Find where to put it
int_t region_begin = x_min;
for(index_t i=0; i<obstacles_passed; ++i){
assert(not obstacles[best_row].empty());
region_begin = obstacles[best_row].back().max_x;
rows[best_row].push_back(obstacles[best_row].back().cell_ind);
obstacles[best_row].pop_back();
}
int_t region_end = obstacles[best_row].empty() ? x_max : obstacles[best_row].back().min_x;
single_row_problems[best_row] = OSRP_leg<int_t>(region_begin, region_end);
assert(region_end - region_begin >= C.width);
single_row_problems[best_row].push(C.task()); // Push this only cell to the single row problem
}
}
else{
throw std::runtime_error("I don't handle fucking macros (here)\n");
}
}
}
for(index_t r=0; r<nbr_rows; ++r){
// Finally, push the remaining standard cells in the row
for(auto p : single_row_problems[r].get_placement()){
rows[r].push_back(p.first);
ret.push_back(cell_leg_properties(p.second, r, p.first));
}
// And the fixed cells
while(not obstacles[r].empty()){
rows[r].push_back(obstacles[r].back().cell_ind);
obstacles[r].pop_back();
}
}
rows.resize(nbr_rows);
return ret;
}
detailed_placement legalize(netlist const & circuit, placement_t const & pl, box<int_t> surface, int_t row_height){
if(row_height <= 0) throw std::runtime_error("The rows' height should be positive\n");
index_t nbr_rows = (surface.y_max - surface.y_min) / row_height;
// The position of the ith row is surface.y_min + i * row_height
std::vector<std::vector<fixed_cell_interval> > row_occupation(nbr_rows);
std::vector<cell_to_leg> cells;
placement_t new_placement = pl;
std::vector<index_t> placement_rows(circuit.cell_cnt());
std::vector<index_t> cell_heights(circuit.cell_cnt());
for(index_t i=0; i<circuit.cell_cnt(); ++i){
auto cur = circuit.get_cell(i);
// Assumes fixed if not both XMovable and YMovable
if( (cur.attributes & XMovable) != 0 && (cur.attributes & YMovable) != 0){
// Just truncate the position we target
point<int_t> target_pos = pl.positions_[i];
index_t cur_cell_rows = (cur.size.y + row_height -1) / row_height;
cells.push_back(cell_to_leg(target_pos.x, target_pos.y, i, cur.size.x, cur_cell_rows));
cell_heights[i] = cur_cell_rows;
}
else{
// In each row, we put the index of the fixed cell and the range that is already occupied
int_t low_x_pos = pl.positions_[i].x,
hgh_x_pos = pl.positions_[i].x + cur.size.x,
low_y_pos = pl.positions_[i].y,
hgh_y_pos = pl.positions_[i].y + cur.size.y;
new_placement.positions_[i] = point<int_t>(low_x_pos, low_y_pos);
if(hgh_y_pos <= surface.y_min or low_y_pos >= surface.y_max or hgh_x_pos <= surface.x_min or low_x_pos >= surface.x_max){
placement_rows[i] = null_ind;
cell_heights[i] = 0;
}
else{
assert(low_x_pos < hgh_x_pos and low_y_pos < hgh_y_pos);
int_t rnd_hgh_x_pos = std::min(surface.x_max, hgh_x_pos);
int_t rnd_hgh_y_pos = std::min(surface.y_max, hgh_y_pos);
int_t rnd_low_x_pos = std::max(surface.x_min, low_x_pos);
int_t rnd_low_y_pos = std::max(surface.y_min, low_y_pos);
index_t first_row = (rnd_low_y_pos - surface.y_min) / row_height;
index_t last_row = (index_t) (rnd_hgh_y_pos - surface.y_min + row_height - 1) / row_height; // Exclusive: if the cell spans the next row, i.e. pos % row_height >= 0, include it too
assert(last_row <= nbr_rows);
placement_rows[i] = first_row;
cell_heights[i] = last_row - first_row;
for(index_t r=first_row; r<last_row; ++r){
row_occupation[r].push_back(fixed_cell_interval(rnd_low_x_pos, rnd_hgh_x_pos, i));
}
}
}
}
for(std::vector<fixed_cell_interval> & L : row_occupation){
std::sort(L.begin(), L.end()); // Sorts from last to first, so that we may use pop_back()
// Doesn't collapse them yet, which may make for bigger complexities
for(index_t i=0; i+1<L.size(); ++i){
if(L[i].min_x < L[i+1].max_x) {
std::ostringstream message;
message << "Coloquinte::dp::legalize(): Sorry, I don't handle overlapping fixed cells yet ";
message << " i:" << i << " max_x: " << L[i].max_x << " > min_x:" << L[i+1].min_x << "\n";
throw std::runtime_error(message.str());
}
}
}
std::vector<std::vector<index_t> > cells_by_rows;
auto final_cells = good_legalize(row_occupation, cells, cells_by_rows,
surface.x_min, surface.x_max, surface.y_min,
row_height, nbr_rows
);
for(cell_leg_properties C : final_cells){
new_placement.positions_[C.ind] = point<int_t>(C.x_pos, static_cast<int_t>(C.row_pos) * row_height + surface.y_min);
placement_rows[C.ind] = C.row_pos;
}
return detailed_placement(
new_placement,
placement_rows,
cell_heights,
cells_by_rows,
surface.x_min, surface.x_max,
surface.y_min,
nbr_rows, row_height
);
}
} // namespace dp
} // namespace coloquinte

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,515 @@
#include "coloquinte/optimization_subproblems.hxx"
#include <stdexcept>
namespace coloquinte{
std::vector<capacity_t> transport_1D(std::vector<t1D_elt> sources, std::vector<t1D_elt> sinks){
/* Description of the algorithm:
*
* For each cell, put it in its optimal region or the last region where a cell is if there is no space in it
* Push all changes in the derivative of the cost function to a priority queue; those changes occur
* when evicting the preceding cell from a region (most such changes are 0 and not considered, hence the complexity)
* when moving to a non-full region
* While the new cell overlaps with a new region, get the new slope (derivative) at this point
* and push all preceding cell until this region is freed or the slope becomes 0 (in which case the new region is now occupied)
*/
struct bound{
capacity_t pos;
int_t slope_diff;
bool operator<(bound const o) const{ return pos < o.pos; }
};
std::priority_queue<bound> bounds;
std::vector<capacity_t> constraining_pos;
std::vector<capacity_t> prev_cap(1, 0), prev_dem(1, 0);
for(auto const s : sinks){
prev_cap.push_back(s.second + prev_cap.back());
}
for(auto const s : sources){
prev_dem.push_back(s.second + prev_dem.back());
}
// The sinks have enough capacity to hold the whole demand
assert(prev_cap.back() >= prev_dem.back());
const capacity_t min_abs_pos = 0, max_abs_pos = prev_cap.back() - prev_dem.back();
assert(min_abs_pos <= max_abs_pos);
auto push_bound = [&](capacity_t p, int_t s){
assert(s >= 0);
if(p > min_abs_pos){
bound B;
B.pos = p;
B.slope_diff = s;
bounds.push(B);
}
};
// Distance to the right - distance to the left
auto get_slope = [&](index_t src, index_t boundary){
assert(boundary+1 < sinks.size());
assert(src < sources.size());
return std::abs((float)(sources[src].first - sinks[boundary+1].first)) - std::abs((float)(sources[src].first - sinks[boundary].first));
};
capacity_t cur_abs_pos = min_abs_pos;
index_t opt_r=0, next_r=0, first_free_r=0;
for(index_t i=0; i<sources.size(); ++i){
// Update the optimal region
while(opt_r+1 < sinks.size() and (sinks[opt_r].first + sinks[opt_r+1].first)/2 < sources[i].first){
++opt_r;
}
// Update the next region
index_t prev_next_r = next_r;
while(next_r < sinks.size() and sinks[next_r].first <= sources[i].first){
++next_r;
}
index_t dest_reg = std::max(first_free_r, opt_r);
assert(dest_reg < sinks.size());
if(i>0){
// Push bounds due to changing the source crossing the boundary j/j+1
// Linear amortized complexity accross all sources (next_r grows)
// get_slope(i-1, j) - get_slope(i, j) == 0 if j >= next_r
// get_slope(i-1, j) - get_slope(i, j) == 0 if j < prev_next_r-1
for(index_t j=std::max(prev_next_r,1u)-1; j<std::min(first_free_r, next_r+1); ++j){
assert(get_slope(i,j) <= get_slope(i-1,j));
push_bound(prev_cap[j+1] - prev_dem[i], get_slope(i-1, j) - get_slope(i,j));
}
}
// Add the bounds due to crossing the boundaries alone
for(index_t j=first_free_r; j<opt_r; ++j){
assert(get_slope(i,j) <= 0);
push_bound(prev_cap[j+1] - prev_dem[i], -get_slope(i, j));
}
first_free_r = std::max(first_free_r, opt_r);
capacity_t this_abs_pos = std::max(cur_abs_pos, prev_cap[first_free_r] - prev_dem[i]); // Just after the previous cell or at the beginning of the destination region
while(first_free_r+1 < sinks.size() and this_abs_pos > std::max(prev_cap[first_free_r+1] - prev_dem[i+1], min_abs_pos)){ // Absolute position that wouldn't make the cell fit in the region, and we are not in the last region yet
capacity_t end_pos = std::max(prev_cap[first_free_r+1] - prev_dem[i+1], min_abs_pos);
int_t add_slope = get_slope(i, first_free_r);
int_t slope = add_slope;
while(not bounds.empty() and slope >= 0 and bounds.top().pos > end_pos){
this_abs_pos = bounds.top().pos;
slope -= bounds.top().slope_diff;
bounds.pop();
}
if(slope >= 0){ // We still push: the cell completely escapes the region
this_abs_pos = end_pos;
push_bound(end_pos, add_slope-slope);
}
else{ // Ok, absorbed the whole slope: push what remains and we still occupy the next region
push_bound(this_abs_pos, -slope);
++first_free_r;
}
}
cur_abs_pos = this_abs_pos;
constraining_pos.push_back(this_abs_pos);
}
assert(constraining_pos.size() == sources.size());
if(not constraining_pos.empty()){
// Calculate the final constraining_pos
constraining_pos.back() = std::min(max_abs_pos, constraining_pos.back());
}
std::partial_sum(constraining_pos.rbegin(), constraining_pos.rend(), constraining_pos.rbegin(), [](capacity_t a, capacity_t b)->capacity_t{ return std::min(a, b); });
for(index_t i=0; i<constraining_pos.size(); ++i){
constraining_pos[i] += prev_dem[i];
}
return constraining_pos;
}
namespace{ // Anonymous namespace to hide the transportation structures
class current_allocation{
static const index_t null_ind;
// Internal data structures
// Priority queue element to determine the source to be used between regions
struct movable_source{
index_t source;
float_t cost;
bool operator<(movable_source const o) const{
return cost > o.cost // Sorted by cost
|| (cost == o.cost && source < o.source); // And by index to limit the number of fractional elements between two regions
}
movable_source(index_t s, float_t c) : source(s), cost(c) {}
};
// Member data
// The current state
std::vector<std::vector<capacity_t> > sr_allocations; // For each region, for each source, the capacity allocated by the region
std::vector<std::vector<float_t> > sr_costs; // The costs from a region to a source
std::vector<capacity_t> s_demands; // The demands of the sources
std::vector<capacity_t> r_capacities; // The remaining capacities of the regions
// Shortest path data
std::vector<float_t> r_costs; // The costs of allocating to a region
std::vector<index_t> r_parents; // The parents of the regions i.e. the regions where we push sources first (or null_ind)
std::vector<index_t> r_sources; // The source involved in these edges
std::vector<capacity_t> arc_capacities; // The capacities of the edges to the parents, or of the region if no parent
// Best edges data
std::vector<std::vector<std::priority_queue<movable_source> > > best_interregions_costs; // What is the best source to move to go from region k1 to region k2?
index_t dijkstra_cnt;
// Helper functions
// Number of regions
index_t region_cnt() const{
assert(sr_costs.size() == sr_allocations.size());
return sr_costs.size();
}
// Update the edge between two regions
void update_edge(index_t r1, index_t r2);
// Add a source to all heaps of a region; returns if we need to update a path
bool add_source_to_heaps(index_t r, index_t source);
// Initialize the heaps of a region
void create_heaps(index_t reg);
// Run the shortest path algorithm to update the cost of each region
void dijkstra_update();
// Update the edge and returns if we need to rerun Dijkstra
bool push_edge(index_t reg, capacity_t flow);
// Updates a full path when pushing an element; returns if we need to rerun Dijkstra
bool push_path(index_t pushed_reg, capacity_t demanded, capacity_t & flow);
public:
// Add a new source to the transportation problem; should be done in decreasing order of demand to keep low complexity
void add_source(index_t elt_ind);
current_allocation(std::vector<capacity_t> caps, std::vector<capacity_t> demands, std::vector<std::vector<float_t> > costs)
:
sr_allocations(caps.size()),
sr_costs(costs),
s_demands(demands),
r_capacities(caps),
r_costs(caps.size(), 0.0),
r_parents(caps.size(), null_ind),
r_sources(caps.size(), null_ind),
arc_capacities(caps),
best_interregions_costs(caps.size(), std::vector<std::priority_queue<movable_source> >(caps.size())),
dijkstra_cnt(0)
{
assert(caps.size() > 0);
assert(costs.size() == caps.size());
dijkstra_update();
}
std::vector<std::vector<capacity_t> > get_allocations() const{ return sr_allocations; }
index_t get_iterations_cnt() const { return dijkstra_cnt; }
};
const index_t current_allocation::null_ind = std::numeric_limits<index_t>::max();
void current_allocation::update_edge(index_t r1, index_t r2){
while(not best_interregions_costs[r1][r2].empty() and sr_allocations[r1][best_interregions_costs[r1][r2].top().source] == 0){
best_interregions_costs[r1][r2].pop();
}
if(not best_interregions_costs[r1][r2].empty()){
// There is an edge
movable_source cur = best_interregions_costs[r1][r2].top();
float_t new_cost = r_costs[r2] + cur.cost;
if(new_cost < r_costs[r1]){
r_costs[r1] = cur.cost;
r_sources[r1] = cur.source;
r_parents[r1] = r2;
arc_capacities[r1] = sr_allocations[r1][cur.source];
}
}
}
bool current_allocation::add_source_to_heaps(index_t r, index_t source){
bool need_rerun = false;
for(index_t i=0; i<region_cnt(); ++i){
if(i == r) continue;
best_interregions_costs[r][i].push(
movable_source(source,
sr_costs[i][source] - sr_costs[r][source]
)
);
while(sr_allocations[r][best_interregions_costs[r][i].top().source] == 0){
best_interregions_costs[r][i].pop();
}
need_rerun = (best_interregions_costs[r][i].top().source == source) or need_rerun;
}
return need_rerun;
}
void current_allocation::create_heaps(index_t reg){
// Get all relevant elements
std::vector<std::vector<movable_source> > interregion_costs(region_cnt());
for(index_t i=0; i<sr_allocations[reg].size(); ++i){
if(sr_allocations[reg][i] > 0){
for(index_t oreg=0; oreg<region_cnt(); ++oreg){
if(oreg == reg) continue;
interregion_costs[oreg].push_back(
movable_source(
i,
sr_costs[oreg][i] - sr_costs[reg][i]
)
);
}
}
}
// Create the heaps
for(index_t oreg=0; oreg<region_cnt(); ++oreg){
best_interregions_costs[reg][oreg] = std::priority_queue<movable_source>(interregion_costs[oreg].begin(), interregion_costs[oreg].end());
}
}
// Returns if the path has been modified so that we would need to rerun Dijkstra
bool current_allocation::push_edge(index_t reg, capacity_t flow){
index_t cur_source = r_sources[reg];
// Does this edge allocates a new source in the destination region? If yes, update the corresponding heaps
bool already_present = sr_allocations[r_parents[reg]][cur_source] > 0;
// Deallocating from the first region is handled by the get_edge function: just substract the flow
sr_allocations[ reg ][cur_source] -= flow;
sr_allocations[r_parents[reg]][cur_source] += flow;
assert(sr_allocations[reg][cur_source] >= 0); // The source to be pushed was indeed present in the region
assert(r_capacities[reg] == 0); // The region is full, which explains why we need to push
assert(flow <= arc_capacities[reg]); // The flow is not bigger than what can be sent
arc_capacities[reg] = sr_allocations[reg][cur_source]; // Just update the capacity if it turns out that we don't need to run Dijkstra
if(arc_capacities[reg] == 0){
// The source may have been deleted from a region: rerun Dijkstra at the end
return true;
}
else if(not already_present and r_capacities[r_parents[reg]] == 0){
// A new source is allocated to a full region: rerun Dijkstra at the end if it changed the heap's top
return add_source_to_heaps(r_parents[reg], cur_source);
}
else{
// The edge is still present with the same cost and non-zero updated capacity
// The path still exists: no need to rerun Dijkstra yet
return false;
}
}
void current_allocation::dijkstra_update(){
// Simple case of the regions with remaining capacity
std::vector<int> visited(region_cnt(), 0);
index_t visited_cnt = 0;
for(index_t i=0; i<region_cnt(); ++i){
r_sources[i] = null_ind;
r_parents[i] = null_ind;
if(r_capacities[i] > 0){
r_costs[i] = 0.0;
arc_capacities[i] = r_capacities[i];
visited[i] = 1;
++visited_cnt;
}
else{
r_costs[i] = std::numeric_limits<float_t>::infinity();
arc_capacities[i] = 0;
}
}
// if(visited_cnt <= 0) throw std::runtime_error("Capacity problem: no region has been marked as reachable\n");
if(visited_cnt == region_cnt()){ return; }
// Get the costs for every non-visited region
for(index_t i=0; i<region_cnt(); ++i) if(visited[i] == 0){ // For every region that is not visited yet
for(index_t j=0; j<region_cnt(); ++j) if(visited[j] == 1){ // For every already visited region
// Get the best interregion cost
update_edge(i,j);
}
}
while(visited_cnt < region_cnt()){
// Find the region with the lowest cost to visit; mark it visited
index_t best_reg = null_ind;
float_t best_cost = std::numeric_limits<float_t>::infinity();
for(index_t i=0; i<region_cnt(); ++i) if(visited[i] == 0){ // For every region that is not visited yet
if(r_costs[i] < best_cost){
best_cost = r_costs[i];
best_reg = i;
}
}
if(best_reg == null_ind) break; // Some regions are unreachable, typically because they have zero capacity at the beginning
visited[best_reg] = 1;
++visited_cnt;
// Update the cost for every unvisited region
for(index_t i=0; i<region_cnt(); ++i) if(visited[i] == 0){ // For every region that is not visited yet
update_edge(i, best_reg);
}
}
}
bool current_allocation::push_path(index_t pushed_reg, capacity_t demanded, capacity_t & flow){
// Get the final flow sent, which is smaller than the capacities on the path
flow = demanded;
for(index_t reg = pushed_reg; reg != null_ind; reg = r_parents[reg]){
flow = std::min(flow, arc_capacities[reg]);
}
bool rerun_dijkstra = false;
// Update the path between the regions
index_t reg = pushed_reg;
for(; r_parents[reg] != null_ind; reg = r_parents[reg]){
assert(r_capacities[reg] == 0);
rerun_dijkstra = push_edge(reg, flow) or rerun_dijkstra;
}
assert(r_capacities[reg] > 0);
assert(arc_capacities[reg] == r_capacities[reg]);
assert(r_capacities[reg] >= flow);
// Update the capacities at the end
r_capacities[reg] -= flow;
arc_capacities[reg] -= flow;
// The last region on the path is the one that satisfies the demand
if(r_capacities[reg] == 0){ // If we just consumed the available capacity, it becomes useful to move sources off this region: build the heap
create_heaps(reg);
rerun_dijkstra = true;
}
assert(flow > 0);
// If an edge changes cost or a region is full,
// we need to update the costs, parents, sources and arc_capacities using a Dijkstra
// but later
return rerun_dijkstra;
}
void current_allocation::add_source(index_t elt_ind){ //capacity_t demand, std::vector<float_t> const & costs){
for(index_t i=0; i<region_cnt(); ++i){
sr_allocations[i].push_back(0);
}
bool need_rerun = false;
capacity_t demand = s_demands[elt_ind];
while(demand > 0){
// In case we modified the structures earlier
if(need_rerun){
dijkstra_update();
need_rerun = false;
}
++ dijkstra_cnt;
index_t best_reg = null_ind;
float_t best_cost = std::numeric_limits<float_t>::infinity();
for(index_t reg=0; reg<region_cnt(); ++reg){
// Find the region which gets the source
if(r_costs[reg] + sr_costs[reg][elt_ind] < best_cost){
best_reg = reg;
best_cost = r_costs[reg] + sr_costs[reg][elt_ind];
}
}
if(best_reg == null_ind){ throw std::runtime_error("No reachable region found\n"); }
capacity_t flow = 0;
// Tells us whether we need to update the data structures
need_rerun = push_path(best_reg, demand, flow);
demand -= flow;
// Lazily store the change
sr_allocations[best_reg][elt_ind] += flow;
}
// Set the source's demand
for(index_t i=0; i<region_cnt(); ++i){
if(r_capacities[i] == 0 and sr_allocations[i][elt_ind] > 0){
need_rerun = add_source_to_heaps(i, elt_ind) or need_rerun;
}
}
// We leave a clean set with correct paths for the next iteration
if(need_rerun)
dijkstra_update();
}
} // End anonymous namespace
std::vector<std::vector<capacity_t> > transport_generic(std::vector<capacity_t> const & capacities, std::vector<capacity_t> const & demands, std::vector<std::vector<float_t> > const & costs){
current_allocation transporter(capacities, demands, costs);
for(index_t i=0; i<demands.size(); ++i){
transporter.add_source(i);
}
return transporter.get_allocations();
}
bool place_convex_single_row(std::vector<int_t> const & widths, std::vector<std::pair<int_t, int_t> > const & ranges, std::vector<cell_bound> bounds, std::vector<int_t> const & const_slopes, std::vector<int_t> & positions){
std::sort(bounds.begin(), bounds.end());
struct bound{
int_t abs_pos;
int_t slope_diff;
bool operator<(bound const o) const{ return abs_pos < o.abs_pos; }
bound(int_t p, int_t s) : abs_pos(p), slope_diff(s) {}
};
std::priority_queue<bound> prio_queue;
std::vector<int_t> prev_widths(widths.size()+1, 0);
std::partial_sum(widths.begin(), widths.end(), std::next(prev_widths.begin()));
std::vector<int_t> constraining_pos(widths.size());
int_t lower_lim = std::numeric_limits<int_t>::min();
for(index_t i=0, j=0; i<widths.size(); ++i){
int_t old_width = prev_widths[i];
int_t new_width = prev_widths[i+1];
lower_lim = std::max(ranges[i].first - old_width, lower_lim);
int_t upper_lim = ranges[i].second - new_width;
for(; j<bounds.size() and bounds[j].c == i; ++j){
prio_queue.push(bound(bounds[j].pos - old_width, bounds[j].slope));
}
if(upper_lim < lower_lim){ // Infeasible
return false;
}
int_t cur_slope = const_slopes[i];
int_t cur_pos = upper_lim;
while(not prio_queue.empty() and (cur_slope > 0 or prio_queue.top().abs_pos > upper_lim)){
cur_slope -= prio_queue.top().slope_diff;
cur_pos = prio_queue.top().abs_pos;
prio_queue.pop();
}
int_t final_abs_pos = std::max(std::min(cur_pos, upper_lim), lower_lim);
constraining_pos[i] = final_abs_pos;
if(cur_slope < 0){
prio_queue.push(bound(final_abs_pos, -cur_slope));
}
}
positions.resize(constraining_pos.size());
std::partial_sum(constraining_pos.rbegin(), constraining_pos.rend(), positions.rbegin(), [](int_t a, int_t b)->int_t{ return std::min(a,b); });
for(index_t i=0; i<positions.size(); ++i){
positions[i] += prev_widths[i];
}
return true;
}
bool place_noncvx_single_row(std::vector<int_t> const & widths, std::vector<std::pair<int_t, int_t> > const & ranges, std::vector<int> const & flippables, std::vector<cell_bound> bounds, std::vector<int_t> const & const_slopes, std::vector<int_t> & positions, std::vector<int> & flippings){
flippings = std::vector<int>(positions.size(), 0);
return place_convex_single_row(widths, ranges, bounds, const_slopes, positions);
}
} // Namespace coloquinte

View File

@ -0,0 +1,166 @@
#include "coloquinte/circuit_helper.hxx"
#include <stack>
#include <functional>
#include <algorithm>
namespace coloquinte{
namespace gp{
namespace{
//index_t const null_ind = std::numeric_limits<index_t>::max();
inline void opt_orient(netlist const & circuit, placement_t & pl, std::function<int_t (point<int_t>)> i_coor, std::function<bool & (point<bool> &)> b_coor,mask_t FLIPPABLE){
std::stack<index_t> opt_cells;
for(index_t cell_ind = 0; cell_ind < circuit.cell_cnt(); ++cell_ind){
if( (circuit.get_cell(cell_ind).attributes & FLIPPABLE) != 0)
opt_cells.push(cell_ind);
}
while(not opt_cells.empty()){
index_t cell_ind = opt_cells.top(); opt_cells.pop();
assert((circuit.get_cell(cell_ind).attributes & FLIPPABLE) != 0);
// What is the current orientation?
bool old_orientation = b_coor(pl.orientations_[cell_ind]);
int_t pos = i_coor(pl.positions_[cell_ind]);
int_t size = i_coor(circuit.get_cell(cell_ind).size);
// Check both orientations of the cell
std::vector<index_t> involved_nets;
for(netlist::pin_t p : circuit.get_cell(cell_ind)){
involved_nets.push_back(p.net_ind);
}
// Deal with cells with multiple pins in one net (uniquify)
std::sort(involved_nets.begin(), involved_nets.end());
involved_nets.resize(std::distance(involved_nets.begin(), std::unique(involved_nets.begin(), involved_nets.end())));
std::int64_t p_cost = 0, n_cost = 0;
std::vector<index_t> extreme_elements;
for(index_t n : involved_nets){
std::vector<pin_1D> other_pins;
std::vector<int_t> offsets;
for(auto p : circuit.get_net(n)){
if(p.cell_ind != cell_ind){
other_pins.push_back(pin_1D(
p.cell_ind,
i_coor(pl.positions_[p.cell_ind])
+ (b_coor(pl.orientations_[p.cell_ind]) ? i_coor(p.offset) : i_coor(circuit.get_cell(p.cell_ind).size) - i_coor(p.offset)),
0, // Don't care about the offset
(circuit.get_cell(p.cell_ind).attributes & FLIPPABLE) != 0)
);
}
else{
offsets.push_back(i_coor(p.offset));
}
}
assert(offsets.size() > 0);
if(other_pins.size() > 0){ // Else the orientation of the cell doesn't change anything
auto minmaxC = std::minmax_element(other_pins.begin(), other_pins.end());
auto minmaxO = std::minmax_element(offsets.begin(), offsets.end());
p_cost += std::max(pos + *minmaxO.second, minmaxC.second->pos) - std::min(pos + *minmaxO.first, minmaxC.first->pos);
n_cost += std::max(pos + size - *minmaxO.first, minmaxC.second->pos) - std::min(pos + size - *minmaxO.second, minmaxC.first->pos);
int_t min_pin_pos = std::min(pos + *minmaxO.second, pos + size - *minmaxO.first),
max_pin_pos = std::max(pos + *minmaxO.second, pos + size - *minmaxO.first);
// Do the extreme elements change between the two positions?
if(minmaxC.second->movable
and (minmaxC.second->pos < max_pin_pos)
and (minmaxC.second->pos > min_pin_pos) ){
extreme_elements.push_back(minmaxC.second->cell_ind);
}
if(minmaxC.first->movable
and (minmaxC.first->pos < max_pin_pos)
and (minmaxC.first->pos > min_pin_pos) ){
extreme_elements.push_back(minmaxC.first->cell_ind);
}
}
}
if(p_cost < n_cost)
b_coor(pl.orientations_[cell_ind]) = true;
if(p_cost > n_cost)
b_coor(pl.orientations_[cell_ind]) = false;
// If we changed the orientation, check the extreme pins which changed and try their cells again
if(b_coor(pl.orientations_[cell_ind]) != old_orientation){
std::sort(extreme_elements.begin(), extreme_elements.end());
extreme_elements.resize(std::distance(extreme_elements.begin(), std::unique(extreme_elements.begin(), extreme_elements.end())));
for(index_t extreme_cell : extreme_elements){
if( (circuit.get_cell(extreme_cell).attributes & FLIPPABLE) != 0)
opt_cells.push(extreme_cell);
}
}
}
}
/*
inline void spread_orient(netlist const & circuit, placement_t & pl, std::function<float_t & (point<float_t> &)> coor, mask_t FLIPPABLE){
std::vector<float_t> weights(circuit.cell_cnt(), 0.0);
for(index_t n=0; n<circuit.net_cnt(); ++n){
float_t min_pos=INF, max_pos=-INF;
float_t min_offs=INF, max_offs=-INF;
index_t min_ind=null_ind, max_ind=null_ind;
for(netlist::pin_t p : circuit.get_net(n)){
if( (circuit.get_cell(p.cell_ind).attributes & FLIPPABLE) != 0){
float_t pos = coor(pl.positions_[p.cell_ind]);
if(pos < min_pos){
min_pos = pos;
min_ind = p.cell_ind;
min_offs = coor(p.offset);
}
if(pos > max_pos){
max_pos = pos;
max_ind = p.cell_ind;
max_offs = coor(p.offset);
}
}
else{
float_t pos = coor(pl.positions_[p.cell_ind]) + coor(pl.orientations_[p.cell_ind]) * coor(p.offset);
if(pos < min_pos){
min_pos = pos;
min_ind = null_ind;
}
if(pos > max_pos){
max_pos = pos;
max_ind = null_ind;
}
}
}
float_t net_weight = circuit.get_net(n).weight;
if(min_ind != null_ind) weights[min_ind] += net_weight * min_offs;
if(max_ind != null_ind) weights[max_ind] -= net_weight * max_offs;
}
for(index_t c=0; c<circuit.cell_cnt(); ++c){
coor(pl.orientations_[c]) = (weights[c] >= 0.0) ? 1.0 : -1.0;
}
}
*/
} // End anonymous namespace
void optimize_x_orientations(netlist const & circuit, placement_t & pl){
opt_orient(circuit, pl, [](point<int_t> p) -> int_t { return p.x; }, [](point<bool> & p) -> bool & { return p.x; }, XFlippable);
}
void optimize_y_orientations(netlist const & circuit, placement_t & pl){
opt_orient(circuit, pl, [](point<int_t> p) -> int_t { return p.y; }, [](point<bool> & p) -> bool & { return p.y; }, YFlippable);
}
// Iteratively optimize feasible orientations; performs only one pass
void optimize_exact_orientations(netlist const & circuit, placement_t & pl){
optimize_x_orientations(circuit, pl);
optimize_y_orientations(circuit, pl);
}
/*
void spread_orientations(netlist const & circuit, placement_t & pl){
spread_orient(circuit, pl, [](point<float_t> & p) -> float_t & { return p.x; }, XFlippable);
spread_orient(circuit, pl, [](point<float_t> & p) -> float_t & { return p.y; }, YFlippable);
}
*/
} // namespace gp
} // namespace coloquinte

View File

@ -0,0 +1,260 @@
#include "coloquinte/piecewise_linear.hxx"
#include <cassert>
#include <cmath>
namespace coloquinte{
namespace{
struct pl_edge{
p_v f, s;
static void push_intersections(pl_edge a, pl_edge b, piecewise_linear_function & lf){
// Strict, because it makes everything easier
//assert(a.f.first < b.s.first and a.s.first > b.f.first);
//assert(a.f.first < a.s.first and b.f.first < b.s.first);
assert(a.f.first <= b.s.first and a.s.first >= b.f.first);
assert(a.f.first <= a.s.first and b.f.first <= b.s.first);
// ra = (a.s.second - a.f.second) / (a.s.first - a.f.first)
// xintersect = (yb - ya - xb * rb + xa * ra) / (ra - rb)
double ra = static_cast<double>(a.s.second - a.f.second) / (a.s.first - a.f.first);
double rb = static_cast<double>(b.s.second - b.f.second) / (b.s.first - b.f.first);
double xintersect = (b.f.second - a.f.second - rb * b.f.first + ra * a.f.first) / (ra - rb);
if( not xintersect ) return;
int_t pos = xintersect;
if( std::ceil(xintersect) == std::floor(xintersect) ){ // Exact integer intersection
if(pos > std::max(a.f.first, b.f.first) and pos < std::min(a.s.first, b.s.first) ){ // Necessarily smaller than s.first due to the previous condition
lf.point_values.push_back(p_v(pos, a.value_at(pos)));
}
}
else{ // Non exact intersection: create two integers since I don't want to mess with floating point
int_t pos1 = pos;
int_t pos2 = pos + 1;
// Value_at is only an approximation, but it shouldn't be too bad
if(pos1 > std::max(a.f.first, b.f.first) and pos1 < std::min(a.s.first, b.s.first))
lf.point_values.push_back(p_v(pos1, std::min(a.value_at(pos1), b.value_at(pos1))));
if(pos2 > std::max(a.f.first, b.f.first) and pos2 < std::min(a.s.first, b.s.first))
lf.point_values.push_back(p_v(pos2, std::min(a.value_at(pos2), b.value_at(pos2))));
}
}
// Lower-rounded value
int_t value_at(int_t pos) const{
assert(pos >= f.first and pos <= s.first and s.first > f.first);
return (static_cast<std::int64_t>(f.second) * (s.first - pos) + static_cast<std::int64_t>(s.second) * (pos - f.first)) / (s.first - f.first);
}
// Lower-rounded value
int_t pos_at(int_t val) const{
assert(val <= std::max(f.second, s.second) and val >= std::min(f.second, s.second));
assert(f.second != s.second);
return (static_cast<std::int64_t>(f.first) * (s.second - val) + static_cast<std::int64_t>(s.first) * (val - f.second)) / (s.second - f.second);
}
bool above(p_v const o) const{
int_t pos = o.first;
assert(pos > f.first and pos < s.first);
return (static_cast<std::int64_t>(f.second) * (s.first - pos) + static_cast<std::int64_t>(s.second) * (pos - f.first)) > o.second * (s.first - f.first);
}
pl_edge(p_v a, p_v b) : f(a), s(b) {}
};
} // End anonymous namespace
void piecewise_linear_function::add_monotone(int_t slope, int_t offset){
for(auto & V : point_values){
// Offset taken into account here, multiplied with the slope
V.second += slope * (V.first - point_values.front().first - offset);
}
}
void piecewise_linear_function::add_bislope(int_t s_l, int_t s_r, int_t pos){
//assert(pos <= point_values.back().first);
//assert(pos >= point_values.front().first);
/*
if(pos >= point_values.back().first){
add_monotone(s_l, pos - point_values.front().first);
}
else if(pos <= point_values.front().first){
add_monotone(s_r, pos - point_values.front().first);
}
else{
auto it = point_values.begin();
while(it->first < pos){
it->second += s_l * (it->first - pos);
++it;
assert(it != point_values.end());
}
if(it->first != pos){
point_values.insert(it, p_v(pos, pl_edge(*std::prev(it), *it).value_at(pos)));
}
for(auto & V : point_values){
if(V.first > pos)
V.second += s_r * (V.first - pos);
}
}
*/
auto it = std::lower_bound(point_values.begin(), point_values.end(), pos, [](p_v o, int_t v){ return o.first < v; });
if(it != point_values.end() and it->first != pos and it != point_values.begin()){
assert(it->first > pos);
point_values.insert(it, p_v(pos, pl_edge(*std::prev(it), *it).value_at(pos)));
}
for(auto & V : point_values){
if(V.first > pos)
V.second += s_r * (V.first - pos);
if(V.first < pos)
V.second += s_l * (V.first - pos);
}
}
piecewise_linear_function::piecewise_linear_function(int_t min_def, int_t max_def){
point_values.push_back(p_v(min_def, 0));
point_values.push_back(p_v(max_def, 0));
}
piecewise_linear_function piecewise_linear_function::previous_min() const{
piecewise_linear_function ret;
assert(not point_values.empty());
auto it = point_values.begin();
ret.point_values.push_back(*it);
++it;
// Use the previous minimum to detect when we find something smaller
for(; it != point_values.end(); ++it){
int_t cur_min = ret.point_values.back().second;
assert(it->first >= ret.point_values.back().first);
if(it->second < cur_min){
if(std::prev(it)->first != ret.point_values.back().first){ // May be equal, in which case we don't need to push anything new
int_t pos = pl_edge(*std::prev(it), *it).pos_at(cur_min);
if(pos != ret.point_values.back().first and pos != it->first){
ret.point_values.push_back(p_v(pos, cur_min));
}
}
ret.point_values.push_back(*it);
}
}
return ret;
}
piecewise_linear_function piecewise_linear_function::previous_min_of_sum(piecewise_linear_function const & a, int_t shift) const{
piecewise_linear_function ret;
// Go to the correct definition
auto b_begin = point_values.begin(), a_begin = a.point_values.begin();
auto b_it = b_begin, a_it = a_begin;
auto b_end = point_values.end(), a_end = a.point_values.end();
while(a_it != a_end){
if(b_it == b_end or a_it->first < b_it->first+shift){ // Ok, create an edge and calculate the value
if(b_it != b_begin){
int_t value;
if(b_it != b_end){
pl_edge b_edge(*std::prev(b_it), *b_it);
value = b_edge.value_at(a_it->first-shift);
}
else{
value = point_values.back().second;
}
ret.point_values.push_back(p_v(a_it->first, a_it->second + value));
}
++a_it;
}
else if(a_it->first > b_it->first+shift){
if(a_it != a_begin){
pl_edge a_edge(*std::prev(a_it), *a_it);
int_t value = a_edge.value_at(b_it->first+shift);
ret.point_values.push_back(p_v(b_it->first+shift, b_it->second + value));
}
++b_it;
}
else{ // if(a_it->first == b_it->first+shift){
ret.point_values.push_back(p_v(a_it->first, a_it->second + b_it->second));
++a_it;
++b_it;
}
}
return ret.previous_min();
}
int_t piecewise_linear_function::last_before(int_t pos) const{
auto it = point_values.rbegin();
while(it != point_values.rend()){
if(it->first <= pos){
if(it != point_values.rbegin() and std::prev(it)->first > pos){ // On a negative slope
return pos;
}
else{
return it->first; // First point or not mapped to a negative slope in the original function
}
}
++it;
}
assert(false); // We should have found it if the bound was correct
return -1;
}
int_t piecewise_linear_function::value_at(int_t pos) const{
// First position bigger or equal than pos
auto it = std::lower_bound(point_values.begin(), point_values.end(), pos, [](p_v o, int_t v){ return o.first < v; });
if(pos != it->first){
assert(it != point_values.begin());
return pl_edge(*std::prev(it), *it).value_at(pos);
}
else{
return it->second;
}
}
piecewise_linear_function piecewise_linear_function::piecewise_linear_function::minimum(piecewise_linear_function const & a, piecewise_linear_function const & b){
assert(a.point_values.front().first == b.point_values.front().first);
assert(a.point_values.back().first == b.point_values.back().first);
piecewise_linear_function ret;
auto a_it = a.point_values.begin(), b_it = b.point_values.begin();
auto a_end = a.point_values.end(), b_end = b.point_values.end();
ret.point_values.push_back(p_v(a_it->first, std::min(a_it->second, b_it->second)));
assert(std::next(a_it) != a_end and std::next(b_it) != b_end);
while(std::next(a_it) != a_end and std::next(b_it) != b_end){
pl_edge a_edge(*a_it, *std::next(a_it)), b_edge(*b_it, *std::next(b_it));
// Three cases: one of them always below, or both intersect
// Both intersect: we push the values when intersecting
pl_edge::push_intersections(a_edge, b_edge, ret);
// In any case, we push the value of the one below if it finishes, and increment the iterator
if(a_edge.s.first < b_edge.s.first){
++a_it;
if(b_edge.above(a_edge.s)){ // We push a_edge.s
ret.point_values.push_back(a_edge.s);
}
}
else if(a_edge.s.first > b_edge.s.first){
++b_it;
if(a_edge.above(b_edge.s)){ // We push a_edge.s
ret.point_values.push_back(b_edge.s);
}
}
else{
ret.point_values.push_back(p_v(a_edge.s.first, std::min(a_edge.s.second, b_edge.s.second)));
++a_it;
++b_it;
}
}
return ret;
}
} // End namespace coloquinte

File diff suppressed because it is too large Load Diff

599
coloquinte/src/row_opt.cxx Normal file
View File

@ -0,0 +1,599 @@
#include "coloquinte/detailed.hxx"
#include "coloquinte/circuit_helper.hxx"
#include "coloquinte/optimization_subproblems.hxx"
#include "coloquinte/union_find.hxx"
#include "coloquinte/piecewise_linear.hxx"
#include <cassert>
#include <iostream>
namespace coloquinte{
namespace dp{
namespace{
struct minmax{
int_t min, max;
minmax(){}
minmax(int_t f, int_t s) : min(f), max(s){}
void merge(minmax const o){
min = std::min(min, o.min);
max = std::max(max, o.max);
}
void merge(int_t const o){
merge(minmax(o, o));
}
};
struct order_gettr{
index_t cell_ind, seq_order;
bool operator<(order_gettr const o) const{ return cell_ind < o.cell_ind; }
bool operator<(index_t const o) const{ return cell_ind < o; }
order_gettr(index_t c, index_t i) : cell_ind(c), seq_order(i) {}
};
std::vector<order_gettr> get_sorted_ordered_cells(std::vector<index_t> const & cells){
std::vector<order_gettr> ret;
for(index_t i=0; i<cells.size(); ++i){
ret.push_back(order_gettr(cells[i],i));
}
std::sort(ret.begin(), ret.end());
return ret;
}
std::vector<index_t> get_unique_nets(netlist const & circuit, std::vector<index_t> const & cells){
std::vector<index_t> involved_nets;
for(index_t c : cells){
for(netlist::pin_t p : circuit.get_cell(c)){
involved_nets.push_back(p.net_ind);
}
}
// Uniquify the nets
std::sort(involved_nets.begin(), involved_nets.end());
involved_nets.resize(std::distance(involved_nets.begin(), std::unique(involved_nets.begin(), involved_nets.end())));
return involved_nets;
}
struct Hnet_group{
struct Hpin{
index_t cell_index; // Not indexes in the circuit!!! Rather in the internal algorithm
minmax offset;
bool operator<(Hpin const o) const{ return cell_index < o.cell_index; }
};
struct Hnet{
bool has_ext_pins;
minmax ext_pins;
int_t weight;
Hnet(){
has_ext_pins = false;
ext_pins = minmax(std::numeric_limits<int_t>::max(), 0);
weight = 1;
}
};
std::vector<index_t> net_limits;
std::vector<Hnet> nets;
std::vector<Hpin> pins;
std::vector<int_t> cell_widths;
Hnet_group(){
net_limits.push_back(0);
}
void add_net(std::vector<pin_1D> const added_pins, int_t weight){
Hnet cur_net;
cur_net.weight = weight;
std::vector<Hpin> new_pins;
for(auto const p : added_pins){
if(p.movable){
Hpin new_pin;
new_pin.cell_index = p.cell_ind;
new_pin.offset = minmax(p.offs, p.offs);
new_pins.push_back(new_pin);
}
else{
cur_net.has_ext_pins = true;
cur_net.ext_pins.merge(p.pos);
}
}
std::sort(new_pins.begin(), new_pins.end());
if(not new_pins.empty()){ // Possible when generating from a Steiner topology
// Uniquify just in case there are several pins on the net on a single cell
index_t j=0;
auto prev_pin = new_pins[0];
for(auto it = new_pins.begin()+1; it != new_pins.end(); ++it){
if(it->cell_index == prev_pin.cell_index){
prev_pin.offset.merge(it->offset);
}
else{
new_pins[j] = prev_pin;
++j;
prev_pin = *it;
}
}
new_pins[j]=prev_pin;
new_pins.resize(j+1);
nets.push_back(cur_net);
net_limits.push_back(net_limits.back() + new_pins.size());
pins.insert(pins.end(), new_pins.begin(), new_pins.end());
}
}
std::int64_t get_cost(std::vector<int_t> const & pos) const{
std::int64_t cost=0;
for(index_t n=0; n<nets.size(); ++n){
auto cur_net = nets[n];
minmax mm(std::numeric_limits<int_t>::max(), std::numeric_limits<int_t>::min());
if(cur_net.has_ext_pins){
mm = cur_net.ext_pins;
}
assert(net_limits[n+1] > net_limits[n]);
for(index_t p=net_limits[n]; p<net_limits[n+1]; ++p){
int_t cur_pos = pos[pins[p].cell_index];
mm.merge( minmax(cur_pos + pins[p].offset.min, cur_pos + pins[p].offset.max) );
}
cost += static_cast<std::int64_t>(cur_net.weight) * (mm.max - mm.min);
}
return cost;
}
std::int64_t get_cost(std::vector<int_t> const & pos, std::vector<int> const & flip) const{
std::int64_t cost=0;
for(index_t n=0; n<nets.size(); ++n){
auto cur_net = nets[n];
minmax mm(std::numeric_limits<int_t>::max(), std::numeric_limits<int_t>::min());
if(cur_net.has_ext_pins){
mm = cur_net.ext_pins;
}
assert(net_limits[n+1] > net_limits[n]);
for(index_t p=net_limits[n]; p<net_limits[n+1]; ++p){
int_t cur_pos = pos[pins[p].cell_index];
bool flipped = flip[pins[p].cell_index];
int_t wdth = cell_widths[pins[p].cell_index];
mm.merge( flipped ?
minmax(cur_pos + wdth - pins[p].offset.max, cur_pos + wdth - pins[p].offset.min)
: minmax(cur_pos + pins[p].offset.min, cur_pos + pins[p].offset.max)
);
}
cost += static_cast<std::int64_t>(cur_net.weight) * (mm.max - mm.min);
}
return cost;
}
};
Hnet_group get_B2B_netgroup(netlist const & circuit, detailed_placement const & pl, std::vector<index_t> const & cells){
std::vector<order_gettr> cells_in_row = get_sorted_ordered_cells(cells);
std::vector<index_t> involved_nets = get_unique_nets(circuit, cells);
Hnet_group ret;
for(index_t c : cells)
ret.cell_widths.push_back(circuit.get_cell(c).size.x);
for(index_t n : involved_nets){
std::vector<pin_1D> cur_pins = get_pins_1D(circuit, pl.plt_, n).x;
for(pin_1D & p : cur_pins){
auto it = std::lower_bound(cells_in_row.begin(), cells_in_row.end(), p.cell_ind);
if(it != cells_in_row.end() and it->cell_ind == p.cell_ind){
p.cell_ind = it->seq_order;
}
else{ // Found a pin which remains fixed for this round
p.movable = false;
}
}
ret.add_net(cur_pins, circuit.get_net(n).weight);
}
return ret;
}
Hnet_group get_RSMT_netgroup(netlist const & circuit, detailed_placement const & pl, std::vector<index_t> const & cells){
std::vector<order_gettr> cells_in_row = get_sorted_ordered_cells(cells);
std::vector<index_t> involved_nets = get_unique_nets(circuit, cells);
Hnet_group ret;
for(index_t c : cells)
ret.cell_widths.push_back(circuit.get_cell(c).size.x);
for(index_t n : involved_nets){
auto vpins = get_pins_2D(circuit, pl.plt_, n);
for(auto & p : vpins){
auto it = std::lower_bound(cells_in_row.begin(), cells_in_row.end(), p.cell_ind);
if(it != cells_in_row.end() and it->cell_ind == p.cell_ind){
p.cell_ind = it->seq_order;
}
else{
p.movable = false;
}
}
std::vector<point<int_t> > pin_locations;
for(auto p : vpins)
pin_locations.push_back(p.pos);
auto const Htopo = get_RSMT_topology(pin_locations, 8).x;
// In the horizontal topology, we transform the parts of the tree that are on the row into HPWL subnets
// Two pins sharing an edge are in the same subnet if one of them is on the row: use union-find
union_find UF(vpins.size());
for(auto E : Htopo){
if( vpins[E.first].movable or vpins[E.second].movable){
UF.merge(E.first, E.second);
}
}
std::vector<std::vector<pin_1D> > connex_comps(vpins.size());
for(index_t i=0; i<vpins.size(); ++i){
connex_comps[UF.find(i)].push_back(vpins[i].x());;
}
int_t weight = circuit.get_net(n).weight;
for(index_t i=0; i<vpins.size(); ++i){
if(not connex_comps[i].empty()){
ret.add_net(connex_comps[i], weight);
}
}
}
return ret;
}
// Optimizes an ordered sequence of standard cells on the same row, returns the cost and the corresponding positions
inline std::int64_t optimize_convex_sequence(Hnet_group const & nets, std::vector<index_t> const & permutation, std::vector<int_t> & positions, std::vector<std::pair<int_t, int_t> > const & cell_ranges){
// Get the widths of the cells in row order
std::vector<int_t> loc_widths(permutation.size());
std::vector<std::pair<int_t, int_t> > loc_ranges(permutation.size());
for(index_t i=0; i<permutation.size(); ++i){
loc_widths[permutation[i]] = nets.cell_widths[i];
loc_ranges[permutation[i]] = cell_ranges[i];
}
std::vector<cell_bound> bounds;
std::vector<int_t> right_slopes(permutation.size(), 0);
for(index_t n=0; n<nets.nets.size(); ++n){
index_t fst_c=std::numeric_limits<index_t>::max(), lst_c=0;
int_t fst_pin_offs=0, lst_pin_offs=0;
assert(nets.net_limits[n+1] > nets.net_limits[n]);
auto cur_net = nets.nets[n];
for(index_t p=nets.net_limits[n]; p<nets.net_limits[n+1]; ++p){
// Permutation: index in the Hnet_group to index in the row
index_t cur_cell = permutation[nets.pins[p].cell_index];
if(cur_cell < fst_c){
fst_c = cur_cell;
fst_pin_offs = nets.pins[p].offset.min;
}
if(cur_cell >= lst_c){
lst_c = cur_cell;
lst_pin_offs = nets.pins[p].offset.max;
}
}
if(cur_net.has_ext_pins){
bounds.push_back(cell_bound(fst_c, cur_net.ext_pins.min - fst_pin_offs, cur_net.weight));
bounds.push_back(cell_bound(lst_c, cur_net.ext_pins.max - lst_pin_offs, cur_net.weight));
right_slopes[lst_c] += cur_net.weight;
}
else{
right_slopes[lst_c] += cur_net.weight;
right_slopes[fst_c] -= cur_net.weight;
}
}
bool feasible = place_convex_single_row(loc_widths, loc_ranges, bounds, right_slopes, positions);
auto permuted_positions = positions;
for(index_t i=0; i<permutation.size(); ++i){
permuted_positions[i] = positions[permutation[i]];
}
if(feasible)
return nets.get_cost(permuted_positions);
else
return std::numeric_limits<std::int64_t>::max(); // Infeasible: return a very big cost
}
// TODO: take modified order relative to the obstacles into account
inline std::int64_t optimize_noncvx_sequence(Hnet_group const & nets, std::vector<index_t> const & permutation, std::vector<int_t> & positions, std::vector<int> & flippings, std::vector<int> const & flippability, std::vector<std::pair<int_t, int_t> > const & cell_ranges){
// Get the widths of the cells in row order
std::vector<int_t> loc_widths(permutation.size());
std::vector<int> loc_flipps(permutation.size());
std::vector<std::pair<int_t, int_t> > loc_ranges(permutation.size());
for(index_t i=0; i<permutation.size(); ++i){
loc_widths[permutation[i]] = nets.cell_widths[i];
loc_ranges[permutation[i]] = cell_ranges[i];
loc_flipps[permutation[i]] = flippability[i];
}
int_t min_limit = std::numeric_limits<int_t>::min();
for(index_t i=0; i<loc_ranges.size(); ++i){
min_limit = std::max(loc_ranges[i].first, min_limit);
loc_ranges[i].first = min_limit;
min_limit += loc_widths[i];
}
int_t max_limit = std::numeric_limits<int_t>::max();
for(index_t i=loc_ranges.size(); i>0; --i){
max_limit = std::min(loc_ranges[i-1].second, max_limit);
max_limit -= loc_widths[i-1];
loc_ranges[i-1].second = max_limit;
}
for(index_t i=0; i<loc_ranges.size(); ++i){
if(loc_ranges[i].first > loc_ranges[i].second){
return std::numeric_limits<std::int64_t>::max(); // Infeasible: return a very big cost
}
}
std::vector<piecewise_linear_function> unflipped_cost_functions, flipped_cost_functions;
for(index_t i=0; i<loc_ranges.size(); ++i){
auto cur = piecewise_linear_function(loc_ranges[i].first, loc_ranges[i].second);
unflipped_cost_functions.push_back(cur);
flipped_cost_functions.push_back(cur);
}
for(index_t n=0; n<nets.nets.size(); ++n){
index_t fst_c=std::numeric_limits<index_t>::max(), lst_c=0;
int_t fst_pin_offs_mn=0, lst_pin_offs_mn=0,
fst_pin_offs_mx=0, lst_pin_offs_mx=0;
assert(nets.net_limits[n+1] > nets.net_limits[n]);
auto cur_net = nets.nets[n];
for(index_t p=nets.net_limits[n]; p<nets.net_limits[n+1]; ++p){
// Permutation: index in the Hnet_group to index in the row
index_t cur_cell = permutation[nets.pins[p].cell_index];
if(cur_cell < fst_c){
fst_c = cur_cell;
fst_pin_offs_mn = nets.pins[p].offset.min;
fst_pin_offs_mx = nets.pins[p].offset.max;
}
if(cur_cell >= lst_c){
lst_c = cur_cell;
lst_pin_offs_mn = nets.pins[p].offset.min;
lst_pin_offs_mx = nets.pins[p].offset.max;
}
}
if(cur_net.has_ext_pins){
unflipped_cost_functions[fst_c].add_bislope(-cur_net.weight, 0, cur_net.ext_pins.min - fst_pin_offs_mn);
unflipped_cost_functions[lst_c].add_bislope(0, cur_net.weight, cur_net.ext_pins.max - lst_pin_offs_mx);
flipped_cost_functions[fst_c].add_bislope(-cur_net.weight, 0, cur_net.ext_pins.min - loc_widths[fst_c] + fst_pin_offs_mx);
flipped_cost_functions[lst_c].add_bislope(0, cur_net.weight, cur_net.ext_pins.max - loc_widths[lst_c] + lst_pin_offs_mn);
}
else{
unflipped_cost_functions[fst_c].add_monotone(-cur_net.weight, -fst_pin_offs_mn);
unflipped_cost_functions[lst_c].add_monotone( cur_net.weight, -lst_pin_offs_mx);
flipped_cost_functions[fst_c].add_monotone(-cur_net.weight, fst_pin_offs_mx - loc_widths[fst_c] );
flipped_cost_functions[lst_c].add_monotone( cur_net.weight, lst_pin_offs_mn - loc_widths[lst_c] );
}
}
std::vector<piecewise_linear_function> prev_mins, merged_costs;
for(index_t i=0; i<loc_ranges.size(); ++i){
merged_costs.push_back(loc_flipps[i] ?
piecewise_linear_function::minimum(unflipped_cost_functions[i], flipped_cost_functions[i])
: unflipped_cost_functions[i]
);
if(i>0){
prev_mins.push_back(prev_mins.back().previous_min_of_sum(merged_costs.back(), loc_widths[i-1]));
}
else{
prev_mins.push_back(merged_costs.back().previous_min());
}
}
for(auto const M : prev_mins){
for(index_t i=0; i+1<M.point_values.size(); ++i){
assert(M.point_values[i].second >= M.point_values[i+1].second);
}
}
flippings.resize(cell_ranges.size(), 0); positions.resize(cell_ranges.size(), 0);
int_t pos = std::numeric_limits<int_t>::max();
for(index_t i=loc_ranges.size(); i>0; --i){
// Find the best position and flipping for each cell
pos = prev_mins[i-1].last_before(std::min(pos - loc_widths[i-1], loc_ranges[i-1].second) );
positions[i-1] = pos;
if(loc_flipps[i-1] and flipped_cost_functions[i-1].value_at(pos) < unflipped_cost_functions[i-1].value_at(pos)){
flippings[i-1] = 1;
}
}
for(index_t i=0; i<loc_ranges.size(); ++i){
assert(positions[i] >= loc_ranges[i].first);
assert(positions[i] <= loc_ranges[i].second);
}
for(index_t i=0; i+1<loc_ranges.size(); ++i){
assert(positions[i] + loc_widths[i] <= positions[i+1]);
}
auto permuted_positions = positions;
auto permuted_flippings = flippings;
for(index_t i=0; i<permutation.size(); ++i){
permuted_positions[i] = positions[permutation[i]];
permuted_flippings[i] = flippings[permutation[i]];
}
return nets.get_cost(permuted_positions, permuted_flippings);
}
std::vector<std::pair<int_t, int_t> > get_cell_ranges(netlist const & circuit, detailed_placement const & pl, std::vector<index_t> const & cells){
std::vector<std::pair<int_t, int_t> > lims;
for(index_t i=0; i+1<cells.size(); ++i){
assert(pl.plt_.positions_[cells[i]].x + circuit.get_cell(cells[i]).size.x <= pl.plt_.positions_[cells[i+1]].x);
}
// Extreme limits, except macros are allowed to be beyond the limit of the placement area
int_t lower_lim = pl.get_limit_positions(circuit, cells.front()).first;
int_t upper_lim = pl.get_limit_positions(circuit, cells.back()).second;
for(index_t OSRP_cell : cells){
auto attr = circuit.get_cell(OSRP_cell).attributes;
auto cur_lim = std::pair<int_t, int_t>(lower_lim, upper_lim);
int_t pos = pl.plt_.positions_[OSRP_cell].x;
if( (attr & XMovable) == 0 or pl.cell_height(OSRP_cell) != 1){
cur_lim = std::pair<int_t, int_t>(pos, pos + circuit.get_cell(OSRP_cell).size.x);
}
else{
assert(pos >= lower_lim);
assert(pos + circuit.get_cell(OSRP_cell).size.x <= upper_lim);
}
lims.push_back(cur_lim);
}
return lims;
}
template<bool NON_CONVEX, bool RSMT>
void OSRP_generic(netlist const & circuit, detailed_placement & pl){
for(index_t r=0; r<pl.row_cnt(); ++r){
// Complete optimization on a row, comprising possible obstacles
std::vector<index_t> cells;
std::vector<int> flippability;
// Get the movable cells, if we can flip them, and the obstacles on the row
for(index_t OSRP_cell = pl.get_first_cell_on_row(r); OSRP_cell != null_ind; OSRP_cell = pl.get_next_cell_on_row(OSRP_cell, r)){
auto attr = circuit.get_cell(OSRP_cell).attributes;
cells.push_back(OSRP_cell);
flippability.push_back( (attr & XFlippable) != 0 ? 1 : 0);
}
if(not cells.empty()){
std::vector<std::pair<int_t, int_t> > lims = get_cell_ranges(circuit, pl, cells); // Limit positions for each cell
Hnet_group nets = RSMT ?
get_RSMT_netgroup(circuit, pl, cells)
: get_B2B_netgroup(circuit, pl, cells);
std::vector<index_t> no_permutation(cells.size());
for(index_t i=0; i<cells.size(); ++i) no_permutation[i] = i;
std::vector<int_t> final_positions;
if(NON_CONVEX){
std::vector<int> flipped;
optimize_noncvx_sequence(nets, no_permutation, final_positions, flipped, flippability, lims);
for(index_t i=0; i<cells.size(); ++i){
bool old_orient = pl.plt_.orientations_[cells[i]].x;
pl.plt_.orientations_[cells[i]].x = flipped[i] ? not old_orient : old_orient;
}
}
else{
optimize_convex_sequence(nets, no_permutation, final_positions, lims);
}
// Update the positions and orientations
for(index_t i=0; i<cells.size(); ++i){
pl.plt_.positions_[cells[i]].x = final_positions[i];
}
}
} // Iteration on the rows
pl.selfcheck();
}
template<bool NON_CONVEX, bool RSMT>
void swaps_row_generic(netlist const & circuit, detailed_placement & pl, index_t range){
assert(range >= 2);
for(index_t r=0; r<pl.row_cnt(); ++r){
index_t OSRP_cell = pl.get_first_cell_on_row(r);
while(OSRP_cell != null_ind){
std::vector<index_t> cells;
std::vector<std::pair<int_t, int_t> > lims;
std::vector<int> flippables;
for(index_t nbr_cells=0;
OSRP_cell != null_ind
and nbr_cells < range;
OSRP_cell = pl.get_next_cell_on_row(OSRP_cell, r), ++nbr_cells
){
cells.push_back(OSRP_cell);
flippables.push_back( (circuit.get_cell(OSRP_cell).attributes & XFlippable) != 0);
}
if(not cells.empty()){
std::vector<std::pair<int_t, int_t> > lims = get_cell_ranges(circuit, pl, cells); // Limit positions for each cell
Hnet_group nets = RSMT ?
get_RSMT_netgroup(circuit, pl, cells)
: get_B2B_netgroup(circuit, pl, cells);
std::int64_t best_cost = std::numeric_limits<std::int64_t>::max();
std::vector<int_t> positions(cells.size());
std::vector<int> flippings(cells.size());
std::vector<int_t> best_positions(cells.size());
std::vector<int> best_flippings(cells.size());
std::vector<index_t> permutation(cells.size());
for(index_t i=0; i<cells.size(); ++i) permutation[i] = i;
std::vector<index_t> best_permutation;
// Check every possible permutation of the cells
do{
std::int64_t cur_cost = NON_CONVEX ?
optimize_noncvx_sequence(nets, permutation, positions, flippings, flippables, lims) :
optimize_convex_sequence(nets, permutation, positions, lims);
if(cur_cost <= best_cost){
best_cost = cur_cost;
best_permutation = permutation;
best_flippings = flippings;
best_positions = positions;
}
}while(std::next_permutation(permutation.begin(), permutation.end()));
std::vector<index_t> new_cell_order(cells.size());
// Update the positions and the topology
for(index_t i=0; i<cells.size(); ++i){
index_t r_ind = best_permutation[i]; // In the row from in the Hnet_group
new_cell_order[r_ind] = cells[i];
pl.plt_.positions_[cells[i]].x = best_positions[r_ind];
if(NON_CONVEX){
bool old_orient = pl.plt_.orientations_[cells[i]].x;
pl.plt_.orientations_[cells[i]].x = best_flippings[r_ind] ? not old_orient : old_orient;
}
}
pl.reorder_cells(cells, new_cell_order, r);
cells = new_cell_order;
assert(best_cost < std::numeric_limits<std::int64_t>::max());
}
if(OSRP_cell != null_ind){
assert(cells.size() == range);
OSRP_cell = cells[range/2];
}
} // Iteration on the entire row
} // Iteration on the rows
pl.selfcheck();
}
} // End anonymous namespace
void OSRP_convex_HPWL(netlist const & circuit, detailed_placement & pl){ OSRP_generic< false, false>(circuit, pl); }
void OSRP_convex_RSMT(netlist const & circuit, detailed_placement & pl){ OSRP_generic< false, true >(circuit, pl); }
void OSRP_noncvx_HPWL(netlist const & circuit, detailed_placement & pl){ OSRP_generic< true , false>(circuit, pl); }
void OSRP_noncvx_RSMT(netlist const & circuit, detailed_placement & pl){ OSRP_generic< true , true >(circuit, pl); }
void swaps_row_convex_HPWL(netlist const & circuit, detailed_placement & pl, index_t range){ swaps_row_generic< false, false>(circuit, pl, range); }
void swaps_row_convex_RSMT(netlist const & circuit, detailed_placement & pl, index_t range){ swaps_row_generic< false, true >(circuit, pl, range); }
void swaps_row_noncvx_HPWL(netlist const & circuit, detailed_placement & pl, index_t range){ swaps_row_generic< true , false>(circuit, pl, range); }
void swaps_row_noncvx_RSMT(netlist const & circuit, detailed_placement & pl, index_t range){ swaps_row_generic< true , true >(circuit, pl, range); }
} // namespace dp
} // namespace coloquinte

384
coloquinte/src/solvers.cxx Normal file
View File

@ -0,0 +1,384 @@
#include "coloquinte/solvers.hxx"
#include <cassert>
#include <stdexcept>
#include <cmath>
#include <limits>
namespace coloquinte{
namespace gp{
linear_system linear_system::operator+(linear_system const & o) const{
if(o.internal_size() != internal_size()){ throw std::runtime_error("Mismatched system sizes"); }
linear_system ret(target_.size() + o.target_.size() - internal_size(), internal_size());
ret.matrix_ = matrix_;
std::vector<matrix_triplet> omatrix = o.matrix_;
for(matrix_triplet & t : omatrix){
if(t.c_ >= internal_size()){
t.c_ += (target_.size() - internal_size());
}
if(t.r_ >= internal_size()){
t.r_ += (target_.size() - internal_size());
}
}
ret.matrix_.insert(ret.matrix_.end(), omatrix.begin(), omatrix.end());
// ret.target_.resize(target_.size() + o.target_.size() - internal_size);
for(index_t i=0; i<internal_size(); ++i){
ret.target_[i] = target_[i] + o.target_[i];
}
for(index_t i=internal_size(); i<target_.size(); ++i){
ret.target_[i] = target_[i];
}
for(index_t i=internal_size(); i<o.target_.size(); ++i){
ret.target_[i + target_.size() - internal_size()] = o.target_[i];
}
return ret;
}
// The classical compressed sparse row storage
struct csr_matrix{
std::vector<std::uint32_t> row_limits, col_indexes;
std::vector<float> values, diag;
std::vector<float> mul(std::vector<float> const & x) const;
std::vector<float> solve_CG(std::vector<float> const & goal, std::vector<float> guess, std::uint32_t min_iter, std::uint32_t max_iter, float tol) const;
csr_matrix(std::vector<std::uint32_t> const & row_l, std::vector<std::uint32_t> const & col_i, std::vector<float> const & vals, std::vector<float> const D) : row_limits(row_l), col_indexes(col_i), values(vals), diag(D){
assert(values.size() == col_indexes.size());
assert(diag.size()+1 == row_limits.size());
}
};
// A matrix with successive rows padded to the same length and accessed column-major; hopefully a little better
template<std::uint32_t unroll_len>
struct ellpack_matrix{
std::vector<std::uint32_t> row_limits, col_indexes;
std::vector<float> values, diag;
std::vector<float> mul(std::vector<float> const & x) const;
std::vector<float> solve_CG(std::vector<float> goal, std::vector<float> guess, std::uint32_t min_iter, std::uint32_t max_iter, float tol) const;
ellpack_matrix(std::vector<std::uint32_t> const & row_l, std::vector<std::uint32_t> const & col_i, std::vector<float> const & vals, std::vector<float> const D) : row_limits(row_l), col_indexes(col_i), values(vals), diag(D){
assert(values.size() == col_indexes.size());
assert(diag.size() % unroll_len == 0);
assert((row_limits.size()-1) * unroll_len == diag.size() );
assert(row_limits.back() * unroll_len == values.size());
assert(values.size() % unroll_len == 0);
assert(col_indexes.size() % unroll_len == 0);
}
};
// The proxy matrix for compressed sparse storage
class doublet_matrix{
std::vector<std::uint32_t> row_limits;
std::vector<matrix_doublet> doublets;
std::uint32_t size;
void get_compressed(std::vector<std::uint32_t> & limits, std::vector<matrix_doublet> & elements, std::vector<float> & diag) const;
public:
doublet_matrix(std::vector<matrix_triplet> const & triplets, std::uint32_t size);
csr_matrix get_compressed_matrix() const;
template<std::uint32_t unroll_len>
ellpack_matrix<unroll_len> get_ellpack_matrix() const;
};
doublet_matrix::doublet_matrix(std::vector<matrix_triplet> const & triplets, std::uint32_t n) : size(n){
row_limits.resize(size+1, 0);
// First store the row sizes in the array
for(uint32_t i=0; i<triplets.size(); ++i){
++row_limits[triplets[i].r_+1];
}
// The total size of the uncompressed matrix
uint32_t tot_triplets=0;
// Get the beginning position of each row in the csr matrix
for(uint32_t i=1; i<n+1; ++i){
uint32_t new_tot_triplets = tot_triplets + row_limits[i];
row_limits[i] = tot_triplets; // Stores the beginning of the row
tot_triplets = new_tot_triplets;
}
assert(tot_triplets == triplets.size());
// Now we know the size and can allocate storage for the indices and values
doublets.resize(tot_triplets);
// We store the triplets in the new storage and tranform beginning positions into end positions
for(uint32_t i=0; i<triplets.size(); ++i){
doublets[row_limits[triplets[i].r_+1]] = matrix_doublet(triplets[i].c_, triplets[i].val_);
++row_limits[triplets[i].r_+1]; // row_limits will hold the end position of the row
}
}
void doublet_matrix::get_compressed(std::vector<std::uint32_t> & sizes, std::vector<matrix_doublet> & elements, std::vector<float> & diag) const{
assert(size+1 == row_limits.size());
sizes.resize(size);
diag.resize(size, 0.0);
std::vector<matrix_doublet> tmp_doublets = doublets;
for(uint32_t i=0; i<size; ++i){
// Sort the elements in the row
std::sort(tmp_doublets.begin() + row_limits[i], tmp_doublets.begin() + row_limits[i+1]);
// Compress them and extract the diagonal
std::uint32_t l=0;
matrix_doublet cur(tmp_doublets[row_limits[i]]);
for(uint32_t j=row_limits[i]+1; j<row_limits[i+1]; ++j){
if(tmp_doublets[j].c_ == cur.c_){
cur.val_ += tmp_doublets[j].val_;
}
else{
if(i != cur.c_){
elements.push_back(cur);
++l;
}
else{
diag[i] = cur.val_;
}
cur = tmp_doublets[j];
}
}
if(i != cur.c_){
elements.push_back(cur);
++l;
}
else{
diag[i] = cur.val_;
}
sizes[i] = l;
}
}
csr_matrix doublet_matrix::get_compressed_matrix() const{
std::vector<matrix_doublet> tmp_doublets;
std::vector<std::uint32_t> sizes;
std::vector<float> diag;
get_compressed(sizes, tmp_doublets, diag);
// Get the limits of each row
std::vector<std::uint32_t> new_row_limits(row_limits.size());
new_row_limits[0] = 0;
for(std::uint32_t i=0; i<size; ++i){
new_row_limits[i+1] = new_row_limits[i] + sizes[i];
}
// Store the doublets to the sparse storage
std::vector<std::uint32_t> col_indices(tmp_doublets.size());
std::vector<float> values(tmp_doublets.size());
for(std::uint32_t i=0; i<tmp_doublets.size(); ++i){
col_indices[i] = tmp_doublets[i].c_;
values[i] = tmp_doublets[i].val_;
}
return csr_matrix(new_row_limits, col_indices, values, diag);
}
template<std::uint32_t unroll_len>
ellpack_matrix<unroll_len> doublet_matrix::get_ellpack_matrix() const{
std::vector<matrix_doublet> tmp_doublets;
std::vector<std::uint32_t> sizes;
std::vector<float> diag;
get_compressed(sizes, tmp_doublets, diag);
std::uint32_t unrolled_size = (diag.size() % unroll_len == 0)? diag.size()/unroll_len : diag.size() / unroll_len + 1;
sizes.resize(unroll_len * unrolled_size, 0);
diag.resize(unroll_len * unrolled_size, 1.0);
// Store the maximum size of a group of rows
std::vector<std::uint32_t> new_row_limits(unrolled_size+1);
new_row_limits[0] = 0;
for(std::uint32_t i=0; i<unrolled_size; ++i){
std::uint32_t max_sz = sizes[unroll_len*i];
for(int j=1; j<unroll_len; ++j){
max_sz = std::max(max_sz, sizes[unroll_len*i + j]);
}
new_row_limits[i+1] = new_row_limits[i] + max_sz;
}
std::vector<std::uint32_t> col_indices(unroll_len * new_row_limits.back());
std::vector<float> values(unroll_len * new_row_limits.back());
std::uint32_t d = 0;
for(std::uint32_t i=0; i<sizes.size(); ++i){ // For every line
std::uint32_t ui = i/unroll_len;
std::uint32_t k = i%unroll_len;
std::uint32_t max_sz = new_row_limits[ui+1] - new_row_limits[ui];
std::uint32_t row_begin = new_row_limits[ui];
for(std::uint32_t j=0; j<sizes[i]; ++j, ++d){ // For the non-zero values
col_indices[unroll_len * (row_begin+j) + k] = tmp_doublets[d].c_;
values[unroll_len * (row_begin+j) + k] = tmp_doublets[d].val_;
}
for(std::uint32_t j=sizes[i]; j<max_sz; ++j){ // For the padding zeroes
col_indices[unroll_len * (row_begin+j) + k] = 0;
values[unroll_len * (row_begin+j) + k] = 0;
}
}
return ellpack_matrix<unroll_len>(new_row_limits, col_indices, values, diag);
}
std::vector<float> csr_matrix::mul(std::vector<float> const & x) const{
std::vector<float> res(x.size());
assert(x.size() == diag.size());
for(std::uint32_t i=0; i<diag.size(); ++i){
res[i] = diag[i] * x[i];
for(std::uint32_t j=row_limits[i]; j<row_limits[i+1]; ++j){
res[i] += values[j] * x[col_indexes[j]];
}
}
return res;
}
template<std::uint32_t unroll_len>
std::vector<float> ellpack_matrix<unroll_len>::mul(std::vector<float> const & x) const{
std::vector<float> res(x.size());
assert(x.size() % unroll_len == 0);
assert(x.size() == diag.size());
for(std::uint32_t i=0; i+1<row_limits.size(); ++i){
float cur[unroll_len];
for(int k=0; k<unroll_len; ++k){
cur[k] = diag[unroll_len*i+k] * x[unroll_len*i+k];
}
for(std::uint32_t j=row_limits[i]; j<row_limits[i+1]; ++j){
for(int k=0; k<unroll_len; ++k){
cur[k] += values[unroll_len*j+k] * x[col_indexes[unroll_len*j+k]];
}
}
for(int k=0; k<unroll_len; ++k){
res[unroll_len*i+k] = cur[k];
}
}
return res;
}
template<std::uint32_t unroll_len>
float dot_prod(std::vector<float> const & a, std::vector<float> const & b){
assert(a.size() == b.size());
float vals[unroll_len];
for(int j=0; j<unroll_len; ++j) vals[j] = 0.0;
for(std::uint32_t i=0; i<a.size() / unroll_len; ++i){
for(int j=0; j<unroll_len; ++j){
vals[j] += a[unroll_len*i + j] * b[unroll_len*i + j];
}
}
float res = 0.0;
for(int j=0; j<unroll_len; ++j) res += vals[j];
for(int i = unroll_len*(a.size() / unroll_len); i< a.size(); ++i){
res += a[i] * b[i];
}
return res;
}
std::vector<float> csr_matrix::solve_CG(std::vector<float> const & goal, std::vector<float> x, std::uint32_t min_iter, std::uint32_t max_iter, float tol_ratio) const{
std::uint32_t n = diag.size();
assert(goal.size() == n);
assert(x.size() == n);
std::vector<float> r, p(n), z(n), mul_res, preconditioner(n);
r = mul(x);
for(uint32_t i=0; i<n; ++i){
r[i] = goal[i] - r[i];
preconditioner[i] = 1.0/diag[i];
assert(std::isfinite(preconditioner[i]));
z[i] = preconditioner[i] * r[i];
p[i] = z[i];
}
float cross_norm = dot_prod<16>(r, z);
assert(std::isfinite(cross_norm));
float_t const epsilon = std::numeric_limits<float_t>::min();
float start_norm = cross_norm;
for(uint32_t k=0; k < max_iter; ++k){
mul_res = mul(p);
float_t pr_prod = dot_prod<16>(p, mul_res);
float_t alpha = cross_norm / pr_prod;
if(
not std::isfinite(cross_norm) or not std::isfinite(alpha) or not std::isfinite(pr_prod)
or cross_norm <= epsilon or alpha <= epsilon or pr_prod <= epsilon
){
break;
}
// Update the result
for(uint32_t i=0; i<n; ++i){
x[i] = x[i] + alpha * p[i];
r[i] = r[i] - alpha * mul_res[i];
z[i] = preconditioner[i] * r[i];
}
float new_cross_norm = dot_prod<16>(r, z);
// Update the scaled residual and the search direction
if(k >= min_iter && new_cross_norm <= tol_ratio * start_norm){
break;
}
float beta = new_cross_norm / cross_norm;
cross_norm = new_cross_norm;
for(uint32_t i=0; i<n; ++i)
p[i] = z[i] + beta * p[i];
}
return x;
}
template<std::uint32_t unroll_len>
std::vector<float> ellpack_matrix<unroll_len>::solve_CG(std::vector<float> goal, std::vector<float> x, std::uint32_t min_iter, std::uint32_t max_iter, float tol_ratio) const{
std::uint32_t n = diag.size();
std::uint32_t old_n = x.size();
assert(goal.size() == x.size());
x.resize(diag.size(), 0.0);
goal.resize(diag.size(), 0.0);
std::vector<float> r, p(n), z(n), mul_res, preconditioner(n);
r = mul(x);
for(uint32_t i=0; i<n; ++i){
r[i] = goal[i] - r[i];
preconditioner[i] = 1.0/diag[i];
z[i] = preconditioner[i] * r[i];
p[i] = z[i];
}
float cross_norm = dot_prod<unroll_len>(r, z);
float start_norm = cross_norm;
for(uint32_t k=0; k < max_iter; ++k){
mul_res = mul(p);
float alpha = cross_norm / dot_prod<unroll_len>(p, mul_res);
// Update the result
for(uint32_t i=0; i<n; ++i){
x[i] = x[i] + alpha * p[i];
r[i] = r[i] - alpha * mul_res[i];
z[i] = preconditioner[i] * r[i];
}
float new_cross_norm = dot_prod<unroll_len>(r, z);
// Update the scaled residual and the search direction
if(k >= min_iter && new_cross_norm <= tol_ratio * start_norm){
break;
}
float beta = new_cross_norm / cross_norm;
cross_norm = new_cross_norm;
for(uint32_t i=0; i<n; ++i)
p[i] = z[i] + beta * p[i];
}
x.resize(old_n);
return x;
}
std::vector<float_t> linear_system::solve_CG(std::vector<float_t> guess, index_t nbr_iter){
doublet_matrix tmp(matrix_, size());
csr_matrix mat = tmp.get_compressed_matrix();
//ellpack_matrix<16> mat = tmp.get_ellpack_matrix<16>();
guess.resize(target_.size(), 0.0);
auto ret = mat.solve_CG(target_, guess, nbr_iter, nbr_iter, 0.0);
ret.resize(internal_size());
return ret;
}
}
}

View File

@ -0,0 +1,536 @@
#include "coloquinte/topologies.hxx"
#include "coloquinte/circuit_helper.hxx"
#include "coloquinte/union_find.hxx"
#include <algorithm>
#include <cassert>
#include <set>
#include <functional>
#include <cmath>
#include <array>
#include <limits>
namespace coloquinte{
using edge_t = std::pair<index_t, index_t>;
namespace{
struct minmax_t{
int_t min, max;
minmax_t(int_t mn, int_t mx) : min(mn), max(mx) {}
minmax_t() {}
void merge(minmax_t const o){
min = std::min(o.max, min);
max = std::max(o.min, max);
}
void merge(int_t const p){
min = std::min(p, min);
max = std::max(p, max);
}
};
}
namespace steiner_lookup{
template<int pin_cnt>
int_t Hconnectivity<pin_cnt>::get_wirelength(std::array<point<int_t>, pin_cnt> const sorted_points) const{
std::array<minmax_t, pin_cnt-2> minmaxs;
for(index_t i=0; i<pin_cnt-2; ++i){
minmaxs[i] = minmax_t(sorted_points[i+1].y, sorted_points[i+1].y);
}
std::uint8_t b_con = extremes & 15u, e_con = extremes >> 4;
minmaxs[b_con].merge(sorted_points.front() .y);
minmaxs[e_con].merge(sorted_points.back() .y);
for(std::uint8_t const E : connexions){
minmaxs[(E >> 4)].merge(minmaxs[(E & 15u)]);
}
int_t cost = sorted_points.back().x - sorted_points.front().x + sorted_points[b_con+1].x - sorted_points[e_con+1].x;
for(std::uint8_t const E : connexions){
cost += std::abs((float)(sorted_points[(E >> 4) +1].x - sorted_points[(E & 15u) +1].x));
}
for(index_t i=0; i<pin_cnt-2; ++i){
cost += (minmaxs[i].max - minmaxs[i].min);
}
return cost;
}
template<int pin_cnt>
std::array<edge_t, pin_cnt-1> Hconnectivity<pin_cnt>::get_x_topology(std::array<point<int_t>, pin_cnt> const sorted_points) const{
std::array<edge_t, pin_cnt-1> ret;
std::uint8_t b_con = extremes & 15u, e_con = extremes >> 4;
ret[0] = edge_t(0, b_con+1);
ret[1] = edge_t(pin_cnt-1, e_con+1);
for(index_t i=0; i<pin_cnt-3; ++i){
std::uint8_t E = connexions[i];
ret[i+2] = edge_t((E & 15u) +1, (E >> 4) +1);
}
return ret;
}
} // End namespace steiner_lookup
namespace {
template<int n, int array_size>
int_t get_wirelength_from_sorted(std::vector<point<int_t> > const & pins, std::array<steiner_lookup::Hconnectivity<n>, array_size> const & lookups){
std::array<point<int_t>, n> points;
std::copy_n(pins.begin(), n, points.begin());
int_t cost = std::numeric_limits<int_t>::max();
for(auto const L : lookups){
cost = std::min(cost, L.get_wirelength(points));
}
return cost;
}
std::int64_t get_wirelength_from_topo(std::vector<point<int_t> > const & points, std::vector<std::pair<index_t, index_t> > Htopo){
std::vector<minmax_t> minmaxs(points.size());
for(index_t i=0; i<points.size(); ++i){
minmaxs[i] = minmax_t(points[i].y, points[i].y);
}
for(auto const E : Htopo){
minmaxs[E.second].merge(minmaxs[E.first]);
}
std::int64_t cost = 0;
for(edge_t const E : Htopo){
cost += std::abs((float)(points[E.first].x - points[E.second].x));
}
for(index_t i=0; i<points.size(); ++i){
cost += (minmaxs[i].max - minmaxs[i].min);
}
return cost;
}
struct indexed_pt : point<int_t>{
index_t index;
indexed_pt(point<int_t> pt, index_t pos) : point<int_t>(pt), index(pos) {}
indexed_pt(){}
};
template<int n, int array_size>
std::vector<std::pair<index_t, index_t> > get_topology_from_sorted(std::vector<point<int_t> > const & pins, std::array<steiner_lookup::Hconnectivity<n>, array_size> const & lookups){
std::array<point<int_t>, n> points;
std::copy_n(pins.begin(), n, points.begin());
// Find the horizontal topology with the smallest cost
int_t cost = std::numeric_limits<int_t>::max();
index_t ind = std::numeric_limits<index_t>::max();
for(index_t i=0; i<array_size; ++i){
int_t this_cost = lookups[i].get_wirelength(points);
if(this_cost < cost){
cost = this_cost;
ind = i;
}
}
assert(ind != std::numeric_limits<index_t>::max());
auto ret = lookups[ind].get_x_topology(points);
return std::vector<std::pair<index_t, index_t> >(ret.begin(), ret.end());
}
std::vector<edge_t> get_vertical_topology(std::vector<point<int_t> > pins, std::vector<edge_t> const & Htopo){
index_t const null_ind = std::numeric_limits<index_t>::max();
std::vector<indexed_pt> ipoints(pins.size());
for(index_t i=0; i<pins.size(); ++i){
ipoints[i] = indexed_pt(pins[i], i);
}
std::sort(ipoints.begin(), ipoints.end(), [](indexed_pt a , indexed_pt b){return a.y < b.y; });
// First pin with y ordering
std::vector<index_t> min_y_pin(pins.size());
for(index_t i=0; i<ipoints.size(); ++i){
min_y_pin[ipoints[i].index] = i;
}
std::vector<index_t> max_y_pin = min_y_pin;
std::vector<index_t> nxt_y_pin(pins.size(), null_ind);
std::vector<edge_t> ret;
for(auto const E : Htopo){
// Assuming a correctly ordered horizontal topology where the first node of the edge is never visited again
index_t f=E.first, s=E.second;
index_t first_yf=min_y_pin[f], first_ys=min_y_pin[s];
// Push the edges from the first and insert one of its elements in the second's linked structure
if(max_y_pin[f] < min_y_pin[s] or max_y_pin[s] < min_y_pin[f]){
for(index_t yf=first_yf; nxt_y_pin[yf] != null_ind; yf = nxt_y_pin[yf]){
ret.push_back(edge_t(yf, nxt_y_pin[yf]));
}
if(max_y_pin[f] < min_y_pin[s]){
nxt_y_pin[max_y_pin[f]] = min_y_pin[s];
min_y_pin[s] = max_y_pin[f];
}
else if(max_y_pin[s] < min_y_pin[f]){
nxt_y_pin[max_y_pin[s]] = min_y_pin[f];
max_y_pin[s] = min_y_pin[f];
nxt_y_pin[min_y_pin[f]] = null_ind;
}
else{
abort();
}
}
else{ // Need to chose a pin with two connexions because there will be no L route
// One pin from the second is in the middle of the first
if(max_y_pin[f] > max_y_pin[s]){
index_t middle_pin = max_y_pin[s];
index_t yf=first_yf;
// Make the first connexions
for(; nxt_y_pin[yf] < middle_pin; yf = nxt_y_pin[yf]){
ret.push_back(edge_t(yf, nxt_y_pin[yf]));
}
// Make the two connexions with the new pin
ret.push_back(edge_t(yf, middle_pin));
yf = nxt_y_pin[yf];
ret.push_back(edge_t(yf, middle_pin));
// Finish the connexions
for(; nxt_y_pin[yf] != null_ind; yf = nxt_y_pin[yf]){
ret.push_back(edge_t(yf, nxt_y_pin[yf]));
}
}
// One pin from the first is in the middle of the second
else{
for(index_t yf=first_yf; nxt_y_pin[yf] != null_ind; yf = nxt_y_pin[yf]){
ret.push_back(edge_t(yf, nxt_y_pin[yf]));
}
index_t middle_pin = max_y_pin[f];
// Find the place where we can insert this pin
index_t ys=first_ys;
for(; nxt_y_pin[ys] < middle_pin; ys = nxt_y_pin[ys]);
nxt_y_pin[middle_pin] = nxt_y_pin[ys];
nxt_y_pin[ys] = middle_pin;
}
}
}
// The last visited gives the remaining connexions to push
for(index_t yf=min_y_pin[Htopo.back().second]; nxt_y_pin[yf] != null_ind; yf = nxt_y_pin[yf]){
ret.push_back(edge_t(yf, nxt_y_pin[yf]));
}
// Back to the original ordering
for(auto & E : ret){
E.first = ipoints[E.first].index;
E.second = ipoints[E.second].index;
}
return ret;
}
inline void northeast_octant_neighbours(std::vector<point<int_t> > pins, std::vector<std::pair<index_t, index_t> > & edges){
std::vector<indexed_pt> point_list;
for(index_t i=0; i<pins.size(); ++i){
point_list.push_back(indexed_pt(pins[i], i));
}
std::sort(point_list.begin(), point_list.end(),
[](indexed_pt const a, indexed_pt const b){ return a.x + a.y < b.x + b.y; }
);
// Decreasing order of x and y; multiset not necessary because no two elements have same coordinate
std::set<indexed_pt, std::function<bool (indexed_pt const, indexed_pt const)> >
active_upper_octant([](indexed_pt const a, indexed_pt const b)->bool{return a.x > b.x;}),
active_lower_octant([](indexed_pt const a, indexed_pt const b)->bool{return a.y > b.y;});
for(indexed_pt const current : point_list){
{ // North to north-east region
auto first_it = active_upper_octant.lower_bound(current); // Largest x with x <= current.x
auto it = first_it;
for(; it != active_upper_octant.end() && it->x - it->y >= current.x - current.y; ++it){
edges.push_back(std::pair<index_t, index_t>(current.index, it->index));
}
if(first_it != active_upper_octant.end()){ active_upper_octant.erase(first_it, it); }
active_upper_octant.insert(it, current); // Hint to insert the element since it is the correct position
} // End region
{ // North-east to east region
auto first_it = active_lower_octant.lower_bound(current); // Largest y with y <= current.y
auto it = first_it;
for(; it != active_lower_octant.end() && it->y - it->x >= current.y - current.x; ++it){
edges.push_back(std::pair<index_t, index_t>(current.index, it->index));
}
if(first_it != active_lower_octant.end()){ active_lower_octant.erase(first_it, it); }
active_lower_octant.insert(it, current); // Hint to insert the element since it is the correct position
} // End region
}
}
// Gets the nearest octant neighbour for each point in the south-east quadrant
inline void southeast_octant_neighbours(std::vector<point<int_t> > pins, std::vector<std::pair<index_t, index_t> > & edges){
for(auto & pin : pins){
pin.y = - pin.y;
}
northeast_octant_neighbours(pins, edges);
}
std::vector<std::pair<index_t, index_t> > get_small_horizontal_topology_from_sorted(std::vector<point<int_t> > const & pins){
assert(pins.size() <= 10);
switch(pins.size()){
case 2:
return std::vector<edge_t>(1, edge_t(0, 1));
case 3:
return std::vector<edge_t>{{0, 1}, {1, 2}};
case 4:
return get_topology_from_sorted<4, 2>(pins, steiner_lookup::topologies_4);
case 5:
return get_topology_from_sorted<5, 6>(pins, steiner_lookup::topologies_5);
case 6:
return get_topology_from_sorted<6, 23>(pins, steiner_lookup::topologies_6);
case 7:
return get_topology_from_sorted<7, 111>(pins, steiner_lookup::topologies_7);
case 8:
return get_topology_from_sorted<8, 642>(pins, steiner_lookup::topologies_8);
case 9:
return get_topology_from_sorted<9, 4334>(pins, steiner_lookup::topologies_9);
case 10:
return get_topology_from_sorted<10, 33510>(pins, steiner_lookup::topologies_10);
default: // Only 1 and 0 left (11 and more are protected by an assertion)
return std::vector<edge_t>();
}
}
// Get an ordering of the edges that is compatible with the processing functions
std::vector<edge_t> get_tree_topo_sort(std::vector<edge_t> const & topo){
std::vector<edge_t> sorted_topo;
std::vector<std::vector<index_t> > neighbours(topo.size()+1);
for(edge_t const E : topo){
neighbours[E.first].push_back(E.second);
neighbours[E.second].push_back(E.first);
}
std::vector<index_t> to_visit;
std::vector<int_t> nbr_unvisited(topo.size()+1);
for(index_t i=0; i<=topo.size(); ++i){
nbr_unvisited[i] = neighbours[i].size();
assert(topo.size() == 0 or nbr_unvisited[i] >= 1);
if(nbr_unvisited[i] == 1)
to_visit.push_back(i);
}
std::vector<int> visited(topo.size()+1, 0);
while(not to_visit.empty()){
index_t f = to_visit.back();
assert(visited[f] == 0);
visited[f] = 1;
to_visit.pop_back();
for(index_t s : neighbours[f]){
--nbr_unvisited[s];
if(visited[s] == 0){ // It is not a node we already visited
sorted_topo.push_back(edge_t(f, s));
}
if(nbr_unvisited[s] == 1){
to_visit.push_back(s);
}
}
}
assert(sorted_topo.size() == topo.size());
return sorted_topo;
}
std::vector<edge_t> get_big_horizontal_topology_from_sorted(std::vector<point<int_t> > const & pins, index_t exactitude_limit){
auto spanning = get_MST_topology(pins);
// TODO: perform local optimizations on the topology using exact Steiner tree algorithms
// Remove horizontal suboptimalities i.e. when the connexions to the left and right are unbalanced
// Reuse existing code by translation to vertical topology
auto first_Htopo = get_tree_topo_sort(spanning);
auto Vtopo = get_vertical_topology(pins, first_Htopo);
Vtopo = get_tree_topo_sort(Vtopo);
std::vector<point<int_t> > inverted_coords = pins;
for(point<int_t> & pt : inverted_coords){
std::swap(pt.x, pt.y);
}
auto Htopo = get_vertical_topology(inverted_coords, Vtopo);
// Sort the tree so that it is usable when building an RSMT
return get_tree_topo_sort(Htopo);
}
} // End anonymous namespace
std::vector<edge_t> get_RSMT_horizontal_topology(std::vector<point<int_t> > const & pins, index_t exactitude_limit){
if(pins.size() <= 1)
return std::vector<edge_t>();
else if(pins.size() == 2)
return std::vector<edge_t>(1, edge_t(0, 1));
else if(pins.size() == 3){
std::vector<indexed_pt> ipoints(pins.size());
for(index_t i=0; i<pins.size(); ++i){
ipoints[i] = indexed_pt(pins[i], i);
}
auto xpoints=ipoints;
std::sort(xpoints.begin(), xpoints.end(), [](indexed_pt a , indexed_pt b){return a.x < b.x; });
return std::vector<edge_t>{{xpoints[0].index, xpoints[1].index}, {xpoints[1].index, xpoints[2].index}};
}
else{
std::vector<edge_t> horizontal_topology;
// Sort the pins by x coordinate
std::vector<indexed_pt> ipoints(pins.size());
for(index_t i=0; i<pins.size(); ++i){
ipoints[i] = indexed_pt(pins[i], i);
}
std::sort(ipoints.begin(), ipoints.end(), [](indexed_pt a , indexed_pt b){return a.x < b.x; });
std::vector<point<int_t> > sorted_pins(pins.size());
for(index_t i=0; i<pins.size(); ++i){
sorted_pins[i] = ipoints[i];
}
// Get the topology for this ordering
if(pins.size() <= exactitude_limit){
horizontal_topology = get_small_horizontal_topology_from_sorted(sorted_pins);
}
else{
horizontal_topology = get_big_horizontal_topology_from_sorted(sorted_pins, exactitude_limit);
}
// Back to the original ordering
for(auto & E : horizontal_topology){
E.first = ipoints[E.first].index;
E.second = ipoints[E.second].index;
}
return horizontal_topology;
}
}
std::vector<std::pair<index_t, index_t> > get_MST_topology(std::vector<point<int_t> > const & pins){
std::vector<edge_t> edges;
if(pins.size() <= 2){
if(pins.size() == 2){
edges.push_back(edge_t(0, 1));
}
if(pins.size() == 3){
auto D = [](point<int_t> a, point<int_t> b){ return (int_t)(std::abs((float)(a.x - b.x)) + std::abs((float)(a.y - b.y))); };
auto dists = std::array<int_t, 3>({{D(pins[1], pins[2]), D(pins[1], pins[2]), D(pins[0], pins[1])}});
index_t mx = std::max_element(dists.begin(), dists.end()) - dists.begin();
for(index_t i=0; i<3; ++i){
if(i != mx)
edges.push_back(edge_t((i+1) % 3, (i+2) % 3));
}
}
return edges;
}
northeast_octant_neighbours(pins, edges);
southeast_octant_neighbours(pins, edges);
std::vector<edge_t> returned_edges;
auto edge_length = [&](edge_t E){
point<int_t> p1 = pins[E.first],
p2 = pins[E.second];
return std::abs((float)(p1.x - p2.x)) + std::abs((float)(p1.y - p2.y));
};
// Perform Kruskal to get the tree
std::sort(edges.begin(), edges.end(), [&](edge_t a, edge_t b){ return edge_length(a) < edge_length(b); });
union_find merger(pins.size());
for(index_t i=0; i<edges.size() && returned_edges.size()+1 < pins.size(); ++i){
edge_t E = edges[i];
if(merger.find(E.first) != merger.find(E.second)){
merger.merge(E.first, E.second);
assert(merger.find(E.first) == merger.find(E.second));
returned_edges.push_back(E);
}
}
assert(returned_edges.size() + 1 == pins.size());
assert(merger.is_connex());
return returned_edges;
}
std::int64_t MST_length(std::vector<point<int_t> > const & pins){
auto edges = get_MST_topology(pins);
std::int64_t sum = 0;
for(auto E : edges){
sum += std::abs((float)(pins[E.first].x - pins[E.second].x));
sum += std::abs((float)(pins[E.first].y - pins[E.second].y));
}
return sum;
}
std::int64_t RSMT_length(std::vector<point<int_t> > const & pins, index_t exactitude_limit){
assert(exactitude_limit <= 10 and exactitude_limit >= 3);
if(pins.size() <= 3){
if(pins.size() == 2){
return std::abs((float)(pins[0].x - pins[1].x)) + std::abs((float)(pins[0].y - pins[1].y));
}
else if(pins.size() == 3){
auto minmaxX = std::minmax_element(pins.begin(), pins.end(), [](point<int_t> a, point<int_t> b){ return a.x < b.x; }),
minmaxY = std::minmax_element(pins.begin(), pins.end(), [](point<int_t> a, point<int_t> b){ return a.y < b.y; });
return (minmaxX.second->x - minmaxX.first->x) + (minmaxY.second->y - minmaxY.first->y);
}
else{
return 0;
}
}
else{
std::vector<point<int_t> > points = pins;
std::sort(points.begin(), points.end(), [](point<int_t> a , point<int_t> b){return a.x < b.x; });
if(points.size() <= exactitude_limit){
switch(points.size()){
case 4:
return get_wirelength_from_sorted<4, 2>(points, steiner_lookup::topologies_4);
case 5:
return get_wirelength_from_sorted<5, 6>(points, steiner_lookup::topologies_5);
case 6:
return get_wirelength_from_sorted<6, 23>(points, steiner_lookup::topologies_6);
case 7:
return get_wirelength_from_sorted<7, 111>(points, steiner_lookup::topologies_7);
case 8:
return get_wirelength_from_sorted<8, 642>(points, steiner_lookup::topologies_8);
case 9:
return get_wirelength_from_sorted<9, 4334>(points, steiner_lookup::topologies_9);
case 10:
return get_wirelength_from_sorted<10, 33510>(points, steiner_lookup::topologies_10);
default:
abort();
}
}
else{ // Need to create the full topology, then calculate the length back
//return MST_length(points);
auto horizontal_topology = get_big_horizontal_topology_from_sorted(points, exactitude_limit);
return get_wirelength_from_topo(points, horizontal_topology);
}
}
}
point<std::vector<std::pair<index_t, index_t> > > get_RSMT_topology(std::vector<point<int_t> > const & pins, index_t exactitude_limit){
assert(exactitude_limit <= 10 and exactitude_limit >= 3);
// For 3 pin and fewer, the topology is very simple
if(pins.size() <= 2){
if(pins.size() == 2){
auto ret = std::vector<edge_t>(1, edge_t(0, 1));
return point<std::vector<edge_t> >(ret, ret);
}
else{
return point<std::vector<edge_t> >();
}
}
else if(pins.size() == 3){
std::vector<indexed_pt> ipoints(pins.size());
for(index_t i=0; i<pins.size(); ++i){
ipoints[i] = indexed_pt(pins[i], i);
}
auto xpoints=ipoints;
std::sort(xpoints.begin(), xpoints.end(), [](indexed_pt a , indexed_pt b){return a.x < b.x; });
auto ypoints=ipoints;
std::sort(ypoints.begin(), ypoints.end(), [](indexed_pt a , indexed_pt b){return a.y < b.y; });
return point<std::vector<edge_t> >{{{xpoints[0].index, xpoints[1].index}, {xpoints[1].index, xpoints[2].index}}, {{ypoints[0].index, ypoints[1].index}, {ypoints[1].index, ypoints[2].index}}};
}
else{
std::vector<edge_t> horizontal_topology = get_RSMT_horizontal_topology(pins, exactitude_limit);
return point<std::vector<edge_t> >(horizontal_topology, get_vertical_topology(pins, horizontal_topology));
}
}
} // Namespace coloquinte

View File

@ -5,7 +5,7 @@
set(ignoreVariables "${CMAKE_INSTALL_DIR}")
cmake_minimum_required(VERSION 3.16)
cmake_minimum_required(VERSION 2.8.9)
OPTION(BUILD_DOC "Build the documentation (latex+doxygen)" OFF)
option(USE_LIBBFD "Link with BFD libraries to print stack traces" OFF)
@ -21,7 +21,6 @@
setup_sysconfdir("${CMAKE_INSTALL_PREFIX}")
setup_boost(program_options)
setup_qt()
setup_python()
cmake_policy(SET CMP0054 NEW)
@ -29,6 +28,7 @@
find_package(Libbfd)
endif()
find_package(BZip2 REQUIRED)
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development)
find_package(PythonSitePackages REQUIRED)
find_package(BISON REQUIRED)
find_package(FLEX REQUIRED)
@ -41,5 +41,6 @@
add_subdirectory(src)
add_subdirectory(python)
add_subdirectory(etc)
add_subdirectory(cmake_modules)
add_subdirectory(doc)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More