Compare commits
134 Commits
staf/gf180
...
devel
Author | SHA1 | Date |
---|---|---|
|
947026cced | |
|
ce084fcf73 | |
|
7b304da14b | |
|
b734d61a00 | |
|
c2750ca127 | |
|
cadae8412b | |
|
d258749373 | |
|
21deed93f1 | |
|
e3d6456ce3 | |
|
fda7054840 | |
|
ffb5e38de2 | |
|
dcf3e7bd77 | |
|
605fa5cdd1 | |
|
508adbd00b | |
|
b06e90d122 | |
|
d8958c3b5a | |
|
9c8e63c11d | |
|
373cbe9835 | |
|
5cd83019db | |
|
d2c2f977f1 | |
|
a110a286d2 | |
|
73cc5c0e76 | |
|
4973d0a181 | |
|
76e9da0b64 | |
|
3243b12abb | |
|
73265c2d68 | |
|
47aadd8ef4 | |
|
30b92ff33a | |
|
ecdcabb8ad | |
|
b7698e7500 | |
|
e084c1e672 | |
|
7b155d1ecf | |
|
06433cc914 | |
|
554aded65b | |
|
9b38590c60 | |
|
014ec72652 | |
|
007677353f | |
|
f8637737a0 | |
|
b77d86c931 | |
|
d019c6aab5 | |
|
b8f15a2c8f | |
|
70fb5cfe3f | |
|
5cdb8b25f0 | |
|
0aa9010b32 | |
|
ee2ed63d35 | |
|
72b906cb68 | |
|
30b69f634a | |
|
73925094f1 | |
|
56da5ebe32 | |
|
0dc33538a7 | |
|
7b7e852f67 | |
|
04410f1cc2 | |
|
a3c05c0f60 | |
|
06ea3d6e09 | |
|
764464911e | |
|
f0c616a5ea | |
|
1df76cdf5a | |
|
4fe1436e1f | |
|
5c75a1ffb7 | |
|
e395069025 | |
|
0743e3bbe4 | |
|
665331252e | |
|
0fdc8f6d3f | |
|
093a4161ef | |
|
011b32d1ed | |
|
238d9dfaba | |
|
fb6979db19 | |
|
3d43a25bb4 | |
|
2bc2e4a988 | |
|
1b41976ca1 | |
|
c178b8c720 | |
|
a9041cbb7c | |
|
495edc6bfe | |
|
d85e7277a4 | |
|
e723a53b69 | |
|
288d89ba93 | |
|
c62383c09f | |
|
7091ac3a77 | |
|
c0b4aad02b | |
|
a9f55021fd | |
|
5d8b994bb6 | |
|
9b87b92eec | |
|
5233d860f4 | |
|
6f793665c2 | |
|
7f0ab625d2 | |
|
e497a4d48f | |
|
052df5d1c8 | |
|
4731e30bb3 | |
|
078e4e0644 | |
|
23975c541d | |
|
0fe1deac94 | |
|
db01b4ff55 | |
|
1f5549d396 | |
|
62e7640a37 | |
|
1beaaf93e4 | |
|
fb694e1c3d | |
|
d873216447 | |
|
49e95115f2 | |
|
2ea099afec | |
|
26184c5016 | |
|
acf6cfe041 | |
|
585489860e | |
|
4f1ce6cfcb | |
|
21eedbcc2b | |
|
393204ba0d | |
|
46c685a7f8 | |
|
1e71b5fb08 | |
|
3830a90482 | |
|
56883db08e | |
|
abee13d669 | |
|
96e6c9dd06 | |
|
c53fc01cb2 | |
|
52fd1c1c40 | |
|
4c7cf227be | |
|
d928a3c7a5 | |
|
c3bed61257 | |
|
57bab117b4 | |
|
31b0c4daf1 | |
|
b9862ecd5e | |
|
518a376c01 | |
|
6361ad4ca0 | |
|
e968a5088f | |
|
5afb4cabe9 | |
|
23c0c24c0f | |
|
2568a1a496 | |
|
e22e7f7476 | |
|
a0911be50a | |
|
e5d9c8808b | |
|
7ed41613de | |
|
50a9036d28 | |
|
8f387620cb | |
|
5879a5b581 | |
|
1f4b9450e5 | |
|
090c13663e |
|
@ -0,0 +1,6 @@
|
|||
[submodule "coloquinte"]
|
||||
path = coloquinte
|
||||
# url = git@github.com:Coloquinte/PlaceRoute.git
|
||||
url = https://github.com/Coloquinte/PlaceRoute.git
|
||||
branch = coriolis-submodule
|
||||
update = merge
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -3069,6 +3069,7 @@ 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;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ endif ( CHECK_DETERMINISM )
|
|||
${QtX_INCLUDE_DIRS}
|
||||
${Python_INCLUDE_DIRS}
|
||||
)
|
||||
find_package (Python3 COMPONENTS Interpreter Development)
|
||||
set( includes anabatic/Constants.h
|
||||
anabatic/Configuration.h
|
||||
anabatic/Matrix.h
|
||||
|
|
|
@ -132,6 +132,7 @@ 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 ()
|
||||
|
|
|
@ -277,7 +277,9 @@ 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) );
|
||||
AutoSegment::create( rpSourceContact, subContact1, Flags::Vertical|useNonPref );
|
||||
rpSourceContact = subContact1;
|
||||
|
@ -1155,8 +1157,8 @@ namespace Anabatic {
|
|||
}
|
||||
|
||||
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 );
|
||||
AutoContact* leftContact = doRp_Access( getGCell(), rpsM1[i-1], HAccess );
|
||||
AutoContact* rightContact = doRp_Access( getGCell(), rpsM1[i ], HAccess );
|
||||
AutoSegment::create( leftContact, rightContact, Flags::Horizontal );
|
||||
}
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ 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;
|
||||
|
@ -202,6 +203,7 @@ 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;
|
||||
|
@ -536,6 +538,7 @@ 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); }
|
||||
|
|
|
@ -110,6 +110,7 @@ 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& );
|
||||
|
|
|
@ -11,8 +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 )
|
||||
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development )
|
||||
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development.Module )
|
||||
find_package(PythonSitePackages REQUIRED)
|
||||
print_cmake_module_path()
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
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
|
||||
buildDir=${commonRoot}/build
|
||||
installDir=${commonRoot}/install
|
||||
|
||||
|
|
|
@ -24,8 +24,9 @@ projects = [
|
|||
#, "knik"
|
||||
#, "katabatic"
|
||||
#, "kite"
|
||||
, "equinox"
|
||||
, "solstice"
|
||||
#, "equinox"
|
||||
#, "solstice"
|
||||
, "tramontana"
|
||||
, "oroshi"
|
||||
, "bora"
|
||||
, "karakaze"
|
||||
|
|
|
@ -35,6 +35,7 @@ class Builder:
|
|||
self._noCache = False
|
||||
self._ninja = False
|
||||
self._clang = False
|
||||
self._manylinux = False
|
||||
self._noSystemBoost = False
|
||||
self._macports = False
|
||||
self._devtoolset = 0
|
||||
|
@ -62,6 +63,7 @@ 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
|
||||
|
@ -177,6 +179,7 @@ class Builder:
|
|||
if self._bfd: command += [ "-D", "USE_LIBBFD:STRING=%s" % self._bfd ]
|
||||
if self._qt4: command += [ "-D", "WITH_QT4: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
|
||||
|
|
|
@ -211,6 +211,7 @@ parser.add_option ( "--bfd" , action="store_true" ,
|
|||
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,6 +283,7 @@ else:
|
|||
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.openmp: builder.openmp = True
|
||||
if options.makeArguments: builder.makeArguments = options.makeArguments
|
||||
#if options.svnMethod: builder.svnMethod = options.svnMethod
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
FindQwt.cmake
|
||||
FindSphinx.cmake
|
||||
FindPelican.cmake
|
||||
FindCOLOQUINTE.cmake
|
||||
GetGitRevisionDescription.cmake
|
||||
GetGitRevisionDescription.cmake.in
|
||||
)
|
||||
|
|
|
@ -84,10 +84,10 @@
|
|||
set(DEBUG_FLAGS "-g")
|
||||
if(CYGWIN)
|
||||
set(ADDITIONAL_FLAGS "-D_GLIBCXX_USE_C99")
|
||||
set(CXX_STANDARD "gnu++11")
|
||||
set(CXX_STANDARD "gnu++17")
|
||||
else()
|
||||
set(ADDITIONAL_FLAGS "-Wl,--no-undefined")
|
||||
set(CXX_STANDARD "c++11")
|
||||
set(CXX_STANDARD "c++17")
|
||||
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)
|
||||
|
@ -223,6 +223,20 @@ 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.
|
||||
#
|
||||
|
|
|
@ -15,13 +15,14 @@ IF(UNIX)
|
|||
#
|
||||
# Look for an installation.
|
||||
#
|
||||
FIND_PATH(COLOQUINTE_INCLUDE_PATH NAMES coloquinte/netlist.hxx PATHS
|
||||
FIND_PATH(COLOQUINTE_INCLUDE_PATH NAMES coloquinte/coloquinte.hpp 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
|
|
@ -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/*.hxx
|
||||
%{coriolisTop}/include/coriolis2/coloquinte/*.hpp
|
||||
%{coriolisTop}/include/coriolis2/hurricane/*.h
|
||||
%{coriolisTop}/include/coriolis2/hurricane/viewer/*.h
|
||||
%{coriolisTop}/include/coriolis2/hurricane/isobar/*.h
|
||||
|
|
|
@ -284,6 +284,16 @@ 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 +313,7 @@ class Configuration ( object ):
|
|||
def __init__ ( self ):
|
||||
self._sender = 'Jean-Paul.Chaput@soc.lip6.fr'
|
||||
self._receivers = [ 'Jean-Paul.Chaput@lip6.fr', ]
|
||||
self._supportRepos = [ 'http://github.com/miloyip/rapidjson' ]
|
||||
self._supportRepos = [ 'https://github.com/Tencent/rapidjson.git' ]
|
||||
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'
|
||||
|
@ -601,6 +611,8 @@ try:
|
|||
if conf.rmSource: gitCoriolis.removeLocalRepo()
|
||||
gitCoriolis.clone ()
|
||||
gitCoriolis.checkout( 'devel' )
|
||||
gitCoriolis.submoduleInit()
|
||||
gitCoriolis.submoduleUpdate()
|
||||
|
||||
if conf.rmSource: gitBenchs.removeLocalRepo()
|
||||
gitBenchs.clone()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 97bb781ba363303fd6b7254c717f621b137b89e3
|
|
@ -1,34 +0,0 @@
|
|||
# -*- 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 3.16)
|
||||
|
||||
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)
|
|
@ -1,2 +0,0 @@
|
|||
|
||||
install ( FILES FindCOLOQUINTE.cmake DESTINATION share/cmake/Modules )
|
|
@ -1,39 +0,0 @@
|
|||
# -*- 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 )
|
||||
|
|
@ -1,185 +0,0 @@
|
|||
|
||||
#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
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
|
||||
#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
|
|
@ -1,408 +0,0 @@
|
|||
|
||||
#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
|
||||
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
|
||||
#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
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
|
||||
#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
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
|
||||
#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
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
|
||||
#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
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
#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
|
|
@ -1,251 +0,0 @@
|
|||
|
||||
#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
|
||||
|
|
@ -1,161 +0,0 @@
|
|||
|
||||
#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
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
|
||||
|
||||
#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
|
||||
|
|
@ -1,263 +0,0 @@
|
|||
|
||||
#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
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
|
||||
#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
|
||||
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
|
||||
#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
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
|
||||
#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
|
||||
|
|
@ -1,261 +0,0 @@
|
|||
|
||||
#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
|
||||
|
||||
|
|
@ -1,452 +0,0 @@
|
|||
|
||||
#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
|
@ -1,515 +0,0 @@
|
|||
|
||||
#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
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
#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
|
||||
|
||||
|
|
@ -1,260 +0,0 @@
|
|||
|
||||
#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
|
@ -1,599 +0,0 @@
|
|||
|
||||
#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
|
||||
|
||||
|
|
@ -1,384 +0,0 @@
|
|||
|
||||
#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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,536 +0,0 @@
|
|||
|
||||
#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
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
setup_sysconfdir("${CMAKE_INSTALL_PREFIX}")
|
||||
setup_boost(program_options)
|
||||
setup_qt()
|
||||
setup_python()
|
||||
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
|
||||
|
@ -28,7 +29,6 @@
|
|||
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)
|
||||
|
|
|
@ -19,36 +19,36 @@ import coriolis.Cfg as Cfg
|
|||
param = Cfg.getParamDouble( 'etesian.aspectRatio' )
|
||||
param.setDouble( 1.0 )
|
||||
|
||||
Cfg.getParamDouble ( 'etesian.spaceMargin' ).setPercentage( 0.05 )
|
||||
Cfg.getParamBool ( 'etesian.uniformDensity' ).setBool ( False )
|
||||
Cfg.getParamBool ( 'etesian.routingDriven' ).setBool ( False )
|
||||
Cfg.getParamString ( 'etesian.feedNames' ).setString ( 'tie_x0,rowend_x0' )
|
||||
Cfg.getParamString ( 'etesian.cell.zero' ).setString ( 'zero_x0' )
|
||||
Cfg.getParamString ( 'etesian.cell.one' ).setString ( 'one_x0' )
|
||||
Cfg.getParamString ( 'etesian.bloat' ).setString ( 'disabled' )
|
||||
Cfg.getParamDouble ( 'etesian.spaceMargin' ).setPercentage( 0.05 )
|
||||
Cfg.getParamDouble ( 'etesian.densityVariation' ).setPercentage( 0.05 )
|
||||
Cfg.getParamBool ( 'etesian.routingDriven' ).setBool ( False )
|
||||
Cfg.getParamString ( 'etesian.feedNames' ).setString ( 'tie_x0,rowend_x0' )
|
||||
Cfg.getParamString ( 'etesian.cell.zero' ).setString ( 'zero_x0' )
|
||||
Cfg.getParamString ( 'etesian.cell.one' ).setString ( 'one_x0' )
|
||||
Cfg.getParamString ( 'etesian.bloat' ).setString ( 'disabled' )
|
||||
|
||||
param = Cfg.getParamEnumerate( 'etesian.effort' )
|
||||
param.setInt( 2 )
|
||||
param.addValue( 'Fast' , 1 )
|
||||
param.addValue( 'Standard', 2 )
|
||||
param.addValue( 'High' , 3 )
|
||||
param.addValue( 'Extreme' , 4 )
|
||||
param.addValue( 'Standard', 3 )
|
||||
param.addValue( 'High' , 6 )
|
||||
param.addValue( 'Extreme' , 9 )
|
||||
|
||||
param = Cfg.getParamEnumerate( 'etesian.graphics' )
|
||||
param.setInt( 2 )
|
||||
param.setInt( 3 )
|
||||
param.addValue( 'Show every step' , 1 )
|
||||
param.addValue( 'Show lower bound', 2 )
|
||||
param.addValue( 'Show result only', 3 )
|
||||
|
||||
layout = Cfg.Configuration.get().getLayout()
|
||||
layout.addTab ( 'Etesian', 'etesian' )
|
||||
layout.addTitle ( 'Etesian', 'Placement area' )
|
||||
layout.addParameter( 'Etesian', 'etesian.aspectRatio' , 'Aspect Ratio, X/Y (%)', 0 )
|
||||
layout.addParameter( 'Etesian', 'etesian.spaceMargin' , 'Space Margin' , 1 )
|
||||
layout.addRule ( 'Etesian' )
|
||||
layout.addTitle ( 'Etesian', 'Etesian - Placer')
|
||||
layout.addParameter( 'Etesian', 'etesian.uniformDensity', 'Uniform density' , 0 )
|
||||
layout.addParameter( 'Etesian', 'etesian.routingDriven' , 'Routing driven' , 0 )
|
||||
layout.addParameter( 'Etesian', 'etesian.effort' , 'Placement effort' , 1 )
|
||||
layout.addParameter( 'Etesian', 'etesian.graphics' , 'Placement view' , 1 )
|
||||
layout.addRule ( 'Etesian' )
|
||||
layout.addTab ( 'Placer', 'etesian' )
|
||||
layout.addTitle ( 'Placer', 'Placement area' )
|
||||
layout.addParameter( 'Placer', 'etesian.aspectRatio' , 'Aspect Ratio, X/Y' , 0 )
|
||||
layout.addParameter( 'Placer', 'etesian.spaceMargin' , 'Space Margin' , 1 )
|
||||
layout.addRule ( 'Placer' )
|
||||
layout.addTitle ( 'Placer', 'Etesian - Placer')
|
||||
layout.addParameter( 'Placer', 'etesian.densityVariation' , 'Density variation' , 0 )
|
||||
layout.addParameter( 'Placer', 'etesian.routingDriven' , 'Routing driven' , 0 )
|
||||
layout.addParameter( 'Placer', 'etesian.effort' , 'Placement effort' , 1 )
|
||||
layout.addParameter( 'Placer', 'etesian.graphics' , 'Placement view' , 1 )
|
||||
layout.addRule ( 'Placer' )
|
||||
|
|
|
@ -19,22 +19,22 @@ import coriolis.Cfg as Cfg
|
|||
layout = Cfg.Configuration.get().getLayout()
|
||||
|
||||
# Kite Layout.
|
||||
layout.addTab ( 'Kite', 'kite' )
|
||||
layout.addTitle ( 'Kite', 'Katabatic - Routing Database' )
|
||||
layout.addParameter( 'Kite', 'katabatic.saturateRatio' , 'Saturate Ratio (%)' , 0, 1 )
|
||||
layout.addParameter( 'Kite', 'katabatic.saturateRp' , 'Saturate RoutingPad' , 0, 1 )
|
||||
layout.addParameter( 'Kite', 'katabatic.globalLengthThreshold', 'Global Length Threshold', 0, 1 )
|
||||
layout.addParameter( 'Kite', 'katabatic.topRoutingLayer' , 'Top Routing Layer' , 0, 1 )
|
||||
layout.addParameter( 'Kite', 'anabatic.gcell.displayMode' , 'GCell Display Mode' , 1, 1 )
|
||||
layout.addRule ( 'Kite' )
|
||||
layout.addTitle ( 'Kite', 'Kite - Detailed Router' )
|
||||
layout.addParameter( 'Kite', 'kite.hTracksReservedLocal', 'Vert. Locally Reserved Tracks', 0 )
|
||||
layout.addParameter( 'Kite', 'kite.vTracksReservedLocal', 'Hor. Locally Reserved Tracks' , 0 )
|
||||
layout.addParameter( 'Kite', 'kite.eventsLimit' , 'Events Limit' , 0 )
|
||||
layout.addParameter( 'Kite', 'kite.ripupCost' , 'Ripup Cost' , 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addSection ( 'Kite', 'Ripup Limits', 1 )
|
||||
layout.addParameter( 'Kite', 'kite.strapRipupLimit' , 'Straps' , 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addParameter( 'Kite', 'kite.localRipupLimit' , 'Locals' , 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addParameter( 'Kite', 'kite.globalRipupLimit' , 'Globals' , 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addParameter( 'Kite', 'kite.longGlobalRipupLimit', 'Long Globals', 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addRule ( 'Kite' )
|
||||
layout.addTab ( 'Router', 'kite' )
|
||||
layout.addTitle ( 'Router', 'Katabatic - Routing Database' )
|
||||
layout.addParameter( 'Router', 'katabatic.saturateRatio' , 'Saturate Ratio (%)' , 0, 1 )
|
||||
layout.addParameter( 'Router', 'katabatic.saturateRp' , 'Saturate RoutingPad' , 0, 1 )
|
||||
layout.addParameter( 'Router', 'katabatic.globalLengthThreshold', 'Global Length Threshold', 0, 1 )
|
||||
layout.addParameter( 'Router', 'katabatic.topRoutingLayer' , 'Top Routing Layer' , 0, 1 )
|
||||
layout.addParameter( 'Router', 'anabatic.gcell.displayMode' , 'GCell Display Mode' , 1, 1 )
|
||||
layout.addRule ( 'Router' )
|
||||
layout.addTitle ( 'Router', 'Kite - Detailed Router' )
|
||||
layout.addParameter( 'Router', 'kite.hTracksReservedLocal', 'Vert. Locally Reserved Tracks', 0 )
|
||||
layout.addParameter( 'Router', 'kite.vTracksReservedLocal', 'Hor. Locally Reserved Tracks' , 0 )
|
||||
layout.addParameter( 'Router', 'kite.eventsLimit' , 'Events Limit' , 0 )
|
||||
layout.addParameter( 'Router', 'kite.ripupCost' , 'Ripup Cost' , 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addSection ( 'Router', 'Ripup Limits', 1 )
|
||||
layout.addParameter( 'Router', 'kite.strapRipupLimit' , 'Straps' , 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addParameter( 'Router', 'kite.localRipupLimit' , 'Locals' , 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addParameter( 'Router', 'kite.globalRipupLimit' , 'Globals' , 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addParameter( 'Router', 'kite.longGlobalRipupLimit', 'Long Globals', 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addRule ( 'Router' )
|
||||
|
|
|
@ -85,19 +85,19 @@ param.addValue( "Custom" , 30 )
|
|||
param.setInt ( 0 )
|
||||
|
||||
layout = Cfg.Configuration.get().getLayout()
|
||||
layout.addTab ( 'misc', 'Misc.' )
|
||||
layout.addTitle ( 'misc', 'Miscellaneous' )
|
||||
layout.addParameter( 'misc', 'misc.catchCore' , 'Catch Core Dumps' , 1 )
|
||||
layout.addParameter( 'misc', 'misc.verboseLevel1' , 'Verbose' , 0 )
|
||||
layout.addParameter( 'misc', 'misc.verboseLevel2' , 'Very Verbose' , 0 )
|
||||
layout.addParameter( 'misc', 'misc.info' , 'Show Info' , 0 )
|
||||
layout.addParameter( 'misc', 'misc.logMode' , 'Output is a TTY' , 0 )
|
||||
layout.addParameter( 'misc', 'misc.minTraceLevel' , 'Min. Trace Level' , 1 )
|
||||
layout.addParameter( 'misc', 'misc.maxTraceLevel' , 'Max. Trace Level' , 1 )
|
||||
layout.addTitle ( 'misc', 'Print/Snapshot Parameters' )
|
||||
layout.addParameter( 'misc', 'viewer.printer.mode' , 'Printer/Snapshot Mode', 1 )
|
||||
layout.addParameter( 'misc', 'viewer.printer.paper' , 'Paper Size' , 0 )
|
||||
layout.addParameter( 'misc', 'viewer.printer.orientation', 'Orientation' , 0 )
|
||||
layout.addParameter( 'misc', 'viewer.printer.DPI' , 'DPI' , 0 )
|
||||
layout.addTab ( 'Misc', 'Misc.' )
|
||||
layout.addTitle ( 'Misc', 'Miscellaneous' )
|
||||
layout.addParameter( 'Misc', 'misc.catchCore' , 'Catch Core Dumps' , 1 )
|
||||
layout.addParameter( 'Misc', 'misc.verboseLevel1' , 'Verbose' , 0 )
|
||||
layout.addParameter( 'Misc', 'misc.verboseLevel2' , 'Very Verbose' , 0 )
|
||||
layout.addParameter( 'Misc', 'misc.info' , 'Show Info' , 0 )
|
||||
layout.addParameter( 'Misc', 'misc.logMode' , 'Output is a TTY' , 0 )
|
||||
layout.addParameter( 'Misc', 'misc.minTraceLevel' , 'Min. Trace Level' , 1 )
|
||||
layout.addParameter( 'Misc', 'misc.maxTraceLevel' , 'Max. Trace Level' , 1 )
|
||||
layout.addTitle ( 'Misc', 'Print/Snapshot Parameters' )
|
||||
layout.addParameter( 'Misc', 'viewer.printer.mode' , 'Printer/Snapshot Mode', 1 )
|
||||
layout.addParameter( 'Misc', 'viewer.printer.paper' , 'Paper Size' , 0 )
|
||||
layout.addParameter( 'Misc', 'viewer.printer.orientation', 'Orientation' , 0 )
|
||||
layout.addParameter( 'Misc', 'viewer.printer.DPI' , 'DPI' , 0 )
|
||||
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
import coriolis.Cfg as Cfg
|
||||
|
||||
layout = Cfg.Configuration.get().getLayout()
|
||||
layout.addTab ( 'stratus1', 'Stratus1' )
|
||||
layout.addTitle ( 'stratus1', 'Stratus1 - Netlist & Layout Capture' )
|
||||
layout.addParameter( 'stratus1', 'stratus1.mappingName', 'Virtual Library Translation', 0, 2 )
|
||||
layout.addParameter( 'stratus1', 'stratus1.format' , 'Netlist Format (vst, vhd)' , 0, 2 )
|
||||
layout.addParameter( 'stratus1', 'stratus1.simulator' , 'Simulator' , 0, 2 )
|
||||
layout.addTab ( 'Netlist', 'Stratus1' )
|
||||
layout.addTitle ( 'Netlist', 'Stratus1 - Netlist & Layout Capture' )
|
||||
layout.addParameter( 'Netlist', 'stratus1.mappingName', 'Virtual Library Translation', 0, 2 )
|
||||
layout.addParameter( 'Netlist', 'stratus1.format' , 'Netlist Format (vst, vhd)' , 0, 2 )
|
||||
layout.addParameter( 'Netlist', 'stratus1.simulator' , 'Simulator' , 0, 2 )
|
||||
|
|
|
@ -0,0 +1,327 @@
|
|||
|
||||
import sys
|
||||
import os.path
|
||||
from coriolis import Cfg
|
||||
from coriolis.Hurricane import Technology, DataBase, DbU, Library, Layer, \
|
||||
BasicLayer, Cell, Net, Horizontal, Vertical, \
|
||||
Rectilinear, Box, Point, Instance, Transformation, \
|
||||
NetExternalComponents, Pad
|
||||
import coriolis.Viewer
|
||||
from coriolis.CRL import AllianceFramework, Gds, LefImport, CellGauge, \
|
||||
RoutingGauge, RoutingLayerGauge
|
||||
from coriolis.helpers import l, u, n, overlay, io, ndaTopDir
|
||||
from coriolis.helpers.overlay import CfgCache, UpdateSession
|
||||
from coriolis.Anabatic import StyleFlags
|
||||
|
||||
|
||||
__all__ = [ "setup" ]
|
||||
|
||||
|
||||
def _routing ():
|
||||
"""
|
||||
Define the routing gauge along with the various P&R tool parameters.
|
||||
"""
|
||||
af = AllianceFramework.get()
|
||||
db = DataBase.getDB()
|
||||
tech = db.getTechnology()
|
||||
rg = RoutingGauge.create('mcu9t5v0')
|
||||
rg.setSymbolic( False )
|
||||
rg.addLayerGauge(
|
||||
RoutingLayerGauge.create( tech.getLayer( 'Metal1' ) # metal
|
||||
, RoutingLayerGauge.Horizontal # preferred routing direction
|
||||
, RoutingLayerGauge.PinOnly # layer usage
|
||||
, 0 # depth
|
||||
, 0.0 # density (deprecated)
|
||||
, u(0.0) # track offset from AB
|
||||
, u(0.56) # track pitch
|
||||
, u(0.23) # wire width
|
||||
, u(0.23) # perpandicular wire width
|
||||
, u(0.26) # VIA side
|
||||
, u(0.0 ) )) # obstacle dW
|
||||
rg.addLayerGauge(
|
||||
RoutingLayerGauge.create( tech.getLayer( 'Metal2' ) # metal
|
||||
, RoutingLayerGauge.Vertical # preferred routing direction
|
||||
, RoutingLayerGauge.Default # layer usage
|
||||
, 1 # depth
|
||||
, 0.0 # density (deprecated)
|
||||
, u(0.0) # track offset from AB
|
||||
, u(0.56) # track pitch
|
||||
, u(0.28) # wire width
|
||||
, u(0.28) # perpandicular wire width
|
||||
, u(0.26) # VIA side
|
||||
, u(0.0 ) )) # obstacle dW
|
||||
rg.addLayerGauge(
|
||||
RoutingLayerGauge.create( tech.getLayer( 'Metal3' ) # metal
|
||||
, RoutingLayerGauge.Horizontal # preferred routing direction
|
||||
, RoutingLayerGauge.Default # layer usage
|
||||
, 2 # depth
|
||||
, 0.0 # density (deprecated)
|
||||
, u(0.0) # track offset from AB
|
||||
, u(0.56) # track pitch
|
||||
, u(0.28) # wire width
|
||||
, u(0.28) # perpandicular wire width
|
||||
, u(0.26) # VIA side
|
||||
, u(0.0 ) )) # obstacle dW
|
||||
rg.addLayerGauge(
|
||||
RoutingLayerGauge.create( tech.getLayer( 'Metal4' ) # metal
|
||||
, RoutingLayerGauge.Vertical # preferred routing direction
|
||||
, RoutingLayerGauge.Default # layer usage
|
||||
, 3 # depth
|
||||
, 0.0 # density (deprecated)
|
||||
, u(0.0) # track offset from AB
|
||||
, u(0.56) # track pitch
|
||||
, u(0.28) # wire width
|
||||
, u(0.28) # perpandicular wire width
|
||||
, u(0.26) # VIA side
|
||||
, u(0.0 ) )) # obstacle dW
|
||||
rg.addLayerGauge(
|
||||
RoutingLayerGauge.create( tech.getLayer( 'Metal5' ) # metal
|
||||
, RoutingLayerGauge.Horizontal # preferred routing direction
|
||||
, RoutingLayerGauge.Default # layer usage
|
||||
, 4 # depth
|
||||
, 0.0 # density (deprecated)
|
||||
, u(0.0) # track offset from AB
|
||||
, u(0.56) # track pitch
|
||||
, u(0.28) # wire width
|
||||
, u(0.28) # perpandicular wire width
|
||||
, u(0.26) # VIA side
|
||||
, u(0.0 ) )) # obstacle dW
|
||||
rg.addLayerGauge(
|
||||
RoutingLayerGauge.create( tech.getLayer( 'MetalTop' ) # metal
|
||||
, RoutingLayerGauge.Vertical # preferred routing direction
|
||||
, RoutingLayerGauge.PowerSupply # layer usage
|
||||
, 5 # depth
|
||||
, 0.0 # density (deprecated)
|
||||
, u(0.0) # track offset from AB
|
||||
, u(0.9) # track pitch
|
||||
, u(0.44) # wire width
|
||||
, u(0.44) # perpandicular wire width
|
||||
, u(0.26) # VIA side
|
||||
, u(0.0 ) )) # obstacle dW
|
||||
af.addRoutingGauge( rg )
|
||||
af.setRoutingGauge( 'mcu9t5v0' )
|
||||
|
||||
cg = CellGauge.create( 'LEF.GF018hv5v_green_sc9'
|
||||
, 'Metal1' # pin layer name.
|
||||
, u( 0.56 ) # pitch.
|
||||
, u( 5.04) # cell slice height.
|
||||
, u( 0.56) # cell slice step.
|
||||
)
|
||||
af.addCellGauge( cg )
|
||||
af.setCellGauge( 'LEF.GF018hv5v_green_sc9' )
|
||||
|
||||
with CfgCache(priority=Cfg.Parameter.Priority.ConfigurationFile) as cfg:
|
||||
env = af.getEnvironment()
|
||||
env.setRegister( '.*__dff.*' )
|
||||
# Place & Route setup
|
||||
cfg.viewer.minimumSize = 500
|
||||
cfg.viewer.pixelThreshold = 2
|
||||
cfg.lefImport.minTerminalWidth = 0.0
|
||||
cfg.crlcore.groundName = 'vss'
|
||||
cfg.crlcore.powerName = 'vdd'
|
||||
cfg.etesian.bloat = 'disabled'
|
||||
cfg.etesian.aspectRatio = 1.00
|
||||
cfg.etesian.aspectRatio = [10, 1000]
|
||||
cfg.etesian.spaceMargin = 0.10
|
||||
cfg.etesian.uniformDensity = True
|
||||
cfg.etesian.routingDriven = False
|
||||
cfg.etesian.latchUpDistance = u(30.0 - 1.0)
|
||||
#cfg.etesian.diodeName = 'diode'
|
||||
#cfg.etesian.antennaInsertThreshold = 0.50
|
||||
#cfg.etesian.antennaMaxWL = u(250.0)
|
||||
cfg.etesian.feedNames = 'gf180mcu_fd_sc_mcu9t5v0__fill_1,gf180mcu_fd_sc_mcu9t5v0__fill_2,gf180mcu_fd_sc_mcu9t5v0__fill_4,gf180mcu_fd_sc_mcu9t5v0__fill_8'
|
||||
cfg.etesian.defaultFeed = 'fill_2'
|
||||
cfg.etesian.cell.zero = 'gf180mcu_fd_sc_mcu9t5v0__tieh'
|
||||
cfg.etesian.cell.one = 'gf180mcu_fd_sc_mcu9t5v0__tiel'
|
||||
cfg.etesian.effort = 2
|
||||
cfg.etesian.effort = (
|
||||
('Fast', 1),
|
||||
('Standard', 2),
|
||||
('High', 3 ),
|
||||
('Extreme', 4 ),
|
||||
)
|
||||
cfg.etesian.graphics = 2
|
||||
cfg.etesian.graphics = (
|
||||
('Show every step', 1),
|
||||
('Show lower bound', 2),
|
||||
('Show result only', 3),
|
||||
)
|
||||
cfg.anabatic.routingGauge = 'mcu9t5v0'
|
||||
cfg.anabatic.cellGauge = 'LEF.GF018hv5v_green_sc9'
|
||||
cfg.anabatic.globalLengthThreshold = 1450
|
||||
cfg.anabatic.saturateRatio = 0.90
|
||||
cfg.anabatic.saturateRp = 10
|
||||
#cfg.anabatic.topRoutingLayer = 'mt2'
|
||||
cfg.anabatic.edgeLength = 192
|
||||
cfg.anabatic.edgeWidth = 32
|
||||
cfg.anabatic.edgeCostH = 9.0
|
||||
cfg.anabatic.edgeCostK = -10.0
|
||||
cfg.anabatic.edgeHInc = 1.0
|
||||
cfg.anabatic.edgeHScaling = 1.0
|
||||
cfg.anabatic.globalIterations = 10
|
||||
cfg.anabatic.globalIterations = [ 1, 100 ]
|
||||
cfg.anabatic.gcell.displayMode = 1
|
||||
cfg.anabatic.gcell.displayMode = (("Boundary", 1), ("Density", 2))
|
||||
cfg.anabatic.netBuilderStyle = 'VH,3RL+'
|
||||
cfg.anabatic.routingStyle = StyleFlags.VH
|
||||
cfg.katana.disableStackedVias = False
|
||||
cfg.katana.hTracksReservedLocal = 4
|
||||
cfg.katana.hTracksReservedLocal = [0, 20]
|
||||
cfg.katana.vTracksReservedLocal = 3
|
||||
cfg.katana.vTracksReservedLocal = [0, 20]
|
||||
cfg.katana.termSatReservedLocal = 8
|
||||
cfg.katana.termSatThreshold = 9
|
||||
cfg.katana.eventsLimit = 4000002
|
||||
cfg.katana.ripupCost = 3
|
||||
cfg.katana.ripupCost = [0, None]
|
||||
cfg.katana.strapRipupLimit = 16
|
||||
cfg.katana.strapRipupLimit = [1, None]
|
||||
cfg.katana.localRipupLimit = 9
|
||||
cfg.katana.localRipupLimit = [1, None]
|
||||
cfg.katana.globalRipupLimit = 5
|
||||
cfg.katana.globalRipupLimit = [1, None]
|
||||
cfg.katana.longGlobalRipupLimit = 5
|
||||
cfg.chip.padCoreSide = 'South'
|
||||
# Plugins setup
|
||||
cfg.clockTree.minimumSide = u(5.04) * 6
|
||||
cfg.clockTree.buffer = 'gf180mcu_fd_sc_mcu9t5v0__clkbuf_2'
|
||||
cfg.clockTree.placerEngine = 'Etesian'
|
||||
cfg.block.spareSide = 10
|
||||
cfg.spares.buffer = 'gf180mcu_fd_sc_mcu9t5v0__clkbuf_2'
|
||||
cfg.spares.maxSinks = 20
|
||||
|
||||
|
||||
def _loadStdLib ( cellsTop ):
|
||||
"""
|
||||
Load the muc9t5v0 library from the GDS files.
|
||||
|
||||
:param cellsTop: The top directory containing the cells views.
|
||||
|
||||
As GDS file is lacking most of the interface informations, apply a
|
||||
post-process on each cell to educated guess :
|
||||
|
||||
* Which nets are external, and in which direction (name matching).
|
||||
* Blockages: any shape in internals nets in Metal1 or Metal2 layer.
|
||||
"""
|
||||
useGds = False
|
||||
af = AllianceFramework.get()
|
||||
db = DataBase.getDB()
|
||||
tech = db.getTechnology()
|
||||
rootlib = db.getRootLibrary()
|
||||
cellLib = Library.create(rootlib, 'mcu9t5v')
|
||||
af.wrapLibrary( cellLib, 0 )
|
||||
|
||||
gaugeName = Cfg.getParamString('anabatic.routingGauge').asString()
|
||||
routingGauge = af.getRoutingGauge( gaugeName )
|
||||
metal1 = DataBase.getDB().getTechnology().getLayer( 'Metal1' )
|
||||
metal2 = DataBase.getDB().getTechnology().getLayer( 'Metal2' )
|
||||
blockage1 = metal1.getBlockageLayer()
|
||||
blockage2 = metal2.getBlockageLayer()
|
||||
hpitch = 0
|
||||
for layerGauge in routingGauge.getLayerGauges():
|
||||
if layerGauge.getType() == RoutingLayerGauge.PinOnly:
|
||||
continue
|
||||
if layerGauge.getDirection() == RoutingLayerGauge.Horizontal:
|
||||
hpitch = layerGauge.getPitch()
|
||||
break
|
||||
|
||||
if useGds:
|
||||
io.vprint( 1, ' o Setup GF 180 mcu9t5v library in {} [GDS].'.format( cellLib.getName() ))
|
||||
io.vprint( 2, ' (__file__="{}")'.format( os.path.abspath( __file__ )))
|
||||
for cellDir in cellsTop.iterdir():
|
||||
for gdsFile in sorted(cellDir.glob('*.gds')):
|
||||
Gds.load( cellLib
|
||||
, gdsFile.as_posix()
|
||||
, Gds.NoGdsPrefix|Gds.Layer_0_IsBoundary )
|
||||
#io.vprint( 1, ' o Skrinking V-AB of {}'.format(DbU.getValueString( hpitch )))
|
||||
with overlay.UpdateSession():
|
||||
for cell in cellLib.getCells():
|
||||
ab = cell.getAbutmentBox()
|
||||
#ab.inflate( 0, -hpitch )
|
||||
cell.setAbutmentBox( ab )
|
||||
cell.setTerminalNetlist( True )
|
||||
for net in cell.getNets():
|
||||
if not net.isExternal():
|
||||
blockages = []
|
||||
for component in net.getComponents():
|
||||
if component.getLayer() == metal1 or component.getLayer() == metal1:
|
||||
blockages.append( component )
|
||||
if blockages:
|
||||
io.vprint( 2, ' - Obstacles found in {}'.format( cell ))
|
||||
for component in blockages:
|
||||
bb = component.getBoundingBox()
|
||||
if component.getLayer() == metal1:
|
||||
v = Vertical.create( net
|
||||
, blockage1
|
||||
, bb.getXCenter()
|
||||
, bb.getWidth()
|
||||
, bb.getYMin()
|
||||
, bb.getYMax() )
|
||||
if component.getLayer() == metal2:
|
||||
h = Horizontal.create( net
|
||||
, blockage2
|
||||
, bb.getYCenter()
|
||||
, bb.getHeight()
|
||||
, bb.getXMin()
|
||||
, bb.getXMax() )
|
||||
continue
|
||||
if net.isPower() or net.getName() == 'VDD':
|
||||
net.setName( 'VDD' )
|
||||
net.setType( Net.Type.POWER )
|
||||
net.setGlobal( True )
|
||||
net.setDirection( Net.Direction.IN )
|
||||
continue
|
||||
if net.isGround() or net.getName() == 'VSS':
|
||||
net.setName( 'VSS' )
|
||||
net.setType( Net.Type.GROUND )
|
||||
net.setGlobal( True )
|
||||
net.setDirection( Net.Direction.IN )
|
||||
continue
|
||||
if net.getName() == 'Z' \
|
||||
or net.getName() == 'ZN' \
|
||||
or net.getName() == 'Q':
|
||||
net.setDirection( Net.Direction.OUT )
|
||||
else:
|
||||
net.setDirection( Net.Direction.IN )
|
||||
toDestroy = []
|
||||
for component in NetExternalComponents.get(net):
|
||||
if isinstance(component,Pad):
|
||||
bb = component.getBoundingBox()
|
||||
pad = Vertical.create( net
|
||||
, component.getLayer()
|
||||
, bb.getCenter().getX()
|
||||
, bb.getWidth()
|
||||
, bb.getYMin()
|
||||
, bb.getYMax() )
|
||||
NetExternalComponents.setExternal( pad )
|
||||
toDestroy.append( component )
|
||||
for component in toDestroy:
|
||||
component.destroy()
|
||||
else:
|
||||
io.vprint( 1, ' o Setup GF 180 mcu9t5v library in {} [LEF].'.format( cellLib.getName() ))
|
||||
io.vprint( 2, ' (__file__="{}")'.format( os.path.abspath( __file__ )))
|
||||
LefImport.load( (cellsTop / '..' / 'tech' / 'gf180mcu_6LM_1TM_9K_9t_tech.lef').as_posix() )
|
||||
LefImport.setMergeLibrary( cellLib )
|
||||
for cellDir in cellsTop.iterdir():
|
||||
for lefFile in sorted(cellDir.glob('*.lef')):
|
||||
LefImport.load( lefFile.as_posix() )
|
||||
af.wrapLibrary( cellLib, 1 )
|
||||
return cellLib
|
||||
|
||||
|
||||
def _loadIoLib ():
|
||||
"""
|
||||
Load the IO library from the GDS files.
|
||||
"""
|
||||
af = AllianceFramework.get()
|
||||
ioLib = af.getLibrary( 1 )
|
||||
io.vprint( 1, ' o Loading GDS library in "{}".'.format( ioLib.getName() ))
|
||||
Gds.load( ioLib
|
||||
, ndaTopDir + '/XXXX.gds'
|
||||
, Gds.NoGdsPrefix )
|
||||
|
||||
|
||||
def setup ( cellsTop ):
|
||||
_routing()
|
||||
_loadStdLib( cellsTop )
|
||||
#_loadIoLib()
|
|
@ -0,0 +1,318 @@
|
|||
|
||||
import sys
|
||||
import os.path
|
||||
from coriolis import Cfg, Hurricane, Viewer, CRL
|
||||
from coriolis.Hurricane import Technology, DataBase, DbU, Library, Layer, \
|
||||
BasicLayer, Cell, Net, Horizontal, Vertical, \
|
||||
Rectilinear, Box, Point, NetExternalComponents
|
||||
from coriolis.technos.common.colors import toRGB
|
||||
from coriolis.technos.common.patterns import toHexa
|
||||
from coriolis.helpers import l, u, trace, io
|
||||
from coriolis.helpers.technology import createBL, createVia, setEnclosures
|
||||
from coriolis.helpers.overlay import CfgCache
|
||||
|
||||
|
||||
__all__ = [ 'setup' ]
|
||||
|
||||
|
||||
def _setup_techno():
|
||||
io.vprint( 1, ' o Setup GF180MCU technology.' )
|
||||
io.vprint( 2, ' (__file__="{}")'.format( os.path.abspath( __file__ )))
|
||||
|
||||
db = DataBase.create()
|
||||
CRL.System.get()
|
||||
|
||||
tech = Technology.create( db, 'GF180MCU' )
|
||||
|
||||
DbU.setPrecision( 2 )
|
||||
DbU.setPhysicalsPerGrid( 0.005, DbU.UnitPowerMicro )
|
||||
with CfgCache(priority=Cfg.Parameter.Priority.ConfigurationFile) as cfg:
|
||||
cfg.gdsDriver.metricDbu = 1e-09
|
||||
cfg.gdsDriver.dbuPerUu = 0.001
|
||||
DbU.setGridsPerLambda ( 10 )
|
||||
DbU.setSymbolicSnapGridStep( DbU.fromGrid( 1.0 ))
|
||||
DbU.setPolygonStep ( DbU.fromGrid( 1.0 ))
|
||||
DbU.setStringMode ( DbU.StringModePhysical, DbU.UnitPowerMicro )
|
||||
|
||||
Nwell = createBL( tech, 'Nwell' , BasicLayer.Material.nWell , size=u(0.86), spacing=u(0.74), gds2Layer=21 )
|
||||
LVPwell = createBL( tech, 'LVPwell' , BasicLayer.Material.pWell , size=u(0.74), spacing=u(1.7 ), gds2Layer=204 )
|
||||
Nplus = createBL( tech, 'Nplus' , BasicLayer.Material.nImplant , size=u(0.4 ), spacing=u(0.4 ), gds2Layer=32 )
|
||||
Pplus = createBL( tech, 'Pplus' , BasicLayer.Material.pImplant , size=u(0.4 ), spacing=u(0.4 ), gds2Layer=31 )
|
||||
COMP = createBL( tech, 'COMP' , BasicLayer.Material.active , size=u(0.3 ), spacing=u(0.36), gds2Layer=22 )
|
||||
Poly2 = createBL( tech, 'Poly2' , BasicLayer.Material.poly , size=u(0.2 ), spacing=u(0.24), gds2Layer=30 )
|
||||
Cont = createBL( tech, 'Contact' , BasicLayer.Material.cut , size=u(0.22), spacing=u(0.25), gds2Layer=33 )
|
||||
Metal1 = createBL( tech, 'Metal1' , BasicLayer.Material.metal , size=u(0.23), spacing=u(0.23), gds2Layer=34 )
|
||||
Via1 = createBL( tech, 'Via1' , BasicLayer.Material.cut , size=u(0.26), spacing=u(0.26), gds2Layer=35 )
|
||||
Metal2 = createBL( tech, 'Metal2' , BasicLayer.Material.metal , size=u(0.28), spacing=u(0.28), gds2Layer=36 )
|
||||
Via2 = createBL( tech, 'Via2' , BasicLayer.Material.cut , size=u(0.26), spacing=u(0.26), gds2Layer=38 )
|
||||
Metal3 = createBL( tech, 'Metal3' , BasicLayer.Material.metal , size=u(0.28), spacing=u(0.28), gds2Layer=42 )
|
||||
Via3 = createBL( tech, 'Via3' , BasicLayer.Material.cut , size=u(0.26), spacing=u(0.26), gds2Layer=40 )
|
||||
Metal4 = createBL( tech, 'Metal4' , BasicLayer.Material.metal , size=u(0.28), spacing=u(0.28), gds2Layer=46 )
|
||||
Via4 = createBL( tech, 'Via4' , BasicLayer.Material.cut , size=u(0.26), spacing=u(0.26), gds2Layer=41 )
|
||||
Metal5 = createBL( tech, 'Metal5' , BasicLayer.Material.metal , size=u(0.28), spacing=u(0.28), gds2Layer=81 )
|
||||
Via5 = createBL( tech, 'Via5' , BasicLayer.Material.cut , size=u(0.26), spacing=u(0.26), gds2Layer=82 )
|
||||
MetalTop = createBL( tech, 'MetalTop', BasicLayer.Material.metal , size=u(0.36), spacing=u(0.38), gds2Layer=53 )
|
||||
|
||||
Poly2_Dummy = createBL( tech, 'Poly2_Dummy' , BasicLayer.Material.poly , gds2Layer=30, gds2DataType=4 )
|
||||
Metal1_Dummy = createBL( tech, 'Metal1_Dummy' , BasicLayer.Material.metal, gds2Layer=34, gds2DataType=4 )
|
||||
Metal2_Dummy = createBL( tech, 'Metal2_Dummy' , BasicLayer.Material.metal, gds2Layer=36, gds2DataType=4 )
|
||||
Metal3_Dummy = createBL( tech, 'Metal3_Dummy' , BasicLayer.Material.metal, gds2Layer=42, gds2DataType=4 )
|
||||
Metal4_Dummy = createBL( tech, 'Metal4_Dummy' , BasicLayer.Material.metal, gds2Layer=46, gds2DataType=4 )
|
||||
Metal5_Dummy = createBL( tech, 'Metal5_Dummy' , BasicLayer.Material.metal, gds2Layer=81, gds2DataType=4 )
|
||||
MetalTop_Dummy = createBL( tech, 'MetalTop_Dummy', BasicLayer.Material.metal, gds2Layer=53, gds2DataType=4 )
|
||||
|
||||
Poly2_Label = createBL( tech, 'Poly2_Label' , BasicLayer.Material.info, gds2Layer=30, gds2DataType=10 )
|
||||
Metal1_Label = createBL( tech, 'Metal1_Label' , BasicLayer.Material.info, gds2Layer=34, gds2DataType=10 )
|
||||
Metal2_Label = createBL( tech, 'Metal2_Label' , BasicLayer.Material.info, gds2Layer=36, gds2DataType=10 )
|
||||
Metal3_Label = createBL( tech, 'Metal3_Label' , BasicLayer.Material.info, gds2Layer=42, gds2DataType=10 )
|
||||
Metal4_Label = createBL( tech, 'Metal4_Label' , BasicLayer.Material.info, gds2Layer=46, gds2DataType=10 )
|
||||
Metal5_Label = createBL( tech, 'Metal5_Label' , BasicLayer.Material.info, gds2Layer=81, gds2DataType=10 )
|
||||
MetalTop_Label = createBL( tech, 'MetalTop_Label', BasicLayer.Material.info, gds2Layer=53, gds2DataType=10 )
|
||||
|
||||
Metal1_BLK = createBL( tech, 'Metal1_BLK' , BasicLayer.Material.blockage, gds2Layer=34, gds2DataType=5 )
|
||||
Metal2_BLK = createBL( tech, 'Metal2_BLK' , BasicLayer.Material.blockage, gds2Layer=36, gds2DataType=5 )
|
||||
Metal3_BLK = createBL( tech, 'Metal3_BLK' , BasicLayer.Material.blockage, gds2Layer=42, gds2DataType=5 )
|
||||
Metal4_BLK = createBL( tech, 'Metal4_BLK' , BasicLayer.Material.blockage, gds2Layer=46, gds2DataType=5 )
|
||||
Metal5_BLK = createBL( tech, 'Metal5_BLK' , BasicLayer.Material.blockage, gds2Layer=81, gds2DataType=5 )
|
||||
MetalTop_BLK = createBL( tech, 'MetalTop_BLK', BasicLayer.Material.blockage, gds2Layer=53, gds2DataType=5 )
|
||||
|
||||
CONT = createVia( tech, 'CONT_POLY2', 'Poly2', 'Contact', 'Metal1', u(0.22) )
|
||||
setEnclosures( CONT, Poly2 , u(0.07) )
|
||||
setEnclosures( CONT, Metal1, u(0.12) )
|
||||
VIA12 = createVia( tech, 'VIA12', 'Metal1', 'Via1', 'Metal2', u(0.26) )
|
||||
setEnclosures( VIA12, Metal1, (u(0.06), u(0.00)) )
|
||||
setEnclosures( VIA12, Metal2, (u(0.06), u(0.01)) )
|
||||
VIA23 = createVia( tech, 'VIA23', 'Metal2', 'Via2', 'Metal3', u(0.26) )
|
||||
setEnclosures( VIA23, Metal2, (u(0.06), u(0.01)) )
|
||||
setEnclosures( VIA23, Metal3, (u(0.01), u(0.06)) )
|
||||
VIA34 = createVia( tech, 'VIA34', 'Metal3', 'Via3', 'Metal4', u(0.26) )
|
||||
setEnclosures( VIA34, Metal3, (u(0.01), u(0.06)) )
|
||||
setEnclosures( VIA34, Metal4, (u(0.06), u(0.01)) )
|
||||
VIA45 = createVia( tech, 'VIA45', 'Metal4', 'Via4', 'Metal5', u(0.26) )
|
||||
setEnclosures( VIA45, Metal4, (u(0.06), u(0.01)) )
|
||||
setEnclosures( VIA45, Metal5, (u(0.01), u(0.06)) )
|
||||
VIA5T = createVia( tech, 'VIA5T', 'Metal5', 'Via5', 'MetalTop', u(0.26) )
|
||||
setEnclosures( VIA5T, Metal5 , (u(0.01), u(0.06)) )
|
||||
setEnclosures( VIA5T, MetalTop, (u(0.06), u(0.01)) )
|
||||
|
||||
Border = createBL( tech, 'Border', BasicLayer.Material.other, gds2Layer=63 )
|
||||
|
||||
Metal1 .setBlockageLayer( Metal1_BLK )
|
||||
Metal2 .setBlockageLayer( Metal2_BLK )
|
||||
Metal3 .setBlockageLayer( Metal3_BLK )
|
||||
Metal4 .setBlockageLayer( Metal4_BLK )
|
||||
Metal5 .setBlockageLayer( Metal5_BLK )
|
||||
MetalTop.setBlockageLayer( MetalTop_BLK )
|
||||
|
||||
# Coriolis internal layers
|
||||
createBL( tech, 'text.cell' , BasicLayer.Material.other )
|
||||
createBL( tech, 'text.instance', BasicLayer.Material.other )
|
||||
createBL( tech, 'SPL1' , BasicLayer.Material.other )
|
||||
createBL( tech, 'AutoLayer' , BasicLayer.Material.other )
|
||||
createBL( tech, 'gmetalh' , BasicLayer.Material.metal )
|
||||
createBL( tech, 'gcontact' , BasicLayer.Material.cut )
|
||||
createBL( tech, 'gmetalv' , BasicLayer.Material.metal )
|
||||
|
||||
|
||||
def _setup_display():
|
||||
# ----------------------------------------------------------------------
|
||||
# Style: Coriolis [black]
|
||||
|
||||
threshold = 0.2 if Viewer.Graphics.isHighDpi() else 0.1
|
||||
scale = 1.0
|
||||
|
||||
style = Viewer.DisplayStyle( 'Coriolis [black]' )
|
||||
style.setDescription( 'Coriolis Look - black background' )
|
||||
style.setDarkening ( Viewer.DisplayStyle.HSVr(1.0, 3.0, 2.5) )
|
||||
# Viewer.
|
||||
style.addDrawingStyle( group='Viewer', name='fallback' , color=toRGB('Gray238' ), border=1, pattern='55AA55AA55AA55AA' )
|
||||
style.addDrawingStyle( group='Viewer', name='background' , color=toRGB('Gray50' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='foreground' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='rubber' , color=toRGB('192,0,192' ), border=4, threshold=0.02 )
|
||||
style.addDrawingStyle( group='Viewer', name='phantom' , color=toRGB('Seashell4' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='boundaries' , color=toRGB('wheat1' ), border=2, pattern='0000000000000000', threshold=0 )
|
||||
style.addDrawingStyle( group='Viewer', name='marker' , color=toRGB('80,250,80' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionDraw' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionFill' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='grid' , color=toRGB('White' ), border=1, threshold=2.0 )
|
||||
style.addDrawingStyle( group='Viewer', name='spot' , color=toRGB('White' ), border=2, threshold=6.0 )
|
||||
style.addDrawingStyle( group='Viewer', name='ghost' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='text.ruler' , color=toRGB('White' ), border=1, threshold= 0.0 )
|
||||
style.addDrawingStyle( group='Viewer', name='text.instance' , color=toRGB('White' ), border=1, threshold=400.0 )
|
||||
style.addDrawingStyle( group='Viewer', name='text.reference', color=toRGB('White' ), border=1, threshold=200.0 )
|
||||
style.addDrawingStyle( group='Viewer', name='undef' , color=toRGB('Violet' ), border=0, pattern='2244118822441188' )
|
||||
style.addDrawingStyle( group='Viewer', name='Border' , color=toRGB('wheat1' ), border=1, pattern='0000000000000000', threshold=0 )
|
||||
|
||||
# Group: Active Layer.
|
||||
style.addDrawingStyle( group='Active Layer', name='Nwell' , color=toRGB('Tan' ), pattern='55AA55AA55AA55AA' , threshold=1.5 *scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='LVPwell' , color=toRGB('LightYellow'), pattern='55AA55AA55AA55AA' , threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='Nplus' , color=toRGB('LawnGreen' ), pattern='55AA55AA55AA55AA' , threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='Pplus' , color=toRGB('Yellow' ), pattern='55AA55AA55AA55AA' , threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='COMP' , color=toRGB('White' ), pattern=toHexa('antihash1.8'), threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='Poly2' , color=toRGB('Red' ), pattern='55AA55AA55AA55AA' , threshold=1.50*scale )
|
||||
|
||||
# Group: Routing Layer.
|
||||
style.addDrawingStyle( group='Routing Layer', name='Metal1' , color=toRGB('Blue' ), pattern=toHexa('poids2.8' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='Metal2' , color=toRGB('Aqua' ), pattern=toHexa('light_antihash0.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='Metal3' , color=toRGB('LightPink'), pattern=toHexa('light_antihash1.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='Metal4' , color=toRGB('Green' ), pattern=toHexa('light_antihash2.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='Metal5' , color=toRGB('Yellow' ), pattern='1144114411441144' , threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='MetalTop', color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.02*scale )
|
||||
|
||||
# Group: Cuts (VIA holes).
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Contact', color=toRGB('0,150,150'), threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via1' , color=toRGB('Aqua' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via2' , color=toRGB('LightPink'), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via3' , color=toRGB('Green' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via4' , color=toRGB('Yellow' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via5' , color=toRGB('Violet' ), threshold=0.80*scale )
|
||||
|
||||
# Group: Fillers.
|
||||
style.addDrawingStyle( group='Fillers', name='Poly2_Dummy' , color=toRGB('Red' ), pattern='55AA55AA55AA55AA' , border=0, threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal1_Dummy' , color=toRGB('Blue' ), pattern=toHexa('poids2.8' ), border=0, threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal2_Dummy' , color=toRGB('Aqua' ), pattern=toHexa('light_antihash0.8'), border=0, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal3_Dummy' , color=toRGB('LightPink'), pattern=toHexa('light_antihash1.8'), border=0, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal4_Dummy' , color=toRGB('Green' ), pattern=toHexa('light_antihash2.8'), border=0, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal5_Dummy' , color=toRGB('Yellow' ), pattern='1144114411441144' , border=0, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='MetalTop_Dummy', color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), border=0, threshold=0.02*scale )
|
||||
|
||||
# Group: Blockages.
|
||||
style.addDrawingStyle( group='Blockages', name='Metal1_BLK' , color=toRGB('Blue' ), pattern='006070381c0e0703' , threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='Metal2_BLK' , color=toRGB('Aqua' ), pattern='8103060c183060c0' , threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='Metal3_BLK' , color=toRGB('LightPink'), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='Metal4_BLK' , color=toRGB('Green' ), pattern=toHexa('light_antihash2.8'), threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='Metal5_BLK' , color=toRGB('Yellow' ), pattern='1144114411441144' , threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='MetalTop_BLK', color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.80*scale, border=2 )
|
||||
|
||||
# Group: Text.
|
||||
style.addDrawingStyle( group='Text', name='Poly2_Label' , color=toRGB('Red' ), pattern='55AA55AA55AA55AA' , threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Text', name='Metal1_Label' , color=toRGB('Blue' ), pattern=toHexa('poids2.8' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Text', name='Metal2_Label' , color=toRGB('Aqua' ), pattern=toHexa('light_antihash0.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Text', name='Metal3_Label' , color=toRGB('LightPink'), pattern=toHexa('light_antihash1.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Text', name='Metal4_Label' , color=toRGB('Green' ), pattern=toHexa('light_antihash2.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Text', name='Metal5_Label' , color=toRGB('Yellow' ), pattern='1144114411441144' , threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Text', name='MetalTop_Label', color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.02*scale )
|
||||
|
||||
# Knick & Kite.
|
||||
style.addDrawingStyle( group='Knik & Kite', name='SPL1' , color=toRGB('Red' ) )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='AutoLayer' , color=toRGB('Magenta' ) )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gmetalh' , color=toRGB('128,255,200'), pattern=toHexa('antislash2.32' ), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gmetalv' , color=toRGB('200,200,255'), pattern=toHexa('light_antihash1.8'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gcontact' , color=toRGB('255,255,190'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='Anabatic::Edge' , color=toRGB('255,255,190'), pattern='0000000000000000' , border=4, threshold=0.02 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='Anabatic::GCell', color=toRGB('255,255,190'), pattern='0000000000000000' , border=2, threshold=threshold )
|
||||
|
||||
Viewer.Graphics.addStyle( style )
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Style: Alliance.Classic [white].
|
||||
|
||||
style = Viewer.DisplayStyle( 'Coriolis [white]' )
|
||||
style.inheritFrom( 'Coriolis [black]' )
|
||||
style.setDescription ( 'Coriolis Look - white background' )
|
||||
style.setDarkening ( Viewer.DisplayStyle.HSVr(1.0, 3.0, 2.5) )
|
||||
style.addDrawingStyle( group='Viewer', name='background', color=toRGB('White'), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='foreground', color=toRGB('Black'), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='boundaries', color=toRGB('Black'), border=1, pattern='0000000000000000' )
|
||||
Viewer.Graphics.addStyle( style )
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Style: Alliance.Classic [black]
|
||||
|
||||
style = Viewer.DisplayStyle( 'Alliance.Classic [black]' )
|
||||
style.setDescription( 'Alliance Classic Look - black background' )
|
||||
style.setDarkening ( Viewer.DisplayStyle.HSVr(1.0, 3.0, 2.5) )
|
||||
|
||||
# Viewer.
|
||||
style.addDrawingStyle( group='Viewer', name='fallback' , color=toRGB('Gray238' ), border=1, pattern='55AA55AA55AA55AA' )
|
||||
style.addDrawingStyle( group='Viewer', name='background' , color=toRGB('Gray50' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='foreground' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='rubber' , color=toRGB('192,0,192' ), border=4, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='phantom' , color=toRGB('Seashell4' ), border=1 )
|
||||
#style.addDrawingStyle( group='Viewer', name='boundaries' , color=toRGB('208,199,192'), border=2, threshold=0 )
|
||||
style.addDrawingStyle( group='Viewer', name='boundaries' , color=toRGB('wheat1') , border=2, pattern='0000000000000000', threshold=0 )
|
||||
style.addDrawingStyle( group='Viewer', name='marker' , color=toRGB('80,250,80' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionDraw' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionFill' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='grid' , color=toRGB('White' ), border=1, threshold=8.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='spot' , color=toRGB('White' ), border=2, threshold=6.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='ghost' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='text.ruler' , color=toRGB('White' ), border=1, threshold= 0.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='text.instance' , color=toRGB('White' ), border=1, threshold=400.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='text.reference', color=toRGB('White' ), border=1, threshold=200.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='undef' , color=toRGB('Violet' ), border=0, pattern='2244118822441188' )
|
||||
style.addDrawingStyle( group='Viewer', name='Border' , color=toRGB('wheat1' ), border=1, pattern='0000000000000000', threshold=0 )
|
||||
|
||||
# Active Layers.
|
||||
style.addDrawingStyle( group='Active Layers', name='Nwell' , color=toRGB('Tan' ), pattern=toHexa('urgo.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='LVPwell' , color=toRGB('LightYellow'), pattern=toHexa('urgo.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='Nplus' , color=toRGB('LawnGreen' ), pattern=toHexa('antihash0.8'), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='Pplus' , color=toRGB('Yellow' ), pattern=toHexa('antihash0.8'), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='COMP' , color=toRGB('White' ), pattern=toHexa('antihash1.8'), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='Poly2' , color=toRGB('Red' ), pattern=toHexa('poids2.8' ), border=1, threshold=0.00*scale )
|
||||
|
||||
# Routing Layers.
|
||||
style.addDrawingStyle( group='Routing Layers', name='Metal1' , color=toRGB('Blue' ), pattern=toHexa('slash.8' ), border=1, threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='Metal2' , color=toRGB('Aqua' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='Metal3' , color=toRGB('LightPink' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='Metal4' , color=toRGB('Green' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='Metal5' , color=toRGB('Yellow' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='MetalTop', color=toRGB('Violet' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
|
||||
# Cuts (VIA holes).
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Contact', color=toRGB('0,150,150'), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via1' , color=toRGB('Aqua' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via2' , color=toRGB('LightPink'), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via3' , color=toRGB('Green' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via4' , color=toRGB('Yellow' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via5' , color=toRGB('Violet' ), threshold=0.0*scale )
|
||||
|
||||
# Fillers.
|
||||
style.addDrawingStyle( group='Fillers', name='Poly2_Dummy' , color=toRGB('Red' ), pattern=toHexa('poids2.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal1_Dummy' , color=toRGB('Blue' ), pattern=toHexa('slash.8' ), border=0, threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal2_Dummy' , color=toRGB('Aqua' ), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal3_Dummy' , color=toRGB('LightPink'), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal4_Dummy' , color=toRGB('Green' ), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal5_Dummy' , color=toRGB('Yellow' ), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='MetalTop_Dummy', color=toRGB('Violet' ), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
|
||||
# Labels.
|
||||
style.addDrawingStyle( group='Labels', name='Poly2_Label' , color=toRGB('Red' ), pattern=toHexa('poids2.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Labels', name='Metal1_Label' , color=toRGB('Blue' ), pattern=toHexa('slash.8' ), border=0, threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Labels', name='Metal2_Label' , color=toRGB('Aqua' ), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Labels', name='Metal3_Label' , color=toRGB('LightPink'), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Labels', name='Metal4_Label' , color=toRGB('Green' ), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Labels', name='Metal5_Label' , color=toRGB('Yellow' ), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Labels', name='MetalTop_Label', color=toRGB('Violet' ), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
|
||||
# Blockages.
|
||||
style.addDrawingStyle( group='Blockages', name='Metal1_BLK' , color=toRGB('Blue' ), pattern=toHexa('light_antislash0.8'), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='Metal2_BLK' , color=toRGB('Aqua' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='Metal3_BLK' , color=toRGB('LightPink'), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='Metal4_BLK' , color=toRGB('Green' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='Metal5_BLK' , color=toRGB('Yellow' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='MetalTop_BLK', color=toRGB('Violet' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
|
||||
# Knick & Kite.
|
||||
style.addDrawingStyle( group='Knik & Kite', name='SPL1' , color=toRGB('Red' ) )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='AutoLayer' , color=toRGB('Magenta' ) )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gcontact' , color=toRGB('255,255,190'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gmetalh' , color=toRGB('128,255,200'), pattern=toHexa('antislash2.32' ), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gmetalv' , color=toRGB('200,200,255'), pattern=toHexa('light_antihash1.8'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gcut' , color=toRGB('255,255,190'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='Anabatic::Edge' , color=toRGB('255,255,190'), pattern='0000000000000000' , border=4, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='Anabatic::GCell', color=toRGB('255,255,190'), pattern='0000000000000000' , border=2, threshold=0.10*scale )
|
||||
|
||||
Viewer.Graphics.addStyle( style )
|
||||
Viewer.Graphics.setStyle( 'Alliance.Classic [black]' )
|
||||
|
||||
|
||||
def setup():
|
||||
_setup_techno()
|
||||
_setup_display()
|
||||
try:
|
||||
from .techno_fix import fix
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
fix()
|
|
@ -43,6 +43,7 @@ env.setGROUND ( 'vss' )
|
|||
env.setCLOCK ( '.*ck.*|.*nck.*' )
|
||||
env.setBLOCKAGE ( 'blockage[Nn]et.*' )
|
||||
env.setPad ( '.*_px$' )
|
||||
env.setRegister ( 'sff.*' )
|
||||
|
||||
env.setWORKING_LIBRARY( '.' )
|
||||
env.addSYSTEM_LIBRARY ( library=cellsTop+'/sxlib' , mode=Environment.Append )
|
||||
|
|
|
@ -43,6 +43,7 @@ env.setGROUND ( 'vss' )
|
|||
env.setCLOCK ( '.*ck.*|.*nck.*' )
|
||||
env.setBLOCKAGE ( 'blockage[Nn]et.*' )
|
||||
env.setPad ( '.*_mpx$' )
|
||||
env.setRegister ( 'sff.*' )
|
||||
|
||||
env.setWORKING_LIBRARY( '.' )
|
||||
env.addSYSTEM_LIBRARY ( library=cellsTop+'/nsxlib', mode=Environment.Append )
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) Sorbonne Université 2019-2023, All Rights Reserved
|
||||
#
|
||||
# +-----------------------------------------------------------------+
|
||||
# | C O R I O L I S |
|
||||
# | Alliance / Hurricane Interface |
|
||||
# | |
|
||||
# | Author : Jean-Paul CHAPUT |
|
||||
# | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
# | =============================================================== |
|
||||
# | Python : "./etc/symbolic/lcmos/__init__.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
import coriolis.Cfg as Cfg
|
||||
from coriolis.helpers import truncPath, tagConfModules
|
||||
from coriolis.helpers.io import vprint
|
||||
vprint( 1, ' o Loading "symbolic.lcmos" technology.' )
|
||||
vprint( 2, ' - "%s".' % truncPath(__file__) )
|
||||
|
||||
from coriolis.Hurricane import DataBase
|
||||
from coriolis.CRL import System
|
||||
|
||||
Cfg.Configuration.pushDefaultPriority( Cfg.Parameter.Priority.ConfigurationFile )
|
||||
|
||||
if not DataBase.getDB(): DataBase.create()
|
||||
System.get()
|
||||
|
||||
from . import misc
|
||||
from . import technology
|
||||
from . import display
|
||||
from . import analog
|
||||
from . import alliance
|
||||
from . import etesian
|
||||
from . import kite
|
||||
from . import plugins
|
||||
from . import stratus1
|
||||
|
||||
Cfg.Configuration.popDefaultPriority()
|
||||
|
||||
tagConfModules()
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) Sorbonne Université 2019-2023, All Rights Reserved
|
||||
#
|
||||
# +-----------------------------------------------------------------+
|
||||
# | C O R I O L I S |
|
||||
# | Alliance / Hurricane Interface |
|
||||
# | |
|
||||
# | Author : Jean-Paul CHAPUT |
|
||||
# | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
# | =============================================================== |
|
||||
# | Python : "./etc/symbolic/lcmos/alliance.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
import os
|
||||
import os.path
|
||||
from coriolis.helpers import truncPath
|
||||
from coriolis.helpers.io import vprint
|
||||
vprint( 2, ' - "{}".'.format(truncPath(__file__)) )
|
||||
|
||||
from coriolis.CRL import Environment, AllianceFramework
|
||||
|
||||
allianceTop = None
|
||||
if 'ALLIANCE_TOP' in os.environ:
|
||||
allianceTop = os.environ['ALLIANCE_TOP']
|
||||
if not os.path.isdir(allianceTop):
|
||||
allianceTop = None
|
||||
if not allianceTop: allianceTop = '/soc/alliance'
|
||||
|
||||
cellsTop = allianceTop+'/cells'
|
||||
af = AllianceFramework.get()
|
||||
env = af.getEnvironment()
|
||||
|
||||
env.setSCALE_X ( 100 )
|
||||
env.setCATALOG ( 'CATAL' )
|
||||
env.setIN_LO ( 'vst' )
|
||||
env.setIN_PH ( 'ap' )
|
||||
env.setOUT_LO ( 'vst' )
|
||||
env.setOUT_PH ( 'ap' )
|
||||
env.setPOWER ( 'vdd' )
|
||||
env.setGROUND ( 'vss' )
|
||||
env.setCLOCK ( '.*ck.*|.*nck.*' )
|
||||
env.setBLOCKAGE ( 'blockage[Nn]et.*' )
|
||||
env.setPad ( '.*_px$' )
|
||||
env.setRegister ( 'sff.*' )
|
||||
|
||||
env.setWORKING_LIBRARY( '.' )
|
||||
env.addSYSTEM_LIBRARY ( library=cellsTop+'/sxlib' , mode=Environment.Append )
|
||||
env.addSYSTEM_LIBRARY ( library=cellsTop+'/dp_sxlib', mode=Environment.Append )
|
||||
env.addSYSTEM_LIBRARY ( library=cellsTop+'/ramlib' , mode=Environment.Append )
|
||||
env.addSYSTEM_LIBRARY ( library=cellsTop+'/romlib' , mode=Environment.Append )
|
||||
env.addSYSTEM_LIBRARY ( library=cellsTop+'/rflib' , mode=Environment.Append )
|
||||
env.addSYSTEM_LIBRARY ( library=cellsTop+'/rf2lib' , mode=Environment.Append )
|
||||
env.addSYSTEM_LIBRARY ( library=cellsTop+'/pxlib' , mode=Environment.Append )
|
||||
env.addSYSTEM_LIBRARY ( library=cellsTop+'/padlib' , mode=Environment.Append )
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) Sorbonne Université 2019-2023, All Rights Reserved
|
||||
#
|
||||
# +-----------------------------------------------------------------+
|
||||
# | C O R I O L I S |
|
||||
# | Alliance / Hurricane Interface |
|
||||
# | |
|
||||
# | Author : Jean-Paul CHAPUT |
|
||||
# | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
# | =============================================================== |
|
||||
# | Python : "./etc/symbolic/lcmos/analog.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
from coriolis.helpers import truncPath
|
||||
from coriolis.helpers.io import vprint
|
||||
vprint( 2, ' - "%s".' % truncPath(__file__) )
|
||||
|
||||
from ...common import analog
|
|
@ -0,0 +1,474 @@
|
|||
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) Sorbonne Université 2019-2023, All Rights Reserved
|
||||
#
|
||||
# +-----------------------------------------------------------------+
|
||||
# | C O R I O L I S |
|
||||
# | Alliance / Hurricane Interface |
|
||||
# | |
|
||||
# | Author : Jean-Paul CHAPUT |
|
||||
# | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
# | =============================================================== |
|
||||
# | Python : "./etc/symbolic/lcmos/display.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
from coriolis.helpers import truncPath
|
||||
from coriolis.helpers.io import vprint
|
||||
import coriolis.Cfg as Cfg
|
||||
import coriolis.Viewer as Viewer
|
||||
from coriolis.helpers import overlay, l, u, n
|
||||
from coriolis.technos.common.colors import toRGB
|
||||
from coriolis.technos.common.patterns import toHexa
|
||||
vprint( 2, ' - "%s".' % truncPath(__file__) )
|
||||
|
||||
|
||||
def createStyles ( scale=1.0 ):
|
||||
with overlay.CfgCache(priority=Cfg.Parameter.Priority.UserFile) as cfg:
|
||||
cfg.viewer.minimumSize = 500
|
||||
cfg.viewer.pixelThreshold = 5
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Style: Alliance.Coriolis [black].
|
||||
|
||||
style = Viewer.DisplayStyle( 'Alliance.Coriolis [black]' )
|
||||
style.setDescription( 'Alliance Coriolis Look - black background' )
|
||||
style.setDarkening ( Viewer.DisplayStyle.HSVr(1.0, 3.0, 2.5) )
|
||||
|
||||
style.addDrawingStyle( group='Viewer', name='fallback' , color=toRGB('Gray238' ), border=1, pattern='55AA55AA55AA55AA' )
|
||||
style.addDrawingStyle( group='Viewer', name='background' , color=toRGB('Gray50' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='foreground' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='rubber' , color=toRGB('192,0,192' ), border=2, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='phantom' , color=toRGB('Seashell4' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='boundaries' , color=toRGB('208,199,192'), border=1, pattern='0000000000000000', threshold=0 )
|
||||
style.addDrawingStyle( group='Viewer', name='marker' , color=toRGB('80,250,80' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionDraw' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionFill' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='grid' , color=toRGB('White' ), border=1, threshold=2.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='spot' , color=toRGB('White' ), border=2, threshold=6.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='ghost' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='text.ruler' , color=toRGB('White' ), border=1, threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='text.instance' , color=toRGB('Black' ), border=1, threshold=4.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='text.reference' , color=toRGB('White' ), border=1, threshold=20.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='undef' , color=toRGB('Violet' ), border=0, pattern='2244118822441188' )
|
||||
style.addDrawingStyle( group='Viewer', name='mauka.container', color=toRGB('Magenta4' ), border=4, pattern='0000000000000000', goMatched=False )
|
||||
|
||||
# Group: Active Layer.
|
||||
style.addDrawingStyle( group='Active Layer', name='nWell' , color=toRGB('Tan' ), pattern='55AA55AA55AA55AA' , threshold=1.5 *scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='pWell' , color=toRGB('LightYellow'), pattern='55AA55AA55AA55AA' , threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='nImplant', color=toRGB('LawnGreen' ), pattern='55AA55AA55AA55AA' , threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='pImplant', color=toRGB('Yellow' ), pattern='55AA55AA55AA55AA' , threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='active' , color=toRGB('White' ), pattern=toHexa('antihash1.8'), threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='poly' , color=toRGB('Red' ), pattern='55AA55AA55AA55AA' , threshold=1.50*scale )
|
||||
|
||||
# Group: Routing Layer.
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal1' , color=toRGB('Blue' ), pattern=toHexa('poids2.8' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal2' , color=toRGB('Aqua' ), pattern=toHexa('light_antihash0.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal3' , color=toRGB('LightPink'), pattern=toHexa('light_antihash1.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal4' , color=toRGB('Green' ), pattern=toHexa('light_antihash2.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal5' , color=toRGB('Yellow' ), pattern='1144114411441144' , threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal6' , color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal7' , color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal8' , color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal9' , color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal10', color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.02*scale )
|
||||
|
||||
# Group: Cuts (VIA holes).
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut0', color=toRGB('0,150,150'), threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut1', color=toRGB('Aqua' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut2', color=toRGB('LightPink'), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut3', color=toRGB('Green' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut4', color=toRGB('Yellow' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut5', color=toRGB('Violet' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut6', color=toRGB('Violet' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut7', color=toRGB('Violet' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut8', color=toRGB('Violet' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut9', color=toRGB('Violet' ), threshold=0.80*scale )
|
||||
|
||||
# Group: MIM6.
|
||||
style.addDrawingStyle( group='MIM6', name='metbot_r', color=toRGB('Aqua' ), pattern=toHexa('light_antihash0.8'), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='MIM6', name='cut6' , color=toRGB('LightPink'), pattern=toHexa('light_antihash1.8'), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='MIM6', name='metal7' , color=toRGB('Green' ), pattern=toHexa('light_antihash2.8'), threshold=0.80*scale )
|
||||
|
||||
# Group: Blockages.
|
||||
style.addDrawingStyle( group='Blockages', name='blockage1' , color=toRGB('Blue' ), pattern='006070381c0e0703' , threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage2' , color=toRGB('Aqua' ), pattern='8103060c183060c0' , threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage3' , color=toRGB('LightPink'), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage4' , color=toRGB('Green' ), pattern=toHexa('light_antihash2.8'), threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage5' , color=toRGB('Yellow' ), pattern='1144114411441144' , threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage6' , color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage7' , color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage8' , color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage9' , color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage10', color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.80*scale, border=2 )
|
||||
|
||||
# Group: Knik & Kite.
|
||||
style.addDrawingStyle( group='Knik & Kite', name='SPL1' , color=toRGB('Red' ) )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='AutoLayer' , color=toRGB('Magenta' ) )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gmetalh' , color=toRGB('128,255,200'), pattern=toHexa('light_antihash0.8'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gmetalv' , color=toRGB('200,200,255'), pattern=toHexa('light_antihash1.8'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gcut' , color=toRGB('255,255,190'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='Anabatic::Edge' , color=toRGB('255,255,190'), pattern='0000000000000000', threshold=0.02*scale, border=4 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='Anabatic::GCell', color=toRGB('255,0,0' ), pattern='0000000000000000', threshold=0.02*scale, border=4 )
|
||||
|
||||
Viewer.Graphics.addStyle( style )
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Style: Alliance.Coriolis [white].
|
||||
|
||||
style = Viewer.DisplayStyle( 'Alliance.Coriolis [white]' )
|
||||
style.inheritFrom( 'Alliance.Coriolis [black]' )
|
||||
style.setDescription( 'Alliance Coriolis Look - white background' )
|
||||
style.setDarkening ( Viewer.DisplayStyle.HSVr(1.0, 3.0, 2.5) )
|
||||
|
||||
style.addDrawingStyle( group='Viewer', name='fallback' , color=toRGB('Gray238' ), border=1, pattern='55AA55AA55AA55AA' )
|
||||
style.addDrawingStyle( group='Viewer', name='background' , color=toRGB('Gray50' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='foreground' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='rubber' , color=toRGB('192,0,192' ), border=4, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='phantom' , color=toRGB('Seashell4' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='boundaries' , color=toRGB('208,199,192'), border=1, pattern='0000000000000000', threshold=0 )
|
||||
style.addDrawingStyle( group='Viewer', name='marker' , color=toRGB('80,250,80' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionDraw' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionFill' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='grid' , color=toRGB('White' ), border=1, threshold=2.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='spot' , color=toRGB('White' ), border=2, threshold=6.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='ghost' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='text.ruler' , color=toRGB('White' ), border=1, threshold=0.0 *scale )
|
||||
style.addDrawingStyle( group='Viewer', name='text.instance' , color=toRGB('White' ), border=1, threshold=400.0 *scale )
|
||||
style.addDrawingStyle( group='Viewer', name='text.reference', color=toRGB('White' ), border=1, threshold=200.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='undef' , color=toRGB('Violet' ), border=0, pattern='2244118822441188' )
|
||||
|
||||
# Active Layers.
|
||||
style.addDrawingStyle( group='Active Layer', name='nWell' , color=toRGB('Tan' ), pattern=toHexa('urgo.8' ), border=1, threshold=0*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='pWell' , color=toRGB('LightYellow'), pattern=toHexa('urgo.8' ), border=1, threshold=0*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='nImplant', color=toRGB('LawnGreen' ), pattern=toHexa('antihash0.8'), border=1, threshold=0*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='pImplant', color=toRGB('Yellow' ), pattern=toHexa('antihash0.8'), border=1, threshold=0*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='active' , color=toRGB('White' ), pattern=toHexa('antihash1.8'), border=1, threshold=0*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='poly' , color=toRGB('Red' ), pattern=toHexa('poids2.8' ), border=1, threshold=0*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='poly2' , color=toRGB('Orange' ), pattern=toHexa('poids2.8' ), border=1, threshold=0*scale )
|
||||
|
||||
# Routing Layers.
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal1' , color=toRGB('Blue' ), pattern=toHexa('slash.8' ), border=1, threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal2' , color=toRGB('Aqua' ), pattern=toHexa('poids4.8'), border=1, threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metcap' , color=toRGB('DarkTurquoise'), pattern=toHexa('poids2.8'), border=2, threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal3' , color=toRGB('LightPink' ), pattern=toHexa('poids4.8'), border=1, threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal4' , color=toRGB('Green' ), pattern=toHexa('poids4.8'), border=1, threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal5' , color=toRGB('Yellow' ), pattern=toHexa('poids4.8'), border=1, threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal6' , color=toRGB('Violet' ), pattern=toHexa('poids4.8'), border=1, threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal7' , color=toRGB('Red' ), pattern=toHexa('poids4.8'), border=1, threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal8' , color=toRGB('Blue' ), pattern=toHexa('poids4.8'), border=1, threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal9' , color=toRGB('Blue' ), pattern=toHexa('poids4.8'), border=1, threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='metal10', color=toRGB('Blue' ), pattern=toHexa('poids4.8'), border=1, threshold=0.0*scale )
|
||||
|
||||
|
||||
# Cuts (VIA holes).
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut0', color=toRGB('0,150,150'), threshold=0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut1', color=toRGB('Aqua' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut2', color=toRGB('LightPink'), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut3', color=toRGB('Green' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut4', color=toRGB('Yellow' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut5', color=toRGB('Violet' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut6', color=toRGB('Red' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut7', color=toRGB('Blue' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut8', color=toRGB('Blue' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut9', color=toRGB('Blue' ), threshold=0.0*scale )
|
||||
|
||||
# MIM6.
|
||||
style.addDrawingStyle( group='MIM6', name='metbot_r', color=toRGB('Aqua' ), pattern=toHexa('light_antihash0.8'), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='MIM6', name='metal7' , color=toRGB('Green'), pattern=toHexa('light_antihash2.8'), threshold=0.80*scale )
|
||||
|
||||
# Blockages.
|
||||
style.addDrawingStyle( group='Blockages', name='blockage1' , color=toRGB('Blue' ), pattern=toHexa('light_antislash0.8'), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage2' , color=toRGB('Aqua' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage3' , color=toRGB('LightPink'), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage4' , color=toRGB('Green' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage5' , color=toRGB('Yellow' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage6' , color=toRGB('Violet' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage7' , color=toRGB('Red' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage8' , color=toRGB('Blue' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage9' , color=toRGB('Blue' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage10', color=toRGB('Blue' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
|
||||
# Knick & Kite.
|
||||
style.addDrawingStyle( group='Knik & Kite', name='SPL1' , color=toRGB('Red' ) )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='AutoLayer' , color=toRGB('Magenta' ) )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gmetalh' , color=toRGB('128,255,200'), pattern=toHexa('antislash2.32' ), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gmetalv' , color=toRGB('200,200,255'), pattern=toHexa('light_antihash1.8'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gcut' , color=toRGB('255,255,190'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='Anabatic::Edge' , color=toRGB('255,255,190'), pattern='0000000000000000', border=4, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='Anabatic::GCell', color=toRGB('255,255,190'), pattern='0000000000000000', border=2, threshold=0.10*scale )
|
||||
|
||||
Viewer.Graphics.addStyle( style )
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Style: Alliance.Classic [black]
|
||||
|
||||
style = Viewer.DisplayStyle( 'Alliance.Classic [black]' )
|
||||
style.setDescription( 'Alliance Classic Look - black background' )
|
||||
style.setDarkening ( Viewer.DisplayStyle.HSVr(1.0, 3.0, 2.5) )
|
||||
|
||||
# Viewer.
|
||||
style.addDrawingStyle( group='Viewer', name='fallback' , color=toRGB('Gray238' ), border=1, pattern='55AA55AA55AA55AA' )
|
||||
style.addDrawingStyle( group='Viewer', name='background' , color=toRGB('Gray50' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='foreground' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='rubber' , color=toRGB('192,0,192' ), border=4, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='phantom' , color=toRGB('Seashell4' ), border=1 )
|
||||
#style.addDrawingStyle( group='Viewer', name='boundaries' , color=toRGB('208,199,192'), border=2, threshold=0 )
|
||||
style.addDrawingStyle( group='Viewer', name='boundaries' , color=toRGB('wheat1') , border=2, pattern='0000000000000000', threshold=0 )
|
||||
style.addDrawingStyle( group='Viewer', name='marker' , color=toRGB('80,250,80' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionDraw' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionFill' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='grid' , color=toRGB('White' ), border=1, threshold=8.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='spot' , color=toRGB('White' ), border=2, threshold=6.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='ghost' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='text.ruler' , color=toRGB('White' ), border=1, threshold= 0.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='text.instance' , color=toRGB('White' ), border=1, threshold=400.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='text.reference', color=toRGB('White' ), border=1, threshold=200.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='undef' , color=toRGB('Violet' ), border=0, pattern='2244118822441188' )
|
||||
|
||||
# Active Layers.
|
||||
style.addDrawingStyle( group='Active Layers', name='nWell' , color=toRGB('Tan' ), pattern=toHexa('urgo.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='pWell' , color=toRGB('LightYellow'), pattern=toHexa('urgo.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='nImplant', color=toRGB('LawnGreen' ), pattern=toHexa('antihash0.8'), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='pImplant', color=toRGB('Yellow' ), pattern=toHexa('antihash0.8'), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='active' , color=toRGB('White' ), pattern='0000000000000000' , border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='poly' , color=toRGB('Red' ), pattern=toHexa('poids2.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='poly2' , color=toRGB('Orange' ), pattern=toHexa('poids2.8' ), border=1, threshold=0.00*scale )
|
||||
|
||||
# Routing Layers.
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal1' , color=toRGB('Blue' ), pattern=toHexa('slash.8' ), border=1, threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal2' , color=toRGB('Aqua' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metcap' , color=toRGB('DarkTurquoise'), pattern=toHexa('poids2.8' ), border=2, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal3' , color=toRGB('LightPink' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal4' , color=toRGB('Green' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal5' , color=toRGB('Yellow' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal6' , color=toRGB('Violet' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal7' , color=toRGB('Red' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal8' , color=toRGB('Blue' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal9' , color=toRGB('Blue' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal10', color=toRGB('Blue' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
|
||||
# Cuts (VIA holes).
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut0', color=toRGB('0,150,150'), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut1', color=toRGB('Aqua' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut2', color=toRGB('LightPink'), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut3', color=toRGB('Green' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut4', color=toRGB('Yellow' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut5', color=toRGB('Violet' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut6', color=toRGB('Red' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut7', color=toRGB('Blue' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut8', color=toRGB('Blue' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut9', color=toRGB('Blue' ), threshold=0.0*scale )
|
||||
|
||||
# MIM6.
|
||||
style.addDrawingStyle( group='MIMI6', name='metbot_r', color=toRGB('Aqua' ), pattern=toHexa('light_antihash0.8'), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='MIMI6', name='metal7' , color=toRGB('Green'), pattern=toHexa('light_antihash2.8'), threshold=0.80*scale )
|
||||
|
||||
# Blockages.
|
||||
style.addDrawingStyle( group='Blockages', name='blockage1' , color=toRGB('Blue' ), pattern=toHexa('light_antislash0.8'), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage2' , color=toRGB('Aqua' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage3' , color=toRGB('LightPink'), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage4' , color=toRGB('Green' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage5' , color=toRGB('Yellow' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage6' , color=toRGB('Violet' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage7' , color=toRGB('Red' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage8' , color=toRGB('Blue' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage9' , color=toRGB('Blue' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage10', color=toRGB('Blue' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
|
||||
# Knick & Kite.
|
||||
style.addDrawingStyle( group='Knik & Kite', name='SPL1' , color=toRGB('Red' ) )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='AutoLayer' , color=toRGB('Magenta' ) )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gmetalh' , color=toRGB('128,255,200'), pattern=toHexa('antislash2.32' ), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gmetalv' , color=toRGB('200,200,255'), pattern=toHexa('light_antihash1.8'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gcut' , color=toRGB('255,255,190'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='Anabatic::Edge' , color=toRGB('255,255,190'), pattern='0000000000000000' , border=4, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='Anabatic::GCell', color=toRGB('255,255,190'), pattern='0000000000000000' , border=2, threshold=0.10*scale )
|
||||
|
||||
Viewer.Graphics.addStyle( style )
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Style: Alliance.Classic [white].
|
||||
|
||||
style = Viewer.DisplayStyle( 'Alliance.Classic [white]' )
|
||||
style.inheritFrom( 'Alliance.Classic [black]' )
|
||||
style.setDescription( 'Alliance Classic Look - white background' )
|
||||
style.setDarkening ( Viewer.DisplayStyle.HSVr(1.0, 3.0, 2.5) )
|
||||
|
||||
# Group: Viewer.
|
||||
style.addDrawingStyle( group='Viewer', name='fallback' , color=toRGB('Black'), border=1, pattern='55AA55AA55AA55AA' )
|
||||
style.addDrawingStyle( group='Viewer', name='background' , color=toRGB('White'), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='foreground' , color=toRGB('Black'), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionDraw' , color=toRGB('Black'), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionFill' , color=toRGB('Black'), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='grid' , color=toRGB('Black'), border=1, threshold=6.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='spot' , color=toRGB('Black'), border=1, threshold=6.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='ghost' , color=toRGB('Black'), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='text.ruler' , color=toRGB('Black'), border=1, threshold=0.0 *scale )
|
||||
style.addDrawingStyle( group='Viewer', name='text.instance' , color=toRGB('Black'), border=1, threshold=4.0 *scale )
|
||||
style.addDrawingStyle( group='Viewer', name='text.reference', color=toRGB('Black'), border=1, threshold=20.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='undef' , color=toRGB('Black'), border=0, pattern='2244118822441188' )
|
||||
|
||||
Viewer.Graphics.addStyle( style )
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Style: Layout Design [black]
|
||||
|
||||
style = Viewer.DisplayStyle( 'Layout Design [black]' )
|
||||
style.inheritFrom( 'Alliance.Classic [black]' )
|
||||
style.setDescription( 'Alliance Classic Look - white background' )
|
||||
style.setDarkening ( Viewer.DisplayStyle.HSVr(1.0, 3.0, 2.5) )
|
||||
|
||||
# Active Layers.
|
||||
style.addDrawingStyle( group='Active Layers', name='nWell' , color=toRGB('Tan' ), pattern='0000000000000000', threshold=1.50*scale, border=2 )
|
||||
style.addDrawingStyle( group='Active Layers', name='pWell' , color=toRGB('LightYellow'), pattern='0000000000000000', threshold=1.50*scale, border=2 )
|
||||
style.addDrawingStyle( group='Active Layers', name='nImplant', color=toRGB('LawnGreen' ), pattern='0000000000000000', threshold=1.50*scale, border=2 )
|
||||
style.addDrawingStyle( group='Active Layers', name='pImplant', color=toRGB('Yellow' ), pattern='0000000000000000', threshold=1.50*scale, border=2 )
|
||||
style.addDrawingStyle( group='Active Layers', name='active' , color=toRGB('White' ), pattern='0000000000000000', threshold=1.50*scale, border=2 )
|
||||
style.addDrawingStyle( group='Active Layers', name='poly' , color=toRGB('Red' ), pattern='0000000000000000', threshold=1.50*scale, border=2 )
|
||||
|
||||
# Routing Layers.
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal1' , color=toRGB('Blue' ), pattern='0000000000000000', threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal2' , color=toRGB('Aqua' ), pattern='0000000000000000', threshold=0.40*scale, border=2 )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal3' , color=toRGB('LightPink'), pattern='0000000000000000', threshold=0.02*scale, border=2 )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal4' , color=toRGB('Green' ), pattern='0000000000000000', threshold=0.02*scale, border=2 )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal5' , color=toRGB('Yellow' ), pattern='0000000000000000', threshold=0.02*scale, border=2 )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal6' , color=toRGB('Violet' ), pattern='0000000000000000', threshold=0.02*scale, border=2 )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal7' , color=toRGB('Violet' ), pattern='0000000000000000', threshold=0.02*scale, border=2 )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal8' , color=toRGB('Violet' ), pattern='0000000000000000', threshold=0.02*scale, border=2 )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal9' , color=toRGB('Violet' ), pattern='0000000000000000', threshold=0.02*scale, border=2 )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal10', color=toRGB('Violet' ), pattern='0000000000000000', threshold=0.02*scale, border=2 )
|
||||
|
||||
# Cuts (VIA holes).
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut0', color=toRGB('0,150,150'), pattern=toHexa('poids4.8'), threshold=1.50*scale, border=1 )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut1', color=toRGB('Aqua' ), pattern='0000000000000000', threshold=0.80*scale, border=1 )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut2', color=toRGB('LightPink'), pattern='0000000000000000', threshold=0.80*scale, border=1 )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut3', color=toRGB('Green' ), pattern='0000000000000000', threshold=0.80*scale, border=1 )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut4', color=toRGB('Yellow' ), pattern='0000000000000000', threshold=0.80*scale, border=1 )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut5', color=toRGB('Violet' ), pattern='0000000000000000', threshold=0.80*scale, border=1 )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut6', color=toRGB('Violet' ), pattern='0000000000000000', threshold=0.80*scale, border=1 )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut7', color=toRGB('Violet' ), pattern='0000000000000000', threshold=0.80*scale, border=1 )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut8', color=toRGB('Violet' ), pattern='0000000000000000', threshold=0.80*scale, border=1 )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut9', color=toRGB('Violet' ), pattern='0000000000000000', threshold=0.80*scale, border=1 )
|
||||
|
||||
Viewer.Graphics.addStyle( style )
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Style: Layout Design [white]
|
||||
|
||||
style = Viewer.DisplayStyle( 'Layout Design [white]' )
|
||||
style.inheritFrom( 'Layout Design [black]' )
|
||||
style.setDescription( 'Layout Design Look - white background' )
|
||||
style.setDarkening ( Viewer.DisplayStyle.HSVr(1.0, 3.0, 2.5) )
|
||||
|
||||
|
||||
# Group: Viewer.
|
||||
style.addDrawingStyle( group='Viewer', name='background' , color=toRGB('White'), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='grid' , color=toRGB('Black'), border=1, threshold=2.0 *scale )
|
||||
style.addDrawingStyle( group='Viewer', name='spot' , color=toRGB('Black'), border=1, threshold=2.0 *scale )
|
||||
style.addDrawingStyle( group='Viewer', name='text.ruler' , color=toRGB('Black'), border=1, threshold=0.0 *scale )
|
||||
style.addDrawingStyle( group='Viewer', name='text.reference', color=toRGB('Black'), border=1, threshold=20.0*scale )
|
||||
|
||||
# Group: Active Layers.
|
||||
style.addDrawingStyle( group='Active Layers', name='active', color=toRGB('175,175,175'), pattern='0000000000000000', threshold=1.50*scale, border=2 )
|
||||
|
||||
Viewer.Graphics.addStyle( style )
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Style: For Printers [white]
|
||||
|
||||
style = Viewer.DisplayStyle( 'For Printers' )
|
||||
style.setDescription( 'For Printers' )
|
||||
style.setDarkening ( Viewer.DisplayStyle.HSVr(1.0, 3.0, 2.5) )
|
||||
|
||||
# Group: Viewer.
|
||||
style.addDrawingStyle( group='Viewer', name='fallback' , color=toRGB('Gray238' ), border=1, pattern='55AA55AA55AA55AA' )
|
||||
style.addDrawingStyle( group='Viewer', name='background' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='foreground' , color=toRGB('Black' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='rubber' , color=toRGB('192,0,192'), border=4, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='phantom' , color=toRGB('Seashell4'), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='boundaries' , color=toRGB('Black' ), border=1, pattern='0000000000000000', threshold=0 )
|
||||
style.addDrawingStyle( group='Viewer', name='marker' , color=toRGB('80,250,80'), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionDraw' , color=toRGB('Black' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionFill' , color=toRGB('Black' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='grid' , color=toRGB('Black' ), border=1, threshold=2.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='spot' , color=toRGB('Black' ), border=2, threshold=6.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='ghost' , color=toRGB('Black' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='text.ruler' , color=toRGB('Black' ), border=1, threshold=0.0 *scale )
|
||||
style.addDrawingStyle( group='Viewer', name='text.instance' , color=toRGB('Black' ), border=1, threshold=4.0 *scale )
|
||||
style.addDrawingStyle( group='Viewer', name='text.reference' , color=toRGB('Black' ), border=1, threshold=20.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='undef' , color=toRGB('Violet' ), border=0, pattern='2244118822441188' )
|
||||
style.addDrawingStyle( group='Viewer', name='mauka.container', color=toRGB('Magenta4' ), border=4, pattern='0000000000000000', goMatched=False )
|
||||
|
||||
# Group: Active Layers.
|
||||
style.addDrawingStyle( group='Active Layers', name='nWell' , color=toRGB('Tan' ), pattern=toHexa('urgo.32' ), border=1, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='pWell' , color=toRGB('LightYellow'), pattern=toHexa('antipoids2.32'), border=1, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='nImplant', color=toRGB('LawnGreen' ), pattern=toHexa('diffusion.32' ), border=0, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='pImplant', color=toRGB('Yellow' ), pattern=toHexa('diffusion.32' ), border=0, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='active' , color=toRGB('White' ), pattern=toHexa('active.32' ), border=0, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='poly' , color=toRGB('Red' ), pattern=toHexa('antipoids2.32'), border=1, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='poly2' , color=toRGB('Orange' ), pattern=toHexa('antipoids2.32'), border=1, threshold=0.02*scale )
|
||||
|
||||
# Group: Routing Layers.
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal1' , color=toRGB('Blue' ), pattern=toHexa('slash.32' ), border=4, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal2' , color=toRGB('Aqua' ), pattern=toHexa('antislash2.32'), border=1, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metcap' , color=toRGB('DarkTurquoise'), pattern=toHexa('poids2.32' ), border=2, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal3' , color=toRGB('LightPink' ), pattern=toHexa('antislash3.32'), border=1, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal4' , color=toRGB('Green' ), pattern=toHexa('antislash4.32'), border=1, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal5' , color=toRGB('Yellow' ), pattern=toHexa('antislash5.32'), border=1, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal6' , color=toRGB('Violet' ), pattern=toHexa('antislash2.32'), border=1, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal7' , color=toRGB('Violet' ), pattern=toHexa('antislash2.32'), border=1, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal8' , color=toRGB('Violet' ), pattern=toHexa('antislash2.32'), border=1, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal9' , color=toRGB('Violet' ), pattern=toHexa('antislash2.32'), border=1, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='metal10', color=toRGB('Violet' ), pattern=toHexa('antislash2.32'), border=1, threshold=0.02*scale )
|
||||
|
||||
# Group: Cuts (VIA holes)
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut0', color=toRGB('Blue' ), pattern=toHexa('poids2.8' ), border=2, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut1', color=toRGB('Aqua' ), pattern=toHexa('antipoids2.8'), border=2, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut2', color=toRGB('LightPink'), pattern=toHexa('poids2.8' ), border=2, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut3', color=toRGB('Green' ), pattern=toHexa('antipoids2.8'), border=2, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut4', color=toRGB('Yellow' ), pattern=toHexa('poids2.8' ), border=2, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut5', color=toRGB('Violet' ), pattern=toHexa('antipoids2.8'), border=2, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut6', color=toRGB('Violet' ), pattern=toHexa('antipoids2.8'), border=2, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut7', color=toRGB('Violet' ), pattern=toHexa('antipoids2.8'), border=2, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut8', color=toRGB('Violet' ), pattern=toHexa('antipoids2.8'), border=2, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='cut9', color=toRGB('Violet' ), pattern=toHexa('antipoids2.8'), border=2, threshold=0.02*scale )
|
||||
|
||||
# Group: MIM6.
|
||||
style.addDrawingStyle( group='MIM6', name='metbot_r', color=toRGB('Aqua' ), pattern=toHexa('light_antihash0.8'), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='MIM6', name='cut6' , color=toRGB('LightPink'), pattern=toHexa('light_antihash1.8'), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='MIM6', name='metal7' , color=toRGB('Green' ), pattern=toHexa('light_antihash2.8'), threshold=0.80*scale )
|
||||
|
||||
# Group: Blockages.
|
||||
style.addDrawingStyle( group='Blockages', name='blockage1' , color=toRGB('Blue' ), pattern='006070381c0e0703' , threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage2' , color=toRGB('Aqua' ), pattern='8103060c183060c0' , threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage3' , color=toRGB('LightPink'), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage4' , color=toRGB('Green' ), pattern=toHexa('light_antihash2.8'), threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage5' , color=toRGB('Yellow' ), pattern='1144114411441144' , threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage6' , color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage7' , color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage8' , color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage9' , color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='blockage10', color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.80*scale, border=2 )
|
||||
|
||||
# Group: Knik & Kite.
|
||||
style.addDrawingStyle( group='Knik & Kite', name='SPL1' , color=toRGB('Red' ) )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='AutoLayer' , color=toRGB('Magenta' ) )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gmetalh' , color=toRGB('128,255,200'), pattern=toHexa('light_antihash0.8') , border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gmetalv' , color=toRGB('200,200,255'), pattern=toHexa('light_antihash1.8') , border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gcut' , color=toRGB('255,255,190'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='Anabatic::Edge' , color=toRGB('255,255,190'), pattern='0000000000000000', border=2 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='Anabatic::GCell', color=toRGB('Black' ), pattern='0000000000000000', border=2, threshold=0.80*scale )
|
||||
|
||||
Viewer.Graphics.addStyle( style )
|
||||
|
||||
|
||||
Viewer.Graphics.setStyle( 'Alliance.Classic [black]' )
|
||||
|
||||
createStyles( scale=1.0 )
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) Sorbonne Université 2019-2023, All Rights Reserved
|
||||
#
|
||||
# +-----------------------------------------------------------------+
|
||||
# | C O R I O L I S |
|
||||
# | Alliance / Hurricane Interface |
|
||||
# | |
|
||||
# | Author : Jean-Paul CHAPUT |
|
||||
# | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
# | =============================================================== |
|
||||
# | Python : "./etc/symbolic/lcmos/etesian.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
from coriolis.helpers import truncPath
|
||||
from coriolis.helpers.io import vprint
|
||||
vprint( 2, ' - "%s".' % truncPath(__file__) )
|
||||
|
||||
from ...common import etesian
|
|
@ -0,0 +1,194 @@
|
|||
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) Sorbonne Université 2019-2023, All Rights Reserved
|
||||
#
|
||||
# +-----------------------------------------------------------------+
|
||||
# | C O R I O L I S |
|
||||
# | Alliance / Hurricane Interface |
|
||||
# | |
|
||||
# | Author : Jean-Paul CHAPUT |
|
||||
# | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
# | =============================================================== |
|
||||
# | Python : "./etc/symbolic/lcmos/kite.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
import coriolis.Cfg as Cfg
|
||||
from coriolis.Hurricane import DataBase
|
||||
from coriolis.CRL import AllianceFramework, RoutingGauge, \
|
||||
RoutingLayerGauge, CellGauge
|
||||
from coriolis.helpers import truncPath, l, u, n
|
||||
from coriolis.helpers.io import vprint
|
||||
vprint( 2, ' - "%s".' % truncPath(__file__) )
|
||||
|
||||
from ...common import kite
|
||||
|
||||
|
||||
p = Cfg.getParamDouble ( 'lefImport.minTerminalWidth' ).setDouble ( 0.0 )
|
||||
p = Cfg.getParamString ( 'katabatic.routingGauge' ).setString ( 'sxlib' )
|
||||
p = Cfg.getParamInt ( "katabatic.globalLengthThreshold" ).setInt ( 1450 )
|
||||
p = Cfg.getParamPercentage( "katabatic.saturateRatio" ).setPercentage( 80 )
|
||||
p = Cfg.getParamInt ( "katabatic.saturateRp" ).setInt ( 8 )
|
||||
p = Cfg.getParamString ( 'katabatic.topRoutingLayer' ).setString ( 'METAL5' )
|
||||
|
||||
# Kite parameters.
|
||||
p = Cfg.getParamInt( "kite.hTracksReservedLocal" ); p.setInt( 3 ); p.setMin( 0 ); p.setMax( 20 )
|
||||
p = Cfg.getParamInt( "kite.vTracksReservedLocal" ); p.setInt( 3 ); p.setMin( 0 ); p.setMax( 20 )
|
||||
p = Cfg.getParamInt( "kite.eventsLimit" ); p.setInt( 4000002 )
|
||||
p = Cfg.getParamInt( "kite.ripupCost" ); p.setInt( 3 ); p.setMin( 0 )
|
||||
p = Cfg.getParamInt( "kite.strapRipupLimit" ); p.setInt( 16 ); p.setMin( 1 )
|
||||
p = Cfg.getParamInt( "kite.localRipupLimit" ); p.setInt( 9 ); p.setMin( 1 )
|
||||
p = Cfg.getParamInt( "kite.globalRipupLimit" ); p.setInt( 5 ); p.setMin( 1 )
|
||||
p = Cfg.getParamInt( "kite.longGlobalRipupLimit" ); p.setInt( 5 ); p.setMin( 1 )
|
||||
|
||||
# Anabatic & Katana parameters are temporarily hosted here.
|
||||
p = Cfg.getParamString ( 'anabatic.routingGauge' ); p.setString ( 'sxlib' )
|
||||
p = Cfg.getParamInt ( "anabatic.globalLengthThreshold" ); p.setInt ( 1450 )
|
||||
p = Cfg.getParamPercentage( "anabatic.saturateRatio" ); p.setPercentage( 80 )
|
||||
p = Cfg.getParamInt ( "anabatic.saturateRp" ); p.setInt ( 8 )
|
||||
p = Cfg.getParamString ( 'anabatic.topRoutingLayer' ); p.setString ( 'METAL5' )
|
||||
p = Cfg.getParamInt ( "anabatic.edgeLength" ); p.setInt ( 24 )
|
||||
p = Cfg.getParamInt ( "anabatic.edgeWidth" ); p.setInt ( 4 )
|
||||
p = Cfg.getParamDouble ( "anabatic.edgeCostH" ); p.setDouble ( 19.0 )
|
||||
p = Cfg.getParamDouble ( "anabatic.edgeCostK" ); p.setDouble ( -60.0 )
|
||||
p = Cfg.getParamDouble ( "anabatic.edgeHScaling" ); p.setDouble ( 1.0 )
|
||||
p = Cfg.getParamInt ( "anabatic.globalIterations" ); p.setInt ( 10 ); p.setMin(1); p.setMax(100)
|
||||
p = Cfg.getParamEnumerate ( "anabatic.gcell.displayMode" ); p.setInt ( 1 )
|
||||
p.addValue( "Boundary", 1 )
|
||||
p.addValue( "Density" , 2 )
|
||||
|
||||
p = Cfg.getParamBool ( "katana.useGlobalEstimate" ); p.setBool ( False );
|
||||
p = Cfg.getParamInt ( "katana.hTracksReservedLocal" ); p.setInt ( 3 ); p.setMin(0); p.setMax(20)
|
||||
p = Cfg.getParamInt ( "katana.vTracksReservedLocal" ); p.setInt ( 3 ); p.setMin(0); p.setMax(20)
|
||||
p = Cfg.getParamInt ( "katana.hTracksReservedMin" ); p.setInt ( 1 ); p.setMin(0); p.setMax(20)
|
||||
p = Cfg.getParamInt ( "katana.vTracksReservedMin" ); p.setInt ( 1 ); p.setMin(0); p.setMax(20)
|
||||
p = Cfg.getParamInt ( "katana.termSatReservedLocal" ); p.setInt ( 8 )
|
||||
p = Cfg.getParamInt ( "katana.termSatThreshold" ); p.setInt ( 9 )
|
||||
p = Cfg.getParamInt ( "katana.eventsLimit" ); p.setInt ( 4000002 )
|
||||
p = Cfg.getParamInt ( "katana.ripupCost" ); p.setInt ( 3 ); p.setMin(0)
|
||||
p = Cfg.getParamInt ( "katana.strapRipupLimit" ); p.setInt ( 16 ); p.setMin(1)
|
||||
p = Cfg.getParamInt ( "katana.localRipupLimit" ); p.setInt ( 9 ); p.setMin(1)
|
||||
p = Cfg.getParamInt ( "katana.globalRipupLimit" ); p.setInt ( 5 ); p.setMin(1)
|
||||
p = Cfg.getParamInt ( "katana.longGlobalRipupLimit" ); p.setInt ( 5 ); p.setMin(1)
|
||||
p = Cfg.getParamString( 'chip.padCoreSide' ); p.setString( 'South' )
|
||||
|
||||
|
||||
tech = DataBase.getDB().getTechnology()
|
||||
af = AllianceFramework.get()
|
||||
rg = RoutingGauge.create( 'sxlib' )
|
||||
|
||||
rg.addLayerGauge( RoutingLayerGauge.create( tech.getLayer('METAL1') # metal.
|
||||
, RoutingLayerGauge.Vertical # preferred routing direction.
|
||||
, RoutingLayerGauge.PinOnly # layer usage.
|
||||
, 0 # depth.
|
||||
, 0.0 # density (deprecated).
|
||||
, l(0) # track offset from AB.
|
||||
, l(5) # track pitch.
|
||||
, l(2) # wire width.
|
||||
, 0 # perpandicular wire width.
|
||||
, l(1) # VIA side (that is VIA12).
|
||||
, l(4) # obstacle dW.
|
||||
) )
|
||||
|
||||
rg.addLayerGauge( RoutingLayerGauge.create( tech.getLayer('METAL2') # metal.
|
||||
, RoutingLayerGauge.Horizontal # preferred routing direction.
|
||||
, RoutingLayerGauge.Default # layer usage.
|
||||
, 1 # depth.
|
||||
, 0.0 # density (deprecated).
|
||||
, l(0) # track offset from AB.
|
||||
, l(5) # track pitch.
|
||||
, l(2) # wire width.
|
||||
, 0 # perpandicular wire width.
|
||||
, l(1) # VIA side (that is VIA23).
|
||||
, l(4) # obstacle dW.
|
||||
) )
|
||||
|
||||
rg.addLayerGauge( RoutingLayerGauge.create( tech.getLayer('METAL3') # metal.
|
||||
, RoutingLayerGauge.Vertical # preferred routing direction.
|
||||
, RoutingLayerGauge.Default # layer usage.
|
||||
, 2 # depth.
|
||||
, 0.0 # density (deprecated).
|
||||
, l(0) # track offset from AB.
|
||||
, l(5) # track pitch.
|
||||
, l(2) # wire width.
|
||||
, 0 # perpandicular wire width.
|
||||
, l(1) # VIA side (that is VIA34).
|
||||
, l(4) # obstacle dW.
|
||||
) )
|
||||
|
||||
rg.addLayerGauge( RoutingLayerGauge.create( tech.getLayer('METAL4') # metal.
|
||||
, RoutingLayerGauge.Horizontal # preferred routing direction.
|
||||
, RoutingLayerGauge.Default # layer usage.
|
||||
, 3 # depth.
|
||||
, 0.0 # density (deprecated).
|
||||
, l(0) # track offset from AB.
|
||||
, l(5) # track pitch.
|
||||
, l(2) # wire width.
|
||||
, 0 # perpandicular wire width.
|
||||
, l(1) # VIA side (that is VIA23).
|
||||
, l(4) # obstacle dW.
|
||||
) )
|
||||
|
||||
rg.addLayerGauge( RoutingLayerGauge.create( tech.getLayer('METAL5') # metal.
|
||||
, RoutingLayerGauge.Vertical # preferred routing direction.
|
||||
, RoutingLayerGauge.Default # layer usage.
|
||||
, 4 # depth.
|
||||
, 0.0 # density (deprecated).
|
||||
, l(0) # track offset from AB.
|
||||
, l(5) # track pitch.
|
||||
, l(2) # wire width.
|
||||
, 0 # perpandicular wire width.
|
||||
, l(1) # VIA side (that is VIA23).
|
||||
, l(4) # obstacle dW.
|
||||
) )
|
||||
|
||||
af.addRoutingGauge( rg )
|
||||
|
||||
rg = RoutingGauge.create( 'sxlib-2M' )
|
||||
|
||||
rg.addLayerGauge( RoutingLayerGauge.create( tech.getLayer('METAL1') # metal.
|
||||
, RoutingLayerGauge.Vertical # preferred routing direction.
|
||||
, RoutingLayerGauge.PinOnly # layer usage.
|
||||
, 0 # depth.
|
||||
, 0.0 # density (deprecated).
|
||||
, l(0) # track offset from AB.
|
||||
, l(5) # track pitch.
|
||||
, l(2) # wire width.
|
||||
, 0 # perpandicular wire width.
|
||||
, l(1) # VIA side (that is VIA12).
|
||||
, l(4) # obstacle dW.
|
||||
) )
|
||||
|
||||
rg.addLayerGauge( RoutingLayerGauge.create( tech.getLayer('METAL2') # metal.
|
||||
, RoutingLayerGauge.Horizontal # preferred routing direction.
|
||||
, RoutingLayerGauge.Default # layer usage.
|
||||
, 1 # depth.
|
||||
, 0.0 # density (deprecated).
|
||||
, l(0) # track offset from AB.
|
||||
, l(5) # track pitch.
|
||||
, l(2) # wire width.
|
||||
, 0 # perpandicular wire width.
|
||||
, l(1) # VIA side (that is VIA23).
|
||||
, l(4) # obstacle dW.
|
||||
) )
|
||||
|
||||
af.addRoutingGauge( rg )
|
||||
af.setRoutingGauge( 'sxlib' )
|
||||
|
||||
# Gauge for standard cells.
|
||||
cg = CellGauge.create( 'sxlib'
|
||||
, 'metal2' # pin layer name.
|
||||
, l( 5.0) # pitch.
|
||||
, l( 50.0) # cell slice height.
|
||||
, l( 5.0) # cell slice step.
|
||||
)
|
||||
af.addCellGauge( cg )
|
||||
|
||||
# Gauge for Alliance symbolic I/O pads.
|
||||
cg = CellGauge.create( 'pxlib'
|
||||
, 'metal2' # pin layer name.
|
||||
, l( 5.0) # pitch.
|
||||
, l(400.0) # cell slice height.
|
||||
, l(200.0) # cell slice step.
|
||||
)
|
||||
af.addCellGauge( cg )
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) Sorbonne Université 2019-2023, All Rights Reserved
|
||||
#
|
||||
# +-----------------------------------------------------------------+
|
||||
# | C O R I O L I S |
|
||||
# | Alliance / Hurricane Interface |
|
||||
# | |
|
||||
# | Author : Jean-Paul CHAPUT |
|
||||
# | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
# | =============================================================== |
|
||||
# | Python : "./etc/symbolic/lcmos/misc.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
from coriolis.helpers import truncPath
|
||||
from coriolis.helpers.io import vprint
|
||||
vprint( 2, ' - "%s".' % truncPath(__file__) )
|
||||
|
||||
from ...common import misc
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) Sorbonne Université 2019-2023, All Rights Reserved
|
||||
#
|
||||
# +-----------------------------------------------------------------+
|
||||
# | C O R I O L I S |
|
||||
# | Alliance / Hurricane Interface |
|
||||
# | |
|
||||
# | Author : Jean-Paul CHAPUT |
|
||||
# | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
# | =============================================================== |
|
||||
# | Python : "./etc/symbolic/lcmos/patterns.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
from coriolis.helpers import truncPath
|
||||
from coriolis.helpers.io import vprint
|
||||
vprint( 2, ' - "%s".' % truncPath(__file__) )
|
||||
|
||||
from ...common import patterns
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) Sorbonne Université 2019-2023, All Rights Reserved
|
||||
#
|
||||
# +-----------------------------------------------------------------+
|
||||
# | C O R I O L I S |
|
||||
# | Alliance / Hurricane Interface |
|
||||
# | |
|
||||
# | Author : Jean-Paul CHAPUT |
|
||||
# | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
# | =============================================================== |
|
||||
# | Python : "./etc/symbolic/lcmos/plugins.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
import coriolis.Cfg as Cfg
|
||||
from coriolis.helpers import truncPath, l, u, n
|
||||
from coriolis.helpers.io import vprint
|
||||
vprint( 2, ' - "%s".' % truncPath(__file__) )
|
||||
|
||||
Cfg.getParamInt ( "chip.block.rails.count" ).setInt ( 5 )
|
||||
Cfg.getParamInt ( "chip.block.rails.hWidth" ).setInt ( l( 12) )
|
||||
Cfg.getParamInt ( "chip.block.rails.vWidth" ).setInt ( l( 12) )
|
||||
Cfg.getParamInt ( "chip.block.rails.hSpacing" ).setInt ( l( 3) )
|
||||
Cfg.getParamInt ( "chip.block.rails.vSpacing" ).setInt ( l( 3) )
|
||||
Cfg.getParamBool ( "chip.useAbstractPads" ).setBool ( True )
|
||||
Cfg.getParamInt ( 'clockTree.minimumSide' ).setInt ( l(600) )
|
||||
Cfg.getParamString( 'clockTree.buffer' ).setString( 'buf_x2')
|
||||
Cfg.getParamString( 'clockTree.placerEngine' ).setString( 'Etesian')
|
||||
Cfg.getParamInt ( 'block.spareSide' ).setInt ( 10 )
|
||||
Cfg.getParamString( 'spares.buffer' ).setString( 'buf_x8')
|
||||
Cfg.getParamInt ( 'spares.maxSinks' ).setInt ( 31 )
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) Sorbonne Université 2019-2023, All Rights Reserved
|
||||
#
|
||||
# +-----------------------------------------------------------------+
|
||||
# | C O R I O L I S |
|
||||
# | Alliance / Hurricane Interface |
|
||||
# | |
|
||||
# | Author : Jean-Paul CHAPUT |
|
||||
# | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
# | =============================================================== |
|
||||
# | Python : "./etc/symbolic/lcmos/stratus1.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
import os.path
|
||||
import coriolis.Cfg as Cfg
|
||||
from coriolis.helpers import sysConfDir, truncPath
|
||||
from coriolis.helpers.io import vprint
|
||||
vprint( 2, ' - "%s".' % truncPath(__file__) )
|
||||
|
||||
from ...common import stratus1
|
||||
|
||||
Cfg.getParamString( "stratus1.format" ).setString( "vst" )
|
||||
Cfg.getParamString( "stratus1.simulator" ).setString( "asimut" )
|
||||
Cfg.getParamString( "stratus1.mappingName" ).setString( os.path.join(sysConfDir,'symbolic/cmos/stratus2sxlib.xml') )
|
|
@ -0,0 +1,401 @@
|
|||
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) Sorbonne Université 2019-2023, All Rights Reserved
|
||||
#
|
||||
# +-----------------------------------------------------------------+
|
||||
# | C O R I O L I S |
|
||||
# | Alliance / Hurricane Interface |
|
||||
# | |
|
||||
# | Author : Jean-Paul CHAPUT |
|
||||
# | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
# | =============================================================== |
|
||||
# | Python : "./etc/symbolic/lcmos/technology.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
from coriolis.helpers import l, u, n, truncPath
|
||||
from coriolis.helpers.io import WarningMessage, vprint
|
||||
vprint( 2, ' - "{}".'.format(truncPath(__file__)) )
|
||||
|
||||
from coriolis.Hurricane import DbU, DataBase, Technology, Layer, BasicLayer, \
|
||||
DiffusionLayer, TransistorLayer, \
|
||||
RegularLayer, ContactLayer, ViaLayer
|
||||
|
||||
|
||||
def createBL ( layerName, material ):
|
||||
global tech
|
||||
return BasicLayer.create( tech, layerName, BasicLayer.Material(material) )
|
||||
|
||||
|
||||
tech = DataBase.getDB().getTechnology()
|
||||
if tech:
|
||||
print( WarningMessage( 'lcmos.technology: Technology already exists, "{}"'.format(tech.getName()) ))
|
||||
else:
|
||||
tech = Technology.create( DataBase.getDB(), 'lcmos' )
|
||||
|
||||
DbU.setPrecision ( 2 )
|
||||
DbU.setPhysicalsPerGrid ( 0.5, DbU.UnitPowerMicro )
|
||||
DbU.setGridsPerLambda ( 2 )
|
||||
DbU.setSymbolicSnapGridStep( DbU.fromLambda(1.0) )
|
||||
DbU.setPolygonStep ( DbU.fromGrid (2.0) )
|
||||
|
||||
|
||||
from ...common import loadGdsLayers
|
||||
|
||||
|
||||
nWell = createBL( 'nWell' , BasicLayer.Material.nWell ) # Non-Routing Layers.
|
||||
pWell = createBL( 'pWell' , BasicLayer.Material.pWell )
|
||||
nImplant = createBL( 'nImplant' , BasicLayer.Material.nImplant )
|
||||
pImplant = createBL( 'pImplant' , BasicLayer.Material.pImplant )
|
||||
active = createBL( 'active' , BasicLayer.Material.active )
|
||||
poly = createBL( 'poly' , BasicLayer.Material.poly )
|
||||
poly2 = createBL( 'poly2' , BasicLayer.Material.poly )
|
||||
cut0 = createBL( 'cut0' , BasicLayer.Material.cut ) # Routing Layers & VIA Cuts.
|
||||
metal1 = createBL( 'metal1' , BasicLayer.Material.metal ) # WARNING: order *is* meaningful.
|
||||
cut1 = createBL( 'cut1' , BasicLayer.Material.cut )
|
||||
metal2 = createBL( 'metal2' , BasicLayer.Material.metal )
|
||||
metcap = createBL( 'metcap' , BasicLayer.Material.other )
|
||||
cut2 = createBL( 'cut2' , BasicLayer.Material.cut )
|
||||
metal3 = createBL( 'metal3' , BasicLayer.Material.metal )
|
||||
cut3 = createBL( 'cut3' , BasicLayer.Material.cut )
|
||||
metal4 = createBL( 'metal4' , BasicLayer.Material.metal )
|
||||
cut4 = createBL( 'cut4' , BasicLayer.Material.cut )
|
||||
metal5 = createBL( 'metal5' , BasicLayer.Material.metal )
|
||||
cut5 = createBL( 'cut5' , BasicLayer.Material.cut )
|
||||
metal6 = createBL( 'metal6' , BasicLayer.Material.metal )
|
||||
cut6 = createBL( 'cut6' , BasicLayer.Material.cut )
|
||||
metal7 = createBL( 'metal7' , BasicLayer.Material.metal )
|
||||
cut7 = createBL( 'cut7' , BasicLayer.Material.cut )
|
||||
metal8 = createBL( 'metal8' , BasicLayer.Material.metal )
|
||||
cut8 = createBL( 'cut8' , BasicLayer.Material.cut )
|
||||
metal9 = createBL( 'metal9' , BasicLayer.Material.metal )
|
||||
cut9 = createBL( 'cut9' , BasicLayer.Material.cut )
|
||||
metal10 = createBL( 'metal10' , BasicLayer.Material.metal )
|
||||
|
||||
blockage1 = createBL( 'blockage1' , BasicLayer.Material.blockage )
|
||||
blockage2 = createBL( 'blockage2' , BasicLayer.Material.blockage )
|
||||
blockage3 = createBL( 'blockage3' , BasicLayer.Material.blockage )
|
||||
blockage4 = createBL( 'blockage4' , BasicLayer.Material.blockage )
|
||||
blockage5 = createBL( 'blockage5' , BasicLayer.Material.blockage )
|
||||
blockage6 = createBL( 'blockage6' , BasicLayer.Material.blockage )
|
||||
blockage7 = createBL( 'blockage7' , BasicLayer.Material.blockage )
|
||||
blockage8 = createBL( 'blockage8' , BasicLayer.Material.blockage )
|
||||
blockage9 = createBL( 'blockage9' , BasicLayer.Material.blockage )
|
||||
blockage10 = createBL( 'blockage10', BasicLayer.Material.blockage )
|
||||
|
||||
metal1 .setBlockageLayer( blockage1 )
|
||||
metal2 .setBlockageLayer( blockage2 )
|
||||
metal3 .setBlockageLayer( blockage3 )
|
||||
metal4 .setBlockageLayer( blockage4 )
|
||||
metal5 .setBlockageLayer( blockage5 )
|
||||
metal6 .setBlockageLayer( blockage6 )
|
||||
metal7 .setBlockageLayer( blockage7 )
|
||||
metal8 .setBlockageLayer( blockage8 )
|
||||
metal9 .setBlockageLayer( blockage9 )
|
||||
metal10.setBlockageLayer( blockage10 )
|
||||
|
||||
textCell = createBL( 'text.cell' , BasicLayer.Material.other ) # Misc. non-physical layers.
|
||||
textInst = createBL( 'text.instance', BasicLayer.Material.other ) # Used by the software for visualization
|
||||
SPL1 = createBL( 'SPL1' , BasicLayer.Material.other ) # purposes only.
|
||||
AutoLayer = createBL( 'AutoLayer' , BasicLayer.Material.other )
|
||||
gmetalh = createBL( 'gmetalh' , BasicLayer.Material.metal ) # Special BasicLayers for Knik & Kite Routers.
|
||||
gcut = createBL( 'gcut' , BasicLayer.Material.cut ) # *Must be after all others*
|
||||
gmetalv = createBL( 'gmetalv' , BasicLayer.Material.metal )
|
||||
|
||||
# VIAs for real technologies.
|
||||
via12 = ViaLayer.create( tech, 'via12' , metal1, cut1, metal2 )
|
||||
via23 = ViaLayer.create( tech, 'via23' , metal2, cut2, metal3 )
|
||||
via34 = ViaLayer.create( tech, 'via34' , metal3, cut3, metal4 )
|
||||
via45 = ViaLayer.create( tech, 'via45' , metal4, cut4, metal5 )
|
||||
via56 = ViaLayer.create( tech, 'via56' , metal5, cut5, metal6 )
|
||||
via67 = ViaLayer.create( tech, 'via67' , metal6, cut6, metal7 )
|
||||
via78 = ViaLayer.create( tech, 'via78' , metal7, cut7, metal8 )
|
||||
via89 = ViaLayer.create( tech, 'via89' , metal8, cut8, metal9 )
|
||||
via910 = ViaLayer.create( tech, 'via910', metal9, cut9, metal10 )
|
||||
|
||||
# Composite/Symbolic layers.
|
||||
NWELL = RegularLayer .create( tech, 'NWELL' , nWell )
|
||||
PWELL = RegularLayer .create( tech, 'PWELL' , pWell )
|
||||
NTIE = DiffusionLayer .create( tech, 'NTIE' , nImplant , active, nWell)
|
||||
PTIE = DiffusionLayer .create( tech, 'PTIE' , pImplant , active, pWell)
|
||||
NDIF = DiffusionLayer .create( tech, 'NDIF' , nImplant , active, None )
|
||||
PDIF = DiffusionLayer .create( tech, 'PDIF' , pImplant , active, None )
|
||||
GATE = DiffusionLayer .create( tech, 'GATE' , poly , active, None )
|
||||
NTRANS = TransistorLayer.create( tech, 'NTRANS' , nImplant , active, poly, None )
|
||||
PTRANS = TransistorLayer.create( tech, 'PTRANS' , pImplant , active, poly, None )
|
||||
POLY = RegularLayer .create( tech, 'POLY' , poly )
|
||||
POLY2 = RegularLayer .create( tech, 'POLY2' , poly2 )
|
||||
METAL1 = RegularLayer .create( tech, 'METAL1' , metal1 )
|
||||
METAL2 = RegularLayer .create( tech, 'METAL2' , metal2 )
|
||||
metcapdum = RegularLayer .create( tech, 'metcapdum' , metcap )
|
||||
metbot = RegularLayer .create( tech, 'metbot' , metal2 )
|
||||
METAL3 = RegularLayer .create( tech, 'METAL3' , metal3 )
|
||||
METAL4 = RegularLayer .create( tech, 'METAL4' , metal4 )
|
||||
METAL5 = RegularLayer .create( tech, 'METAL5' , metal5 )
|
||||
METAL6 = RegularLayer .create( tech, 'METAL6' , metal6 )
|
||||
METAL7 = RegularLayer .create( tech, 'METAL7' , metal7 )
|
||||
METAL8 = RegularLayer .create( tech, 'METAL8' , metal8 )
|
||||
METAL9 = RegularLayer .create( tech, 'METAL9' , metal9 )
|
||||
METAL10 = RegularLayer .create( tech, 'METAL10' , metal10 )
|
||||
CONT_BODY_N = ContactLayer .create( tech, 'CONT_BODY_N', nImplant , cut0, active, metal1, None )
|
||||
CONT_BODY_P = ContactLayer .create( tech, 'CONT_BODY_P', pImplant , cut0, active, metal1, None )
|
||||
CONT_DIF_N = ContactLayer .create( tech, 'CONT_DIF_N' , nImplant , cut0, active, metal1, None )
|
||||
CONT_DIF_P = ContactLayer .create( tech, 'CONT_DIF_P' , pImplant , cut0, active, metal1, None )
|
||||
CONT_POLY = ViaLayer .create( tech, 'CONT_POLY' , poly , cut0, metal1 )
|
||||
|
||||
# VIAs for symbolic technologies.
|
||||
VIA12 = ViaLayer .create( tech, 'VIA12' , metal1, cut1, metal2 )
|
||||
VIA23 = ViaLayer .create( tech, 'VIA23' , metal2, cut2, metal3 )
|
||||
VIA23cap = ViaLayer .create( tech, 'VIA23cap' , metcap, cut2, metal3 )
|
||||
VIA34 = ViaLayer .create( tech, 'VIA34' , metal3, cut3, metal4 )
|
||||
VIA45 = ViaLayer .create( tech, 'VIA45' , metal4, cut4, metal5 )
|
||||
VIA56 = ViaLayer .create( tech, 'VIA56' , metal5, cut5, metal6 )
|
||||
VIA67 = ViaLayer .create( tech, 'VIA67' , metal6, cut6, metal7 )
|
||||
VIA78 = ViaLayer .create( tech, 'VIA78' , metal7, cut7, metal8 )
|
||||
VIA89 = ViaLayer .create( tech, 'VIA89' , metal8, cut8, metal9 )
|
||||
VIA910 = ViaLayer .create( tech, 'VIA910' , metal9, cut9, metal10 )
|
||||
BLOCKAGE1 = RegularLayer.create( tech, 'BLOCKAGE1' , blockage1 )
|
||||
BLOCKAGE2 = RegularLayer.create( tech, 'BLOCKAGE2' , blockage2 )
|
||||
BLOCKAGE3 = RegularLayer.create( tech, 'BLOCKAGE3' , blockage3 )
|
||||
BLOCKAGE4 = RegularLayer.create( tech, 'BLOCKAGE4' , blockage4 )
|
||||
BLOCKAGE5 = RegularLayer.create( tech, 'BLOCKAGE5' , blockage5 )
|
||||
BLOCKAGE6 = RegularLayer.create( tech, 'BLOCKAGE6' , blockage6 )
|
||||
BLOCKAGE7 = RegularLayer.create( tech, 'BLOCKAGE7' , blockage7 )
|
||||
BLOCKAGE8 = RegularLayer.create( tech, 'BLOCKAGE8' , blockage8 )
|
||||
BLOCKAGE9 = RegularLayer.create( tech, 'BLOCKAGE9' , blockage9 )
|
||||
BLOCKAGE10 = RegularLayer.create( tech, 'BLOCKAGE10', blockage10 )
|
||||
gcontact = ViaLayer .create( tech, 'gcontact' , gmetalh , gcut, gmetalv )
|
||||
|
||||
tech.setSymbolicLayer( CONT_BODY_N.getName() )
|
||||
tech.setSymbolicLayer( CONT_BODY_P.getName() )
|
||||
tech.setSymbolicLayer( CONT_DIF_N .getName() )
|
||||
tech.setSymbolicLayer( CONT_DIF_P .getName() )
|
||||
tech.setSymbolicLayer( CONT_POLY .getName() )
|
||||
tech.setSymbolicLayer( POLY .getName() )
|
||||
tech.setSymbolicLayer( POLY2 .getName() )
|
||||
tech.setSymbolicLayer( METAL1 .getName() )
|
||||
tech.setSymbolicLayer( METAL2 .getName() )
|
||||
tech.setSymbolicLayer( METAL3 .getName() )
|
||||
tech.setSymbolicLayer( METAL4 .getName() )
|
||||
tech.setSymbolicLayer( METAL5 .getName() )
|
||||
tech.setSymbolicLayer( METAL6 .getName() )
|
||||
tech.setSymbolicLayer( METAL7 .getName() )
|
||||
tech.setSymbolicLayer( METAL8 .getName() )
|
||||
tech.setSymbolicLayer( METAL9 .getName() )
|
||||
tech.setSymbolicLayer( METAL10 .getName() )
|
||||
tech.setSymbolicLayer( BLOCKAGE1 .getName() )
|
||||
tech.setSymbolicLayer( BLOCKAGE2 .getName() )
|
||||
tech.setSymbolicLayer( BLOCKAGE3 .getName() )
|
||||
tech.setSymbolicLayer( BLOCKAGE4 .getName() )
|
||||
tech.setSymbolicLayer( BLOCKAGE5 .getName() )
|
||||
tech.setSymbolicLayer( BLOCKAGE6 .getName() )
|
||||
tech.setSymbolicLayer( BLOCKAGE7 .getName() )
|
||||
tech.setSymbolicLayer( BLOCKAGE8 .getName() )
|
||||
tech.setSymbolicLayer( BLOCKAGE9 .getName() )
|
||||
tech.setSymbolicLayer( BLOCKAGE10 .getName() )
|
||||
tech.setSymbolicLayer( VIA12 .getName() )
|
||||
tech.setSymbolicLayer( VIA23 .getName() )
|
||||
tech.setSymbolicLayer( VIA34 .getName() )
|
||||
tech.setSymbolicLayer( VIA45 .getName() )
|
||||
tech.setSymbolicLayer( VIA56 .getName() )
|
||||
tech.setSymbolicLayer( VIA67 .getName() )
|
||||
tech.setSymbolicLayer( VIA78 .getName() )
|
||||
tech.setSymbolicLayer( VIA89 .getName() )
|
||||
tech.setSymbolicLayer( VIA910 .getName() )
|
||||
tech.setSymbolicLayer( gcut .getName() )
|
||||
tech.setSymbolicLayer( gmetalh .getName() )
|
||||
tech.setSymbolicLayer( gmetalv .getName() )
|
||||
tech.setSymbolicLayer( gcontact .getName() )
|
||||
|
||||
NWELL.setExtentionCap ( nWell, l(2.0) )
|
||||
NWELL.setExtentionWidth( nWell, l(0.0) )
|
||||
PWELL.setExtentionCap ( pWell, l(2.0) )
|
||||
PWELL.setExtentionWidth( nWell, l(0.0) )
|
||||
|
||||
NTIE.setMinimalSize ( l(3.0) )
|
||||
NTIE.setExtentionCap ( nWell , l(2.0) )
|
||||
NTIE.setExtentionWidth( nWell , l(2.5) )
|
||||
NTIE.setExtentionCap ( nImplant, l(1.5) )
|
||||
NTIE.setExtentionWidth( nImplant, l(0.0) )
|
||||
NTIE.setExtentionCap ( active , l(0.0) )
|
||||
NTIE.setExtentionWidth( active , l(0.0) )
|
||||
|
||||
PTIE.setMinimalSize ( l(3.0) )
|
||||
PTIE.setExtentionCap ( pWell , l(2.0) )
|
||||
PTIE.setExtentionWidth( pWell , l(2.5) )
|
||||
PTIE.setExtentionCap ( pImplant, l(1.5) )
|
||||
PTIE.setExtentionWidth( pImplant, l(0.0) )
|
||||
PTIE.setExtentionCap ( active , l(0.0) )
|
||||
PTIE.setExtentionWidth( active , l(0.0) )
|
||||
|
||||
NDIF.setMinimalSize ( l(3.0) )
|
||||
NDIF.setExtentionCap ( nImplant, l(0.5) )
|
||||
NDIF.setExtentionWidth( nImplant, l(0.0) )
|
||||
NDIF.setExtentionCap ( active , l(0.5) )
|
||||
NDIF.setExtentionWidth( active , l(0.0) )
|
||||
|
||||
PDIF.setMinimalSize ( l(3.0) )
|
||||
PDIF.setExtentionCap ( pImplant, l(0.5) )
|
||||
PDIF.setExtentionWidth( pImplant, l(0.0) )
|
||||
PDIF.setExtentionCap ( active , l(0.5) )
|
||||
PDIF.setExtentionWidth( active , l(0.0) )
|
||||
|
||||
GATE.setMinimalSize ( l(1.0) )
|
||||
GATE.setExtentionCap ( poly , l(1.5) )
|
||||
|
||||
NTRANS.setMinimalSize ( l( 1.0) )
|
||||
NTRANS.setExtentionCap ( nImplant, l(-1.5) )
|
||||
NTRANS.setExtentionWidth( nImplant, l( 3.0) )
|
||||
NTRANS.setExtentionCap ( active , l(-1.5) )
|
||||
NTRANS.setExtentionWidth( active , l( 2.0) )
|
||||
|
||||
PTRANS.setMinimalSize ( l( 1.0) )
|
||||
PTRANS.setExtentionCap ( nWell , l(-1.5) )
|
||||
PTRANS.setExtentionWidth( nWell , l( 2.5) )
|
||||
PTRANS.setExtentionCap ( pImplant, l(-1.5) )
|
||||
PTRANS.setExtentionWidth( pImplant, l( 2.5) )
|
||||
PTRANS.setExtentionCap ( active , l(-1.5) )
|
||||
PTRANS.setExtentionWidth( active , l( 2.5) )
|
||||
|
||||
POLY .setMinimalSize ( l(1.0) )
|
||||
POLY .setExtentionCap ( poly , l(0.5) )
|
||||
POLY2.setMinimalSize ( l(1.0) )
|
||||
POLY2.setExtentionCap ( poly , l(0.5) )
|
||||
|
||||
METAL1 .setMinimalSize ( l(1.0) )
|
||||
METAL1 .setExtentionCap ( metal1 , l(1.0) )
|
||||
METAL2 .setMinimalSize ( l(1.0) )
|
||||
METAL2 .setExtentionCap ( metal2 , l(1.0) )
|
||||
METAL3 .setMinimalSize ( l(1.0) )
|
||||
METAL3 .setExtentionCap ( metal3 , l(1.0) )
|
||||
METAL4 .setMinimalSize ( l(1.0) )
|
||||
METAL4 .setExtentionCap ( metal4 , l(1.0) )
|
||||
METAL4 .setMinimalSpacing( l(3.0) )
|
||||
METAL5 .setMinimalSize ( l(2.0) )
|
||||
METAL5 .setExtentionCap ( metal5 , l(1.0) )
|
||||
METAL6 .setMinimalSize ( l(2.0) )
|
||||
METAL6 .setExtentionCap ( metal6 , l(1.0) )
|
||||
METAL7 .setMinimalSize ( l(2.0) )
|
||||
METAL7 .setExtentionCap ( metal7 , l(1.0) )
|
||||
METAL8 .setMinimalSize ( l(2.0) )
|
||||
METAL8 .setExtentionCap ( metal8 , l(1.0) )
|
||||
METAL9 .setMinimalSize ( l(2.0) )
|
||||
METAL9 .setExtentionCap ( metal9 , l(1.0) )
|
||||
METAL10.setMinimalSize ( l(2.0) )
|
||||
METAL10.setExtentionCap ( metal10 , l(1.0) )
|
||||
|
||||
# Contacts (i.e. Active <--> Metal) (symbolic).
|
||||
CONT_BODY_N.setMinimalSize( l( 1.0) )
|
||||
#CONT_BODY_N.setEnclosure ( nWell , l( 1.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
CONT_BODY_N.setEnclosure ( nImplant, l( 1.0), Layer.EnclosureH|Layer.EnclosureV )
|
||||
CONT_BODY_N.setEnclosure ( cut0 , l( 0.0), Layer.EnclosureH|Layer.EnclosureV )
|
||||
CONT_BODY_N.setEnclosure ( active , l( 1.0), Layer.EnclosureH|Layer.EnclosureV )
|
||||
CONT_BODY_N.setEnclosure ( metal1 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
|
||||
CONT_BODY_P.setMinimalSize( l( 1.0) )
|
||||
#CONT_BODY_P.setEnclosure ( pWell , l( 1.0), Layer.EnclosureH|Layer.EnclosureV )
|
||||
CONT_BODY_P.setEnclosure ( pImplant, l( 1.0), Layer.EnclosureH|Layer.EnclosureV )
|
||||
CONT_BODY_P.setEnclosure ( cut0 , l( 0.0), Layer.EnclosureH|Layer.EnclosureV )
|
||||
CONT_BODY_P.setEnclosure ( active , l( 1.0), Layer.EnclosureH|Layer.EnclosureV )
|
||||
CONT_BODY_P.setEnclosure ( metal1 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
|
||||
CONT_DIF_N.setMinimalSize( l( 1.0) )
|
||||
CONT_DIF_N.setEnclosure ( nImplant, l( 1.0), Layer.EnclosureH|Layer.EnclosureV )
|
||||
CONT_DIF_N.setEnclosure ( cut0 , l( 0.0), Layer.EnclosureH|Layer.EnclosureV )
|
||||
CONT_DIF_N.setEnclosure ( active , l( 1.0), Layer.EnclosureH|Layer.EnclosureV )
|
||||
CONT_DIF_N.setEnclosure ( metal1 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
|
||||
CONT_DIF_P.setMinimalSize( l( 1.0) )
|
||||
CONT_DIF_P.setEnclosure ( pImplant, l( 1.0), Layer.EnclosureH|Layer.EnclosureV )
|
||||
CONT_DIF_P.setEnclosure ( cut0 , l( 0.0), Layer.EnclosureH|Layer.EnclosureV )
|
||||
CONT_DIF_P.setEnclosure ( active , l( 1.0), Layer.EnclosureH|Layer.EnclosureV )
|
||||
CONT_DIF_P.setEnclosure ( metal1 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
|
||||
CONT_POLY.setMinimalSize( l( 1.0) )
|
||||
CONT_POLY.setEnclosure ( poly , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
CONT_POLY.setEnclosure ( metal1 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
|
||||
# VIAs (i.e. Metal <--> Metal) (symbolic).
|
||||
VIA12 .setMinimalSize ( l( 1.0) )
|
||||
VIA12 .setEnclosure ( metal1 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA12 .setEnclosure ( metal2 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA12 .setMinimalSpacing( l( 4.0) )
|
||||
VIA23 .setMinimalSize ( l( 1.0) )
|
||||
VIA23 .setEnclosure ( metal2 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA23 .setEnclosure ( metal3 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA23 .setMinimalSpacing( l( 4.0) )
|
||||
VIA34 .setMinimalSize ( l( 1.0) )
|
||||
VIA34 .setEnclosure ( metal3 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA34 .setEnclosure ( metal4 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA34 .setMinimalSpacing( l( 4.0) )
|
||||
VIA45 .setMinimalSize ( l( 1.0) )
|
||||
VIA45 .setEnclosure ( metal4 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA45 .setEnclosure ( metal5 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA45 .setMinimalSpacing( l( 4.0) )
|
||||
VIA56 .setMinimalSize ( l( 1.0) )
|
||||
VIA56 .setEnclosure ( metal5 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA56 .setEnclosure ( metal6 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA56 .setMinimalSpacing( l( 4.0) )
|
||||
VIA67 .setMinimalSize ( l( 1.0) )
|
||||
VIA67 .setEnclosure ( metal6 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA67 .setEnclosure ( metal7 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA67 .setMinimalSpacing( l( 4.0) )
|
||||
VIA78 .setMinimalSpacing( l( 4.0) )
|
||||
VIA78 .setMinimalSize ( l( 1.0) )
|
||||
VIA78 .setEnclosure ( metal7 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA78 .setEnclosure ( metal8 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA78 .setMinimalSpacing( l( 4.0) )
|
||||
VIA89 .setMinimalSize ( l( 1.0) )
|
||||
VIA89 .setEnclosure ( metal8 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA89 .setEnclosure ( metal9 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA89 .setMinimalSpacing( l( 4.0) )
|
||||
VIA910.setMinimalSize ( l( 1.0) )
|
||||
VIA910.setEnclosure ( metal9 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA910.setEnclosure ( metal10 , l( 0.5), Layer.EnclosureH|Layer.EnclosureV )
|
||||
VIA910.setMinimalSpacing( l( 4.0) )
|
||||
|
||||
# Blockages (symbolic).
|
||||
BLOCKAGE1 .setMinimalSize ( l( 1.0) )
|
||||
BLOCKAGE1 .setExtentionCap( blockage1 , l( 0.5) )
|
||||
BLOCKAGE2 .setMinimalSize ( l( 2.0) )
|
||||
BLOCKAGE2 .setExtentionCap( blockage2 , l( 0.5) )
|
||||
BLOCKAGE3 .setMinimalSize ( l( 2.0) )
|
||||
BLOCKAGE3 .setExtentionCap( blockage3 , l( 0.5) )
|
||||
BLOCKAGE4 .setMinimalSize ( l( 2.0) )
|
||||
BLOCKAGE4 .setExtentionCap( blockage4 , l( 0.5) )
|
||||
BLOCKAGE5 .setMinimalSize ( l( 2.0) )
|
||||
BLOCKAGE5 .setExtentionCap( blockage5 , l( 1.0) )
|
||||
BLOCKAGE6 .setMinimalSize ( l( 2.0) )
|
||||
BLOCKAGE6 .setExtentionCap( blockage6 , l( 1.0) )
|
||||
BLOCKAGE7 .setMinimalSize ( l( 2.0) )
|
||||
BLOCKAGE7 .setExtentionCap( blockage7 , l( 1.0) )
|
||||
BLOCKAGE8 .setMinimalSize ( l( 2.0) )
|
||||
BLOCKAGE8 .setExtentionCap( blockage8 , l( 1.0) )
|
||||
BLOCKAGE9 .setMinimalSize ( l( 2.0) )
|
||||
BLOCKAGE9 .setExtentionCap( blockage9 , l( 1.0) )
|
||||
BLOCKAGE10.setMinimalSize ( l( 2.0) )
|
||||
BLOCKAGE10.setExtentionCap( blockage10, l( 1.0) )
|
||||
|
||||
|
||||
gdsLayersTable = \
|
||||
[ ("nWell" , "LNWELL" , 1, 0)
|
||||
, ("nImplant", "LNIF" , 3, 0)
|
||||
, ("pImplant", "LPDIF" , 4, 0)
|
||||
, ("active" , "LACTIVE" , 2, 0)
|
||||
, ("poly" , "LPOLY" , 7, 0)
|
||||
, ("cut0" , "LCONT" , 10, 0)
|
||||
, ("metal1" , "LALU1" , 11, 0)
|
||||
, ("cut1" , "LVIA" , 14, 0)
|
||||
, ("metal2" , "LALU2" , 16, 0)
|
||||
, ("cut2" , "LVIA2" , 18, 0)
|
||||
, ("metal3" , "LALU3" , 19, 0)
|
||||
, ("cut3" , "LVIA3" , 21, 0)
|
||||
, ("metal4" , "LALU4" , 22, 0)
|
||||
, ("cut4" , "LVIA4" , 25, 0)
|
||||
, ("metal5" , "LALU5" , 26, 0)
|
||||
, ("cut5" , "LVIA5" , 28, 0)
|
||||
, ("metal6" , "LALU6" , 29, 0)
|
||||
]
|
||||
|
||||
|
||||
loadGdsLayers( gdsLayersTable )
|
|
@ -191,8 +191,9 @@ namespace CRL {
|
|||
bool ToolEngine::_inDestroyAll = false;
|
||||
|
||||
|
||||
ToolEngine::ToolEngine ( Cell* cell )
|
||||
ToolEngine::ToolEngine ( Cell* cell, bool verbose )
|
||||
: Super()
|
||||
, _verbose (verbose)
|
||||
, _cell (cell)
|
||||
, _placementModificationFlag(0)
|
||||
, _routingModificationFlag (0)
|
||||
|
@ -219,11 +220,13 @@ namespace CRL {
|
|||
|
||||
put( enginesRelation );
|
||||
|
||||
cmess1 << " o Creating ToolEngine<" << getName() << "> for Cell <"
|
||||
<< _cell->getName() << ">" << endl;
|
||||
|
||||
cmess1 << Dots::asString( " - Initial memory"
|
||||
, Timer::getStringMemory(Timer::getMemorySize()) ) << endl;
|
||||
if (_verbose) {
|
||||
cmess1 << " o Creating ToolEngine<" << getName() << "> for Cell <"
|
||||
<< _cell->getName() << ">" << endl;
|
||||
|
||||
cmess1 << Dots::asString( " - Initial memory"
|
||||
, Timer::getStringMemory(Timer::getMemorySize()) ) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,8 +29,9 @@ namespace CRL {
|
|||
|
||||
class LefImport {
|
||||
public:
|
||||
static void reset ();
|
||||
static Hurricane::Library* load ( std::string fileName );
|
||||
static void reset ();
|
||||
static Hurricane::Library* load ( std::string fileName );
|
||||
static void setMergeLibrary ( Hurricane::Library* );
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -81,13 +81,14 @@ namespace CRL {
|
|||
protected:
|
||||
Cell* _cell;
|
||||
private:
|
||||
bool _verbose;
|
||||
unsigned int _placementModificationFlag;
|
||||
unsigned int _routingModificationFlag;
|
||||
bool _inRelationDestroy;
|
||||
Timer _timer;
|
||||
uint32_t _passNumber;
|
||||
protected:
|
||||
ToolEngine ( Cell* cell );
|
||||
ToolEngine ( Cell* cell, bool verbose=true );
|
||||
virtual void _postCreate ();
|
||||
virtual void _preDestroy ();
|
||||
protected:
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "hurricane/Contact.h"
|
||||
#include "hurricane/Horizontal.h"
|
||||
#include "hurricane/Vertical.h"
|
||||
#include "hurricane/Rectilinear.h"
|
||||
#include "hurricane/Cell.h"
|
||||
#include "hurricane/Library.h"
|
||||
#include "hurricane/UpdateSession.h"
|
||||
|
@ -71,6 +72,7 @@ namespace {
|
|||
|
||||
class LefParser {
|
||||
public:
|
||||
static void setMergeLibrary ( Library* );
|
||||
static DbU::Unit fromLefUnits ( int );
|
||||
static Layer* getLayer ( string );
|
||||
static void addLayer ( string, Layer* );
|
||||
|
@ -108,8 +110,8 @@ namespace {
|
|||
inline int getNthRouting () const;
|
||||
inline void incNthRouting ();
|
||||
inline RoutingGauge* getRoutingGauge () const;
|
||||
inline void addPinSegment ( string name, Segment* );
|
||||
inline void clearPinSegments ();
|
||||
inline void addPinComponent ( string name, Component* );
|
||||
inline void clearPinComponents ();
|
||||
private:
|
||||
static int _unitsCbk ( lefrCallbackType_e, lefiUnits* , lefiUserData );
|
||||
static int _layerCbk ( lefrCallbackType_e, lefiLayer* , lefiUserData );
|
||||
|
@ -121,6 +123,7 @@ namespace {
|
|||
void _pinStdPostProcess ();
|
||||
void _pinPadPostProcess ();
|
||||
private:
|
||||
static Library* _mergeLibrary;
|
||||
string _file;
|
||||
string _libraryName;
|
||||
Library* _library;
|
||||
|
@ -128,7 +131,7 @@ namespace {
|
|||
Net* _net;
|
||||
string _busBits;
|
||||
double _unitsMicrons;
|
||||
map< string, vector<Segment*> > _pinSegments;
|
||||
map< string, vector<Component*> > _pinComponents;
|
||||
static map<string,Layer*> _layerLut;
|
||||
vector<string> _unmatchedLayers;
|
||||
vector<string> _errors;
|
||||
|
@ -170,15 +173,20 @@ namespace {
|
|||
inline const vector<string>& LefParser::getErrors () const { return _errors; }
|
||||
inline void LefParser::pushError ( const string& error ) { _errors.push_back(error); }
|
||||
inline void LefParser::clearErrors () { return _errors.clear(); }
|
||||
inline void LefParser::addPinSegment ( string name, Segment* s ) { _pinSegments[name].push_back(s); }
|
||||
inline void LefParser::clearPinSegments () { _pinSegments.clear(); }
|
||||
inline void LefParser::addPinComponent ( string name, Component* comp ) { _pinComponents[name].push_back(comp); }
|
||||
inline void LefParser::clearPinComponents () { _pinComponents.clear(); }
|
||||
|
||||
|
||||
Library* LefParser::_mergeLibrary = nullptr;
|
||||
map<string,Layer*> LefParser::_layerLut;
|
||||
DbU::Unit LefParser::_coreSiteX = 0;
|
||||
DbU::Unit LefParser::_coreSiteY = 0;
|
||||
|
||||
|
||||
void LefParser::setMergeLibrary ( Library* library )
|
||||
{ _mergeLibrary = library; }
|
||||
|
||||
|
||||
void LefParser::reset ()
|
||||
{
|
||||
_layerLut.clear();
|
||||
|
@ -272,6 +280,11 @@ namespace {
|
|||
|
||||
Library* LefParser::createLibrary ()
|
||||
{
|
||||
if (_mergeLibrary) {
|
||||
_library = _mergeLibrary;
|
||||
return _library;
|
||||
}
|
||||
|
||||
DataBase* db = DataBase::getDB();
|
||||
Library* rootLibrary = db->getRootLibrary();
|
||||
if (not rootLibrary) rootLibrary = Library::create( db, "RootLibrary" );
|
||||
|
@ -499,6 +512,19 @@ namespace {
|
|||
}
|
||||
cdebug_log(100,0) << "| " << segment << endl;
|
||||
}
|
||||
|
||||
if (geoms->itemType(igeom) == lefiGeomPolygonE) {
|
||||
lefiGeomPolygon* polygon = geoms->getPolygon(igeom);
|
||||
vector<Point> points;
|
||||
for ( int ipoint=0 ; ipoint<polygon->numPoints ; ++ipoint ) {
|
||||
points.push_back( Point( parser->fromUnitsMicrons(polygon->x[ipoint])
|
||||
, parser->fromUnitsMicrons(polygon->y[ipoint]) ));
|
||||
}
|
||||
points.push_back( Point( parser->fromUnitsMicrons(polygon->x[0])
|
||||
, parser->fromUnitsMicrons(polygon->y[0]) ));
|
||||
Rectilinear::create( blockageNet, blockageLayer, points );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -553,7 +579,7 @@ namespace {
|
|||
|
||||
if (not isPad) parser->_pinStdPostProcess();
|
||||
else parser->_pinPadPostProcess();
|
||||
parser->clearPinSegments();
|
||||
parser->clearPinComponents();
|
||||
|
||||
cerr << " - " << cellName
|
||||
<< " " << DbU::getValueString(width) << " " << DbU::getValueString(height)
|
||||
|
@ -643,10 +669,23 @@ namespace {
|
|||
, parser->fromUnitsMicrons( r->yh )
|
||||
);
|
||||
}
|
||||
if (segment) parser->addPinSegment( pin->name(), segment );
|
||||
if (segment) parser->addPinComponent( pin->name(), segment );
|
||||
//cerr << " | " << segment << endl;
|
||||
continue;
|
||||
}
|
||||
if (geoms->itemType(igeom) == lefiGeomPolygonE) {
|
||||
lefiGeomPolygon* polygon = geoms->getPolygon(igeom);
|
||||
vector<Point> points;
|
||||
for ( int ipoint=0 ; ipoint<polygon->numPoints ; ++ipoint ) {
|
||||
points.push_back( Point( parser->fromUnitsMicrons(polygon->x[ipoint])
|
||||
, parser->fromUnitsMicrons(polygon->y[ipoint]) ));
|
||||
}
|
||||
points.push_back( Point( parser->fromUnitsMicrons(polygon->x[0])
|
||||
, parser->fromUnitsMicrons(polygon->y[0]) ));
|
||||
Rectilinear* rectilinear = Rectilinear::create( net, layer, points );
|
||||
if (rectilinear) parser->addPinComponent( pin->name(), rectilinear );
|
||||
continue;
|
||||
}
|
||||
if (geoms->itemType(igeom) == lefiGeomClassE) {
|
||||
// Ignore CLASS <site>. Deduced from segments positions.
|
||||
continue;
|
||||
|
@ -688,20 +727,27 @@ namespace {
|
|||
const RoutingLayerGauge* gaugeMetal2 = _routingGauge->getLayerGauge( 1 );
|
||||
Box ab = _cell->getAbutmentBox();
|
||||
|
||||
//cerr << " @ _pinStdPostProcess" << endl;
|
||||
cerr << " @ _pinStdPostProcess" << endl;
|
||||
|
||||
for ( auto element : _pinSegments ) {
|
||||
string pinName = element.first;
|
||||
vector<Segment*>& segments = element.second;
|
||||
vector<Segment*> ongrids;
|
||||
for ( auto element : _pinComponents ) {
|
||||
string pinName = element.first;
|
||||
vector<Component*>& components = element.second;
|
||||
vector<Segment*> ongrids;
|
||||
|
||||
for ( Segment* segment : segments ) {
|
||||
bool isWide = (segment->getWidth() >= getMinTerminalWidth());
|
||||
for ( Component* component : components ) {
|
||||
Segment* segment = dynamic_cast<Segment*>( component );
|
||||
if (segment) {
|
||||
if (component->getNet()->isSupply()) continue;
|
||||
bool isWide = (segment->getWidth() >= getMinTerminalWidth());
|
||||
|
||||
//cerr << " > " << segment << endl;
|
||||
cerr << " > " << segment << endl;
|
||||
if (not isVH())
|
||||
cerr << "NOT isVH()" << endl;
|
||||
else
|
||||
cerr << "isVH()" << endl;
|
||||
|
||||
if (not segment->getNet()->isSupply()) {
|
||||
if (isVH() and (segment->getLayer()->getMask() == metal1->getMask())) {
|
||||
cerr << "isVH()" << endl;
|
||||
Vertical* v = dynamic_cast<Vertical*>( segment );
|
||||
if (v) {
|
||||
DbU::Unit nearestX = gaugeMetal2->getTrackPosition( ab.getXMin()
|
||||
|
@ -712,7 +758,7 @@ namespace {
|
|||
if (nearestX == v->getX()) {
|
||||
} else {
|
||||
DbU::Unit neighbor = nearestX
|
||||
+ ((nearestX > v->getX()) ? 1 : -1) * gaugeMetal2->getPitch();
|
||||
+ ((nearestX > v->getX()) ? 1 : -1) * gaugeMetal2->getPitch();
|
||||
|
||||
//cerr << " | X:" << DbU::getValueString(v->getX())
|
||||
// << " nearestX:" << DbU::getValueString(nearestX)
|
||||
|
@ -738,16 +784,67 @@ namespace {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isWide) ongrids.push_back( segment );
|
||||
if (isWide) ongrids.push_back( segment );
|
||||
}
|
||||
Rectilinear* rectilinear = dynamic_cast<Rectilinear*>( component );
|
||||
if (not (rectilinear->getLayer()->getMask() == metal1->getMask()))
|
||||
continue;
|
||||
|
||||
if (rectilinear) {
|
||||
cerr << " > " << rectilinear << endl;
|
||||
vector<Box> boxes;
|
||||
rectilinear->getAsRectangles( boxes );
|
||||
|
||||
if (component->getNet()->isSupply()) {
|
||||
ongrids.push_back( Horizontal::create( rectilinear->getNet()
|
||||
, rectilinear->getLayer()
|
||||
, boxes.front().getYCenter()
|
||||
, boxes.front().getHeight()
|
||||
, _cell->getAbutmentBox().getXMin()
|
||||
, _cell->getAbutmentBox().getXMax()
|
||||
)
|
||||
);
|
||||
} else {
|
||||
for ( const Box& box : boxes ) {
|
||||
DbU::Unit nearestX = gaugeMetal2->getTrackPosition( ab.getXMin()
|
||||
, ab.getXMax()
|
||||
, box.getXCenter()
|
||||
, Constant::Nearest );
|
||||
DbU::Unit xmin = std::min( box.getXMin(), nearestX - gaugeMetal2->getViaWidth()/2 );
|
||||
DbU::Unit xmax = std::max( box.getXMax(), nearestX + gaugeMetal2->getViaWidth()/2 );
|
||||
ongrids.push_back( Vertical::create( rectilinear->getNet()
|
||||
, rectilinear->getLayer()
|
||||
, (xmax+xmin)/2
|
||||
, xmax-xmin
|
||||
, box.getYMin()
|
||||
, box.getYMax()
|
||||
)
|
||||
);
|
||||
// DbU::Unit neighbor = nearestY
|
||||
// + ((nearestY > box.getYCenter()) ? 1 : -1) * gaugeMetal2->getPitch();
|
||||
|
||||
// if ( (box.getYMin() > neighbor)
|
||||
// or (box.getYMax() < neighbor) ) {
|
||||
// ongrids.push_back( Vertical::create( rectilinear->getNet()
|
||||
// , rectilinear->getLayer()
|
||||
// , box.getXCenter()
|
||||
// , box.getWidth()
|
||||
// , box.getYMin()
|
||||
// , box.getYMax()
|
||||
// )
|
||||
// );
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ongrids.empty()) {
|
||||
cerr << Warning( "LefParser::_pinStdPostProcess(): Pin \"%s\" has no terminal ongrid."
|
||||
, pinName.c_str() ) << endl;
|
||||
for ( Segment* segment : segments ) {
|
||||
NetExternalComponents::setExternal( segment );
|
||||
for ( Component* component : components ) {
|
||||
NetExternalComponents::setExternal( component );
|
||||
}
|
||||
} else {
|
||||
for ( Segment* segment : ongrids ) {
|
||||
|
@ -763,10 +860,10 @@ namespace {
|
|||
Box ab = getCell()->getAbutmentBox();
|
||||
bool isCornerPad = (_cellGauge) and (_cellGauge->getSliceHeight() == _cellGauge->getSliceStep());
|
||||
|
||||
for ( auto element : _pinSegments ) {
|
||||
string pinName = element.first;
|
||||
vector<Segment*>& segments = element.second;
|
||||
vector<Segment*> ongrids;
|
||||
for ( auto element : _pinComponents ) {
|
||||
string pinName = element.first;
|
||||
vector<Component*>& segments = element.second;
|
||||
vector<Segment*> ongrids;
|
||||
|
||||
if (segments.empty()) continue;
|
||||
|
||||
|
@ -963,4 +1060,12 @@ namespace CRL {
|
|||
}
|
||||
|
||||
|
||||
void LefImport::setMergeLibrary ( Library* library )
|
||||
{
|
||||
#if defined(HAVE_LEFDEF)
|
||||
LefParser::setMergeLibrary( library );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
} // End of CRL namespace.
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
# -*- explicit-buffer-name: "CMakeLists.txt<crlcore/src/ccore/cyclop>" -*-
|
||||
|
||||
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development)
|
||||
include_directories ( ${CRLCORE_SOURCE_DIR}/src/ccore
|
||||
${HURRICANE_INCLUDE_DIR}
|
||||
${UTILITIES_INCLUDE_DIR}
|
||||
|
|
|
@ -32,8 +32,6 @@
|
|||
-lutil
|
||||
)
|
||||
|
||||
find_package (Python3 COMPONENTS Interpreter Development)
|
||||
|
||||
add_definitions( -DCORIOLIS_TOP="${CORIOLIS_TOP}"
|
||||
-DSYS_CONF_DIR="${SYS_CONF_DIR}"
|
||||
-DPYTHON_SITE_PACKAGES="${PYTHON_SITE_PACKAGES}"
|
||||
|
|
|
@ -43,6 +43,8 @@ namespace CRL {
|
|||
using Isobar::ParseTwoArg;
|
||||
using Isobar::__cs;
|
||||
using Isobar::PyLibrary_Link;
|
||||
using Isobar::PyTypeLibrary;
|
||||
using Isobar::PyLibrary;
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
@ -86,14 +88,37 @@ extern "C" {
|
|||
}
|
||||
|
||||
|
||||
static PyObject* PyLefImport_setMergeLibrary ( PyObject*, PyObject* args )
|
||||
{
|
||||
cdebug_log(30,0) << "PyLefImport_setMergeLibrary()" << endl;
|
||||
HTRY
|
||||
PyObject* pyLibrary = NULL;
|
||||
if (PyArg_ParseTuple( args, "O:LefImport.setMergeLibrary", &pyLibrary )) {
|
||||
if (IsPyLibrary(pyLibrary)) {
|
||||
LefImport::setMergeLibrary( PYLIBRARY_O(pyLibrary) );
|
||||
} else {
|
||||
PyErr_SetString( ConstructorError, "LefImport.setMergeLibrary(): Bad parameter type (not a Library)." );
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
PyErr_SetString( ConstructorError, "LefImport.setMergeLibrary(): Bad number of parameters." );
|
||||
return NULL;
|
||||
}
|
||||
HCATCH
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
// Standart Destroy (Attribute).
|
||||
|
||||
|
||||
PyMethodDef PyLefImport_Methods[] =
|
||||
{ { "load" , (PyCFunction)PyLefImport_load , METH_VARARGS|METH_STATIC
|
||||
{ { "load" , (PyCFunction)PyLefImport_load , METH_VARARGS|METH_STATIC
|
||||
, "Load a complete Cadence LEF library." }
|
||||
, { "reset" , (PyCFunction)PyLefImport_reset , METH_NOARGS|METH_STATIC
|
||||
, { "reset" , (PyCFunction)PyLefImport_reset , METH_NOARGS|METH_STATIC
|
||||
, "Reset the Cadence LEF parser (clear technology)." }
|
||||
, { "setMergeLibrary" , (PyCFunction)PyLefImport_setMergeLibrary, METH_VARARGS|METH_STATIC
|
||||
, "Merge into this library instead of creating a new one." }
|
||||
//, { "destroy" , (PyCFunction)PyLefImport_destroy , METH_VARARGS
|
||||
// , "Destroy the associated hurricane object. The python object remains." }
|
||||
, {NULL, NULL, 0, NULL} /* sentinel */
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# -*- explicit-buffer-name: "CMakeLists.txt<crlcore/src/x2y> -*-
|
||||
|
||||
|
||||
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development)
|
||||
include_directories ( ${CRLCORE_SOURCE_DIR}/src/ccore
|
||||
${HURRICANE_INCLUDE_DIR}
|
||||
${UTILITIES_INCLUDE_DIR}
|
||||
|
|
|
@ -64,7 +64,7 @@ class PnR ( FlowTask ):
|
|||
else:
|
||||
print( 'PnR.doTask() run in interactive CGT mode.' )
|
||||
PnR.textMode = False
|
||||
from .. import Etesian, Anabatic, Katana, Bora, Tutorial, Viewer, Unicorn
|
||||
from .. import Etesian, Anabatic, Katana, Bora, Tramontana, Tutorial, Viewer, Unicorn
|
||||
|
||||
ShellEnv().export()
|
||||
if self.script and not callable(self.script):
|
||||
|
@ -80,8 +80,8 @@ class PnR ( FlowTask ):
|
|||
unicorn = Unicorn.UnicornGui.create()
|
||||
unicorn.setApplicationName ( 'cgt')
|
||||
unicorn.registerTool ( Etesian.GraphicEtesianEngine.grab() )
|
||||
#unicorn.registerTool ( Kite.GraphicKiteEngine.grab() )
|
||||
unicorn.registerTool ( Katana.GraphicKatanaEngine.grab() )
|
||||
unicorn.registerTool ( Tramontana.GraphicTramontanaEngine.grab() )
|
||||
unicorn.registerTool ( Bora.GraphicBoraEngine.grab() )
|
||||
unicorn.registerTool ( Tutorial.GraphicTutorialEngine.grab() )
|
||||
#unicorn.setAnonNetSelectable(False)
|
||||
|
|
|
@ -69,7 +69,13 @@ class ShellEnv ( object ):
|
|||
self.shellEnv[ 'MBK_CATAL_NAME' ] = env.getCATALOG()
|
||||
self.shellEnv[ 'RDS_IN' ] = 'gds'
|
||||
self.shellEnv[ 'RDS_OUT' ] = 'gds'
|
||||
self.shellEnv[ 'ALLIANCE_TOP' ] = ShellEnv.ALLIANCE_TOP
|
||||
if ShellEnv.ALLIANCE_TOP:
|
||||
self.shellEnv[ 'ALLIANCE_TOP' ] = ShellEnv.ALLIANCE_TOP
|
||||
libPath = ShellEnv.ALLIANCE_TOP + '/lib'
|
||||
LD_LIBRARY_PATH = os.environ[ 'LD_LIBRARY_PATH' ]
|
||||
if LD_LIBRARY_PATH != '':
|
||||
libPath += ':' + LD_LIBRARY_PATH
|
||||
self.shellEnv[ 'LD_LIBRARY_PATH' ] = libPath
|
||||
|
||||
def export ( self ):
|
||||
"""
|
||||
|
|
|
@ -42,15 +42,16 @@ class Where ( object ):
|
|||
return '<Where coriolisTop="{}">'.format( Where.coriolisTop.as_posix() )
|
||||
|
||||
|
||||
def setupCMOS ():
|
||||
def setupCMOS ( checkToolkit=None ):
|
||||
Where( checkToolkit )
|
||||
ShellEnv().export()
|
||||
|
||||
from .. import Cfg
|
||||
from .. import Viewer
|
||||
from .. import CRL
|
||||
from ..helpers import overlay, l, u, n
|
||||
from .yosys import Yosys
|
||||
import coriolis.technos.symbolic.cmos
|
||||
|
||||
Where()
|
||||
|
||||
with overlay.CfgCache(priority=Cfg.Parameter.Priority.UserFile) as cfg:
|
||||
cfg.misc.catchCore = False
|
||||
|
@ -81,6 +82,46 @@ def setupCMOS ():
|
|||
break
|
||||
|
||||
|
||||
def setupLCMOS ( checkToolkit=None ):
|
||||
Where( checkToolkit )
|
||||
ShellEnv().export()
|
||||
|
||||
from .. import Cfg
|
||||
from .. import Viewer
|
||||
from .. import CRL
|
||||
from ..helpers import overlay, l, u, n
|
||||
from .yosys import Yosys
|
||||
import coriolis.technos.symbolic.lcmos
|
||||
|
||||
with overlay.CfgCache(priority=Cfg.Parameter.Priority.UserFile) as cfg:
|
||||
cfg.misc.catchCore = False
|
||||
cfg.misc.info = False
|
||||
cfg.misc.paranoid = False
|
||||
cfg.misc.bug = False
|
||||
cfg.misc.logMode = True
|
||||
cfg.misc.verboseLevel1 = True
|
||||
cfg.misc.verboseLevel2 = True
|
||||
cfg.misc.minTraceLevel = 1900
|
||||
cfg.misc.maxTraceLevel = 3000
|
||||
cfg.katana.eventsLimit = 1000000
|
||||
cfg.katana.termSatReservedLocal = 6
|
||||
cfg.katana.termSatThreshold = 9
|
||||
Viewer.Graphics.setStyle( 'Alliance.Classic [black]' )
|
||||
af = CRL.AllianceFramework.get()
|
||||
env = af.getEnvironment()
|
||||
env.setCLOCK( '^ck$|m_clock|^clk$' )
|
||||
|
||||
Yosys.setLiberty( Where.checkToolkit / 'cells' / 'lsxlib' / 'lsxlib.lib' )
|
||||
ShellEnv.RDS_TECHNO_NAME = (Where.allianceTop / 'etc' / 'cmos.rds').as_posix()
|
||||
|
||||
path = None
|
||||
for pathVar in [ 'PATH', 'path' ]:
|
||||
if pathVar in os.environ:
|
||||
path = os.environ[ pathVar ]
|
||||
os.environ[ pathVar ] = path + ':' + (Where.allianceTop / 'bin').as_posix()
|
||||
break
|
||||
|
||||
|
||||
def setupCMOS45 ( useNsxlib=False, checkToolkit=None, cellsTop=None ):
|
||||
from .. import Cfg
|
||||
from .. import Viewer
|
||||
|
@ -189,6 +230,7 @@ def setupSky130_c4m ( checkToolkit=None, pdkMasterTop=None ):
|
|||
cfg.misc.logMode = True
|
||||
cfg.misc.verboseLevel1 = False
|
||||
cfg.misc.verboseLevel2 = False
|
||||
cfg.viewer.pixelThreshold = 5
|
||||
cfg.etesian.graphics = 2
|
||||
cfg.anabatic.topRoutingLayer = 'm4'
|
||||
cfg.katana.eventsLimit = 4000000
|
||||
|
@ -294,7 +336,7 @@ def setupTSMC_c180_c4m ( checkToolkit=None, ndaTop=None ):
|
|||
cfg.misc.verboseLevel1 = True
|
||||
cfg.misc.verboseLevel2 = True
|
||||
cfg.etesian.graphics = 3
|
||||
cfg.etesian.uniformDensity = True
|
||||
cfg.etesian.densityVariation = 0.04
|
||||
cfg.etesian.spaceMargin = 0.04
|
||||
cfg.katana.eventsLimit = 4000000
|
||||
af = CRL.AllianceFramework.get()
|
||||
|
@ -303,3 +345,52 @@ def setupTSMC_c180_c4m ( checkToolkit=None, ndaTop=None ):
|
|||
|
||||
Yosys.setLiberty( liberty )
|
||||
ShellEnv.CHECK_TOOLKIT = Where.checkToolkit.as_posix()
|
||||
|
||||
|
||||
def setupGF180MCU_GF ( checkToolkit=None, pdkTop=None ):
|
||||
from .. import Cfg
|
||||
from .. import Viewer
|
||||
from .. import CRL
|
||||
from ..helpers import setNdaTopDir, overlay, l, u, n
|
||||
from .yosys import Yosys
|
||||
|
||||
if isinstance(pdkTop,str):
|
||||
pdkTop = Path( pdkTop )
|
||||
if not pdkTop:
|
||||
print( '[ERROR] technos.setupGF180MCU_GF(): pdkTop directory has *not* been set.' )
|
||||
if not pdkTop.is_dir():
|
||||
print( '[ERROR] technos.setupSky130_c4m(): pdkTop directory do *not* exists:' )
|
||||
print( ' "{}"'.format(pdkTop.as_posix()) )
|
||||
|
||||
Where( checkToolkit )
|
||||
|
||||
cellsTop = pdkTop / 'libraries' / 'gf180mcu_fd_sc_mcu9t5v0' / 'latest' / 'cells'
|
||||
#liberty = pdkTop / 'libraries' / 'gf180mcu_fd_sc_mcu9t5v0' / 'latest' / 'liberty' / 'gf180mcu_fd_sc_mcu9t5v0__tt_025C_5v00.lib'
|
||||
liberty = pdkTop / 'FULL.lib'
|
||||
|
||||
from coriolis.technos.node180.gf180mcu import techno
|
||||
from coriolis.technos.node180.gf180mcu import mcu9t5v0
|
||||
techno.setup()
|
||||
mcu9t5v0.setup( cellsTop )
|
||||
|
||||
with overlay.CfgCache(priority=Cfg.Parameter.Priority.UserFile) as cfg:
|
||||
cfg.misc.catchCore = False
|
||||
cfg.misc.minTraceLevel = 12300
|
||||
cfg.misc.maxTraceLevel = 12400
|
||||
cfg.misc.info = False
|
||||
cfg.misc.paranoid = False
|
||||
cfg.misc.bug = False
|
||||
cfg.misc.logMode = True
|
||||
cfg.misc.verboseLevel1 = False
|
||||
cfg.misc.verboseLevel2 = False
|
||||
cfg.etesian.graphics = 2
|
||||
cfg.anabatic.topRoutingLayer = 'm4'
|
||||
cfg.katana.eventsLimit = 4000000
|
||||
af = CRL.AllianceFramework.get()
|
||||
#lg5 = af.getRoutingGauge( 'mcu9t' ).getLayerGauge( 5 )
|
||||
#lg5.setType( CRL.RoutingLayerGauge.PowerSupply )
|
||||
env = af.getEnvironment()
|
||||
env.setCLOCK( '^sys_clk$|^ck|^jtag_tck$' )
|
||||
|
||||
Yosys.setLiberty( liberty )
|
||||
ShellEnv.CHECK_TOOLKIT = Where.checkToolkit.as_posix()
|
||||
|
|
|
@ -36,15 +36,15 @@ You can configure the placer in two ways:
|
|||
.. code-block:: Python
|
||||
|
||||
with overlay.CfgCache(priority=Cfg.Parameter.Priority.UserFile) as cfg:
|
||||
cfg.etesian.effort = 2
|
||||
cfg.etesian.uniformDensity = True
|
||||
cfg.etesian.spaceMargin = 0.8
|
||||
cfg.etesian.aspectRatio = 1.0
|
||||
cfg.etesian.effort = 2
|
||||
cfg.etesian.spaceMargin = 0.8
|
||||
cfg.etesian.densityVariation = 0.1
|
||||
cfg.etesian.aspectRatio = 1.0
|
||||
|
||||
|
||||
With this setup, the cells will be spread uniformally over the
|
||||
area (``etesian.uniformDensity``), with ``80%`` of free space
|
||||
added and an aspect ratio of ``100%`` (square shape).
|
||||
With this setup, the placement will have ``80%`` of free space added and
|
||||
an aspect ratio of ``100%`` (square shape). Some variations in density
|
||||
is allowed, with at most ``10%`` unused space.
|
||||
|
||||
|
||||
8.1 Router -- Katana
|
||||
|
|
|
@ -176,11 +176,10 @@ Etesian Configuration Parameters
|
|||
| | The extra white space added to the total area |
|
||||
| | of the standard cells |
|
||||
+-----------------------------------+------------------+----------------------------+
|
||||
|``etesian.uniformDensity`` | TypeBool | :cb:`False` |
|
||||
|``etesian.densityVariation`` | TypePercentage | :cb:`5` |
|
||||
| +------------------+----------------------------+
|
||||
| | Whether the cells will be spread envenly |
|
||||
| | across the area or allowed to form denser |
|
||||
| | clusters |
|
||||
| | Control deviation from uniform density in the |
|
||||
| | placement, as a percentage of area. |
|
||||
+-----------------------------------+------------------+----------------------------+
|
||||
|``etesian.effort`` | TypeInt | :cb:`2` |
|
||||
| +------------------+----------------------------+
|
||||
|
|
|
@ -24,8 +24,8 @@ with overlay.CfgCache(priority=Cfg.Parameter.Priority.UserFile) as cfg:
|
|||
cfg.misc.minTraceLevel = 1900
|
||||
cfg.misc.maxTraceLevel = 3000
|
||||
cfg.etesian.effort = 2
|
||||
cfg.etesian.uniformDensity = True
|
||||
cfg.etesian.spaceMargin = 0.8
|
||||
cfg.etesian.densityVariation = 0.1
|
||||
cfg.etesian.aspectRatio = 1.0
|
||||
cfg.katana.eventsLimit = 1000000
|
||||
cfg.katana.termSatReservedLocal = 6
|
||||
|
|
|
@ -176,11 +176,10 @@ Etesian Configuration Parameters
|
|||
| | The extra white space added to the total area |
|
||||
| | of the standard cells |
|
||||
+-----------------------------------+------------------+----------------------------+
|
||||
|``etesian.uniformDensity`` | TypeBool | :cb:`False` |
|
||||
|``etesian.densityVariation`` | TypePercentage | :cb:`5` |
|
||||
| +------------------+----------------------------+
|
||||
| | Whether the cells will be spread envenly |
|
||||
| | across the area or allowed to form denser |
|
||||
| | clusters |
|
||||
| | Control deviation from uniform density in the |
|
||||
| | placement, as a percentage of area. |
|
||||
+-----------------------------------+------------------+----------------------------+
|
||||
|``etesian.effort`` | TypeInt | :cb:`2` |
|
||||
| +------------------+----------------------------+
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
|
||||
set_cmake_policies()
|
||||
setup_boost(program_options)
|
||||
setup_python()
|
||||
|
||||
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development)
|
||||
find_package(PythonSitePackages REQUIRED)
|
||||
find_package(HURRICANE REQUIRED)
|
||||
#find_package(KATABATIC REQUIRED)
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
${Boost_INCLUDE_DIRS}
|
||||
${Python_INCLUDE_DIRS}
|
||||
)
|
||||
find_package (Python3 COMPONENTS Interpreter Development)
|
||||
set( includes etesian/Configuration.h
|
||||
etesian/Placement.h
|
||||
etesian/FeedCells.h
|
||||
|
|
|
@ -56,13 +56,11 @@ namespace Etesian {
|
|||
, _placeEffort ( static_cast<Effort>
|
||||
(Cfg::getParamEnumerate ("etesian.effort" , Standard )->asInt()) )
|
||||
, _updateConf ( static_cast<GraphicUpdate>
|
||||
(Cfg::getParamEnumerate ("etesian.graphics" , LowerBound )->asInt()) )
|
||||
, _spreadingConf ( Cfg::getParamBool ("etesian.uniformDensity" , false )->asBool()? ForceUniform : MaxDensity )
|
||||
(Cfg::getParamEnumerate ("etesian.graphics" , FinalOnly )->asInt()) )
|
||||
, _routingDriven ( Cfg::getParamBool ("etesian.routingDriven" , false )->asBool())
|
||||
, _spaceMargin ( Cfg::getParamPercentage("etesian.spaceMargin" , 5.0)->asDouble() )
|
||||
, _densityVariation ( Cfg::getParamPercentage("etesian.densityVariation", 5.0)->asDouble() )
|
||||
, _aspectRatio ( Cfg::getParamPercentage("etesian.aspectRatio" ,100.0)->asDouble() )
|
||||
, _antennaInsertThreshold
|
||||
( Cfg::getParamDouble ("etesian.antennaInsertThreshold", 50.0)->asDouble() )
|
||||
, _tieName ( Cfg::getParamString ("etesian.tieName" ,"tie_x0" )->asString() )
|
||||
, _feedNames ( Cfg::getParamString ("etesian.feedNames" ,"tie_x0,rowend_x0")->asString() )
|
||||
, _diodeName ( Cfg::getParamString ("etesian.diodeName" ,"dio_x0" )->asString() )
|
||||
|
@ -107,18 +105,17 @@ namespace Etesian {
|
|||
, _cg (NULL)
|
||||
, _placeEffort ( other._placeEffort )
|
||||
, _updateConf ( other._updateConf )
|
||||
, _spreadingConf ( other._spreadingConf )
|
||||
, _spaceMargin ( other._spaceMargin )
|
||||
, _densityVariation ( other._densityVariation)
|
||||
, _aspectRatio ( other._aspectRatio )
|
||||
, _antennaInsertThreshold( other._antennaInsertThreshold )
|
||||
, _tieName ( other._tieName )
|
||||
, _feedNames ( other._feedNames )
|
||||
, _diodeName ( other._diodeName )
|
||||
, _spareBufferName ( other._spareBufferName )
|
||||
, _bloat ( other._bloat )
|
||||
, _latchUpDistance ( other._latchUpDistance )
|
||||
, _antennaGateMaxWL ( other._antennaGateMaxWL )
|
||||
, _antennaDiodeMaxWL( other._antennaDiodeMaxWL )
|
||||
, _antennaGateMaxWL ( other._antennaGateMaxWL )
|
||||
, _antennaDiodeMaxWL( other._antennaDiodeMaxWL)
|
||||
{
|
||||
if (other._rg) _rg = other._rg->getClone();
|
||||
if (other._cg) _cg = other._cg->getClone();
|
||||
|
@ -141,12 +138,11 @@ namespace Etesian {
|
|||
cmess1 << Dots::asIdentifier(" - Cell Gauge" ,getString(_cg->getName())) << endl;
|
||||
cmess1 << Dots::asInt (" - Place Effort" ,_placeEffort ) << endl;
|
||||
cmess1 << Dots::asInt (" - Update Conf" ,_updateConf ) << endl;
|
||||
cmess1 << Dots::asInt (" - Spreading Conf" ,_spreadingConf ) << endl;
|
||||
cmess1 << Dots::asBool (" - Routing driven" ,_routingDriven ) << endl;
|
||||
cmess1 << Dots::asPercentage(" - Space Margin" ,_spaceMargin ) << endl;
|
||||
cmess1 << Dots::asPercentage(" - Spread Margin" ,_densityVariation ) << endl;
|
||||
cmess1 << Dots::asPercentage(" - Aspect Ratio" ,_aspectRatio ) << endl;
|
||||
cmess1 << Dots::asString (" - Bloat model" ,_bloat ) << endl;
|
||||
cmess1 << Dots::asPercentage(" - Antenna Insert" ,_antennaInsertThreshold ) << endl;
|
||||
cmess1 << Dots::asString (" - Antenna gate Max. WL" ,DbU::getValueString(_antennaGateMaxWL )) << endl;
|
||||
cmess1 << Dots::asString (" - Antenna diode Max. WL",DbU::getValueString(_antennaDiodeMaxWL)) << endl;
|
||||
cmess1 << Dots::asString (" - Latch up Distance",DbU::getValueString(_latchUpDistance)) << endl;
|
||||
|
@ -174,11 +170,10 @@ namespace Etesian {
|
|||
record->add ( getSlot( "_cg" , _cg ) );
|
||||
record->add ( getSlot( "_placeEffort" , (int)_placeEffort ) );
|
||||
record->add ( getSlot( "_updateConf" , (int)_updateConf ) );
|
||||
record->add ( getSlot( "_spreadingConf" , (int)_spreadingConf ) );
|
||||
record->add ( getSlot( "_spaceMargin" , _spaceMargin ) );
|
||||
record->add ( getSlot( "_densityVariation" , _densityVariation ) );
|
||||
record->add ( getSlot( "_aspectRatio" , _aspectRatio ) );
|
||||
record->add ( getSlot( "_antennaInsertThreshold", _antennaInsertThreshold ) );
|
||||
record->add ( getSlot( "_tieName" , _tieName ) );
|
||||
record->add ( getSlot( "_tieName" , _tieName ) );
|
||||
record->add ( getSlot( "_feedNames" , _feedNames ) );
|
||||
record->add ( getSlot( "_diodeName" , _diodeName ) );
|
||||
record->add ( getSlot( "_spareBufferName" , _spareBufferName ) );
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -81,6 +81,7 @@ extern "C" {
|
|||
DirectSetLongAttribute (PyEtesianEngine_setFixedAbHeight,setFixedAbHeight,PyEtesianEngine,EtesianEngine)
|
||||
DirectSetLongAttribute (PyEtesianEngine_setFixedAbWidth ,setFixedAbWidth ,PyEtesianEngine,EtesianEngine)
|
||||
DirectSetDoubleAttribute (PyEtesianEngine_setSpaceMargin ,setSpaceMargin ,PyEtesianEngine,EtesianEngine)
|
||||
DirectSetDoubleAttribute (PyEtesianEngine_setDensityVariation,setDensityVariation ,PyEtesianEngine,EtesianEngine)
|
||||
DirectSetDoubleAttribute (PyEtesianEngine_setAspectRatio ,setAspectRatio ,PyEtesianEngine,EtesianEngine)
|
||||
DirectGetLongAttribute (PyEtesianEngine_getFixedAbHeight,getFixedAbHeight,PyEtesianEngine,EtesianEngine)
|
||||
DirectGetLongAttribute (PyEtesianEngine_getFixedAbWidth ,getFixedAbWidth ,PyEtesianEngine,EtesianEngine)
|
||||
|
@ -273,6 +274,8 @@ extern "C" {
|
|||
, "Use this width when computing the size of the default abutment box (disable aspect ratio)." }
|
||||
, { "setSpaceMargin" , (PyCFunction)PyEtesianEngine_setSpaceMargin , METH_VARARGS
|
||||
, "Override the configuration space margin parameter value." }
|
||||
, { "setDensityVariation" , (PyCFunction)PyEtesianEngine_setDensityVariation, METH_VARARGS
|
||||
, "Override the configuration density variation parameter value." }
|
||||
, { "setAspectRatio" , (PyCFunction)PyEtesianEngine_setAspectRatio , METH_VARARGS
|
||||
, "Override the configuration aspect ratio parameter value." }
|
||||
, { "resetPlacement" , (PyCFunction)PyEtesianEngine_resetPlacement , METH_NOARGS
|
||||
|
|
|
@ -40,17 +40,14 @@ namespace Etesian {
|
|||
// Class : "Etesian::Configuration".
|
||||
|
||||
enum Effort { Fast =1
|
||||
, Standard=2
|
||||
, High =3
|
||||
, Extreme =4
|
||||
, Standard=3
|
||||
, High =6
|
||||
, Extreme =9
|
||||
};
|
||||
enum GraphicUpdate { UpdateAll =1
|
||||
, LowerBound=2
|
||||
, FinalOnly =3
|
||||
};
|
||||
enum Density { ForceUniform=1
|
||||
, MaxDensity =2
|
||||
};
|
||||
|
||||
class Configuration {
|
||||
public:
|
||||
|
@ -63,11 +60,10 @@ namespace Etesian {
|
|||
inline CellGauge* getCellGauge () const;
|
||||
inline Effort getPlaceEffort () const;
|
||||
inline GraphicUpdate getUpdateConf () const;
|
||||
inline Density getSpreadingConf () const;
|
||||
inline bool getRoutingDriven () const;
|
||||
inline double getSpaceMargin () const;
|
||||
inline double getDensityVariation () const;
|
||||
inline double getAspectRatio () const;
|
||||
inline double getAntennaInsertThreshold () const;
|
||||
inline string getTieName () const;
|
||||
inline string getFeedNames () const;
|
||||
inline string getDiodeName () const;
|
||||
|
@ -77,6 +73,7 @@ namespace Etesian {
|
|||
inline DbU::Unit getAntennaGateMaxWL () const;
|
||||
inline DbU::Unit getAntennaDiodeMaxWL () const;
|
||||
inline void setSpaceMargin ( double );
|
||||
inline void setDensityVariation ( double );
|
||||
inline void setAspectRatio ( double );
|
||||
void print ( Cell* ) const;
|
||||
Record* _getRecord () const;
|
||||
|
@ -88,11 +85,10 @@ namespace Etesian {
|
|||
CellGauge* _cg;
|
||||
Effort _placeEffort;
|
||||
GraphicUpdate _updateConf;
|
||||
Density _spreadingConf;
|
||||
bool _routingDriven;
|
||||
double _spaceMargin;
|
||||
double _densityVariation;
|
||||
double _aspectRatio;
|
||||
double _antennaInsertThreshold;
|
||||
string _tieName;
|
||||
string _feedNames;
|
||||
string _diodeName;
|
||||
|
@ -111,11 +107,10 @@ namespace Etesian {
|
|||
inline CellGauge* Configuration::getCellGauge () const { return _cg; }
|
||||
inline Effort Configuration::getPlaceEffort () const { return _placeEffort; }
|
||||
inline GraphicUpdate Configuration::getUpdateConf () const { return _updateConf; }
|
||||
inline Density Configuration::getSpreadingConf () const { return _spreadingConf; }
|
||||
inline bool Configuration::getRoutingDriven () const { return _routingDriven; }
|
||||
inline double Configuration::getSpaceMargin () const { return _spaceMargin; }
|
||||
inline double Configuration::getDensityVariation () const { return _densityVariation; }
|
||||
inline double Configuration::getAspectRatio () const { return _aspectRatio; }
|
||||
inline double Configuration::getAntennaInsertThreshold () const { return _antennaInsertThreshold; }
|
||||
inline string Configuration::getTieName () const { return _tieName; }
|
||||
inline string Configuration::getFeedNames () const { return _feedNames; }
|
||||
inline string Configuration::getDiodeName () const { return _diodeName; }
|
||||
|
@ -125,6 +120,7 @@ namespace Etesian {
|
|||
inline DbU::Unit Configuration::getAntennaGateMaxWL () const { return _antennaGateMaxWL; }
|
||||
inline DbU::Unit Configuration::getAntennaDiodeMaxWL () const { return _antennaDiodeMaxWL; }
|
||||
inline void Configuration::setSpaceMargin ( double margin ) { _spaceMargin = margin; }
|
||||
inline void Configuration::setDensityVariation ( double margin ) { _densityVariation = margin; }
|
||||
inline void Configuration::setAspectRatio ( double ratio ) { _aspectRatio = ratio; }
|
||||
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <tuple>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include "coloquinte/circuit.hxx"
|
||||
#include "coloquinte/coloquinte.hpp"
|
||||
|
||||
#include "hurricane/Timer.h"
|
||||
#include "hurricane/Name.h"
|
||||
|
@ -70,7 +70,6 @@ namespace Etesian {
|
|||
typedef std::tuple<Net*,int32_t,uint32_t> NetInfos;
|
||||
typedef std::tuple<Instance*, std::vector<RoutingPad*> > InstanceInfos;
|
||||
typedef std::map<Instance*,size_t,DBo::CompareById> InstancesToIds;
|
||||
typedef std::map<Net*,size_t,DBo::CompareById> NetsToIds;
|
||||
typedef std::set<std::string> NetNameSet;
|
||||
public:
|
||||
static const Name& staticGetName ();
|
||||
|
@ -91,10 +90,9 @@ namespace Etesian {
|
|||
inline DbU::Unit getFixedAbWidth () const;
|
||||
inline Effort getPlaceEffort () const;
|
||||
inline GraphicUpdate getUpdateConf () const;
|
||||
inline Density getSpreadingConf () const;
|
||||
inline double getSpaceMargin () const;
|
||||
inline double getDensityVariation () const;
|
||||
inline double getAspectRatio () const;
|
||||
inline double getAntennaInsertThreshold () const;
|
||||
inline DbU::Unit getAntennaGateMaxWL () const;
|
||||
inline DbU::Unit getAntennaDiodeMaxWL () const;
|
||||
inline DbU::Unit getLatchUpDistance () const;
|
||||
|
@ -114,6 +112,7 @@ namespace Etesian {
|
|||
inline void setFixedAbHeight ( DbU::Unit );
|
||||
inline void setFixedAbWidth ( DbU::Unit );
|
||||
inline void setSpaceMargin ( double );
|
||||
inline void setDensityVariation ( double );
|
||||
inline void setAspectRatio ( double );
|
||||
void setDefaultAb ();
|
||||
void adjustSliceHeight ();
|
||||
|
@ -131,11 +130,8 @@ namespace Etesian {
|
|||
inline Transformation toBlock ( const Transformation& ) const;
|
||||
void setPlaceArea ( const Box& );
|
||||
size_t toColoquinte ();
|
||||
void preplace ();
|
||||
void roughLegalize ( float minDisruption, unsigned options );
|
||||
void globalPlace ( float initPenalty, float minDisruption, float targetImprovement, float minInc, float maxInc, unsigned options=0 );
|
||||
void detailedPlace ( int iterations, int effort, unsigned options=0 );
|
||||
void antennaProtect ();
|
||||
void globalPlace ();
|
||||
void detailedPlace ();
|
||||
void place ();
|
||||
uint32_t doHFNS ();
|
||||
inline void useFeed ( Cell* );
|
||||
|
@ -160,15 +156,12 @@ namespace Etesian {
|
|||
bool _flatDesign;
|
||||
Box _placeArea;
|
||||
std::vector<Box> _trackAvoids;
|
||||
coloquinte::box<coloquinte::int_t>* _surface;
|
||||
coloquinte::netlist* _circuit;
|
||||
coloquinte::placement_t* _placementLB;
|
||||
coloquinte::placement_t* _placementUB;
|
||||
coloquinte::density_restrictions* _densityLimits;
|
||||
NetsToIds _netsToIds;
|
||||
coloquinte::Rectangle* _surface;
|
||||
coloquinte::Circuit* _circuit;
|
||||
coloquinte::PlacementSolution* _placementLB;
|
||||
coloquinte::PlacementSolution* _placementUB;
|
||||
InstancesToIds _instsToIds;
|
||||
std::vector<InstanceInfos> _idsToInsts;
|
||||
std::vector<NetInfos> _idsToNets;
|
||||
Hurricane::CellViewer* _viewer;
|
||||
Cell* _diodeCell;
|
||||
FeedCells _feedCells;
|
||||
|
@ -195,9 +188,9 @@ namespace Etesian {
|
|||
private:
|
||||
inline uint32_t _getNewDiodeId ();
|
||||
Instance* _createDiode ( Cell* );
|
||||
void _updatePlacement ( const coloquinte::placement_t*, uint32_t flags=0 );
|
||||
void _progressReport1 ( string label ) const;
|
||||
void _progressReport2 ( string label ) const;
|
||||
void _updatePlacement ( const coloquinte::PlacementSolution* );
|
||||
void _coloquinteCallback(coloquinte::PlacementStep step);
|
||||
void _checkNotAFeed ( Occurrence occurrence ) const;
|
||||
};
|
||||
|
||||
|
||||
|
@ -214,10 +207,9 @@ namespace Etesian {
|
|||
inline DbU::Unit EtesianEngine::getFixedAbWidth () const { return _fixedAbWidth; }
|
||||
inline Effort EtesianEngine::getPlaceEffort () const { return getConfiguration()->getPlaceEffort(); }
|
||||
inline GraphicUpdate EtesianEngine::getUpdateConf () const { return getConfiguration()->getUpdateConf(); }
|
||||
inline Density EtesianEngine::getSpreadingConf () const { return getConfiguration()->getSpreadingConf(); }
|
||||
inline double EtesianEngine::getSpaceMargin () const { return getConfiguration()->getSpaceMargin(); }
|
||||
inline double EtesianEngine::getDensityVariation () const { return getConfiguration()->getDensityVariation(); }
|
||||
inline double EtesianEngine::getAspectRatio () const { return getConfiguration()->getAspectRatio(); }
|
||||
inline double EtesianEngine::getAntennaInsertThreshold () const { return getConfiguration()->getAntennaInsertThreshold(); }
|
||||
inline DbU::Unit EtesianEngine::getAntennaGateMaxWL () const { return getConfiguration()->getAntennaGateMaxWL(); }
|
||||
inline DbU::Unit EtesianEngine::getAntennaDiodeMaxWL () const { return getConfiguration()->getAntennaDiodeMaxWL(); }
|
||||
inline DbU::Unit EtesianEngine::getLatchUpDistance () const { return getConfiguration()->getLatchUpDistance(); }
|
||||
|
@ -232,6 +224,7 @@ namespace Etesian {
|
|||
inline void EtesianEngine::setFixedAbHeight ( DbU::Unit abHeight ) { _fixedAbHeight = abHeight; }
|
||||
inline void EtesianEngine::setFixedAbWidth ( DbU::Unit abWidth ) { _fixedAbWidth = abWidth; }
|
||||
inline void EtesianEngine::setSpaceMargin ( double margin ) { getConfiguration()->setSpaceMargin(margin); }
|
||||
inline void EtesianEngine::setDensityVariation ( double margin ) { getConfiguration()->setDensityVariation(margin); }
|
||||
inline void EtesianEngine::setAspectRatio ( double ratio ) { getConfiguration()->setAspectRatio(ratio); }
|
||||
inline DbU::Unit EtesianEngine::toDbU ( int64_t v ) const { return v*getSliceStep(); }
|
||||
inline uint32_t EtesianEngine::_getNewDiodeId () { return _diodeCount++; }
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
set_cmake_policies()
|
||||
check_distribution()
|
||||
setup_sysconfdir( "${CMAKE_INSTALL_PREFIX}" )
|
||||
setup_python()
|
||||
|
||||
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development)
|
||||
find_package(PythonSitePackages REQUIRED)
|
||||
find_package(HURRICANE REQUIRED)
|
||||
find_package(CORIOLIS REQUIRED)
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
${CONFIGURATION_INCLUDE_DIR}
|
||||
${Python_INCLUDE_DIRS}
|
||||
)
|
||||
find_package (Python3 COMPONENTS Interpreter Development)
|
||||
|
||||
set( includes flute.h
|
||||
dl.h
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -20,11 +20,11 @@
|
|||
cmake_policy(SET CMP0054 NEW)
|
||||
setup_boost(program_options)
|
||||
setup_qt()
|
||||
setup_python()
|
||||
|
||||
find_package(BZip2 REQUIRED)
|
||||
find_package(BISON REQUIRED)
|
||||
find_package(FLEX REQUIRED)
|
||||
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development )
|
||||
find_package(PythonSitePackages REQUIRED)
|
||||
find_package(Libexecinfo REQUIRED)
|
||||
if (USE_LIBBFD)
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace Hurricane {
|
|||
#ifdef HAVE_CXA_DEMANGLE
|
||||
|
||||
string demangle ( const char* symbol )
|
||||
{
|
||||
{
|
||||
int status;
|
||||
size_t length = 4096;
|
||||
char demangled[length];
|
||||
|
@ -49,13 +49,25 @@ string demangle ( const char* symbol )
|
|||
#else
|
||||
|
||||
string demangle ( const char* symbol )
|
||||
{
|
||||
return symbol;
|
||||
}
|
||||
{ return symbol; }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
string& split ( string& s )
|
||||
{
|
||||
size_t i = s.find( "<" );
|
||||
while ( i != string::npos ) {
|
||||
if (i+3 > s.size()) break;
|
||||
//if (s[i+2] != '>') {
|
||||
s.insert( i, "\\n" );
|
||||
//}
|
||||
i = s.find( "<", i+3 );
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
} // End of Hurricane namespace.
|
||||
|
||||
|
||||
|
|
|
@ -118,6 +118,9 @@ Contact::Contact(Net* net, const Layer* layer, DbU::Unit x, DbU::Unit y, DbU::Un
|
|||
{
|
||||
if (not _layer)
|
||||
throw Error("Contact::Contact(): Can't create " + _TName("Contact") + ", NULL layer.");
|
||||
|
||||
if ( _width < _layer->getMinimalSize() ) _width = _layer->getMinimalSize();
|
||||
if ( _height < _layer->getMinimalSize() ) _height = _layer->getMinimalSize();
|
||||
}
|
||||
|
||||
Contact::Contact(Net* net, Component* anchor, const Layer* layer, DbU::Unit dx, DbU::Unit dy, DbU::Unit width, DbU::Unit height)
|
||||
|
|
|
@ -111,21 +111,21 @@ bool Interval::intersect(const Interval& interval, bool strict) const
|
|||
if (isEmpty() or interval.isEmpty()) return false;
|
||||
if ( (_vMax < interval._vMin) or (interval._vMax < _vMin) ) return false;
|
||||
|
||||
return not strict or ( (_vMax != interval._vMin) and (interval._vMax != _vMin) );
|
||||
return not strict or ( (_vMax > interval._vMin) or (interval._vMax > _vMin) );
|
||||
}
|
||||
|
||||
bool Interval::inferior(const Interval& interval, bool strict) const
|
||||
// *****************************************************************
|
||||
{
|
||||
if (_vMax < interval._vMin) return true;
|
||||
return not strict and (_vMax == interval._vMin);
|
||||
if (_vMax == interval._vMin) return not strict;
|
||||
return (_vMax < interval._vMin);
|
||||
}
|
||||
|
||||
bool Interval::superior(const Interval& interval, bool strict) const
|
||||
// *****************************************************************
|
||||
{
|
||||
if (_vMin > interval._vMax) return true;
|
||||
return !strict && (_vMin == interval._vMax);
|
||||
return not (strict or (_vMin != interval._vMax));
|
||||
}
|
||||
|
||||
bool Interval::isConstrainedBy(const Interval& interval) const
|
||||
|
|
|
@ -772,15 +772,23 @@ void Net::_preDestroy()
|
|||
cdebug_tabw(18,-1);
|
||||
}
|
||||
|
||||
string Net::_getFlagsAsString() const
|
||||
// **********************************
|
||||
{
|
||||
string ds;
|
||||
ds += ((isDeepNet() ) ? "d" : "-");
|
||||
ds += ((_isExternal ) ? "e" : "-");
|
||||
ds += ((_isGlobal ) ? "g" : "-");
|
||||
ds += ((_isAutomatic) ? "a" : "-");
|
||||
return ds;
|
||||
}
|
||||
|
||||
string Net::_getString() const
|
||||
// ***************************
|
||||
{
|
||||
string bs = Inherit::_getString();
|
||||
string ds = "\"" + getString(_name) + "\" ";
|
||||
ds += ((isDeepNet() ) ? "d" : "-");
|
||||
ds += ((_isExternal ) ? "e" : "-");
|
||||
ds += ((_isGlobal ) ? "g" : "-");
|
||||
ds += ((_isAutomatic) ? "a" : "-");
|
||||
ds += _getFlagsAsString();
|
||||
ds += " ";
|
||||
ds += getString(_type ) + " ";
|
||||
ds += getString(_direction);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue