Compare commits

..

No commits in common. "devel" and "tramontana" have entirely different histories.

145 changed files with 45899 additions and 3164 deletions

6
.gitmodules vendored
View File

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

View File

@ -18,9 +18,9 @@
set_cmake_policies()
setup_boost(program_options)
setup_qt()
setup_python()
find_package(Libexecinfo REQUIRED)
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development)
find_package(PythonSitePackages REQUIRED)
find_package(LEFDEF REQUIRED)
find_package(FLUTE REQUIRED)

View File

@ -18,8 +18,8 @@
set_cmake_policies()
setup_boost()
setup_qt()
setup_python()
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development)
find_package(PythonSitePackages REQUIRED)
find_package(FLUTE REQUIRED)
find_package(HURRICANE REQUIRED)

View File

@ -3069,7 +3069,6 @@ namespace Anabatic {
if (wPitch > 1) segment->setFlags( SegWide );
if (source->canDrag() or target->canDrag()) segment->setFlags( SegDrag );
if (dir & Flags::UseNonPref) segment->setFlags( SegNonPref );
if (dir.contains(Flags::UseNonPref|Flags::OnVSmall)) segment->setFlags( SegOnVSmall );
return segment;
}

View File

@ -14,6 +14,7 @@ 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

View File

@ -132,7 +132,6 @@ namespace Anabatic {
const BaseFlags Flags::NoMinLength = (1L << 37);
const BaseFlags Flags::NoSegExt = (1L << 38);
const BaseFlags Flags::NullLength = (1L << 39);
const BaseFlags Flags::OnVSmall = (1L << 40);
Flags::~Flags ()

View File

@ -278,8 +278,6 @@ 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;
@ -1157,8 +1155,8 @@ namespace Anabatic {
}
for ( size_t i=1 ; i<rpsM1.size() ; ++i ) {
AutoContact* leftContact = doRp_Access( getGCell(), rpsM1[i-1], HAccess );
AutoContact* rightContact = doRp_Access( getGCell(), rpsM1[i ], HAccess );
AutoContact* leftContact = doRp_Access( getGCell(), getRoutingPads()[i-1], HAccess );
AutoContact* rightContact = doRp_Access( getGCell(), getRoutingPads()[i ], HAccess );
AutoSegment::create( leftContact, rightContact, Flags::Horizontal );
}

View File

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

View File

@ -110,7 +110,6 @@ namespace Anabatic {
static const BaseFlags NoMinLength ;
static const BaseFlags NoSegExt ;
static const BaseFlags NullLength ;
static const BaseFlags OnVSmall ;
public:
inline Flags ( uint64_t flags = NoFlags );
inline Flags ( const Hurricane::BaseFlags& );

View File

@ -11,7 +11,8 @@
list(INSERT CMAKE_MODULE_PATH 0 "${Bootstrap_SOURCE_DIR}/cmake_modules/")
find_package(Bootstrap REQUIRED)
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development.Module )
# find_package(Python 3 REQUIRED COMPONENTS Interpreter Development )
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development )
find_package(PythonSitePackages REQUIRED)
print_cmake_module_path()

View File

@ -35,7 +35,6 @@ class Builder:
self._noCache = False
self._ninja = False
self._clang = False
self._manylinux = False
self._noSystemBoost = False
self._macports = False
self._devtoolset = 0
@ -63,7 +62,6 @@ class Builder:
elif attribute == "noCache": self._noCache = value
elif attribute == "ninja": self._ninja = value
elif attribute == "clang": self._clang = value
elif attribute == "manylinux": self._manylinux = value
elif attribute == "macports":
self._macports = value
if value: self._noSystemBoost = True
@ -179,7 +177,6 @@ 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

View File

@ -211,7 +211,6 @@ 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)." )
@ -283,7 +282,6 @@ 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

View File

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

View File

@ -84,10 +84,10 @@
set(DEBUG_FLAGS "-g")
if(CYGWIN)
set(ADDITIONAL_FLAGS "-D_GLIBCXX_USE_C99")
set(CXX_STANDARD "gnu++17")
set(CXX_STANDARD "gnu++11")
else()
set(ADDITIONAL_FLAGS "-Wl,--no-undefined")
set(CXX_STANDARD "c++17")
set(CXX_STANDARD "c++11")
endif()
#set(CMAKE_C_FLAGS_DEBUG " -Wall -fsanitize=address ${ADDITIONAL_FLAGS} ${DEBUG_FLAGS}" CACHE STRING "C Compiler Debug options." FORCE)
set(CMAKE_C_FLAGS_DEBUG " -Wall ${ADDITIONAL_FLAGS} ${DEBUG_FLAGS}" CACHE STRING "C Compiler Debug options." FORCE)
@ -223,20 +223,6 @@ 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.
#

View File

@ -180,7 +180,7 @@ Development files for the Coriolis 2 package.
%{coriolisTop}/include/vlsisapd/configuration/*.h
%{coriolisTop}/include/vlsisapd/dtr/*.h
%{coriolisTop}/include/vlsisapd/openChams/*.h
%{coriolisTop}/include/coriolis2/coloquinte/*.hpp
%{coriolisTop}/include/coriolis2/coloquinte/*.hxx
%{coriolisTop}/include/coriolis2/hurricane/*.h
%{coriolisTop}/include/coriolis2/hurricane/viewer/*.h
%{coriolisTop}/include/coriolis2/hurricane/isobar/*.h

View File

@ -284,16 +284,6 @@ class GitRepository ( object ):
Command( [ 'git', 'checkout', branch ], self.fdLog ).execute()
return
def submoduleInit ( self ):
os.chdir( self.localRepoDir )
Command( [ 'git', 'submodule', 'init' ], self.fdLog ).execute()
return
def submoduleUpdate ( self ):
os.chdir( self.localRepoDir )
Command( [ 'git', 'submodule', 'update' ], self.fdLog ).execute()
return
class Configuration ( object ):
@ -313,7 +303,7 @@ class Configuration ( object ):
def __init__ ( self ):
self._sender = 'Jean-Paul.Chaput@soc.lip6.fr'
self._receivers = [ 'Jean-Paul.Chaput@lip6.fr', ]
self._supportRepos = [ 'https://github.com/Tencent/rapidjson.git' ]
self._supportRepos = [ 'http://github.com/miloyip/rapidjson' ]
self._allianceRepo = 'https://gitlab.lip6.fr/jpc/alliance.git'
self._coriolisRepo = 'https://gitlab.lip6.fr/jpc/coriolis.git'
self._benchsRepo = 'https://gitlab.lip6.fr/jpc/alliance-check-toolkit.git'
@ -611,8 +601,6 @@ try:
if conf.rmSource: gitCoriolis.removeLocalRepo()
gitCoriolis.clone ()
gitCoriolis.checkout( 'devel' )
gitCoriolis.submoduleInit()
gitCoriolis.submoduleUpdate()
if conf.rmSource: gitBenchs.removeLocalRepo()
gitBenchs.clone()

View File

@ -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)

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

34
coloquinte/CMakeLists.txt Normal file
View File

@ -0,0 +1,34 @@
# -*- explicit-buffer-name: "CMakeLists.txt<coloquinte>" -*-
set(CMAKE_LEGACY_CYGWIN_WIN32 0)
project(COLOQUINTE)
set(ignoreVariables "${CMAKE_INSTALL_DIR}" "${BUILD_DOC}")
#option(BUILD_DOC "Build the documentation (doxygen)" OFF)
option(USE_LIBBFD "Link with BFD libraries to print stack traces" OFF)
cmake_minimum_required(VERSION 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)

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

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

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

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

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

View File

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

View File

@ -21,7 +21,6 @@
setup_sysconfdir("${CMAKE_INSTALL_PREFIX}")
setup_boost(program_options)
setup_qt()
setup_python()
cmake_policy(SET CMP0054 NEW)
@ -29,6 +28,7 @@
find_package(Libbfd)
endif()
find_package(BZip2 REQUIRED)
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development)
find_package(PythonSitePackages REQUIRED)
find_package(BISON REQUIRED)
find_package(FLEX REQUIRED)

View File

@ -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.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' )
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' )
param = Cfg.getParamEnumerate( 'etesian.effort' )
param.setInt( 2 )
param.addValue( 'Fast' , 1 )
param.addValue( 'Standard', 3 )
param.addValue( 'High' , 6 )
param.addValue( 'Extreme' , 9 )
param.addValue( 'Standard', 2 )
param.addValue( 'High' , 3 )
param.addValue( 'Extreme' , 4 )
param = Cfg.getParamEnumerate( 'etesian.graphics' )
param.setInt( 3 )
param.setInt( 2 )
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 ( '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' )
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' )

View File

@ -19,22 +19,22 @@ import coriolis.Cfg as Cfg
layout = Cfg.Configuration.get().getLayout()
# Kite Layout.
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' )
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' )

View File

@ -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 )

View File

@ -16,8 +16,8 @@
import coriolis.Cfg as Cfg
layout = Cfg.Configuration.get().getLayout()
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 )
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 )

View File

@ -1,327 +0,0 @@
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()

View File

@ -1,318 +0,0 @@
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()

View File

@ -43,7 +43,6 @@ 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 )

View File

@ -43,7 +43,6 @@ 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 )

View File

@ -1,42 +0,0 @@
# 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()

View File

@ -1,56 +0,0 @@
# 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 )

View File

@ -1,20 +0,0 @@
# 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

View File

@ -1,474 +0,0 @@
# 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 )

View File

@ -1,20 +0,0 @@
# 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

View File

@ -1,194 +0,0 @@
# 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 )

View File

@ -1,20 +0,0 @@
# 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

View File

@ -1,20 +0,0 @@
# 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

View File

@ -1,32 +0,0 @@
# 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 )

View File

@ -1,26 +0,0 @@
# 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') )

View File

@ -1,401 +0,0 @@
# 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 )

View File

@ -29,9 +29,8 @@ namespace CRL {
class LefImport {
public:
static void reset ();
static Hurricane::Library* load ( std::string fileName );
static void setMergeLibrary ( Hurricane::Library* );
static void reset ();
static Hurricane::Library* load ( std::string fileName );
};

View File

@ -33,7 +33,6 @@
#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"
@ -72,7 +71,6 @@ namespace {
class LefParser {
public:
static void setMergeLibrary ( Library* );
static DbU::Unit fromLefUnits ( int );
static Layer* getLayer ( string );
static void addLayer ( string, Layer* );
@ -110,8 +108,8 @@ namespace {
inline int getNthRouting () const;
inline void incNthRouting ();
inline RoutingGauge* getRoutingGauge () const;
inline void addPinComponent ( string name, Component* );
inline void clearPinComponents ();
inline void addPinSegment ( string name, Segment* );
inline void clearPinSegments ();
private:
static int _unitsCbk ( lefrCallbackType_e, lefiUnits* , lefiUserData );
static int _layerCbk ( lefrCallbackType_e, lefiLayer* , lefiUserData );
@ -123,7 +121,6 @@ namespace {
void _pinStdPostProcess ();
void _pinPadPostProcess ();
private:
static Library* _mergeLibrary;
string _file;
string _libraryName;
Library* _library;
@ -131,7 +128,7 @@ namespace {
Net* _net;
string _busBits;
double _unitsMicrons;
map< string, vector<Component*> > _pinComponents;
map< string, vector<Segment*> > _pinSegments;
static map<string,Layer*> _layerLut;
vector<string> _unmatchedLayers;
vector<string> _errors;
@ -173,20 +170,15 @@ 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::addPinComponent ( string name, Component* comp ) { _pinComponents[name].push_back(comp); }
inline void LefParser::clearPinComponents () { _pinComponents.clear(); }
inline void LefParser::addPinSegment ( string name, Segment* s ) { _pinSegments[name].push_back(s); }
inline void LefParser::clearPinSegments () { _pinSegments.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();
@ -280,11 +272,6 @@ 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" );
@ -512,19 +499,6 @@ 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;
@ -579,7 +553,7 @@ namespace {
if (not isPad) parser->_pinStdPostProcess();
else parser->_pinPadPostProcess();
parser->clearPinComponents();
parser->clearPinSegments();
cerr << " - " << cellName
<< " " << DbU::getValueString(width) << " " << DbU::getValueString(height)
@ -669,23 +643,10 @@ namespace {
, parser->fromUnitsMicrons( r->yh )
);
}
if (segment) parser->addPinComponent( pin->name(), segment );
if (segment) parser->addPinSegment( 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;
@ -727,27 +688,20 @@ namespace {
const RoutingLayerGauge* gaugeMetal2 = _routingGauge->getLayerGauge( 1 );
Box ab = _cell->getAbutmentBox();
cerr << " @ _pinStdPostProcess" << endl;
//cerr << " @ _pinStdPostProcess" << endl;
for ( auto element : _pinComponents ) {
string pinName = element.first;
vector<Component*>& components = element.second;
vector<Segment*> ongrids;
for ( auto element : _pinSegments ) {
string pinName = element.first;
vector<Segment*>& segments = element.second;
vector<Segment*> ongrids;
for ( Component* component : components ) {
Segment* segment = dynamic_cast<Segment*>( component );
if (segment) {
if (component->getNet()->isSupply()) continue;
bool isWide = (segment->getWidth() >= getMinTerminalWidth());
for ( Segment* segment : segments ) {
bool isWide = (segment->getWidth() >= getMinTerminalWidth());
cerr << " > " << segment << endl;
if (not isVH())
cerr << "NOT isVH()" << endl;
else
cerr << "isVH()" << endl;
//cerr << " > " << segment << 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()
@ -758,7 +712,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)
@ -784,67 +738,16 @@ namespace {
}
}
}
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 (isWide) ongrids.push_back( segment );
}
if (ongrids.empty()) {
cerr << Warning( "LefParser::_pinStdPostProcess(): Pin \"%s\" has no terminal ongrid."
, pinName.c_str() ) << endl;
for ( Component* component : components ) {
NetExternalComponents::setExternal( component );
for ( Segment* segment : segments ) {
NetExternalComponents::setExternal( segment );
}
} else {
for ( Segment* segment : ongrids ) {
@ -860,10 +763,10 @@ namespace {
Box ab = getCell()->getAbutmentBox();
bool isCornerPad = (_cellGauge) and (_cellGauge->getSliceHeight() == _cellGauge->getSliceStep());
for ( auto element : _pinComponents ) {
string pinName = element.first;
vector<Component*>& segments = element.second;
vector<Segment*> ongrids;
for ( auto element : _pinSegments ) {
string pinName = element.first;
vector<Segment*>& segments = element.second;
vector<Segment*> ongrids;
if (segments.empty()) continue;
@ -1060,12 +963,4 @@ namespace CRL {
}
void LefImport::setMergeLibrary ( Library* library )
{
#if defined(HAVE_LEFDEF)
LefParser::setMergeLibrary( library );
#endif
}
} // End of CRL namespace.

View File

@ -1,5 +1,6 @@
# -*- 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}

View File

@ -32,6 +32,8 @@
-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}"

View File

@ -43,8 +43,6 @@ namespace CRL {
using Isobar::ParseTwoArg;
using Isobar::__cs;
using Isobar::PyLibrary_Link;
using Isobar::PyTypeLibrary;
using Isobar::PyLibrary;
extern "C" {
@ -88,37 +86,14 @@ 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 */

View File

@ -1,6 +1,7 @@
# -*- 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}

View File

@ -69,13 +69,7 @@ class ShellEnv ( object ):
self.shellEnv[ 'MBK_CATAL_NAME' ] = env.getCATALOG()
self.shellEnv[ 'RDS_IN' ] = 'gds'
self.shellEnv[ 'RDS_OUT' ] = 'gds'
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
self.shellEnv[ 'ALLIANCE_TOP' ] = ShellEnv.ALLIANCE_TOP
def export ( self ):
"""

View File

@ -42,10 +42,7 @@ class Where ( object ):
return '<Where coriolisTop="{}">'.format( Where.coriolisTop.as_posix() )
def setupCMOS ( checkToolkit=None ):
Where( checkToolkit )
ShellEnv().export()
def setupCMOS ():
from .. import Cfg
from .. import Viewer
from .. import CRL
@ -53,6 +50,8 @@ def setupCMOS ( checkToolkit=None ):
from .yosys import Yosys
import coriolis.technos.symbolic.cmos
Where()
with overlay.CfgCache(priority=Cfg.Parameter.Priority.UserFile) as cfg:
cfg.misc.catchCore = False
cfg.misc.info = False
@ -82,46 +81,6 @@ def setupCMOS ( checkToolkit=None ):
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
@ -336,7 +295,7 @@ def setupTSMC_c180_c4m ( checkToolkit=None, ndaTop=None ):
cfg.misc.verboseLevel1 = True
cfg.misc.verboseLevel2 = True
cfg.etesian.graphics = 3
cfg.etesian.densityVariation = 0.04
cfg.etesian.uniformDensity = True
cfg.etesian.spaceMargin = 0.04
cfg.katana.eventsLimit = 4000000
af = CRL.AllianceFramework.get()
@ -345,52 +304,3 @@ 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()

View File

@ -21,13 +21,13 @@ The ``sram`` module provide base classes for SRAM assemby.
import sys
import re
import traceback
from ...helpers.io import ErrorMessage, WarningMessage
from ...helpers.overlay import UpdateSession
from ...helpers import trace, l, u, n
from ...Hurricane import DataBase, Breakpoint, DbU, Box, Net, Cell, \
Instance, Transformation, PythonAttributes
from ... import CRL
from ..block.configuration import GaugeConf
from ..helpers.io import ErrorMessage, WarningMessage
from ..helpers.overlay import UpdateSession
from ..helpers import trace, l, u, n
from ..Hurricane import DataBase, Breakpoint, DbU, Box, Net, Cell, \
Instance, Transformation, PythonAttributes
from .. import CRL
from .chip.configuration import GaugeConf
af = CRL.AllianceFramework.get()

View File

@ -176,15 +176,15 @@ Conclusion for the nand2+nor2 implementation:
import sys
import re
import traceback
from ...helpers.io import ErrorMessage, WarningMessage
from ...helpers.overlay import UpdateSession
from ...helpers import trace, l, u, n
from ...Hurricane import Breakpoint, DbU, Box, Net, Cell, Instance, \
Transformation, PythonAttributes
from ... import CRL
from ..block.configuration import GaugeConf
from .sram import Bus, Column, ColBlock, ColGroup, \
HeaderRow, BaseSRAM
from ...helpers.io import ErrorMessage, WarningMessage
from ...helpers.overlay import UpdateSession
from ...helpers import trace, l, u, n
from ...Hurricane import Breakpoint, DbU, Box, Net, Cell, Instance, \
Transformation, PythonAttributes
from ... import CRL
from ..chip.configuration import GaugeConf
from .sram import Bus, Column, ColBlock, ColGroup, \
HeaderRow, BaseSRAM
"""

View File

@ -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.spaceMargin = 0.8
cfg.etesian.densityVariation = 0.1
cfg.etesian.aspectRatio = 1.0
cfg.etesian.effort = 2
cfg.etesian.uniformDensity = True
cfg.etesian.spaceMargin = 0.8
cfg.etesian.aspectRatio = 1.0
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.
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).
8.1 Router -- Katana

View File

@ -176,10 +176,11 @@ Etesian Configuration Parameters
| | The extra white space added to the total area |
| | of the standard cells |
+-----------------------------------+------------------+----------------------------+
|``etesian.densityVariation`` | TypePercentage | :cb:`5` |
|``etesian.uniformDensity`` | TypeBool | :cb:`False` |
| +------------------+----------------------------+
| | Control deviation from uniform density in the |
| | placement, as a percentage of area. |
| | Whether the cells will be spread envenly |
| | across the area or allowed to form denser |
| | clusters |
+-----------------------------------+------------------+----------------------------+
|``etesian.effort`` | TypeInt | :cb:`2` |
| +------------------+----------------------------+

View File

@ -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

View File

@ -176,10 +176,11 @@ Etesian Configuration Parameters
| | The extra white space added to the total area |
| | of the standard cells |
+-----------------------------------+------------------+----------------------------+
|``etesian.densityVariation`` | TypePercentage | :cb:`5` |
|``etesian.uniformDensity`` | TypeBool | :cb:`False` |
| +------------------+----------------------------+
| | Control deviation from uniform density in the |
| | placement, as a percentage of area. |
| | Whether the cells will be spread envenly |
| | across the area or allowed to form denser |
| | clusters |
+-----------------------------------+------------------+----------------------------+
|``etesian.effort`` | TypeInt | :cb:`2` |
| +------------------+----------------------------+

View File

@ -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)

View File

@ -10,6 +10,7 @@
${Boost_INCLUDE_DIRS}
${Python_INCLUDE_DIRS}
)
find_package (Python3 COMPONENTS Interpreter Development)
set( includes etesian/Configuration.h
etesian/Placement.h
etesian/FeedCells.h

View File

@ -56,11 +56,13 @@ namespace Etesian {
, _placeEffort ( static_cast<Effort>
(Cfg::getParamEnumerate ("etesian.effort" , Standard )->asInt()) )
, _updateConf ( static_cast<GraphicUpdate>
(Cfg::getParamEnumerate ("etesian.graphics" , FinalOnly )->asInt()) )
(Cfg::getParamEnumerate ("etesian.graphics" , LowerBound )->asInt()) )
, _spreadingConf ( Cfg::getParamBool ("etesian.uniformDensity" , false )->asBool()? ForceUniform : MaxDensity )
, _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() )
@ -105,17 +107,18 @@ 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();
@ -138,11 +141,12 @@ 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;
@ -170,10 +174,11 @@ 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( "_tieName" , _tieName ) );
record->add ( getSlot( "_antennaInsertThreshold", _antennaInsertThreshold ) );
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

View File

@ -81,7 +81,6 @@ 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)
@ -274,8 +273,6 @@ 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

View File

@ -40,14 +40,17 @@ namespace Etesian {
// Class : "Etesian::Configuration".
enum Effort { Fast =1
, Standard=3
, High =6
, Extreme =9
, Standard=2
, High =3
, Extreme =4
};
enum GraphicUpdate { UpdateAll =1
, LowerBound=2
, FinalOnly =3
};
enum Density { ForceUniform=1
, MaxDensity =2
};
class Configuration {
public:
@ -60,10 +63,11 @@ 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;
@ -73,7 +77,6 @@ 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;
@ -85,10 +88,11 @@ 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;
@ -107,10 +111,11 @@ 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; }
@ -120,7 +125,6 @@ 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; }

View File

@ -18,7 +18,7 @@
#include <tuple>
#include <iostream>
#include <unordered_map>
#include "coloquinte/coloquinte.hpp"
#include "coloquinte/circuit.hxx"
#include "hurricane/Timer.h"
#include "hurricane/Name.h"
@ -70,6 +70,7 @@ 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 ();
@ -90,9 +91,10 @@ 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;
@ -112,7 +114,6 @@ 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 ();
@ -130,8 +131,11 @@ namespace Etesian {
inline Transformation toBlock ( const Transformation& ) const;
void setPlaceArea ( const Box& );
size_t toColoquinte ();
void globalPlace ();
void detailedPlace ();
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 place ();
uint32_t doHFNS ();
inline void useFeed ( Cell* );
@ -156,12 +160,15 @@ namespace Etesian {
bool _flatDesign;
Box _placeArea;
std::vector<Box> _trackAvoids;
coloquinte::Rectangle* _surface;
coloquinte::Circuit* _circuit;
coloquinte::PlacementSolution* _placementLB;
coloquinte::PlacementSolution* _placementUB;
coloquinte::box<coloquinte::int_t>* _surface;
coloquinte::netlist* _circuit;
coloquinte::placement_t* _placementLB;
coloquinte::placement_t* _placementUB;
coloquinte::density_restrictions* _densityLimits;
NetsToIds _netsToIds;
InstancesToIds _instsToIds;
std::vector<InstanceInfos> _idsToInsts;
std::vector<NetInfos> _idsToNets;
Hurricane::CellViewer* _viewer;
Cell* _diodeCell;
FeedCells _feedCells;
@ -188,9 +195,9 @@ namespace Etesian {
private:
inline uint32_t _getNewDiodeId ();
Instance* _createDiode ( Cell* );
void _updatePlacement ( const coloquinte::PlacementSolution* );
void _coloquinteCallback(coloquinte::PlacementStep step);
void _checkNotAFeed ( Occurrence occurrence ) const;
void _updatePlacement ( const coloquinte::placement_t*, uint32_t flags=0 );
void _progressReport1 ( string label ) const;
void _progressReport2 ( string label ) const;
};
@ -207,9 +214,10 @@ 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(); }
@ -224,7 +232,6 @@ 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++; }

View File

@ -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)

View File

@ -6,6 +6,7 @@
${CONFIGURATION_INCLUDE_DIR}
${Python_INCLUDE_DIRS}
)
find_package (Python3 COMPONENTS Interpreter Development)
set( includes flute.h
dl.h

View File

@ -18,9 +18,9 @@
set_cmake_policies()
setup_boost(program_options)
setup_qt()
setup_python()
find_package(Libexecinfo REQUIRED)
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development)
find_package(PythonSitePackages REQUIRED)
find_package(LEFDEF REQUIRED)
find_package(FLUTE REQUIRED)

View File

@ -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)

View File

@ -20,7 +20,6 @@
FloatParameter.cpp
MatrixParameter.cpp
MCheckBoxParameter.cpp
SpinBoxParameter.cpp
StepParameter.cpp
StringParameter.cpp
BJT.cpp

View File

@ -107,17 +107,4 @@ namespace Analog {
}
string Cascode::_getTypeName () const
{ return "Cascode"; }
Record* Cascode::_getRecord () const
{
Record* record = Super::_getRecord();
record->add( getSlot("_cBulkConnectedName" , _cBulkConnectedName ) );
record->add( getSlot("_cBulkUnconnectedName", _cBulkUnconnectedName ) );
return record;
}
} // Analog namespace.

View File

@ -109,17 +109,4 @@ namespace Analog {
}
string CommonDrain::_getTypeName () const
{ return "CommonDrain"; }
Record* CommonDrain::_getRecord () const
{
Record* record = Super::_getRecord();
record->add( getSlot("_cdBulkConnectedName" , _cdBulkConnectedName ) );
record->add( getSlot("_cdBulkUnconnectedName", _cdBulkUnconnectedName ) );
return record;
}
} // Analog namespace.

View File

@ -103,16 +103,4 @@ namespace Analog {
{ return (isBulkConnected()) ? _cgBulkConnectedName : _cgBulkUnconnectedName; }
string CommonGatePair::_getTypeName () const
{ return "CommonGatePair"; }
Record* CommonGatePair::_getRecord () const
{
Record* record = Super::_getRecord();
record->add( getSlot("_cgBulkConnectedName" , _cgBulkConnectedName ) );
record->add( getSlot("_cgBulkUnconnectedName", _cgBulkUnconnectedName ) );
return record;
}
} // Analog namespace.

View File

@ -244,17 +244,4 @@ namespace Analog {
}
string CommonSourcePair::_getTypeName () const
{ return "CommonSourcePair"; }
Record* CommonSourcePair::_getRecord () const
{
Record* record = Super::_getRecord();
record->add( getSlot("_cspBulkConnectedName" , _cspBulkConnectedName ) );
record->add( getSlot("_cspBulkUnconnectedName", _cspBulkUnconnectedName ) );
return record;
}
} // Analog namespace.

View File

@ -98,17 +98,4 @@ namespace Analog {
{ return (isBulkConnected()) ? _ccpBulkConnectedName : _ccpBulkUnconnectedName; }
string CrossCoupledPair::_getTypeName () const
{ return "CrossCoupledPair"; }
Record* CrossCoupledPair::_getRecord () const
{
Record* record = Super::_getRecord();
record->add( getSlot("_ccpBulkConnectedName" , _ccpBulkConnectedName ) );
record->add( getSlot("_ccpBulkUnconnectedName", _ccpBulkUnconnectedName ) );
return record;
}
} // Analog namespace.

View File

@ -264,17 +264,4 @@ namespace Analog {
}
string DifferentialPair::_getTypeName () const
{ return "DifferentialPair"; }
Record* DifferentialPair::_getRecord () const
{
Record* record = Super::_getRecord();
record->add( getSlot("_dpBulkConnectedName" , _dpBulkConnectedName ) );
record->add( getSlot("_dpBulkUnconnectedName", _dpBulkUnconnectedName ) );
return record;
}
} // Analog namespace.

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