Merge branch 'devel' into 'serge/changes'
# Conflicts: # bootstrap/cmake_modules/FindBootstrap.cmake
This commit is contained in:
commit
5e5ae997f5
|
@ -0,0 +1,5 @@
|
|||
[submodule "coloquinte"]
|
||||
path = coloquinte
|
||||
# url = git@github.com:Coloquinte/PlaceRoute.git
|
||||
url = https://github.com/Coloquinte/PlaceRoute.git
|
||||
branch = coriolis-submodule
|
|
@ -1155,8 +1155,8 @@ namespace Anabatic {
|
|||
}
|
||||
|
||||
for ( size_t i=1 ; i<rpsM1.size() ; ++i ) {
|
||||
AutoContact* leftContact = doRp_Access( getGCell(), getRoutingPads()[i-1], HAccess );
|
||||
AutoContact* rightContact = doRp_Access( getGCell(), getRoutingPads()[i ], HAccess );
|
||||
AutoContact* leftContact = doRp_Access( getGCell(), rpsM1[i-1], HAccess );
|
||||
AutoContact* rightContact = doRp_Access( getGCell(), rpsM1[i ], HAccess );
|
||||
AutoSegment::create( leftContact, rightContact, Flags::Horizontal );
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
srcDir=${HOME}${nightly}/coriolis-2.x/src/alliance/alliance/src
|
||||
commonRoot=${HOME}${nightly}/coriolis-2.x/${arch}/Release.Shared
|
||||
#commonRoot=${HOME}${nightly}/coriolis-2.x/${arch}/Debug.Shared
|
||||
buildDir=${commonRoot}/build
|
||||
installDir=${commonRoot}/install
|
||||
|
||||
|
|
|
@ -24,8 +24,9 @@ projects = [
|
|||
#, "knik"
|
||||
#, "katabatic"
|
||||
#, "kite"
|
||||
, "equinox"
|
||||
, "solstice"
|
||||
#, "equinox"
|
||||
#, "solstice"
|
||||
, "tramontana"
|
||||
, "oroshi"
|
||||
, "bora"
|
||||
, "karakaze"
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
FindQwt.cmake
|
||||
FindSphinx.cmake
|
||||
FindPelican.cmake
|
||||
FindCOLOQUINTE.cmake
|
||||
GetGitRevisionDescription.cmake
|
||||
GetGitRevisionDescription.cmake.in
|
||||
)
|
||||
|
|
|
@ -84,10 +84,10 @@
|
|||
set(DEBUG_FLAGS "-g")
|
||||
if(CYGWIN)
|
||||
set(ADDITIONAL_FLAGS "-D_GLIBCXX_USE_C99")
|
||||
set(CXX_STANDARD "gnu++11 ${CXX_STANDARD}")
|
||||
set(CXX_STANDARD "gnu++17")
|
||||
else()
|
||||
set(ADDITIONAL_FLAGS "-Wl,--no-undefined")
|
||||
set(CXX_STANDARD "c++11 ${CXX_STANDARD}")
|
||||
set(CXX_STANDARD "c++17")
|
||||
endif()
|
||||
#set(CMAKE_C_FLAGS_DEBUG " -Wall -fsanitize=address ${ADDITIONAL_FLAGS} ${DEBUG_FLAGS}" CACHE STRING "C Compiler Debug options." FORCE)
|
||||
set(CMAKE_C_FLAGS_DEBUG " -Wall ${ADDITIONAL_FLAGS} ${DEBUG_FLAGS}" CACHE STRING "C Compiler Debug options." FORCE)
|
||||
|
|
|
@ -15,13 +15,14 @@ IF(UNIX)
|
|||
#
|
||||
# Look for an installation.
|
||||
#
|
||||
FIND_PATH(COLOQUINTE_INCLUDE_PATH NAMES coloquinte/netlist.hxx PATHS
|
||||
FIND_PATH(COLOQUINTE_INCLUDE_PATH NAMES coloquinte/coloquinte.hpp PATHS
|
||||
# Look in other places.
|
||||
${CORIOLIS_DIR_SEARCH}
|
||||
PATH_SUFFIXES include/coriolis2
|
||||
# Help the user find it if we cannot.
|
||||
DOC "The ${COLOQUINTE_INCLUDE_PATH_DESCRIPTION}"
|
||||
)
|
||||
MESSAGE( "COL ${COLOQUINTE_INCLUDE_PATH}" )
|
||||
|
||||
FIND_LIBRARY(COLOQUINTE_LIBRARY_PATH
|
||||
NAMES coloquinte
|
|
@ -180,7 +180,7 @@ Development files for the Coriolis 2 package.
|
|||
%{coriolisTop}/include/vlsisapd/configuration/*.h
|
||||
%{coriolisTop}/include/vlsisapd/dtr/*.h
|
||||
%{coriolisTop}/include/vlsisapd/openChams/*.h
|
||||
%{coriolisTop}/include/coriolis2/coloquinte/*.hxx
|
||||
%{coriolisTop}/include/coriolis2/coloquinte/*.hpp
|
||||
%{coriolisTop}/include/coriolis2/hurricane/*.h
|
||||
%{coriolisTop}/include/coriolis2/hurricane/viewer/*.h
|
||||
%{coriolisTop}/include/coriolis2/hurricane/isobar/*.h
|
||||
|
|
|
@ -284,6 +284,16 @@ class GitRepository ( object ):
|
|||
Command( [ 'git', 'checkout', branch ], self.fdLog ).execute()
|
||||
return
|
||||
|
||||
def submoduleInit ( self ):
|
||||
os.chdir( self.localRepoDir )
|
||||
Command( [ 'git', 'submodule', 'init' ], self.fdLog ).execute()
|
||||
return
|
||||
|
||||
def submoduleUpdate ( self ):
|
||||
os.chdir( self.localRepoDir )
|
||||
Command( [ 'git', 'submodule', 'update' ], self.fdLog ).execute()
|
||||
return
|
||||
|
||||
|
||||
class Configuration ( object ):
|
||||
|
||||
|
@ -601,6 +611,8 @@ try:
|
|||
if conf.rmSource: gitCoriolis.removeLocalRepo()
|
||||
gitCoriolis.clone ()
|
||||
gitCoriolis.checkout( 'devel' )
|
||||
gitCoriolis.submoduleInit()
|
||||
gitCoriolis.submoduleUpdate()
|
||||
|
||||
if conf.rmSource: gitBenchs.removeLocalRepo()
|
||||
gitBenchs.clone()
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 127cb78333be711eccffb848d00aad7144e2f890
|
|
@ -1,34 +0,0 @@
|
|||
# -*- explicit-buffer-name: "CMakeLists.txt<coloquinte>" -*-
|
||||
|
||||
set(CMAKE_LEGACY_CYGWIN_WIN32 0)
|
||||
project(COLOQUINTE)
|
||||
|
||||
set(ignoreVariables "${CMAKE_INSTALL_DIR}" "${BUILD_DOC}")
|
||||
|
||||
#option(BUILD_DOC "Build the documentation (doxygen)" OFF)
|
||||
option(USE_LIBBFD "Link with BFD libraries to print stack traces" OFF)
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
list(INSERT CMAKE_MODULE_PATH 0 "${DESTDIR}$ENV{CORIOLIS_TOP}/share/cmake/Modules/")
|
||||
find_package(Bootstrap REQUIRED)
|
||||
setup_project_paths(CORIOLIS)
|
||||
setup_qt()
|
||||
|
||||
set_cmake_policies()
|
||||
setup_boost()
|
||||
|
||||
find_package(Libexecinfo REQUIRED)
|
||||
find_package(Doxygen)
|
||||
|
||||
if(WITH_OPENMP)
|
||||
find_package(OpenMP REQUIRED)
|
||||
add_definitions(${OpenMP_CXX_FLAGS})
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${OpenMP_CXX_FLAGS}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${OpenMP_CXX_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_CXX_FLAGS}")
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(cmake_modules)
|
||||
#add_subdirectory(doc)
|
|
@ -1,2 +0,0 @@
|
|||
|
||||
install ( FILES FindCOLOQUINTE.cmake DESTINATION share/cmake/Modules )
|
|
@ -1,39 +0,0 @@
|
|||
# -*- explicit-buffer-name: "CMakeLists.txt<coloquinte/src>" -*-
|
||||
|
||||
include_directories( ${COLOQUINTE_SOURCE_DIR}/src
|
||||
)
|
||||
|
||||
set ( includes coloquinte/circuit.hxx
|
||||
coloquinte/circuit_helper.hxx
|
||||
coloquinte/common.hxx
|
||||
coloquinte/netlist.hxx
|
||||
coloquinte/solvers.hxx
|
||||
coloquinte/rough_legalizers.hxx
|
||||
coloquinte/legalizer.hxx
|
||||
coloquinte/detailed.hxx
|
||||
coloquinte/topologies.hxx
|
||||
coloquinte/optimization_subproblems.hxx
|
||||
coloquinte/piecewise_linear.hxx
|
||||
)
|
||||
set ( cpps circuit.cxx
|
||||
checkers.cxx
|
||||
rough_legalizers.cxx
|
||||
solvers.cxx
|
||||
optimization_subproblems.cxx
|
||||
piecewise_linear.cxx
|
||||
orientation.cxx
|
||||
detailed.cxx
|
||||
cell_swapping.cxx
|
||||
#MCF_opt.cxx
|
||||
row_opt.cxx
|
||||
topologies.cxx
|
||||
lookup_table.cxx
|
||||
legalizer.cxx
|
||||
)
|
||||
|
||||
add_library ( coloquinte ${cpps} )
|
||||
set_target_properties( coloquinte PROPERTIES VERSION 1.0 SOVERSION 1 )
|
||||
|
||||
install( TARGETS coloquinte DESTINATION lib${LIB_SUFFIX} )
|
||||
install( FILES ${includes} DESTINATION include/coriolis2/coloquinte )
|
||||
|
|
@ -1,185 +0,0 @@
|
|||
|
||||
#include "coloquinte/detailed.hxx"
|
||||
#include "coloquinte/circuit_helper.hxx"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace coloquinte{
|
||||
namespace dp{
|
||||
|
||||
namespace{
|
||||
|
||||
// Tries to swap two cells;
|
||||
inline bool try_swap(netlist const & circuit, detailed_placement & pl, index_t c1, index_t c2, bool try_flip,
|
||||
std::function<std::int64_t(netlist const &, detailed_placement const &, std::vector<index_t> const &)> get_nets_cost){
|
||||
assert(pl.cell_height(c1) == 1 and pl.cell_height(c2) == 1);
|
||||
assert( (circuit.get_cell(c1).attributes & XMovable) != 0 and (circuit.get_cell(c1).attributes & YMovable) != 0);
|
||||
assert( (circuit.get_cell(c2).attributes & XMovable) != 0 and (circuit.get_cell(c2).attributes & YMovable) != 0);
|
||||
|
||||
auto c1_bnds = pl.get_limit_positions(circuit, c1),
|
||||
c2_bnds = pl.get_limit_positions(circuit, c2);
|
||||
|
||||
// Get the possible positions for a swap
|
||||
int_t swp_min_c1 = c2_bnds.first,
|
||||
swp_min_c2 = c1_bnds.first,
|
||||
swp_max_c1 = c2_bnds.second - circuit.get_cell(c1).size.x,
|
||||
swp_max_c2 = c1_bnds.second - circuit.get_cell(c2).size.x;
|
||||
|
||||
if(swp_max_c1 >= swp_min_c1 and swp_max_c2 >= swp_min_c2){
|
||||
// Check both orientations of the cell
|
||||
|
||||
// Get all the nets involved and uniquify them (nets with more than one pin on the cells)
|
||||
std::vector<index_t> involved_nets;
|
||||
for(netlist::pin_t p : circuit.get_cell(c1)){
|
||||
involved_nets.push_back(p.net_ind);
|
||||
}
|
||||
for(netlist::pin_t p : circuit.get_cell(c2)){
|
||||
involved_nets.push_back(p.net_ind);
|
||||
}
|
||||
std::sort(involved_nets.begin(), involved_nets.end());
|
||||
involved_nets.resize(std::distance(involved_nets.begin(), std::unique(involved_nets.begin(), involved_nets.end())));
|
||||
|
||||
// Test the cost for the old position and the cost swapping the cells
|
||||
std::int64_t old_cost = get_nets_cost(circuit, pl, involved_nets);
|
||||
|
||||
// Save the old values
|
||||
point<int_t> p1 = pl.plt_.positions_[c1];
|
||||
point<int_t> p2 = pl.plt_.positions_[c2];
|
||||
point<bool> o1 = pl.plt_.orientations_[c1];
|
||||
point<bool> o2 = pl.plt_.orientations_[c2];
|
||||
|
||||
// Warning: won't work if the two cells don't have the same height
|
||||
pl.plt_.positions_[c1].x = (swp_min_c1 + swp_max_c1) / 2;
|
||||
pl.plt_.positions_[c2].x = (swp_min_c2 + swp_max_c2) / 2;
|
||||
pl.plt_.positions_[c1].y = p2.y;
|
||||
pl.plt_.positions_[c2].y = p1.y;
|
||||
|
||||
// For standard cell placement, we want all the rows to be aligned in the same way
|
||||
if( (circuit.get_cell(c1).attributes & YFlippable) != 0 and (circuit.get_cell(c2).attributes & YFlippable) != 0)
|
||||
std::swap(pl.plt_.orientations_[c1].y, pl.plt_.orientations_[c2].y);
|
||||
|
||||
if(try_flip and (circuit.get_cell(c1).attributes & XFlippable) != 0 and (circuit.get_cell(c2).attributes & XFlippable) != 0){
|
||||
index_t bst_ind = 4;
|
||||
for(index_t i=0; i<4; ++i){
|
||||
pl.plt_.orientations_[c1].x = i % 2;
|
||||
pl.plt_.orientations_[c2].x = i / 2;
|
||||
std::int64_t new_cost = get_nets_cost(circuit, pl, involved_nets);
|
||||
if(new_cost < old_cost){
|
||||
old_cost = new_cost;
|
||||
bst_ind = i;
|
||||
}
|
||||
}
|
||||
|
||||
// One of the orientations with the new positions was better
|
||||
if(bst_ind < 4){
|
||||
pl.swap_standard_cell_topologies(c1, c2);
|
||||
pl.plt_.orientations_[c1].x = bst_ind % 2;
|
||||
pl.plt_.orientations_[c2].x = bst_ind / 2;
|
||||
// We kept the swap
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
pl.plt_.positions_[c1] = p1;
|
||||
pl.plt_.positions_[c2] = p2;
|
||||
pl.plt_.orientations_[c1] = o1;
|
||||
pl.plt_.orientations_[c2] = o2;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(get_nets_cost(circuit, pl, involved_nets) < old_cost){
|
||||
pl.swap_standard_cell_topologies(c1, c2);
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
// Reset the old values since we didn't swap anything
|
||||
pl.plt_.positions_[c1] = p1;
|
||||
pl.plt_.positions_[c2] = p2;
|
||||
pl.plt_.orientations_[c1] = o1;
|
||||
pl.plt_.orientations_[c2] = o2;
|
||||
return false;
|
||||
}
|
||||
|
||||
// A better solution would be
|
||||
// Check the cost on y depending on the position (extremely simple: two positions for each cell)
|
||||
// Check the cost on x depending on the position: piecewise linear and relatively complex
|
||||
// * Get all external pins
|
||||
// * Get all nets involving only one of the cells: piecewise linear cost for each of them
|
||||
// * For nets involving the two cells, we have an additional cost
|
||||
|
||||
}
|
||||
else{ // We just cannot swap those two cells without pushing anything
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline void generic_swaps_global(netlist const & circuit, detailed_placement & pl, index_t row_extent, index_t cell_extent, bool try_flip,
|
||||
std::function<std::int64_t(netlist const &, detailed_placement const &, std::vector<index_t> const &)> get_nets_cost){
|
||||
for(index_t main_row = 0; main_row < pl.row_cnt(); ++main_row){
|
||||
|
||||
for(index_t other_row = main_row+1; other_row <= std::min(pl.row_cnt()-1, main_row+row_extent) ; ++other_row){
|
||||
|
||||
index_t first_oc = pl.get_first_standard_cell_on_row(other_row); // The first candidate cell to be examined
|
||||
for(index_t c = pl.get_first_standard_cell_on_row(main_row); c != null_ind; c = pl.get_next_standard_cell_on_row(c, main_row)){
|
||||
assert(pl.cell_rows_[c] == main_row);
|
||||
if( (circuit.get_cell(c).attributes & XMovable) == 0) continue; // Don't touch fixed cells
|
||||
|
||||
// Number of cells after/before the end of the cell
|
||||
index_t nb_after = 0;
|
||||
index_t nb_before = 0;
|
||||
int_t pos_low = pl.plt_.positions_[c].x - circuit.get_cell(c).size.x,
|
||||
pos_hgh = pl.plt_.positions_[c].x + 2*circuit.get_cell(c).size.x;
|
||||
for(index_t oc=first_oc; oc != null_ind and nb_after <= row_extent; oc = pl.get_next_standard_cell_on_row(oc, other_row)){
|
||||
assert(pl.cell_rows_[oc] == other_row);
|
||||
if( (circuit.get_cell(oc).attributes & XMovable) == 0) continue; // Don't touche fixed cells
|
||||
|
||||
// Count the cells which should trigger stop or shouldn't be used at the next iteration
|
||||
if(pl.plt_.positions_[oc].x >= pos_hgh) ++nb_after;
|
||||
if(pl.plt_.positions_[oc].x + circuit.get_cell(oc).size.x <= pos_low) ++ nb_before;
|
||||
|
||||
if(try_swap(circuit, pl, c, oc, try_flip, get_nets_cost)){
|
||||
std::swap(c, oc);
|
||||
if(c == first_oc) first_oc = oc;
|
||||
}
|
||||
}
|
||||
while(nb_before > cell_extent){
|
||||
nb_before--;
|
||||
first_oc = pl.get_next_standard_cell_on_row(first_oc, other_row);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pl.selfcheck();
|
||||
}
|
||||
|
||||
} // End anonymous namespace
|
||||
|
||||
void swaps_global_HPWL(netlist const & circuit, detailed_placement & pl, index_t row_extent, index_t cell_extent, bool try_flip){
|
||||
generic_swaps_global(circuit, pl, row_extent, cell_extent, try_flip,
|
||||
[](netlist const & circuit, detailed_placement const & pl, std::vector<index_t> const & involved_nets) -> std::int64_t{
|
||||
std::int64_t sum = 0;
|
||||
for(index_t n : involved_nets){
|
||||
if(circuit.get_net(n).pin_cnt <= 1) continue;
|
||||
sum += get_HPWL_length(circuit, pl.plt_, n);
|
||||
}
|
||||
return sum;
|
||||
});
|
||||
}
|
||||
|
||||
void swaps_global_RSMT(netlist const & circuit, detailed_placement & pl, index_t row_extent, index_t cell_extent, bool try_flip){
|
||||
generic_swaps_global(circuit, pl, row_extent, cell_extent, try_flip,
|
||||
[](netlist const & circuit, detailed_placement const & pl, std::vector<index_t> const & involved_nets) -> std::int64_t{
|
||||
std::int64_t sum = 0;
|
||||
for(index_t n : involved_nets){
|
||||
if(circuit.get_net(n).pin_cnt <= 1) continue;
|
||||
sum += get_RSMT_length(circuit, pl.plt_, n);
|
||||
}
|
||||
return sum;
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace dp
|
||||
} // namespace coloquinte
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
|
||||
#include "coloquinte/circuit.hxx"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace coloquinte{
|
||||
|
||||
void netlist::selfcheck() const{
|
||||
index_t cell_cnt = cell_areas_.size();
|
||||
assert(cell_cnt+1 == cell_limits_.size());
|
||||
assert(cell_cnt == cell_sizes_.size());
|
||||
assert(cell_cnt == cell_attributes_.size());
|
||||
assert(cell_cnt == cell_internal_mapping_.size());
|
||||
|
||||
index_t net_cnt = net_weights_.size();
|
||||
assert(net_cnt+1 == net_limits_.size());
|
||||
assert(net_cnt == net_internal_mapping_.size());
|
||||
|
||||
index_t pin_cnt = pin_offsets_.size();
|
||||
assert(pin_cnt == cell_indexes_.size());
|
||||
assert(pin_cnt == pin_indexes_.size());
|
||||
assert(pin_cnt == net_indexes_.size());
|
||||
|
||||
for(auto const p : pin_offsets_){
|
||||
assert(std::isfinite(p.x) and std::isfinite(p.y));
|
||||
}
|
||||
}
|
||||
|
||||
// For compatibility reasons
|
||||
void placement_t::selfcheck() const{
|
||||
}
|
||||
|
||||
void verify_placement_legality(netlist const & circuit, placement_t const & pl, box<int_t> surface){
|
||||
std::vector<box<int_t> > cells;
|
||||
for(index_t i=0; i<circuit.cell_cnt(); ++i){
|
||||
auto S = circuit.get_cell(i).size;
|
||||
cells.push_back(box<int_t>(pl.positions_[i], pl.positions_[i] + S));
|
||||
|
||||
// Verify that they are within the placement surface; doesn't take fixed macros into account
|
||||
if( (circuit.get_cell(i).attributes & XMovable) != 0 or (circuit.get_cell(i).attributes & YMovable) != 0){
|
||||
assert(cells[i].in(surface));
|
||||
}
|
||||
}
|
||||
|
||||
// Simple sweepline algorithm to verify that there is no overlap
|
||||
struct event{
|
||||
int_t x_min, x_max, y;
|
||||
index_t cell;
|
||||
bool removal;
|
||||
bool operator<(event const o) const{
|
||||
return y < o.y
|
||||
or (y == o.y and removal and not o.removal); // Remove before inserting
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<event> all_events;
|
||||
for(index_t i=0; i<circuit.cell_cnt(); ++i){
|
||||
event b, e;
|
||||
b.cell = i; e.cell = i;
|
||||
b.x_min = cells[i].x_min; e.x_min = cells[i].x_min;
|
||||
b.x_max = cells[i].x_max; e.x_max = cells[i].x_max;
|
||||
b.y = cells[i].y_min; b.removal = false;
|
||||
e.y = cells[i].y_max; e.removal = true;
|
||||
if(b.x_max > b.x_min and e.y != b.y){
|
||||
all_events.push_back(b);
|
||||
all_events.push_back(e);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(all_events.begin(), all_events.end());
|
||||
|
||||
// Indexed by beginning of interval, with end of interval and cell within
|
||||
std::map<int_t, std::pair<int_t, index_t> > active_rectangles;
|
||||
|
||||
for(event E : all_events){
|
||||
if(E.removal){
|
||||
auto it = active_rectangles.find(E.x_min);
|
||||
assert(it != active_rectangles.end());
|
||||
active_rectangles.erase(it);
|
||||
}
|
||||
else{ // Find anything that intersects with E; if not, add it
|
||||
auto it = active_rectangles.lower_bound(E.x_min); // First interval after
|
||||
if(it != active_rectangles.end()){
|
||||
assert(it->first >= E.x_max); //Intersection between E.cell and it->second->second
|
||||
}
|
||||
if(it != active_rectangles.begin()){
|
||||
--it;
|
||||
assert(it->second.first <= E.x_min); //Intersection between E.cell and it->second->second
|
||||
}
|
||||
active_rectangles.insert(std::pair<int_t, std::pair<int_t, index_t> >(E.x_min, std::pair<int_t, index_t>(E.x_max, E.cell)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace coloquinte
|
|
@ -1,408 +0,0 @@
|
|||
|
||||
#include "coloquinte/circuit_helper.hxx"
|
||||
#include "coloquinte/circuit.hxx"
|
||||
#include <cmath>
|
||||
|
||||
namespace coloquinte{
|
||||
|
||||
std::int64_t get_HPWL_length(netlist const & circuit, placement_t const & pl, index_t net_ind){
|
||||
if(circuit.get_net(net_ind).pin_cnt <= 1) return 0;
|
||||
|
||||
auto pins = get_pins_1D(circuit, pl, net_ind);
|
||||
auto minmaxX = std::minmax_element(pins.x.begin(), pins.x.end()), minmaxY = std::minmax_element(pins.y.begin(), pins.y.end());
|
||||
return ((minmaxX.second->pos - minmaxX.first->pos) + (minmaxY.second->pos - minmaxY.first->pos));
|
||||
}
|
||||
|
||||
std::int64_t get_RSMT_length(netlist const & circuit, placement_t const & pl, index_t net_ind){
|
||||
if(circuit.get_net(net_ind).pin_cnt <= 1) return 0;
|
||||
auto pins = get_pins_2D(circuit, pl, net_ind);
|
||||
std::vector<point<int_t> > points;
|
||||
for(pin_2D const p : pins){
|
||||
points.push_back(p.pos);
|
||||
}
|
||||
return RSMT_length(points, 8);
|
||||
}
|
||||
|
||||
namespace gp{
|
||||
|
||||
void add_force(pin_1D const p1, pin_1D const p2, linear_system & L, float_t force){
|
||||
if(p1.movable && p2.movable){
|
||||
L.add_force(
|
||||
force,
|
||||
p1.cell_ind, p2.cell_ind,
|
||||
p1.offs, p2.offs
|
||||
);
|
||||
}
|
||||
else if(p1.movable){
|
||||
L.add_fixed_force(
|
||||
force,
|
||||
p1.cell_ind,
|
||||
p2.pos,
|
||||
p1.offs
|
||||
);
|
||||
}
|
||||
else if(p2.movable){
|
||||
L.add_fixed_force(
|
||||
force,
|
||||
p2.cell_ind,
|
||||
p1.pos,
|
||||
p2.offs
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void add_force(pin_1D const p1, pin_1D const p2, linear_system & L, float_t tol, float_t scale){
|
||||
add_force(p1, p2, L, scale/std::max(tol, static_cast<float_t>(std::abs((float)(p2.pos-p1.pos)))));
|
||||
}
|
||||
|
||||
point<linear_system> empty_linear_systems(netlist const & circuit, placement_t const & pl){
|
||||
point<linear_system> ret = point<linear_system>(linear_system(circuit.cell_cnt()), linear_system(circuit.cell_cnt()));
|
||||
|
||||
for(index_t i=0; i<circuit.cell_cnt(); ++i){
|
||||
bool found_true_net=false;
|
||||
for(auto p : circuit.get_cell(i)){
|
||||
if(circuit.get_net(p.net_ind).pin_cnt > 1){
|
||||
found_true_net = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( (XMovable & circuit.get_cell(i).attributes) == 0 or not found_true_net){
|
||||
ret.x.add_triplet(i, i, 1.0f);
|
||||
ret.x.add_doublet(i, pl.positions_[i].x);
|
||||
}
|
||||
if( (YMovable & circuit.get_cell(i).attributes) == 0 or not found_true_net){
|
||||
ret.y.add_triplet(i, i, 1.0f);
|
||||
ret.y.add_doublet(i, pl.positions_[i].y);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
namespace{ // Anonymous namespace for helper functions
|
||||
|
||||
void get_HPWLF(std::vector<pin_1D> const & pins, linear_system & L, float_t tol){
|
||||
if(pins.size() >= 2){
|
||||
auto min_elt = std::min_element(pins.begin(), pins.end()), max_elt = std::max_element(pins.begin(), pins.end());
|
||||
|
||||
for(auto it = pins.begin(); it != pins.end(); ++it){
|
||||
// Just comparing the iterator is poorer due to redundancies in the benchmarks!
|
||||
if(it != min_elt){
|
||||
add_force(*it, *min_elt, L, tol, 1.0f/(pins.size()-1));
|
||||
if(it != max_elt){ // Hopefully only one connexion between the min and max pins
|
||||
add_force(*it, *max_elt, L, tol, 1.0f/(pins.size()-1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void get_HPWLR(std::vector<pin_1D> const & pins, linear_system & L, float_t tol){
|
||||
std::vector<pin_1D> sorted_pins = pins;
|
||||
std::sort(sorted_pins.begin(), sorted_pins.end());
|
||||
// Pins are connected to the pin two places away
|
||||
for(index_t i=0; i+2<sorted_pins.size(); ++i){
|
||||
add_force(sorted_pins[i], sorted_pins[i+2], L, tol, 0.5f);
|
||||
}
|
||||
// The extreme pins are connected with their direct neighbour too
|
||||
if(sorted_pins.size() > 1){
|
||||
add_force(sorted_pins[0], sorted_pins[1], L, tol, 0.5f);
|
||||
add_force(sorted_pins[sorted_pins.size()-1], sorted_pins[sorted_pins.size()-2], L, tol, 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
void get_star(std::vector<pin_1D> const & pins, linear_system & L, float_t tol, index_t star_index){
|
||||
// The net is empty, but we still populate the diagonal to avoid divide by zeros
|
||||
if(pins.size() < 2){
|
||||
L.add_triplet(star_index, star_index, 1.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
for(pin_1D p : pins){
|
||||
pin_1D star_pin = pin_1D(star_index, 0, 0, true);
|
||||
add_force(p, star_pin, L, 1.0/pins.size());
|
||||
}
|
||||
}
|
||||
|
||||
void get_clique(std::vector<pin_1D> const & pins, linear_system & L, float_t tol){
|
||||
// Pins are connected to the pin two places away
|
||||
for(index_t i=0; i+1<pins.size(); ++i){
|
||||
for(index_t j=i+1; j<pins.size(); ++j){
|
||||
add_force(pins[i], pins[j], L, tol, 1.0f/(pins.size()-1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End anonymous namespace
|
||||
|
||||
point<linear_system> get_HPWLF_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){
|
||||
point<linear_system> L = empty_linear_systems(circuit, pl);
|
||||
for(index_t i=0; i<circuit.net_cnt(); ++i){
|
||||
// Has the net the right pin count?
|
||||
index_t pin_cnt = circuit.get_net(i).pin_cnt;
|
||||
if(pin_cnt < min_s or pin_cnt >= max_s) continue;
|
||||
|
||||
auto pins = get_pins_1D(circuit, pl, i);
|
||||
get_HPWLF(pins.x, L.x, tol);
|
||||
get_HPWLF(pins.y, L.y, tol);
|
||||
}
|
||||
return L;
|
||||
}
|
||||
|
||||
point<linear_system> get_HPWLR_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){
|
||||
point<linear_system> L = empty_linear_systems(circuit, pl);
|
||||
for(index_t i=0; i<circuit.net_cnt(); ++i){
|
||||
// Has the net the right pin count?
|
||||
index_t pin_cnt = circuit.get_net(i).pin_cnt;
|
||||
if(pin_cnt < min_s or pin_cnt >= max_s) continue;
|
||||
|
||||
auto pins = get_pins_1D(circuit, pl, i);
|
||||
get_HPWLR(pins.x, L.x, tol);
|
||||
get_HPWLR(pins.y, L.y, tol);
|
||||
}
|
||||
return L;
|
||||
}
|
||||
|
||||
point<linear_system> get_star_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){
|
||||
point<linear_system> L = empty_linear_systems(circuit, pl);
|
||||
L.x.add_variables(circuit.net_cnt());
|
||||
L.y.add_variables(circuit.net_cnt());
|
||||
for(index_t i=0; i<circuit.net_cnt(); ++i){
|
||||
// Has the net the right pin count?
|
||||
index_t pin_cnt = circuit.get_net(i).pin_cnt;
|
||||
if(pin_cnt < min_s or pin_cnt >= max_s){
|
||||
// Put a one in the intermediate variable in order to avoid non-invertible matrices
|
||||
L.x.add_triplet(i+circuit.cell_cnt(), i+circuit.cell_cnt(), 1.0f);
|
||||
L.y.add_triplet(i+circuit.cell_cnt(), i+circuit.cell_cnt(), 1.0f);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto pins = get_pins_1D(circuit, pl, i);
|
||||
// Provide the index of the star's central pin in the linear system
|
||||
get_star(pins.x, L.x, tol, i+circuit.cell_cnt());
|
||||
get_star(pins.y, L.y, tol, i+circuit.cell_cnt());
|
||||
}
|
||||
return L;
|
||||
}
|
||||
|
||||
point<linear_system> get_clique_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){
|
||||
point<linear_system> L = empty_linear_systems(circuit, pl);
|
||||
for(index_t i=0; i<circuit.net_cnt(); ++i){
|
||||
// Has the net the right pin count?
|
||||
index_t pin_cnt = circuit.get_net(i).pin_cnt;
|
||||
if(pin_cnt < min_s or pin_cnt >= max_s) continue;
|
||||
|
||||
auto pins = get_pins_1D(circuit, pl, i);
|
||||
get_clique(pins.x, L.x, tol);
|
||||
get_clique(pins.y, L.y, tol);
|
||||
}
|
||||
return L;
|
||||
}
|
||||
|
||||
point<linear_system> get_MST_linear_system(netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){
|
||||
point<linear_system> L = empty_linear_systems(circuit, pl);
|
||||
for(index_t i=0; i<circuit.net_cnt(); ++i){
|
||||
// Has the net the right pin count?
|
||||
index_t pin_cnt = circuit.get_net(i).pin_cnt;
|
||||
if(pin_cnt < min_s or pin_cnt >= max_s or pin_cnt <= 1) continue;
|
||||
|
||||
auto pins = get_pins_2D(circuit, pl, i);
|
||||
std::vector<point<int_t> > points;
|
||||
for(pin_2D const p : pins){
|
||||
points.push_back(p.pos);
|
||||
}
|
||||
auto const edges = get_MST_topology(points);
|
||||
for(auto E : edges){
|
||||
add_force(pins[E.first].x(), pins[E.second].x(), L.x, tol, 1.0f);
|
||||
add_force(pins[E.first].y(), pins[E.second].y(), L.y, tol, 1.0f);
|
||||
}
|
||||
}
|
||||
return L;
|
||||
}
|
||||
|
||||
point<linear_system> get_RSMT_linear_system(netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s){
|
||||
point<linear_system> L = empty_linear_systems(circuit, pl);
|
||||
for(index_t i=0; i<circuit.net_cnt(); ++i){
|
||||
// Has the net the right pin count?
|
||||
index_t pin_cnt = circuit.get_net(i).pin_cnt;
|
||||
if(pin_cnt < min_s or pin_cnt >= max_s or pin_cnt <= 1) continue;
|
||||
|
||||
auto pins = get_pins_2D(circuit, pl, i);
|
||||
std::vector<point<int_t> > points;
|
||||
for(pin_2D const p : pins){
|
||||
points.push_back(p.pos);
|
||||
}
|
||||
auto const edges = get_RSMT_topology(points, 8);
|
||||
for(auto E : edges.x){
|
||||
add_force(pins[E.first].x(), pins[E.second].x(), L.x, tol, 1.0f);
|
||||
}
|
||||
for(auto E : edges.y){
|
||||
add_force(pins[E.first].y(), pins[E.second].y(), L.y, tol, 1.0f);
|
||||
}
|
||||
}
|
||||
return L;
|
||||
}
|
||||
|
||||
|
||||
std::int64_t get_HPWL_wirelength(netlist const & circuit, placement_t const & pl){
|
||||
std::int64_t sum = 0;
|
||||
for(index_t i=0; i<circuit.net_cnt(); ++i){
|
||||
sum += get_HPWL_length(circuit, pl, i);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
// The true wirelength with minimum spanning trees, except for very small nets (<= 3) where we have HPWL == true WL
|
||||
std::int64_t get_MST_wirelength(netlist const & circuit, placement_t const & pl){
|
||||
std::int64_t sum = 0;
|
||||
for(index_t i=0; i<circuit.net_cnt(); ++i){
|
||||
auto pins = get_pins_2D(circuit, pl, i);
|
||||
std::vector<point<int_t> > points;
|
||||
for(pin_2D const p : pins){
|
||||
points.push_back(p.pos);
|
||||
}
|
||||
sum += MST_length(points);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
std::int64_t get_RSMT_wirelength(netlist const & circuit, placement_t const & pl){
|
||||
std::int64_t sum = 0;
|
||||
for(index_t i=0; i<circuit.net_cnt(); ++i){
|
||||
sum += get_RSMT_length(circuit, pl, i);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void solve_linear_system(netlist const & circuit, placement_t & pl, point<linear_system> & L, index_t nbr_iter){
|
||||
std::vector<float_t> x_sol, y_sol;
|
||||
std::vector<float_t> x_guess(pl.cell_cnt()), y_guess(pl.cell_cnt());
|
||||
|
||||
assert(L.x.internal_size() == x_guess.size());
|
||||
assert(L.y.internal_size() == y_guess.size());
|
||||
|
||||
for(index_t i=0; i<pl.cell_cnt(); ++i){
|
||||
x_guess[i] = static_cast<float_t>(pl.positions_[i].x);
|
||||
y_guess[i] = static_cast<float_t>(pl.positions_[i].y);
|
||||
}
|
||||
#pragma omp parallel sections num_threads(2)
|
||||
{
|
||||
#pragma omp section
|
||||
x_sol = L.x.solve_CG(x_guess, nbr_iter);
|
||||
#pragma omp section
|
||||
y_sol = L.y.solve_CG(y_guess, nbr_iter);
|
||||
}
|
||||
for(index_t i=0; i<pl.cell_cnt(); ++i){
|
||||
if( (circuit.get_cell(i).attributes & XMovable) != 0){
|
||||
assert(std::isfinite(x_sol[i]));
|
||||
pl.positions_[i].x = static_cast<int_t>(x_sol[i]);
|
||||
}
|
||||
if( (circuit.get_cell(i).attributes & YMovable) != 0){
|
||||
assert(std::isfinite(y_sol[i]));
|
||||
pl.positions_[i].y = static_cast<int_t>(y_sol[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Intended to be used by pulling forces to adapt the forces to the cell's areas
|
||||
std::vector<float_t> get_area_scales(netlist const & circuit){
|
||||
std::vector<float_t> ret(circuit.cell_cnt());
|
||||
capacity_t int_tot_area = 0;
|
||||
for(index_t i=0; i<circuit.cell_cnt(); ++i){
|
||||
capacity_t A = circuit.get_cell(i).area;
|
||||
ret[i] = static_cast<float_t>(A);
|
||||
int_tot_area += A;
|
||||
}
|
||||
float_t inv_average_area = circuit.cell_cnt() / static_cast<float_t>(int_tot_area);
|
||||
for(index_t i=0; i<circuit.cell_cnt(); ++i){
|
||||
ret[i] *= inv_average_area;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
point<linear_system> get_pulling_forces (netlist const & circuit, placement_t const & pl, float_t typical_distance){
|
||||
point<linear_system> L = empty_linear_systems(circuit, pl);
|
||||
float_t typical_force = 1.0f / typical_distance;
|
||||
std::vector<float_t> scaling = get_area_scales(circuit);
|
||||
for(index_t i=0; i<pl.cell_cnt(); ++i){
|
||||
L.x.add_anchor(
|
||||
typical_force * scaling[i],
|
||||
i, pl.positions_[i].x
|
||||
);
|
||||
L.y.add_anchor(
|
||||
typical_force * scaling[i],
|
||||
i, pl.positions_[i].y
|
||||
);
|
||||
}
|
||||
|
||||
return L;
|
||||
}
|
||||
|
||||
point<linear_system> get_linear_pulling_forces (netlist const & circuit, placement_t const & UB_pl, placement_t const & LB_pl, float_t force, float_t min_distance){
|
||||
point<linear_system> L = empty_linear_systems(circuit, UB_pl);
|
||||
assert(LB_pl.cell_cnt() == UB_pl.cell_cnt());
|
||||
std::vector<float_t> scaling = get_area_scales(circuit);
|
||||
for(index_t i=0; i<LB_pl.cell_cnt(); ++i){
|
||||
L.x.add_anchor(
|
||||
force * scaling[i] / (std::max(static_cast<float_t>(std::abs((float)(UB_pl.positions_[i].x - LB_pl.positions_[i].x))), min_distance)),
|
||||
i, UB_pl.positions_[i].x
|
||||
);
|
||||
L.y.add_anchor(
|
||||
force * scaling[i] / (std::max(static_cast<float_t>(std::abs((float)(UB_pl.positions_[i].y - LB_pl.positions_[i].y))), min_distance)),
|
||||
i, UB_pl.positions_[i].y
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return L;
|
||||
}
|
||||
|
||||
region_distribution get_rough_legalizer(netlist const & circuit, placement_t const & pl, box<int_t> surface){
|
||||
return region_distribution::uniform_density_distribution(surface, circuit, pl);
|
||||
}
|
||||
|
||||
void get_rough_legalization(netlist const & circuit, placement_t & pl, region_distribution const & legalizer){
|
||||
auto exportation = legalizer.export_spread_positions_linear();
|
||||
for(auto const C : exportation){
|
||||
pl.positions_[C.index_in_placement_] = static_cast<point<int_t> >(C.pos_ - 0.5f * static_cast<point<float_t> >(circuit.get_cell(C.index_in_placement_).size));
|
||||
}
|
||||
}
|
||||
|
||||
float_t get_mean_linear_disruption(netlist const & circuit, placement_t const & LB_pl, placement_t const & UB_pl){
|
||||
float_t tot_cost = 0.0;
|
||||
float_t tot_area = 0.0;
|
||||
for(index_t i=0; i<circuit.cell_cnt(); ++i){
|
||||
float_t area = static_cast<float_t>(circuit.get_cell(i).area);
|
||||
point<int_t> diff = LB_pl.positions_[i] - UB_pl.positions_[i];
|
||||
|
||||
if( (circuit.get_cell(i).attributes & XMovable) == 0) assert(diff.x == 0);
|
||||
if( (circuit.get_cell(i).attributes & YMovable) == 0) assert(diff.y == 0);
|
||||
|
||||
tot_cost += area * (std::abs((float)diff.x) + std::abs((float)diff.y));
|
||||
tot_area += area;
|
||||
}
|
||||
return tot_cost / tot_area;
|
||||
}
|
||||
|
||||
float_t get_mean_quadratic_disruption(netlist const & circuit, placement_t const & LB_pl, placement_t const & UB_pl){
|
||||
float_t tot_cost = 0.0;
|
||||
float_t tot_area = 0.0;
|
||||
for(index_t i=0; i<circuit.cell_cnt(); ++i){
|
||||
float_t area = static_cast<float_t>(circuit.get_cell(i).area);
|
||||
point<int_t> diff = LB_pl.positions_[i] - UB_pl.positions_[i];
|
||||
|
||||
if( (circuit.get_cell(i).attributes & XMovable) == 0) assert(diff.x == 0);
|
||||
if( (circuit.get_cell(i).attributes & YMovable) == 0) assert(diff.y == 0);
|
||||
|
||||
float_t manhattan = (std::abs((float)diff.x) + std::abs((float)diff.y));
|
||||
tot_cost += area * manhattan * manhattan;
|
||||
tot_area += area;
|
||||
}
|
||||
return std::sqrt(tot_cost / tot_area);
|
||||
}
|
||||
|
||||
} // namespace gp
|
||||
} // namespace coloquinte
|
||||
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
|
||||
#ifndef COLOQUINTE_GP_CIRCUIT
|
||||
#define COLOQUINTE_GP_CIRCUIT
|
||||
|
||||
#include "common.hxx"
|
||||
#include "solvers.hxx"
|
||||
#include "netlist.hxx"
|
||||
#include "rough_legalizers.hxx"
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
namespace coloquinte{
|
||||
|
||||
void verify_placement_legality(netlist const & circuit, placement_t const & pl, box<int_t> surface);
|
||||
|
||||
namespace gp{
|
||||
|
||||
point<linear_system> empty_linear_systems(netlist const & circuit, placement_t const & pl);
|
||||
|
||||
// Net models stuff
|
||||
point<linear_system> get_HPWLF_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s);
|
||||
point<linear_system> get_HPWLR_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s);
|
||||
point<linear_system> get_star_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s);
|
||||
point<linear_system> get_clique_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s);
|
||||
point<linear_system> get_MST_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s);
|
||||
point<linear_system> get_RSMT_linear_system (netlist const & circuit, placement_t const & pl, float_t tol, index_t min_s, index_t max_s);
|
||||
|
||||
// Additional forces
|
||||
point<linear_system> get_pulling_forces (netlist const & circuit, placement_t const & pl, float_t typical_distance);
|
||||
point<linear_system> get_linear_pulling_forces (netlist const & circuit, placement_t const & UB_pl, placement_t const & LB_pl, float_t force, float_t min_distance);
|
||||
|
||||
// Solve the final linear system
|
||||
void solve_linear_system(netlist const & circuit, placement_t & pl, point<linear_system> & L, index_t nbr_iter);
|
||||
|
||||
// Cost-related stuff, whether wirelength or disruption
|
||||
std::int64_t get_HPWL_wirelength (netlist const & circuit, placement_t const & pl);
|
||||
std::int64_t get_MST_wirelength (netlist const & circuit, placement_t const & pl);
|
||||
std::int64_t get_RSMT_wirelength (netlist const & circuit, placement_t const & pl);
|
||||
|
||||
float_t get_mean_linear_disruption(netlist const & circuit, placement_t const & LB_pl, placement_t const & UB_pl);
|
||||
float_t get_mean_quadratic_disruption(netlist const & circuit, placement_t const & LB_pl, placement_t const & UB_pl);
|
||||
|
||||
// Legalizer-related stuff
|
||||
region_distribution get_rough_legalizer(netlist const & circuit, placement_t const & pl, box<int_t> surface);
|
||||
void get_rough_legalization(netlist const & circuit, placement_t & pl, region_distribution const & legalizer);
|
||||
|
||||
// Cell orientation optimization
|
||||
void optimize_x_orientations(netlist const & circuit, placement_t & pl);
|
||||
void optimize_y_orientations(netlist const & circuit, placement_t & pl);
|
||||
void optimize_exact_orientations(netlist const & circuit, placement_t & pl);
|
||||
//void spread_orientations(netlist const & circuit, placement_t & pl);
|
||||
|
||||
|
||||
} // namespace gp
|
||||
} // namespace coloquinte
|
||||
|
||||
#endif
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
|
||||
#ifndef COLOQUINTE_GP_HELPERCIRCUIT
|
||||
#define COLOQUINTE_GP_HELPERCIRCUIT
|
||||
|
||||
#include "common.hxx"
|
||||
#include "netlist.hxx"
|
||||
#include <cmath>
|
||||
|
||||
namespace coloquinte{
|
||||
|
||||
struct pin_1D{
|
||||
index_t cell_ind;
|
||||
int_t pos;
|
||||
int_t offs;
|
||||
bool movable;
|
||||
|
||||
bool operator<(pin_1D const o) const { return pos < o.pos; }
|
||||
|
||||
pin_1D(index_t c, int_t p, int_t o, bool m) : cell_ind(c), pos(p), offs(o), movable(m){}
|
||||
};
|
||||
struct pin_2D{
|
||||
index_t cell_ind;
|
||||
point<int_t> pos;
|
||||
point<int_t> offs;
|
||||
bool movable;
|
||||
|
||||
pin_2D(index_t c, point<int_t> p, point<int_t> o, bool m) : cell_ind(c), pos(p), offs(o), movable(m){}
|
||||
pin_1D x() const{ return pin_1D(cell_ind, pos.x, offs.x, movable); }
|
||||
pin_1D y() const{ return pin_1D(cell_ind, pos.y, offs.y, movable); }
|
||||
};
|
||||
|
||||
inline int_t dist(pin_2D const a, pin_2D const b){
|
||||
point<int_t> diff = a.pos - b.pos;
|
||||
return std::abs((float)diff.x) + std::abs((float)diff.y);
|
||||
}
|
||||
|
||||
inline std::vector<pin_2D> get_pins_2D(netlist const & circuit, placement_t const & pl, index_t net_ind){
|
||||
std::vector<pin_2D> ret;
|
||||
for(auto p : circuit.get_net(net_ind)){
|
||||
assert(std::isfinite(pl.positions_[p.cell_ind].x) and std::isfinite(pl.positions_[p.cell_ind].y));
|
||||
assert(std::isfinite(pl.orientations_[p.cell_ind].x) and std::isfinite(pl.orientations_[p.cell_ind].y));
|
||||
|
||||
point<int_t> offs;
|
||||
offs.x = pl.orientations_[p.cell_ind].x ? p.offset.x : circuit.get_cell(p.cell_ind).size.x - p.offset.x;
|
||||
offs.y = pl.orientations_[p.cell_ind].y ? p.offset.y : circuit.get_cell(p.cell_ind).size.y - p.offset.y;
|
||||
point<int_t> pos = offs + pl.positions_[p.cell_ind];
|
||||
|
||||
assert(std::isfinite(offs.x) and std::isfinite(offs.y));
|
||||
assert(std::isfinite(pos.x) and std::isfinite(pos.y));
|
||||
|
||||
bool movable = (circuit.get_cell(p.cell_ind).attributes & XMovable) != 0 and (circuit.get_cell(p.cell_ind).attributes & YMovable) != 0;
|
||||
ret.push_back(pin_2D(p.cell_ind, pos, offs, movable));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline point<std::vector<pin_1D> > get_pins_1D(netlist const & circuit, placement_t const & pl, index_t net_ind){
|
||||
point<std::vector<pin_1D> > ret;
|
||||
for(auto p : circuit.get_net(net_ind)){
|
||||
assert(std::isfinite(pl.positions_[p.cell_ind].x) and std::isfinite(pl.positions_[p.cell_ind].y));
|
||||
assert(std::isfinite(pl.orientations_[p.cell_ind].x) and std::isfinite(pl.orientations_[p.cell_ind].y));
|
||||
|
||||
point<int_t> offs;
|
||||
offs.x = pl.orientations_[p.cell_ind].x ? p.offset.x : circuit.get_cell(p.cell_ind).size.x - p.offset.x;
|
||||
offs.y = pl.orientations_[p.cell_ind].y ? p.offset.y : circuit.get_cell(p.cell_ind).size.y - p.offset.y;
|
||||
point<int_t> pos = offs + pl.positions_[p.cell_ind];
|
||||
|
||||
assert(std::isfinite(offs.x) and std::isfinite(offs.y));
|
||||
assert(std::isfinite(pos.x) and std::isfinite(pos.y));
|
||||
|
||||
bool x_movable = (circuit.get_cell(p.cell_ind).attributes & XMovable) != 0;
|
||||
bool y_movable = (circuit.get_cell(p.cell_ind).attributes & YMovable) != 0;
|
||||
|
||||
ret.x.push_back(pin_1D(p.cell_ind, pos.x, offs.x, x_movable));
|
||||
ret.y.push_back(pin_1D(p.cell_ind, pos.y, offs.y, y_movable));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::int64_t MST_length(std::vector<point<int_t> > const & pins);
|
||||
std::int64_t RSMT_length(std::vector<point<int_t> > const & pins, index_t exactitude_limit);
|
||||
std::int64_t get_HPWL_length(netlist const & circuit, placement_t const & pl, index_t net_ind);
|
||||
std::int64_t get_RSMT_length(netlist const & circuit, placement_t const & pl, index_t net_ind);
|
||||
|
||||
std::vector<std::pair<index_t, index_t> > get_MST_topology(std::vector<point<int_t> > const & pins);
|
||||
std::vector<std::pair<index_t, index_t> > get_RSMT_horizontal_topology(std::vector<point<int_t> > const & pins, index_t exactitude_limits);
|
||||
point<std::vector<std::pair<index_t, index_t> > > get_RSMT_topology(std::vector<point<int_t> > const & pins, index_t exactitude_limit);
|
||||
|
||||
} // namespace coloquinte
|
||||
|
||||
#endif
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
|
||||
#ifndef COLOQUINTE_GP_COMMON
|
||||
#define COLOQUINTE_GP_COMMON
|
||||
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
|
||||
namespace coloquinte{
|
||||
|
||||
using float_t = float;
|
||||
using int_t = std::int32_t;
|
||||
using index_t = std::uint32_t;
|
||||
using capacity_t = std::int64_t;
|
||||
using mask_t = std::uint32_t;
|
||||
|
||||
using ext_object = std::uint64_t;
|
||||
|
||||
enum PlacementType{
|
||||
Optimist = 0,
|
||||
Pessimist = 1
|
||||
};
|
||||
|
||||
enum Movability{
|
||||
XMovable = 1 ,
|
||||
YMovable = 1 << 1,
|
||||
XFlippable = 1 << 2,
|
||||
YFlippable = 1 << 3,
|
||||
SoftMacro = 1 << 4
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct point{
|
||||
T x, y;
|
||||
point(){}
|
||||
point(T x, T y): x(x), y(y){}
|
||||
|
||||
template<typename S>
|
||||
operator point<S>() const{
|
||||
return point<S>(static_cast<S>(x), static_cast<S>(y));
|
||||
}
|
||||
|
||||
void operator+=(point<T> const o){
|
||||
x += o.x;
|
||||
y += o.y;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
point<T> operator+(point<T> const a, point<T> const b){
|
||||
return point<T>(a.x+b.x, a.y+b.y);
|
||||
}
|
||||
template<typename T>
|
||||
point<T> operator-(point<T> const a, point<T> const b){
|
||||
return point<T>(a.x-b.x, a.y-b.y);
|
||||
}
|
||||
template<typename T>
|
||||
point<T> operator*(T lambda, point<T> const p){
|
||||
return point<T>(lambda * p.x, lambda * p.y);
|
||||
}
|
||||
template<typename T>
|
||||
point<T> operator*(point<T> const a, point<T> const b){
|
||||
return point<T>(a.x*b.x, a.y*b.y);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct box{
|
||||
T x_min, x_max, y_min, y_max;
|
||||
box(){}
|
||||
box(T x_mn, T x_mx, T y_mn, T y_mx) : x_min(x_mn), x_max(x_mx), y_min(y_mn), y_max(y_mx){}
|
||||
box(point<T> mn, point<T> mx) : x_min(mn.x), x_max(mx.x), y_min(mn.y), y_max(mx.y){}
|
||||
|
||||
bool in(box<T> const o) const{
|
||||
return x_max <= o.x_max
|
||||
&& y_max <= o.y_max
|
||||
&& x_min >= o.x_min
|
||||
&& y_min >= o.y_min;
|
||||
}
|
||||
bool intersects(box<T> const o) const{
|
||||
return x_min < o.x_max
|
||||
&& y_min < o.y_max
|
||||
&& o.x_min < x_max
|
||||
&& o.y_min < y_max;
|
||||
}
|
||||
box<T> intersection(box<T> const o) const{
|
||||
return box<T>(
|
||||
std::max(x_min, o.x_min),
|
||||
std::min(x_max, o.x_max),
|
||||
std::max(y_min, o.y_min),
|
||||
std::min(y_max, o.y_max)
|
||||
);
|
||||
}
|
||||
box<T> bounding_box(box<T> const o) const{
|
||||
return box<T>(
|
||||
std::min(x_min, o.x_min),
|
||||
std::max(x_max, o.x_max),
|
||||
std::min(y_min, o.y_min),
|
||||
std::max(y_max, o.y_max)
|
||||
);
|
||||
}
|
||||
point<T> dimensions() const{
|
||||
return point<T>(x_max-x_min, y_max-y_min);
|
||||
}
|
||||
bool empty() const{
|
||||
return dimensions().x <= 0 or dimensions().y <= 0;
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
operator box<S>() const{
|
||||
return box<S>(static_cast<S>(x_min), static_cast<S>(x_max), static_cast<S>(y_min), static_cast<S>(y_max));
|
||||
}
|
||||
};
|
||||
|
||||
using orientation_t = point<bool>;
|
||||
|
||||
} // Namespace coloquinte
|
||||
|
||||
#endif
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
|
||||
#ifndef COLOQUINTE_DETAILED
|
||||
#define COLOQUINTE_DETAILED
|
||||
|
||||
#include "common.hxx"
|
||||
#include "netlist.hxx"
|
||||
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
namespace coloquinte{
|
||||
namespace dp{
|
||||
|
||||
const index_t null_ind = std::numeric_limits<index_t>::max();
|
||||
|
||||
struct detailed_placement{
|
||||
// All position and orientation stuff
|
||||
placement_t plt_;
|
||||
|
||||
std::vector<index_t> cell_rows_;
|
||||
|
||||
// The placement region
|
||||
int_t min_x_, max_x_;
|
||||
int_t y_origin_;
|
||||
int_t row_height_;
|
||||
|
||||
// Encode the topological state of the circuit: which cells are near each other
|
||||
// Makes extracting part of the circuit or optimizing positions at fixed topology easy
|
||||
std::vector<std::pair<index_t, index_t> > neighbours_; // The cells before and after on each row; cells spanning multiple columns use several positions
|
||||
// In order to get the neighbours in the detailed placement
|
||||
std::vector<index_t> neighbours_limits_;
|
||||
|
||||
std::vector<index_t> row_first_cells_, row_last_cells_; // For each row, which cells are the on the boundaries
|
||||
|
||||
// Tests the coherency between positions, widths and topological representation
|
||||
void selfcheck() const;
|
||||
|
||||
detailed_placement(
|
||||
placement_t pl,
|
||||
std::vector<index_t> placement_rows,
|
||||
std::vector<index_t> cell_heights,
|
||||
std::vector<std::vector<index_t> > rows,
|
||||
int_t min_x, int_t max_x,
|
||||
int_t y_origin,
|
||||
index_t nbr_rows, int_t row_height
|
||||
);
|
||||
|
||||
index_t cell_height(index_t c) const{ return neighbours_limits_[c+1] - neighbours_limits_[c]; }
|
||||
index_t cell_cnt() const{ return cell_rows_.size(); }
|
||||
index_t row_cnt() const{ return row_first_cells_.size(); }
|
||||
index_t neighbour_index(index_t c, index_t r) const{
|
||||
assert(r - cell_rows_[c] < cell_height(c));
|
||||
return neighbours_limits_[c] + r - cell_rows_[c];
|
||||
}
|
||||
|
||||
void swap_standard_cell_topologies(index_t c1, index_t c2);
|
||||
std::pair<int_t, int_t> get_limit_positions(netlist const & circuit, index_t c) const;
|
||||
|
||||
index_t get_first_cell_on_row(index_t r);
|
||||
index_t get_next_cell_on_row(index_t c, index_t r);
|
||||
index_t get_prev_cell_on_row(index_t c, index_t r);
|
||||
|
||||
index_t get_first_standard_cell_on_row(index_t r);
|
||||
index_t get_next_standard_cell_on_row(index_t c, index_t r);
|
||||
|
||||
void reorder_standard_cells(std::vector<index_t> const old_order, std::vector<index_t> const new_order);
|
||||
void reorder_cells(std::vector<index_t> const old_order, std::vector<index_t> const new_order, index_t row);
|
||||
};
|
||||
|
||||
void swaps_global_HPWL(netlist const & circuit, detailed_placement & pl, index_t row_extent, index_t cell_extent, bool try_flip = false);
|
||||
void swaps_global_RSMT(netlist const & circuit, detailed_placement & pl, index_t row_extent, index_t cell_extent, bool try_flip = false);
|
||||
|
||||
void swaps_row_convex_HPWL(netlist const & circuit, detailed_placement & pl, index_t range);
|
||||
void swaps_row_convex_RSMT(netlist const & circuit, detailed_placement & pl, index_t range);
|
||||
void swaps_row_noncvx_HPWL(netlist const & circuit, detailed_placement & pl, index_t range);
|
||||
void swaps_row_noncvx_RSMT(netlist const & circuit, detailed_placement & pl, index_t range);
|
||||
|
||||
void OSRP_convex_HPWL(netlist const & circuit, detailed_placement & pl);
|
||||
void OSRP_convex_RSMT(netlist const & circuit, detailed_placement & pl);
|
||||
void OSRP_noncvx_HPWL(netlist const & circuit, detailed_placement & pl);
|
||||
void OSRP_noncvx_RSMT(netlist const & circuit, detailed_placement & pl);
|
||||
|
||||
void row_compatible_orientation(netlist const & circuit, detailed_placement & pl, bool first_row_orient);
|
||||
|
||||
} // namespace dp
|
||||
} // namespace coloquinte
|
||||
|
||||
#endif
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
#include "circuit.hxx"
|
||||
#include "detailed.hxx"
|
||||
|
||||
namespace coloquinte{
|
||||
namespace dp{
|
||||
|
||||
detailed_placement legalize(netlist const & circuit, placement_t const & pl, box<int_t> surface, int_t row_height);
|
||||
void get_result(netlist const & circuit, detailed_placement const & dpl, placement_t & pl);
|
||||
|
||||
} // namespace dp
|
||||
} // namespace coloquinte
|
|
@ -1,251 +0,0 @@
|
|||
|
||||
#ifndef COLOQUINTE_NETLIST
|
||||
#define COLOQUINTE_NETLIST
|
||||
|
||||
#include "common.hxx"
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
|
||||
namespace coloquinte{
|
||||
|
||||
// Structures for construction and circuit_loader
|
||||
struct temporary_pin{
|
||||
point<int_t> offset;
|
||||
index_t cell_ind, net_ind;
|
||||
temporary_pin(){}
|
||||
temporary_pin(point<int_t> offs, index_t c, index_t n) : offset(offs), cell_ind(c), net_ind(n){}
|
||||
};
|
||||
|
||||
struct temporary_cell{
|
||||
point<int_t> size;
|
||||
capacity_t area;
|
||||
mask_t attributes;
|
||||
index_t list_index;
|
||||
|
||||
temporary_cell(){}
|
||||
temporary_cell(point<int_t> s, mask_t attr, index_t ind) : size(s), attributes(attr), list_index(ind){ area = static_cast<capacity_t>(s.x) * static_cast<capacity_t>(s.y);}
|
||||
};
|
||||
|
||||
struct temporary_net{
|
||||
int_t weight;
|
||||
index_t list_index;
|
||||
temporary_net(){}
|
||||
temporary_net(index_t ind, int_t wght) : weight(wght), list_index(ind){}
|
||||
};
|
||||
|
||||
|
||||
// Main class
|
||||
class netlist{
|
||||
std::vector<int_t> net_weights_;
|
||||
|
||||
std::vector<capacity_t> cell_areas_;
|
||||
std::vector<point<int_t> > cell_sizes_;
|
||||
std::vector<mask_t> cell_attributes_;
|
||||
|
||||
// Mapping of the order given at construction time to the internal representation
|
||||
std::vector<index_t> cell_internal_mapping_;
|
||||
std::vector<index_t> net_internal_mapping_;
|
||||
|
||||
// Optimized sparse storage for nets
|
||||
std::vector<index_t> net_limits_;
|
||||
std::vector<index_t> cell_indexes_;
|
||||
std::vector<point<int_t> > pin_offsets_;
|
||||
|
||||
// Sparse storage from cell to net appartenance
|
||||
std::vector<index_t> cell_limits_;
|
||||
std::vector<index_t> net_indexes_;
|
||||
std::vector<index_t> pin_indexes_;
|
||||
|
||||
public:
|
||||
netlist(std::vector<temporary_cell> cells, std::vector<temporary_net> nets, std::vector<temporary_pin> all_pins);
|
||||
netlist(){}
|
||||
|
||||
void selfcheck() const;
|
||||
|
||||
struct pin_t{
|
||||
point<int_t> offset;
|
||||
index_t cell_ind, net_ind;
|
||||
pin_t(point<int_t> offs, index_t c, index_t n) : offset(offs), cell_ind(c), net_ind(n){}
|
||||
};
|
||||
|
||||
class net_pin_iterator{
|
||||
index_t pin_ind, net_ind;
|
||||
netlist const & N;
|
||||
|
||||
public:
|
||||
pin_t operator*() const{
|
||||
return pin_t(N.pin_offsets_[pin_ind], N.cell_indexes_[pin_ind], net_ind);
|
||||
}
|
||||
net_pin_iterator & operator++(){
|
||||
pin_ind++;
|
||||
return *this;
|
||||
}
|
||||
bool operator!=(net_pin_iterator const o) const{
|
||||
return pin_ind != o.pin_ind;
|
||||
}
|
||||
|
||||
net_pin_iterator(index_t net_index, index_t pin_index, netlist const & orig) : pin_ind(pin_index), net_ind(net_index), N(orig){}
|
||||
};
|
||||
|
||||
class cell_pin_iterator{
|
||||
index_t pin_ind, cell_ind;
|
||||
netlist const & N;
|
||||
|
||||
public:
|
||||
pin_t operator*() const{
|
||||
return pin_t(N.pin_offsets_[N.pin_indexes_[pin_ind]], cell_ind, N.net_indexes_[pin_ind]);
|
||||
}
|
||||
cell_pin_iterator & operator++(){
|
||||
pin_ind++;
|
||||
return *this;
|
||||
}
|
||||
bool operator!=(cell_pin_iterator const o) const{
|
||||
return pin_ind != o.pin_ind;
|
||||
}
|
||||
|
||||
cell_pin_iterator(index_t cell_index, index_t pin_index, netlist const & orig) : pin_ind(pin_index), cell_ind(cell_index), N(orig){}
|
||||
};
|
||||
|
||||
struct internal_cell{
|
||||
point<int_t> size;
|
||||
capacity_t area;
|
||||
mask_t attributes;
|
||||
netlist const & N;
|
||||
index_t index;
|
||||
index_t pin_cnt;
|
||||
|
||||
internal_cell(index_t ind, netlist const & orig) :
|
||||
size(orig.cell_sizes_[ind]),
|
||||
area(orig.cell_areas_[ind]),
|
||||
attributes(orig.cell_attributes_[ind]),
|
||||
N(orig),
|
||||
index(ind),
|
||||
pin_cnt(N.cell_limits_[ind+1] - N.cell_limits_[ind])
|
||||
{}
|
||||
|
||||
cell_pin_iterator begin(){ return cell_pin_iterator(index, N.cell_limits_[index], N); }
|
||||
cell_pin_iterator end(){ return cell_pin_iterator(index, N.cell_limits_[index+1], N); }
|
||||
};
|
||||
|
||||
struct internal_net{
|
||||
int_t weight;
|
||||
netlist const & N;
|
||||
index_t index;
|
||||
index_t pin_cnt;
|
||||
|
||||
internal_net(index_t ind, netlist const & orig) :
|
||||
weight(orig.net_weights_[ind]),
|
||||
N(orig),
|
||||
index(ind),
|
||||
pin_cnt(N.net_limits_[ind+1] - N.net_limits_[ind])
|
||||
{}
|
||||
|
||||
net_pin_iterator begin(){ return net_pin_iterator(index, N.net_limits_[index], N); }
|
||||
net_pin_iterator end(){ return net_pin_iterator(index, N.net_limits_[index+1], N); }
|
||||
};
|
||||
|
||||
internal_cell get_cell(index_t ind) const{
|
||||
return internal_cell(ind, *this);
|
||||
}
|
||||
internal_net get_net(index_t ind) const{
|
||||
return internal_net(ind, *this);
|
||||
}
|
||||
|
||||
index_t cell_cnt() const{ return cell_internal_mapping_.size(); }
|
||||
index_t net_cnt() const{ return net_internal_mapping_.size(); }
|
||||
index_t pin_cnt() const{ return pin_offsets_.size(); }
|
||||
|
||||
index_t get_cell_ind(index_t external_ind) const{ return cell_internal_mapping_[external_ind]; }
|
||||
index_t get_net_ind(index_t external_ind) const{ return net_internal_mapping_[external_ind]; }
|
||||
|
||||
point<int_t> get_cell_size(index_t external_ind){
|
||||
return cell_sizes_[ cell_internal_mapping_[external_ind] ];
|
||||
}
|
||||
|
||||
void set_cell_size(index_t external_ind,point<int_t> cell_size){
|
||||
cell_sizes_[cell_internal_mapping_[external_ind]] = cell_size;
|
||||
}
|
||||
};
|
||||
|
||||
inline netlist::netlist(std::vector<temporary_cell> cells, std::vector<temporary_net> nets, std::vector<temporary_pin> all_pins){
|
||||
struct extended_pin : public temporary_pin{
|
||||
index_t pin_index;
|
||||
extended_pin(temporary_pin const p) : temporary_pin(p){}
|
||||
};
|
||||
std::vector<extended_pin> pins;
|
||||
for(temporary_pin const p : all_pins){
|
||||
pins.push_back(extended_pin(p));
|
||||
}
|
||||
|
||||
cell_limits_.resize(cells.size()+1);
|
||||
net_limits_.resize(nets.size()+1);
|
||||
|
||||
net_weights_.resize(nets.size());
|
||||
|
||||
cell_areas_.resize(cells.size());
|
||||
cell_sizes_.resize(cells.size());
|
||||
cell_attributes_.resize(cells.size());
|
||||
|
||||
cell_internal_mapping_.resize(cells.size());
|
||||
net_internal_mapping_.resize(nets.size());
|
||||
|
||||
cell_indexes_.resize(pins.size());
|
||||
pin_offsets_.resize(pins.size());
|
||||
net_indexes_.resize(pins.size());
|
||||
pin_indexes_.resize(pins.size());
|
||||
|
||||
for(index_t i=0; i<nets.size(); ++i){
|
||||
net_internal_mapping_[i] = i;
|
||||
}
|
||||
for(index_t i=0; i<cells.size(); ++i){
|
||||
cell_internal_mapping_[i] = i;
|
||||
}
|
||||
|
||||
std::sort(pins.begin(), pins.end(), [](extended_pin const a, extended_pin const b){ return a.net_ind < b.net_ind; });
|
||||
for(index_t n=0, p=0; n<nets.size(); ++n){
|
||||
net_weights_[n] = nets[n].weight;
|
||||
|
||||
net_limits_[n] = p;
|
||||
while(p<pins.size() && pins[p].net_ind == n){
|
||||
cell_indexes_[p] = pins[p].cell_ind;
|
||||
pin_offsets_[p] = pins[p].offset;
|
||||
pins[p].pin_index = p;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
net_limits_.back() = pins.size();
|
||||
|
||||
std::sort(pins.begin(), pins.end(), [](extended_pin const a, extended_pin const b){ return a.cell_ind < b.cell_ind; });
|
||||
|
||||
for(index_t c=0, p=0; c<cells.size(); ++c){
|
||||
cell_areas_[c] = cells[c].area;
|
||||
cell_attributes_[c] = cells[c].attributes;
|
||||
cell_sizes_[c] = cells[c].size;
|
||||
|
||||
cell_limits_[c] = p;
|
||||
while(p<pins.size() && pins[p].cell_ind == c){
|
||||
net_indexes_[p] = pins[p].net_ind;
|
||||
pin_indexes_[p] = pins[p].pin_index;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
cell_limits_.back() = pins.size();
|
||||
}
|
||||
|
||||
struct placement_t{
|
||||
std::vector<point<int_t> > positions_;
|
||||
std::vector<point<bool> > orientations_;
|
||||
|
||||
index_t cell_cnt() const{
|
||||
assert(positions_.size() == orientations_.size());
|
||||
return positions_.size();
|
||||
}
|
||||
|
||||
void selfcheck() const;
|
||||
};
|
||||
|
||||
} // namespace coloquinte
|
||||
|
||||
#endif
|
||||
|
|
@ -1,161 +0,0 @@
|
|||
|
||||
#ifndef COLOQUINTE_GP_OPTSUBPROBLEMS
|
||||
#define COLOQUINTE_GP_OPTSUBPROBLEMS
|
||||
|
||||
#include "common.hxx"
|
||||
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <numeric>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
namespace coloquinte{
|
||||
|
||||
typedef std::pair<int_t, capacity_t> t1D_elt;
|
||||
|
||||
std::vector<capacity_t> transport_1D(std::vector<t1D_elt> sources, std::vector<t1D_elt> sinks);
|
||||
std::vector<std::vector<capacity_t> > transport_convex(std::vector<capacity_t> const & capacities, std::vector<capacity_t> const & demands, std::vector<std::vector<float_t> > const & costs);
|
||||
std::vector<std::vector<capacity_t> > transport_generic(std::vector<capacity_t> const & capacities, std::vector<capacity_t> const & demands, std::vector<std::vector<float_t> > const & costs);
|
||||
|
||||
template<typename T>
|
||||
struct legalizable_task{
|
||||
T width;
|
||||
T target_pos;
|
||||
index_t ind;
|
||||
legalizable_task(T w, T p, index_t i) : width(w), target_pos(p), ind(i){}
|
||||
bool operator<(legalizable_task<T> const o) const{ return target_pos < o.target_pos; }
|
||||
};
|
||||
|
||||
// A class to obtain the optimal positions minimizing total weighted displacement along a row
|
||||
// It is an ordered single row problem/fixed order single machine scheduling problem, solved by the clumping/specialized cascading descent algorithm
|
||||
// The cost is linear in the distance to the target position, weighted by the width of the cells
|
||||
template<typename T>
|
||||
class OSRP_leg{
|
||||
struct OSRP_bound{
|
||||
T absolute_pos; // Will be the target absolute position of the cell
|
||||
T weight; // Will be the width of the cell
|
||||
|
||||
bool operator<(OSRP_bound const o) const{ return absolute_pos < o.absolute_pos; }
|
||||
OSRP_bound(T w, T abs_pos) : absolute_pos(abs_pos), weight(w) {}
|
||||
};
|
||||
|
||||
T begin, end;
|
||||
|
||||
std::vector<index_t> cells; // The indexes in the circuit
|
||||
std::vector<T> constraining_pos; // Where the cells have been pushed and constrain the positions of preceding cells
|
||||
std::vector<T> prev_width; // Cumulative width of the cells: calculates the absolute position of new cells
|
||||
|
||||
std::priority_queue<OSRP_bound> bounds;
|
||||
|
||||
// Get the cost of pushing a cell on the row
|
||||
T get_displacement(legalizable_task<T> const newly_pushed, bool update);
|
||||
|
||||
public:
|
||||
T current_width() const{ return prev_width.back(); }
|
||||
T remaining_space() const{ return end - begin - current_width(); }
|
||||
T last_available_pos() const{ return constraining_pos.back() + current_width(); }
|
||||
|
||||
T get_cost(legalizable_task<T> const task){ return get_displacement(task, false); }
|
||||
void push(legalizable_task<T> const task){ get_displacement(task, true); }
|
||||
|
||||
// Initialize
|
||||
OSRP_leg(T b, T e) : begin(b), end(e), prev_width(1, 0) {}
|
||||
OSRP_leg(){}
|
||||
|
||||
typedef std::pair<index_t, T> result_t;
|
||||
|
||||
// Get the resulting placement
|
||||
std::vector<result_t> get_placement() const;
|
||||
};
|
||||
|
||||
struct cell_bound{
|
||||
index_t c;
|
||||
int_t pos;
|
||||
int_t slope;
|
||||
bool operator<(cell_bound const o) const{ return c < o.c; }
|
||||
cell_bound(index_t order, int_t p, int_t s) : c(order), pos(p), slope(s) {}
|
||||
};
|
||||
|
||||
bool place_convex_single_row(std::vector<int_t> const & widths, std::vector<std::pair<int_t, int_t> > const & ranges, std::vector<cell_bound> bounds, std::vector<int_t> const & const_slopes, std::vector<int_t> & positions);
|
||||
bool place_noncvx_single_row(std::vector<int_t> const & widths, std::vector<std::pair<int_t, int_t> > const & ranges, std::vector<int> const & flippables, std::vector<cell_bound> bounds, std::vector<int_t> const & const_slopes, std::vector<int_t> & positions, std::vector<int> & flippings);
|
||||
|
||||
template<typename T>
|
||||
inline T OSRP_leg<T>::get_displacement(legalizable_task<T> const newly_pushed, bool update){
|
||||
T target_abs_pos = newly_pushed.target_pos - current_width();
|
||||
T width = newly_pushed.width;
|
||||
T slope = - width;
|
||||
|
||||
T cur_pos = end;
|
||||
T cur_cost = 0;
|
||||
|
||||
std::vector<OSRP_bound> passed_bounds;
|
||||
|
||||
while( not bounds.empty() and
|
||||
((slope < 0 and bounds.top().absolute_pos > target_abs_pos) // Not reached equilibrium
|
||||
or bounds.top().absolute_pos > end - current_width() - width) // Still not a legal position
|
||||
){
|
||||
T old_pos = cur_pos;
|
||||
cur_pos = bounds.top().absolute_pos;
|
||||
cur_cost += (old_pos - cur_pos) * (slope + width); // The additional cost for the other cells encountered
|
||||
slope += bounds.top().weight;
|
||||
|
||||
// Remember which bounds we encountered in order to reset the object to its initial state
|
||||
if(not update)
|
||||
passed_bounds.push_back(bounds.top());
|
||||
bounds.pop();
|
||||
}
|
||||
|
||||
T final_abs_pos = std::min(end - current_width() - width, // Always before the end and after the beginning
|
||||
std::max(begin, slope >= 0 ? cur_pos : target_abs_pos) // but did we stop before reaching the target position?
|
||||
);
|
||||
|
||||
cur_cost += (cur_pos - final_abs_pos) * (slope + width); // The additional cost for the other cells encountered
|
||||
|
||||
if(std::numeric_limits<T>::is_integer){
|
||||
assert(final_abs_pos >= begin);
|
||||
assert(final_abs_pos <= end - current_width() - width);
|
||||
}
|
||||
|
||||
if(update){
|
||||
prev_width.push_back(width + current_width());
|
||||
cells.push_back(newly_pushed.ind);
|
||||
constraining_pos.push_back(final_abs_pos);
|
||||
if(slope > 0){ // Remaining capacity of an encountered bound
|
||||
bounds.push(OSRP_bound(slope, cur_pos));
|
||||
}
|
||||
// The new bound, minus what it absorbs of the remaining slope
|
||||
if(target_abs_pos > begin){
|
||||
bounds.push(OSRP_bound(2*width + std::min(slope, static_cast<T>(0) ), target_abs_pos));
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(OSRP_bound b : passed_bounds){
|
||||
bounds.push(b);
|
||||
}
|
||||
}
|
||||
|
||||
return cur_cost + width * std::abs((float)(final_abs_pos - target_abs_pos)); // Add the cost of the new cell
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline std::vector<std::pair<index_t, T> > OSRP_leg<T>::get_placement() const{
|
||||
auto final_abs_pos = constraining_pos;
|
||||
std::partial_sum(final_abs_pos.rbegin(), final_abs_pos.rend(), final_abs_pos.rbegin(), [](T a, T b)->T{ return std::min(a,b); });
|
||||
|
||||
std::vector<result_t> ret(cells.size());
|
||||
for(index_t i=0; i<cells.size(); ++i){
|
||||
ret[i] = result_t(cells[i], final_abs_pos[i] + prev_width[i]);
|
||||
|
||||
if(std::numeric_limits<T>::is_integer){
|
||||
assert(final_abs_pos[i] >= begin);
|
||||
assert(final_abs_pos[i] + prev_width[i+1] <= end);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
|
||||
|
||||
#include "common.hxx"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace coloquinte{
|
||||
|
||||
typedef std::pair<int_t, int_t> p_v;
|
||||
|
||||
struct piecewise_linear_function{
|
||||
std::vector<p_v> point_values;
|
||||
|
||||
static piecewise_linear_function minimum(piecewise_linear_function const & a, piecewise_linear_function const & b);
|
||||
piecewise_linear_function previous_min_of_sum(piecewise_linear_function const & o, int_t added_cell_width) const;
|
||||
piecewise_linear_function previous_min() const;
|
||||
|
||||
int_t value_at(int_t pos) const;
|
||||
int_t last_before(int_t pos) const;
|
||||
|
||||
void add_monotone(int_t slope, int_t offset);
|
||||
void add_bislope(int_t s_l, int_t s_r, int_t pos);
|
||||
|
||||
piecewise_linear_function(){}
|
||||
piecewise_linear_function(int_t min_def, int_t max_def);
|
||||
};
|
||||
|
||||
} // End namespace coloquinte
|
||||
|
|
@ -1,263 +0,0 @@
|
|||
|
||||
#ifndef COLOQUINTE_GP_ROUGH_LEGALIZER
|
||||
#define COLOQUINTE_GP_ROUGH_LEGALIZER
|
||||
|
||||
#include "common.hxx"
|
||||
#include "netlist.hxx"
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
|
||||
/*
|
||||
* A simple class to perform approximate legalization with extreme efficiency
|
||||
*
|
||||
* To be called during global placement or before an exact legalization
|
||||
*
|
||||
*/
|
||||
|
||||
namespace coloquinte{
|
||||
|
||||
struct density_limit{
|
||||
box<int_t> box_;
|
||||
float_t density_; // from 0.0 for a macro to 1.0 if it does nothing
|
||||
};
|
||||
typedef std::vector<density_limit> density_restrictions;
|
||||
|
||||
namespace gp{
|
||||
|
||||
class region_distribution{
|
||||
/*
|
||||
* Coordinates are mostly float but obstacles and areas are integers for correctness
|
||||
*/
|
||||
|
||||
public:
|
||||
struct movable_cell{
|
||||
capacity_t demand_; // == area; No FP!!!
|
||||
point<float_t> pos_; // Target position, determining the cost to allocate it
|
||||
// int_t x_size, y_size; // May split cells
|
||||
index_t index_in_placement_;
|
||||
|
||||
movable_cell();
|
||||
movable_cell(capacity_t demand, point<float_t> p, index_t ind);
|
||||
};
|
||||
|
||||
// Specifies a maximum density of movable cells per usable area
|
||||
// Representing either a macroblock or a routing congestion
|
||||
private:
|
||||
|
||||
struct region;
|
||||
|
||||
struct cell_ref{
|
||||
capacity_t allocated_capacity_;
|
||||
point<float_t> pos_;
|
||||
index_t index_in_list_;
|
||||
|
||||
cell_ref(){}
|
||||
cell_ref(capacity_t demand, point<float_t> p, index_t ind) : allocated_capacity_(demand), pos_(p), index_in_list_(ind){}
|
||||
friend region;
|
||||
};
|
||||
|
||||
struct region{
|
||||
public:
|
||||
// Data members
|
||||
capacity_t capacity_; // ==area; No floating point!!!
|
||||
point<float_t> pos_;
|
||||
|
||||
std::vector<cell_ref> cell_references_;
|
||||
|
||||
// Constructors
|
||||
region(){} // Necessary if we want to resize vectors
|
||||
region(capacity_t cap, point<float_t> pos, std::vector<cell_ref> cells);
|
||||
|
||||
// Helper functions for bipartitioning
|
||||
private:
|
||||
static void distribute_new_cells(region & a, region & b, std::vector<cell_ref> cells); // Called by the other two to do the dirty work
|
||||
public:
|
||||
void distribute_cells(region & a, region & b) const; // Distribute the cells from one region to two
|
||||
static void redistribute_cells(region & a, region & b); // Optimizes the distribution between two regions
|
||||
|
||||
// Helper functions for multipartitioning
|
||||
private:
|
||||
static void distribute_new_cells(std::vector<std::reference_wrapper<region_distribution::region> > regions, std::vector<cell_ref> cells);
|
||||
public:
|
||||
void distribute_cells(std::vector<std::reference_wrapper<region_distribution::region> > regions) const;
|
||||
static void redistribute_cells(std::vector<std::reference_wrapper<region_distribution::region> > regions);
|
||||
|
||||
// Helper functions for 1D transportation
|
||||
public:
|
||||
static void distribute_new_cells(std::vector<std::reference_wrapper<region_distribution::region> > regions, std::vector<cell_ref> cells, std::function<float_t (point<float_t>)> coord);
|
||||
static void redistribute_cells(std::vector<std::reference_wrapper<region_distribution::region> > & regions, std::function<float_t (point<float_t>)> coord);
|
||||
|
||||
public:
|
||||
void uniquify_references();
|
||||
void selfcheck() const;
|
||||
|
||||
// Accessors
|
||||
capacity_t capacity() const;
|
||||
capacity_t allocated_capacity() const;
|
||||
capacity_t unused_capacity() const;
|
||||
index_t cell_cnt() const;
|
||||
|
||||
float_t distance(cell_ref const & C) const;
|
||||
float_t cost() const;
|
||||
};
|
||||
|
||||
private:
|
||||
// Members
|
||||
index_t x_regions_cnt_, y_regions_cnt_;
|
||||
|
||||
std::vector<movable_cell> cell_list_;
|
||||
std::vector<region> placement_regions_;
|
||||
|
||||
box<int_t> placement_area_;
|
||||
std::vector<density_limit> density_map_;
|
||||
const capacity_t full_density_mul; // Multiplicator giving the grain for fractional areas for the surface
|
||||
capacity_t cell_density_mul; // ANd for the cells
|
||||
float_t density_scaling_factor_;
|
||||
|
||||
private:
|
||||
// Helper functions
|
||||
region & get_region(index_t x_coord, index_t y_coord);
|
||||
region const & get_region(index_t x_coord, index_t y_coord) const;
|
||||
box<int_t> get_box(index_t x, index_t y, index_t x_cnt, index_t y_cnt) const;
|
||||
|
||||
static void sort_uniquify(std::vector<cell_ref> & cell_references);
|
||||
static void just_uniquify(std::vector<cell_ref> & cell_references);
|
||||
|
||||
// Prepare regions with the right positions and capacities; different levels of nesting are compatible
|
||||
std::vector<region> prepare_regions(index_t x_cnt, index_t y_cnt) const;
|
||||
|
||||
public:
|
||||
|
||||
inline box<int_t> placement_area() const;
|
||||
inline point<float_t> region_dimensions() const;
|
||||
|
||||
inline index_t x_regions_cnt() const;
|
||||
inline index_t y_regions_cnt() const;
|
||||
inline index_t regions_cnt() const;
|
||||
|
||||
inline index_t cell_cnt() const;
|
||||
inline index_t fractional_cell_cnt() const;
|
||||
|
||||
/*
|
||||
* Two types of export
|
||||
* Region center : upper bound of legalization cost
|
||||
* 1D quadratic optimization : lower bound of legalization cost
|
||||
*/
|
||||
|
||||
std::vector<movable_cell> export_positions() const;
|
||||
std::vector<movable_cell> export_spread_positions_quadratic() const;
|
||||
std::vector<movable_cell> export_spread_positions_linear() const;
|
||||
|
||||
// The cost as seen by the partitioning algorithms (but not the export)
|
||||
float_t cost() const;
|
||||
|
||||
/*
|
||||
* Further partitions
|
||||
*/
|
||||
|
||||
void x_bipartition();
|
||||
void y_bipartition();
|
||||
void x_resize(index_t sz);
|
||||
void y_resize(index_t sz);
|
||||
void multipartition(index_t x_width, index_t y_width);
|
||||
void multipartition(index_t width){ multipartition(width, width); }
|
||||
|
||||
/*
|
||||
* Optimization functions
|
||||
*/
|
||||
|
||||
// Bipartitioning: only two regions are considered at a time
|
||||
void redo_adjacent_bipartitions();
|
||||
void redo_diagonal_bipartitions();
|
||||
void redo_bipartitions();
|
||||
|
||||
// Line partitioning: optimal on coordinate axis with Manhattan distance (Euclidean distance could use it in any direction)
|
||||
void redo_line_partitions();
|
||||
|
||||
// Multipartitioning: several regions considered, slow runtimes
|
||||
void redo_diag_partitions(index_t len);
|
||||
void redo_multipartitions(index_t x_width, index_t y_width);
|
||||
void redo_multipartitions(index_t width){ redo_multipartitions(width, width); }
|
||||
|
||||
// Try to remove duplicate fractional cells
|
||||
void fractions_minimization();
|
||||
|
||||
// Verify
|
||||
void selfcheck() const;
|
||||
|
||||
private:
|
||||
region_distribution(box<int_t> placement_area, netlist const & circuit, placement_t const & pl, std::vector<density_limit> const & density_map, bool full_density);
|
||||
|
||||
public:
|
||||
/*
|
||||
* Obtain a region_distribution from a placement
|
||||
*
|
||||
* Full density: the object tries to pack the cells as much as possible while still respecting the density limits
|
||||
* Uniform density: not only are the density limits respected, the allocated capacities are proportional to the allowed densities
|
||||
*
|
||||
*/
|
||||
|
||||
static region_distribution full_density_distribution(box<int_t> placement_area, netlist const & circuit, placement_t const & pl, std::vector<density_limit> const & density_map = std::vector<density_limit>());
|
||||
static region_distribution uniform_density_distribution(box<int_t> placement_area, netlist const & circuit, placement_t const & pl, std::vector<density_limit> const & density_map = std::vector<density_limit>());
|
||||
|
||||
void update(netlist const & circuit, placement_t const & pl);
|
||||
};
|
||||
|
||||
inline region_distribution::movable_cell::movable_cell(){}
|
||||
inline region_distribution::movable_cell::movable_cell(capacity_t demand, point<float_t> p, index_t ind) : demand_(demand), pos_(p), index_in_placement_(ind){}
|
||||
|
||||
inline box<int_t> region_distribution::placement_area() const { return placement_area_; }
|
||||
inline point<float_t> region_distribution::region_dimensions() const {
|
||||
point<int_t> s = static_cast<point<float_t> >(placement_area().dimensions());
|
||||
return point<float_t>(s.x/x_regions_cnt(), s.y/y_regions_cnt());
|
||||
}
|
||||
|
||||
inline index_t region_distribution::x_regions_cnt() const { return x_regions_cnt_; }
|
||||
inline index_t region_distribution::y_regions_cnt() const { return y_regions_cnt_; }
|
||||
inline index_t region_distribution::regions_cnt() const { index_t ret = x_regions_cnt() * y_regions_cnt(); assert(placement_regions_.size() == ret); return ret; }
|
||||
inline region_distribution::region & region_distribution::get_region(index_t x_coord, index_t y_coord){
|
||||
return placement_regions_[y_coord * x_regions_cnt() + x_coord];
|
||||
}
|
||||
inline region_distribution::region const & region_distribution::get_region(index_t x_coord, index_t y_coord) const{
|
||||
return placement_regions_[y_coord * x_regions_cnt() + x_coord];
|
||||
}
|
||||
|
||||
inline index_t region_distribution::cell_cnt() const{ return cell_list_.size(); }
|
||||
inline index_t region_distribution::fractional_cell_cnt() const{
|
||||
index_t tot_cnt = 0;
|
||||
for(auto const & R : placement_regions_){
|
||||
tot_cnt += R.cell_cnt();
|
||||
}
|
||||
return tot_cnt;
|
||||
}
|
||||
|
||||
|
||||
inline capacity_t region_distribution::region::capacity() const{ return capacity_; }
|
||||
inline capacity_t region_distribution::region::unused_capacity() const{ return capacity() - allocated_capacity(); }
|
||||
inline capacity_t region_distribution::region::allocated_capacity() const{
|
||||
capacity_t ret = 0;
|
||||
for(cell_ref const C : cell_references_){
|
||||
ret += C.allocated_capacity_;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
inline index_t region_distribution::region::cell_cnt() const{ return cell_references_.size(); }
|
||||
|
||||
inline float_t region_distribution::region::distance(region_distribution::cell_ref const & C) const{
|
||||
return std::abs(pos_.x - C.pos_.x) + std::abs(pos_.y - C.pos_.y);
|
||||
/*
|
||||
float_t manhattan = std::max(static_cast<float_t>(0.0), std::max(C.pos_.x - surface_.x_max, surface_.x_min - C.pos_.x))
|
||||
+ std::max(static_cast<float_t>(0.0), std::max(C.pos_.y - surface_.y_max, surface_.y_min - C.pos_.y));
|
||||
return manhattan * (1.0 + manhattan * 0.0001);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
} // Namespace gp
|
||||
} // Namespace coloquinte
|
||||
|
||||
#endif
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
|
||||
#ifndef COLOQUINE_GP_SOLVERS
|
||||
#define COLOQUINE_GP_SOLVERS
|
||||
|
||||
#include "common.hxx"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace coloquinte{
|
||||
namespace gp{
|
||||
|
||||
struct matrix_doublet{
|
||||
index_t c_;
|
||||
float val_;
|
||||
bool operator<(matrix_doublet const o) const{ return c_ < o.c_; }
|
||||
matrix_doublet(){}
|
||||
matrix_doublet(index_t c, float v) : c_(c), val_(v){}
|
||||
};
|
||||
|
||||
struct matrix_triplet{
|
||||
index_t r_, c_;
|
||||
float_t val_;
|
||||
matrix_triplet(index_t ri, index_t ci, float_t v) : r_(ri), c_(ci), val_(v){}
|
||||
bool operator<(matrix_triplet const o){ return r_ < o.r_ || (r_ == o.r_ && c_ < o.c_); }
|
||||
};
|
||||
|
||||
class linear_system{
|
||||
std::vector<matrix_triplet> matrix_;
|
||||
std::vector<float_t> target_;
|
||||
index_t internal_size_;
|
||||
|
||||
public:
|
||||
void add_triplet(index_t row, index_t col, float_t val){ matrix_.push_back(matrix_triplet(row, col, val)); }
|
||||
|
||||
linear_system operator+(linear_system const & o) const;
|
||||
|
||||
void add_doublet(index_t row, float_t val){
|
||||
target_[row] += val;
|
||||
}
|
||||
|
||||
void add_force(
|
||||
float_t force,
|
||||
index_t c1, index_t c2,
|
||||
float_t offs1, float_t offs2
|
||||
){
|
||||
add_triplet(c1, c1, force);
|
||||
add_triplet(c2, c2, force);
|
||||
add_triplet(c1, c2, -force);
|
||||
add_triplet(c2, c1, -force);
|
||||
add_doublet(c1, force * (offs2-offs1));
|
||||
add_doublet(c2, force * (offs1-offs2));
|
||||
}
|
||||
|
||||
void add_fixed_force(
|
||||
float_t force,
|
||||
index_t c,
|
||||
float_t fixed_pos,
|
||||
float_t offs
|
||||
){
|
||||
add_triplet(c, c, force);
|
||||
add_doublet(c, force * (fixed_pos-offs));
|
||||
}
|
||||
|
||||
void add_anchor(
|
||||
float_t scale,
|
||||
index_t c,
|
||||
float_t pos
|
||||
){
|
||||
add_triplet(c, c, scale);
|
||||
add_doublet(c, scale*pos);
|
||||
}
|
||||
|
||||
linear_system(index_t s) : target_(s, 0.0), internal_size_(s){}
|
||||
linear_system(index_t s, index_t i) : target_(s, 0.0), internal_size_(i){}
|
||||
|
||||
index_t size() const{ return target_.size(); }
|
||||
index_t internal_size() const{ return internal_size_; }
|
||||
void add_variables(index_t cnt){ target_.resize(target_.size() + cnt, 0.0); }
|
||||
|
||||
std::vector<float_t> solve_CG(std::vector<float_t> guess, index_t nbr_iter);
|
||||
};
|
||||
|
||||
} // namespace gp
|
||||
} // namespace coloquinte
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
|
||||
#include "common.hxx"
|
||||
|
||||
#include <array>
|
||||
|
||||
#ifndef COLOQUINTE_TOPOLOGIES
|
||||
#define COLOQUINTE_TOPOLOGIES
|
||||
|
||||
namespace coloquinte{
|
||||
namespace steiner_lookup{
|
||||
|
||||
template<int pin_cnt>
|
||||
struct Hconnectivity{
|
||||
// The edges and the couple of pins connected to the extreme ones are represented by one char each
|
||||
// The first 4 bits represent the first pin minus one, the next 4 bits the second pin minus one
|
||||
std::uint8_t connexions[pin_cnt-3];
|
||||
std::uint8_t extremes;
|
||||
|
||||
int_t get_wirelength(std::array<point<int_t>, pin_cnt> const sorted_points) const;
|
||||
std::array<std::pair<index_t, index_t>, pin_cnt-1> get_x_topology(std::array<point<int_t>, pin_cnt> const sorted_points) const;
|
||||
};
|
||||
|
||||
extern std::array<Hconnectivity<4>, 2> const topologies_4;
|
||||
extern std::array<Hconnectivity<5>, 6> const topologies_5;
|
||||
extern std::array<Hconnectivity<6>, 23> const topologies_6;
|
||||
extern std::array<Hconnectivity<7>, 111> const topologies_7;
|
||||
extern std::array<Hconnectivity<8>, 642> const topologies_8;
|
||||
extern std::array<Hconnectivity<9>, 4334> const topologies_9;
|
||||
extern std::array<Hconnectivity<10>, 33510> const topologies_10;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
|
||||
#ifndef COLOQUINTE_UNION_FIND
|
||||
#define COLOQUINTE_UNION_FIND
|
||||
|
||||
#include "common.hxx"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace coloquinte{
|
||||
|
||||
class union_find{
|
||||
std::vector<index_t> connex_representants;
|
||||
|
||||
public:
|
||||
index_t size() const { return connex_representants.size(); }
|
||||
|
||||
void merge(index_t a, index_t b){
|
||||
connex_representants[find(a)] = b;
|
||||
}
|
||||
|
||||
index_t find(index_t ind){
|
||||
if(connex_representants[ind] != ind){
|
||||
connex_representants[ind] = find(connex_representants[ind]);
|
||||
}
|
||||
return connex_representants[ind];
|
||||
}
|
||||
|
||||
union_find(index_t s) : connex_representants(s){
|
||||
for(index_t i=0; i<size(); ++i){
|
||||
connex_representants[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_connex(){
|
||||
bool connex = true;
|
||||
for(index_t i=0; i+1<size(); ++i){
|
||||
connex = connex && (find(i) == find(i+1));
|
||||
}
|
||||
return connex;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // End namespace coloquinte
|
||||
|
||||
#endif
|
||||
|
|
@ -1,261 +0,0 @@
|
|||
|
||||
#include "coloquinte/detailed.hxx"
|
||||
#include "coloquinte/circuit_helper.hxx"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace coloquinte{
|
||||
namespace dp{
|
||||
|
||||
detailed_placement::detailed_placement(
|
||||
placement_t pl,
|
||||
std::vector<index_t> placement_rows,
|
||||
std::vector<index_t> cell_heights,
|
||||
std::vector<std::vector<index_t> > rows,
|
||||
int_t min_x, int_t max_x,
|
||||
int_t y_origin,
|
||||
index_t nbr_rows, int_t row_height
|
||||
)
|
||||
:
|
||||
plt_(pl),
|
||||
cell_rows_(placement_rows),
|
||||
min_x_(min_x), max_x_(max_x),
|
||||
y_origin_(y_origin),
|
||||
row_height_(row_height)
|
||||
{
|
||||
|
||||
assert(row_height > 0);
|
||||
assert(min_x < max_x);
|
||||
assert(rows.size() == nbr_rows);
|
||||
|
||||
neighbours_limits_.push_back(0);
|
||||
for(index_t h : cell_heights){
|
||||
neighbours_limits_.push_back(neighbours_limits_.back() + h);
|
||||
}
|
||||
|
||||
neighbours_ .resize(neighbours_limits_.back(), std::pair<index_t, index_t>(null_ind, null_ind) );
|
||||
|
||||
row_first_cells_ .resize(nbr_rows, null_ind);
|
||||
row_last_cells_ .resize(nbr_rows, null_ind);
|
||||
|
||||
std::vector<bool> explored(neighbours_limits_.back(), false);
|
||||
// Now we extract the dependencies
|
||||
for(index_t r=0; r<rows.size(); ++r){
|
||||
|
||||
if(not rows[r].empty()){
|
||||
row_first_cells_[r] = rows[r].front();
|
||||
row_last_cells_[r] = rows[r].back();
|
||||
}
|
||||
|
||||
for(index_t c : rows[r]){
|
||||
// Has this row of the cell already been visited?
|
||||
assert(not explored[neighbour_index(c, r)]);
|
||||
explored[neighbour_index(c, r)] = true;
|
||||
}
|
||||
|
||||
for(index_t i=0; i+1<rows[r].size(); ++i){
|
||||
index_t c1 = rows[r][i], c2 = rows[r][i+1];
|
||||
|
||||
// Save in the internal format
|
||||
neighbours_[neighbour_index(c1, r)].second = c2;
|
||||
neighbours_[neighbour_index(c2, r)].first = c1;
|
||||
|
||||
// The positions are correct
|
||||
}
|
||||
}
|
||||
|
||||
// Every level of every cell must have been visited
|
||||
for(bool o : explored)
|
||||
assert(o);
|
||||
|
||||
// Verify that we haven't made any obvious mistake
|
||||
selfcheck();
|
||||
}
|
||||
|
||||
void detailed_placement::selfcheck() const{
|
||||
assert(row_first_cells_.size() == row_last_cells_.size());
|
||||
|
||||
for(index_t i=0; i<cell_cnt(); ++i){
|
||||
for(index_t l=0; l<cell_height(i); ++l){
|
||||
// not verified now since we don't modify the position for the obstacles
|
||||
// : assert(c.position.x >= min_x_ and c.position.x + c.width <= max_x_);
|
||||
|
||||
index_t n_ind = l + neighbours_limits_[i];
|
||||
assert(cell_rows_[i] + cell_height(i) <= row_cnt());
|
||||
|
||||
if(neighbours_[n_ind].first != null_ind){
|
||||
index_t oi = neighbours_[n_ind].first;
|
||||
// Correct neighbour position
|
||||
assert(neighbours_[neighbour_index(oi, cell_rows_[i]+l)].second == i);
|
||||
}
|
||||
else{
|
||||
// Beginning of a row
|
||||
assert(row_first_cells_[cell_rows_[i] + l] == i);
|
||||
}
|
||||
if(neighbours_[n_ind].second != null_ind){
|
||||
index_t oi = neighbours_[n_ind].second;
|
||||
// Correct neighbour position
|
||||
assert(neighbours_[neighbour_index(oi, cell_rows_[i]+l)].first == i);
|
||||
}
|
||||
else{
|
||||
// End of a row
|
||||
assert(row_last_cells_[cell_rows_[i] + l] == i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void detailed_placement::swap_standard_cell_topologies(index_t c1, index_t c2){
|
||||
assert(cell_height(c1) == cell_height(c2));
|
||||
assert(cell_height(c1) == 1 and cell_height(c2) == 1);
|
||||
|
||||
index_t row_c1 = cell_rows_[c1],
|
||||
row_c2 = cell_rows_[c2];
|
||||
|
||||
index_t b_c1 = neighbours_[neighbours_limits_[c1]].first;
|
||||
index_t b_c2 = neighbours_[neighbours_limits_[c2]].first;
|
||||
index_t a_c1 = neighbours_[neighbours_limits_[c1]].second;
|
||||
index_t a_c2 = neighbours_[neighbours_limits_[c2]].second;
|
||||
|
||||
// Two cases: they were adjacent or they were not
|
||||
// Luckily updating in the neighbours first then swapping the recorded neighbours works in both cases for standard cells
|
||||
|
||||
// Update the pointers in the cells' neighbours
|
||||
if(b_c1 != null_ind) neighbours_[neighbour_index(b_c1, row_c1)].second = c2;
|
||||
else row_first_cells_[row_c1] = c2;
|
||||
if(b_c2 != null_ind) neighbours_[neighbour_index(b_c2, row_c2)].second = c1;
|
||||
else row_first_cells_[row_c2] = c1;
|
||||
|
||||
if(a_c1 != null_ind) neighbours_[neighbour_index(a_c1, row_c1)].first = c2;
|
||||
else row_last_cells_[row_c1] = c2;
|
||||
if(a_c2 != null_ind) neighbours_[neighbour_index(a_c2, row_c2)].first = c1;
|
||||
else row_last_cells_[row_c2] = c1;
|
||||
|
||||
// Swap the properties in both cells
|
||||
std::swap(neighbours_[neighbours_limits_[c1]], neighbours_[neighbours_limits_[c2]]);
|
||||
std::swap(cell_rows_[c1], cell_rows_[c2]);
|
||||
}
|
||||
|
||||
std::pair<int_t, int_t> detailed_placement::get_limit_positions(netlist const & circuit, index_t c) const{
|
||||
auto ret = std::pair<int_t, int_t>(min_x_, max_x_);
|
||||
for(index_t l=neighbours_limits_[c]; l<neighbours_limits_[c+1]; ++l){
|
||||
index_t b_i = neighbours_[l].first,
|
||||
a_i = neighbours_[l].second;
|
||||
|
||||
if(b_i != null_ind){
|
||||
ret.first = std::max(ret.first, plt_.positions_[b_i].x + circuit.get_cell(b_i).size.x);
|
||||
}
|
||||
if(a_i != null_ind){
|
||||
ret.second = std::min(ret.second, plt_.positions_[a_i].x);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
index_t detailed_placement::get_first_cell_on_row(index_t r){
|
||||
return row_first_cells_[r];
|
||||
}
|
||||
|
||||
index_t detailed_placement::get_first_standard_cell_on_row(index_t r){
|
||||
index_t c = get_first_cell_on_row(r);
|
||||
while(c != null_ind and cell_height(c) != 1){
|
||||
index_t next_c = get_next_cell_on_row(c, r);
|
||||
assert(c != next_c);
|
||||
c = next_c;
|
||||
}
|
||||
assert(c == null_ind or cell_rows_[c] == r);
|
||||
return c;
|
||||
}
|
||||
|
||||
index_t detailed_placement::get_next_cell_on_row(index_t c, index_t r){
|
||||
return neighbours_[neighbour_index(c, r)].second;
|
||||
}
|
||||
index_t detailed_placement::get_prev_cell_on_row(index_t c, index_t r){
|
||||
return neighbours_[neighbour_index(c, r)].first;
|
||||
}
|
||||
|
||||
index_t detailed_placement::get_next_standard_cell_on_row(index_t c, index_t r){
|
||||
do{
|
||||
index_t next_c = get_next_cell_on_row(c, r);
|
||||
assert(c != next_c);
|
||||
c = next_c;
|
||||
}while(c != null_ind and cell_height(c) != 1);
|
||||
assert(c == null_ind or cell_rows_[c] == r);
|
||||
return c;
|
||||
}
|
||||
|
||||
void detailed_placement::reorder_cells(std::vector<index_t> const old_order, std::vector<index_t> const new_order, index_t r){
|
||||
assert(old_order.size() == new_order.size());
|
||||
assert(not old_order.empty());
|
||||
|
||||
index_t before_row = get_prev_cell_on_row(old_order.front(), r);
|
||||
index_t after_row = get_next_cell_on_row(old_order.back(), r);
|
||||
|
||||
for(index_t i=0; i<new_order.size(); ++i){
|
||||
auto & nghs = neighbours_[neighbour_index(new_order[i], r)];
|
||||
if(i > 0){
|
||||
nghs.first = new_order[i-1];
|
||||
}
|
||||
else{
|
||||
nghs.first = before_row;
|
||||
}
|
||||
if(i+1 < new_order.size()){
|
||||
nghs.second = new_order[i+1];
|
||||
}
|
||||
else{
|
||||
nghs.second = after_row;
|
||||
}
|
||||
}
|
||||
|
||||
if(before_row != null_ind) neighbours_[neighbour_index(before_row, r)].second = new_order.front();
|
||||
else row_first_cells_[r] = new_order.front();
|
||||
if(after_row != null_ind) neighbours_[neighbour_index(after_row, r)].first = new_order.back();
|
||||
else row_last_cells_[r] = new_order.back();
|
||||
}
|
||||
|
||||
void detailed_placement::reorder_standard_cells(std::vector<index_t> const old_order, std::vector<index_t> const new_order){
|
||||
assert(old_order.size() == new_order.size());
|
||||
assert(not old_order.empty());
|
||||
|
||||
index_t before_row = neighbours_[neighbours_limits_[old_order.front()]].first;
|
||||
index_t after_row = neighbours_[neighbours_limits_[old_order.back() ]].second;
|
||||
|
||||
index_t r = cell_rows_[new_order.front()];
|
||||
|
||||
for(index_t i=0; i<new_order.size(); ++i){
|
||||
assert(cell_height(new_order[i]) == 1);
|
||||
assert(cell_rows_[new_order[i]] == r);
|
||||
|
||||
auto & nghs = neighbours_[neighbours_limits_[new_order[i]]];
|
||||
if(i > 0){
|
||||
nghs.first = new_order[i-1];
|
||||
}
|
||||
else{
|
||||
nghs.first = before_row;
|
||||
}
|
||||
if(i+1 < new_order.size()){
|
||||
nghs.second = new_order[i+1];
|
||||
}
|
||||
else{
|
||||
nghs.second = after_row;
|
||||
}
|
||||
}
|
||||
|
||||
if(before_row != null_ind) neighbours_[neighbour_index(before_row, r)].second = new_order.front();
|
||||
else row_first_cells_[r] = new_order.front();
|
||||
if(after_row != null_ind) neighbours_[neighbour_index(after_row, r)].first = new_order.back();
|
||||
else row_last_cells_[r] = new_order.back();
|
||||
}
|
||||
|
||||
void row_compatible_orientation(netlist const & circuit, detailed_placement & pl, bool first_row_orient){
|
||||
for(index_t c=0; c<circuit.cell_cnt(); ++c){
|
||||
if( (circuit.get_cell(c).attributes & YFlippable) != 0 and pl.cell_height(c) == 1){
|
||||
pl.plt_.orientations_[c].y = (pl.cell_rows_[c] % 2 != 0) ^ first_row_orient;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dp
|
||||
} // namespace coloquinte
|
||||
|
||||
|
|
@ -1,452 +0,0 @@
|
|||
|
||||
#include "coloquinte/legalizer.hxx"
|
||||
#include "coloquinte/optimization_subproblems.hxx"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <queue>
|
||||
|
||||
namespace coloquinte{
|
||||
namespace dp{
|
||||
|
||||
void get_result(netlist const & circuit, detailed_placement const & dpl, placement_t & gpl){
|
||||
for(index_t c=0; c<circuit.cell_cnt(); ++c){
|
||||
if( (circuit.get_cell(c).attributes & XMovable) != 0)
|
||||
gpl.positions_[c].x = dpl.plt_.positions_[c].x;
|
||||
if( (circuit.get_cell(c).attributes & YMovable) != 0)
|
||||
gpl.positions_[c].y = dpl.plt_.positions_[c].y;
|
||||
|
||||
if( (circuit.get_cell(c).attributes & XFlippable) != 0)
|
||||
gpl.orientations_[c].x = dpl.plt_.orientations_[c].x;
|
||||
if( (circuit.get_cell(c).attributes & YFlippable) != 0)
|
||||
gpl.orientations_[c].y = dpl.plt_.orientations_[c].y;
|
||||
}
|
||||
}
|
||||
|
||||
struct cell_to_leg{
|
||||
int_t x_pos, y_pos;
|
||||
index_t original_cell;
|
||||
int_t width;
|
||||
index_t nbr_rows;
|
||||
|
||||
bool operator<(cell_to_leg const o) const{ return x_pos < o.x_pos; }
|
||||
|
||||
cell_to_leg(int_t x, int_t y, index_t ind, int_t w, index_t rows)
|
||||
: x_pos(x), y_pos(y),
|
||||
original_cell(ind),
|
||||
width(w),
|
||||
nbr_rows(rows)
|
||||
{}
|
||||
|
||||
legalizable_task<int_t> task() const{ return legalizable_task<int_t>(width, x_pos, original_cell); }
|
||||
};
|
||||
|
||||
struct fixed_cell_interval{
|
||||
int_t min_x, max_x;
|
||||
index_t cell_ind;
|
||||
|
||||
bool operator<(fixed_cell_interval const o) const{ return min_x > o.min_x; }
|
||||
fixed_cell_interval(int_t mn, int_t mx, index_t ind) : min_x(mn), max_x(mx), cell_ind(ind){}
|
||||
};
|
||||
|
||||
struct cell_leg_properties{
|
||||
int_t x_pos;
|
||||
index_t row_pos;
|
||||
index_t ind;
|
||||
|
||||
cell_leg_properties(){}
|
||||
cell_leg_properties(int_t x, int_t r, index_t i) : x_pos(x), row_pos(r), ind(i){}
|
||||
};
|
||||
|
||||
std::vector<cell_leg_properties> simple_legalize(
|
||||
std::vector<std::vector<fixed_cell_interval> > obstacles, std::vector<cell_to_leg> cells,
|
||||
std::vector<std::vector<index_t> > & rows,
|
||||
int_t x_min, int_t x_max, int_t y_orig,
|
||||
int_t row_height, index_t nbr_rows
|
||||
){
|
||||
|
||||
std::vector<int_t> first_available_position(nbr_rows, x_min);
|
||||
rows.resize(nbr_rows);
|
||||
|
||||
// Sort the cells by x position
|
||||
std::sort(cells.begin(), cells.end());
|
||||
|
||||
std::vector<cell_leg_properties> ret;
|
||||
|
||||
for(cell_to_leg C : cells){
|
||||
// Dumb, quick and dirty best-fit legalization
|
||||
bool found_location = false;
|
||||
|
||||
// Properties of the current best solution
|
||||
int_t best_x=0;
|
||||
int_t best_cost=0;
|
||||
index_t best_row=0;
|
||||
|
||||
// Helper function
|
||||
auto check_row_cost = [&](index_t r, cell_to_leg const cell, int_t additional_cost){
|
||||
// Find where to put the cell in these rows
|
||||
// Simple method: get a range where we can put the cell
|
||||
|
||||
assert(r + cell.nbr_rows <= nbr_rows);
|
||||
assert(additional_cost >= 0);
|
||||
|
||||
// First position where we can put it
|
||||
int_t cur_pos = *std::max_element(first_available_position.begin() + r, first_available_position.begin() + r + cell.nbr_rows);
|
||||
int_t max_lim = x_max - cell.width;
|
||||
int_t interval_lim;
|
||||
do{
|
||||
interval_lim = max_lim;
|
||||
// For each row, test if obstacles prevent us from putting a cell here
|
||||
// Until we find a correct position or are beyond the maximum position
|
||||
for(index_t i = 0; i<cell.nbr_rows; ++i){
|
||||
// Find the first obstacle which is after this position
|
||||
// TODO: use lower/upper bound
|
||||
auto it=obstacles[r+i].rbegin();
|
||||
for(; it != obstacles[r+i].rend() && it->max_x <= cur_pos; ++it){
|
||||
}
|
||||
if(it != obstacles[r+i].rend()){ // There is an obstacle on the right
|
||||
assert(it->min_x < it->max_x);
|
||||
int_t cur_lim = it->min_x - cell.width; // Where the obstacles contrains us
|
||||
interval_lim = std::min(cur_lim, interval_lim); // Constraint
|
||||
if(cur_lim < cur_pos){ // If this particular obstacle constrained us so that it is not possible to make it here, we increment the position
|
||||
cur_pos = std::max(it->max_x, cur_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Do it again until we find a solution
|
||||
// TODO: continue until we can't find a better solution (currently sticks before the first obstacle if there is enough whitespace)
|
||||
}while(interval_lim < cur_pos and interval_lim < max_lim and cur_pos < max_lim); // Not admissible and we encountered an obstacle and there is still hope
|
||||
|
||||
if(interval_lim >= cur_pos){ // An admissible solution is found (and if cell.x_pos is between cur_pos and interval_lim it is optimal)
|
||||
int_t row_best_x = std::min(interval_lim, std::max(cur_pos, cell.x_pos));
|
||||
int_t row_cost_x = std::abs((float)(row_best_x - cell.x_pos));
|
||||
if(not found_location or row_cost_x + additional_cost < best_cost){
|
||||
found_location = true;
|
||||
best_cost = row_cost_x + additional_cost;
|
||||
best_x = row_best_x;
|
||||
best_row = r;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// The row where we would prefer the cell to go
|
||||
if(C.nbr_rows > nbr_rows) throw std::runtime_error("Impossible to legalize a cell spanning more rows than are available\n");
|
||||
index_t central_row = std::min( (index_t) std::max( (C.y_pos - y_orig) / row_height, 0), nbr_rows-C.nbr_rows);
|
||||
|
||||
// Try every possible row from the best one, until we can't improve the cost
|
||||
for(index_t row_dist = 0;
|
||||
(central_row + row_dist < nbr_rows or central_row >= row_dist)
|
||||
and (not found_location or (int_t) row_dist * row_height * C.width < (int_t) row_height + best_cost);
|
||||
++row_dist
|
||||
){
|
||||
if(central_row + row_dist < nbr_rows - C.nbr_rows){
|
||||
int_t add_cost = C.width * std::abs((float)static_cast<int_t>(central_row + row_dist) * static_cast<int_t>(row_height) + y_orig - C.y_pos);
|
||||
check_row_cost(central_row + row_dist, C, add_cost);
|
||||
}
|
||||
if(central_row >= row_dist){
|
||||
int_t add_cost = C.width * std::abs((float)static_cast<int_t>(central_row - row_dist) * static_cast<int_t>(row_height) + y_orig - C.y_pos);
|
||||
check_row_cost(central_row - row_dist, C, add_cost);
|
||||
}
|
||||
}
|
||||
|
||||
if(not found_location){ // We didn't find any whitespace to put the cell in
|
||||
throw std::runtime_error("Didn't manage to pack a cell due to dumb algorithm\n");
|
||||
}
|
||||
else{
|
||||
assert(best_x + C.width <= x_max and best_x >= x_min);
|
||||
// Update the occupied rows
|
||||
for(index_t r = best_row; r < best_row + C.nbr_rows; ++r){
|
||||
// Include the obstacles
|
||||
while(not obstacles[r].empty()
|
||||
and obstacles[r].back().max_x <= best_x){
|
||||
rows[r].push_back(obstacles[r].back().cell_ind);
|
||||
obstacles[r].pop_back();
|
||||
}
|
||||
assert(obstacles[r].empty() or obstacles[r].back().min_x >= best_x + C.width);
|
||||
|
||||
rows[r].push_back(C.original_cell);
|
||||
first_available_position[r] = best_x + C.width;
|
||||
}
|
||||
|
||||
ret.push_back(cell_leg_properties(best_x, best_row, C.original_cell));
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, push the remaining fixed cells
|
||||
for(index_t r=0; r<nbr_rows; ++r){
|
||||
while(not obstacles[r].empty()){
|
||||
rows[r].push_back(obstacles[r].back().cell_ind);
|
||||
obstacles[r].pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// A better legalization function which is able to push already legalized cells
|
||||
std::vector<cell_leg_properties> good_legalize(
|
||||
std::vector<std::vector<fixed_cell_interval> > obstacles, std::vector<cell_to_leg> cells,
|
||||
std::vector<std::vector<index_t> > & rows,
|
||||
int_t x_min, int_t x_max, int_t y_orig,
|
||||
int_t row_height, index_t nbr_rows
|
||||
){
|
||||
|
||||
// Two possibilities:
|
||||
// * Single OSRP (group of movable cells) at the current end of the row of standard cells
|
||||
// * Multiple OSRPs, between each pair of obstacles
|
||||
// -> allows pushing cells past obstacles
|
||||
// -> tricky with multiple standard cell heights
|
||||
// Therefore I chose single OSRP, which gets cleared and pushed to the final state whenever
|
||||
// * we encounter a multiple-rows cell
|
||||
// * a new standard cell gets past an obstacle
|
||||
|
||||
// The current group of standard cells on the right of the row
|
||||
std::vector<OSRP_leg<int_t> > single_row_problems(nbr_rows);
|
||||
for(index_t r=0; r<nbr_rows; ++r){
|
||||
single_row_problems[r] = OSRP_leg<int_t>(x_min, obstacles[r].empty() ? x_max : obstacles[r].back().min_x);
|
||||
}
|
||||
rows.resize(nbr_rows);
|
||||
|
||||
// Sort the cells by x position
|
||||
std::sort(cells.begin(), cells.end());
|
||||
|
||||
std::vector<cell_leg_properties> ret;
|
||||
|
||||
for(cell_to_leg C : cells){
|
||||
// Dumb, quick and dirty best-fit legalization
|
||||
bool found_location = false;
|
||||
|
||||
// Properties of the current best solution
|
||||
int_t best_cost=0;
|
||||
index_t best_row=0;
|
||||
index_t obstacles_passed = 0;
|
||||
|
||||
// Helper function
|
||||
auto check_row_cost = [&](index_t r, cell_to_leg const cell, int_t additional_cost){
|
||||
// Find where to put the cell in these rows
|
||||
// Check if we can put it in the current ranges and at what cost; if not or if the optimal position is beyond an obstacle, try after this obstacle too
|
||||
|
||||
assert(cell.nbr_rows > 0);
|
||||
assert(r + cell.nbr_rows <= nbr_rows);
|
||||
assert(additional_cost >= 0);
|
||||
|
||||
// Where can we put a standard cell if we allow to move the cells?
|
||||
if(cell.nbr_rows == 1){
|
||||
int_t cur_cost = 0;
|
||||
|
||||
// Can we simply add it to the single row problem?
|
||||
bool found_here = single_row_problems[r].remaining_space() >= cell.width;
|
||||
int_t loc_obstacles_passed = 0;
|
||||
if(found_here){
|
||||
// Check the cost of pushing it here with possible displacement
|
||||
cur_cost = single_row_problems[r].get_cost(cell.task()); // Don't update the row
|
||||
}
|
||||
|
||||
// Other positions where we can put it, without moving other cells this time
|
||||
if(not found_here or cur_cost > 0){
|
||||
index_t obstacles_to_throw = 0;
|
||||
auto it = obstacles[r].rbegin();
|
||||
while(it != obstacles[r].rend()){
|
||||
++ obstacles_to_throw;
|
||||
auto prev_it = it++;
|
||||
int_t region_end = it != obstacles[r].rend() ? it->min_x : x_max;
|
||||
if(region_end >= prev_it->max_x + cell.width){
|
||||
int_t loc_x = std::min(region_end - cell.width, std::max(prev_it->max_x, cell.x_pos));
|
||||
int_t loc_cost = cell.width * std::abs((float)(cell.x_pos - loc_x));
|
||||
if(not found_here or cur_cost > loc_cost){
|
||||
found_here = true;
|
||||
cur_cost = loc_cost;
|
||||
loc_obstacles_passed = obstacles_to_throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(found_here and (not found_location or cur_cost + additional_cost < best_cost)){
|
||||
found_location = true;
|
||||
//std::cout << "Found with displacement cost " << cur_cost << " and total cost " << cur_cost + additional_cost << std::endl;
|
||||
best_cost = cur_cost + additional_cost;
|
||||
best_row = r;
|
||||
obstacles_passed = loc_obstacles_passed;
|
||||
if(loc_obstacles_passed > 0) assert(not obstacles[r].empty());
|
||||
}
|
||||
}
|
||||
else{
|
||||
// If it is a fixed cell, we use fixed locations
|
||||
std::cerr << "cell.nbr_rows:" << cell.nbr_rows << std::endl;
|
||||
throw std::runtime_error("I don't handle fucking macros (good_legalize)\n");
|
||||
}
|
||||
};
|
||||
|
||||
// The row where we would prefer the cell to go
|
||||
if(C.nbr_rows > nbr_rows) throw std::runtime_error("Impossible to legalize a cell spanning more rows than are available\n");
|
||||
index_t central_row = std::min( (index_t) std::max( (C.y_pos - y_orig) / row_height, 0), nbr_rows-C.nbr_rows);
|
||||
|
||||
// Try every possible row from the best one, until we can't improve the cost
|
||||
for(index_t row_dist = 0;
|
||||
(central_row + row_dist < nbr_rows or central_row >= row_dist)
|
||||
and (not found_location or (int_t) row_dist * row_height * C.width < (int_t) row_height + best_cost);
|
||||
++row_dist
|
||||
){
|
||||
if(central_row + row_dist < nbr_rows - C.nbr_rows){
|
||||
int_t add_cost = C.width * std::abs((float)static_cast<int_t>(central_row + row_dist) * static_cast<int_t>(row_height) + y_orig - C.y_pos);
|
||||
check_row_cost(central_row + row_dist, C, add_cost);
|
||||
}
|
||||
if(central_row >= row_dist){
|
||||
int_t add_cost = C.width * std::abs((float)static_cast<int_t>(central_row - row_dist) * static_cast<int_t>(row_height) + y_orig - C.y_pos);
|
||||
check_row_cost(central_row - row_dist, C, add_cost);
|
||||
}
|
||||
}
|
||||
|
||||
if(not found_location){ // We didn't find any whitespace to put the cell in
|
||||
throw std::runtime_error("Didn't manage to pack a cell: leave more whitespace and avoid macros near the right side\n");
|
||||
}
|
||||
else{
|
||||
//std::cout << "Cell " << C.original_cell << " of width " << C.width << " targetting row " << central_row << " and position " << C.x_pos << " put at row " << best_row << " with displacement " << best_cost / C.width << " with " << obstacles_passed << " obstacles passed" << std::endl;
|
||||
// If the cell spans multiple rows, it becomes fixed
|
||||
// In this case or if the cell goes after an obstacle, push everything before the cell to the fixed state
|
||||
|
||||
if(C.nbr_rows == 1){
|
||||
if(obstacles_passed == 0){ // Ok; just update the old single row problem
|
||||
single_row_problems[best_row].push(C.task()); // Push it to the row
|
||||
}
|
||||
else{
|
||||
assert(obstacles_passed > 0);
|
||||
// Empty the single row problem
|
||||
for(auto p : single_row_problems[best_row].get_placement()){
|
||||
rows[best_row].push_back(p.first);
|
||||
ret.push_back(cell_leg_properties(p.second, best_row, p.first));
|
||||
}
|
||||
// Find where to put it
|
||||
int_t region_begin = x_min;
|
||||
for(index_t i=0; i<obstacles_passed; ++i){
|
||||
assert(not obstacles[best_row].empty());
|
||||
region_begin = obstacles[best_row].back().max_x;
|
||||
rows[best_row].push_back(obstacles[best_row].back().cell_ind);
|
||||
obstacles[best_row].pop_back();
|
||||
}
|
||||
int_t region_end = obstacles[best_row].empty() ? x_max : obstacles[best_row].back().min_x;
|
||||
single_row_problems[best_row] = OSRP_leg<int_t>(region_begin, region_end);
|
||||
assert(region_end - region_begin >= C.width);
|
||||
single_row_problems[best_row].push(C.task()); // Push this only cell to the single row problem
|
||||
}
|
||||
}
|
||||
else{
|
||||
throw std::runtime_error("I don't handle fucking macros (here)\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(index_t r=0; r<nbr_rows; ++r){
|
||||
// Finally, push the remaining standard cells in the row
|
||||
for(auto p : single_row_problems[r].get_placement()){
|
||||
rows[r].push_back(p.first);
|
||||
ret.push_back(cell_leg_properties(p.second, r, p.first));
|
||||
}
|
||||
// And the fixed cells
|
||||
while(not obstacles[r].empty()){
|
||||
rows[r].push_back(obstacles[r].back().cell_ind);
|
||||
obstacles[r].pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
rows.resize(nbr_rows);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
detailed_placement legalize(netlist const & circuit, placement_t const & pl, box<int_t> surface, int_t row_height){
|
||||
if(row_height <= 0) throw std::runtime_error("The rows' height should be positive\n");
|
||||
|
||||
index_t nbr_rows = (surface.y_max - surface.y_min) / row_height;
|
||||
// The position of the ith row is surface.y_min + i * row_height
|
||||
|
||||
std::vector<std::vector<fixed_cell_interval> > row_occupation(nbr_rows);
|
||||
std::vector<cell_to_leg> cells;
|
||||
|
||||
placement_t new_placement = pl;
|
||||
std::vector<index_t> placement_rows(circuit.cell_cnt());
|
||||
std::vector<index_t> cell_heights(circuit.cell_cnt());
|
||||
|
||||
for(index_t i=0; i<circuit.cell_cnt(); ++i){
|
||||
auto cur = circuit.get_cell(i);
|
||||
// Assumes fixed if not both XMovable and YMovable
|
||||
if( (cur.attributes & XMovable) != 0 && (cur.attributes & YMovable) != 0){
|
||||
// Just truncate the position we target
|
||||
point<int_t> target_pos = pl.positions_[i];
|
||||
index_t cur_cell_rows = (cur.size.y + row_height -1) / row_height;
|
||||
cells.push_back(cell_to_leg(target_pos.x, target_pos.y, i, cur.size.x, cur_cell_rows));
|
||||
cell_heights[i] = cur_cell_rows;
|
||||
}
|
||||
else{
|
||||
// In each row, we put the index of the fixed cell and the range that is already occupied
|
||||
int_t low_x_pos = pl.positions_[i].x,
|
||||
hgh_x_pos = pl.positions_[i].x + cur.size.x,
|
||||
low_y_pos = pl.positions_[i].y,
|
||||
hgh_y_pos = pl.positions_[i].y + cur.size.y;
|
||||
|
||||
new_placement.positions_[i] = point<int_t>(low_x_pos, low_y_pos);
|
||||
if(hgh_y_pos <= surface.y_min or low_y_pos >= surface.y_max or hgh_x_pos <= surface.x_min or low_x_pos >= surface.x_max){
|
||||
placement_rows[i] = null_ind;
|
||||
cell_heights[i] = 0;
|
||||
}
|
||||
else{
|
||||
assert(low_x_pos < hgh_x_pos and low_y_pos < hgh_y_pos);
|
||||
|
||||
int_t rnd_hgh_x_pos = std::min(surface.x_max, hgh_x_pos);
|
||||
int_t rnd_hgh_y_pos = std::min(surface.y_max, hgh_y_pos);
|
||||
int_t rnd_low_x_pos = std::max(surface.x_min, low_x_pos);
|
||||
int_t rnd_low_y_pos = std::max(surface.y_min, low_y_pos);
|
||||
index_t first_row = (rnd_low_y_pos - surface.y_min) / row_height;
|
||||
index_t last_row = (index_t) (rnd_hgh_y_pos - surface.y_min + row_height - 1) / row_height; // Exclusive: if the cell spans the next row, i.e. pos % row_height >= 0, include it too
|
||||
assert(last_row <= nbr_rows);
|
||||
|
||||
placement_rows[i] = first_row;
|
||||
cell_heights[i] = last_row - first_row;
|
||||
for(index_t r=first_row; r<last_row; ++r){
|
||||
row_occupation[r].push_back(fixed_cell_interval(rnd_low_x_pos, rnd_hgh_x_pos, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(std::vector<fixed_cell_interval> & L : row_occupation){
|
||||
std::sort(L.begin(), L.end()); // Sorts from last to first, so that we may use pop_back()
|
||||
// Doesn't collapse them yet, which may make for bigger complexities
|
||||
for(index_t i=0; i+1<L.size(); ++i){
|
||||
if(L[i].min_x < L[i+1].max_x) {
|
||||
std::ostringstream message;
|
||||
message << "Coloquinte::dp::legalize(): Sorry, I don't handle overlapping fixed cells yet ";
|
||||
message << " i:" << i << " max_x: " << L[i].max_x << " > min_x:" << L[i+1].min_x << "\n";
|
||||
throw std::runtime_error(message.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<index_t> > cells_by_rows;
|
||||
|
||||
auto final_cells = good_legalize(row_occupation, cells, cells_by_rows,
|
||||
surface.x_min, surface.x_max, surface.y_min,
|
||||
row_height, nbr_rows
|
||||
);
|
||||
|
||||
for(cell_leg_properties C : final_cells){
|
||||
new_placement.positions_[C.ind] = point<int_t>(C.x_pos, static_cast<int_t>(C.row_pos) * row_height + surface.y_min);
|
||||
placement_rows[C.ind] = C.row_pos;
|
||||
}
|
||||
|
||||
return detailed_placement(
|
||||
new_placement,
|
||||
placement_rows,
|
||||
cell_heights,
|
||||
cells_by_rows,
|
||||
surface.x_min, surface.x_max,
|
||||
surface.y_min,
|
||||
nbr_rows, row_height
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace dp
|
||||
} // namespace coloquinte
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,515 +0,0 @@
|
|||
|
||||
#include "coloquinte/optimization_subproblems.hxx"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace coloquinte{
|
||||
|
||||
std::vector<capacity_t> transport_1D(std::vector<t1D_elt> sources, std::vector<t1D_elt> sinks){
|
||||
/* Description of the algorithm:
|
||||
*
|
||||
* For each cell, put it in its optimal region or the last region where a cell is if there is no space in it
|
||||
* Push all changes in the derivative of the cost function to a priority queue; those changes occur
|
||||
* when evicting the preceding cell from a region (most such changes are 0 and not considered, hence the complexity)
|
||||
* when moving to a non-full region
|
||||
* While the new cell overlaps with a new region, get the new slope (derivative) at this point
|
||||
* and push all preceding cell until this region is freed or the slope becomes 0 (in which case the new region is now occupied)
|
||||
*/
|
||||
|
||||
struct bound{
|
||||
capacity_t pos;
|
||||
int_t slope_diff;
|
||||
bool operator<(bound const o) const{ return pos < o.pos; }
|
||||
};
|
||||
|
||||
std::priority_queue<bound> bounds;
|
||||
std::vector<capacity_t> constraining_pos;
|
||||
std::vector<capacity_t> prev_cap(1, 0), prev_dem(1, 0);
|
||||
for(auto const s : sinks){
|
||||
prev_cap.push_back(s.second + prev_cap.back());
|
||||
}
|
||||
for(auto const s : sources){
|
||||
prev_dem.push_back(s.second + prev_dem.back());
|
||||
}
|
||||
// The sinks have enough capacity to hold the whole demand
|
||||
assert(prev_cap.back() >= prev_dem.back());
|
||||
|
||||
const capacity_t min_abs_pos = 0, max_abs_pos = prev_cap.back() - prev_dem.back();
|
||||
assert(min_abs_pos <= max_abs_pos);
|
||||
|
||||
auto push_bound = [&](capacity_t p, int_t s){
|
||||
assert(s >= 0);
|
||||
if(p > min_abs_pos){
|
||||
bound B;
|
||||
B.pos = p;
|
||||
B.slope_diff = s;
|
||||
bounds.push(B);
|
||||
}
|
||||
};
|
||||
|
||||
// Distance to the right - distance to the left
|
||||
auto get_slope = [&](index_t src, index_t boundary){
|
||||
assert(boundary+1 < sinks.size());
|
||||
assert(src < sources.size());
|
||||
return std::abs((float)(sources[src].first - sinks[boundary+1].first)) - std::abs((float)(sources[src].first - sinks[boundary].first));
|
||||
};
|
||||
|
||||
capacity_t cur_abs_pos = min_abs_pos;
|
||||
index_t opt_r=0, next_r=0, first_free_r=0;
|
||||
|
||||
for(index_t i=0; i<sources.size(); ++i){
|
||||
// Update the optimal region
|
||||
while(opt_r+1 < sinks.size() and (sinks[opt_r].first + sinks[opt_r+1].first)/2 < sources[i].first){
|
||||
++opt_r;
|
||||
}
|
||||
// Update the next region
|
||||
index_t prev_next_r = next_r;
|
||||
while(next_r < sinks.size() and sinks[next_r].first <= sources[i].first){
|
||||
++next_r;
|
||||
}
|
||||
|
||||
index_t dest_reg = std::max(first_free_r, opt_r);
|
||||
assert(dest_reg < sinks.size());
|
||||
|
||||
if(i>0){
|
||||
// Push bounds due to changing the source crossing the boundary j/j+1
|
||||
// Linear amortized complexity accross all sources (next_r grows)
|
||||
// get_slope(i-1, j) - get_slope(i, j) == 0 if j >= next_r
|
||||
// get_slope(i-1, j) - get_slope(i, j) == 0 if j < prev_next_r-1
|
||||
|
||||
for(index_t j=std::max(prev_next_r,1u)-1; j<std::min(first_free_r, next_r+1); ++j){
|
||||
assert(get_slope(i,j) <= get_slope(i-1,j));
|
||||
push_bound(prev_cap[j+1] - prev_dem[i], get_slope(i-1, j) - get_slope(i,j));
|
||||
}
|
||||
}
|
||||
// Add the bounds due to crossing the boundaries alone
|
||||
for(index_t j=first_free_r; j<opt_r; ++j){
|
||||
assert(get_slope(i,j) <= 0);
|
||||
push_bound(prev_cap[j+1] - prev_dem[i], -get_slope(i, j));
|
||||
}
|
||||
|
||||
first_free_r = std::max(first_free_r, opt_r);
|
||||
capacity_t this_abs_pos = std::max(cur_abs_pos, prev_cap[first_free_r] - prev_dem[i]); // Just after the previous cell or at the beginning of the destination region
|
||||
|
||||
while(first_free_r+1 < sinks.size() and this_abs_pos > std::max(prev_cap[first_free_r+1] - prev_dem[i+1], min_abs_pos)){ // Absolute position that wouldn't make the cell fit in the region, and we are not in the last region yet
|
||||
capacity_t end_pos = std::max(prev_cap[first_free_r+1] - prev_dem[i+1], min_abs_pos);
|
||||
|
||||
int_t add_slope = get_slope(i, first_free_r);
|
||||
int_t slope = add_slope;
|
||||
|
||||
while(not bounds.empty() and slope >= 0 and bounds.top().pos > end_pos){
|
||||
this_abs_pos = bounds.top().pos;
|
||||
slope -= bounds.top().slope_diff;
|
||||
bounds.pop();
|
||||
}
|
||||
if(slope >= 0){ // We still push: the cell completely escapes the region
|
||||
this_abs_pos = end_pos;
|
||||
push_bound(end_pos, add_slope-slope);
|
||||
}
|
||||
else{ // Ok, absorbed the whole slope: push what remains and we still occupy the next region
|
||||
push_bound(this_abs_pos, -slope);
|
||||
++first_free_r;
|
||||
}
|
||||
}
|
||||
cur_abs_pos = this_abs_pos;
|
||||
constraining_pos.push_back(this_abs_pos);
|
||||
}
|
||||
|
||||
assert(constraining_pos.size() == sources.size());
|
||||
if(not constraining_pos.empty()){
|
||||
// Calculate the final constraining_pos
|
||||
constraining_pos.back() = std::min(max_abs_pos, constraining_pos.back());
|
||||
}
|
||||
|
||||
std::partial_sum(constraining_pos.rbegin(), constraining_pos.rend(), constraining_pos.rbegin(), [](capacity_t a, capacity_t b)->capacity_t{ return std::min(a, b); });
|
||||
|
||||
for(index_t i=0; i<constraining_pos.size(); ++i){
|
||||
constraining_pos[i] += prev_dem[i];
|
||||
}
|
||||
|
||||
return constraining_pos;
|
||||
}
|
||||
|
||||
namespace{ // Anonymous namespace to hide the transportation structures
|
||||
|
||||
class current_allocation{
|
||||
static const index_t null_ind;
|
||||
|
||||
// Internal data structures
|
||||
|
||||
// Priority queue element to determine the source to be used between regions
|
||||
struct movable_source{
|
||||
index_t source;
|
||||
float_t cost;
|
||||
bool operator<(movable_source const o) const{
|
||||
return cost > o.cost // Sorted by cost
|
||||
|| (cost == o.cost && source < o.source); // And by index to limit the number of fractional elements between two regions
|
||||
}
|
||||
movable_source(index_t s, float_t c) : source(s), cost(c) {}
|
||||
};
|
||||
|
||||
// Member data
|
||||
|
||||
// The current state
|
||||
std::vector<std::vector<capacity_t> > sr_allocations; // For each region, for each source, the capacity allocated by the region
|
||||
std::vector<std::vector<float_t> > sr_costs; // The costs from a region to a source
|
||||
std::vector<capacity_t> s_demands; // The demands of the sources
|
||||
std::vector<capacity_t> r_capacities; // The remaining capacities of the regions
|
||||
|
||||
// Shortest path data
|
||||
std::vector<float_t> r_costs; // The costs of allocating to a region
|
||||
std::vector<index_t> r_parents; // The parents of the regions i.e. the regions where we push sources first (or null_ind)
|
||||
std::vector<index_t> r_sources; // The source involved in these edges
|
||||
std::vector<capacity_t> arc_capacities; // The capacities of the edges to the parents, or of the region if no parent
|
||||
|
||||
// Best edges data
|
||||
std::vector<std::vector<std::priority_queue<movable_source> > > best_interregions_costs; // What is the best source to move to go from region k1 to region k2?
|
||||
index_t dijkstra_cnt;
|
||||
|
||||
|
||||
// Helper functions
|
||||
|
||||
// Number of regions
|
||||
index_t region_cnt() const{
|
||||
assert(sr_costs.size() == sr_allocations.size());
|
||||
return sr_costs.size();
|
||||
}
|
||||
|
||||
// Update the edge between two regions
|
||||
void update_edge(index_t r1, index_t r2);
|
||||
// Add a source to all heaps of a region; returns if we need to update a path
|
||||
bool add_source_to_heaps(index_t r, index_t source);
|
||||
// Initialize the heaps of a region
|
||||
void create_heaps(index_t reg);
|
||||
|
||||
// Run the shortest path algorithm to update the cost of each region
|
||||
void dijkstra_update();
|
||||
|
||||
// Update the edge and returns if we need to rerun Dijkstra
|
||||
bool push_edge(index_t reg, capacity_t flow);
|
||||
// Updates a full path when pushing an element; returns if we need to rerun Dijkstra
|
||||
bool push_path(index_t pushed_reg, capacity_t demanded, capacity_t & flow);
|
||||
|
||||
public:
|
||||
// Add a new source to the transportation problem; should be done in decreasing order of demand to keep low complexity
|
||||
void add_source(index_t elt_ind);
|
||||
|
||||
current_allocation(std::vector<capacity_t> caps, std::vector<capacity_t> demands, std::vector<std::vector<float_t> > costs)
|
||||
:
|
||||
sr_allocations(caps.size()),
|
||||
sr_costs(costs),
|
||||
s_demands(demands),
|
||||
r_capacities(caps),
|
||||
r_costs(caps.size(), 0.0),
|
||||
r_parents(caps.size(), null_ind),
|
||||
r_sources(caps.size(), null_ind),
|
||||
arc_capacities(caps),
|
||||
best_interregions_costs(caps.size(), std::vector<std::priority_queue<movable_source> >(caps.size())),
|
||||
dijkstra_cnt(0)
|
||||
{
|
||||
assert(caps.size() > 0);
|
||||
assert(costs.size() == caps.size());
|
||||
dijkstra_update();
|
||||
}
|
||||
|
||||
std::vector<std::vector<capacity_t> > get_allocations() const{ return sr_allocations; }
|
||||
index_t get_iterations_cnt() const { return dijkstra_cnt; }
|
||||
};
|
||||
|
||||
const index_t current_allocation::null_ind = std::numeric_limits<index_t>::max();
|
||||
|
||||
void current_allocation::update_edge(index_t r1, index_t r2){
|
||||
while(not best_interregions_costs[r1][r2].empty() and sr_allocations[r1][best_interregions_costs[r1][r2].top().source] == 0){
|
||||
best_interregions_costs[r1][r2].pop();
|
||||
}
|
||||
|
||||
if(not best_interregions_costs[r1][r2].empty()){
|
||||
// There is an edge
|
||||
movable_source cur = best_interregions_costs[r1][r2].top();
|
||||
float_t new_cost = r_costs[r2] + cur.cost;
|
||||
if(new_cost < r_costs[r1]){
|
||||
r_costs[r1] = cur.cost;
|
||||
r_sources[r1] = cur.source;
|
||||
r_parents[r1] = r2;
|
||||
arc_capacities[r1] = sr_allocations[r1][cur.source];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool current_allocation::add_source_to_heaps(index_t r, index_t source){
|
||||
bool need_rerun = false;
|
||||
for(index_t i=0; i<region_cnt(); ++i){
|
||||
if(i == r) continue;
|
||||
best_interregions_costs[r][i].push(
|
||||
movable_source(source,
|
||||
sr_costs[i][source] - sr_costs[r][source]
|
||||
)
|
||||
);
|
||||
while(sr_allocations[r][best_interregions_costs[r][i].top().source] == 0){
|
||||
best_interregions_costs[r][i].pop();
|
||||
}
|
||||
need_rerun = (best_interregions_costs[r][i].top().source == source) or need_rerun;
|
||||
}
|
||||
return need_rerun;
|
||||
}
|
||||
|
||||
void current_allocation::create_heaps(index_t reg){
|
||||
// Get all relevant elements
|
||||
std::vector<std::vector<movable_source> > interregion_costs(region_cnt());
|
||||
for(index_t i=0; i<sr_allocations[reg].size(); ++i){
|
||||
if(sr_allocations[reg][i] > 0){
|
||||
for(index_t oreg=0; oreg<region_cnt(); ++oreg){
|
||||
if(oreg == reg) continue;
|
||||
interregion_costs[oreg].push_back(
|
||||
movable_source(
|
||||
i,
|
||||
sr_costs[oreg][i] - sr_costs[reg][i]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Create the heaps
|
||||
for(index_t oreg=0; oreg<region_cnt(); ++oreg){
|
||||
best_interregions_costs[reg][oreg] = std::priority_queue<movable_source>(interregion_costs[oreg].begin(), interregion_costs[oreg].end());
|
||||
}
|
||||
}
|
||||
|
||||
// Returns if the path has been modified so that we would need to rerun Dijkstra
|
||||
bool current_allocation::push_edge(index_t reg, capacity_t flow){
|
||||
index_t cur_source = r_sources[reg];
|
||||
|
||||
// Does this edge allocates a new source in the destination region? If yes, update the corresponding heaps
|
||||
bool already_present = sr_allocations[r_parents[reg]][cur_source] > 0;
|
||||
|
||||
// Deallocating from the first region is handled by the get_edge function: just substract the flow
|
||||
sr_allocations[ reg ][cur_source] -= flow;
|
||||
sr_allocations[r_parents[reg]][cur_source] += flow;
|
||||
|
||||
assert(sr_allocations[reg][cur_source] >= 0); // The source to be pushed was indeed present in the region
|
||||
assert(r_capacities[reg] == 0); // The region is full, which explains why we need to push
|
||||
assert(flow <= arc_capacities[reg]); // The flow is not bigger than what can be sent
|
||||
|
||||
arc_capacities[reg] = sr_allocations[reg][cur_source]; // Just update the capacity if it turns out that we don't need to run Dijkstra
|
||||
|
||||
if(arc_capacities[reg] == 0){
|
||||
// The source may have been deleted from a region: rerun Dijkstra at the end
|
||||
return true;
|
||||
}
|
||||
else if(not already_present and r_capacities[r_parents[reg]] == 0){
|
||||
// A new source is allocated to a full region: rerun Dijkstra at the end if it changed the heap's top
|
||||
return add_source_to_heaps(r_parents[reg], cur_source);
|
||||
}
|
||||
else{
|
||||
// The edge is still present with the same cost and non-zero updated capacity
|
||||
// The path still exists: no need to rerun Dijkstra yet
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void current_allocation::dijkstra_update(){
|
||||
// Simple case of the regions with remaining capacity
|
||||
std::vector<int> visited(region_cnt(), 0);
|
||||
index_t visited_cnt = 0;
|
||||
for(index_t i=0; i<region_cnt(); ++i){
|
||||
r_sources[i] = null_ind;
|
||||
r_parents[i] = null_ind;
|
||||
if(r_capacities[i] > 0){
|
||||
r_costs[i] = 0.0;
|
||||
arc_capacities[i] = r_capacities[i];
|
||||
|
||||
visited[i] = 1;
|
||||
++visited_cnt;
|
||||
}
|
||||
else{
|
||||
r_costs[i] = std::numeric_limits<float_t>::infinity();
|
||||
arc_capacities[i] = 0;
|
||||
}
|
||||
}
|
||||
// if(visited_cnt <= 0) throw std::runtime_error("Capacity problem: no region has been marked as reachable\n");
|
||||
if(visited_cnt == region_cnt()){ return; }
|
||||
// Get the costs for every non-visited region
|
||||
for(index_t i=0; i<region_cnt(); ++i) if(visited[i] == 0){ // For every region that is not visited yet
|
||||
for(index_t j=0; j<region_cnt(); ++j) if(visited[j] == 1){ // For every already visited region
|
||||
// Get the best interregion cost
|
||||
update_edge(i,j);
|
||||
}
|
||||
}
|
||||
while(visited_cnt < region_cnt()){
|
||||
// Find the region with the lowest cost to visit; mark it visited
|
||||
index_t best_reg = null_ind;
|
||||
float_t best_cost = std::numeric_limits<float_t>::infinity();
|
||||
for(index_t i=0; i<region_cnt(); ++i) if(visited[i] == 0){ // For every region that is not visited yet
|
||||
if(r_costs[i] < best_cost){
|
||||
best_cost = r_costs[i];
|
||||
best_reg = i;
|
||||
}
|
||||
}
|
||||
if(best_reg == null_ind) break; // Some regions are unreachable, typically because they have zero capacity at the beginning
|
||||
visited[best_reg] = 1;
|
||||
++visited_cnt;
|
||||
// Update the cost for every unvisited region
|
||||
for(index_t i=0; i<region_cnt(); ++i) if(visited[i] == 0){ // For every region that is not visited yet
|
||||
update_edge(i, best_reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool current_allocation::push_path(index_t pushed_reg, capacity_t demanded, capacity_t & flow){
|
||||
// Get the final flow sent, which is smaller than the capacities on the path
|
||||
flow = demanded;
|
||||
for(index_t reg = pushed_reg; reg != null_ind; reg = r_parents[reg]){
|
||||
flow = std::min(flow, arc_capacities[reg]);
|
||||
}
|
||||
|
||||
bool rerun_dijkstra = false;
|
||||
// Update the path between the regions
|
||||
index_t reg = pushed_reg;
|
||||
for(; r_parents[reg] != null_ind; reg = r_parents[reg]){
|
||||
assert(r_capacities[reg] == 0);
|
||||
rerun_dijkstra = push_edge(reg, flow) or rerun_dijkstra;
|
||||
}
|
||||
|
||||
assert(r_capacities[reg] > 0);
|
||||
assert(arc_capacities[reg] == r_capacities[reg]);
|
||||
assert(r_capacities[reg] >= flow);
|
||||
|
||||
// Update the capacities at the end
|
||||
r_capacities[reg] -= flow;
|
||||
arc_capacities[reg] -= flow;
|
||||
|
||||
// The last region on the path is the one that satisfies the demand
|
||||
if(r_capacities[reg] == 0){ // If we just consumed the available capacity, it becomes useful to move sources off this region: build the heap
|
||||
create_heaps(reg);
|
||||
rerun_dijkstra = true;
|
||||
}
|
||||
|
||||
assert(flow > 0);
|
||||
|
||||
// If an edge changes cost or a region is full,
|
||||
// we need to update the costs, parents, sources and arc_capacities using a Dijkstra
|
||||
// but later
|
||||
return rerun_dijkstra;
|
||||
}
|
||||
|
||||
void current_allocation::add_source(index_t elt_ind){ //capacity_t demand, std::vector<float_t> const & costs){
|
||||
for(index_t i=0; i<region_cnt(); ++i){
|
||||
sr_allocations[i].push_back(0);
|
||||
}
|
||||
|
||||
bool need_rerun = false;
|
||||
capacity_t demand = s_demands[elt_ind];
|
||||
|
||||
while(demand > 0){
|
||||
// In case we modified the structures earlier
|
||||
if(need_rerun){
|
||||
dijkstra_update();
|
||||
need_rerun = false;
|
||||
}
|
||||
|
||||
++ dijkstra_cnt;
|
||||
index_t best_reg = null_ind;
|
||||
float_t best_cost = std::numeric_limits<float_t>::infinity();
|
||||
for(index_t reg=0; reg<region_cnt(); ++reg){
|
||||
// Find the region which gets the source
|
||||
if(r_costs[reg] + sr_costs[reg][elt_ind] < best_cost){
|
||||
best_reg = reg;
|
||||
best_cost = r_costs[reg] + sr_costs[reg][elt_ind];
|
||||
}
|
||||
}
|
||||
if(best_reg == null_ind){ throw std::runtime_error("No reachable region found\n"); }
|
||||
|
||||
capacity_t flow = 0;
|
||||
// Tells us whether we need to update the data structures
|
||||
need_rerun = push_path(best_reg, demand, flow);
|
||||
demand -= flow;
|
||||
|
||||
// Lazily store the change
|
||||
sr_allocations[best_reg][elt_ind] += flow;
|
||||
}
|
||||
|
||||
// Set the source's demand
|
||||
for(index_t i=0; i<region_cnt(); ++i){
|
||||
if(r_capacities[i] == 0 and sr_allocations[i][elt_ind] > 0){
|
||||
need_rerun = add_source_to_heaps(i, elt_ind) or need_rerun;
|
||||
}
|
||||
}
|
||||
// We leave a clean set with correct paths for the next iteration
|
||||
if(need_rerun)
|
||||
dijkstra_update();
|
||||
}
|
||||
|
||||
} // End anonymous namespace
|
||||
|
||||
std::vector<std::vector<capacity_t> > transport_generic(std::vector<capacity_t> const & capacities, std::vector<capacity_t> const & demands, std::vector<std::vector<float_t> > const & costs){
|
||||
current_allocation transporter(capacities, demands, costs);
|
||||
|
||||
for(index_t i=0; i<demands.size(); ++i){
|
||||
transporter.add_source(i);
|
||||
}
|
||||
|
||||
return transporter.get_allocations();
|
||||
}
|
||||
|
||||
bool place_convex_single_row(std::vector<int_t> const & widths, std::vector<std::pair<int_t, int_t> > const & ranges, std::vector<cell_bound> bounds, std::vector<int_t> const & const_slopes, std::vector<int_t> & positions){
|
||||
std::sort(bounds.begin(), bounds.end());
|
||||
|
||||
struct bound{
|
||||
int_t abs_pos;
|
||||
int_t slope_diff;
|
||||
|
||||
bool operator<(bound const o) const{ return abs_pos < o.abs_pos; }
|
||||
bound(int_t p, int_t s) : abs_pos(p), slope_diff(s) {}
|
||||
};
|
||||
std::priority_queue<bound> prio_queue;
|
||||
|
||||
std::vector<int_t> prev_widths(widths.size()+1, 0);
|
||||
std::partial_sum(widths.begin(), widths.end(), std::next(prev_widths.begin()));
|
||||
|
||||
std::vector<int_t> constraining_pos(widths.size());
|
||||
|
||||
int_t lower_lim = std::numeric_limits<int_t>::min();
|
||||
for(index_t i=0, j=0; i<widths.size(); ++i){
|
||||
int_t old_width = prev_widths[i];
|
||||
int_t new_width = prev_widths[i+1];
|
||||
|
||||
lower_lim = std::max(ranges[i].first - old_width, lower_lim);
|
||||
int_t upper_lim = ranges[i].second - new_width;
|
||||
|
||||
for(; j<bounds.size() and bounds[j].c == i; ++j){
|
||||
prio_queue.push(bound(bounds[j].pos - old_width, bounds[j].slope));
|
||||
}
|
||||
|
||||
if(upper_lim < lower_lim){ // Infeasible
|
||||
return false;
|
||||
}
|
||||
int_t cur_slope = const_slopes[i];
|
||||
int_t cur_pos = upper_lim;
|
||||
|
||||
while(not prio_queue.empty() and (cur_slope > 0 or prio_queue.top().abs_pos > upper_lim)){
|
||||
cur_slope -= prio_queue.top().slope_diff;
|
||||
cur_pos = prio_queue.top().abs_pos;
|
||||
prio_queue.pop();
|
||||
}
|
||||
int_t final_abs_pos = std::max(std::min(cur_pos, upper_lim), lower_lim);
|
||||
constraining_pos[i] = final_abs_pos;
|
||||
if(cur_slope < 0){
|
||||
prio_queue.push(bound(final_abs_pos, -cur_slope));
|
||||
}
|
||||
}
|
||||
|
||||
positions.resize(constraining_pos.size());
|
||||
std::partial_sum(constraining_pos.rbegin(), constraining_pos.rend(), positions.rbegin(), [](int_t a, int_t b)->int_t{ return std::min(a,b); });
|
||||
for(index_t i=0; i<positions.size(); ++i){
|
||||
positions[i] += prev_widths[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool place_noncvx_single_row(std::vector<int_t> const & widths, std::vector<std::pair<int_t, int_t> > const & ranges, std::vector<int> const & flippables, std::vector<cell_bound> bounds, std::vector<int_t> const & const_slopes, std::vector<int_t> & positions, std::vector<int> & flippings){
|
||||
flippings = std::vector<int>(positions.size(), 0);
|
||||
return place_convex_single_row(widths, ranges, bounds, const_slopes, positions);
|
||||
}
|
||||
|
||||
} // Namespace coloquinte
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
#include "coloquinte/circuit_helper.hxx"
|
||||
|
||||
#include <stack>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
|
||||
namespace coloquinte{
|
||||
namespace gp{
|
||||
|
||||
namespace{
|
||||
//index_t const null_ind = std::numeric_limits<index_t>::max();
|
||||
|
||||
inline void opt_orient(netlist const & circuit, placement_t & pl, std::function<int_t (point<int_t>)> i_coor, std::function<bool & (point<bool> &)> b_coor,mask_t FLIPPABLE){
|
||||
std::stack<index_t> opt_cells;
|
||||
for(index_t cell_ind = 0; cell_ind < circuit.cell_cnt(); ++cell_ind){
|
||||
if( (circuit.get_cell(cell_ind).attributes & FLIPPABLE) != 0)
|
||||
opt_cells.push(cell_ind);
|
||||
}
|
||||
while(not opt_cells.empty()){
|
||||
index_t cell_ind = opt_cells.top(); opt_cells.pop();
|
||||
assert((circuit.get_cell(cell_ind).attributes & FLIPPABLE) != 0);
|
||||
|
||||
// What is the current orientation?
|
||||
bool old_orientation = b_coor(pl.orientations_[cell_ind]);
|
||||
int_t pos = i_coor(pl.positions_[cell_ind]);
|
||||
int_t size = i_coor(circuit.get_cell(cell_ind).size);
|
||||
|
||||
// Check both orientations of the cell
|
||||
std::vector<index_t> involved_nets;
|
||||
for(netlist::pin_t p : circuit.get_cell(cell_ind)){
|
||||
involved_nets.push_back(p.net_ind);
|
||||
}
|
||||
// Deal with cells with multiple pins in one net (uniquify)
|
||||
std::sort(involved_nets.begin(), involved_nets.end());
|
||||
involved_nets.resize(std::distance(involved_nets.begin(), std::unique(involved_nets.begin(), involved_nets.end())));
|
||||
|
||||
std::int64_t p_cost = 0, n_cost = 0;
|
||||
std::vector<index_t> extreme_elements;
|
||||
for(index_t n : involved_nets){
|
||||
std::vector<pin_1D> other_pins;
|
||||
std::vector<int_t> offsets;
|
||||
for(auto p : circuit.get_net(n)){
|
||||
if(p.cell_ind != cell_ind){
|
||||
other_pins.push_back(pin_1D(
|
||||
p.cell_ind,
|
||||
i_coor(pl.positions_[p.cell_ind])
|
||||
+ (b_coor(pl.orientations_[p.cell_ind]) ? i_coor(p.offset) : i_coor(circuit.get_cell(p.cell_ind).size) - i_coor(p.offset)),
|
||||
0, // Don't care about the offset
|
||||
(circuit.get_cell(p.cell_ind).attributes & FLIPPABLE) != 0)
|
||||
);
|
||||
}
|
||||
else{
|
||||
offsets.push_back(i_coor(p.offset));
|
||||
}
|
||||
}
|
||||
assert(offsets.size() > 0);
|
||||
if(other_pins.size() > 0){ // Else the orientation of the cell doesn't change anything
|
||||
auto minmaxC = std::minmax_element(other_pins.begin(), other_pins.end());
|
||||
auto minmaxO = std::minmax_element(offsets.begin(), offsets.end());
|
||||
p_cost += std::max(pos + *minmaxO.second, minmaxC.second->pos) - std::min(pos + *minmaxO.first, minmaxC.first->pos);
|
||||
n_cost += std::max(pos + size - *minmaxO.first, minmaxC.second->pos) - std::min(pos + size - *minmaxO.second, minmaxC.first->pos);
|
||||
|
||||
int_t min_pin_pos = std::min(pos + *minmaxO.second, pos + size - *minmaxO.first),
|
||||
max_pin_pos = std::max(pos + *minmaxO.second, pos + size - *minmaxO.first);
|
||||
|
||||
// Do the extreme elements change between the two positions?
|
||||
if(minmaxC.second->movable
|
||||
and (minmaxC.second->pos < max_pin_pos)
|
||||
and (minmaxC.second->pos > min_pin_pos) ){
|
||||
extreme_elements.push_back(minmaxC.second->cell_ind);
|
||||
}
|
||||
if(minmaxC.first->movable
|
||||
and (minmaxC.first->pos < max_pin_pos)
|
||||
and (minmaxC.first->pos > min_pin_pos) ){
|
||||
extreme_elements.push_back(minmaxC.first->cell_ind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(p_cost < n_cost)
|
||||
b_coor(pl.orientations_[cell_ind]) = true;
|
||||
if(p_cost > n_cost)
|
||||
b_coor(pl.orientations_[cell_ind]) = false;
|
||||
|
||||
// If we changed the orientation, check the extreme pins which changed and try their cells again
|
||||
if(b_coor(pl.orientations_[cell_ind]) != old_orientation){
|
||||
std::sort(extreme_elements.begin(), extreme_elements.end());
|
||||
extreme_elements.resize(std::distance(extreme_elements.begin(), std::unique(extreme_elements.begin(), extreme_elements.end())));
|
||||
for(index_t extreme_cell : extreme_elements){
|
||||
if( (circuit.get_cell(extreme_cell).attributes & FLIPPABLE) != 0)
|
||||
opt_cells.push(extreme_cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
inline void spread_orient(netlist const & circuit, placement_t & pl, std::function<float_t & (point<float_t> &)> coor, mask_t FLIPPABLE){
|
||||
std::vector<float_t> weights(circuit.cell_cnt(), 0.0);
|
||||
for(index_t n=0; n<circuit.net_cnt(); ++n){
|
||||
float_t min_pos=INF, max_pos=-INF;
|
||||
float_t min_offs=INF, max_offs=-INF;
|
||||
index_t min_ind=null_ind, max_ind=null_ind;
|
||||
for(netlist::pin_t p : circuit.get_net(n)){
|
||||
if( (circuit.get_cell(p.cell_ind).attributes & FLIPPABLE) != 0){
|
||||
float_t pos = coor(pl.positions_[p.cell_ind]);
|
||||
if(pos < min_pos){
|
||||
min_pos = pos;
|
||||
min_ind = p.cell_ind;
|
||||
min_offs = coor(p.offset);
|
||||
}
|
||||
if(pos > max_pos){
|
||||
max_pos = pos;
|
||||
max_ind = p.cell_ind;
|
||||
max_offs = coor(p.offset);
|
||||
}
|
||||
}
|
||||
else{
|
||||
float_t pos = coor(pl.positions_[p.cell_ind]) + coor(pl.orientations_[p.cell_ind]) * coor(p.offset);
|
||||
if(pos < min_pos){
|
||||
min_pos = pos;
|
||||
min_ind = null_ind;
|
||||
}
|
||||
if(pos > max_pos){
|
||||
max_pos = pos;
|
||||
max_ind = null_ind;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float_t net_weight = circuit.get_net(n).weight;
|
||||
|
||||
if(min_ind != null_ind) weights[min_ind] += net_weight * min_offs;
|
||||
if(max_ind != null_ind) weights[max_ind] -= net_weight * max_offs;
|
||||
}
|
||||
|
||||
for(index_t c=0; c<circuit.cell_cnt(); ++c){
|
||||
coor(pl.orientations_[c]) = (weights[c] >= 0.0) ? 1.0 : -1.0;
|
||||
}
|
||||
}
|
||||
*/
|
||||
} // End anonymous namespace
|
||||
|
||||
void optimize_x_orientations(netlist const & circuit, placement_t & pl){
|
||||
opt_orient(circuit, pl, [](point<int_t> p) -> int_t { return p.x; }, [](point<bool> & p) -> bool & { return p.x; }, XFlippable);
|
||||
}
|
||||
void optimize_y_orientations(netlist const & circuit, placement_t & pl){
|
||||
opt_orient(circuit, pl, [](point<int_t> p) -> int_t { return p.y; }, [](point<bool> & p) -> bool & { return p.y; }, YFlippable);
|
||||
}
|
||||
|
||||
// Iteratively optimize feasible orientations; performs only one pass
|
||||
void optimize_exact_orientations(netlist const & circuit, placement_t & pl){
|
||||
optimize_x_orientations(circuit, pl);
|
||||
optimize_y_orientations(circuit, pl);
|
||||
}
|
||||
|
||||
/*
|
||||
void spread_orientations(netlist const & circuit, placement_t & pl){
|
||||
spread_orient(circuit, pl, [](point<float_t> & p) -> float_t & { return p.x; }, XFlippable);
|
||||
spread_orient(circuit, pl, [](point<float_t> & p) -> float_t & { return p.y; }, YFlippable);
|
||||
}
|
||||
*/
|
||||
|
||||
} // namespace gp
|
||||
} // namespace coloquinte
|
||||
|
||||
|
|
@ -1,260 +0,0 @@
|
|||
|
||||
#include "coloquinte/piecewise_linear.hxx"
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
namespace coloquinte{
|
||||
|
||||
namespace{
|
||||
|
||||
struct pl_edge{
|
||||
p_v f, s;
|
||||
|
||||
static void push_intersections(pl_edge a, pl_edge b, piecewise_linear_function & lf){
|
||||
// Strict, because it makes everything easier
|
||||
//assert(a.f.first < b.s.first and a.s.first > b.f.first);
|
||||
//assert(a.f.first < a.s.first and b.f.first < b.s.first);
|
||||
assert(a.f.first <= b.s.first and a.s.first >= b.f.first);
|
||||
assert(a.f.first <= a.s.first and b.f.first <= b.s.first);
|
||||
|
||||
// ra = (a.s.second - a.f.second) / (a.s.first - a.f.first)
|
||||
// xintersect = (yb - ya - xb * rb + xa * ra) / (ra - rb)
|
||||
|
||||
double ra = static_cast<double>(a.s.second - a.f.second) / (a.s.first - a.f.first);
|
||||
double rb = static_cast<double>(b.s.second - b.f.second) / (b.s.first - b.f.first);
|
||||
|
||||
double xintersect = (b.f.second - a.f.second - rb * b.f.first + ra * a.f.first) / (ra - rb);
|
||||
if( not xintersect ) return;
|
||||
|
||||
int_t pos = xintersect;
|
||||
if( std::ceil(xintersect) == std::floor(xintersect) ){ // Exact integer intersection
|
||||
if(pos > std::max(a.f.first, b.f.first) and pos < std::min(a.s.first, b.s.first) ){ // Necessarily smaller than s.first due to the previous condition
|
||||
lf.point_values.push_back(p_v(pos, a.value_at(pos)));
|
||||
}
|
||||
}
|
||||
else{ // Non exact intersection: create two integers since I don't want to mess with floating point
|
||||
int_t pos1 = pos;
|
||||
int_t pos2 = pos + 1;
|
||||
// Value_at is only an approximation, but it shouldn't be too bad
|
||||
if(pos1 > std::max(a.f.first, b.f.first) and pos1 < std::min(a.s.first, b.s.first))
|
||||
lf.point_values.push_back(p_v(pos1, std::min(a.value_at(pos1), b.value_at(pos1))));
|
||||
if(pos2 > std::max(a.f.first, b.f.first) and pos2 < std::min(a.s.first, b.s.first))
|
||||
lf.point_values.push_back(p_v(pos2, std::min(a.value_at(pos2), b.value_at(pos2))));
|
||||
}
|
||||
}
|
||||
|
||||
// Lower-rounded value
|
||||
int_t value_at(int_t pos) const{
|
||||
assert(pos >= f.first and pos <= s.first and s.first > f.first);
|
||||
return (static_cast<std::int64_t>(f.second) * (s.first - pos) + static_cast<std::int64_t>(s.second) * (pos - f.first)) / (s.first - f.first);
|
||||
}
|
||||
// Lower-rounded value
|
||||
int_t pos_at(int_t val) const{
|
||||
assert(val <= std::max(f.second, s.second) and val >= std::min(f.second, s.second));
|
||||
assert(f.second != s.second);
|
||||
return (static_cast<std::int64_t>(f.first) * (s.second - val) + static_cast<std::int64_t>(s.first) * (val - f.second)) / (s.second - f.second);
|
||||
}
|
||||
|
||||
bool above(p_v const o) const{
|
||||
int_t pos = o.first;
|
||||
assert(pos > f.first and pos < s.first);
|
||||
return (static_cast<std::int64_t>(f.second) * (s.first - pos) + static_cast<std::int64_t>(s.second) * (pos - f.first)) > o.second * (s.first - f.first);
|
||||
}
|
||||
|
||||
pl_edge(p_v a, p_v b) : f(a), s(b) {}
|
||||
};
|
||||
} // End anonymous namespace
|
||||
|
||||
void piecewise_linear_function::add_monotone(int_t slope, int_t offset){
|
||||
for(auto & V : point_values){
|
||||
// Offset taken into account here, multiplied with the slope
|
||||
V.second += slope * (V.first - point_values.front().first - offset);
|
||||
}
|
||||
}
|
||||
|
||||
void piecewise_linear_function::add_bislope(int_t s_l, int_t s_r, int_t pos){
|
||||
//assert(pos <= point_values.back().first);
|
||||
//assert(pos >= point_values.front().first);
|
||||
|
||||
/*
|
||||
if(pos >= point_values.back().first){
|
||||
add_monotone(s_l, pos - point_values.front().first);
|
||||
}
|
||||
else if(pos <= point_values.front().first){
|
||||
add_monotone(s_r, pos - point_values.front().first);
|
||||
}
|
||||
else{
|
||||
auto it = point_values.begin();
|
||||
while(it->first < pos){
|
||||
it->second += s_l * (it->first - pos);
|
||||
++it;
|
||||
assert(it != point_values.end());
|
||||
}
|
||||
if(it->first != pos){
|
||||
point_values.insert(it, p_v(pos, pl_edge(*std::prev(it), *it).value_at(pos)));
|
||||
}
|
||||
for(auto & V : point_values){
|
||||
if(V.first > pos)
|
||||
V.second += s_r * (V.first - pos);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
auto it = std::lower_bound(point_values.begin(), point_values.end(), pos, [](p_v o, int_t v){ return o.first < v; });
|
||||
if(it != point_values.end() and it->first != pos and it != point_values.begin()){
|
||||
assert(it->first > pos);
|
||||
point_values.insert(it, p_v(pos, pl_edge(*std::prev(it), *it).value_at(pos)));
|
||||
}
|
||||
|
||||
for(auto & V : point_values){
|
||||
if(V.first > pos)
|
||||
V.second += s_r * (V.first - pos);
|
||||
if(V.first < pos)
|
||||
V.second += s_l * (V.first - pos);
|
||||
}
|
||||
}
|
||||
|
||||
piecewise_linear_function::piecewise_linear_function(int_t min_def, int_t max_def){
|
||||
point_values.push_back(p_v(min_def, 0));
|
||||
point_values.push_back(p_v(max_def, 0));
|
||||
}
|
||||
|
||||
piecewise_linear_function piecewise_linear_function::previous_min() const{
|
||||
|
||||
piecewise_linear_function ret;
|
||||
|
||||
assert(not point_values.empty());
|
||||
|
||||
auto it = point_values.begin();
|
||||
ret.point_values.push_back(*it);
|
||||
++it;
|
||||
// Use the previous minimum to detect when we find something smaller
|
||||
for(; it != point_values.end(); ++it){
|
||||
int_t cur_min = ret.point_values.back().second;
|
||||
assert(it->first >= ret.point_values.back().first);
|
||||
if(it->second < cur_min){
|
||||
if(std::prev(it)->first != ret.point_values.back().first){ // May be equal, in which case we don't need to push anything new
|
||||
int_t pos = pl_edge(*std::prev(it), *it).pos_at(cur_min);
|
||||
if(pos != ret.point_values.back().first and pos != it->first){
|
||||
ret.point_values.push_back(p_v(pos, cur_min));
|
||||
}
|
||||
}
|
||||
ret.point_values.push_back(*it);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
piecewise_linear_function piecewise_linear_function::previous_min_of_sum(piecewise_linear_function const & a, int_t shift) const{
|
||||
piecewise_linear_function ret;
|
||||
|
||||
// Go to the correct definition
|
||||
auto b_begin = point_values.begin(), a_begin = a.point_values.begin();
|
||||
auto b_it = b_begin, a_it = a_begin;
|
||||
auto b_end = point_values.end(), a_end = a.point_values.end();
|
||||
|
||||
while(a_it != a_end){
|
||||
if(b_it == b_end or a_it->first < b_it->first+shift){ // Ok, create an edge and calculate the value
|
||||
if(b_it != b_begin){
|
||||
int_t value;
|
||||
if(b_it != b_end){
|
||||
pl_edge b_edge(*std::prev(b_it), *b_it);
|
||||
value = b_edge.value_at(a_it->first-shift);
|
||||
}
|
||||
else{
|
||||
value = point_values.back().second;
|
||||
}
|
||||
ret.point_values.push_back(p_v(a_it->first, a_it->second + value));
|
||||
}
|
||||
++a_it;
|
||||
}
|
||||
else if(a_it->first > b_it->first+shift){
|
||||
if(a_it != a_begin){
|
||||
pl_edge a_edge(*std::prev(a_it), *a_it);
|
||||
int_t value = a_edge.value_at(b_it->first+shift);
|
||||
ret.point_values.push_back(p_v(b_it->first+shift, b_it->second + value));
|
||||
}
|
||||
++b_it;
|
||||
}
|
||||
else{ // if(a_it->first == b_it->first+shift){
|
||||
ret.point_values.push_back(p_v(a_it->first, a_it->second + b_it->second));
|
||||
++a_it;
|
||||
++b_it;
|
||||
}
|
||||
}
|
||||
|
||||
return ret.previous_min();
|
||||
}
|
||||
|
||||
|
||||
int_t piecewise_linear_function::last_before(int_t pos) const{
|
||||
auto it = point_values.rbegin();
|
||||
while(it != point_values.rend()){
|
||||
if(it->first <= pos){
|
||||
if(it != point_values.rbegin() and std::prev(it)->first > pos){ // On a negative slope
|
||||
return pos;
|
||||
}
|
||||
else{
|
||||
return it->first; // First point or not mapped to a negative slope in the original function
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
assert(false); // We should have found it if the bound was correct
|
||||
return -1;
|
||||
}
|
||||
|
||||
int_t piecewise_linear_function::value_at(int_t pos) const{
|
||||
// First position bigger or equal than pos
|
||||
auto it = std::lower_bound(point_values.begin(), point_values.end(), pos, [](p_v o, int_t v){ return o.first < v; });
|
||||
if(pos != it->first){
|
||||
assert(it != point_values.begin());
|
||||
return pl_edge(*std::prev(it), *it).value_at(pos);
|
||||
}
|
||||
else{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
piecewise_linear_function piecewise_linear_function::piecewise_linear_function::minimum(piecewise_linear_function const & a, piecewise_linear_function const & b){
|
||||
assert(a.point_values.front().first == b.point_values.front().first);
|
||||
assert(a.point_values.back().first == b.point_values.back().first);
|
||||
|
||||
piecewise_linear_function ret;
|
||||
auto a_it = a.point_values.begin(), b_it = b.point_values.begin();
|
||||
auto a_end = a.point_values.end(), b_end = b.point_values.end();
|
||||
|
||||
ret.point_values.push_back(p_v(a_it->first, std::min(a_it->second, b_it->second)));
|
||||
|
||||
assert(std::next(a_it) != a_end and std::next(b_it) != b_end);
|
||||
while(std::next(a_it) != a_end and std::next(b_it) != b_end){
|
||||
pl_edge a_edge(*a_it, *std::next(a_it)), b_edge(*b_it, *std::next(b_it));
|
||||
// Three cases: one of them always below, or both intersect
|
||||
// Both intersect: we push the values when intersecting
|
||||
pl_edge::push_intersections(a_edge, b_edge, ret);
|
||||
|
||||
// In any case, we push the value of the one below if it finishes, and increment the iterator
|
||||
if(a_edge.s.first < b_edge.s.first){
|
||||
++a_it;
|
||||
if(b_edge.above(a_edge.s)){ // We push a_edge.s
|
||||
ret.point_values.push_back(a_edge.s);
|
||||
}
|
||||
}
|
||||
else if(a_edge.s.first > b_edge.s.first){
|
||||
++b_it;
|
||||
if(a_edge.above(b_edge.s)){ // We push a_edge.s
|
||||
ret.point_values.push_back(b_edge.s);
|
||||
}
|
||||
}
|
||||
else{
|
||||
ret.point_values.push_back(p_v(a_edge.s.first, std::min(a_edge.s.second, b_edge.s.second)));
|
||||
++a_it;
|
||||
++b_it;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // End namespace coloquinte
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,599 +0,0 @@
|
|||
|
||||
#include "coloquinte/detailed.hxx"
|
||||
#include "coloquinte/circuit_helper.hxx"
|
||||
|
||||
#include "coloquinte/optimization_subproblems.hxx"
|
||||
#include "coloquinte/union_find.hxx"
|
||||
#include "coloquinte/piecewise_linear.hxx"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace coloquinte{
|
||||
namespace dp{
|
||||
|
||||
namespace{
|
||||
|
||||
struct minmax{
|
||||
int_t min, max;
|
||||
minmax(){}
|
||||
minmax(int_t f, int_t s) : min(f), max(s){}
|
||||
void merge(minmax const o){
|
||||
min = std::min(min, o.min);
|
||||
max = std::max(max, o.max);
|
||||
}
|
||||
void merge(int_t const o){
|
||||
merge(minmax(o, o));
|
||||
}
|
||||
};
|
||||
|
||||
struct order_gettr{
|
||||
index_t cell_ind, seq_order;
|
||||
bool operator<(order_gettr const o) const{ return cell_ind < o.cell_ind; }
|
||||
bool operator<(index_t const o) const{ return cell_ind < o; }
|
||||
order_gettr(index_t c, index_t i) : cell_ind(c), seq_order(i) {}
|
||||
};
|
||||
|
||||
std::vector<order_gettr> get_sorted_ordered_cells(std::vector<index_t> const & cells){
|
||||
std::vector<order_gettr> ret;
|
||||
for(index_t i=0; i<cells.size(); ++i){
|
||||
ret.push_back(order_gettr(cells[i],i));
|
||||
}
|
||||
std::sort(ret.begin(), ret.end());
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<index_t> get_unique_nets(netlist const & circuit, std::vector<index_t> const & cells){
|
||||
std::vector<index_t> involved_nets;
|
||||
for(index_t c : cells){
|
||||
for(netlist::pin_t p : circuit.get_cell(c)){
|
||||
involved_nets.push_back(p.net_ind);
|
||||
}
|
||||
}
|
||||
// Uniquify the nets
|
||||
std::sort(involved_nets.begin(), involved_nets.end());
|
||||
involved_nets.resize(std::distance(involved_nets.begin(), std::unique(involved_nets.begin(), involved_nets.end())));
|
||||
return involved_nets;
|
||||
}
|
||||
|
||||
struct Hnet_group{
|
||||
struct Hpin{
|
||||
index_t cell_index; // Not indexes in the circuit!!! Rather in the internal algorithm
|
||||
minmax offset;
|
||||
bool operator<(Hpin const o) const{ return cell_index < o.cell_index; }
|
||||
};
|
||||
struct Hnet{
|
||||
bool has_ext_pins;
|
||||
minmax ext_pins;
|
||||
int_t weight;
|
||||
|
||||
Hnet(){
|
||||
has_ext_pins = false;
|
||||
ext_pins = minmax(std::numeric_limits<int_t>::max(), 0);
|
||||
weight = 1;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<index_t> net_limits;
|
||||
std::vector<Hnet> nets;
|
||||
|
||||
std::vector<Hpin> pins;
|
||||
std::vector<int_t> cell_widths;
|
||||
|
||||
Hnet_group(){
|
||||
net_limits.push_back(0);
|
||||
}
|
||||
|
||||
void add_net(std::vector<pin_1D> const added_pins, int_t weight){
|
||||
Hnet cur_net;
|
||||
cur_net.weight = weight;
|
||||
std::vector<Hpin> new_pins;
|
||||
for(auto const p : added_pins){
|
||||
if(p.movable){
|
||||
Hpin new_pin;
|
||||
new_pin.cell_index = p.cell_ind;
|
||||
new_pin.offset = minmax(p.offs, p.offs);
|
||||
new_pins.push_back(new_pin);
|
||||
}
|
||||
else{
|
||||
cur_net.has_ext_pins = true;
|
||||
|
||||
cur_net.ext_pins.merge(p.pos);
|
||||
}
|
||||
}
|
||||
std::sort(new_pins.begin(), new_pins.end());
|
||||
|
||||
if(not new_pins.empty()){ // Possible when generating from a Steiner topology
|
||||
// Uniquify just in case there are several pins on the net on a single cell
|
||||
index_t j=0;
|
||||
auto prev_pin = new_pins[0];
|
||||
for(auto it = new_pins.begin()+1; it != new_pins.end(); ++it){
|
||||
if(it->cell_index == prev_pin.cell_index){
|
||||
prev_pin.offset.merge(it->offset);
|
||||
}
|
||||
else{
|
||||
new_pins[j] = prev_pin;
|
||||
++j;
|
||||
prev_pin = *it;
|
||||
}
|
||||
}
|
||||
new_pins[j]=prev_pin;
|
||||
new_pins.resize(j+1);
|
||||
nets.push_back(cur_net);
|
||||
net_limits.push_back(net_limits.back() + new_pins.size());
|
||||
pins.insert(pins.end(), new_pins.begin(), new_pins.end());
|
||||
}
|
||||
}
|
||||
|
||||
std::int64_t get_cost(std::vector<int_t> const & pos) const{
|
||||
std::int64_t cost=0;
|
||||
for(index_t n=0; n<nets.size(); ++n){
|
||||
auto cur_net = nets[n];
|
||||
|
||||
minmax mm(std::numeric_limits<int_t>::max(), std::numeric_limits<int_t>::min());
|
||||
if(cur_net.has_ext_pins){
|
||||
mm = cur_net.ext_pins;
|
||||
}
|
||||
|
||||
assert(net_limits[n+1] > net_limits[n]);
|
||||
for(index_t p=net_limits[n]; p<net_limits[n+1]; ++p){
|
||||
int_t cur_pos = pos[pins[p].cell_index];
|
||||
mm.merge( minmax(cur_pos + pins[p].offset.min, cur_pos + pins[p].offset.max) );
|
||||
}
|
||||
cost += static_cast<std::int64_t>(cur_net.weight) * (mm.max - mm.min);
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
std::int64_t get_cost(std::vector<int_t> const & pos, std::vector<int> const & flip) const{
|
||||
std::int64_t cost=0;
|
||||
for(index_t n=0; n<nets.size(); ++n){
|
||||
auto cur_net = nets[n];
|
||||
|
||||
minmax mm(std::numeric_limits<int_t>::max(), std::numeric_limits<int_t>::min());
|
||||
if(cur_net.has_ext_pins){
|
||||
mm = cur_net.ext_pins;
|
||||
}
|
||||
|
||||
assert(net_limits[n+1] > net_limits[n]);
|
||||
for(index_t p=net_limits[n]; p<net_limits[n+1]; ++p){
|
||||
int_t cur_pos = pos[pins[p].cell_index];
|
||||
bool flipped = flip[pins[p].cell_index];
|
||||
int_t wdth = cell_widths[pins[p].cell_index];
|
||||
mm.merge( flipped ?
|
||||
minmax(cur_pos + wdth - pins[p].offset.max, cur_pos + wdth - pins[p].offset.min)
|
||||
: minmax(cur_pos + pins[p].offset.min, cur_pos + pins[p].offset.max)
|
||||
);
|
||||
}
|
||||
cost += static_cast<std::int64_t>(cur_net.weight) * (mm.max - mm.min);
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Hnet_group get_B2B_netgroup(netlist const & circuit, detailed_placement const & pl, std::vector<index_t> const & cells){
|
||||
|
||||
std::vector<order_gettr> cells_in_row = get_sorted_ordered_cells(cells);
|
||||
std::vector<index_t> involved_nets = get_unique_nets(circuit, cells);
|
||||
|
||||
Hnet_group ret;
|
||||
for(index_t c : cells)
|
||||
ret.cell_widths.push_back(circuit.get_cell(c).size.x);
|
||||
|
||||
for(index_t n : involved_nets){
|
||||
std::vector<pin_1D> cur_pins = get_pins_1D(circuit, pl.plt_, n).x;
|
||||
for(pin_1D & p : cur_pins){
|
||||
auto it = std::lower_bound(cells_in_row.begin(), cells_in_row.end(), p.cell_ind);
|
||||
if(it != cells_in_row.end() and it->cell_ind == p.cell_ind){
|
||||
p.cell_ind = it->seq_order;
|
||||
}
|
||||
else{ // Found a pin which remains fixed for this round
|
||||
p.movable = false;
|
||||
}
|
||||
}
|
||||
ret.add_net(cur_pins, circuit.get_net(n).weight);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Hnet_group get_RSMT_netgroup(netlist const & circuit, detailed_placement const & pl, std::vector<index_t> const & cells){
|
||||
|
||||
std::vector<order_gettr> cells_in_row = get_sorted_ordered_cells(cells);
|
||||
std::vector<index_t> involved_nets = get_unique_nets(circuit, cells);
|
||||
|
||||
Hnet_group ret;
|
||||
for(index_t c : cells)
|
||||
ret.cell_widths.push_back(circuit.get_cell(c).size.x);
|
||||
|
||||
for(index_t n : involved_nets){
|
||||
auto vpins = get_pins_2D(circuit, pl.plt_, n);
|
||||
for(auto & p : vpins){
|
||||
auto it = std::lower_bound(cells_in_row.begin(), cells_in_row.end(), p.cell_ind);
|
||||
if(it != cells_in_row.end() and it->cell_ind == p.cell_ind){
|
||||
p.cell_ind = it->seq_order;
|
||||
}
|
||||
else{
|
||||
p.movable = false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<point<int_t> > pin_locations;
|
||||
for(auto p : vpins)
|
||||
pin_locations.push_back(p.pos);
|
||||
auto const Htopo = get_RSMT_topology(pin_locations, 8).x;
|
||||
|
||||
// In the horizontal topology, we transform the parts of the tree that are on the row into HPWL subnets
|
||||
// Two pins sharing an edge are in the same subnet if one of them is on the row: use union-find
|
||||
union_find UF(vpins.size());
|
||||
for(auto E : Htopo){
|
||||
if( vpins[E.first].movable or vpins[E.second].movable){
|
||||
UF.merge(E.first, E.second);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<pin_1D> > connex_comps(vpins.size());
|
||||
for(index_t i=0; i<vpins.size(); ++i){
|
||||
connex_comps[UF.find(i)].push_back(vpins[i].x());;
|
||||
}
|
||||
|
||||
int_t weight = circuit.get_net(n).weight;
|
||||
for(index_t i=0; i<vpins.size(); ++i){
|
||||
if(not connex_comps[i].empty()){
|
||||
ret.add_net(connex_comps[i], weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Optimizes an ordered sequence of standard cells on the same row, returns the cost and the corresponding positions
|
||||
inline std::int64_t optimize_convex_sequence(Hnet_group const & nets, std::vector<index_t> const & permutation, std::vector<int_t> & positions, std::vector<std::pair<int_t, int_t> > const & cell_ranges){
|
||||
// Get the widths of the cells in row order
|
||||
std::vector<int_t> loc_widths(permutation.size());
|
||||
std::vector<std::pair<int_t, int_t> > loc_ranges(permutation.size());
|
||||
for(index_t i=0; i<permutation.size(); ++i){
|
||||
loc_widths[permutation[i]] = nets.cell_widths[i];
|
||||
loc_ranges[permutation[i]] = cell_ranges[i];
|
||||
}
|
||||
|
||||
std::vector<cell_bound> bounds;
|
||||
std::vector<int_t> right_slopes(permutation.size(), 0);
|
||||
for(index_t n=0; n<nets.nets.size(); ++n){
|
||||
index_t fst_c=std::numeric_limits<index_t>::max(), lst_c=0;
|
||||
int_t fst_pin_offs=0, lst_pin_offs=0;
|
||||
assert(nets.net_limits[n+1] > nets.net_limits[n]);
|
||||
auto cur_net = nets.nets[n];
|
||||
for(index_t p=nets.net_limits[n]; p<nets.net_limits[n+1]; ++p){
|
||||
// Permutation: index in the Hnet_group to index in the row
|
||||
index_t cur_cell = permutation[nets.pins[p].cell_index];
|
||||
if(cur_cell < fst_c){
|
||||
fst_c = cur_cell;
|
||||
fst_pin_offs = nets.pins[p].offset.min;
|
||||
}
|
||||
if(cur_cell >= lst_c){
|
||||
lst_c = cur_cell;
|
||||
lst_pin_offs = nets.pins[p].offset.max;
|
||||
}
|
||||
}
|
||||
if(cur_net.has_ext_pins){
|
||||
bounds.push_back(cell_bound(fst_c, cur_net.ext_pins.min - fst_pin_offs, cur_net.weight));
|
||||
bounds.push_back(cell_bound(lst_c, cur_net.ext_pins.max - lst_pin_offs, cur_net.weight));
|
||||
|
||||
right_slopes[lst_c] += cur_net.weight;
|
||||
}
|
||||
else{
|
||||
right_slopes[lst_c] += cur_net.weight;
|
||||
right_slopes[fst_c] -= cur_net.weight;
|
||||
}
|
||||
}
|
||||
|
||||
bool feasible = place_convex_single_row(loc_widths, loc_ranges, bounds, right_slopes, positions);
|
||||
|
||||
auto permuted_positions = positions;
|
||||
for(index_t i=0; i<permutation.size(); ++i){
|
||||
permuted_positions[i] = positions[permutation[i]];
|
||||
}
|
||||
if(feasible)
|
||||
return nets.get_cost(permuted_positions);
|
||||
else
|
||||
return std::numeric_limits<std::int64_t>::max(); // Infeasible: return a very big cost
|
||||
}
|
||||
|
||||
// TODO: take modified order relative to the obstacles into account
|
||||
inline std::int64_t optimize_noncvx_sequence(Hnet_group const & nets, std::vector<index_t> const & permutation, std::vector<int_t> & positions, std::vector<int> & flippings, std::vector<int> const & flippability, std::vector<std::pair<int_t, int_t> > const & cell_ranges){
|
||||
// Get the widths of the cells in row order
|
||||
std::vector<int_t> loc_widths(permutation.size());
|
||||
std::vector<int> loc_flipps(permutation.size());
|
||||
std::vector<std::pair<int_t, int_t> > loc_ranges(permutation.size());
|
||||
for(index_t i=0; i<permutation.size(); ++i){
|
||||
loc_widths[permutation[i]] = nets.cell_widths[i];
|
||||
loc_ranges[permutation[i]] = cell_ranges[i];
|
||||
loc_flipps[permutation[i]] = flippability[i];
|
||||
}
|
||||
|
||||
int_t min_limit = std::numeric_limits<int_t>::min();
|
||||
for(index_t i=0; i<loc_ranges.size(); ++i){
|
||||
min_limit = std::max(loc_ranges[i].first, min_limit);
|
||||
loc_ranges[i].first = min_limit;
|
||||
min_limit += loc_widths[i];
|
||||
}
|
||||
int_t max_limit = std::numeric_limits<int_t>::max();
|
||||
for(index_t i=loc_ranges.size(); i>0; --i){
|
||||
max_limit = std::min(loc_ranges[i-1].second, max_limit);
|
||||
max_limit -= loc_widths[i-1];
|
||||
loc_ranges[i-1].second = max_limit;
|
||||
}
|
||||
|
||||
for(index_t i=0; i<loc_ranges.size(); ++i){
|
||||
if(loc_ranges[i].first > loc_ranges[i].second){
|
||||
return std::numeric_limits<std::int64_t>::max(); // Infeasible: return a very big cost
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<piecewise_linear_function> unflipped_cost_functions, flipped_cost_functions;
|
||||
for(index_t i=0; i<loc_ranges.size(); ++i){
|
||||
auto cur = piecewise_linear_function(loc_ranges[i].first, loc_ranges[i].second);
|
||||
unflipped_cost_functions.push_back(cur);
|
||||
flipped_cost_functions.push_back(cur);
|
||||
}
|
||||
|
||||
for(index_t n=0; n<nets.nets.size(); ++n){
|
||||
index_t fst_c=std::numeric_limits<index_t>::max(), lst_c=0;
|
||||
int_t fst_pin_offs_mn=0, lst_pin_offs_mn=0,
|
||||
fst_pin_offs_mx=0, lst_pin_offs_mx=0;
|
||||
|
||||
assert(nets.net_limits[n+1] > nets.net_limits[n]);
|
||||
auto cur_net = nets.nets[n];
|
||||
for(index_t p=nets.net_limits[n]; p<nets.net_limits[n+1]; ++p){
|
||||
// Permutation: index in the Hnet_group to index in the row
|
||||
index_t cur_cell = permutation[nets.pins[p].cell_index];
|
||||
if(cur_cell < fst_c){
|
||||
fst_c = cur_cell;
|
||||
fst_pin_offs_mn = nets.pins[p].offset.min;
|
||||
fst_pin_offs_mx = nets.pins[p].offset.max;
|
||||
}
|
||||
if(cur_cell >= lst_c){
|
||||
lst_c = cur_cell;
|
||||
lst_pin_offs_mn = nets.pins[p].offset.min;
|
||||
lst_pin_offs_mx = nets.pins[p].offset.max;
|
||||
}
|
||||
}
|
||||
if(cur_net.has_ext_pins){
|
||||
unflipped_cost_functions[fst_c].add_bislope(-cur_net.weight, 0, cur_net.ext_pins.min - fst_pin_offs_mn);
|
||||
unflipped_cost_functions[lst_c].add_bislope(0, cur_net.weight, cur_net.ext_pins.max - lst_pin_offs_mx);
|
||||
flipped_cost_functions[fst_c].add_bislope(-cur_net.weight, 0, cur_net.ext_pins.min - loc_widths[fst_c] + fst_pin_offs_mx);
|
||||
flipped_cost_functions[lst_c].add_bislope(0, cur_net.weight, cur_net.ext_pins.max - loc_widths[lst_c] + lst_pin_offs_mn);
|
||||
}
|
||||
else{
|
||||
unflipped_cost_functions[fst_c].add_monotone(-cur_net.weight, -fst_pin_offs_mn);
|
||||
unflipped_cost_functions[lst_c].add_monotone( cur_net.weight, -lst_pin_offs_mx);
|
||||
flipped_cost_functions[fst_c].add_monotone(-cur_net.weight, fst_pin_offs_mx - loc_widths[fst_c] );
|
||||
flipped_cost_functions[lst_c].add_monotone( cur_net.weight, lst_pin_offs_mn - loc_widths[lst_c] );
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<piecewise_linear_function> prev_mins, merged_costs;
|
||||
for(index_t i=0; i<loc_ranges.size(); ++i){
|
||||
merged_costs.push_back(loc_flipps[i] ?
|
||||
piecewise_linear_function::minimum(unflipped_cost_functions[i], flipped_cost_functions[i])
|
||||
: unflipped_cost_functions[i]
|
||||
);
|
||||
|
||||
if(i>0){
|
||||
prev_mins.push_back(prev_mins.back().previous_min_of_sum(merged_costs.back(), loc_widths[i-1]));
|
||||
}
|
||||
else{
|
||||
prev_mins.push_back(merged_costs.back().previous_min());
|
||||
}
|
||||
}
|
||||
|
||||
for(auto const M : prev_mins){
|
||||
for(index_t i=0; i+1<M.point_values.size(); ++i){
|
||||
assert(M.point_values[i].second >= M.point_values[i+1].second);
|
||||
}
|
||||
}
|
||||
|
||||
flippings.resize(cell_ranges.size(), 0); positions.resize(cell_ranges.size(), 0);
|
||||
|
||||
int_t pos = std::numeric_limits<int_t>::max();
|
||||
for(index_t i=loc_ranges.size(); i>0; --i){
|
||||
// Find the best position and flipping for each cell
|
||||
pos = prev_mins[i-1].last_before(std::min(pos - loc_widths[i-1], loc_ranges[i-1].second) );
|
||||
positions[i-1] = pos;
|
||||
|
||||
if(loc_flipps[i-1] and flipped_cost_functions[i-1].value_at(pos) < unflipped_cost_functions[i-1].value_at(pos)){
|
||||
flippings[i-1] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for(index_t i=0; i<loc_ranges.size(); ++i){
|
||||
assert(positions[i] >= loc_ranges[i].first);
|
||||
assert(positions[i] <= loc_ranges[i].second);
|
||||
}
|
||||
for(index_t i=0; i+1<loc_ranges.size(); ++i){
|
||||
assert(positions[i] + loc_widths[i] <= positions[i+1]);
|
||||
}
|
||||
|
||||
auto permuted_positions = positions;
|
||||
auto permuted_flippings = flippings;
|
||||
for(index_t i=0; i<permutation.size(); ++i){
|
||||
permuted_positions[i] = positions[permutation[i]];
|
||||
permuted_flippings[i] = flippings[permutation[i]];
|
||||
}
|
||||
|
||||
return nets.get_cost(permuted_positions, permuted_flippings);
|
||||
}
|
||||
|
||||
std::vector<std::pair<int_t, int_t> > get_cell_ranges(netlist const & circuit, detailed_placement const & pl, std::vector<index_t> const & cells){
|
||||
std::vector<std::pair<int_t, int_t> > lims;
|
||||
|
||||
for(index_t i=0; i+1<cells.size(); ++i){
|
||||
assert(pl.plt_.positions_[cells[i]].x + circuit.get_cell(cells[i]).size.x <= pl.plt_.positions_[cells[i+1]].x);
|
||||
}
|
||||
|
||||
// Extreme limits, except macros are allowed to be beyond the limit of the placement area
|
||||
int_t lower_lim = pl.get_limit_positions(circuit, cells.front()).first;
|
||||
int_t upper_lim = pl.get_limit_positions(circuit, cells.back()).second;
|
||||
|
||||
for(index_t OSRP_cell : cells){
|
||||
auto attr = circuit.get_cell(OSRP_cell).attributes;
|
||||
auto cur_lim = std::pair<int_t, int_t>(lower_lim, upper_lim);
|
||||
int_t pos = pl.plt_.positions_[OSRP_cell].x;
|
||||
if( (attr & XMovable) == 0 or pl.cell_height(OSRP_cell) != 1){
|
||||
cur_lim = std::pair<int_t, int_t>(pos, pos + circuit.get_cell(OSRP_cell).size.x);
|
||||
}
|
||||
else{
|
||||
assert(pos >= lower_lim);
|
||||
assert(pos + circuit.get_cell(OSRP_cell).size.x <= upper_lim);
|
||||
}
|
||||
lims.push_back(cur_lim);
|
||||
}
|
||||
|
||||
return lims;
|
||||
}
|
||||
|
||||
template<bool NON_CONVEX, bool RSMT>
|
||||
void OSRP_generic(netlist const & circuit, detailed_placement & pl){
|
||||
for(index_t r=0; r<pl.row_cnt(); ++r){
|
||||
// Complete optimization on a row, comprising possible obstacles
|
||||
|
||||
std::vector<index_t> cells;
|
||||
std::vector<int> flippability;
|
||||
|
||||
// Get the movable cells, if we can flip them, and the obstacles on the row
|
||||
for(index_t OSRP_cell = pl.get_first_cell_on_row(r); OSRP_cell != null_ind; OSRP_cell = pl.get_next_cell_on_row(OSRP_cell, r)){
|
||||
auto attr = circuit.get_cell(OSRP_cell).attributes;
|
||||
cells.push_back(OSRP_cell);
|
||||
flippability.push_back( (attr & XFlippable) != 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
if(not cells.empty()){
|
||||
std::vector<std::pair<int_t, int_t> > lims = get_cell_ranges(circuit, pl, cells); // Limit positions for each cell
|
||||
|
||||
Hnet_group nets = RSMT ?
|
||||
get_RSMT_netgroup(circuit, pl, cells)
|
||||
: get_B2B_netgroup(circuit, pl, cells);
|
||||
|
||||
std::vector<index_t> no_permutation(cells.size());
|
||||
for(index_t i=0; i<cells.size(); ++i) no_permutation[i] = i;
|
||||
|
||||
std::vector<int_t> final_positions;
|
||||
if(NON_CONVEX){
|
||||
std::vector<int> flipped;
|
||||
optimize_noncvx_sequence(nets, no_permutation, final_positions, flipped, flippability, lims);
|
||||
for(index_t i=0; i<cells.size(); ++i){
|
||||
bool old_orient = pl.plt_.orientations_[cells[i]].x;
|
||||
pl.plt_.orientations_[cells[i]].x = flipped[i] ? not old_orient : old_orient;
|
||||
}
|
||||
}
|
||||
else{
|
||||
optimize_convex_sequence(nets, no_permutation, final_positions, lims);
|
||||
}
|
||||
|
||||
// Update the positions and orientations
|
||||
for(index_t i=0; i<cells.size(); ++i){
|
||||
pl.plt_.positions_[cells[i]].x = final_positions[i];
|
||||
}
|
||||
}
|
||||
} // Iteration on the rows
|
||||
|
||||
pl.selfcheck();
|
||||
}
|
||||
|
||||
template<bool NON_CONVEX, bool RSMT>
|
||||
void swaps_row_generic(netlist const & circuit, detailed_placement & pl, index_t range){
|
||||
assert(range >= 2);
|
||||
|
||||
for(index_t r=0; r<pl.row_cnt(); ++r){
|
||||
index_t OSRP_cell = pl.get_first_cell_on_row(r);
|
||||
|
||||
while(OSRP_cell != null_ind){
|
||||
std::vector<index_t> cells;
|
||||
std::vector<std::pair<int_t, int_t> > lims;
|
||||
std::vector<int> flippables;
|
||||
|
||||
for(index_t nbr_cells=0;
|
||||
OSRP_cell != null_ind
|
||||
and nbr_cells < range;
|
||||
OSRP_cell = pl.get_next_cell_on_row(OSRP_cell, r), ++nbr_cells
|
||||
){
|
||||
cells.push_back(OSRP_cell);
|
||||
flippables.push_back( (circuit.get_cell(OSRP_cell).attributes & XFlippable) != 0);
|
||||
}
|
||||
|
||||
if(not cells.empty()){
|
||||
std::vector<std::pair<int_t, int_t> > lims = get_cell_ranges(circuit, pl, cells); // Limit positions for each cell
|
||||
|
||||
Hnet_group nets = RSMT ?
|
||||
get_RSMT_netgroup(circuit, pl, cells)
|
||||
: get_B2B_netgroup(circuit, pl, cells);
|
||||
|
||||
std::int64_t best_cost = std::numeric_limits<std::int64_t>::max();
|
||||
std::vector<int_t> positions(cells.size());
|
||||
std::vector<int> flippings(cells.size());
|
||||
std::vector<int_t> best_positions(cells.size());
|
||||
std::vector<int> best_flippings(cells.size());
|
||||
|
||||
std::vector<index_t> permutation(cells.size());
|
||||
for(index_t i=0; i<cells.size(); ++i) permutation[i] = i;
|
||||
std::vector<index_t> best_permutation;
|
||||
|
||||
// Check every possible permutation of the cells
|
||||
do{
|
||||
std::int64_t cur_cost = NON_CONVEX ?
|
||||
optimize_noncvx_sequence(nets, permutation, positions, flippings, flippables, lims) :
|
||||
optimize_convex_sequence(nets, permutation, positions, lims);
|
||||
if(cur_cost <= best_cost){
|
||||
best_cost = cur_cost;
|
||||
best_permutation = permutation;
|
||||
best_flippings = flippings;
|
||||
best_positions = positions;
|
||||
}
|
||||
}while(std::next_permutation(permutation.begin(), permutation.end()));
|
||||
|
||||
std::vector<index_t> new_cell_order(cells.size());
|
||||
// Update the positions and the topology
|
||||
for(index_t i=0; i<cells.size(); ++i){
|
||||
index_t r_ind = best_permutation[i]; // In the row from in the Hnet_group
|
||||
new_cell_order[r_ind] = cells[i];
|
||||
pl.plt_.positions_[cells[i]].x = best_positions[r_ind];
|
||||
if(NON_CONVEX){
|
||||
bool old_orient = pl.plt_.orientations_[cells[i]].x;
|
||||
pl.plt_.orientations_[cells[i]].x = best_flippings[r_ind] ? not old_orient : old_orient;
|
||||
}
|
||||
}
|
||||
|
||||
pl.reorder_cells(cells, new_cell_order, r);
|
||||
cells = new_cell_order;
|
||||
|
||||
assert(best_cost < std::numeric_limits<std::int64_t>::max());
|
||||
}
|
||||
|
||||
if(OSRP_cell != null_ind){
|
||||
assert(cells.size() == range);
|
||||
OSRP_cell = cells[range/2];
|
||||
}
|
||||
} // Iteration on the entire row
|
||||
} // Iteration on the rows
|
||||
|
||||
pl.selfcheck();
|
||||
}
|
||||
} // End anonymous namespace
|
||||
|
||||
void OSRP_convex_HPWL(netlist const & circuit, detailed_placement & pl){ OSRP_generic< false, false>(circuit, pl); }
|
||||
void OSRP_convex_RSMT(netlist const & circuit, detailed_placement & pl){ OSRP_generic< false, true >(circuit, pl); }
|
||||
void OSRP_noncvx_HPWL(netlist const & circuit, detailed_placement & pl){ OSRP_generic< true , false>(circuit, pl); }
|
||||
void OSRP_noncvx_RSMT(netlist const & circuit, detailed_placement & pl){ OSRP_generic< true , true >(circuit, pl); }
|
||||
void swaps_row_convex_HPWL(netlist const & circuit, detailed_placement & pl, index_t range){ swaps_row_generic< false, false>(circuit, pl, range); }
|
||||
void swaps_row_convex_RSMT(netlist const & circuit, detailed_placement & pl, index_t range){ swaps_row_generic< false, true >(circuit, pl, range); }
|
||||
void swaps_row_noncvx_HPWL(netlist const & circuit, detailed_placement & pl, index_t range){ swaps_row_generic< true , false>(circuit, pl, range); }
|
||||
void swaps_row_noncvx_RSMT(netlist const & circuit, detailed_placement & pl, index_t range){ swaps_row_generic< true , true >(circuit, pl, range); }
|
||||
|
||||
} // namespace dp
|
||||
} // namespace coloquinte
|
||||
|
||||
|
|
@ -1,384 +0,0 @@
|
|||
|
||||
#include "coloquinte/solvers.hxx"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
namespace coloquinte{
|
||||
namespace gp{
|
||||
|
||||
linear_system linear_system::operator+(linear_system const & o) const{
|
||||
if(o.internal_size() != internal_size()){ throw std::runtime_error("Mismatched system sizes"); }
|
||||
linear_system ret(target_.size() + o.target_.size() - internal_size(), internal_size());
|
||||
|
||||
ret.matrix_ = matrix_;
|
||||
std::vector<matrix_triplet> omatrix = o.matrix_;
|
||||
for(matrix_triplet & t : omatrix){
|
||||
if(t.c_ >= internal_size()){
|
||||
t.c_ += (target_.size() - internal_size());
|
||||
}
|
||||
if(t.r_ >= internal_size()){
|
||||
t.r_ += (target_.size() - internal_size());
|
||||
}
|
||||
}
|
||||
ret.matrix_.insert(ret.matrix_.end(), omatrix.begin(), omatrix.end());
|
||||
|
||||
// ret.target_.resize(target_.size() + o.target_.size() - internal_size);
|
||||
for(index_t i=0; i<internal_size(); ++i){
|
||||
ret.target_[i] = target_[i] + o.target_[i];
|
||||
}
|
||||
for(index_t i=internal_size(); i<target_.size(); ++i){
|
||||
ret.target_[i] = target_[i];
|
||||
}
|
||||
for(index_t i=internal_size(); i<o.target_.size(); ++i){
|
||||
ret.target_[i + target_.size() - internal_size()] = o.target_[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// The classical compressed sparse row storage
|
||||
struct csr_matrix{
|
||||
std::vector<std::uint32_t> row_limits, col_indexes;
|
||||
std::vector<float> values, diag;
|
||||
|
||||
std::vector<float> mul(std::vector<float> const & x) const;
|
||||
std::vector<float> solve_CG(std::vector<float> const & goal, std::vector<float> guess, std::uint32_t min_iter, std::uint32_t max_iter, float tol) const;
|
||||
csr_matrix(std::vector<std::uint32_t> const & row_l, std::vector<std::uint32_t> const & col_i, std::vector<float> const & vals, std::vector<float> const D) : row_limits(row_l), col_indexes(col_i), values(vals), diag(D){
|
||||
assert(values.size() == col_indexes.size());
|
||||
assert(diag.size()+1 == row_limits.size());
|
||||
}
|
||||
};
|
||||
|
||||
// A matrix with successive rows padded to the same length and accessed column-major; hopefully a little better
|
||||
template<std::uint32_t unroll_len>
|
||||
struct ellpack_matrix{
|
||||
std::vector<std::uint32_t> row_limits, col_indexes;
|
||||
std::vector<float> values, diag;
|
||||
|
||||
std::vector<float> mul(std::vector<float> const & x) const;
|
||||
std::vector<float> solve_CG(std::vector<float> goal, std::vector<float> guess, std::uint32_t min_iter, std::uint32_t max_iter, float tol) const;
|
||||
|
||||
ellpack_matrix(std::vector<std::uint32_t> const & row_l, std::vector<std::uint32_t> const & col_i, std::vector<float> const & vals, std::vector<float> const D) : row_limits(row_l), col_indexes(col_i), values(vals), diag(D){
|
||||
assert(values.size() == col_indexes.size());
|
||||
assert(diag.size() % unroll_len == 0);
|
||||
assert((row_limits.size()-1) * unroll_len == diag.size() );
|
||||
assert(row_limits.back() * unroll_len == values.size());
|
||||
assert(values.size() % unroll_len == 0);
|
||||
assert(col_indexes.size() % unroll_len == 0);
|
||||
}
|
||||
};
|
||||
|
||||
// The proxy matrix for compressed sparse storage
|
||||
class doublet_matrix{
|
||||
std::vector<std::uint32_t> row_limits;
|
||||
std::vector<matrix_doublet> doublets;
|
||||
std::uint32_t size;
|
||||
|
||||
void get_compressed(std::vector<std::uint32_t> & limits, std::vector<matrix_doublet> & elements, std::vector<float> & diag) const;
|
||||
public:
|
||||
doublet_matrix(std::vector<matrix_triplet> const & triplets, std::uint32_t size);
|
||||
csr_matrix get_compressed_matrix() const;
|
||||
template<std::uint32_t unroll_len>
|
||||
ellpack_matrix<unroll_len> get_ellpack_matrix() const;
|
||||
};
|
||||
|
||||
doublet_matrix::doublet_matrix(std::vector<matrix_triplet> const & triplets, std::uint32_t n) : size(n){
|
||||
row_limits.resize(size+1, 0);
|
||||
// First store the row sizes in the array
|
||||
for(uint32_t i=0; i<triplets.size(); ++i){
|
||||
++row_limits[triplets[i].r_+1];
|
||||
}
|
||||
|
||||
// The total size of the uncompressed matrix
|
||||
uint32_t tot_triplets=0;
|
||||
// Get the beginning position of each row in the csr matrix
|
||||
for(uint32_t i=1; i<n+1; ++i){
|
||||
uint32_t new_tot_triplets = tot_triplets + row_limits[i];
|
||||
row_limits[i] = tot_triplets; // Stores the beginning of the row
|
||||
tot_triplets = new_tot_triplets;
|
||||
}
|
||||
assert(tot_triplets == triplets.size());
|
||||
|
||||
// Now we know the size and can allocate storage for the indices and values
|
||||
doublets.resize(tot_triplets);
|
||||
|
||||
// We store the triplets in the new storage and tranform beginning positions into end positions
|
||||
for(uint32_t i=0; i<triplets.size(); ++i){
|
||||
doublets[row_limits[triplets[i].r_+1]] = matrix_doublet(triplets[i].c_, triplets[i].val_);
|
||||
++row_limits[triplets[i].r_+1]; // row_limits will hold the end position of the row
|
||||
}
|
||||
}
|
||||
|
||||
void doublet_matrix::get_compressed(std::vector<std::uint32_t> & sizes, std::vector<matrix_doublet> & elements, std::vector<float> & diag) const{
|
||||
assert(size+1 == row_limits.size());
|
||||
sizes.resize(size);
|
||||
diag.resize(size, 0.0);
|
||||
std::vector<matrix_doublet> tmp_doublets = doublets;
|
||||
|
||||
for(uint32_t i=0; i<size; ++i){
|
||||
// Sort the elements in the row
|
||||
std::sort(tmp_doublets.begin() + row_limits[i], tmp_doublets.begin() + row_limits[i+1]);
|
||||
// Compress them and extract the diagonal
|
||||
std::uint32_t l=0;
|
||||
matrix_doublet cur(tmp_doublets[row_limits[i]]);
|
||||
for(uint32_t j=row_limits[i]+1; j<row_limits[i+1]; ++j){
|
||||
if(tmp_doublets[j].c_ == cur.c_){
|
||||
cur.val_ += tmp_doublets[j].val_;
|
||||
}
|
||||
else{
|
||||
if(i != cur.c_){
|
||||
elements.push_back(cur);
|
||||
++l;
|
||||
}
|
||||
else{
|
||||
diag[i] = cur.val_;
|
||||
}
|
||||
cur = tmp_doublets[j];
|
||||
}
|
||||
}
|
||||
if(i != cur.c_){
|
||||
elements.push_back(cur);
|
||||
++l;
|
||||
}
|
||||
else{
|
||||
diag[i] = cur.val_;
|
||||
}
|
||||
sizes[i] = l;
|
||||
}
|
||||
}
|
||||
|
||||
csr_matrix doublet_matrix::get_compressed_matrix() const{
|
||||
std::vector<matrix_doublet> tmp_doublets;
|
||||
std::vector<std::uint32_t> sizes;
|
||||
std::vector<float> diag;
|
||||
get_compressed(sizes, tmp_doublets, diag);
|
||||
|
||||
// Get the limits of each row
|
||||
std::vector<std::uint32_t> new_row_limits(row_limits.size());
|
||||
new_row_limits[0] = 0;
|
||||
for(std::uint32_t i=0; i<size; ++i){
|
||||
new_row_limits[i+1] = new_row_limits[i] + sizes[i];
|
||||
}
|
||||
|
||||
// Store the doublets to the sparse storage
|
||||
std::vector<std::uint32_t> col_indices(tmp_doublets.size());
|
||||
std::vector<float> values(tmp_doublets.size());
|
||||
for(std::uint32_t i=0; i<tmp_doublets.size(); ++i){
|
||||
col_indices[i] = tmp_doublets[i].c_;
|
||||
values[i] = tmp_doublets[i].val_;
|
||||
}
|
||||
|
||||
return csr_matrix(new_row_limits, col_indices, values, diag);
|
||||
}
|
||||
|
||||
template<std::uint32_t unroll_len>
|
||||
ellpack_matrix<unroll_len> doublet_matrix::get_ellpack_matrix() const{
|
||||
std::vector<matrix_doublet> tmp_doublets;
|
||||
std::vector<std::uint32_t> sizes;
|
||||
std::vector<float> diag;
|
||||
get_compressed(sizes, tmp_doublets, diag);
|
||||
|
||||
std::uint32_t unrolled_size = (diag.size() % unroll_len == 0)? diag.size()/unroll_len : diag.size() / unroll_len + 1;
|
||||
sizes.resize(unroll_len * unrolled_size, 0);
|
||||
diag.resize(unroll_len * unrolled_size, 1.0);
|
||||
|
||||
// Store the maximum size of a group of rows
|
||||
std::vector<std::uint32_t> new_row_limits(unrolled_size+1);
|
||||
new_row_limits[0] = 0;
|
||||
for(std::uint32_t i=0; i<unrolled_size; ++i){
|
||||
std::uint32_t max_sz = sizes[unroll_len*i];
|
||||
for(int j=1; j<unroll_len; ++j){
|
||||
max_sz = std::max(max_sz, sizes[unroll_len*i + j]);
|
||||
}
|
||||
new_row_limits[i+1] = new_row_limits[i] + max_sz;
|
||||
}
|
||||
|
||||
std::vector<std::uint32_t> col_indices(unroll_len * new_row_limits.back());
|
||||
std::vector<float> values(unroll_len * new_row_limits.back());
|
||||
|
||||
std::uint32_t d = 0;
|
||||
for(std::uint32_t i=0; i<sizes.size(); ++i){ // For every line
|
||||
std::uint32_t ui = i/unroll_len;
|
||||
std::uint32_t k = i%unroll_len;
|
||||
std::uint32_t max_sz = new_row_limits[ui+1] - new_row_limits[ui];
|
||||
std::uint32_t row_begin = new_row_limits[ui];
|
||||
for(std::uint32_t j=0; j<sizes[i]; ++j, ++d){ // For the non-zero values
|
||||
col_indices[unroll_len * (row_begin+j) + k] = tmp_doublets[d].c_;
|
||||
values[unroll_len * (row_begin+j) + k] = tmp_doublets[d].val_;
|
||||
}
|
||||
for(std::uint32_t j=sizes[i]; j<max_sz; ++j){ // For the padding zeroes
|
||||
col_indices[unroll_len * (row_begin+j) + k] = 0;
|
||||
values[unroll_len * (row_begin+j) + k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ellpack_matrix<unroll_len>(new_row_limits, col_indices, values, diag);
|
||||
}
|
||||
|
||||
std::vector<float> csr_matrix::mul(std::vector<float> const & x) const{
|
||||
std::vector<float> res(x.size());
|
||||
assert(x.size() == diag.size());
|
||||
for(std::uint32_t i=0; i<diag.size(); ++i){
|
||||
res[i] = diag[i] * x[i];
|
||||
for(std::uint32_t j=row_limits[i]; j<row_limits[i+1]; ++j){
|
||||
res[i] += values[j] * x[col_indexes[j]];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
template<std::uint32_t unroll_len>
|
||||
std::vector<float> ellpack_matrix<unroll_len>::mul(std::vector<float> const & x) const{
|
||||
std::vector<float> res(x.size());
|
||||
assert(x.size() % unroll_len == 0);
|
||||
assert(x.size() == diag.size());
|
||||
for(std::uint32_t i=0; i+1<row_limits.size(); ++i){
|
||||
float cur[unroll_len];
|
||||
for(int k=0; k<unroll_len; ++k){
|
||||
cur[k] = diag[unroll_len*i+k] * x[unroll_len*i+k];
|
||||
}
|
||||
for(std::uint32_t j=row_limits[i]; j<row_limits[i+1]; ++j){
|
||||
for(int k=0; k<unroll_len; ++k){
|
||||
cur[k] += values[unroll_len*j+k] * x[col_indexes[unroll_len*j+k]];
|
||||
}
|
||||
}
|
||||
for(int k=0; k<unroll_len; ++k){
|
||||
res[unroll_len*i+k] = cur[k];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
template<std::uint32_t unroll_len>
|
||||
float dot_prod(std::vector<float> const & a, std::vector<float> const & b){
|
||||
assert(a.size() == b.size());
|
||||
float vals[unroll_len];
|
||||
for(int j=0; j<unroll_len; ++j) vals[j] = 0.0;
|
||||
for(std::uint32_t i=0; i<a.size() / unroll_len; ++i){
|
||||
for(int j=0; j<unroll_len; ++j){
|
||||
vals[j] += a[unroll_len*i + j] * b[unroll_len*i + j];
|
||||
}
|
||||
}
|
||||
float res = 0.0;
|
||||
for(int j=0; j<unroll_len; ++j) res += vals[j];
|
||||
for(int i = unroll_len*(a.size() / unroll_len); i< a.size(); ++i){
|
||||
res += a[i] * b[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<float> csr_matrix::solve_CG(std::vector<float> const & goal, std::vector<float> x, std::uint32_t min_iter, std::uint32_t max_iter, float tol_ratio) const{
|
||||
std::uint32_t n = diag.size();
|
||||
assert(goal.size() == n);
|
||||
assert(x.size() == n);
|
||||
std::vector<float> r, p(n), z(n), mul_res, preconditioner(n);
|
||||
r = mul(x);
|
||||
for(uint32_t i=0; i<n; ++i){
|
||||
r[i] = goal[i] - r[i];
|
||||
preconditioner[i] = 1.0/diag[i];
|
||||
assert(std::isfinite(preconditioner[i]));
|
||||
z[i] = preconditioner[i] * r[i];
|
||||
p[i] = z[i];
|
||||
}
|
||||
|
||||
float cross_norm = dot_prod<16>(r, z);
|
||||
assert(std::isfinite(cross_norm));
|
||||
float_t const epsilon = std::numeric_limits<float_t>::min();
|
||||
|
||||
float start_norm = cross_norm;
|
||||
for(uint32_t k=0; k < max_iter; ++k){
|
||||
mul_res = mul(p);
|
||||
|
||||
float_t pr_prod = dot_prod<16>(p, mul_res);
|
||||
float_t alpha = cross_norm / pr_prod;
|
||||
|
||||
if(
|
||||
not std::isfinite(cross_norm) or not std::isfinite(alpha) or not std::isfinite(pr_prod)
|
||||
or cross_norm <= epsilon or alpha <= epsilon or pr_prod <= epsilon
|
||||
){
|
||||
break;
|
||||
}
|
||||
|
||||
// Update the result
|
||||
for(uint32_t i=0; i<n; ++i){
|
||||
x[i] = x[i] + alpha * p[i];
|
||||
r[i] = r[i] - alpha * mul_res[i];
|
||||
z[i] = preconditioner[i] * r[i];
|
||||
}
|
||||
float new_cross_norm = dot_prod<16>(r, z);
|
||||
|
||||
// Update the scaled residual and the search direction
|
||||
if(k >= min_iter && new_cross_norm <= tol_ratio * start_norm){
|
||||
break;
|
||||
}
|
||||
float beta = new_cross_norm / cross_norm;
|
||||
cross_norm = new_cross_norm;
|
||||
for(uint32_t i=0; i<n; ++i)
|
||||
p[i] = z[i] + beta * p[i];
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
template<std::uint32_t unroll_len>
|
||||
std::vector<float> ellpack_matrix<unroll_len>::solve_CG(std::vector<float> goal, std::vector<float> x, std::uint32_t min_iter, std::uint32_t max_iter, float tol_ratio) const{
|
||||
std::uint32_t n = diag.size();
|
||||
std::uint32_t old_n = x.size();
|
||||
assert(goal.size() == x.size());
|
||||
x.resize(diag.size(), 0.0);
|
||||
goal.resize(diag.size(), 0.0);
|
||||
|
||||
std::vector<float> r, p(n), z(n), mul_res, preconditioner(n);
|
||||
r = mul(x);
|
||||
for(uint32_t i=0; i<n; ++i){
|
||||
r[i] = goal[i] - r[i];
|
||||
preconditioner[i] = 1.0/diag[i];
|
||||
z[i] = preconditioner[i] * r[i];
|
||||
p[i] = z[i];
|
||||
}
|
||||
|
||||
float cross_norm = dot_prod<unroll_len>(r, z);
|
||||
float start_norm = cross_norm;
|
||||
for(uint32_t k=0; k < max_iter; ++k){
|
||||
mul_res = mul(p);
|
||||
float alpha = cross_norm / dot_prod<unroll_len>(p, mul_res);
|
||||
// Update the result
|
||||
for(uint32_t i=0; i<n; ++i){
|
||||
x[i] = x[i] + alpha * p[i];
|
||||
r[i] = r[i] - alpha * mul_res[i];
|
||||
z[i] = preconditioner[i] * r[i];
|
||||
}
|
||||
float new_cross_norm = dot_prod<unroll_len>(r, z);
|
||||
|
||||
// Update the scaled residual and the search direction
|
||||
if(k >= min_iter && new_cross_norm <= tol_ratio * start_norm){
|
||||
break;
|
||||
}
|
||||
float beta = new_cross_norm / cross_norm;
|
||||
cross_norm = new_cross_norm;
|
||||
for(uint32_t i=0; i<n; ++i)
|
||||
p[i] = z[i] + beta * p[i];
|
||||
}
|
||||
x.resize(old_n);
|
||||
return x;
|
||||
}
|
||||
|
||||
std::vector<float_t> linear_system::solve_CG(std::vector<float_t> guess, index_t nbr_iter){
|
||||
doublet_matrix tmp(matrix_, size());
|
||||
csr_matrix mat = tmp.get_compressed_matrix();
|
||||
//ellpack_matrix<16> mat = tmp.get_ellpack_matrix<16>();
|
||||
guess.resize(target_.size(), 0.0);
|
||||
auto ret = mat.solve_CG(target_, guess, nbr_iter, nbr_iter, 0.0);
|
||||
ret.resize(internal_size());
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,536 +0,0 @@
|
|||
|
||||
#include "coloquinte/topologies.hxx"
|
||||
#include "coloquinte/circuit_helper.hxx"
|
||||
#include "coloquinte/union_find.hxx"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <set>
|
||||
#include <functional>
|
||||
#include <cmath>
|
||||
#include <array>
|
||||
#include <limits>
|
||||
|
||||
namespace coloquinte{
|
||||
using edge_t = std::pair<index_t, index_t>;
|
||||
|
||||
namespace{
|
||||
struct minmax_t{
|
||||
int_t min, max;
|
||||
|
||||
minmax_t(int_t mn, int_t mx) : min(mn), max(mx) {}
|
||||
minmax_t() {}
|
||||
void merge(minmax_t const o){
|
||||
min = std::min(o.max, min);
|
||||
max = std::max(o.min, max);
|
||||
}
|
||||
void merge(int_t const p){
|
||||
min = std::min(p, min);
|
||||
max = std::max(p, max);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace steiner_lookup{
|
||||
|
||||
template<int pin_cnt>
|
||||
int_t Hconnectivity<pin_cnt>::get_wirelength(std::array<point<int_t>, pin_cnt> const sorted_points) const{
|
||||
std::array<minmax_t, pin_cnt-2> minmaxs;
|
||||
for(index_t i=0; i<pin_cnt-2; ++i){
|
||||
minmaxs[i] = minmax_t(sorted_points[i+1].y, sorted_points[i+1].y);
|
||||
}
|
||||
std::uint8_t b_con = extremes & 15u, e_con = extremes >> 4;
|
||||
minmaxs[b_con].merge(sorted_points.front() .y);
|
||||
minmaxs[e_con].merge(sorted_points.back() .y);
|
||||
for(std::uint8_t const E : connexions){
|
||||
minmaxs[(E >> 4)].merge(minmaxs[(E & 15u)]);
|
||||
}
|
||||
int_t cost = sorted_points.back().x - sorted_points.front().x + sorted_points[b_con+1].x - sorted_points[e_con+1].x;
|
||||
for(std::uint8_t const E : connexions){
|
||||
cost += std::abs((float)(sorted_points[(E >> 4) +1].x - sorted_points[(E & 15u) +1].x));
|
||||
}
|
||||
for(index_t i=0; i<pin_cnt-2; ++i){
|
||||
cost += (minmaxs[i].max - minmaxs[i].min);
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
template<int pin_cnt>
|
||||
std::array<edge_t, pin_cnt-1> Hconnectivity<pin_cnt>::get_x_topology(std::array<point<int_t>, pin_cnt> const sorted_points) const{
|
||||
std::array<edge_t, pin_cnt-1> ret;
|
||||
std::uint8_t b_con = extremes & 15u, e_con = extremes >> 4;
|
||||
ret[0] = edge_t(0, b_con+1);
|
||||
ret[1] = edge_t(pin_cnt-1, e_con+1);
|
||||
for(index_t i=0; i<pin_cnt-3; ++i){
|
||||
std::uint8_t E = connexions[i];
|
||||
ret[i+2] = edge_t((E & 15u) +1, (E >> 4) +1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
} // End namespace steiner_lookup
|
||||
|
||||
namespace {
|
||||
|
||||
template<int n, int array_size>
|
||||
int_t get_wirelength_from_sorted(std::vector<point<int_t> > const & pins, std::array<steiner_lookup::Hconnectivity<n>, array_size> const & lookups){
|
||||
std::array<point<int_t>, n> points;
|
||||
std::copy_n(pins.begin(), n, points.begin());
|
||||
|
||||
int_t cost = std::numeric_limits<int_t>::max();
|
||||
for(auto const L : lookups){
|
||||
cost = std::min(cost, L.get_wirelength(points));
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
std::int64_t get_wirelength_from_topo(std::vector<point<int_t> > const & points, std::vector<std::pair<index_t, index_t> > Htopo){
|
||||
std::vector<minmax_t> minmaxs(points.size());
|
||||
for(index_t i=0; i<points.size(); ++i){
|
||||
minmaxs[i] = minmax_t(points[i].y, points[i].y);
|
||||
}
|
||||
for(auto const E : Htopo){
|
||||
minmaxs[E.second].merge(minmaxs[E.first]);
|
||||
}
|
||||
std::int64_t cost = 0;
|
||||
for(edge_t const E : Htopo){
|
||||
cost += std::abs((float)(points[E.first].x - points[E.second].x));
|
||||
}
|
||||
for(index_t i=0; i<points.size(); ++i){
|
||||
cost += (minmaxs[i].max - minmaxs[i].min);
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
struct indexed_pt : point<int_t>{
|
||||
index_t index;
|
||||
indexed_pt(point<int_t> pt, index_t pos) : point<int_t>(pt), index(pos) {}
|
||||
indexed_pt(){}
|
||||
};
|
||||
|
||||
template<int n, int array_size>
|
||||
std::vector<std::pair<index_t, index_t> > get_topology_from_sorted(std::vector<point<int_t> > const & pins, std::array<steiner_lookup::Hconnectivity<n>, array_size> const & lookups){
|
||||
std::array<point<int_t>, n> points;
|
||||
std::copy_n(pins.begin(), n, points.begin());
|
||||
|
||||
// Find the horizontal topology with the smallest cost
|
||||
int_t cost = std::numeric_limits<int_t>::max();
|
||||
index_t ind = std::numeric_limits<index_t>::max();
|
||||
for(index_t i=0; i<array_size; ++i){
|
||||
int_t this_cost = lookups[i].get_wirelength(points);
|
||||
if(this_cost < cost){
|
||||
cost = this_cost;
|
||||
ind = i;
|
||||
}
|
||||
}
|
||||
assert(ind != std::numeric_limits<index_t>::max());
|
||||
auto ret = lookups[ind].get_x_topology(points);
|
||||
return std::vector<std::pair<index_t, index_t> >(ret.begin(), ret.end());
|
||||
}
|
||||
|
||||
std::vector<edge_t> get_vertical_topology(std::vector<point<int_t> > pins, std::vector<edge_t> const & Htopo){
|
||||
index_t const null_ind = std::numeric_limits<index_t>::max();
|
||||
|
||||
std::vector<indexed_pt> ipoints(pins.size());
|
||||
for(index_t i=0; i<pins.size(); ++i){
|
||||
ipoints[i] = indexed_pt(pins[i], i);
|
||||
}
|
||||
|
||||
std::sort(ipoints.begin(), ipoints.end(), [](indexed_pt a , indexed_pt b){return a.y < b.y; });
|
||||
|
||||
// First pin with y ordering
|
||||
std::vector<index_t> min_y_pin(pins.size());
|
||||
for(index_t i=0; i<ipoints.size(); ++i){
|
||||
min_y_pin[ipoints[i].index] = i;
|
||||
}
|
||||
std::vector<index_t> max_y_pin = min_y_pin;
|
||||
|
||||
|
||||
std::vector<index_t> nxt_y_pin(pins.size(), null_ind);
|
||||
std::vector<edge_t> ret;
|
||||
for(auto const E : Htopo){
|
||||
// Assuming a correctly ordered horizontal topology where the first node of the edge is never visited again
|
||||
index_t f=E.first, s=E.second;
|
||||
index_t first_yf=min_y_pin[f], first_ys=min_y_pin[s];
|
||||
|
||||
// Push the edges from the first and insert one of its elements in the second's linked structure
|
||||
if(max_y_pin[f] < min_y_pin[s] or max_y_pin[s] < min_y_pin[f]){
|
||||
for(index_t yf=first_yf; nxt_y_pin[yf] != null_ind; yf = nxt_y_pin[yf]){
|
||||
ret.push_back(edge_t(yf, nxt_y_pin[yf]));
|
||||
}
|
||||
|
||||
if(max_y_pin[f] < min_y_pin[s]){
|
||||
nxt_y_pin[max_y_pin[f]] = min_y_pin[s];
|
||||
min_y_pin[s] = max_y_pin[f];
|
||||
}
|
||||
else if(max_y_pin[s] < min_y_pin[f]){
|
||||
nxt_y_pin[max_y_pin[s]] = min_y_pin[f];
|
||||
max_y_pin[s] = min_y_pin[f];
|
||||
nxt_y_pin[min_y_pin[f]] = null_ind;
|
||||
}
|
||||
else{
|
||||
abort();
|
||||
}
|
||||
}
|
||||
else{ // Need to chose a pin with two connexions because there will be no L route
|
||||
// One pin from the second is in the middle of the first
|
||||
if(max_y_pin[f] > max_y_pin[s]){
|
||||
index_t middle_pin = max_y_pin[s];
|
||||
index_t yf=first_yf;
|
||||
// Make the first connexions
|
||||
for(; nxt_y_pin[yf] < middle_pin; yf = nxt_y_pin[yf]){
|
||||
ret.push_back(edge_t(yf, nxt_y_pin[yf]));
|
||||
}
|
||||
// Make the two connexions with the new pin
|
||||
ret.push_back(edge_t(yf, middle_pin));
|
||||
yf = nxt_y_pin[yf];
|
||||
ret.push_back(edge_t(yf, middle_pin));
|
||||
// Finish the connexions
|
||||
for(; nxt_y_pin[yf] != null_ind; yf = nxt_y_pin[yf]){
|
||||
ret.push_back(edge_t(yf, nxt_y_pin[yf]));
|
||||
}
|
||||
}
|
||||
// One pin from the first is in the middle of the second
|
||||
else{
|
||||
for(index_t yf=first_yf; nxt_y_pin[yf] != null_ind; yf = nxt_y_pin[yf]){
|
||||
ret.push_back(edge_t(yf, nxt_y_pin[yf]));
|
||||
}
|
||||
index_t middle_pin = max_y_pin[f];
|
||||
// Find the place where we can insert this pin
|
||||
index_t ys=first_ys;
|
||||
for(; nxt_y_pin[ys] < middle_pin; ys = nxt_y_pin[ys]);
|
||||
nxt_y_pin[middle_pin] = nxt_y_pin[ys];
|
||||
nxt_y_pin[ys] = middle_pin;
|
||||
}
|
||||
}
|
||||
}
|
||||
// The last visited gives the remaining connexions to push
|
||||
for(index_t yf=min_y_pin[Htopo.back().second]; nxt_y_pin[yf] != null_ind; yf = nxt_y_pin[yf]){
|
||||
ret.push_back(edge_t(yf, nxt_y_pin[yf]));
|
||||
}
|
||||
|
||||
// Back to the original ordering
|
||||
for(auto & E : ret){
|
||||
E.first = ipoints[E.first].index;
|
||||
E.second = ipoints[E.second].index;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline void northeast_octant_neighbours(std::vector<point<int_t> > pins, std::vector<std::pair<index_t, index_t> > & edges){
|
||||
|
||||
std::vector<indexed_pt> point_list;
|
||||
for(index_t i=0; i<pins.size(); ++i){
|
||||
point_list.push_back(indexed_pt(pins[i], i));
|
||||
}
|
||||
|
||||
std::sort(point_list.begin(), point_list.end(),
|
||||
[](indexed_pt const a, indexed_pt const b){ return a.x + a.y < b.x + b.y; }
|
||||
);
|
||||
|
||||
// Decreasing order of x and y; multiset not necessary because no two elements have same coordinate
|
||||
std::set<indexed_pt, std::function<bool (indexed_pt const, indexed_pt const)> >
|
||||
active_upper_octant([](indexed_pt const a, indexed_pt const b)->bool{return a.x > b.x;}),
|
||||
active_lower_octant([](indexed_pt const a, indexed_pt const b)->bool{return a.y > b.y;});
|
||||
|
||||
for(indexed_pt const current : point_list){
|
||||
{ // North to north-east region
|
||||
auto first_it = active_upper_octant.lower_bound(current); // Largest x with x <= current.x
|
||||
auto it = first_it;
|
||||
for(; it != active_upper_octant.end() && it->x - it->y >= current.x - current.y; ++it){
|
||||
edges.push_back(std::pair<index_t, index_t>(current.index, it->index));
|
||||
}
|
||||
if(first_it != active_upper_octant.end()){ active_upper_octant.erase(first_it, it); }
|
||||
active_upper_octant.insert(it, current); // Hint to insert the element since it is the correct position
|
||||
} // End region
|
||||
{ // North-east to east region
|
||||
auto first_it = active_lower_octant.lower_bound(current); // Largest y with y <= current.y
|
||||
auto it = first_it;
|
||||
for(; it != active_lower_octant.end() && it->y - it->x >= current.y - current.x; ++it){
|
||||
edges.push_back(std::pair<index_t, index_t>(current.index, it->index));
|
||||
}
|
||||
if(first_it != active_lower_octant.end()){ active_lower_octant.erase(first_it, it); }
|
||||
active_lower_octant.insert(it, current); // Hint to insert the element since it is the correct position
|
||||
} // End region
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the nearest octant neighbour for each point in the south-east quadrant
|
||||
inline void southeast_octant_neighbours(std::vector<point<int_t> > pins, std::vector<std::pair<index_t, index_t> > & edges){
|
||||
for(auto & pin : pins){
|
||||
pin.y = - pin.y;
|
||||
}
|
||||
northeast_octant_neighbours(pins, edges);
|
||||
}
|
||||
|
||||
std::vector<std::pair<index_t, index_t> > get_small_horizontal_topology_from_sorted(std::vector<point<int_t> > const & pins){
|
||||
assert(pins.size() <= 10);
|
||||
|
||||
switch(pins.size()){
|
||||
case 2:
|
||||
return std::vector<edge_t>(1, edge_t(0, 1));
|
||||
case 3:
|
||||
return std::vector<edge_t>{{0, 1}, {1, 2}};
|
||||
case 4:
|
||||
return get_topology_from_sorted<4, 2>(pins, steiner_lookup::topologies_4);
|
||||
case 5:
|
||||
return get_topology_from_sorted<5, 6>(pins, steiner_lookup::topologies_5);
|
||||
case 6:
|
||||
return get_topology_from_sorted<6, 23>(pins, steiner_lookup::topologies_6);
|
||||
case 7:
|
||||
return get_topology_from_sorted<7, 111>(pins, steiner_lookup::topologies_7);
|
||||
case 8:
|
||||
return get_topology_from_sorted<8, 642>(pins, steiner_lookup::topologies_8);
|
||||
case 9:
|
||||
return get_topology_from_sorted<9, 4334>(pins, steiner_lookup::topologies_9);
|
||||
case 10:
|
||||
return get_topology_from_sorted<10, 33510>(pins, steiner_lookup::topologies_10);
|
||||
default: // Only 1 and 0 left (11 and more are protected by an assertion)
|
||||
return std::vector<edge_t>();
|
||||
}
|
||||
}
|
||||
|
||||
// Get an ordering of the edges that is compatible with the processing functions
|
||||
std::vector<edge_t> get_tree_topo_sort(std::vector<edge_t> const & topo){
|
||||
std::vector<edge_t> sorted_topo;
|
||||
std::vector<std::vector<index_t> > neighbours(topo.size()+1);
|
||||
for(edge_t const E : topo){
|
||||
neighbours[E.first].push_back(E.second);
|
||||
neighbours[E.second].push_back(E.first);
|
||||
}
|
||||
std::vector<index_t> to_visit;
|
||||
std::vector<int_t> nbr_unvisited(topo.size()+1);
|
||||
for(index_t i=0; i<=topo.size(); ++i){
|
||||
nbr_unvisited[i] = neighbours[i].size();
|
||||
assert(topo.size() == 0 or nbr_unvisited[i] >= 1);
|
||||
if(nbr_unvisited[i] == 1)
|
||||
to_visit.push_back(i);
|
||||
}
|
||||
std::vector<int> visited(topo.size()+1, 0);
|
||||
while(not to_visit.empty()){
|
||||
index_t f = to_visit.back();
|
||||
assert(visited[f] == 0);
|
||||
visited[f] = 1;
|
||||
to_visit.pop_back();
|
||||
for(index_t s : neighbours[f]){
|
||||
--nbr_unvisited[s];
|
||||
if(visited[s] == 0){ // It is not a node we already visited
|
||||
sorted_topo.push_back(edge_t(f, s));
|
||||
}
|
||||
if(nbr_unvisited[s] == 1){
|
||||
to_visit.push_back(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(sorted_topo.size() == topo.size());
|
||||
return sorted_topo;
|
||||
}
|
||||
|
||||
std::vector<edge_t> get_big_horizontal_topology_from_sorted(std::vector<point<int_t> > const & pins, index_t exactitude_limit){
|
||||
auto spanning = get_MST_topology(pins);
|
||||
|
||||
// TODO: perform local optimizations on the topology using exact Steiner tree algorithms
|
||||
|
||||
// Remove horizontal suboptimalities i.e. when the connexions to the left and right are unbalanced
|
||||
// Reuse existing code by translation to vertical topology
|
||||
auto first_Htopo = get_tree_topo_sort(spanning);
|
||||
auto Vtopo = get_vertical_topology(pins, first_Htopo);
|
||||
Vtopo = get_tree_topo_sort(Vtopo);
|
||||
|
||||
std::vector<point<int_t> > inverted_coords = pins;
|
||||
for(point<int_t> & pt : inverted_coords){
|
||||
std::swap(pt.x, pt.y);
|
||||
}
|
||||
auto Htopo = get_vertical_topology(inverted_coords, Vtopo);
|
||||
|
||||
// Sort the tree so that it is usable when building an RSMT
|
||||
return get_tree_topo_sort(Htopo);
|
||||
}
|
||||
} // End anonymous namespace
|
||||
|
||||
std::vector<edge_t> get_RSMT_horizontal_topology(std::vector<point<int_t> > const & pins, index_t exactitude_limit){
|
||||
if(pins.size() <= 1)
|
||||
return std::vector<edge_t>();
|
||||
else if(pins.size() == 2)
|
||||
return std::vector<edge_t>(1, edge_t(0, 1));
|
||||
else if(pins.size() == 3){
|
||||
std::vector<indexed_pt> ipoints(pins.size());
|
||||
for(index_t i=0; i<pins.size(); ++i){
|
||||
ipoints[i] = indexed_pt(pins[i], i);
|
||||
}
|
||||
auto xpoints=ipoints;
|
||||
std::sort(xpoints.begin(), xpoints.end(), [](indexed_pt a , indexed_pt b){return a.x < b.x; });
|
||||
|
||||
return std::vector<edge_t>{{xpoints[0].index, xpoints[1].index}, {xpoints[1].index, xpoints[2].index}};
|
||||
}
|
||||
else{
|
||||
std::vector<edge_t> horizontal_topology;
|
||||
|
||||
// Sort the pins by x coordinate
|
||||
std::vector<indexed_pt> ipoints(pins.size());
|
||||
for(index_t i=0; i<pins.size(); ++i){
|
||||
ipoints[i] = indexed_pt(pins[i], i);
|
||||
}
|
||||
std::sort(ipoints.begin(), ipoints.end(), [](indexed_pt a , indexed_pt b){return a.x < b.x; });
|
||||
std::vector<point<int_t> > sorted_pins(pins.size());
|
||||
for(index_t i=0; i<pins.size(); ++i){
|
||||
sorted_pins[i] = ipoints[i];
|
||||
}
|
||||
|
||||
// Get the topology for this ordering
|
||||
if(pins.size() <= exactitude_limit){
|
||||
horizontal_topology = get_small_horizontal_topology_from_sorted(sorted_pins);
|
||||
}
|
||||
else{
|
||||
horizontal_topology = get_big_horizontal_topology_from_sorted(sorted_pins, exactitude_limit);
|
||||
}
|
||||
|
||||
// Back to the original ordering
|
||||
for(auto & E : horizontal_topology){
|
||||
E.first = ipoints[E.first].index;
|
||||
E.second = ipoints[E.second].index;
|
||||
}
|
||||
|
||||
return horizontal_topology;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<index_t, index_t> > get_MST_topology(std::vector<point<int_t> > const & pins){
|
||||
|
||||
std::vector<edge_t> edges;
|
||||
|
||||
if(pins.size() <= 2){
|
||||
if(pins.size() == 2){
|
||||
edges.push_back(edge_t(0, 1));
|
||||
}
|
||||
if(pins.size() == 3){
|
||||
auto D = [](point<int_t> a, point<int_t> b){ return (int_t)(std::abs((float)(a.x - b.x)) + std::abs((float)(a.y - b.y))); };
|
||||
auto dists = std::array<int_t, 3>({{D(pins[1], pins[2]), D(pins[1], pins[2]), D(pins[0], pins[1])}});
|
||||
index_t mx = std::max_element(dists.begin(), dists.end()) - dists.begin();
|
||||
for(index_t i=0; i<3; ++i){
|
||||
if(i != mx)
|
||||
edges.push_back(edge_t((i+1) % 3, (i+2) % 3));
|
||||
}
|
||||
}
|
||||
return edges;
|
||||
}
|
||||
|
||||
northeast_octant_neighbours(pins, edges);
|
||||
southeast_octant_neighbours(pins, edges);
|
||||
|
||||
std::vector<edge_t> returned_edges;
|
||||
|
||||
auto edge_length = [&](edge_t E){
|
||||
point<int_t> p1 = pins[E.first],
|
||||
p2 = pins[E.second];
|
||||
return std::abs((float)(p1.x - p2.x)) + std::abs((float)(p1.y - p2.y));
|
||||
};
|
||||
// Perform Kruskal to get the tree
|
||||
std::sort(edges.begin(), edges.end(), [&](edge_t a, edge_t b){ return edge_length(a) < edge_length(b); });
|
||||
|
||||
union_find merger(pins.size());
|
||||
|
||||
for(index_t i=0; i<edges.size() && returned_edges.size()+1 < pins.size(); ++i){
|
||||
edge_t E = edges[i];
|
||||
if(merger.find(E.first) != merger.find(E.second)){
|
||||
merger.merge(E.first, E.second);
|
||||
assert(merger.find(E.first) == merger.find(E.second));
|
||||
returned_edges.push_back(E);
|
||||
}
|
||||
}
|
||||
assert(returned_edges.size() + 1 == pins.size());
|
||||
assert(merger.is_connex());
|
||||
return returned_edges;
|
||||
}
|
||||
|
||||
std::int64_t MST_length(std::vector<point<int_t> > const & pins){
|
||||
auto edges = get_MST_topology(pins);
|
||||
std::int64_t sum = 0;
|
||||
for(auto E : edges){
|
||||
sum += std::abs((float)(pins[E.first].x - pins[E.second].x));
|
||||
sum += std::abs((float)(pins[E.first].y - pins[E.second].y));
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
std::int64_t RSMT_length(std::vector<point<int_t> > const & pins, index_t exactitude_limit){
|
||||
assert(exactitude_limit <= 10 and exactitude_limit >= 3);
|
||||
if(pins.size() <= 3){
|
||||
if(pins.size() == 2){
|
||||
return std::abs((float)(pins[0].x - pins[1].x)) + std::abs((float)(pins[0].y - pins[1].y));
|
||||
}
|
||||
else if(pins.size() == 3){
|
||||
auto minmaxX = std::minmax_element(pins.begin(), pins.end(), [](point<int_t> a, point<int_t> b){ return a.x < b.x; }),
|
||||
minmaxY = std::minmax_element(pins.begin(), pins.end(), [](point<int_t> a, point<int_t> b){ return a.y < b.y; });
|
||||
return (minmaxX.second->x - minmaxX.first->x) + (minmaxY.second->y - minmaxY.first->y);
|
||||
}
|
||||
else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else{
|
||||
std::vector<point<int_t> > points = pins;
|
||||
std::sort(points.begin(), points.end(), [](point<int_t> a , point<int_t> b){return a.x < b.x; });
|
||||
|
||||
if(points.size() <= exactitude_limit){
|
||||
switch(points.size()){
|
||||
case 4:
|
||||
return get_wirelength_from_sorted<4, 2>(points, steiner_lookup::topologies_4);
|
||||
case 5:
|
||||
return get_wirelength_from_sorted<5, 6>(points, steiner_lookup::topologies_5);
|
||||
case 6:
|
||||
return get_wirelength_from_sorted<6, 23>(points, steiner_lookup::topologies_6);
|
||||
case 7:
|
||||
return get_wirelength_from_sorted<7, 111>(points, steiner_lookup::topologies_7);
|
||||
case 8:
|
||||
return get_wirelength_from_sorted<8, 642>(points, steiner_lookup::topologies_8);
|
||||
case 9:
|
||||
return get_wirelength_from_sorted<9, 4334>(points, steiner_lookup::topologies_9);
|
||||
case 10:
|
||||
return get_wirelength_from_sorted<10, 33510>(points, steiner_lookup::topologies_10);
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
else{ // Need to create the full topology, then calculate the length back
|
||||
//return MST_length(points);
|
||||
auto horizontal_topology = get_big_horizontal_topology_from_sorted(points, exactitude_limit);
|
||||
return get_wirelength_from_topo(points, horizontal_topology);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
point<std::vector<std::pair<index_t, index_t> > > get_RSMT_topology(std::vector<point<int_t> > const & pins, index_t exactitude_limit){
|
||||
|
||||
assert(exactitude_limit <= 10 and exactitude_limit >= 3);
|
||||
|
||||
// For 3 pin and fewer, the topology is very simple
|
||||
if(pins.size() <= 2){
|
||||
if(pins.size() == 2){
|
||||
auto ret = std::vector<edge_t>(1, edge_t(0, 1));
|
||||
return point<std::vector<edge_t> >(ret, ret);
|
||||
}
|
||||
else{
|
||||
return point<std::vector<edge_t> >();
|
||||
}
|
||||
}
|
||||
else if(pins.size() == 3){
|
||||
std::vector<indexed_pt> ipoints(pins.size());
|
||||
for(index_t i=0; i<pins.size(); ++i){
|
||||
ipoints[i] = indexed_pt(pins[i], i);
|
||||
}
|
||||
auto xpoints=ipoints;
|
||||
std::sort(xpoints.begin(), xpoints.end(), [](indexed_pt a , indexed_pt b){return a.x < b.x; });
|
||||
auto ypoints=ipoints;
|
||||
std::sort(ypoints.begin(), ypoints.end(), [](indexed_pt a , indexed_pt b){return a.y < b.y; });
|
||||
|
||||
return point<std::vector<edge_t> >{{{xpoints[0].index, xpoints[1].index}, {xpoints[1].index, xpoints[2].index}}, {{ypoints[0].index, ypoints[1].index}, {ypoints[1].index, ypoints[2].index}}};
|
||||
}
|
||||
else{
|
||||
std::vector<edge_t> horizontal_topology = get_RSMT_horizontal_topology(pins, exactitude_limit);
|
||||
return point<std::vector<edge_t> >(horizontal_topology, get_vertical_topology(pins, horizontal_topology));
|
||||
}
|
||||
}
|
||||
|
||||
} // Namespace coloquinte
|
||||
|
|
@ -19,36 +19,36 @@ import coriolis.Cfg as Cfg
|
|||
param = Cfg.getParamDouble( 'etesian.aspectRatio' )
|
||||
param.setDouble( 1.0 )
|
||||
|
||||
Cfg.getParamDouble ( 'etesian.spaceMargin' ).setPercentage( 0.05 )
|
||||
Cfg.getParamBool ( 'etesian.uniformDensity' ).setBool ( False )
|
||||
Cfg.getParamBool ( 'etesian.routingDriven' ).setBool ( False )
|
||||
Cfg.getParamString ( 'etesian.feedNames' ).setString ( 'tie_x0,rowend_x0' )
|
||||
Cfg.getParamString ( 'etesian.cell.zero' ).setString ( 'zero_x0' )
|
||||
Cfg.getParamString ( 'etesian.cell.one' ).setString ( 'one_x0' )
|
||||
Cfg.getParamString ( 'etesian.bloat' ).setString ( 'disabled' )
|
||||
Cfg.getParamDouble ( 'etesian.spaceMargin' ).setPercentage( 0.05 )
|
||||
Cfg.getParamDouble ( 'etesian.densityVariation' ).setPercentage( 0.05 )
|
||||
Cfg.getParamBool ( 'etesian.routingDriven' ).setBool ( False )
|
||||
Cfg.getParamString ( 'etesian.feedNames' ).setString ( 'tie_x0,rowend_x0' )
|
||||
Cfg.getParamString ( 'etesian.cell.zero' ).setString ( 'zero_x0' )
|
||||
Cfg.getParamString ( 'etesian.cell.one' ).setString ( 'one_x0' )
|
||||
Cfg.getParamString ( 'etesian.bloat' ).setString ( 'disabled' )
|
||||
|
||||
param = Cfg.getParamEnumerate( 'etesian.effort' )
|
||||
param.setInt( 2 )
|
||||
param.addValue( 'Fast' , 1 )
|
||||
param.addValue( 'Standard', 2 )
|
||||
param.addValue( 'High' , 3 )
|
||||
param.addValue( 'Extreme' , 4 )
|
||||
param.addValue( 'Standard', 3 )
|
||||
param.addValue( 'High' , 6 )
|
||||
param.addValue( 'Extreme' , 9 )
|
||||
|
||||
param = Cfg.getParamEnumerate( 'etesian.graphics' )
|
||||
param.setInt( 2 )
|
||||
param.setInt( 3 )
|
||||
param.addValue( 'Show every step' , 1 )
|
||||
param.addValue( 'Show lower bound', 2 )
|
||||
param.addValue( 'Show result only', 3 )
|
||||
|
||||
layout = Cfg.Configuration.get().getLayout()
|
||||
layout.addTab ( 'Etesian', 'etesian' )
|
||||
layout.addTitle ( 'Etesian', 'Placement area' )
|
||||
layout.addParameter( 'Etesian', 'etesian.aspectRatio' , 'Aspect Ratio, X/Y (%)', 0 )
|
||||
layout.addParameter( 'Etesian', 'etesian.spaceMargin' , 'Space Margin' , 1 )
|
||||
layout.addRule ( 'Etesian' )
|
||||
layout.addTitle ( 'Etesian', 'Etesian - Placer')
|
||||
layout.addParameter( 'Etesian', 'etesian.uniformDensity', 'Uniform density' , 0 )
|
||||
layout.addParameter( 'Etesian', 'etesian.routingDriven' , 'Routing driven' , 0 )
|
||||
layout.addParameter( 'Etesian', 'etesian.effort' , 'Placement effort' , 1 )
|
||||
layout.addParameter( 'Etesian', 'etesian.graphics' , 'Placement view' , 1 )
|
||||
layout.addRule ( 'Etesian' )
|
||||
layout.addTab ( 'Placer', 'etesian' )
|
||||
layout.addTitle ( 'Placer', 'Placement area' )
|
||||
layout.addParameter( 'Placer', 'etesian.aspectRatio' , 'Aspect Ratio, X/Y' , 0 )
|
||||
layout.addParameter( 'Placer', 'etesian.spaceMargin' , 'Space Margin' , 1 )
|
||||
layout.addRule ( 'Placer' )
|
||||
layout.addTitle ( 'Placer', 'Etesian - Placer')
|
||||
layout.addParameter( 'Placer', 'etesian.densityVariation' , 'Density variation' , 0 )
|
||||
layout.addParameter( 'Placer', 'etesian.routingDriven' , 'Routing driven' , 0 )
|
||||
layout.addParameter( 'Placer', 'etesian.effort' , 'Placement effort' , 1 )
|
||||
layout.addParameter( 'Placer', 'etesian.graphics' , 'Placement view' , 1 )
|
||||
layout.addRule ( 'Placer' )
|
||||
|
|
|
@ -19,22 +19,22 @@ import coriolis.Cfg as Cfg
|
|||
layout = Cfg.Configuration.get().getLayout()
|
||||
|
||||
# Kite Layout.
|
||||
layout.addTab ( 'Kite', 'kite' )
|
||||
layout.addTitle ( 'Kite', 'Katabatic - Routing Database' )
|
||||
layout.addParameter( 'Kite', 'katabatic.saturateRatio' , 'Saturate Ratio (%)' , 0, 1 )
|
||||
layout.addParameter( 'Kite', 'katabatic.saturateRp' , 'Saturate RoutingPad' , 0, 1 )
|
||||
layout.addParameter( 'Kite', 'katabatic.globalLengthThreshold', 'Global Length Threshold', 0, 1 )
|
||||
layout.addParameter( 'Kite', 'katabatic.topRoutingLayer' , 'Top Routing Layer' , 0, 1 )
|
||||
layout.addParameter( 'Kite', 'anabatic.gcell.displayMode' , 'GCell Display Mode' , 1, 1 )
|
||||
layout.addRule ( 'Kite' )
|
||||
layout.addTitle ( 'Kite', 'Kite - Detailed Router' )
|
||||
layout.addParameter( 'Kite', 'kite.hTracksReservedLocal', 'Vert. Locally Reserved Tracks', 0 )
|
||||
layout.addParameter( 'Kite', 'kite.vTracksReservedLocal', 'Hor. Locally Reserved Tracks' , 0 )
|
||||
layout.addParameter( 'Kite', 'kite.eventsLimit' , 'Events Limit' , 0 )
|
||||
layout.addParameter( 'Kite', 'kite.ripupCost' , 'Ripup Cost' , 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addSection ( 'Kite', 'Ripup Limits', 1 )
|
||||
layout.addParameter( 'Kite', 'kite.strapRipupLimit' , 'Straps' , 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addParameter( 'Kite', 'kite.localRipupLimit' , 'Locals' , 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addParameter( 'Kite', 'kite.globalRipupLimit' , 'Globals' , 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addParameter( 'Kite', 'kite.longGlobalRipupLimit', 'Long Globals', 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addRule ( 'Kite' )
|
||||
layout.addTab ( 'Router', 'kite' )
|
||||
layout.addTitle ( 'Router', 'Katabatic - Routing Database' )
|
||||
layout.addParameter( 'Router', 'katabatic.saturateRatio' , 'Saturate Ratio (%)' , 0, 1 )
|
||||
layout.addParameter( 'Router', 'katabatic.saturateRp' , 'Saturate RoutingPad' , 0, 1 )
|
||||
layout.addParameter( 'Router', 'katabatic.globalLengthThreshold', 'Global Length Threshold', 0, 1 )
|
||||
layout.addParameter( 'Router', 'katabatic.topRoutingLayer' , 'Top Routing Layer' , 0, 1 )
|
||||
layout.addParameter( 'Router', 'anabatic.gcell.displayMode' , 'GCell Display Mode' , 1, 1 )
|
||||
layout.addRule ( 'Router' )
|
||||
layout.addTitle ( 'Router', 'Kite - Detailed Router' )
|
||||
layout.addParameter( 'Router', 'kite.hTracksReservedLocal', 'Vert. Locally Reserved Tracks', 0 )
|
||||
layout.addParameter( 'Router', 'kite.vTracksReservedLocal', 'Hor. Locally Reserved Tracks' , 0 )
|
||||
layout.addParameter( 'Router', 'kite.eventsLimit' , 'Events Limit' , 0 )
|
||||
layout.addParameter( 'Router', 'kite.ripupCost' , 'Ripup Cost' , 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addSection ( 'Router', 'Ripup Limits', 1 )
|
||||
layout.addParameter( 'Router', 'kite.strapRipupLimit' , 'Straps' , 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addParameter( 'Router', 'kite.localRipupLimit' , 'Locals' , 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addParameter( 'Router', 'kite.globalRipupLimit' , 'Globals' , 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addParameter( 'Router', 'kite.longGlobalRipupLimit', 'Long Globals', 1, 1, Cfg.Parameter.Flags.UseSpinBox )
|
||||
layout.addRule ( 'Router' )
|
||||
|
|
|
@ -85,19 +85,19 @@ param.addValue( "Custom" , 30 )
|
|||
param.setInt ( 0 )
|
||||
|
||||
layout = Cfg.Configuration.get().getLayout()
|
||||
layout.addTab ( 'misc', 'Misc.' )
|
||||
layout.addTitle ( 'misc', 'Miscellaneous' )
|
||||
layout.addParameter( 'misc', 'misc.catchCore' , 'Catch Core Dumps' , 1 )
|
||||
layout.addParameter( 'misc', 'misc.verboseLevel1' , 'Verbose' , 0 )
|
||||
layout.addParameter( 'misc', 'misc.verboseLevel2' , 'Very Verbose' , 0 )
|
||||
layout.addParameter( 'misc', 'misc.info' , 'Show Info' , 0 )
|
||||
layout.addParameter( 'misc', 'misc.logMode' , 'Output is a TTY' , 0 )
|
||||
layout.addParameter( 'misc', 'misc.minTraceLevel' , 'Min. Trace Level' , 1 )
|
||||
layout.addParameter( 'misc', 'misc.maxTraceLevel' , 'Max. Trace Level' , 1 )
|
||||
layout.addTitle ( 'misc', 'Print/Snapshot Parameters' )
|
||||
layout.addParameter( 'misc', 'viewer.printer.mode' , 'Printer/Snapshot Mode', 1 )
|
||||
layout.addParameter( 'misc', 'viewer.printer.paper' , 'Paper Size' , 0 )
|
||||
layout.addParameter( 'misc', 'viewer.printer.orientation', 'Orientation' , 0 )
|
||||
layout.addParameter( 'misc', 'viewer.printer.DPI' , 'DPI' , 0 )
|
||||
layout.addTab ( 'Misc', 'Misc.' )
|
||||
layout.addTitle ( 'Misc', 'Miscellaneous' )
|
||||
layout.addParameter( 'Misc', 'misc.catchCore' , 'Catch Core Dumps' , 1 )
|
||||
layout.addParameter( 'Misc', 'misc.verboseLevel1' , 'Verbose' , 0 )
|
||||
layout.addParameter( 'Misc', 'misc.verboseLevel2' , 'Very Verbose' , 0 )
|
||||
layout.addParameter( 'Misc', 'misc.info' , 'Show Info' , 0 )
|
||||
layout.addParameter( 'Misc', 'misc.logMode' , 'Output is a TTY' , 0 )
|
||||
layout.addParameter( 'Misc', 'misc.minTraceLevel' , 'Min. Trace Level' , 1 )
|
||||
layout.addParameter( 'Misc', 'misc.maxTraceLevel' , 'Max. Trace Level' , 1 )
|
||||
layout.addTitle ( 'Misc', 'Print/Snapshot Parameters' )
|
||||
layout.addParameter( 'Misc', 'viewer.printer.mode' , 'Printer/Snapshot Mode', 1 )
|
||||
layout.addParameter( 'Misc', 'viewer.printer.paper' , 'Paper Size' , 0 )
|
||||
layout.addParameter( 'Misc', 'viewer.printer.orientation', 'Orientation' , 0 )
|
||||
layout.addParameter( 'Misc', 'viewer.printer.DPI' , 'DPI' , 0 )
|
||||
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
import coriolis.Cfg as Cfg
|
||||
|
||||
layout = Cfg.Configuration.get().getLayout()
|
||||
layout.addTab ( 'stratus1', 'Stratus1' )
|
||||
layout.addTitle ( 'stratus1', 'Stratus1 - Netlist & Layout Capture' )
|
||||
layout.addParameter( 'stratus1', 'stratus1.mappingName', 'Virtual Library Translation', 0, 2 )
|
||||
layout.addParameter( 'stratus1', 'stratus1.format' , 'Netlist Format (vst, vhd)' , 0, 2 )
|
||||
layout.addParameter( 'stratus1', 'stratus1.simulator' , 'Simulator' , 0, 2 )
|
||||
layout.addTab ( 'Netlist', 'Stratus1' )
|
||||
layout.addTitle ( 'Netlist', 'Stratus1 - Netlist & Layout Capture' )
|
||||
layout.addParameter( 'Netlist', 'stratus1.mappingName', 'Virtual Library Translation', 0, 2 )
|
||||
layout.addParameter( 'Netlist', 'stratus1.format' , 'Netlist Format (vst, vhd)' , 0, 2 )
|
||||
layout.addParameter( 'Netlist', 'stratus1.simulator' , 'Simulator' , 0, 2 )
|
||||
|
|
|
@ -0,0 +1,324 @@
|
|||
|
||||
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
|
||||
|
||||
|
||||
__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.Vertical # 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.Horizontal # 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.Vertical # 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.Horizontal # 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.Vertical # 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.Horizontal # 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.katana.disableStackedVias = True
|
||||
cfg.katana.hTracksReservedLocal = 4
|
||||
cfg.katana.hTracksReservedLocal = [0, 20]
|
||||
cfg.katana.vTracksReservedLocal = 3
|
||||
cfg.katana.vTracksReservedLocal = [0, 20]
|
||||
cfg.katana.termSatReservedLocal = 8
|
||||
cfg.katana.termSatThreshold = 9
|
||||
cfg.katana.eventsLimit = 4000002
|
||||
cfg.katana.ripupCost = 3
|
||||
cfg.katana.ripupCost = [0, None]
|
||||
cfg.katana.strapRipupLimit = 16
|
||||
cfg.katana.strapRipupLimit = [1, None]
|
||||
cfg.katana.localRipupLimit = 9
|
||||
cfg.katana.localRipupLimit = [1, None]
|
||||
cfg.katana.globalRipupLimit = 5
|
||||
cfg.katana.globalRipupLimit = [1, None]
|
||||
cfg.katana.longGlobalRipupLimit = 5
|
||||
cfg.chip.padCoreSide = 'South'
|
||||
# Plugins setup
|
||||
cfg.clockTree.minimumSide = u(5.04) * 6
|
||||
cfg.clockTree.buffer = 'gf180mcu_fd_sc_mcu9t5v0__clkbuf_2'
|
||||
cfg.clockTree.placerEngine = 'Etesian'
|
||||
cfg.block.spareSide = 10
|
||||
cfg.spares.buffer = 'gf180mcu_fd_sc_mcu9t5v0__clkbuf_2'
|
||||
cfg.spares.maxSinks = 20
|
||||
|
||||
|
||||
def _loadStdLib ( cellsTop ):
|
||||
"""
|
||||
Load the muc9t5v0 library from the GDS files.
|
||||
|
||||
:param cellsTop: The top directory containing the cells views.
|
||||
|
||||
As GDS file is lacking most of the interface informations, apply a
|
||||
post-process on each cell to educated guess :
|
||||
|
||||
* Which nets are external, and in which direction (name matching).
|
||||
* Blockages: any shape in internals nets in Metal1 or Metal2 layer.
|
||||
"""
|
||||
useGds = False
|
||||
af = AllianceFramework.get()
|
||||
db = DataBase.getDB()
|
||||
tech = db.getTechnology()
|
||||
rootlib = db.getRootLibrary()
|
||||
cellLib = Library.create(rootlib, 'mcu9t5v')
|
||||
af.wrapLibrary( cellLib, 0 )
|
||||
|
||||
gaugeName = Cfg.getParamString('anabatic.routingGauge').asString()
|
||||
routingGauge = af.getRoutingGauge( gaugeName )
|
||||
metal1 = DataBase.getDB().getTechnology().getLayer( 'Metal1' )
|
||||
metal2 = DataBase.getDB().getTechnology().getLayer( 'Metal2' )
|
||||
blockage1 = metal1.getBlockageLayer()
|
||||
blockage2 = metal2.getBlockageLayer()
|
||||
hpitch = 0
|
||||
for layerGauge in routingGauge.getLayerGauges():
|
||||
if layerGauge.getType() == RoutingLayerGauge.PinOnly:
|
||||
continue
|
||||
if layerGauge.getDirection() == RoutingLayerGauge.Horizontal:
|
||||
hpitch = layerGauge.getPitch()
|
||||
break
|
||||
|
||||
if useGds:
|
||||
io.vprint( 1, ' o Setup GF 180 mcu9t5v library in {} [GDS].'.format( cellLib.getName() ))
|
||||
io.vprint( 2, ' (__file__="{}")'.format( os.path.abspath( __file__ )))
|
||||
for cellDir in cellsTop.iterdir():
|
||||
for gdsFile in sorted(cellDir.glob('*.gds')):
|
||||
Gds.load( cellLib
|
||||
, gdsFile.as_posix()
|
||||
, Gds.NoGdsPrefix|Gds.Layer_0_IsBoundary )
|
||||
#io.vprint( 1, ' o Skrinking V-AB of {}'.format(DbU.getValueString( hpitch )))
|
||||
with overlay.UpdateSession():
|
||||
for cell in cellLib.getCells():
|
||||
ab = cell.getAbutmentBox()
|
||||
#ab.inflate( 0, -hpitch )
|
||||
cell.setAbutmentBox( ab )
|
||||
cell.setTerminalNetlist( True )
|
||||
for net in cell.getNets():
|
||||
if not net.isExternal():
|
||||
blockages = []
|
||||
for component in net.getComponents():
|
||||
if component.getLayer() == metal1 or component.getLayer() == metal1:
|
||||
blockages.append( component )
|
||||
if blockages:
|
||||
io.vprint( 2, ' - Obstacles found in {}'.format( cell ))
|
||||
for component in blockages:
|
||||
bb = component.getBoundingBox()
|
||||
if component.getLayer() == metal1:
|
||||
v = Vertical.create( net
|
||||
, blockage1
|
||||
, bb.getXCenter()
|
||||
, bb.getWidth()
|
||||
, bb.getYMin()
|
||||
, bb.getYMax() )
|
||||
if component.getLayer() == metal2:
|
||||
h = Horizontal.create( net
|
||||
, blockage2
|
||||
, bb.getYCenter()
|
||||
, bb.getHeight()
|
||||
, bb.getXMin()
|
||||
, bb.getXMax() )
|
||||
continue
|
||||
if net.isPower() or net.getName() == 'VDD':
|
||||
net.setName( 'VDD' )
|
||||
net.setType( Net.Type.POWER )
|
||||
net.setGlobal( True )
|
||||
net.setDirection( Net.Direction.IN )
|
||||
continue
|
||||
if net.isGround() or net.getName() == 'VSS':
|
||||
net.setName( 'VSS' )
|
||||
net.setType( Net.Type.GROUND )
|
||||
net.setGlobal( True )
|
||||
net.setDirection( Net.Direction.IN )
|
||||
continue
|
||||
if net.getName() == 'Z' \
|
||||
or net.getName() == 'ZN' \
|
||||
or net.getName() == 'Q':
|
||||
net.setDirection( Net.Direction.OUT )
|
||||
else:
|
||||
net.setDirection( Net.Direction.IN )
|
||||
toDestroy = []
|
||||
for component in NetExternalComponents.get(net):
|
||||
if isinstance(component,Pad):
|
||||
bb = component.getBoundingBox()
|
||||
pad = Vertical.create( net
|
||||
, component.getLayer()
|
||||
, bb.getCenter().getX()
|
||||
, bb.getWidth()
|
||||
, bb.getYMin()
|
||||
, bb.getYMax() )
|
||||
NetExternalComponents.setExternal( pad )
|
||||
toDestroy.append( component )
|
||||
for component in toDestroy:
|
||||
component.destroy()
|
||||
else:
|
||||
io.vprint( 1, ' o Setup GF 180 mcu9t5v library in {} [LEF].'.format( cellLib.getName() ))
|
||||
io.vprint( 2, ' (__file__="{}")'.format( os.path.abspath( __file__ )))
|
||||
LefImport.load( (cellsTop / '..' / 'tech' / 'gf180mcu_6LM_1TM_9K_9t_tech.lef').as_posix() )
|
||||
LefImport.setMergeLibrary( cellLib )
|
||||
for cellDir in cellsTop.iterdir():
|
||||
for lefFile in sorted(cellDir.glob('*.lef')):
|
||||
LefImport.load( lefFile.as_posix() )
|
||||
af.wrapLibrary( cellLib, 1 )
|
||||
return cellLib
|
||||
|
||||
|
||||
def _loadIoLib ():
|
||||
"""
|
||||
Load the IO library from the GDS files.
|
||||
"""
|
||||
af = AllianceFramework.get()
|
||||
ioLib = af.getLibrary( 1 )
|
||||
io.vprint( 1, ' o Loading GDS library in "{}".'.format( ioLib.getName() ))
|
||||
Gds.load( ioLib
|
||||
, ndaTopDir + '/XXXX.gds'
|
||||
, Gds.NoGdsPrefix )
|
||||
|
||||
|
||||
def setup ( cellsTop ):
|
||||
_routing()
|
||||
_loadStdLib( cellsTop )
|
||||
#_loadIoLib()
|
|
@ -0,0 +1,318 @@
|
|||
|
||||
import sys
|
||||
import os.path
|
||||
from coriolis import Cfg, Hurricane, Viewer, CRL
|
||||
from coriolis.Hurricane import Technology, DataBase, DbU, Library, Layer, \
|
||||
BasicLayer, Cell, Net, Horizontal, Vertical, \
|
||||
Rectilinear, Box, Point, NetExternalComponents
|
||||
from coriolis.technos.common.colors import toRGB
|
||||
from coriolis.technos.common.patterns import toHexa
|
||||
from coriolis.helpers import l, u, trace, io
|
||||
from coriolis.helpers.technology import createBL, createVia, setEnclosures
|
||||
from coriolis.helpers.overlay import CfgCache
|
||||
|
||||
|
||||
__all__ = [ 'setup' ]
|
||||
|
||||
|
||||
def _setup_techno():
|
||||
io.vprint( 1, ' o Setup GF180MCU technology.' )
|
||||
io.vprint( 2, ' (__file__="{}")'.format( os.path.abspath( __file__ )))
|
||||
|
||||
db = DataBase.create()
|
||||
CRL.System.get()
|
||||
|
||||
tech = Technology.create( db, 'GF180MCU' )
|
||||
|
||||
DbU.setPrecision( 2 )
|
||||
DbU.setPhysicalsPerGrid( 0.005, DbU.UnitPowerMicro )
|
||||
with CfgCache(priority=Cfg.Parameter.Priority.ConfigurationFile) as cfg:
|
||||
cfg.gdsDriver.metricDbu = 1e-09
|
||||
cfg.gdsDriver.dbuPerUu = 0.001
|
||||
DbU.setGridsPerLambda ( 10 )
|
||||
DbU.setSymbolicSnapGridStep( DbU.fromGrid( 1.0 ))
|
||||
DbU.setPolygonStep ( DbU.fromGrid( 1.0 ))
|
||||
DbU.setStringMode ( DbU.StringModePhysical, DbU.UnitPowerMicro )
|
||||
|
||||
Nwell = createBL( tech, 'Nwell' , BasicLayer.Material.nWell , size=u(0.86), spacing=u(0.74), gds2Layer=21 )
|
||||
LVPwell = createBL( tech, 'LVPwell' , BasicLayer.Material.pWell , size=u(0.74), spacing=u(1.7 ), gds2Layer=204 )
|
||||
Nplus = createBL( tech, 'Nplus' , BasicLayer.Material.nImplant , size=u(0.4 ), spacing=u(0.4 ), gds2Layer=32 )
|
||||
Pplus = createBL( tech, 'Pplus' , BasicLayer.Material.pImplant , size=u(0.4 ), spacing=u(0.4 ), gds2Layer=31 )
|
||||
COMP = createBL( tech, 'COMP' , BasicLayer.Material.active , size=u(0.3 ), spacing=u(0.36), gds2Layer=22 )
|
||||
Poly2 = createBL( tech, 'Poly2' , BasicLayer.Material.poly , size=u(0.2 ), spacing=u(0.24), gds2Layer=30 )
|
||||
Cont = createBL( tech, 'Contact' , BasicLayer.Material.cut , size=u(0.22), spacing=u(0.25), gds2Layer=33 )
|
||||
Metal1 = createBL( tech, 'Metal1' , BasicLayer.Material.metal , size=u(0.23), spacing=u(0.23), gds2Layer=34 )
|
||||
Via1 = createBL( tech, 'Via1' , BasicLayer.Material.cut , size=u(0.26), spacing=u(0.26), gds2Layer=35 )
|
||||
Metal2 = createBL( tech, 'Metal2' , BasicLayer.Material.metal , size=u(0.28), spacing=u(0.28), gds2Layer=36 )
|
||||
Via2 = createBL( tech, 'Via2' , BasicLayer.Material.cut , size=u(0.26), spacing=u(0.26), gds2Layer=38 )
|
||||
Metal3 = createBL( tech, 'Metal3' , BasicLayer.Material.metal , size=u(0.28), spacing=u(0.28), gds2Layer=42 )
|
||||
Via3 = createBL( tech, 'Via3' , BasicLayer.Material.cut , size=u(0.26), spacing=u(0.26), gds2Layer=40 )
|
||||
Metal4 = createBL( tech, 'Metal4' , BasicLayer.Material.metal , size=u(0.28), spacing=u(0.28), gds2Layer=46 )
|
||||
Via4 = createBL( tech, 'Via4' , BasicLayer.Material.cut , size=u(0.26), spacing=u(0.26), gds2Layer=41 )
|
||||
Metal5 = createBL( tech, 'Metal5' , BasicLayer.Material.metal , size=u(0.28), spacing=u(0.28), gds2Layer=81 )
|
||||
Via5 = createBL( tech, 'Via5' , BasicLayer.Material.cut , size=u(0.26), spacing=u(0.26), gds2Layer=82 )
|
||||
MetalTop = createBL( tech, 'MetalTop', BasicLayer.Material.metal , size=u(0.36), spacing=u(0.38), gds2Layer=53 )
|
||||
|
||||
Poly2_Dummy = createBL( tech, 'Poly2_Dummy' , BasicLayer.Material.poly , gds2Layer=30, gds2DataType=4 )
|
||||
Metal1_Dummy = createBL( tech, 'Metal1_Dummy' , BasicLayer.Material.metal, gds2Layer=34, gds2DataType=4 )
|
||||
Metal2_Dummy = createBL( tech, 'Metal2_Dummy' , BasicLayer.Material.metal, gds2Layer=36, gds2DataType=4 )
|
||||
Metal3_Dummy = createBL( tech, 'Metal3_Dummy' , BasicLayer.Material.metal, gds2Layer=42, gds2DataType=4 )
|
||||
Metal4_Dummy = createBL( tech, 'Metal4_Dummy' , BasicLayer.Material.metal, gds2Layer=46, gds2DataType=4 )
|
||||
Metal5_Dummy = createBL( tech, 'Metal5_Dummy' , BasicLayer.Material.metal, gds2Layer=81, gds2DataType=4 )
|
||||
MetalTop_Dummy = createBL( tech, 'MetalTop_Dummy', BasicLayer.Material.metal, gds2Layer=53, gds2DataType=4 )
|
||||
|
||||
Poly2_Label = createBL( tech, 'Poly2_Label' , BasicLayer.Material.info, gds2Layer=30, gds2DataType=10 )
|
||||
Metal1_Label = createBL( tech, 'Metal1_Label' , BasicLayer.Material.info, gds2Layer=34, gds2DataType=10 )
|
||||
Metal2_Label = createBL( tech, 'Metal2_Label' , BasicLayer.Material.info, gds2Layer=36, gds2DataType=10 )
|
||||
Metal3_Label = createBL( tech, 'Metal3_Label' , BasicLayer.Material.info, gds2Layer=42, gds2DataType=10 )
|
||||
Metal4_Label = createBL( tech, 'Metal4_Label' , BasicLayer.Material.info, gds2Layer=46, gds2DataType=10 )
|
||||
Metal5_Label = createBL( tech, 'Metal5_Label' , BasicLayer.Material.info, gds2Layer=81, gds2DataType=10 )
|
||||
MetalTop_Label = createBL( tech, 'MetalTop_Label', BasicLayer.Material.info, gds2Layer=53, gds2DataType=10 )
|
||||
|
||||
Metal1_BLK = createBL( tech, 'Metal1_BLK' , BasicLayer.Material.blockage, gds2Layer=34, gds2DataType=5 )
|
||||
Metal2_BLK = createBL( tech, 'Metal2_BLK' , BasicLayer.Material.blockage, gds2Layer=36, gds2DataType=5 )
|
||||
Metal3_BLK = createBL( tech, 'Metal3_BLK' , BasicLayer.Material.blockage, gds2Layer=42, gds2DataType=5 )
|
||||
Metal4_BLK = createBL( tech, 'Metal4_BLK' , BasicLayer.Material.blockage, gds2Layer=46, gds2DataType=5 )
|
||||
Metal5_BLK = createBL( tech, 'Metal5_BLK' , BasicLayer.Material.blockage, gds2Layer=81, gds2DataType=5 )
|
||||
MetalTop_BLK = createBL( tech, 'MetalTop_BLK', BasicLayer.Material.blockage, gds2Layer=53, gds2DataType=5 )
|
||||
|
||||
CONT = createVia( tech, 'CONT_POLY2', 'Poly2', 'Contact', 'Metal1', u(0.22) )
|
||||
setEnclosures( CONT, Poly2 , u(0.07) )
|
||||
setEnclosures( CONT, Metal1, u(0.12) )
|
||||
VIA12 = createVia( tech, 'VIA12', 'Metal1', 'Via1', 'Metal2', u(0.26) )
|
||||
setEnclosures( VIA12, Metal1, u(0.06) )
|
||||
setEnclosures( VIA12, Metal2, u(0.06) )
|
||||
VIA23 = createVia( tech, 'VIA23', 'Metal2', 'Via2', 'Metal3', u(0.26) )
|
||||
setEnclosures( VIA23, Metal2, u(0.06) )
|
||||
setEnclosures( VIA23, Metal3, u(0.06) )
|
||||
VIA34 = createVia( tech, 'VIA34', 'Metal3', 'Via3', 'Metal4', u(0.26) )
|
||||
setEnclosures( VIA34, Metal3, u(0.06) )
|
||||
setEnclosures( VIA34, Metal4, u(0.06) )
|
||||
VIA45 = createVia( tech, 'VIA45', 'Metal4', 'Via4', 'Metal5', u(0.26) )
|
||||
setEnclosures( VIA45, Metal4, u(0.06) )
|
||||
setEnclosures( VIA45, Metal5, u(0.06) )
|
||||
VIA5T = createVia( tech, 'VIA5T', 'Metal5', 'Via5', 'MetalTop', u(0.26) )
|
||||
setEnclosures( VIA5T, Metal5 , u(0.06) )
|
||||
setEnclosures( VIA5T, MetalTop, u(0.06) )
|
||||
|
||||
Border = createBL( tech, 'Border', BasicLayer.Material.other, gds2Layer=63 )
|
||||
|
||||
Metal1 .setBlockageLayer( Metal1_BLK )
|
||||
Metal2 .setBlockageLayer( Metal2_BLK )
|
||||
Metal3 .setBlockageLayer( Metal3_BLK )
|
||||
Metal4 .setBlockageLayer( Metal4_BLK )
|
||||
Metal5 .setBlockageLayer( Metal5_BLK )
|
||||
MetalTop.setBlockageLayer( MetalTop_BLK )
|
||||
|
||||
# Coriolis internal layers
|
||||
createBL( tech, 'text.cell' , BasicLayer.Material.other )
|
||||
createBL( tech, 'text.instance', BasicLayer.Material.other )
|
||||
createBL( tech, 'SPL1' , BasicLayer.Material.other )
|
||||
createBL( tech, 'AutoLayer' , BasicLayer.Material.other )
|
||||
createBL( tech, 'gmetalh' , BasicLayer.Material.metal )
|
||||
createBL( tech, 'gcontact' , BasicLayer.Material.cut )
|
||||
createBL( tech, 'gmetalv' , BasicLayer.Material.metal )
|
||||
|
||||
|
||||
def _setup_display():
|
||||
# ----------------------------------------------------------------------
|
||||
# Style: Coriolis [black]
|
||||
|
||||
threshold = 0.2 if Viewer.Graphics.isHighDpi() else 0.1
|
||||
scale = 1.0
|
||||
|
||||
style = Viewer.DisplayStyle( 'Coriolis [black]' )
|
||||
style.setDescription( 'Coriolis Look - black background' )
|
||||
style.setDarkening ( Viewer.DisplayStyle.HSVr(1.0, 3.0, 2.5) )
|
||||
# Viewer.
|
||||
style.addDrawingStyle( group='Viewer', name='fallback' , color=toRGB('Gray238' ), border=1, pattern='55AA55AA55AA55AA' )
|
||||
style.addDrawingStyle( group='Viewer', name='background' , color=toRGB('Gray50' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='foreground' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='rubber' , color=toRGB('192,0,192' ), border=4, threshold=0.02 )
|
||||
style.addDrawingStyle( group='Viewer', name='phantom' , color=toRGB('Seashell4' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='boundaries' , color=toRGB('wheat1' ), border=2, pattern='0000000000000000', threshold=0 )
|
||||
style.addDrawingStyle( group='Viewer', name='marker' , color=toRGB('80,250,80' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionDraw' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionFill' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='grid' , color=toRGB('White' ), border=1, threshold=2.0 )
|
||||
style.addDrawingStyle( group='Viewer', name='spot' , color=toRGB('White' ), border=2, threshold=6.0 )
|
||||
style.addDrawingStyle( group='Viewer', name='ghost' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='text.ruler' , color=toRGB('White' ), border=1, threshold= 0.0 )
|
||||
style.addDrawingStyle( group='Viewer', name='text.instance' , color=toRGB('White' ), border=1, threshold=400.0 )
|
||||
style.addDrawingStyle( group='Viewer', name='text.reference', color=toRGB('White' ), border=1, threshold=200.0 )
|
||||
style.addDrawingStyle( group='Viewer', name='undef' , color=toRGB('Violet' ), border=0, pattern='2244118822441188' )
|
||||
style.addDrawingStyle( group='Viewer', name='Border' , color=toRGB('wheat1' ), border=1, pattern='0000000000000000', threshold=0 )
|
||||
|
||||
# Group: Active Layer.
|
||||
style.addDrawingStyle( group='Active Layer', name='Nwell' , color=toRGB('Tan' ), pattern='55AA55AA55AA55AA' , threshold=1.5 *scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='LVPwell' , color=toRGB('LightYellow'), pattern='55AA55AA55AA55AA' , threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='Nplus' , color=toRGB('LawnGreen' ), pattern='55AA55AA55AA55AA' , threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='Pplus' , color=toRGB('Yellow' ), pattern='55AA55AA55AA55AA' , threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='COMP' , color=toRGB('White' ), pattern=toHexa('antihash1.8'), threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Active Layer', name='Poly2' , color=toRGB('Red' ), pattern='55AA55AA55AA55AA' , threshold=1.50*scale )
|
||||
|
||||
# Group: Routing Layer.
|
||||
style.addDrawingStyle( group='Routing Layer', name='Metal1' , color=toRGB('Blue' ), pattern=toHexa('poids2.8' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='Metal2' , color=toRGB('Aqua' ), pattern=toHexa('light_antihash0.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='Metal3' , color=toRGB('LightPink'), pattern=toHexa('light_antihash1.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='Metal4' , color=toRGB('Green' ), pattern=toHexa('light_antihash2.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='Metal5' , color=toRGB('Yellow' ), pattern='1144114411441144' , threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Routing Layer', name='MetalTop', color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.02*scale )
|
||||
|
||||
# Group: Cuts (VIA holes).
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Contact', color=toRGB('0,150,150'), threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via1' , color=toRGB('Aqua' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via2' , color=toRGB('LightPink'), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via3' , color=toRGB('Green' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via4' , color=toRGB('Yellow' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via5' , color=toRGB('Violet' ), threshold=0.80*scale )
|
||||
|
||||
# Group: Fillers.
|
||||
style.addDrawingStyle( group='Fillers', name='Poly2_Dummy' , color=toRGB('Red' ), pattern='55AA55AA55AA55AA' , border=0, threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal1_Dummy' , color=toRGB('Blue' ), pattern=toHexa('poids2.8' ), border=0, threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal2_Dummy' , color=toRGB('Aqua' ), pattern=toHexa('light_antihash0.8'), border=0, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal3_Dummy' , color=toRGB('LightPink'), pattern=toHexa('light_antihash1.8'), border=0, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal4_Dummy' , color=toRGB('Green' ), pattern=toHexa('light_antihash2.8'), border=0, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal5_Dummy' , color=toRGB('Yellow' ), pattern='1144114411441144' , border=0, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='MetalTop_Dummy', color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), border=0, threshold=0.02*scale )
|
||||
|
||||
# Group: Blockages.
|
||||
style.addDrawingStyle( group='Blockages', name='Metal1_BLK' , color=toRGB('Blue' ), pattern='006070381c0e0703' , threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='Metal2_BLK' , color=toRGB('Aqua' ), pattern='8103060c183060c0' , threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='Metal3_BLK' , color=toRGB('LightPink'), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='Metal4_BLK' , color=toRGB('Green' ), pattern=toHexa('light_antihash2.8'), threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='Metal5_BLK' , color=toRGB('Yellow' ), pattern='1144114411441144' , threshold=0.80*scale, border=2 )
|
||||
style.addDrawingStyle( group='Blockages', name='MetalTop_BLK', color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.80*scale, border=2 )
|
||||
|
||||
# Group: Text.
|
||||
style.addDrawingStyle( group='Text', name='Poly2_Label' , color=toRGB('Red' ), pattern='55AA55AA55AA55AA' , threshold=1.50*scale )
|
||||
style.addDrawingStyle( group='Text', name='Metal1_Label' , color=toRGB('Blue' ), pattern=toHexa('poids2.8' ), threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Text', name='Metal2_Label' , color=toRGB('Aqua' ), pattern=toHexa('light_antihash0.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Text', name='Metal3_Label' , color=toRGB('LightPink'), pattern=toHexa('light_antihash1.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Text', name='Metal4_Label' , color=toRGB('Green' ), pattern=toHexa('light_antihash2.8'), threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Text', name='Metal5_Label' , color=toRGB('Yellow' ), pattern='1144114411441144' , threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Text', name='MetalTop_Label', color=toRGB('Violet' ), pattern=toHexa('light_antihash0.8'), threshold=0.02*scale )
|
||||
|
||||
# Knick & Kite.
|
||||
style.addDrawingStyle( group='Knik & Kite', name='SPL1' , color=toRGB('Red' ) )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='AutoLayer' , color=toRGB('Magenta' ) )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gmetalh' , color=toRGB('128,255,200'), pattern=toHexa('antislash2.32' ), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gmetalv' , color=toRGB('200,200,255'), pattern=toHexa('light_antihash1.8'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gcontact' , color=toRGB('255,255,190'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='Anabatic::Edge' , color=toRGB('255,255,190'), pattern='0000000000000000' , border=4, threshold=0.02 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='Anabatic::GCell', color=toRGB('255,255,190'), pattern='0000000000000000' , border=2, threshold=threshold )
|
||||
|
||||
Viewer.Graphics.addStyle( style )
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Style: Alliance.Classic [white].
|
||||
|
||||
style = Viewer.DisplayStyle( 'Coriolis [white]' )
|
||||
style.inheritFrom( 'Coriolis [black]' )
|
||||
style.setDescription ( 'Coriolis Look - white background' )
|
||||
style.setDarkening ( Viewer.DisplayStyle.HSVr(1.0, 3.0, 2.5) )
|
||||
style.addDrawingStyle( group='Viewer', name='background', color=toRGB('White'), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='foreground', color=toRGB('Black'), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='boundaries', color=toRGB('Black'), border=1, pattern='0000000000000000' )
|
||||
Viewer.Graphics.addStyle( style )
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Style: Alliance.Classic [black]
|
||||
|
||||
style = Viewer.DisplayStyle( 'Alliance.Classic [black]' )
|
||||
style.setDescription( 'Alliance Classic Look - black background' )
|
||||
style.setDarkening ( Viewer.DisplayStyle.HSVr(1.0, 3.0, 2.5) )
|
||||
|
||||
# Viewer.
|
||||
style.addDrawingStyle( group='Viewer', name='fallback' , color=toRGB('Gray238' ), border=1, pattern='55AA55AA55AA55AA' )
|
||||
style.addDrawingStyle( group='Viewer', name='background' , color=toRGB('Gray50' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='foreground' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='rubber' , color=toRGB('192,0,192' ), border=4, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='phantom' , color=toRGB('Seashell4' ), border=1 )
|
||||
#style.addDrawingStyle( group='Viewer', name='boundaries' , color=toRGB('208,199,192'), border=2, threshold=0 )
|
||||
style.addDrawingStyle( group='Viewer', name='boundaries' , color=toRGB('wheat1') , border=2, pattern='0000000000000000', threshold=0 )
|
||||
style.addDrawingStyle( group='Viewer', name='marker' , color=toRGB('80,250,80' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionDraw' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='selectionFill' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='grid' , color=toRGB('White' ), border=1, threshold=8.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='spot' , color=toRGB('White' ), border=2, threshold=6.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='ghost' , color=toRGB('White' ), border=1 )
|
||||
style.addDrawingStyle( group='Viewer', name='text.ruler' , color=toRGB('White' ), border=1, threshold= 0.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='text.instance' , color=toRGB('White' ), border=1, threshold=400.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='text.reference', color=toRGB('White' ), border=1, threshold=200.0*scale )
|
||||
style.addDrawingStyle( group='Viewer', name='undef' , color=toRGB('Violet' ), border=0, pattern='2244118822441188' )
|
||||
style.addDrawingStyle( group='Viewer', name='Border' , color=toRGB('wheat1' ), border=1, pattern='0000000000000000', threshold=0 )
|
||||
|
||||
# Active Layers.
|
||||
style.addDrawingStyle( group='Active Layers', name='Nwell' , color=toRGB('Tan' ), pattern=toHexa('urgo.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='LVPwell' , color=toRGB('LightYellow'), pattern=toHexa('urgo.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='Nplus' , color=toRGB('LawnGreen' ), pattern=toHexa('antihash0.8'), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='Pplus' , color=toRGB('Yellow' ), pattern=toHexa('antihash0.8'), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='COMP' , color=toRGB('White' ), pattern=toHexa('antihash1.8'), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Active Layers', name='Poly2' , color=toRGB('Red' ), pattern=toHexa('poids2.8' ), border=1, threshold=0.00*scale )
|
||||
|
||||
# Routing Layers.
|
||||
style.addDrawingStyle( group='Routing Layers', name='Metal1' , color=toRGB('Blue' ), pattern=toHexa('slash.8' ), border=1, threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='Metal2' , color=toRGB('Aqua' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='Metal3' , color=toRGB('LightPink' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='Metal4' , color=toRGB('Green' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='Metal5' , color=toRGB('Yellow' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Routing Layers', name='MetalTop', color=toRGB('Violet' ), pattern=toHexa('poids4.8' ), border=1, threshold=0.00*scale )
|
||||
|
||||
# Cuts (VIA holes).
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Contact', color=toRGB('0,150,150'), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via1' , color=toRGB('Aqua' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via2' , color=toRGB('LightPink'), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via3' , color=toRGB('Green' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via4' , color=toRGB('Yellow' ), threshold=0.0*scale )
|
||||
style.addDrawingStyle( group='Cuts (VIA holes)', name='Via5' , color=toRGB('Violet' ), threshold=0.0*scale )
|
||||
|
||||
# Fillers.
|
||||
style.addDrawingStyle( group='Fillers', name='Poly2_Dummy' , color=toRGB('Red' ), pattern=toHexa('poids2.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal1_Dummy' , color=toRGB('Blue' ), pattern=toHexa('slash.8' ), border=0, threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal2_Dummy' , color=toRGB('Aqua' ), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal3_Dummy' , color=toRGB('LightPink'), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal4_Dummy' , color=toRGB('Green' ), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='Metal5_Dummy' , color=toRGB('Yellow' ), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Fillers', name='MetalTop_Dummy', color=toRGB('Violet' ), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
|
||||
# Labels.
|
||||
style.addDrawingStyle( group='Labels', name='Poly2_Label' , color=toRGB('Red' ), pattern=toHexa('poids2.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Labels', name='Metal1_Label' , color=toRGB('Blue' ), pattern=toHexa('slash.8' ), border=0, threshold=0.80*scale )
|
||||
style.addDrawingStyle( group='Labels', name='Metal2_Label' , color=toRGB('Aqua' ), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Labels', name='Metal3_Label' , color=toRGB('LightPink'), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Labels', name='Metal4_Label' , color=toRGB('Green' ), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Labels', name='Metal5_Label' , color=toRGB('Yellow' ), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
style.addDrawingStyle( group='Labels', name='MetalTop_Label', color=toRGB('Violet' ), pattern=toHexa('poids4.8' ), border=0, threshold=0.00*scale )
|
||||
|
||||
# Blockages.
|
||||
style.addDrawingStyle( group='Blockages', name='Metal1_BLK' , color=toRGB('Blue' ), pattern=toHexa('light_antislash0.8'), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='Metal2_BLK' , color=toRGB('Aqua' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='Metal3_BLK' , color=toRGB('LightPink'), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='Metal4_BLK' , color=toRGB('Green' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='Metal5_BLK' , color=toRGB('Yellow' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
style.addDrawingStyle( group='Blockages', name='MetalTop_BLK', color=toRGB('Violet' ), pattern=toHexa('poids4.8' ), threshold=0.80*scale, border=4 )
|
||||
|
||||
# Knick & Kite.
|
||||
style.addDrawingStyle( group='Knik & Kite', name='SPL1' , color=toRGB('Red' ) )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='AutoLayer' , color=toRGB('Magenta' ) )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gcontact' , color=toRGB('255,255,190'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gmetalh' , color=toRGB('128,255,200'), pattern=toHexa('antislash2.32' ), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gmetalv' , color=toRGB('200,200,255'), pattern=toHexa('light_antihash1.8'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='gcut' , color=toRGB('255,255,190'), border=1 )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='Anabatic::Edge' , color=toRGB('255,255,190'), pattern='0000000000000000' , border=4, threshold=0.02*scale )
|
||||
style.addDrawingStyle( group='Knik & Kite', name='Anabatic::GCell', color=toRGB('255,255,190'), pattern='0000000000000000' , border=2, threshold=0.10*scale )
|
||||
|
||||
Viewer.Graphics.addStyle( style )
|
||||
Viewer.Graphics.setStyle( 'Alliance.Classic [black]' )
|
||||
|
||||
|
||||
def setup():
|
||||
_setup_techno()
|
||||
_setup_display()
|
||||
try:
|
||||
from .techno_fix import fix
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
fix()
|
|
@ -43,6 +43,7 @@ env.setGROUND ( 'vss' )
|
|||
env.setCLOCK ( '.*ck.*|.*nck.*' )
|
||||
env.setBLOCKAGE ( 'blockage[Nn]et.*' )
|
||||
env.setPad ( '.*_px$' )
|
||||
env.setRegister ( 'sff.*' )
|
||||
|
||||
env.setWORKING_LIBRARY( '.' )
|
||||
env.addSYSTEM_LIBRARY ( library=cellsTop+'/sxlib' , mode=Environment.Append )
|
||||
|
|
|
@ -43,6 +43,7 @@ env.setGROUND ( 'vss' )
|
|||
env.setCLOCK ( '.*ck.*|.*nck.*' )
|
||||
env.setBLOCKAGE ( 'blockage[Nn]et.*' )
|
||||
env.setPad ( '.*_mpx$' )
|
||||
env.setRegister ( 'sff.*' )
|
||||
|
||||
env.setWORKING_LIBRARY( '.' )
|
||||
env.addSYSTEM_LIBRARY ( library=cellsTop+'/nsxlib', mode=Environment.Append )
|
||||
|
|
|
@ -191,8 +191,9 @@ namespace CRL {
|
|||
bool ToolEngine::_inDestroyAll = false;
|
||||
|
||||
|
||||
ToolEngine::ToolEngine ( Cell* cell )
|
||||
ToolEngine::ToolEngine ( Cell* cell, bool verbose )
|
||||
: Super()
|
||||
, _verbose (verbose)
|
||||
, _cell (cell)
|
||||
, _placementModificationFlag(0)
|
||||
, _routingModificationFlag (0)
|
||||
|
@ -219,11 +220,13 @@ namespace CRL {
|
|||
|
||||
put( enginesRelation );
|
||||
|
||||
cmess1 << " o Creating ToolEngine<" << getName() << "> for Cell <"
|
||||
<< _cell->getName() << ">" << endl;
|
||||
|
||||
cmess1 << Dots::asString( " - Initial memory"
|
||||
, Timer::getStringMemory(Timer::getMemorySize()) ) << endl;
|
||||
if (_verbose) {
|
||||
cmess1 << " o Creating ToolEngine<" << getName() << "> for Cell <"
|
||||
<< _cell->getName() << ">" << endl;
|
||||
|
||||
cmess1 << Dots::asString( " - Initial memory"
|
||||
, Timer::getStringMemory(Timer::getMemorySize()) ) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,8 +29,9 @@ namespace CRL {
|
|||
|
||||
class LefImport {
|
||||
public:
|
||||
static void reset ();
|
||||
static Hurricane::Library* load ( std::string fileName );
|
||||
static void reset ();
|
||||
static Hurricane::Library* load ( std::string fileName );
|
||||
static void setMergeLibrary ( Hurricane::Library* );
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -81,13 +81,14 @@ namespace CRL {
|
|||
protected:
|
||||
Cell* _cell;
|
||||
private:
|
||||
bool _verbose;
|
||||
unsigned int _placementModificationFlag;
|
||||
unsigned int _routingModificationFlag;
|
||||
bool _inRelationDestroy;
|
||||
Timer _timer;
|
||||
uint32_t _passNumber;
|
||||
protected:
|
||||
ToolEngine ( Cell* cell );
|
||||
ToolEngine ( Cell* cell, bool verbose=true );
|
||||
virtual void _postCreate ();
|
||||
virtual void _preDestroy ();
|
||||
protected:
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "hurricane/Contact.h"
|
||||
#include "hurricane/Horizontal.h"
|
||||
#include "hurricane/Vertical.h"
|
||||
#include "hurricane/Rectilinear.h"
|
||||
#include "hurricane/Cell.h"
|
||||
#include "hurricane/Library.h"
|
||||
#include "hurricane/UpdateSession.h"
|
||||
|
@ -71,6 +72,7 @@ namespace {
|
|||
|
||||
class LefParser {
|
||||
public:
|
||||
static void setMergeLibrary ( Library* );
|
||||
static DbU::Unit fromLefUnits ( int );
|
||||
static Layer* getLayer ( string );
|
||||
static void addLayer ( string, Layer* );
|
||||
|
@ -121,6 +123,7 @@ namespace {
|
|||
void _pinStdPostProcess ();
|
||||
void _pinPadPostProcess ();
|
||||
private:
|
||||
static Library* _mergeLibrary;
|
||||
string _file;
|
||||
string _libraryName;
|
||||
Library* _library;
|
||||
|
@ -174,11 +177,16 @@ namespace {
|
|||
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();
|
||||
|
@ -272,6 +280,11 @@ namespace {
|
|||
|
||||
Library* LefParser::createLibrary ()
|
||||
{
|
||||
if (_mergeLibrary) {
|
||||
_library = _mergeLibrary;
|
||||
return _library;
|
||||
}
|
||||
|
||||
DataBase* db = DataBase::getDB();
|
||||
Library* rootLibrary = db->getRootLibrary();
|
||||
if (not rootLibrary) rootLibrary = Library::create( db, "RootLibrary" );
|
||||
|
@ -499,6 +512,17 @@ 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]) ));
|
||||
}
|
||||
Rectilinear::create( blockageNet, blockageLayer, points );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -647,6 +671,16 @@ namespace {
|
|||
//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]) ));
|
||||
}
|
||||
Rectilinear::create( net, layer, points );
|
||||
continue;
|
||||
}
|
||||
if (geoms->itemType(igeom) == lefiGeomClassE) {
|
||||
// Ignore CLASS <site>. Deduced from segments positions.
|
||||
continue;
|
||||
|
@ -963,4 +997,12 @@ namespace CRL {
|
|||
}
|
||||
|
||||
|
||||
void LefImport::setMergeLibrary ( Library* library )
|
||||
{
|
||||
#if defined(HAVE_LEFDEF)
|
||||
LefParser::setMergeLibrary( library );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
} // End of CRL namespace.
|
||||
|
|
|
@ -43,6 +43,8 @@ namespace CRL {
|
|||
using Isobar::ParseTwoArg;
|
||||
using Isobar::__cs;
|
||||
using Isobar::PyLibrary_Link;
|
||||
using Isobar::PyTypeLibrary;
|
||||
using Isobar::PyLibrary;
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
@ -86,14 +88,37 @@ extern "C" {
|
|||
}
|
||||
|
||||
|
||||
static PyObject* PyLefImport_setMergeLibrary ( PyObject*, PyObject* args )
|
||||
{
|
||||
cdebug_log(30,0) << "PyLefImport_setMergeLibrary()" << endl;
|
||||
HTRY
|
||||
PyObject* pyLibrary = NULL;
|
||||
if (PyArg_ParseTuple( args, "O:LefImport.setMergeLibrary", &pyLibrary )) {
|
||||
if (IsPyLibrary(pyLibrary)) {
|
||||
LefImport::setMergeLibrary( PYLIBRARY_O(pyLibrary) );
|
||||
} else {
|
||||
PyErr_SetString( ConstructorError, "LefImport.setMergeLibrary(): Bad parameter type (not a Library)." );
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
PyErr_SetString( ConstructorError, "LefImport.setMergeLibrary(): Bad number of parameters." );
|
||||
return NULL;
|
||||
}
|
||||
HCATCH
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
// Standart Destroy (Attribute).
|
||||
|
||||
|
||||
PyMethodDef PyLefImport_Methods[] =
|
||||
{ { "load" , (PyCFunction)PyLefImport_load , METH_VARARGS|METH_STATIC
|
||||
{ { "load" , (PyCFunction)PyLefImport_load , METH_VARARGS|METH_STATIC
|
||||
, "Load a complete Cadence LEF library." }
|
||||
, { "reset" , (PyCFunction)PyLefImport_reset , METH_NOARGS|METH_STATIC
|
||||
, { "reset" , (PyCFunction)PyLefImport_reset , METH_NOARGS|METH_STATIC
|
||||
, "Reset the Cadence LEF parser (clear technology)." }
|
||||
, { "setMergeLibrary" , (PyCFunction)PyLefImport_setMergeLibrary, METH_VARARGS|METH_STATIC
|
||||
, "Merge into this library instead of creating a new one." }
|
||||
//, { "destroy" , (PyCFunction)PyLefImport_destroy , METH_VARARGS
|
||||
// , "Destroy the associated hurricane object. The python object remains." }
|
||||
, {NULL, NULL, 0, NULL} /* sentinel */
|
||||
|
|
|
@ -64,7 +64,7 @@ class PnR ( FlowTask ):
|
|||
else:
|
||||
print( 'PnR.doTask() run in interactive CGT mode.' )
|
||||
PnR.textMode = False
|
||||
from .. import Etesian, Anabatic, Katana, Bora, Tutorial, Viewer, Unicorn
|
||||
from .. import Etesian, Anabatic, Katana, Bora, Tramontana, Tutorial, Viewer, Unicorn
|
||||
|
||||
ShellEnv().export()
|
||||
if self.script and not callable(self.script):
|
||||
|
@ -80,8 +80,8 @@ class PnR ( FlowTask ):
|
|||
unicorn = Unicorn.UnicornGui.create()
|
||||
unicorn.setApplicationName ( 'cgt')
|
||||
unicorn.registerTool ( Etesian.GraphicEtesianEngine.grab() )
|
||||
#unicorn.registerTool ( Kite.GraphicKiteEngine.grab() )
|
||||
unicorn.registerTool ( Katana.GraphicKatanaEngine.grab() )
|
||||
unicorn.registerTool ( Tramontana.GraphicTramontanaEngine.grab() )
|
||||
unicorn.registerTool ( Bora.GraphicBoraEngine.grab() )
|
||||
unicorn.registerTool ( Tutorial.GraphicTutorialEngine.grab() )
|
||||
#unicorn.setAnonNetSelectable(False)
|
||||
|
|
|
@ -69,7 +69,13 @@ class ShellEnv ( object ):
|
|||
self.shellEnv[ 'MBK_CATAL_NAME' ] = env.getCATALOG()
|
||||
self.shellEnv[ 'RDS_IN' ] = 'gds'
|
||||
self.shellEnv[ 'RDS_OUT' ] = 'gds'
|
||||
self.shellEnv[ 'ALLIANCE_TOP' ] = ShellEnv.ALLIANCE_TOP
|
||||
if ShellEnv.ALLIANCE_TOP:
|
||||
self.shellEnv[ 'ALLIANCE_TOP' ] = ShellEnv.ALLIANCE_TOP
|
||||
libPath = ShellEnv.ALLIANCE_TOP + '/lib'
|
||||
LD_LIBRARY_PATH = os.environ[ 'LD_LIBRARY_PATH' ]
|
||||
if LD_LIBRARY_PATH != '':
|
||||
libPath += ':' + LD_LIBRARY_PATH
|
||||
self.shellEnv[ 'LD_LIBRARY_PATH' ] = libPath
|
||||
|
||||
def export ( self ):
|
||||
"""
|
||||
|
|
|
@ -42,15 +42,16 @@ class Where ( object ):
|
|||
return '<Where coriolisTop="{}">'.format( Where.coriolisTop.as_posix() )
|
||||
|
||||
|
||||
def setupCMOS ():
|
||||
def setupCMOS ( checkToolkit=None ):
|
||||
Where( checkToolkit )
|
||||
ShellEnv().export()
|
||||
|
||||
from .. import Cfg
|
||||
from .. import Viewer
|
||||
from .. import CRL
|
||||
from ..helpers import overlay, l, u, n
|
||||
from .yosys import Yosys
|
||||
import coriolis.technos.symbolic.cmos
|
||||
|
||||
Where()
|
||||
|
||||
with overlay.CfgCache(priority=Cfg.Parameter.Priority.UserFile) as cfg:
|
||||
cfg.misc.catchCore = False
|
||||
|
@ -189,6 +190,7 @@ def setupSky130_c4m ( checkToolkit=None, pdkMasterTop=None ):
|
|||
cfg.misc.logMode = True
|
||||
cfg.misc.verboseLevel1 = False
|
||||
cfg.misc.verboseLevel2 = False
|
||||
cfg.viewer.pixelThreshold = 5
|
||||
cfg.etesian.graphics = 2
|
||||
cfg.anabatic.topRoutingLayer = 'm4'
|
||||
cfg.katana.eventsLimit = 4000000
|
||||
|
@ -294,7 +296,7 @@ def setupTSMC_c180_c4m ( checkToolkit=None, ndaTop=None ):
|
|||
cfg.misc.verboseLevel1 = True
|
||||
cfg.misc.verboseLevel2 = True
|
||||
cfg.etesian.graphics = 3
|
||||
cfg.etesian.uniformDensity = True
|
||||
cfg.etesian.densityVariation = 0.04
|
||||
cfg.etesian.spaceMargin = 0.04
|
||||
cfg.katana.eventsLimit = 4000000
|
||||
af = CRL.AllianceFramework.get()
|
||||
|
@ -303,3 +305,52 @@ def setupTSMC_c180_c4m ( checkToolkit=None, ndaTop=None ):
|
|||
|
||||
Yosys.setLiberty( liberty )
|
||||
ShellEnv.CHECK_TOOLKIT = Where.checkToolkit.as_posix()
|
||||
|
||||
|
||||
def setupGF180MCU_GF ( checkToolkit=None, pdkTop=None ):
|
||||
from .. import Cfg
|
||||
from .. import Viewer
|
||||
from .. import CRL
|
||||
from ..helpers import setNdaTopDir, overlay, l, u, n
|
||||
from .yosys import Yosys
|
||||
|
||||
if isinstance(pdkTop,str):
|
||||
pdkTop = Path( pdkTop )
|
||||
if not pdkTop:
|
||||
print( '[ERROR] technos.setupGF180MCU_GF(): pdkTop directory has *not* been set.' )
|
||||
if not pdkTop.is_dir():
|
||||
print( '[ERROR] technos.setupSky130_c4m(): pdkTop directory do *not* exists:' )
|
||||
print( ' "{}"'.format(pdkTop.as_posix()) )
|
||||
|
||||
Where( checkToolkit )
|
||||
|
||||
cellsTop = pdkTop / 'libraries' / 'gf180mcu_fd_sc_mcu9t5v0' / 'latest' / 'cells'
|
||||
#liberty = pdkTop / 'libraries' / 'gf180mcu_fd_sc_mcu9t5v0' / 'latest' / 'liberty' / 'gf180mcu_fd_sc_mcu9t5v0__tt_025C_5v00.lib'
|
||||
liberty = pdkTop / 'FULL.lib'
|
||||
|
||||
from coriolis.technos.node180.gf180mcu import techno
|
||||
from coriolis.technos.node180.gf180mcu import mcu9t5v0
|
||||
techno.setup()
|
||||
mcu9t5v0.setup( cellsTop )
|
||||
|
||||
with overlay.CfgCache(priority=Cfg.Parameter.Priority.UserFile) as cfg:
|
||||
cfg.misc.catchCore = False
|
||||
cfg.misc.minTraceLevel = 12300
|
||||
cfg.misc.maxTraceLevel = 12400
|
||||
cfg.misc.info = False
|
||||
cfg.misc.paranoid = False
|
||||
cfg.misc.bug = False
|
||||
cfg.misc.logMode = True
|
||||
cfg.misc.verboseLevel1 = False
|
||||
cfg.misc.verboseLevel2 = False
|
||||
cfg.etesian.graphics = 2
|
||||
cfg.anabatic.topRoutingLayer = 'm4'
|
||||
cfg.katana.eventsLimit = 4000000
|
||||
af = CRL.AllianceFramework.get()
|
||||
#lg5 = af.getRoutingGauge( 'mcu9t' ).getLayerGauge( 5 )
|
||||
#lg5.setType( CRL.RoutingLayerGauge.PowerSupply )
|
||||
env = af.getEnvironment()
|
||||
env.setCLOCK( '^sys_clk$|^ck|^jtag_tck$' )
|
||||
|
||||
Yosys.setLiberty( liberty )
|
||||
ShellEnv.CHECK_TOOLKIT = Where.checkToolkit.as_posix()
|
||||
|
|
|
@ -36,15 +36,15 @@ You can configure the placer in two ways:
|
|||
.. code-block:: Python
|
||||
|
||||
with overlay.CfgCache(priority=Cfg.Parameter.Priority.UserFile) as cfg:
|
||||
cfg.etesian.effort = 2
|
||||
cfg.etesian.uniformDensity = True
|
||||
cfg.etesian.spaceMargin = 0.8
|
||||
cfg.etesian.aspectRatio = 1.0
|
||||
cfg.etesian.effort = 2
|
||||
cfg.etesian.spaceMargin = 0.8
|
||||
cfg.etesian.densityVariation = 0.1
|
||||
cfg.etesian.aspectRatio = 1.0
|
||||
|
||||
|
||||
With this setup, the cells will be spread uniformally over the
|
||||
area (``etesian.uniformDensity``), with ``80%`` of free space
|
||||
added and an aspect ratio of ``100%`` (square shape).
|
||||
With this setup, the placement will have ``80%`` of free space added and
|
||||
an aspect ratio of ``100%`` (square shape). Some variations in density
|
||||
is allowed, with at most ``10%`` unused space.
|
||||
|
||||
|
||||
8.1 Router -- Katana
|
||||
|
|
|
@ -176,11 +176,10 @@ Etesian Configuration Parameters
|
|||
| | The extra white space added to the total area |
|
||||
| | of the standard cells |
|
||||
+-----------------------------------+------------------+----------------------------+
|
||||
|``etesian.uniformDensity`` | TypeBool | :cb:`False` |
|
||||
|``etesian.densityVariation`` | TypePercentage | :cb:`5` |
|
||||
| +------------------+----------------------------+
|
||||
| | Whether the cells will be spread envenly |
|
||||
| | across the area or allowed to form denser |
|
||||
| | clusters |
|
||||
| | Control deviation from uniform density in the |
|
||||
| | placement, as a percentage of area. |
|
||||
+-----------------------------------+------------------+----------------------------+
|
||||
|``etesian.effort`` | TypeInt | :cb:`2` |
|
||||
| +------------------+----------------------------+
|
||||
|
|
|
@ -24,8 +24,8 @@ with overlay.CfgCache(priority=Cfg.Parameter.Priority.UserFile) as cfg:
|
|||
cfg.misc.minTraceLevel = 1900
|
||||
cfg.misc.maxTraceLevel = 3000
|
||||
cfg.etesian.effort = 2
|
||||
cfg.etesian.uniformDensity = True
|
||||
cfg.etesian.spaceMargin = 0.8
|
||||
cfg.etesian.densityVariation = 0.1
|
||||
cfg.etesian.aspectRatio = 1.0
|
||||
cfg.katana.eventsLimit = 1000000
|
||||
cfg.katana.termSatReservedLocal = 6
|
||||
|
|
|
@ -176,11 +176,10 @@ Etesian Configuration Parameters
|
|||
| | The extra white space added to the total area |
|
||||
| | of the standard cells |
|
||||
+-----------------------------------+------------------+----------------------------+
|
||||
|``etesian.uniformDensity`` | TypeBool | :cb:`False` |
|
||||
|``etesian.densityVariation`` | TypePercentage | :cb:`5` |
|
||||
| +------------------+----------------------------+
|
||||
| | Whether the cells will be spread envenly |
|
||||
| | across the area or allowed to form denser |
|
||||
| | clusters |
|
||||
| | Control deviation from uniform density in the |
|
||||
| | placement, as a percentage of area. |
|
||||
+-----------------------------------+------------------+----------------------------+
|
||||
|``etesian.effort`` | TypeInt | :cb:`2` |
|
||||
| +------------------+----------------------------+
|
||||
|
|
|
@ -56,13 +56,11 @@ namespace Etesian {
|
|||
, _placeEffort ( static_cast<Effort>
|
||||
(Cfg::getParamEnumerate ("etesian.effort" , Standard )->asInt()) )
|
||||
, _updateConf ( static_cast<GraphicUpdate>
|
||||
(Cfg::getParamEnumerate ("etesian.graphics" , LowerBound )->asInt()) )
|
||||
, _spreadingConf ( Cfg::getParamBool ("etesian.uniformDensity" , false )->asBool()? ForceUniform : MaxDensity )
|
||||
(Cfg::getParamEnumerate ("etesian.graphics" , FinalOnly )->asInt()) )
|
||||
, _routingDriven ( Cfg::getParamBool ("etesian.routingDriven" , false )->asBool())
|
||||
, _spaceMargin ( Cfg::getParamPercentage("etesian.spaceMargin" , 5.0)->asDouble() )
|
||||
, _densityVariation ( Cfg::getParamPercentage("etesian.densityVariation", 5.0)->asDouble() )
|
||||
, _aspectRatio ( Cfg::getParamPercentage("etesian.aspectRatio" ,100.0)->asDouble() )
|
||||
, _antennaInsertThreshold
|
||||
( Cfg::getParamDouble ("etesian.antennaInsertThreshold", 50.0)->asDouble() )
|
||||
, _tieName ( Cfg::getParamString ("etesian.tieName" ,"tie_x0" )->asString() )
|
||||
, _feedNames ( Cfg::getParamString ("etesian.feedNames" ,"tie_x0,rowend_x0")->asString() )
|
||||
, _diodeName ( Cfg::getParamString ("etesian.diodeName" ,"dio_x0" )->asString() )
|
||||
|
@ -107,18 +105,17 @@ namespace Etesian {
|
|||
, _cg (NULL)
|
||||
, _placeEffort ( other._placeEffort )
|
||||
, _updateConf ( other._updateConf )
|
||||
, _spreadingConf ( other._spreadingConf )
|
||||
, _spaceMargin ( other._spaceMargin )
|
||||
, _densityVariation ( other._densityVariation)
|
||||
, _aspectRatio ( other._aspectRatio )
|
||||
, _antennaInsertThreshold( other._antennaInsertThreshold )
|
||||
, _tieName ( other._tieName )
|
||||
, _feedNames ( other._feedNames )
|
||||
, _diodeName ( other._diodeName )
|
||||
, _spareBufferName ( other._spareBufferName )
|
||||
, _bloat ( other._bloat )
|
||||
, _latchUpDistance ( other._latchUpDistance )
|
||||
, _antennaGateMaxWL ( other._antennaGateMaxWL )
|
||||
, _antennaDiodeMaxWL( other._antennaDiodeMaxWL )
|
||||
, _antennaGateMaxWL ( other._antennaGateMaxWL )
|
||||
, _antennaDiodeMaxWL( other._antennaDiodeMaxWL)
|
||||
{
|
||||
if (other._rg) _rg = other._rg->getClone();
|
||||
if (other._cg) _cg = other._cg->getClone();
|
||||
|
@ -141,12 +138,11 @@ namespace Etesian {
|
|||
cmess1 << Dots::asIdentifier(" - Cell Gauge" ,getString(_cg->getName())) << endl;
|
||||
cmess1 << Dots::asInt (" - Place Effort" ,_placeEffort ) << endl;
|
||||
cmess1 << Dots::asInt (" - Update Conf" ,_updateConf ) << endl;
|
||||
cmess1 << Dots::asInt (" - Spreading Conf" ,_spreadingConf ) << endl;
|
||||
cmess1 << Dots::asBool (" - Routing driven" ,_routingDriven ) << endl;
|
||||
cmess1 << Dots::asPercentage(" - Space Margin" ,_spaceMargin ) << endl;
|
||||
cmess1 << Dots::asPercentage(" - Spread Margin" ,_densityVariation ) << endl;
|
||||
cmess1 << Dots::asPercentage(" - Aspect Ratio" ,_aspectRatio ) << endl;
|
||||
cmess1 << Dots::asString (" - Bloat model" ,_bloat ) << endl;
|
||||
cmess1 << Dots::asPercentage(" - Antenna Insert" ,_antennaInsertThreshold ) << endl;
|
||||
cmess1 << Dots::asString (" - Antenna gate Max. WL" ,DbU::getValueString(_antennaGateMaxWL )) << endl;
|
||||
cmess1 << Dots::asString (" - Antenna diode Max. WL",DbU::getValueString(_antennaDiodeMaxWL)) << endl;
|
||||
cmess1 << Dots::asString (" - Latch up Distance",DbU::getValueString(_latchUpDistance)) << endl;
|
||||
|
@ -174,11 +170,10 @@ namespace Etesian {
|
|||
record->add ( getSlot( "_cg" , _cg ) );
|
||||
record->add ( getSlot( "_placeEffort" , (int)_placeEffort ) );
|
||||
record->add ( getSlot( "_updateConf" , (int)_updateConf ) );
|
||||
record->add ( getSlot( "_spreadingConf" , (int)_spreadingConf ) );
|
||||
record->add ( getSlot( "_spaceMargin" , _spaceMargin ) );
|
||||
record->add ( getSlot( "_densityVariation" , _densityVariation ) );
|
||||
record->add ( getSlot( "_aspectRatio" , _aspectRatio ) );
|
||||
record->add ( getSlot( "_antennaInsertThreshold", _antennaInsertThreshold ) );
|
||||
record->add ( getSlot( "_tieName" , _tieName ) );
|
||||
record->add ( getSlot( "_tieName" , _tieName ) );
|
||||
record->add ( getSlot( "_feedNames" , _feedNames ) );
|
||||
record->add ( getSlot( "_diodeName" , _diodeName ) );
|
||||
record->add ( getSlot( "_spareBufferName" , _spareBufferName ) );
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -81,6 +81,7 @@ extern "C" {
|
|||
DirectSetLongAttribute (PyEtesianEngine_setFixedAbHeight,setFixedAbHeight,PyEtesianEngine,EtesianEngine)
|
||||
DirectSetLongAttribute (PyEtesianEngine_setFixedAbWidth ,setFixedAbWidth ,PyEtesianEngine,EtesianEngine)
|
||||
DirectSetDoubleAttribute (PyEtesianEngine_setSpaceMargin ,setSpaceMargin ,PyEtesianEngine,EtesianEngine)
|
||||
DirectSetDoubleAttribute (PyEtesianEngine_setDensityVariation,setDensityVariation ,PyEtesianEngine,EtesianEngine)
|
||||
DirectSetDoubleAttribute (PyEtesianEngine_setAspectRatio ,setAspectRatio ,PyEtesianEngine,EtesianEngine)
|
||||
DirectGetLongAttribute (PyEtesianEngine_getFixedAbHeight,getFixedAbHeight,PyEtesianEngine,EtesianEngine)
|
||||
DirectGetLongAttribute (PyEtesianEngine_getFixedAbWidth ,getFixedAbWidth ,PyEtesianEngine,EtesianEngine)
|
||||
|
@ -273,6 +274,8 @@ extern "C" {
|
|||
, "Use this width when computing the size of the default abutment box (disable aspect ratio)." }
|
||||
, { "setSpaceMargin" , (PyCFunction)PyEtesianEngine_setSpaceMargin , METH_VARARGS
|
||||
, "Override the configuration space margin parameter value." }
|
||||
, { "setDensityVariation" , (PyCFunction)PyEtesianEngine_setDensityVariation, METH_VARARGS
|
||||
, "Override the configuration density variation parameter value." }
|
||||
, { "setAspectRatio" , (PyCFunction)PyEtesianEngine_setAspectRatio , METH_VARARGS
|
||||
, "Override the configuration aspect ratio parameter value." }
|
||||
, { "resetPlacement" , (PyCFunction)PyEtesianEngine_resetPlacement , METH_NOARGS
|
||||
|
|
|
@ -40,17 +40,14 @@ namespace Etesian {
|
|||
// Class : "Etesian::Configuration".
|
||||
|
||||
enum Effort { Fast =1
|
||||
, Standard=2
|
||||
, High =3
|
||||
, Extreme =4
|
||||
, Standard=3
|
||||
, High =6
|
||||
, Extreme =9
|
||||
};
|
||||
enum GraphicUpdate { UpdateAll =1
|
||||
, LowerBound=2
|
||||
, FinalOnly =3
|
||||
};
|
||||
enum Density { ForceUniform=1
|
||||
, MaxDensity =2
|
||||
};
|
||||
|
||||
class Configuration {
|
||||
public:
|
||||
|
@ -63,11 +60,10 @@ namespace Etesian {
|
|||
inline CellGauge* getCellGauge () const;
|
||||
inline Effort getPlaceEffort () const;
|
||||
inline GraphicUpdate getUpdateConf () const;
|
||||
inline Density getSpreadingConf () const;
|
||||
inline bool getRoutingDriven () const;
|
||||
inline double getSpaceMargin () const;
|
||||
inline double getDensityVariation () const;
|
||||
inline double getAspectRatio () const;
|
||||
inline double getAntennaInsertThreshold () const;
|
||||
inline string getTieName () const;
|
||||
inline string getFeedNames () const;
|
||||
inline string getDiodeName () const;
|
||||
|
@ -77,6 +73,7 @@ namespace Etesian {
|
|||
inline DbU::Unit getAntennaGateMaxWL () const;
|
||||
inline DbU::Unit getAntennaDiodeMaxWL () const;
|
||||
inline void setSpaceMargin ( double );
|
||||
inline void setDensityVariation ( double );
|
||||
inline void setAspectRatio ( double );
|
||||
void print ( Cell* ) const;
|
||||
Record* _getRecord () const;
|
||||
|
@ -88,11 +85,10 @@ namespace Etesian {
|
|||
CellGauge* _cg;
|
||||
Effort _placeEffort;
|
||||
GraphicUpdate _updateConf;
|
||||
Density _spreadingConf;
|
||||
bool _routingDriven;
|
||||
double _spaceMargin;
|
||||
double _densityVariation;
|
||||
double _aspectRatio;
|
||||
double _antennaInsertThreshold;
|
||||
string _tieName;
|
||||
string _feedNames;
|
||||
string _diodeName;
|
||||
|
@ -111,11 +107,10 @@ namespace Etesian {
|
|||
inline CellGauge* Configuration::getCellGauge () const { return _cg; }
|
||||
inline Effort Configuration::getPlaceEffort () const { return _placeEffort; }
|
||||
inline GraphicUpdate Configuration::getUpdateConf () const { return _updateConf; }
|
||||
inline Density Configuration::getSpreadingConf () const { return _spreadingConf; }
|
||||
inline bool Configuration::getRoutingDriven () const { return _routingDriven; }
|
||||
inline double Configuration::getSpaceMargin () const { return _spaceMargin; }
|
||||
inline double Configuration::getDensityVariation () const { return _densityVariation; }
|
||||
inline double Configuration::getAspectRatio () const { return _aspectRatio; }
|
||||
inline double Configuration::getAntennaInsertThreshold () const { return _antennaInsertThreshold; }
|
||||
inline string Configuration::getTieName () const { return _tieName; }
|
||||
inline string Configuration::getFeedNames () const { return _feedNames; }
|
||||
inline string Configuration::getDiodeName () const { return _diodeName; }
|
||||
|
@ -125,6 +120,7 @@ namespace Etesian {
|
|||
inline DbU::Unit Configuration::getAntennaGateMaxWL () const { return _antennaGateMaxWL; }
|
||||
inline DbU::Unit Configuration::getAntennaDiodeMaxWL () const { return _antennaDiodeMaxWL; }
|
||||
inline void Configuration::setSpaceMargin ( double margin ) { _spaceMargin = margin; }
|
||||
inline void Configuration::setDensityVariation ( double margin ) { _densityVariation = margin; }
|
||||
inline void Configuration::setAspectRatio ( double ratio ) { _aspectRatio = ratio; }
|
||||
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <tuple>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include "coloquinte/circuit.hxx"
|
||||
#include "coloquinte/coloquinte.hpp"
|
||||
|
||||
#include "hurricane/Timer.h"
|
||||
#include "hurricane/Name.h"
|
||||
|
@ -70,7 +70,6 @@ namespace Etesian {
|
|||
typedef std::tuple<Net*,int32_t,uint32_t> NetInfos;
|
||||
typedef std::tuple<Instance*, std::vector<RoutingPad*> > InstanceInfos;
|
||||
typedef std::map<Instance*,size_t,DBo::CompareById> InstancesToIds;
|
||||
typedef std::map<Net*,size_t,DBo::CompareById> NetsToIds;
|
||||
typedef std::set<std::string> NetNameSet;
|
||||
public:
|
||||
static const Name& staticGetName ();
|
||||
|
@ -91,10 +90,9 @@ namespace Etesian {
|
|||
inline DbU::Unit getFixedAbWidth () const;
|
||||
inline Effort getPlaceEffort () const;
|
||||
inline GraphicUpdate getUpdateConf () const;
|
||||
inline Density getSpreadingConf () const;
|
||||
inline double getSpaceMargin () const;
|
||||
inline double getDensityVariation () const;
|
||||
inline double getAspectRatio () const;
|
||||
inline double getAntennaInsertThreshold () const;
|
||||
inline DbU::Unit getAntennaGateMaxWL () const;
|
||||
inline DbU::Unit getAntennaDiodeMaxWL () const;
|
||||
inline DbU::Unit getLatchUpDistance () const;
|
||||
|
@ -114,6 +112,7 @@ namespace Etesian {
|
|||
inline void setFixedAbHeight ( DbU::Unit );
|
||||
inline void setFixedAbWidth ( DbU::Unit );
|
||||
inline void setSpaceMargin ( double );
|
||||
inline void setDensityVariation ( double );
|
||||
inline void setAspectRatio ( double );
|
||||
void setDefaultAb ();
|
||||
void adjustSliceHeight ();
|
||||
|
@ -131,11 +130,8 @@ namespace Etesian {
|
|||
inline Transformation toBlock ( const Transformation& ) const;
|
||||
void setPlaceArea ( const Box& );
|
||||
size_t toColoquinte ();
|
||||
void preplace ();
|
||||
void roughLegalize ( float minDisruption, unsigned options );
|
||||
void globalPlace ( float initPenalty, float minDisruption, float targetImprovement, float minInc, float maxInc, unsigned options=0 );
|
||||
void detailedPlace ( int iterations, int effort, unsigned options=0 );
|
||||
void antennaProtect ();
|
||||
void globalPlace ();
|
||||
void detailedPlace ();
|
||||
void place ();
|
||||
uint32_t doHFNS ();
|
||||
inline void useFeed ( Cell* );
|
||||
|
@ -160,15 +156,12 @@ namespace Etesian {
|
|||
bool _flatDesign;
|
||||
Box _placeArea;
|
||||
std::vector<Box> _trackAvoids;
|
||||
coloquinte::box<coloquinte::int_t>* _surface;
|
||||
coloquinte::netlist* _circuit;
|
||||
coloquinte::placement_t* _placementLB;
|
||||
coloquinte::placement_t* _placementUB;
|
||||
coloquinte::density_restrictions* _densityLimits;
|
||||
NetsToIds _netsToIds;
|
||||
coloquinte::Rectangle* _surface;
|
||||
coloquinte::Circuit* _circuit;
|
||||
coloquinte::PlacementSolution* _placementLB;
|
||||
coloquinte::PlacementSolution* _placementUB;
|
||||
InstancesToIds _instsToIds;
|
||||
std::vector<InstanceInfos> _idsToInsts;
|
||||
std::vector<NetInfos> _idsToNets;
|
||||
Hurricane::CellViewer* _viewer;
|
||||
Cell* _diodeCell;
|
||||
FeedCells _feedCells;
|
||||
|
@ -195,9 +188,9 @@ namespace Etesian {
|
|||
private:
|
||||
inline uint32_t _getNewDiodeId ();
|
||||
Instance* _createDiode ( Cell* );
|
||||
void _updatePlacement ( const coloquinte::placement_t*, uint32_t flags=0 );
|
||||
void _progressReport1 ( string label ) const;
|
||||
void _progressReport2 ( string label ) const;
|
||||
void _updatePlacement ( const coloquinte::PlacementSolution* );
|
||||
void _coloquinteCallback(coloquinte::PlacementStep step);
|
||||
void _checkNotAFeed ( Occurrence occurrence ) const;
|
||||
};
|
||||
|
||||
|
||||
|
@ -214,10 +207,9 @@ namespace Etesian {
|
|||
inline DbU::Unit EtesianEngine::getFixedAbWidth () const { return _fixedAbWidth; }
|
||||
inline Effort EtesianEngine::getPlaceEffort () const { return getConfiguration()->getPlaceEffort(); }
|
||||
inline GraphicUpdate EtesianEngine::getUpdateConf () const { return getConfiguration()->getUpdateConf(); }
|
||||
inline Density EtesianEngine::getSpreadingConf () const { return getConfiguration()->getSpreadingConf(); }
|
||||
inline double EtesianEngine::getSpaceMargin () const { return getConfiguration()->getSpaceMargin(); }
|
||||
inline double EtesianEngine::getDensityVariation () const { return getConfiguration()->getDensityVariation(); }
|
||||
inline double EtesianEngine::getAspectRatio () const { return getConfiguration()->getAspectRatio(); }
|
||||
inline double EtesianEngine::getAntennaInsertThreshold () const { return getConfiguration()->getAntennaInsertThreshold(); }
|
||||
inline DbU::Unit EtesianEngine::getAntennaGateMaxWL () const { return getConfiguration()->getAntennaGateMaxWL(); }
|
||||
inline DbU::Unit EtesianEngine::getAntennaDiodeMaxWL () const { return getConfiguration()->getAntennaDiodeMaxWL(); }
|
||||
inline DbU::Unit EtesianEngine::getLatchUpDistance () const { return getConfiguration()->getLatchUpDistance(); }
|
||||
|
@ -232,6 +224,7 @@ namespace Etesian {
|
|||
inline void EtesianEngine::setFixedAbHeight ( DbU::Unit abHeight ) { _fixedAbHeight = abHeight; }
|
||||
inline void EtesianEngine::setFixedAbWidth ( DbU::Unit abWidth ) { _fixedAbWidth = abWidth; }
|
||||
inline void EtesianEngine::setSpaceMargin ( double margin ) { getConfiguration()->setSpaceMargin(margin); }
|
||||
inline void EtesianEngine::setDensityVariation ( double margin ) { getConfiguration()->setDensityVariation(margin); }
|
||||
inline void EtesianEngine::setAspectRatio ( double ratio ) { getConfiguration()->setAspectRatio(ratio); }
|
||||
inline DbU::Unit EtesianEngine::toDbU ( int64_t v ) const { return v*getSliceStep(); }
|
||||
inline uint32_t EtesianEngine::_getNewDiodeId () { return _diodeCount++; }
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace Hurricane {
|
|||
#ifdef HAVE_CXA_DEMANGLE
|
||||
|
||||
string demangle ( const char* symbol )
|
||||
{
|
||||
{
|
||||
int status;
|
||||
size_t length = 4096;
|
||||
char demangled[length];
|
||||
|
@ -49,13 +49,25 @@ string demangle ( const char* symbol )
|
|||
#else
|
||||
|
||||
string demangle ( const char* symbol )
|
||||
{
|
||||
return symbol;
|
||||
}
|
||||
{ return symbol; }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
string& split ( string& s )
|
||||
{
|
||||
size_t i = s.find( "<" );
|
||||
while ( i != string::npos ) {
|
||||
if (i+3 > s.size()) break;
|
||||
//if (s[i+2] != '>') {
|
||||
s.insert( i, "\\n" );
|
||||
//}
|
||||
i = s.find( "<", i+3 );
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
} // End of Hurricane namespace.
|
||||
|
||||
|
||||
|
|
|
@ -111,21 +111,21 @@ bool Interval::intersect(const Interval& interval, bool strict) const
|
|||
if (isEmpty() or interval.isEmpty()) return false;
|
||||
if ( (_vMax < interval._vMin) or (interval._vMax < _vMin) ) return false;
|
||||
|
||||
return not strict or ( (_vMax != interval._vMin) and (interval._vMax != _vMin) );
|
||||
return not strict or ( (_vMax > interval._vMin) or (interval._vMax > _vMin) );
|
||||
}
|
||||
|
||||
bool Interval::inferior(const Interval& interval, bool strict) const
|
||||
// *****************************************************************
|
||||
{
|
||||
if (_vMax < interval._vMin) return true;
|
||||
return not strict and (_vMax == interval._vMin);
|
||||
if (_vMax == interval._vMin) return not strict;
|
||||
return (_vMax < interval._vMin);
|
||||
}
|
||||
|
||||
bool Interval::superior(const Interval& interval, bool strict) const
|
||||
// *****************************************************************
|
||||
{
|
||||
if (_vMin > interval._vMax) return true;
|
||||
return !strict && (_vMin == interval._vMax);
|
||||
return not (strict or (_vMin != interval._vMax));
|
||||
}
|
||||
|
||||
bool Interval::isConstrainedBy(const Interval& interval) const
|
||||
|
|
|
@ -772,15 +772,23 @@ void Net::_preDestroy()
|
|||
cdebug_tabw(18,-1);
|
||||
}
|
||||
|
||||
string Net::_getFlagsAsString() const
|
||||
// **********************************
|
||||
{
|
||||
string ds;
|
||||
ds += ((isDeepNet() ) ? "d" : "-");
|
||||
ds += ((_isExternal ) ? "e" : "-");
|
||||
ds += ((_isGlobal ) ? "g" : "-");
|
||||
ds += ((_isAutomatic) ? "a" : "-");
|
||||
return ds;
|
||||
}
|
||||
|
||||
string Net::_getString() const
|
||||
// ***************************
|
||||
{
|
||||
string bs = Inherit::_getString();
|
||||
string ds = "\"" + getString(_name) + "\" ";
|
||||
ds += ((isDeepNet() ) ? "d" : "-");
|
||||
ds += ((_isExternal ) ? "e" : "-");
|
||||
ds += ((_isGlobal ) ? "g" : "-");
|
||||
ds += ((_isAutomatic) ? "a" : "-");
|
||||
ds += _getFlagsAsString();
|
||||
ds += " ";
|
||||
ds += getString(_type ) + " ";
|
||||
ds += getString(_direction);
|
||||
|
|
|
@ -96,16 +96,27 @@ bool Occurrence::operator!=(const Occurrence& occurrence) const
|
|||
bool Occurrence::operator<(const Occurrence& occurrence) const
|
||||
// ********************************************************
|
||||
{
|
||||
if (not _entity and not occurrence._entity) return false;
|
||||
if (not _entity) return true;
|
||||
if (not occurrence._entity) return false;
|
||||
cdebug_log(0,0) << "Occurrence::operator<()" << endl;
|
||||
cdebug_log(0,0) << "| lhs=" << *this << endl;
|
||||
cdebug_log(0,0) << "| rhs=" << occurrence << endl;
|
||||
if ((not _sharedPath) xor (not occurrence._sharedPath)) return not _sharedPath;
|
||||
if ((not _entity ) xor (not occurrence._entity )) return not _entity;
|
||||
if (_entity and (_entity->getId() != occurrence._entity->getId()))
|
||||
return _entity->getId() < occurrence._entity->getId();
|
||||
if (not _sharedPath) return false;
|
||||
|
||||
if (_entity->getId() < occurrence._entity->getId()) return true;
|
||||
if (_entity->getId() > occurrence._entity->getId()) return false;
|
||||
// if (not _sharedPath) return true;
|
||||
// if (not occurrence._sharedPath) return false;
|
||||
// if (not _sharedPath and not occurrence._sharedPath) return false;
|
||||
// if (not _sharedPath) return true;
|
||||
// if (not occurrence._sharedPath) return false;
|
||||
|
||||
if (not _sharedPath and not occurrence._sharedPath) return false;
|
||||
if (not _sharedPath) return true;
|
||||
if (not occurrence._sharedPath) return false;
|
||||
// if (not _entity and not occurrence._entity) return false;
|
||||
// if (not _entity) return true;
|
||||
// if (not occurrence._entity) return false;
|
||||
|
||||
// if (_entity->getId() < occurrence._entity->getId()) return true;
|
||||
// if (_entity->getId() > occurrence._entity->getId()) return false;
|
||||
|
||||
return _sharedPath->getHash() < occurrence._sharedPath->getHash();
|
||||
|
||||
|
@ -274,11 +285,12 @@ string Occurrence::_getString() const
|
|||
string Occurrence::getCompactString() const
|
||||
// ****************************************
|
||||
{
|
||||
string s = "<";
|
||||
string s;
|
||||
if (_entity) {
|
||||
s += getString(getOwnerCell()->getName());
|
||||
s += ":";
|
||||
if (_sharedPath) s += getString(_sharedPath->getName()) + ":";
|
||||
if (_sharedPath) s += getString(_sharedPath->getName());
|
||||
s += ":";
|
||||
Instance* instance = dynamic_cast<Instance*>(_entity);
|
||||
if (instance) {
|
||||
s += "I."+getString(instance->getName());
|
||||
|
@ -291,7 +303,6 @@ string Occurrence::getCompactString() const
|
|||
}
|
||||
}
|
||||
}
|
||||
s += ">";
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,284 @@
|
|||
#include "hurricane/Warning.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace std;
|
||||
using Hurricane::DbU;
|
||||
using Hurricane::Point;
|
||||
using Hurricane::Box;
|
||||
using Hurricane::Interval;
|
||||
using Hurricane::Rectilinear;
|
||||
|
||||
|
||||
class SweepInterval : public Interval {
|
||||
public:
|
||||
inline SweepInterval ( DbU::Unit vmin , DbU::Unit vmax, DbU::Unit xmin );
|
||||
inline SweepInterval ( Interval&, DbU::Unit xmin );
|
||||
inline SweepInterval& inflate ( DbU::Unit dvMin, DbU::Unit dvMax );
|
||||
inline SweepInterval& merge ( DbU::Unit v );
|
||||
inline DbU::Unit getXMin () const;
|
||||
inline void setXMin ( DbU::Unit );
|
||||
inline string _getString () const;
|
||||
private:
|
||||
DbU::Unit _xMin;
|
||||
};
|
||||
|
||||
|
||||
inline SweepInterval::SweepInterval ( DbU::Unit vmin , DbU::Unit vmax, DbU::Unit xmin )
|
||||
: Interval(vmin,vmax)
|
||||
, _xMin (xmin)
|
||||
{ }
|
||||
|
||||
inline SweepInterval::SweepInterval ( Interval& base, DbU::Unit xmin )
|
||||
: Interval(base)
|
||||
, _xMin (xmin)
|
||||
{ }
|
||||
|
||||
inline SweepInterval& SweepInterval::inflate ( DbU::Unit dvMin, DbU::Unit dvMax ) { Interval::inflate(dvMin,dvMax); return *this; }
|
||||
inline SweepInterval& SweepInterval::merge ( DbU::Unit v ) { Interval::merge(v); return *this; }
|
||||
inline DbU::Unit SweepInterval::getXMin () const { return _xMin; }
|
||||
inline void SweepInterval::setXMin ( DbU::Unit xmin ) { _xMin=xmin; }
|
||||
|
||||
inline string SweepInterval::_getString () const
|
||||
{
|
||||
string s;
|
||||
s += "@" + DbU::getValueString(_xMin);
|
||||
s += " [" + DbU::getValueString(getVMin());
|
||||
s += " " + DbU::getValueString(getVMax()) + "]";
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
} // Anonymous namespace.
|
||||
|
||||
|
||||
GETSTRING_VALUE_SUPPORT(::SweepInterval);
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
class SweepLine {
|
||||
public:
|
||||
SweepLine ( const Rectilinear*, vector<Box>& );
|
||||
~SweepLine ();
|
||||
void addVEdge ( DbU::Unit ymin, DbU::Unit ymax, DbU::Unit x );
|
||||
void loadVEdges ();
|
||||
void process ( Interval );
|
||||
void process ( const pair< DbU::Unit, list<Interval> >& );
|
||||
void toBox ( SweepInterval& );
|
||||
void asRectangles ();
|
||||
private:
|
||||
const Rectilinear* _rectilinear;
|
||||
vector<Box>& _boxes;
|
||||
list< pair< DbU::Unit, list<Interval> > > _vedges;
|
||||
list< SweepInterval > _sweepLine;
|
||||
DbU::Unit _prevX;
|
||||
DbU::Unit _currX;
|
||||
};
|
||||
|
||||
|
||||
SweepLine::SweepLine ( const Rectilinear* r, vector<Box>& boxes )
|
||||
: _rectilinear(r)
|
||||
, _boxes (boxes)
|
||||
, _vedges ()
|
||||
, _sweepLine ()
|
||||
, _prevX (0)
|
||||
, _currX (0)
|
||||
{
|
||||
cdebug_log(17,1) << "SweepLine::SweepLine()" << endl;
|
||||
}
|
||||
|
||||
|
||||
SweepLine::~SweepLine ()
|
||||
{
|
||||
cdebug_tabw(17,-1);
|
||||
}
|
||||
|
||||
|
||||
void SweepLine::addVEdge ( DbU::Unit ymin, DbU::Unit ymax, DbU::Unit x )
|
||||
{
|
||||
if (ymin > ymax) std::swap( ymin, ymax );
|
||||
|
||||
cdebug_log(17,1) << "SweepLine::addVEdge() @"<< DbU::getValueString(x)
|
||||
<< " [" << DbU::getValueString(ymin)
|
||||
<< " " << DbU::getValueString(ymax) << "]" << endl;
|
||||
|
||||
bool inserted = false;
|
||||
for ( auto ix = _vedges.begin() ; ix != _vedges.end() ; ++ix ) {
|
||||
cdebug_log(17,0) << "| Looking @" << DbU::getValueString(ix->first)
|
||||
<< " size=" << ix->second.size() << endl;
|
||||
|
||||
if (ix->first > x) {
|
||||
_vedges.insert( ix, make_pair( x, list<Interval>() ));
|
||||
cdebug_log(17,0) << "+ add new @" << DbU::getValueString(x) << endl;
|
||||
--ix;
|
||||
}
|
||||
if (ix->first == x) {
|
||||
for ( auto iintv = ix->second.begin() ; iintv != ix->second.end() ; ++iintv ) {
|
||||
if (iintv->getVMin() >= ymax) {
|
||||
ix->second.insert( iintv, Interval(ymin,ymax) );
|
||||
inserted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (not inserted) {
|
||||
ix->second.push_back( Interval(ymin,ymax) );
|
||||
inserted = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (not inserted) {
|
||||
cdebug_log(17,0) << "+ add new (back) @" << DbU::getValueString(x) << endl;
|
||||
_vedges.push_back( make_pair( x, list<Interval>() ));
|
||||
_vedges.back().second.push_back( Interval(ymin,ymax) );
|
||||
}
|
||||
|
||||
cdebug_tabw(17,-1);
|
||||
}
|
||||
|
||||
|
||||
void SweepLine::loadVEdges ()
|
||||
{
|
||||
const vector<Point>& points = _rectilinear->getPoints();
|
||||
for ( size_t i=0 ; i<points.size()-1 ; ++i ) {
|
||||
const Point& source = points[ i ];
|
||||
const Point& target = points[ (i+1) % points.size() ];
|
||||
DbU::Unit dx = target.getX() - source.getX();
|
||||
//DbU::Unit dy = target.getY() - source.getY();
|
||||
if (dx == 0) {
|
||||
addVEdge( source.getY(), target.getY(), source.getX() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SweepLine::toBox ( SweepInterval& intv )
|
||||
{
|
||||
if (intv.getXMin() == _currX) return;
|
||||
_boxes.push_back( Box( intv.getXMin(), intv.getVMin()
|
||||
, _currX , intv.getVMax() ));
|
||||
intv.setXMin( _currX );
|
||||
}
|
||||
|
||||
|
||||
void SweepLine::process ( Interval v )
|
||||
{
|
||||
cdebug_log(17,1) << "SweepLine::process(Interval&) "
|
||||
<< " [" << DbU::getValueString(v.getVMin())
|
||||
<< " " << DbU::getValueString(v.getVMax()) << "]" << endl;
|
||||
bool done = false;
|
||||
for ( auto iintv = _sweepLine.begin() ; iintv != _sweepLine.end() ; ++iintv ) {
|
||||
// Extractor p. 9 (a).
|
||||
if (v.getVMax() < iintv->getVMin()) {
|
||||
_sweepLine.insert( iintv, SweepInterval(v,_currX) );
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
// Extractor p. 9 (f).
|
||||
if ( (v.getVMin() == iintv->getVMin())
|
||||
and (v.getVMax() == iintv->getVMax()) ) {
|
||||
toBox( *iintv );
|
||||
_sweepLine.erase( iintv );
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
// Extractor p. 9 (b).
|
||||
if (v.getVMax() == iintv->getVMin()) {
|
||||
toBox( *iintv );
|
||||
iintv->merge( v.getVMin() );
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
// Extractor p. 9 (g).
|
||||
if (v.getVMax() == iintv->getVMax()) {
|
||||
toBox( *iintv );
|
||||
cdebug_log(17,0) << "case (g): carve" << endl;
|
||||
iintv->inflate( 0, v.getVMin() - iintv->getVMax() );
|
||||
cdebug_log(17,0) << "| " << (*iintv) << endl;
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
// Extractor p. 9 (h).
|
||||
if (v.getVMin() == iintv->getVMin()) {
|
||||
toBox( *iintv );
|
||||
iintv->inflate(iintv->getVMin() - v.getVMax(), 0 );
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
// Extractor p. 9 (c).
|
||||
if ( (v.getVMin() > iintv->getVMin())
|
||||
and (v.getVMax() < iintv->getVMax()) ) {
|
||||
toBox( *iintv );
|
||||
cdebug_log(17,0) << "case (c): carve" << endl;
|
||||
DbU::Unit wholeVMin = iintv->getVMin();
|
||||
iintv->inflate( iintv->getVMin() - v.getVMax(), 0 );
|
||||
cdebug_log(17,0) << "| " << (*iintv) << endl;
|
||||
_sweepLine.insert( iintv, SweepInterval( wholeVMin, v.getVMin(), _currX ) );
|
||||
cdebug_log(17,0) << "| " << (*(--iintv)) << endl;
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
// Extractor p. 9 (d,e).
|
||||
if (v.getVMin() == iintv->getVMax()) {
|
||||
auto iintvNext = iintv;
|
||||
++iintvNext;
|
||||
// Extractor p. 9 (d).
|
||||
if (iintvNext == _sweepLine.end()) {
|
||||
toBox( *iintv );
|
||||
iintv->merge( v.getVMax() );
|
||||
} else {
|
||||
// Extractor p. 9 (d).
|
||||
if (v.getVMax() < iintvNext->getVMin()) {
|
||||
toBox( *iintv );
|
||||
iintv->merge( v.getVMax() );
|
||||
} else {
|
||||
// Extractor p. 9 (e).
|
||||
toBox( *iintv );
|
||||
toBox( *iintvNext );
|
||||
iintv->merge( iintvNext->getVMax() );
|
||||
_sweepLine.erase( iintvNext );
|
||||
}
|
||||
}
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (not done) {
|
||||
_sweepLine.push_back( SweepInterval(v,_currX) );
|
||||
}
|
||||
|
||||
cdebug_tabw(17,-1);
|
||||
}
|
||||
|
||||
|
||||
void SweepLine::process ( const pair< DbU::Unit, list<Interval> >& intervals )
|
||||
{
|
||||
cdebug_log(17,1) << "SweepLine::process() @"<< DbU::getValueString(intervals.first)
|
||||
<< " size=" << intervals.second.size() << endl;
|
||||
_currX = intervals.first;
|
||||
for ( const Interval& v : intervals.second ) process( v );
|
||||
cdebug_tabw(17,-1);
|
||||
}
|
||||
|
||||
|
||||
void SweepLine::asRectangles ()
|
||||
{
|
||||
loadVEdges();
|
||||
for ( auto intervals : _vedges ) {
|
||||
process( intervals );
|
||||
}
|
||||
cdebug_log(17,0) << "SweepLine::asRectangles() size=" << _boxes.size() << endl;
|
||||
for ( const Box& b : _boxes )
|
||||
cdebug_log(17,0) << "| " << b << endl;
|
||||
}
|
||||
|
||||
|
||||
} // Anonymous namespace.
|
||||
|
||||
|
||||
namespace Hurricane {
|
||||
|
||||
|
||||
|
@ -50,6 +328,7 @@ namespace Hurricane {
|
|||
: Super (net)
|
||||
, _layer (layer)
|
||||
, _points(points)
|
||||
, _flags (IsRectilinear)
|
||||
{ }
|
||||
|
||||
|
||||
|
@ -58,9 +337,21 @@ namespace Hurricane {
|
|||
if (not layer)
|
||||
throw Error( "Rectilinear::create(): Can't create, NULL layer" );
|
||||
|
||||
if (points.size() > 1000)
|
||||
throw Error( "Rectilinear::create(): Rectlinear polygons must not exceed 1000 vertexes." );
|
||||
if (points.size() < 4)
|
||||
throw Error( "Rectilinear::create(): Rectilinear polygons must at least contains 3 vertexes." );
|
||||
|
||||
if (points.size() > 1000)
|
||||
throw Error( "Rectilinear::create(): Rectilinear polygons must not exceed 1000 vertexes." );
|
||||
|
||||
if (points[0] != points[points.size()-1])
|
||||
throw Error( "Rectilinear::create(): First and last point must be the same.\n"
|
||||
"0:%s %d:%s"
|
||||
, getString(points[0]).c_str()
|
||||
, points.size()-1
|
||||
, getString(points[points.size()-1]).c_str()
|
||||
);
|
||||
|
||||
bool isRect = true;
|
||||
DbU::Unit oneGrid = DbU::fromGrid( 1.0 );
|
||||
for ( size_t i=0 ; i<points.size() ; ++i ) {
|
||||
size_t j = (i+1) % points.size();
|
||||
|
@ -68,9 +359,12 @@ namespace Hurricane {
|
|||
DbU::Unit dx = std::abs( points[i].getX() - points[j].getX() );
|
||||
DbU::Unit dy = std::abs( points[i].getY() - points[j].getY() );
|
||||
|
||||
if ( (dx != 0) and (dy != 0) and (dx != dy) )
|
||||
throw Error( "Rectilinear::create(): Can't create, non H/V edge (points %d:%s - %d:%s)."
|
||||
, i, getString(points[i]).c_str(), j, getString(points[j]).c_str() );
|
||||
if ((dx != 0) and (dy != 0)) {
|
||||
isRect = false;
|
||||
if (dx != dy)
|
||||
throw Error( "Rectilinear::create(): Can't create, non H/V edge (points %d:%s - %d:%s)."
|
||||
, i, getString(points[i]).c_str(), j, getString(points[j]).c_str() );
|
||||
}
|
||||
|
||||
if (points[i].getX() % oneGrid)
|
||||
cerr << Warning( "Rectilinear::create(): In Cell \"%s\", Net \"%s\",\n"
|
||||
|
@ -91,7 +385,7 @@ namespace Hurricane {
|
|||
}
|
||||
|
||||
Rectilinear* rectilinear = new Rectilinear ( net, layer, points );
|
||||
|
||||
if (not isRect) rectilinear->_flags &= ~IsRectilinear;
|
||||
rectilinear->_postCreate();
|
||||
|
||||
return rectilinear;
|
||||
|
@ -176,6 +470,15 @@ namespace Hurricane {
|
|||
}
|
||||
|
||||
|
||||
bool Rectilinear::getAsRectangles ( std::vector<Box>& rectangles ) const
|
||||
{
|
||||
rectangles.clear();
|
||||
if (not isRectilinear()) return false;
|
||||
SweepLine( this, rectangles ).asRectangles();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Rectilinear::_toJson ( JsonWriter* writer ) const
|
||||
{
|
||||
Inherit::_toJson( writer );
|
||||
|
|
|
@ -146,6 +146,9 @@ namespace Hurricane {
|
|||
}
|
||||
|
||||
|
||||
string& split ( std::string& );
|
||||
|
||||
|
||||
} // End of Hurricane namespace.
|
||||
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#ifndef HURRICANE_COMPONENT_H
|
||||
#define HURRICANE_COMPONENT_H
|
||||
|
||||
#include <set>
|
||||
#include "hurricane/Points.h"
|
||||
#include "hurricane/Go.h"
|
||||
#include "hurricane/Components.h"
|
||||
|
@ -170,6 +171,9 @@ namespace Hurricane {
|
|||
};
|
||||
|
||||
|
||||
typedef std::set<Component*,DBo::CompareById> ComponentSet;
|
||||
|
||||
|
||||
} // Hurricane namespace.
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// -*- C++ -*-
|
||||
//
|
||||
// Copyright (c) BULL S.A. 2000-2018, All Rights Reserved
|
||||
// Copyright (c) BULL S.A. 2000-2023, All Rights Reserved
|
||||
//
|
||||
// This file is part of Hurricane.
|
||||
//
|
||||
|
@ -29,9 +29,7 @@
|
|||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#ifndef HURRICANE_INTERVAL_H
|
||||
#define HURRICANE_INTERVAL_H
|
||||
|
||||
#pragma once
|
||||
#include "hurricane/DbU.h"
|
||||
|
||||
namespace Hurricane {
|
||||
|
@ -48,6 +46,11 @@ namespace Hurricane {
|
|||
inline bool operator() ( const Interval& rhs, const Interval& lhs ) const;
|
||||
inline bool operator() ( const Interval* rhs, const Interval* lhs ) const;
|
||||
};
|
||||
class CompareByMinMax {
|
||||
public:
|
||||
inline bool operator() ( const Interval& rhs, const Interval& lhs ) const;
|
||||
inline bool operator() ( const Interval* rhs, const Interval* lhs ) const;
|
||||
};
|
||||
public:
|
||||
Interval ( bool makeEmpty=true );
|
||||
Interval ( const DbU::Unit& );
|
||||
|
@ -124,6 +127,20 @@ namespace Hurricane {
|
|||
{ return lhs->getVMin() < rhs->getVMin(); }
|
||||
|
||||
|
||||
inline bool Interval::CompareByMinMax::operator() ( const Interval& lhs, const Interval& rhs ) const
|
||||
{
|
||||
if (lhs.getVMin() != rhs.getVMin()) return lhs.getVMin() < rhs.getVMin();
|
||||
return lhs.getVMax() < rhs.getVMax();
|
||||
}
|
||||
|
||||
|
||||
inline bool Interval::CompareByMinMax::operator() ( const Interval* lhs, const Interval* rhs ) const
|
||||
{
|
||||
if (lhs->getVMin() != rhs->getVMin()) return lhs->getVMin() < rhs->getVMin();
|
||||
return lhs->getVMax() < rhs->getVMax();
|
||||
}
|
||||
|
||||
|
||||
} // Hurricane namespace.
|
||||
|
||||
|
||||
|
@ -136,7 +153,5 @@ inline void jsonWrite ( JsonWriter* w, const std::string& key, const Hurricane:
|
|||
w->endArray();
|
||||
}
|
||||
|
||||
|
||||
INSPECTOR_PR_SUPPORT(Hurricane::Interval);
|
||||
|
||||
|
||||
#endif // HURRICANE_INTERVAL_H
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// -*- C++ -*-
|
||||
//
|
||||
// Copyright (c) BULL S.A. 2018-2018, All Rights Reserved
|
||||
// Copyright (c) BULL S.A. 2018-2023, All Rights Reserved
|
||||
//
|
||||
// This file is part of Hurricane.
|
||||
//
|
||||
|
@ -34,9 +34,7 @@
|
|||
// Third edition, MIT press, 2011, p. 348.
|
||||
|
||||
|
||||
#ifndef HURRICANE_INTERVAL_TREE_H
|
||||
#define HURRICANE_INTERVAL_TREE_H
|
||||
|
||||
#pragma once
|
||||
#include "hurricane/Interval.h"
|
||||
#include "hurricane/RbTree.h"
|
||||
|
||||
|
@ -57,6 +55,7 @@ namespace Hurricane {
|
|||
inline Data& getData () const;
|
||||
inline DbU::Unit getChildsVMax () const;
|
||||
inline DbU::Unit updateChildsVMax ( DbU::Unit lvmax, DbU::Unit rvmax );
|
||||
inline bool operator== ( const IntervalData& ) const;
|
||||
string _getString () const;
|
||||
Record* _getRecord () const;
|
||||
private:
|
||||
|
@ -64,7 +63,7 @@ namespace Hurricane {
|
|||
Data data_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template< typename Data >
|
||||
inline IntervalData<Data>::IntervalData ()
|
||||
: Interval(1,-1)
|
||||
|
@ -93,7 +92,17 @@ namespace Hurricane {
|
|||
|
||||
template< typename Data >
|
||||
inline DbU::Unit IntervalData<Data>::updateChildsVMax ( DbU::Unit lvmax, DbU::Unit rvmax )
|
||||
{ childsVMax_ = std::max( getVMax(), std::max( lvmax, rvmax ) ); return childsVMax_; }
|
||||
{
|
||||
cdebug_log(0,0) << "IntervalData::updateChildsVMax() " << DbU::getValueString(lvmax)
|
||||
<< " " << DbU::getValueString(lvmax)
|
||||
<< " " << this << endl;
|
||||
childsVMax_ = std::max( getVMax(), std::max( lvmax, rvmax ) ); return childsVMax_;
|
||||
}
|
||||
|
||||
|
||||
template< typename Data >
|
||||
inline bool IntervalData<Data>::operator== ( const IntervalData<Data>& other ) const
|
||||
{ return Interval::operator==(*this) and (data_ == other.data_); }
|
||||
|
||||
|
||||
template< typename Data >
|
||||
|
@ -117,14 +126,35 @@ namespace Hurricane {
|
|||
return record;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "Hurricane::IntervalDataCompare".
|
||||
|
||||
template< typename Data, typename DataCompare=std::less<Data> >
|
||||
class IntervalDataCompare {
|
||||
public:
|
||||
inline bool operator() ( const IntervalData<Data>& lhs, const IntervalData<Data>& rhs ) const
|
||||
{
|
||||
static Interval::CompareByMinMax compare;
|
||||
static DataCompare dataCompare;
|
||||
if ( (lhs.getVMin() == rhs.getVMin())
|
||||
and (lhs.getVMax() == rhs.getVMax())) {
|
||||
cdebug_log(0,0) << "IntervalDataCompare::operator<() - Data fallback." << endl;
|
||||
cdebug_log(0,0) << "| " << lhs.getData() << endl;
|
||||
return dataCompare( lhs.getData(), rhs.getData() );
|
||||
}
|
||||
return compare( lhs, rhs );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "Hurricane::IntervalTree".
|
||||
|
||||
|
||||
template< typename Data >
|
||||
class IntervalTree : public RbTree< IntervalData<Data>, Interval::CompareByMin > {
|
||||
template< typename Data, typename DataCompare=std::less<Data> >
|
||||
class IntervalTree : public RbTree< IntervalData<Data>, IntervalDataCompare<Data,DataCompare> > {
|
||||
public:
|
||||
typedef RbTree< IntervalData<Data>, Interval::CompareByMin > Super;
|
||||
typedef RbTree< IntervalData<Data>, IntervalDataCompare<Data,DataCompare> > Super;
|
||||
public:
|
||||
class overlap_iterator : public Super::iterator {
|
||||
public:
|
||||
|
@ -171,31 +201,39 @@ namespace Hurricane {
|
|||
size_t getThickness () const;
|
||||
overlap_iterator beginOverlaps ( const Interval& ) const;
|
||||
inline OverlapElements getOverlaps ( const Interval& ) const;
|
||||
void checkVMax () const;
|
||||
void checkVMax ( typename Super::Node* node ) const;
|
||||
private:
|
||||
inline void updateChildsVMax ( typename Super::Node* );
|
||||
};
|
||||
|
||||
|
||||
template< typename Data >
|
||||
IntervalTree<Data>::overlap_iterator::overlap_iterator ( const typename Super::Node* node, const Interval& overlap )
|
||||
template< typename Data, typename DataCompare >
|
||||
IntervalTree<Data,DataCompare>::overlap_iterator::overlap_iterator ( const typename Super::Node* node, const Interval& overlap )
|
||||
: Super::iterator(node)
|
||||
, overlap_(overlap)
|
||||
{ }
|
||||
|
||||
|
||||
template< typename Data >
|
||||
typename IntervalTree<Data>::overlap_iterator& IntervalTree<Data>::overlap_iterator::operator++ ()
|
||||
{
|
||||
while (this->isValid()) {
|
||||
cdebug_log(0,0) << "IntervalTree::overlap_iterator CTOR "
|
||||
<< (node ? ::getString(node->getValue()) : "node=NULL")
|
||||
<< " " << overlap << endl;
|
||||
}
|
||||
|
||||
|
||||
template< typename Data, typename DataCompare >
|
||||
typename IntervalTree<Data,DataCompare>::overlap_iterator&
|
||||
IntervalTree<Data,DataCompare>::overlap_iterator::operator++ ()
|
||||
{
|
||||
cdebug_log(0,0) << "IntervalTree::overlap_iterator::operator++()" << endl;
|
||||
while ( true ) {
|
||||
Super::iterator::operator++();
|
||||
if (not this->isValid()) break;
|
||||
|
||||
cdebug_log(0,0) << "IntervalTree::overlap_iterator::operator++() "
|
||||
<< ::getString(this->getNode()) << std::endl;
|
||||
cdebug_log(0,0) << " ==> " << ::getString(this->getNode()->getValue()) << std::endl;
|
||||
|
||||
if (this->getNode()->getValue().intersect(overlap_,true)) break;
|
||||
cdebug_log(0,0) << "NO intersections" << endl;
|
||||
if (overlap_.inferior(this->getNode()->getValue(),true)) {
|
||||
cdebug_log(0,0) << "Node is inferior, stop here." << endl;
|
||||
if (this->getNode()->getValue().intersect(overlap_,false)) break;
|
||||
cdebug_log(0,0) << " NO intersections" << endl;
|
||||
if (overlap_.inferior(this->getNode()->getValue(),false)) {
|
||||
cdebug_log(0,0) << " Node is inferior, stop here." << endl;
|
||||
this->setNode( NULL );
|
||||
break;
|
||||
}
|
||||
|
@ -208,44 +246,45 @@ namespace Hurricane {
|
|||
// Class : "Hurricane::IntervalTree::OverlapOverlapElements" (implementation)
|
||||
|
||||
|
||||
template< typename Data >
|
||||
inline IntervalTree<Data>::OverlapElements::Locator::Locator ( const Locator &locator )
|
||||
template< typename Data, typename DataCompare >
|
||||
inline IntervalTree<Data,DataCompare>::OverlapElements::Locator::Locator ( const Locator &locator )
|
||||
: Hurricane::Locator< IntervalData<Data> >()
|
||||
, iterator_(locator.iterator_)
|
||||
{ }
|
||||
|
||||
|
||||
template< typename Data >
|
||||
IntervalTree<Data>::OverlapElements::Locator::Locator ( const IntervalTree<Data>& tree, const Interval& span )
|
||||
template< typename Data, typename DataCompare >
|
||||
IntervalTree<Data,DataCompare>::OverlapElements::Locator::Locator ( const IntervalTree<Data,DataCompare>& tree, const Interval& span )
|
||||
: Hurricane::Locator< IntervalData<Data> >()
|
||||
, iterator_(tree.beginOverlaps(span))
|
||||
{ }
|
||||
|
||||
|
||||
template< typename Data >
|
||||
typename IntervalTree<Data>::OverlapElements::Locator* IntervalTree<Data>::OverlapElements::Locator::getClone () const
|
||||
template< typename Data, typename DataCompare >
|
||||
typename IntervalTree<Data,DataCompare>::OverlapElements::Locator*
|
||||
IntervalTree<Data,DataCompare>::OverlapElements::Locator::getClone () const
|
||||
{ return new Locator(*this); }
|
||||
|
||||
|
||||
template< typename Data >
|
||||
IntervalData<Data> IntervalTree<Data>::OverlapElements::Locator::getElement () const
|
||||
template< typename Data, typename DataCompare >
|
||||
IntervalData<Data> IntervalTree<Data,DataCompare>::OverlapElements::Locator::getElement () const
|
||||
{ return (*iterator_); }
|
||||
|
||||
|
||||
template< typename Data >
|
||||
bool IntervalTree<Data>::OverlapElements::Locator::isValid () const
|
||||
template< typename Data, typename DataCompare >
|
||||
bool IntervalTree<Data,DataCompare>::OverlapElements::Locator::isValid () const
|
||||
{ return iterator_.isValid(); }
|
||||
|
||||
|
||||
template< typename Data >
|
||||
void IntervalTree<Data>::OverlapElements::Locator::progress ()
|
||||
template< typename Data, typename DataCompare >
|
||||
void IntervalTree<Data,DataCompare>::OverlapElements::Locator::progress ()
|
||||
{
|
||||
if (isValid()) ++iterator_;
|
||||
}
|
||||
|
||||
|
||||
template< typename Data >
|
||||
std::string IntervalTree<Data>::OverlapElements::Locator::_getString () const
|
||||
template< typename Data, typename DataCompare >
|
||||
std::string IntervalTree<Data,DataCompare>::OverlapElements::Locator::_getString () const
|
||||
{
|
||||
std::string s = "<" + _TName("OverlapElements::Locator")
|
||||
+ ">";
|
||||
|
@ -253,34 +292,34 @@ namespace Hurricane {
|
|||
}
|
||||
|
||||
|
||||
template< typename Data >
|
||||
inline IntervalTree<Data>::OverlapElements::OverlapElements ( const IntervalTree& tree, const Interval& span )
|
||||
template< typename Data, typename DataCompare >
|
||||
inline IntervalTree<Data,DataCompare>::OverlapElements::OverlapElements ( const IntervalTree& tree, const Interval& span )
|
||||
: Collection< IntervalData<Data> >()
|
||||
, tree_(tree)
|
||||
, span_(span)
|
||||
{ }
|
||||
|
||||
|
||||
template< typename Data >
|
||||
inline IntervalTree<Data>::OverlapElements::OverlapElements ( const OverlapElements& elements )
|
||||
template< typename Data, typename DataCompare >
|
||||
inline IntervalTree<Data,DataCompare>::OverlapElements::OverlapElements ( const OverlapElements& elements )
|
||||
: Collection< IntervalData<Data> >()
|
||||
, tree_(elements.tree_)
|
||||
, span_(elements.span_)
|
||||
{ }
|
||||
|
||||
|
||||
template< typename Data >
|
||||
Collection< IntervalData<Data> >* IntervalTree<Data>::OverlapElements::getClone () const
|
||||
template< typename Data, typename DataCompare >
|
||||
Collection< IntervalData<Data> >* IntervalTree<Data,DataCompare>::OverlapElements::getClone () const
|
||||
{ return new OverlapElements(*this); }
|
||||
|
||||
|
||||
template< typename Data >
|
||||
typename IntervalTree<Data>::OverlapElements::Locator* IntervalTree<Data>::OverlapElements::getLocator () const
|
||||
template< typename Data, typename DataCompare >
|
||||
typename IntervalTree<Data,DataCompare>::OverlapElements::Locator* IntervalTree<Data,DataCompare>::OverlapElements::getLocator () const
|
||||
{ return new Locator( tree_, span_ ); }
|
||||
|
||||
|
||||
template< typename Data >
|
||||
std::string IntervalTree<Data>::OverlapElements::_getString () const
|
||||
template< typename Data, typename DataCompare >
|
||||
std::string IntervalTree<Data,DataCompare>::OverlapElements::_getString () const
|
||||
{
|
||||
std::string s = "<" + _TName("OverlapElements") + " "
|
||||
+ getString(tree_)
|
||||
|
@ -293,39 +332,45 @@ namespace Hurricane {
|
|||
// Class : "Hurricane::IntervalTree" (implementation).
|
||||
|
||||
|
||||
template< typename Data >
|
||||
inline void IntervalTree<Data>::updateChildsVMax ( typename Super::Node* node )
|
||||
template< typename Data, typename DataCompare >
|
||||
inline void IntervalTree<Data,DataCompare>::updateChildsVMax ( typename Super::Node* node )
|
||||
{
|
||||
cdebug_log(0,1) << "IntervalTree::updateChildsVMax() " << node->getValue() << endl;
|
||||
DbU::Unit lchildVMax = (node->getLeft ()) ? node->getLeft ()->getValue().getChildsVMax() : node->getValue().getVMax();
|
||||
DbU::Unit rchildVMax = (node->getRight()) ? node->getRight()->getValue().getChildsVMax() : node->getValue().getVMax();
|
||||
|
||||
const_cast< IntervalData<Data>& >( node->getValue() ).updateChildsVMax( lchildVMax, rchildVMax );
|
||||
cdebug_tabw(0,-1);
|
||||
}
|
||||
|
||||
|
||||
template< typename Data >
|
||||
void IntervalTree<Data>::postRotateLeft ( typename Super::Node* node )
|
||||
template< typename Data, typename DataCompare >
|
||||
void IntervalTree<Data,DataCompare>::postRotateLeft ( typename Super::Node* node )
|
||||
{
|
||||
cdebug_log(0,1) << "IntervalTree::postRotateLeft() " << node->getValue() << endl;
|
||||
updateChildsVMax( node );
|
||||
if (node->getParent()) updateChildsVMax( node->getParent() );
|
||||
cdebug_tabw(0,-1);
|
||||
}
|
||||
|
||||
|
||||
template< typename Data, typename DataCompare >
|
||||
void IntervalTree<Data,DataCompare>::postRotateRight ( typename Super::Node* node )
|
||||
{
|
||||
cdebug_log(0,0) << "IntervalTree::postRotateRight() " << node->getValue() << endl;
|
||||
updateChildsVMax( node );
|
||||
if (node->getParent()) updateChildsVMax( node->getParent() );
|
||||
}
|
||||
|
||||
|
||||
template< typename Data >
|
||||
void IntervalTree<Data>::postRotateRight ( typename Super::Node* node )
|
||||
template< typename Data, typename DataCompare >
|
||||
void IntervalTree<Data,DataCompare>::postInsert ( typename Super::Node* node )
|
||||
{
|
||||
updateChildsVMax( node );
|
||||
if (node->getParent()) updateChildsVMax( node->getParent() );
|
||||
}
|
||||
|
||||
|
||||
template< typename Data >
|
||||
void IntervalTree<Data>::postInsert ( typename Super::Node* node )
|
||||
{
|
||||
cdebug_log(0,1) << "IntervalTree::postInsert() " << node << std::endl;
|
||||
cdebug_log(0,1) << "IntervalTree::postInsert() "
|
||||
<< ((node) ? ::getString(node->getValue()) : "node=NULL") << std::endl;
|
||||
|
||||
while ( node ) {
|
||||
cdebug_log(0,0) << "| " << node << std::endl;
|
||||
cdebug_log(0,0) << "| " << node->getValue() << std::endl;
|
||||
|
||||
updateChildsVMax( node );
|
||||
node = node->getParent();
|
||||
|
@ -335,26 +380,38 @@ namespace Hurricane {
|
|||
}
|
||||
|
||||
|
||||
template< typename Data >
|
||||
void IntervalTree<Data>::postRemove ( typename Super::Node* node )
|
||||
template< typename Data, typename DataCompare >
|
||||
void IntervalTree<Data,DataCompare>::postRemove ( typename Super::Node* node )
|
||||
{
|
||||
cdebug_log(0,1) << "IntervalTree::postRemove() "
|
||||
<< ((node) ? ::getString(node->getValue()) : "node=NULL") << std::endl;
|
||||
|
||||
if (not node) {
|
||||
cdebug_tabw(0,-1);
|
||||
return;
|
||||
}
|
||||
|
||||
typename Super::Node* parent = node->getParent();
|
||||
if (parent) {
|
||||
typename Super::Node* child = NULL;
|
||||
DbU::Unit childsVMax = parent->getValue().getVMax();
|
||||
typename Super::Node* child1 = parent->getLeft ();
|
||||
typename Super::Node* child2 = parent->getRight();
|
||||
if (child1 == node) std::swap( child1, child2 );
|
||||
if (child1) childsVMax = std::max( childsVMax, child1->getValue().getChildsVMax() );
|
||||
if (child2->getLeft ()) childsVMax = std::max( childsVMax, child2->getLeft ()->getValue().getChildsVMax() );
|
||||
if (child2->getRight()) childsVMax = std::max( childsVMax, child2->getRight()->getValue().getChildsVMax() );
|
||||
|
||||
if (parent->hasLeftChild(node)) child = parent->getRight();
|
||||
else child = parent->getLeft ();
|
||||
|
||||
DbU::Unit childVMax = (child) ? child->getValue().getChildsVMax() : parent->getValue().getVMax();
|
||||
const_cast< IntervalData<Data>& >( parent->getValue() ).updateChildsVMax( childVMax, childVMax );
|
||||
const_cast< IntervalData<Data>& >( parent->getValue() ).updateChildsVMax( childsVMax, childsVMax );
|
||||
|
||||
postInsert( parent->getParent() );
|
||||
}
|
||||
|
||||
cdebug_tabw(0,-1);
|
||||
}
|
||||
|
||||
|
||||
template< typename Data >
|
||||
size_t IntervalTree<Data>::getThickness () const
|
||||
template< typename Data, typename DataCompare >
|
||||
size_t IntervalTree<Data,DataCompare>::getThickness () const
|
||||
{
|
||||
cdebug_log(0,0) << "IntervalTree::getThickness() " << std::endl;
|
||||
|
||||
|
@ -382,36 +439,70 @@ namespace Hurricane {
|
|||
}
|
||||
|
||||
|
||||
template< typename Data >
|
||||
typename IntervalTree<Data>::overlap_iterator IntervalTree<Data>::beginOverlaps ( const Interval& overlap ) const
|
||||
template< typename Data, typename DataCompare >
|
||||
typename IntervalTree<Data,DataCompare>::overlap_iterator
|
||||
IntervalTree<Data,DataCompare>::beginOverlaps ( const Interval& overlap ) const
|
||||
{
|
||||
cdebug_log(0,0) << "IntervalTree::beginOverlaps() " << overlap << std::endl;
|
||||
|
||||
const typename Super::Node* current = this->getRoot();
|
||||
const typename Super::Node* leftMost = NULL;
|
||||
const typename Super::Node* leftMost = nullptr;
|
||||
while ( current ) {
|
||||
cdebug_log(0,0) << "| " << ::getString(current) << endl;
|
||||
cdebug_log(0,0) << "| " << ::getString(current->getValue()) << endl;
|
||||
|
||||
if (current->getValue().intersect(overlap)) leftMost = current;
|
||||
if (current->getValue().intersect(overlap,false)) {
|
||||
cdebug_log(0,0) << "* Leftmost candidate." << endl;
|
||||
leftMost = current;
|
||||
}
|
||||
if ( current->getLeft()
|
||||
and (overlap.getVMin() < current->getLeft()->getValue().getChildsVMax()) )
|
||||
current = current->getLeft();
|
||||
else
|
||||
current = current->getRight();
|
||||
and (overlap.getVMin() < current->getLeft()->getValue().getChildsVMax()) ) {
|
||||
current = current->getLeft();
|
||||
leftMost = nullptr;
|
||||
} else {
|
||||
if (not leftMost)
|
||||
current = current->getRight();
|
||||
else
|
||||
current = nullptr;
|
||||
}
|
||||
}
|
||||
return overlap_iterator( leftMost, overlap );
|
||||
}
|
||||
|
||||
|
||||
template< typename Data >
|
||||
typename IntervalTree<Data>::OverlapElements IntervalTree<Data>::getOverlaps ( const Interval& overlap ) const
|
||||
template< typename Data, typename DataCompare >
|
||||
typename IntervalTree<Data,DataCompare>::OverlapElements
|
||||
IntervalTree<Data,DataCompare>::getOverlaps ( const Interval& overlap ) const
|
||||
{
|
||||
cdebug_log(0,0) << "IntervalTree::getOverlaps() " << overlap << std::endl;
|
||||
return OverlapElements( *this, overlap );
|
||||
}
|
||||
|
||||
|
||||
template< typename Data, typename DataCompare >
|
||||
void IntervalTree<Data,DataCompare>::checkVMax () const
|
||||
{
|
||||
checkVMax( this->getRoot() );
|
||||
}
|
||||
|
||||
|
||||
template< typename Data, typename DataCompare >
|
||||
void IntervalTree<Data,DataCompare>::checkVMax ( typename Super::Node* node ) const
|
||||
{
|
||||
if (not node) return;
|
||||
|
||||
DbU::Unit lchildVMax = (node->getLeft ()) ? node->getLeft ()->getValue().getChildsVMax() : node->getValue().getVMax();
|
||||
DbU::Unit rchildVMax = (node->getRight()) ? node->getRight()->getValue().getChildsVMax() : node->getValue().getVMax();
|
||||
DbU::Unit childsVMax = std::max( lchildVMax, rchildVMax );
|
||||
childsVMax = std::max( childsVMax, node->getValue().getVMax() );
|
||||
|
||||
if (node->getValue().getChildsVMax() != childsVMax) {
|
||||
cerr << "ChildVMax discrepency on vmax=" << DbU::getValueString(childsVMax)
|
||||
<< " " << ::getString(node->getValue()) << endl;
|
||||
}
|
||||
|
||||
checkVMax( node->getLeft() );
|
||||
checkVMax( node->getRight() );
|
||||
}
|
||||
|
||||
|
||||
} // HUrricane namespace.
|
||||
|
||||
#endif // HURRICANE_INTERVAL_TREE_H
|
||||
|
|
|
@ -17,9 +17,7 @@
|
|||
// not, see <http://www.gnu.org/licenses/>.
|
||||
// ****************************************************************************************************
|
||||
|
||||
#ifndef HURRICANE_NET
|
||||
#define HURRICANE_NET
|
||||
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include "hurricane/Entity.h"
|
||||
#include "hurricane/Nets.h"
|
||||
|
@ -253,6 +251,7 @@ class Net : public Entity {
|
|||
public: virtual void _toJsonSignature(JsonWriter*) const;
|
||||
public: virtual void _toJsonCollections(JsonWriter*) const;
|
||||
public: virtual string _getTypeName() const {return _TName("Net");};
|
||||
public: string _getFlagsAsString() const;
|
||||
public: virtual string _getString() const;
|
||||
public: virtual Record* _getRecord() const;
|
||||
public: NetMainName& _getMainName() { return _mainName; }
|
||||
|
@ -445,9 +444,10 @@ namespace Hurricane {
|
|||
// Because sometimes it didn't happens (?).
|
||||
const SlotTemplate<Net*> dummyNetSlot ( string("dummyNetSlot"), NULL );
|
||||
|
||||
}
|
||||
|
||||
#endif // HURRICANE_NET
|
||||
typedef std::set<Net*,DBo::CompareById> NetSet;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ****************************************************************************************************
|
||||
|
|
|
@ -121,6 +121,10 @@ class JsonOccurrence : public JsonObject {
|
|||
public: virtual void toData(JsonStack&);
|
||||
};
|
||||
|
||||
|
||||
typedef std::set<Occurrence> OccurrenceSet;
|
||||
|
||||
|
||||
} // End of Hurricane namespace.
|
||||
|
||||
|
||||
|
|
|
@ -34,9 +34,7 @@
|
|||
// Third edition, MIT press, 2011, p. 308.
|
||||
|
||||
|
||||
#ifndef HURRICANE_RBTREE_H
|
||||
#define HURRICANE_RBTREE_H
|
||||
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
@ -90,7 +88,7 @@ namespace Hurricane {
|
|||
inline void copyColor ( Node* );
|
||||
void updateEdge ( Node* oldChild, Node* newChild );
|
||||
void clear ();
|
||||
inline void copy ( const Node* );
|
||||
inline void swap ( Node* );
|
||||
virtual std::string _getString () const;
|
||||
virtual Record* _getRecord () const;
|
||||
private:
|
||||
|
@ -284,8 +282,15 @@ namespace Hurricane {
|
|||
|
||||
|
||||
template< typename Data, typename Compare >
|
||||
inline void RbTree<Data,Compare>::Node::copy ( const Node* other )
|
||||
{ value_ = other->value_; }
|
||||
inline void RbTree<Data,Compare>::Node::swap ( Node* other )
|
||||
{
|
||||
cdebug_log(0,0) << "Node::swap()" << endl;
|
||||
cdebug_log(0,0) << "| " << value_ << endl;
|
||||
cdebug_log(0,0) << "| " << other->value_ << endl;
|
||||
Data tmp = value_; value_ = other->value_; other->value_ = tmp;
|
||||
cdebug_log(0,0) << "| " << value_ << endl;
|
||||
cdebug_log(0,0) << "| " << other->value_ << endl;
|
||||
}
|
||||
|
||||
|
||||
template< typename Data, typename Compare >
|
||||
|
@ -515,7 +520,7 @@ namespace Hurricane {
|
|||
template< typename Data, typename Compare >
|
||||
void RbTree<Data,Compare>::rotateLeft ( typename RbTree<Data,Compare>::Node* node )
|
||||
{
|
||||
cdebug_log(0,0) << "RbTree::rotateLeft() " << node << std::endl;
|
||||
cdebug_log(0,0) << "RbTree::rotateLeft() " << node->getValue() << std::endl;
|
||||
|
||||
Node* rchild = node->getRight();
|
||||
|
||||
|
@ -534,7 +539,7 @@ namespace Hurricane {
|
|||
template< typename Data, typename Compare >
|
||||
void RbTree<Data,Compare>::rotateRight ( typename RbTree<Data,Compare>::Node* node )
|
||||
{
|
||||
cdebug_log(0,0) << "RbTree::rotateRight() " << node << std::endl;
|
||||
cdebug_log(0,0) << "RbTree::rotateRight() " << node->getValue() << std::endl;
|
||||
|
||||
Node* lchild = node->getLeft();
|
||||
|
||||
|
@ -557,15 +562,21 @@ namespace Hurricane {
|
|||
|
||||
Node* current = root_;
|
||||
while ( current ) {
|
||||
cdebug_log(0,0) << "| " << current << std::endl;
|
||||
cdebug_log(0,0) << "| " << current->getValue() << std::endl;
|
||||
|
||||
if (current->getValue() == value) {
|
||||
cdebug_log(0,-1) << "> Value found: " << current <<std::endl;
|
||||
cdebug_log(0,-1) << "> Value found: " << current->getValue() << std::endl;
|
||||
return iterator(current);
|
||||
}
|
||||
|
||||
if (compare_(value,current->getValue())) current = current->getLeft ();
|
||||
else current = current->getRight();
|
||||
if (compare_(value,current->getValue())) {
|
||||
current = current->getLeft ();
|
||||
cdebug_log(0,0) << "| Go left " << ((current) ? ::getString(current->getValue()) : "NULL") << std::endl;
|
||||
}
|
||||
else {
|
||||
current = current->getRight();
|
||||
cdebug_log(0,0) << "| Go right " << ((current) ? ::getString(current->getValue()) : "NULL") << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
cdebug_log(0,-1) << "Value not found." << std::endl;
|
||||
|
@ -630,21 +641,22 @@ namespace Hurricane {
|
|||
|
||||
Node* rmNode = const_cast<Node*>( find( value ).getNode() );
|
||||
if (not rmNode) {
|
||||
cdebug_log(0,1) << "No node of value=" << value << std::endl;
|
||||
cdebug_log(0,-1) << "No node of value=" << value << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
Node* rmLeaf = nullptr;
|
||||
if (rmNode->getLeft() and rmNode->getRight()) {
|
||||
Node* rmLeaf = rmNode->getLeft();
|
||||
Node* rmMax = rmLeaf->getMax();
|
||||
rmLeaf = rmNode->getLeft();
|
||||
Node* rmMax = rmLeaf->getMax();
|
||||
if (rmMax) rmLeaf = rmMax;
|
||||
|
||||
rmNode->copy( rmLeaf );
|
||||
rmNode = rmLeaf;
|
||||
rmNode->swap( rmLeaf );
|
||||
std::swap( rmNode, rmLeaf );
|
||||
}
|
||||
|
||||
postRemove ( rmNode );
|
||||
|
||||
removeRepair( rmNode, 0 );
|
||||
postRemove ( rmNode );
|
||||
|
||||
Node* parent = rmNode->getParent();
|
||||
Node* child = (rmNode->getLeft()) ? rmNode->getLeft() : rmNode->getRight();
|
||||
|
@ -660,8 +672,9 @@ namespace Hurricane {
|
|||
}
|
||||
}
|
||||
|
||||
cdebug_log(0,0) << "delete " << rmNode << std::endl;
|
||||
cdebug_log(0,0) << "delete " << rmNode->getValue() << std::endl;
|
||||
delete rmNode;
|
||||
|
||||
--count_;
|
||||
|
||||
cdebug_tabw(0,-1);
|
||||
|
@ -671,8 +684,13 @@ namespace Hurricane {
|
|||
template< typename Data, typename Compare >
|
||||
void RbTree<Data,Compare>::removeRepair ( typename RbTree<Data,Compare>::Node* rmNode, size_t depth )
|
||||
{
|
||||
cdebug_log(0,1) << "RbTree::removeRepair() rmNode:" << rmNode
|
||||
cdebug_log(0,1) << "RbTree::removeRepair() rmNode:" << rmNode->getValue()
|
||||
<< " depth:" << depth << std::endl;
|
||||
|
||||
if (not rmNode) {
|
||||
cdebug_tabw(0,-1);
|
||||
return ;
|
||||
}
|
||||
|
||||
if (rmNode->isBlack()) {
|
||||
Node* parent = rmNode->getParent();
|
||||
|
@ -979,6 +997,7 @@ namespace Hurricane {
|
|||
void RbTreeToDot<Data,Compare,RbTree>::write ( std::ostream& o ) const
|
||||
{
|
||||
o << "digraph RbTree {\n";
|
||||
o << " ratio=\"1.0\";\n";
|
||||
toDot( o, tree_->getRoot() );
|
||||
o << "}";
|
||||
}
|
||||
|
@ -989,8 +1008,9 @@ namespace Hurricane {
|
|||
{
|
||||
if (not node) return;
|
||||
|
||||
string svalue = ::getString( node->getValue() );
|
||||
o << " id_" << getId(node) << " "
|
||||
<< "[label=\"id:" << getId(node) << "\\n" << ::getString(node->getValue())
|
||||
<< "[label=\"id:" << getId(node) << "\\n" << split( svalue )
|
||||
<< "\""
|
||||
<< ",color=" << (node->isRed() ? "red" : "black")
|
||||
<< ",fontcolor=" << (node->isRed() ? "red" : "black")
|
||||
|
@ -1031,6 +1051,3 @@ namespace Hurricane {
|
|||
|
||||
|
||||
} // Hurricane namespace.
|
||||
|
||||
|
||||
#endif // HURRICANE_RBTREE_H
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// -*- C++ -*-
|
||||
//
|
||||
// Copyright (c) BULL S.A. 2018-2018, All Rights Reserved
|
||||
// Copyright (c) BULL S.A. 2018-2023, All Rights Reserved
|
||||
//
|
||||
// This file is part of Hurricane.
|
||||
//
|
||||
|
@ -28,10 +28,7 @@
|
|||
// | C++ Header : "./hurricane/Rectilinear.h" |
|
||||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#ifndef HURRICANE_RECTILINEAR_H
|
||||
#define HURRICANE_RECTILINEAR_H
|
||||
|
||||
#pragma once
|
||||
#include "hurricane/Component.h"
|
||||
|
||||
|
||||
|
@ -46,11 +43,13 @@ namespace Hurricane {
|
|||
class Rectilinear : public Component {
|
||||
public:
|
||||
typedef Component Super;
|
||||
static const uint32_t IsRectilinear = (1<<0);
|
||||
|
||||
public:
|
||||
static Rectilinear* create ( Net*, const Layer*, const vector<Point>& );
|
||||
// Accessors.
|
||||
virtual bool isNonRectangle () const;
|
||||
inline bool isRectilinear () const;
|
||||
virtual DbU::Unit getX () const;
|
||||
virtual DbU::Unit getY () const;
|
||||
virtual Box getBoundingBox () const;
|
||||
|
@ -59,6 +58,7 @@ namespace Hurricane {
|
|||
virtual Point getPoint ( size_t i ) const;
|
||||
virtual const Layer* getLayer () const;
|
||||
inline Points getContour () const;
|
||||
bool getAsRectangles ( std::vector<Box>& ) const;
|
||||
inline const vector<Point>& getPoints () const;
|
||||
// Mutators.
|
||||
void setLayer ( const Layer* );
|
||||
|
@ -75,11 +75,13 @@ namespace Hurricane {
|
|||
private:
|
||||
const Layer* _layer;
|
||||
vector<Point> _points;
|
||||
uint32_t _flags;
|
||||
};
|
||||
|
||||
|
||||
inline Points Rectilinear::getContour () const { return new VectorCollection<Point>(_points); }
|
||||
inline const vector<Point>& Rectilinear::getPoints () const { return _points; }
|
||||
inline bool Rectilinear::isRectilinear () const { return _flags & IsRectilinear; }
|
||||
inline Points Rectilinear::getContour () const { return new VectorCollection<Point>(_points); }
|
||||
inline const vector<Point>& Rectilinear::getPoints () const { return _points; }
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
@ -99,5 +101,3 @@ namespace Hurricane {
|
|||
|
||||
|
||||
INSPECTOR_P_SUPPORT(Hurricane::Rectilinear);
|
||||
|
||||
#endif // HURRICANE_RECTILINEAR_H
|
||||
|
|
|
@ -45,6 +45,24 @@ namespace Isobar {
|
|||
}
|
||||
|
||||
|
||||
PyObject* VectorToList ( const std::vector<Box>& v )
|
||||
{
|
||||
PyObject* pyList = PyList_New( v.size() );
|
||||
|
||||
for ( size_t i=0 ; i<v.size() ; ++i ) {
|
||||
PyBox* pyBox = PyObject_NEW( PyBox, &PyTypeBox );
|
||||
if (not pyBox) { return NULL; }
|
||||
|
||||
HTRY
|
||||
pyBox->_object = new Box ( v[i] );
|
||||
HCATCH
|
||||
PyList_SetItem( pyList, i, (PyObject*)pyBox );
|
||||
}
|
||||
|
||||
return pyList;
|
||||
}
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
||||
|
@ -168,20 +186,54 @@ extern "C" {
|
|||
}
|
||||
|
||||
|
||||
static PyObject* PyRectilinear_getAsRectangles ( PyRectilinear *self, PyObject* args )
|
||||
{
|
||||
cdebug_log(20,0) << "Rectilinear.getAsRectangles()" << endl;
|
||||
|
||||
HTRY
|
||||
METHOD_HEAD( "Rectilinear.getAsRectangles()" )
|
||||
|
||||
PyObject* pyList = NULL;
|
||||
if (not PyArg_ParseTuple( args, "O:Rectilinear.getAsRectangles", &pyList )) {
|
||||
PyErr_SetString( ConstructorError, "Rectilinear.getAsRectangles(): Must have exactly one parameter." );
|
||||
return NULL;
|
||||
}
|
||||
if (not PyList_Check(pyList)) {
|
||||
PyErr_SetString( ConstructorError, "Rectilinear.getAsRectangles(): Argument must be a list." );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyList_SetSlice( pyList, 0, PyList_Size(pyList), NULL );
|
||||
vector<Box> boxes;
|
||||
rectilinear->getAsRectangles( boxes );
|
||||
for ( size_t i=0 ; i<boxes.size() ; ++i ) {
|
||||
PyBox* pyBox = PyObject_NEW( PyBox, &PyTypeBox );
|
||||
if (not pyBox) { return NULL; }
|
||||
|
||||
pyBox->_object = new Box ( boxes[i] );
|
||||
PyList_Append( pyList, (PyObject*)pyBox );
|
||||
}
|
||||
HCATCH
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// PyRectilinear Attribute Method table.
|
||||
|
||||
PyMethodDef PyRectilinear_Methods[] =
|
||||
{ { "create" , (PyCFunction)PyRectilinear_create , METH_VARARGS|METH_STATIC
|
||||
, "Create a new Rectilinear polygon." }
|
||||
, { "isNonRectangle", (PyCFunction)PyRectilinear_isNonRectangle, METH_NOARGS , "Tells if the shape is not a rectangle." }
|
||||
, { "getX" , (PyCFunction)PyRectilinear_getX , METH_NOARGS , "Return the Rectilinear X value." }
|
||||
, { "getY" , (PyCFunction)PyRectilinear_getY , METH_NOARGS , "Return the Rectilinear Y value." }
|
||||
, { "getBoundingBox", (PyCFunction)PyRectilinear_getBoundingBox, METH_NOARGS , "Return the Rectilinear Bounding Box." }
|
||||
, { "setPoints" , (PyCFunction)PyRectilinear_setPoints , METH_VARARGS, "Sets the Rectilinear Bounding Box." }
|
||||
, { "translate" , (PyCFunction)PyRectilinear_translate , METH_VARARGS, "Translates the Rectilinear of dx and dy." }
|
||||
, { "destroy" , (PyCFunction)PyRectilinear_destroy , METH_NOARGS
|
||||
, "Destroy associated hurricane object, the python object remains." }
|
||||
{ { "create" , (PyCFunction)PyRectilinear_create , METH_VARARGS|METH_STATIC
|
||||
, "Create a new Rectilinear polygon." }
|
||||
, { "isNonRectangle" , (PyCFunction)PyRectilinear_isNonRectangle , METH_NOARGS , "Tells if the shape is not a rectangle." }
|
||||
, { "getX" , (PyCFunction)PyRectilinear_getX , METH_NOARGS , "Return the Rectilinear X value." }
|
||||
, { "getY" , (PyCFunction)PyRectilinear_getY , METH_NOARGS , "Return the Rectilinear Y value." }
|
||||
, { "getBoundingBox" , (PyCFunction)PyRectilinear_getBoundingBox , METH_NOARGS , "Return the Rectilinear Bounding Box." }
|
||||
, { "setPoints" , (PyCFunction)PyRectilinear_setPoints , METH_VARARGS, "Sets the Rectilinear Bounding Box." }
|
||||
, { "translate" , (PyCFunction)PyRectilinear_translate , METH_VARARGS, "Translates the Rectilinear of dx and dy." }
|
||||
, { "getAsRectangles", (PyCFunction)PyRectilinear_getAsRectangles, METH_VARARGS, "Return the rectangle coverage." }
|
||||
, { "destroy" , (PyCFunction)PyRectilinear_destroy , METH_NOARGS
|
||||
, "Destroy associated hurricane object, the python object remains." }
|
||||
, {NULL, NULL, 0, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
|
|
@ -1625,31 +1625,31 @@ extern "C" {
|
|||
catch ( const Warning& w ) { \
|
||||
std::string message = getString(w); \
|
||||
PyErr_Warn ( HurricaneWarning, const_cast<char*>(message.c_str()) ); \
|
||||
std::cerr << message << std::endl; \
|
||||
std::cerr << message << std::endl; \
|
||||
} \
|
||||
catch ( const Error& e ) { \
|
||||
std::string message = getString(e); \
|
||||
if (not e.where().empty()) message += "\n" + e.where(); \
|
||||
PyErr_SetString ( HurricaneError, message.c_str() ); \
|
||||
std::cerr << message << std::endl; \
|
||||
std::cerr << message << std::endl; \
|
||||
return NULL; \
|
||||
} \
|
||||
catch ( const Bug& e ) { \
|
||||
std::string message = getString(e); \
|
||||
PyErr_SetString ( HurricaneError, message.c_str() ); \
|
||||
std::cerr << message << std::endl; \
|
||||
std::cerr << message << std::endl; \
|
||||
return NULL; \
|
||||
} \
|
||||
catch ( const Exception& e ) { \
|
||||
std::string message = "Unknown Hurricane::Exception"; \
|
||||
PyErr_SetString ( HurricaneError, message.c_str() ); \
|
||||
std::cerr << message << std::endl; \
|
||||
std::cerr << message << std::endl; \
|
||||
return NULL; \
|
||||
} \
|
||||
catch ( const std::exception& e ) { \
|
||||
std::string message = std::string(e.what()); \
|
||||
PyErr_SetString ( HurricaneError, message.c_str() ); \
|
||||
std::cerr << message << std::endl; \
|
||||
std::cerr << message << std::endl; \
|
||||
return NULL; \
|
||||
} \
|
||||
catch ( ... ) { \
|
||||
|
@ -1657,7 +1657,7 @@ extern "C" {
|
|||
"Unmanaged exception, neither a Hurricane::Error nor" \
|
||||
" a std::exception."; \
|
||||
PyErr_SetString ( HurricaneError, message.c_str() ); \
|
||||
std::cerr << message << std::endl; \
|
||||
std::cerr << message << std::endl; \
|
||||
return NULL; \
|
||||
} \
|
||||
|
||||
|
|
|
@ -157,8 +157,9 @@ namespace Hurricane {
|
|||
|
||||
//int scale = 80 * Cfg::getParamEnumerate("viewer.printer.mode")->asInt();
|
||||
int scale = (Graphics::isHighDpi()) ? 4 : 2;
|
||||
_drawingWidth = _cellWidget->width () * scale;
|
||||
_drawingHeight = _cellWidget->height() * scale;
|
||||
_drawingWidth = _screenCellWidget->geometry().width () * scale;
|
||||
_drawingHeight = _screenCellWidget->geometry().height() * scale;
|
||||
_cellWidget->resize( _drawingWidth, _drawingHeight );
|
||||
|
||||
_image = new QImage( _drawingWidth
|
||||
, _drawingHeight + ((_flags&ShowScale) ? 60 : 0)
|
||||
|
@ -188,7 +189,7 @@ namespace Hurricane {
|
|||
setFitOnAbutmentBox( true );
|
||||
_cellWidget->fitToContents();
|
||||
} else {
|
||||
//_cellWidget->reframe( _screenCellWidget->getVisibleArea() );
|
||||
_cellWidget->reframe( _screenCellWidget->getVisibleArea() );
|
||||
}
|
||||
|
||||
cerr << " After resize CellWidget: " << _cellWidget->geometry().width() << "x" << _cellWidget->geometry().height() << endl;
|
||||
|
|
|
@ -584,7 +584,7 @@ namespace Hurricane {
|
|||
|
||||
void CellViewer::refreshTitle ()
|
||||
{
|
||||
QString cellName = "None";
|
||||
QString cellName = "empty";
|
||||
if ( getCell() )
|
||||
cellName = getString(getCell()->getName()).c_str();
|
||||
|
||||
|
|
|
@ -2683,7 +2683,86 @@ namespace Hurricane {
|
|||
} else
|
||||
selected = false;
|
||||
|
||||
if ( (--_delaySelectionChanged == 0) and selected ) emit selectionChanged( _selectors );
|
||||
if ( (--_delaySelectionChanged == 0) and selected )
|
||||
emit selectionChanged( _selectors );
|
||||
}
|
||||
|
||||
|
||||
void CellWidget::selectSet ( const ComponentSet& components )
|
||||
{
|
||||
if ( (++_delaySelectionChanged == 1) and not _state->cumulativeSelection() ) {
|
||||
openRefreshSession();
|
||||
unselectAll();
|
||||
closeRefreshSession();
|
||||
}
|
||||
|
||||
bool selected = true;
|
||||
// SelectorCriterion* criterion = _state->getSelection().add ( selectArea );
|
||||
// if ( criterion and (not criterion->isEnabled()) ) {
|
||||
// criterion->enable();
|
||||
|
||||
for ( Component* component : components ) {
|
||||
if (component->getCell() == getCell()) {
|
||||
select( Occurrence( component ));
|
||||
}
|
||||
}
|
||||
// } else
|
||||
// selected = false;
|
||||
|
||||
if ( (--_delaySelectionChanged == 0) and selected )
|
||||
emit selectionChanged( _selectors );
|
||||
}
|
||||
|
||||
|
||||
void CellWidget::selectSet ( const OccurrenceSet& occurrences )
|
||||
{
|
||||
if ( (++_delaySelectionChanged == 1) and not _state->cumulativeSelection() ) {
|
||||
openRefreshSession();
|
||||
unselectAll();
|
||||
closeRefreshSession();
|
||||
}
|
||||
|
||||
bool selected = true;
|
||||
// SelectorCriterion* criterion = _state->getSelection().add ( selectArea );
|
||||
// if ( criterion and (not criterion->isEnabled()) ) {
|
||||
// criterion->enable();
|
||||
|
||||
for ( const Occurrence& occurrence : occurrences ) {
|
||||
if (occurrence.getOwnerCell() == getCell()) {
|
||||
select( occurrence );
|
||||
}
|
||||
}
|
||||
// } else
|
||||
// selected = false;
|
||||
|
||||
if ( (--_delaySelectionChanged == 0) and selected )
|
||||
emit selectionChanged( _selectors );
|
||||
}
|
||||
|
||||
|
||||
void CellWidget::select ( Occurrences occurrences )
|
||||
{
|
||||
if ( (++_delaySelectionChanged == 1) and not _state->cumulativeSelection() ) {
|
||||
openRefreshSession();
|
||||
unselectAll();
|
||||
closeRefreshSession();
|
||||
}
|
||||
|
||||
bool selected = true;
|
||||
// SelectorCriterion* criterion = _state->getSelection().add ( selectArea );
|
||||
// if ( criterion and (not criterion->isEnabled()) ) {
|
||||
// criterion->enable();
|
||||
|
||||
for ( const Occurrence& occurrence : occurrences ) {
|
||||
if (occurrence.getOwnerCell() == getCell()) {
|
||||
select( occurrence );
|
||||
}
|
||||
}
|
||||
// } else
|
||||
// selected = false;
|
||||
|
||||
if ( (--_delaySelectionChanged == 0) and selected )
|
||||
emit selectionChanged( _selectors );
|
||||
}
|
||||
|
||||
|
||||
|
@ -2744,7 +2823,7 @@ namespace Hurricane {
|
|||
|
||||
if ( (--_delaySelectionChanged == 0) and selected ) {
|
||||
if ( _state->showSelection() ) _redrawManager.refresh ();
|
||||
emit selectionChanged(_selectors);
|
||||
emit selectionChanged(_selectors);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2782,7 +2861,47 @@ namespace Hurricane {
|
|||
}
|
||||
|
||||
_selectionHasChanged = true;
|
||||
if ( (_delaySelectionChanged == 0) and unselected ) emit selectionChanged( _selectors );
|
||||
if ( (_delaySelectionChanged == 0) and unselected )
|
||||
emit selectionChanged( _selectors );
|
||||
}
|
||||
|
||||
|
||||
void CellWidget::unselectSet ( const ComponentSet& components )
|
||||
{
|
||||
++_delaySelectionChanged;
|
||||
for ( Component* component : components ) {
|
||||
if (component->getCell() == getCell()) {
|
||||
unselect( Occurrence( component ));
|
||||
}
|
||||
}
|
||||
if ( --_delaySelectionChanged == 0 )
|
||||
emit selectionChanged( _selectors );
|
||||
}
|
||||
|
||||
|
||||
void CellWidget::unselectSet ( const OccurrenceSet& occurrences )
|
||||
{
|
||||
++_delaySelectionChanged;
|
||||
for ( const Occurrence& occurrence : occurrences ) {
|
||||
if (occurrence.getOwnerCell() == getCell()) {
|
||||
unselect( occurrence );
|
||||
}
|
||||
}
|
||||
if ( --_delaySelectionChanged == 0 )
|
||||
emit selectionChanged( _selectors );
|
||||
}
|
||||
|
||||
|
||||
void CellWidget::unselect ( Occurrences occurrences )
|
||||
{
|
||||
++_delaySelectionChanged;
|
||||
for ( const Occurrence& occurrence : occurrences ) {
|
||||
if (occurrence.getOwnerCell() == getCell()) {
|
||||
unselect( occurrence );
|
||||
}
|
||||
}
|
||||
if ( --_delaySelectionChanged == 0 )
|
||||
emit selectionChanged( _selectors );
|
||||
}
|
||||
|
||||
|
||||
|
@ -2793,7 +2912,8 @@ namespace Hurricane {
|
|||
_state->getSelection().clear ();
|
||||
_unselectAll ();
|
||||
|
||||
if ( --_delaySelectionChanged == 0 ) emit selectionChanged(_selectors);
|
||||
if ( --_delaySelectionChanged == 0 )
|
||||
emit selectionChanged(_selectors);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -658,6 +658,19 @@ namespace Hurricane {
|
|||
}
|
||||
|
||||
|
||||
void ControllerWidget::insertTabAfter ( const QString& ref, QWidget* tab, const QString& label )
|
||||
{
|
||||
for ( int itab=0 ; true; ++itab ) {
|
||||
QWidget* refTab = widget( itab );
|
||||
if (not refTab) break;
|
||||
if (refTab->objectName() != ref) continue;
|
||||
insertTab( itab, tab, label );
|
||||
return;
|
||||
}
|
||||
addTab( tab, label );
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "ControllerWidget::GraphicsObserver".
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace Hurricane {
|
|||
|
||||
|
||||
int SimpleNetInformations::getColumnCount ()
|
||||
{ return 3; }
|
||||
{ return 6; }
|
||||
|
||||
|
||||
QVariant SimpleNetInformations::getColumnName ( int column )
|
||||
|
@ -71,7 +71,10 @@ namespace Hurricane {
|
|||
switch ( column ) {
|
||||
case 0: return QVariant(QObject::tr("Net"));
|
||||
case 1: return QVariant(QObject::tr("Plugs"));
|
||||
case 2: return QVariant(QObject::tr("RoutingPads"));
|
||||
case 2: return QVariant(QObject::tr("RPs"));
|
||||
case 3: return QVariant(QObject::tr("Flags"));
|
||||
case 4: return QVariant(QObject::tr("Type"));
|
||||
case 5: return QVariant(QObject::tr("Direction"));
|
||||
}
|
||||
return QVariant(QObject::tr("Column Out of Bound"));
|
||||
}
|
||||
|
@ -84,11 +87,15 @@ namespace Hurricane {
|
|||
case 1: return (unsigned int)_plugsCount;
|
||||
case 2:
|
||||
if (_net->isGlobal()) {
|
||||
if (not _rpsCount) return "N/A (global)";
|
||||
string s = getString(_rpsCount) + " (global)";
|
||||
if (not _rpsCount) return "N/A";
|
||||
string s = getString(_rpsCount);
|
||||
return s.c_str();
|
||||
}
|
||||
return (unsigned int)_rpsCount;
|
||||
case 3: return QString::fromStdString( getString( _net->_getFlagsAsString() ));
|
||||
case 4: return QString::fromStdString( getString( _net->getType() ));
|
||||
case 5: return QString::fromStdString( getString( _net->getDirection() ));
|
||||
|
||||
}
|
||||
return QVariant(QObject::tr("Column Out of Bound"));
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace Hurricane {
|
|||
|
||||
QHeaderView* horizontalHeader = _view->horizontalHeader();
|
||||
horizontalHeader->setDefaultAlignment ( Qt::AlignHCenter );
|
||||
horizontalHeader->setMinimumSectionSize( (Graphics::isHighDpi()) ? 300 : 150 );
|
||||
horizontalHeader->setMinimumSectionSize( (Graphics::isHighDpi()) ? 150 : 75 );
|
||||
horizontalHeader->setStretchLastSection( true );
|
||||
|
||||
QHeaderView* verticalHeader = _view->verticalHeader();
|
||||
|
@ -151,24 +151,18 @@ namespace Hurricane {
|
|||
_forceReselect = false;
|
||||
}
|
||||
|
||||
SelectedNetSet::iterator remove;
|
||||
SelectedNetSet::iterator isel = _selecteds.begin ();
|
||||
SelectedNetSet::iterator isel = _selecteds.begin ();
|
||||
while ( isel != _selecteds.end() ) {
|
||||
switch ( isel->getAccesses() ) {
|
||||
case 1: break;
|
||||
case 64:
|
||||
emit netSelected ( Occurrence(isel->getNet()) );
|
||||
break;
|
||||
case 0:
|
||||
emit netUnselected ( Occurrence(isel->getNet()) );
|
||||
remove = isel;
|
||||
++isel;
|
||||
_selecteds.erase ( remove );
|
||||
continue;
|
||||
default:
|
||||
cerr << Bug("NetlistWidget::updateSelecteds(): invalid code %d"
|
||||
,isel->getAccesses()) << endl;
|
||||
SelectedNetSet::iterator remove = isel++;
|
||||
if ( remove->getAccesses() == 0 ) {
|
||||
emit netUnselected ( Occurrence(remove->getNet()) );
|
||||
_selecteds.erase ( remove );
|
||||
}
|
||||
}
|
||||
isel = _selecteds.begin ();
|
||||
while ( isel != _selecteds.end() ) {
|
||||
if ( isel->getAccesses() == 64 )
|
||||
emit netSelected ( Occurrence(isel->getNet()) );
|
||||
++isel;
|
||||
}
|
||||
|
||||
|
|
|
@ -219,6 +219,7 @@ extern "C" {
|
|||
}
|
||||
|
||||
cw->setApplicationName ( name );
|
||||
cw->refreshTitle ();
|
||||
HCATCH
|
||||
|
||||
Py_RETURN_NONE;
|
||||
|
|
|
@ -91,8 +91,8 @@ namespace Hurricane {
|
|||
{
|
||||
if (not _cellWidget) return;
|
||||
|
||||
if (not isCumulative()) clear ();
|
||||
beginResetModel();
|
||||
if (not isCumulative()) _selection.clear ();
|
||||
|
||||
for ( Selector* selector : selection ) {
|
||||
if (not selector->isInModel(_cellWidget)) {
|
||||
|
|
|
@ -87,6 +87,7 @@ namespace Hurricane {
|
|||
CellViewer ( QWidget* parent=NULL );
|
||||
virtual ~CellViewer ();
|
||||
inline bool isToolInterrupted () const;
|
||||
void refreshTitle ();
|
||||
QMenu* createDebugMenu ();
|
||||
bool hasMenu ( const QString& path ) const;
|
||||
bool hasMenuAction ( const QString& path ) const;
|
||||
|
@ -166,7 +167,6 @@ namespace Hurricane {
|
|||
void cellPostModificated ();
|
||||
protected:
|
||||
void createMenus ();
|
||||
void refreshTitle ();
|
||||
void refreshHistory ();
|
||||
void rebuildHistory ();
|
||||
private:
|
||||
|
|
|
@ -265,10 +265,16 @@ namespace Hurricane {
|
|||
inline DrawingPlanes& getDrawingPlanes ();
|
||||
// void select ( const Net* );
|
||||
void select ( Occurrence );
|
||||
void select ( Occurrences );
|
||||
void selectSet ( const OccurrenceSet& );
|
||||
void selectSet ( const ComponentSet& );
|
||||
bool isSelected ( Occurrence );
|
||||
void selectOccurrencesUnder ( Box selectArea );
|
||||
// void unselect ( const Net* );
|
||||
void unselect ( Occurrence );
|
||||
void unselect ( Occurrences );
|
||||
void unselectSet ( const ComponentSet& );
|
||||
void unselectSet ( const OccurrenceSet& );
|
||||
void unselectAll ();
|
||||
void toggleSelection ( Occurrence );
|
||||
void setShowSelection ( bool state );
|
||||
|
|
|
@ -312,6 +312,7 @@ namespace Hurricane {
|
|||
inline TabSettings* getSettings ();
|
||||
void setCellWidget ( CellWidget* );
|
||||
//inline int addSetting ( QWidget* page, const QString& label );
|
||||
void insertTabAfter ( const QString& ref, QWidget*, const QString& label );
|
||||
public slots:
|
||||
void graphicsUpdated ();
|
||||
void cellPreModificate ();
|
||||
|
|
|
@ -473,7 +473,7 @@ namespace Katana {
|
|||
|
||||
for ( size_t depth=0 ; depth<_routingPlanes.size() ; ++depth ) {
|
||||
RoutingPlane* rp = _routingPlanes[depth];
|
||||
if (rp->getLayerGauge()->getType() == Constant::PinOnly) continue;
|
||||
if (rp->getLayerGauge()->getType() != Constant::Default) continue;
|
||||
if (rp->getLayerGauge()->getDepth() > getConfiguration()->getAllowedDepth()) continue;
|
||||
|
||||
int elementCapacity = 1;
|
||||
|
|
|
@ -12,8 +12,6 @@ stdenv.mkDerivation {
|
|||
buildInputs = [ boostWithPython coriolis-bootstrap qt4 ];
|
||||
nativeBuildInputs = [ cmake ninja doxygen ];
|
||||
|
||||
cmakeFlags = [ "-DWITH_OPENMP:STRING=TRUE" ];
|
||||
|
||||
inherit version;
|
||||
|
||||
meta = meta // { license = lib.licenses.gpl2Plus; };
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
# -*- explicit-buffer-name: "CMakeLists.txt<tramontana>" -*-
|
||||
|
||||
set(CMAKE_LEGACY_CYGWIN_WIN32 0)
|
||||
project(TRAMONTANA)
|
||||
|
||||
set(ignoreVariables "${BUILD_DOC} ${CMAKE_INSTALL_DIR}")
|
||||
|
||||
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)
|
||||
|
||||
set_cmake_policies()
|
||||
setup_boost()
|
||||
setup_qt()
|
||||
|
||||
find_package(Python 3 REQUIRED COMPONENTS Interpreter Development)
|
||||
find_package(PythonSitePackages REQUIRED)
|
||||
find_package(HURRICANE REQUIRED)
|
||||
find_package(CORIOLIS REQUIRED)
|
||||
find_package(Doxygen)
|
||||
|
||||
add_subdirectory(src)
|
||||
#add_subdirectory(cmake_modules)
|
||||
#add_subdirectory(doc)
|
|
@ -0,0 +1,78 @@
|
|||
# -*- explicit-buffer-name: "CMakeLists.txt<tramontana/src>" -*-
|
||||
|
||||
# include( ${QT_USE_FILE} )
|
||||
include_directories( ${TRAMONTANA_SOURCE_DIR}/src
|
||||
${CORIOLIS_INCLUDE_DIR}
|
||||
${HURRICANE_INCLUDE_DIR}
|
||||
${CONFIGURATION_INCLUDE_DIR}
|
||||
${QtX_INCLUDE_DIRS}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${Python_INCLUDE_DIRS}
|
||||
)
|
||||
set( includes tramontana/Tile.h
|
||||
tramontana/QueryTiles.h
|
||||
tramontana/SweepLine.h
|
||||
tramontana/Equipotential.h
|
||||
tramontana/EquipotentialRelation.h
|
||||
tramontana/EquipotentialComponents.h
|
||||
tramontana/TramontanaEngine.h
|
||||
tramontana/GraphicTramontanaEngine.h
|
||||
)
|
||||
set( pyIncludes tramontana/PyTramontanaEngine.h
|
||||
tramontana/PyGraphicTramontanaEngine.h
|
||||
)
|
||||
set( mocIncludes tramontana/GraphicTramontanaEngine.h
|
||||
tramontana/EquipotentialsModel.h
|
||||
tramontana/EquipotentialsWidget.h
|
||||
tramontana/TabEquipotentials.h
|
||||
)
|
||||
set( cpps Tile.cpp
|
||||
QueryTiles.cpp
|
||||
SweepLine.cpp
|
||||
Equipotential.cpp
|
||||
EquipotentialRelation.cpp
|
||||
EquipotentialComponents.cpp
|
||||
TramontanaEngine.cpp
|
||||
GraphicTramontanaEngine.cpp
|
||||
EquipotentialsModel.cpp
|
||||
EquipotentialsWidget.cpp
|
||||
TabEquipotentials.cpp
|
||||
)
|
||||
set( pyCpps PyTramontana.cpp
|
||||
PyTramontanaEngine.cpp
|
||||
PyGraphicTramontanaEngine.cpp
|
||||
)
|
||||
qtX_wrap_cpp( mocCpps ${mocIncludes} )
|
||||
|
||||
set( depLibs ${CORIOLIS_PYTHON_LIBRARIES}
|
||||
${CORIOLIS_LIBRARIES}
|
||||
${HURRICANE_PYTHON_LIBRARIES}
|
||||
${HURRICANE_GRAPHICAL_LIBRARIES}
|
||||
${HURRICANE_LIBRARIES}
|
||||
${CONFIGURATION_LIBRARY}
|
||||
${UTILITIES_LIBRARY}
|
||||
${LEFDEF_LIBRARIES}
|
||||
${QtX_LIBRARIES}
|
||||
${Boost_LIBRARIES}
|
||||
${Python3_LIBRARIES}
|
||||
-lutil
|
||||
${LIBEXECINFO_LIBRARIES}
|
||||
)
|
||||
|
||||
add_library( tramontana ${cpps} ${mocCpps} ${pyCpps} )
|
||||
set_target_properties( tramontana PROPERTIES VERSION 1.0 SOVERSION 1 )
|
||||
target_link_libraries( tramontana ${depLibs} )
|
||||
|
||||
add_python_module( "${pyCpps}"
|
||||
"${pyIncludes}"
|
||||
"Do_not_generate_C_library"
|
||||
Tramontana
|
||||
"tramontana;${depLibs}"
|
||||
include/coriolis2/tramontana
|
||||
)
|
||||
|
||||
install( TARGETS tramontana DESTINATION lib${LIB_SUFFIX} )
|
||||
install( FILES ${includes}
|
||||
${mocIncludes} DESTINATION include/coriolis2/tramontana )
|
||||
|
||||
|
|
@ -0,0 +1,533 @@
|
|||
// -*- C++ -*-
|
||||
//
|
||||
// This file is part of the Coriolis Software.
|
||||
// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved
|
||||
//
|
||||
// +-----------------------------------------------------------------+
|
||||
// | C O R I O L I S |
|
||||
// | T r a m o n t a n a - Extractor & LVX |
|
||||
// | |
|
||||
// | Algorithm : Christian MASSON |
|
||||
// | First impl. : Yifei WU |
|
||||
// | Second impl. : Jean-Paul CHAPUT |
|
||||
// | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
// | =============================================================== |
|
||||
// | C++ Module : "./Equipotential.cpp" |
|
||||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#include <iomanip>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include "hurricane/utilities/Path.h"
|
||||
#include "hurricane/DebugSession.h"
|
||||
#include "hurricane/UpdateSession.h"
|
||||
#include "hurricane/Bug.h"
|
||||
#include "hurricane/Error.h"
|
||||
#include "hurricane/Warning.h"
|
||||
#include "hurricane/Breakpoint.h"
|
||||
#include "hurricane/Timer.h"
|
||||
#include "hurricane/Layer.h"
|
||||
#include "hurricane/Net.h"
|
||||
#include "hurricane/Pad.h"
|
||||
#include "hurricane/Contact.h"
|
||||
#include "hurricane/Plug.h"
|
||||
#include "hurricane/Cell.h"
|
||||
#include "hurricane/Instance.h"
|
||||
#include "hurricane/Vertical.h"
|
||||
#include "hurricane/Horizontal.h"
|
||||
#include "hurricane/RoutingPad.h"
|
||||
#include "crlcore/Utilities.h"
|
||||
#include "tramontana/Equipotential.h"
|
||||
#include "tramontana/EquipotentialRelation.h"
|
||||
#include "tramontana/EquipotentialComponents.h"
|
||||
#include "tramontana/TramontanaEngine.h"
|
||||
|
||||
|
||||
namespace Tramontana {
|
||||
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
using std::dec;
|
||||
using std::setw;
|
||||
using std::setfill;
|
||||
using std::left;
|
||||
using std::string;
|
||||
using std::ostream;
|
||||
using std::ofstream;
|
||||
using std::ostringstream;
|
||||
using std::setprecision;
|
||||
using std::vector;
|
||||
using std::set;
|
||||
using std::make_pair;
|
||||
using Hurricane::dbo_ptr;
|
||||
using Hurricane::UpdateSession;
|
||||
using Hurricane::DebugSession;
|
||||
using Hurricane::tab;
|
||||
using Hurricane::Bug;
|
||||
using Hurricane::Error;
|
||||
using Hurricane::Warning;
|
||||
using Hurricane::Breakpoint;
|
||||
using Hurricane::Box;
|
||||
using Hurricane::Layer;
|
||||
using Hurricane::Entity;
|
||||
using Hurricane::Net;
|
||||
using Hurricane::Plug;
|
||||
using Hurricane::Contact;
|
||||
using Hurricane::Horizontal;
|
||||
using Hurricane::Vertical;
|
||||
using Hurricane::RoutingPad;
|
||||
using Hurricane::Cell;
|
||||
using Hurricane::Instance;
|
||||
using Hurricane::Path;
|
||||
|
||||
|
||||
bool NetCompareByName::operator() ( const Net* lhs, const Net* rhs ) const
|
||||
{
|
||||
if (lhs->isFused () != rhs->isFused ()) return rhs->isFused();
|
||||
if (lhs->isAutomatic() != rhs->isAutomatic()) return rhs->isAutomatic();
|
||||
if (lhs->isGlobal () != rhs->isGlobal ()) return rhs->isGlobal();
|
||||
|
||||
if (lhs->getName().size() != rhs->getName().size())
|
||||
return lhs->getName().size() < rhs->getName().size();
|
||||
return lhs->getName() < rhs->getName();
|
||||
}
|
||||
|
||||
|
||||
bool OccNetCompareByName::operator() ( const Occurrence& lhs, const Occurrence& rhs ) const
|
||||
{
|
||||
static NetCompareByName compareByName;
|
||||
|
||||
size_t lhsLength = lhs.getPath().getInstances().getSize();
|
||||
size_t rhsLength = rhs.getPath().getInstances().getSize();
|
||||
|
||||
if (lhsLength != rhsLength) return lhsLength < rhsLength;
|
||||
return compareByName( static_cast<Net*>(lhs.getEntity()), static_cast<Net*>(rhs.getEntity()) );
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "Tramontana::Equipotential".
|
||||
|
||||
|
||||
Equipotential* Equipotential::get ( Component* component )
|
||||
{
|
||||
EquipotentialRelation* relation = dynamic_cast<EquipotentialRelation*>(
|
||||
component->getNet()->getProperty( EquipotentialRelation::staticGetName() ));
|
||||
if (not relation) {
|
||||
relation = dynamic_cast<EquipotentialRelation*>(
|
||||
component->getProperty( EquipotentialRelation::staticGetName() ));
|
||||
}
|
||||
if (not relation) return nullptr;
|
||||
return dynamic_cast<Equipotential*>( relation->getMasterOwner() );
|
||||
}
|
||||
|
||||
|
||||
Equipotential* Equipotential::get ( Occurrence occurrence )
|
||||
{
|
||||
EquipotentialRelation* relation = dynamic_cast<EquipotentialRelation*>(
|
||||
occurrence.getProperty( EquipotentialRelation::staticGetName() ));
|
||||
if (not relation) return nullptr;
|
||||
return dynamic_cast<Equipotential*>( relation->getMasterOwner() );
|
||||
}
|
||||
|
||||
|
||||
Occurrence Equipotential::getChildEqui ( Occurrence flatOccurrence )
|
||||
{
|
||||
Component* component = dynamic_cast<Component*>( flatOccurrence.getEntity() );
|
||||
if (not component) {
|
||||
cerr << Error( "Equipotential::getChildEqui(): Occurrence must be over a Component.\n"
|
||||
" (on:%s)"
|
||||
, getString(flatOccurrence).c_str()
|
||||
) << endl;
|
||||
return Occurrence();
|
||||
}
|
||||
|
||||
Equipotential* equi = Equipotential::get( component );
|
||||
if (not equi) {
|
||||
cerr << Error( "Equipotential::getChildEqui(): Component not associated to an Equipotential.\n"
|
||||
" (on:%s)"
|
||||
, getString(flatOccurrence).c_str()
|
||||
) << endl;
|
||||
return Occurrence();
|
||||
}
|
||||
|
||||
if (flatOccurrence.getPath().isEmpty()) return flatOccurrence;
|
||||
|
||||
// cerr << "childEqui:" << flatOccurrence << endl;
|
||||
// cerr << " " << equi << endl;
|
||||
Instance* tailInst = flatOccurrence.getPath().getTailInstance();
|
||||
Path headPath = flatOccurrence.getPath().getHeadPath();
|
||||
Occurrence tailOccurrence;
|
||||
while ( tailInst ) {
|
||||
tailOccurrence = Occurrence( equi, tailInst );
|
||||
equi = Equipotential::get( tailOccurrence );
|
||||
tailInst = headPath.getTailInstance();
|
||||
headPath = headPath.getHeadPath();
|
||||
}
|
||||
|
||||
// cerr << " ==> " << tailOccurrence << endl;
|
||||
// cerr << " " << equi << endl;
|
||||
return tailOccurrence;
|
||||
}
|
||||
|
||||
|
||||
Equipotential::Equipotential ( Cell* owner )
|
||||
: _owner (owner)
|
||||
, _boundingBox ()
|
||||
, _components ()
|
||||
, _childs ()
|
||||
, _name ()
|
||||
, _type (Net::Type::UNDEFINED)
|
||||
, _direction (Net::Direction::DirUndefined)
|
||||
, _netCount (0)
|
||||
, _isBuried (false)
|
||||
, _isExternal (false)
|
||||
, _isGlobal (false)
|
||||
, _isAutomatic (false)
|
||||
, _hasFused (false)
|
||||
, _shortCircuits()
|
||||
{
|
||||
_name = "Unnamed_" + getString( getId() );
|
||||
}
|
||||
|
||||
|
||||
void Equipotential::_postCreate ()
|
||||
{
|
||||
Super::_postCreate();
|
||||
TramontanaEngine* tramontana = TramontanaEngine::get( _owner );
|
||||
tramontana->add( this );
|
||||
}
|
||||
|
||||
|
||||
Equipotential* Equipotential::create ( Cell* owner )
|
||||
{
|
||||
Equipotential* equi = new Equipotential ( owner );
|
||||
equi->_postCreate();
|
||||
return equi;
|
||||
}
|
||||
|
||||
|
||||
void Equipotential::_preDestroy ()
|
||||
{
|
||||
Super::_preDestroy();
|
||||
}
|
||||
|
||||
|
||||
Equipotential::~Equipotential ()
|
||||
{
|
||||
for ( ShortCircuit* shortCircuit : _shortCircuits ) delete shortCircuit;
|
||||
}
|
||||
|
||||
|
||||
Cell* Equipotential::getCell () const
|
||||
{ return _owner; }
|
||||
|
||||
|
||||
Box Equipotential::getBoundingBox () const
|
||||
{ return _boundingBox; }
|
||||
|
||||
|
||||
Occurrences Equipotential::getFlatComponents () const
|
||||
{ return EquipotentialComponents( this ); }
|
||||
|
||||
|
||||
void Equipotential::add ( Occurrence occ, const Box& boundingBox )
|
||||
{
|
||||
if(occ.getPath().isEmpty()) {
|
||||
Contact* contact = dynamic_cast<Contact*>( occ.getEntity() );
|
||||
if ((_components.find(occ) != _components.end())) {
|
||||
if (not contact)
|
||||
cdebug_log(160,0) << "Equipotential::add(): Duplicated " << occ.getCompactString() << endl;
|
||||
return;
|
||||
}
|
||||
Component* comp = dynamic_cast<Component*>( occ.getEntity() );
|
||||
if (not comp) {
|
||||
cerr << Error( "Equipotential::add(): Occurrences with null Path must be Components.\n"
|
||||
" (on:%s)"
|
||||
, getString(occ).c_str()
|
||||
) << endl;
|
||||
return;
|
||||
}
|
||||
cdebug_log(160,0) << "Equipotential::add(): " << occ << endl;
|
||||
_components.insert( occ );
|
||||
NetMap::iterator inet = _nets.find( comp->getNet() );
|
||||
if (inet != _nets.end()) {
|
||||
inet->second.first++;
|
||||
if (inet->second.first > inet->second.second) {
|
||||
cerr << Error( "Equipotential::add(): Doubly counted component of %s.\n"
|
||||
" (on:%s)"
|
||||
, getString(inet->first).c_str()
|
||||
, getString(occ).c_str()
|
||||
) << endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
uint32_t compCount = 0;
|
||||
for ( Component* component : comp->getNet()->getComponents() ) {
|
||||
if (dynamic_cast<Plug*>(component)) continue;
|
||||
++compCount;
|
||||
}
|
||||
_nets.insert( make_pair( comp->getNet(), make_pair(1,compCount) ));
|
||||
if (comp->getNet()->isFused()) {
|
||||
_hasFused = true;
|
||||
return;
|
||||
}
|
||||
if (_nets.size() <= 1 + ((_hasFused) ? 1 : 0))
|
||||
return;
|
||||
Net* netA = nullptr;
|
||||
for ( auto item : _nets ) {
|
||||
if (not item.first->isFused() and (item.first != comp->getNet())) {
|
||||
netA = item.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_shortCircuits.push_back( new ShortCircuit( netA, comp->getNet(), comp ));
|
||||
} else {
|
||||
Equipotential* equi = dynamic_cast<Equipotential*>( occ.getEntity() );
|
||||
if (not equi) {
|
||||
cerr << Error( "Equipotential::add(): Occurrence is not an Equipotential.\n"
|
||||
" (on:%s)"
|
||||
, getString(occ).c_str()
|
||||
) << endl;
|
||||
return;
|
||||
}
|
||||
if (not occ.getPath().getTailPath().isEmpty()) {
|
||||
cerr << Error( "Equipotential::add(): Occurrence is more than one instances deep.\n"
|
||||
" (on:%s)"
|
||||
, getString(occ).c_str()
|
||||
) << endl;
|
||||
return;
|
||||
}
|
||||
_childs.insert( occ );
|
||||
}
|
||||
_boundingBox.merge( boundingBox );
|
||||
}
|
||||
|
||||
void Equipotential::merge ( Equipotential* other )
|
||||
{
|
||||
if (this == other) {
|
||||
cerr << Warning( "Equipotential::merge(): Attempt to merge itself (ignored).\n"
|
||||
" (on: %s)"
|
||||
, getString(this).c_str()
|
||||
) << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
for ( auto otherNetData : other->_nets ) {
|
||||
NetMap::iterator inet = _nets.find( otherNetData.first );
|
||||
if (inet != _nets.end()) {
|
||||
//inet->second.first += otherNetData.second.first;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (otherNetData.first->isFused()) _hasFused = true;
|
||||
_nets.insert( make_pair( otherNetData.first, make_pair(0,otherNetData.second.second) ));
|
||||
|
||||
if (_nets.size() > 1 + ((_hasFused) ? 1 : 0)) {
|
||||
cdebug_log(169,0) << "Short by merging equis." << _nets.size() << endl;
|
||||
for ( auto inet : _nets ) {
|
||||
cdebug_log(169,0) << "this | " << inet.first << endl;
|
||||
}
|
||||
for ( auto inet : other->_nets ) {
|
||||
cdebug_log(169,0) << "other | " << inet.first << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//cerr << "Equipotential::merge() " << this << endl;
|
||||
//cerr << " " << other << endl;
|
||||
for ( const Occurrence& component : other->getComponents () ) add( component );
|
||||
for ( const Occurrence& child : other->getChilds () ) add( child );
|
||||
for ( ShortCircuit* shortCircuit : other->getShortCircuits () ) add( shortCircuit );
|
||||
_boundingBox.merge( other->_boundingBox );
|
||||
//cerr << "Equipotential::merge() done" << endl;
|
||||
other->clear();
|
||||
}
|
||||
|
||||
|
||||
void Equipotential::consolidate ()
|
||||
{
|
||||
EquipotentialRelation* relation = EquipotentialRelation::create( this );
|
||||
|
||||
|
||||
for ( const Occurrence& occurrence : getComponents() ) {
|
||||
Component* component = dynamic_cast<Component*>( occurrence.getEntity() );
|
||||
if (not component) continue;
|
||||
if (not occurrence.getPath().isEmpty()) {
|
||||
//cerr << "Occurrence from a DeepNet " << occurrence << endl;
|
||||
continue;
|
||||
}
|
||||
component->put( relation );
|
||||
}
|
||||
|
||||
if (not _nets.empty()) {
|
||||
_name = getString( (*_nets.begin()).first->getName() );
|
||||
}
|
||||
|
||||
for ( auto netData : _nets ) {
|
||||
Net* net = netData.first;
|
||||
if (net->isFused()) continue;
|
||||
if (net->isExternal ()) _isExternal = true;
|
||||
if (net->isGlobal ()) _isGlobal = true;
|
||||
if (net->isAutomatic()) _isAutomatic = true;
|
||||
_type = net->getType();
|
||||
_direction |= net->getDirection();
|
||||
|
||||
if (netData.second.first >= netData.second.second) {
|
||||
for ( Component* component : net->getComponents() ) {
|
||||
if (dynamic_cast<Plug*>(component)) continue;
|
||||
component->remove( relation );
|
||||
}
|
||||
net->put( relation );
|
||||
}
|
||||
cdebug_log(169,0) << netData.first << " [" << netData.second.first
|
||||
<< " / " << netData.second.second << "]" << endl;
|
||||
}
|
||||
|
||||
for ( Occurrence childEqui : _childs ) {
|
||||
childEqui.put( relation );
|
||||
}
|
||||
if (_components.empty() and _nets.empty()) _isBuried = true;
|
||||
|
||||
#if FIRST_IMPLEMENTATION
|
||||
EquipotentialRelation* relation = EquipotentialRelation::create( this );
|
||||
map<Net*,uint32_t,NetCompareByName> nets;
|
||||
set<Occurrence,OccNetCompareByName> deepNets;
|
||||
for ( const Occurrence& occurrence : getComponents() ) {
|
||||
Component* component = dynamic_cast<Component*>( occurrence.getEntity() );
|
||||
if (not component) continue;
|
||||
if (not occurrence.getPath().isEmpty()) {
|
||||
deepNets.insert( Occurrence( component->getNet(), occurrence.getPath() ));
|
||||
continue;
|
||||
}
|
||||
component->put( relation );
|
||||
Net* net = component->getNet();
|
||||
if (net->isFused()) _hasFused = true;
|
||||
else {
|
||||
if (net->isExternal ()) _isExternal = true;
|
||||
if (net->isGlobal ()) _isGlobal = true;
|
||||
if (net->isAutomatic()) _isAutomatic = true;
|
||||
_type = net->getType();
|
||||
_direction |= net->getDirection();
|
||||
}
|
||||
uint32_t accounted = (dynamic_cast<Plug*>(component)) ? 0 : 1;
|
||||
auto inet = nets.find( component->getNet() );
|
||||
if (inet != nets.end())
|
||||
inet->second += accounted;
|
||||
else
|
||||
nets.insert( make_pair( component->getNet(), accounted ) );
|
||||
}
|
||||
if (not nets.empty()) {
|
||||
_name = getString( (*nets.begin()).first->getName() );
|
||||
} else {
|
||||
if (not deepNets.empty()) {
|
||||
_name = (*deepNets.begin()).getCompactString();
|
||||
}
|
||||
}
|
||||
_netCount = nets.size();
|
||||
|
||||
for ( auto item : nets ) {
|
||||
Net* net = item.first;
|
||||
uint32_t count = 0;
|
||||
for ( Component* component : net->getComponents() ) {
|
||||
count += (dynamic_cast<Plug*>(component)) ? 0 : 1;
|
||||
}
|
||||
if (count > item.second) continue;
|
||||
if (count < item.second) {
|
||||
cerr << Error( "Equipotential::consolidate(): On %s, found more components of %s than existing (%d > %d)."
|
||||
, getString(this).c_str()
|
||||
, getString(net).c_str()
|
||||
, item.second
|
||||
, count ) << endl;
|
||||
}
|
||||
for ( Component* component : net->getComponents() ) {
|
||||
if (dynamic_cast<Plug*>(component)) continue;
|
||||
component->remove( relation );
|
||||
}
|
||||
net->put( relation );
|
||||
//_nets.insert( net );
|
||||
}
|
||||
for ( Occurrence childEqui : _childs ) {
|
||||
childEqui.put( relation );
|
||||
}
|
||||
if (_components.empty() and _nets.empty()) _isBuried = true;
|
||||
|
||||
// if (_name == "abc_11873_auto_rtlil_cc_2560_muxgate_11612")
|
||||
// show();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Equipotential::clear ()
|
||||
{
|
||||
_components .clear();
|
||||
_childs .clear();
|
||||
_nets .clear();
|
||||
_shortCircuits.clear();
|
||||
}
|
||||
|
||||
|
||||
void Equipotential::show () const
|
||||
{
|
||||
cerr << this << endl;
|
||||
cerr << "+ Components:" << endl;
|
||||
for ( const Occurrence& component : _components ) {
|
||||
cerr << "| " << component << endl;
|
||||
}
|
||||
cerr << "+ Occurrences:" << endl;
|
||||
for ( Occurrence occ : _childs ) {
|
||||
cerr << "| " << occ << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string Equipotential::getFlagsAsString () const
|
||||
{
|
||||
string sflags;
|
||||
sflags += ((_isExternal ) ? "e" : "-");
|
||||
sflags += ((_isGlobal ) ? "g" : "-");
|
||||
sflags += ((_isAutomatic) ? "a" : "-");
|
||||
sflags += ((_isBuried ) ? "B" : "-");
|
||||
sflags += " [N:" + getString( _nets.size() - ((_hasFused) ? 1 : 0) );
|
||||
sflags += "+E:" + getString( _childs.size() );
|
||||
if (_hasFused)
|
||||
sflags += "+fused";
|
||||
sflags += "] ";
|
||||
return sflags;
|
||||
}
|
||||
|
||||
|
||||
string Equipotential::_getTypeName () const
|
||||
{ return "Tramontana::Equipotential"; }
|
||||
|
||||
|
||||
string Equipotential::_getString () const
|
||||
{
|
||||
ostringstream os;
|
||||
os << "<Equipotential id:" << getId() << " "
|
||||
<< getFlagsAsString()
|
||||
<< " " << getName()
|
||||
<< " " << getType()
|
||||
<< " " << getDirection()
|
||||
<< ">";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
|
||||
Record* Equipotential::_getRecord () const
|
||||
{
|
||||
Record* record = Super::_getRecord();
|
||||
if (record) {
|
||||
record->add( getSlot( "_name" , &_name ) );
|
||||
record->add( getSlot( "_boundingBox", &_boundingBox ) );
|
||||
//record->add( getSlot( "_nets" , &_nets ) );
|
||||
record->add( getSlot( "_components" , &_components ) );
|
||||
record->add( getSlot( "_childs" , &_childs ) );
|
||||
}
|
||||
return record;
|
||||
}
|
||||
|
||||
|
||||
} // Tramontana namespace.
|
|
@ -0,0 +1,245 @@
|
|||
// -*- C++ -*-
|
||||
//
|
||||
// This file is part of the Coriolis Software.
|
||||
// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved
|
||||
//
|
||||
// +-----------------------------------------------------------------+
|
||||
// | C O R I O L I S |
|
||||
// | T r a m o n t a n a - Extractor & LVX |
|
||||
// | |
|
||||
// | Algorithm : Christian MASSON |
|
||||
// | First impl. : Yifei WU |
|
||||
// | Second impl. : Jean-Paul CHAPUT |
|
||||
// | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
// | =============================================================== |
|
||||
// | C++ Module : "./EquipotentialComponents.cpp" |
|
||||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#include "hurricane/Error.h"
|
||||
#include "tramontana/EquipotentialComponents.h"
|
||||
#include "tramontana/Equipotential.h"
|
||||
|
||||
|
||||
namespace Tramontana {
|
||||
|
||||
using namespace std;
|
||||
using Hurricane::tab;
|
||||
using Hurricane::Error;
|
||||
using Hurricane::Path;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "Tramontana::EquipotentialComponents".
|
||||
|
||||
EquipotentialComponents::EquipotentialComponents ()
|
||||
: Super()
|
||||
, _equipotential(nullptr)
|
||||
{ }
|
||||
|
||||
|
||||
EquipotentialComponents::EquipotentialComponents ( const Equipotential* equi )
|
||||
: Super()
|
||||
, _equipotential(equi)
|
||||
{ }
|
||||
|
||||
|
||||
EquipotentialComponents::EquipotentialComponents ( const EquipotentialComponents& other )
|
||||
: Super()
|
||||
, _equipotential(other._equipotential)
|
||||
{ }
|
||||
|
||||
|
||||
EquipotentialComponents& EquipotentialComponents::operator= ( const EquipotentialComponents& other )
|
||||
{
|
||||
_equipotential = other._equipotential;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Collection<Occurrence>* EquipotentialComponents::getClone () const
|
||||
{ return new EquipotentialComponents( *this ); }
|
||||
|
||||
|
||||
Locator<Occurrence>* EquipotentialComponents::getLocator () const
|
||||
{ return new Locator ( _equipotential ); }
|
||||
|
||||
|
||||
string EquipotentialComponents::_getString () const
|
||||
{
|
||||
string s = "<EquipotentialComponents ";
|
||||
if (_equipotential) {
|
||||
s += " " + getString( _equipotential );
|
||||
} else {
|
||||
s += " NULL";
|
||||
}
|
||||
s += ">";
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "Tramontana::EquipotentialComponents::Locator".
|
||||
|
||||
|
||||
EquipotentialComponents::Locator::Locator ()
|
||||
: Super()
|
||||
, _equipotential (nullptr)
|
||||
, _state (Constructed)
|
||||
, _componentsIterator()
|
||||
, _netsIterator ()
|
||||
, _childsIterator ()
|
||||
, _childCompsLocator (nullptr)
|
||||
, _componentsLocator (nullptr)
|
||||
{ }
|
||||
|
||||
|
||||
EquipotentialComponents::Locator::Locator ( const Equipotential* equi )
|
||||
: Super()
|
||||
, _equipotential (equi)
|
||||
, _state (Constructed)
|
||||
, _componentsIterator(equi->getComponents().end())
|
||||
, _netsIterator (equi->getNets().end())
|
||||
, _childsIterator (equi->getChilds().end())
|
||||
, _childCompsLocator (nullptr)
|
||||
, _componentsLocator (nullptr)
|
||||
{
|
||||
progress();
|
||||
}
|
||||
|
||||
|
||||
EquipotentialComponents::Locator::Locator ( const Locator& other )
|
||||
: Super()
|
||||
, _equipotential (other._equipotential)
|
||||
, _state (other._state)
|
||||
, _componentsIterator(other._componentsIterator)
|
||||
, _netsIterator (other._netsIterator)
|
||||
, _childsIterator (other._childsIterator)
|
||||
, _childCompsLocator (nullptr)
|
||||
, _componentsLocator (nullptr)
|
||||
{
|
||||
if (other._childCompsLocator) _childCompsLocator = other._childCompsLocator->getClone();
|
||||
if (other._componentsLocator) _componentsLocator = other._componentsLocator->getClone();
|
||||
}
|
||||
|
||||
|
||||
EquipotentialComponents::Locator& EquipotentialComponents::Locator::operator= ( const Locator& other )
|
||||
{
|
||||
_equipotential = other._equipotential;
|
||||
_state = other._state;
|
||||
_componentsIterator= other._componentsIterator;
|
||||
_netsIterator = other._netsIterator;
|
||||
_childsIterator = other._childsIterator;
|
||||
_componentsLocator = (other._componentsLocator) ? other._componentsLocator->getClone() : nullptr;
|
||||
_childCompsLocator = (other._childCompsLocator) ? other._childCompsLocator->getClone() : nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Occurrence EquipotentialComponents::Locator::getElement () const
|
||||
{
|
||||
if (not _equipotential or (_state >= Finished)) return Occurrence();
|
||||
switch ( _state ) {
|
||||
case InComponents: return (*_componentsIterator);
|
||||
case InNets: return Occurrence( _componentsLocator->getElement() );
|
||||
case InChildEquis: {
|
||||
Path compPath = (*_childsIterator).getPath();
|
||||
Path tailPath = _childCompsLocator->getElement().getPath();
|
||||
while ( not tailPath.isEmpty() ) {
|
||||
compPath = Path( compPath, tailPath.getHeadInstance() );
|
||||
tailPath = tailPath.getTailPath();
|
||||
}
|
||||
return Occurrence( _childCompsLocator->getElement().getEntity(), compPath );
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Occurrence();
|
||||
}
|
||||
|
||||
|
||||
Locator<Occurrence>* EquipotentialComponents::Locator::getClone () const
|
||||
{ return new Locator( *this ); }
|
||||
|
||||
|
||||
bool EquipotentialComponents::Locator::isValid () const
|
||||
{ return (_equipotential) and (_state < Finished); }
|
||||
|
||||
|
||||
void EquipotentialComponents::Locator::progress ()
|
||||
{
|
||||
while ( isValid() ) {
|
||||
switch ( _state ) {
|
||||
case Constructed: {
|
||||
_state = InComponents;
|
||||
_componentsIterator = _equipotential->getComponents().begin();
|
||||
if (_componentsIterator != _equipotential->getComponents().end()) return;
|
||||
}
|
||||
case InComponents: {
|
||||
if (_componentsIterator != _equipotential->getComponents().end()) {
|
||||
++_componentsIterator;
|
||||
if (_componentsIterator != _equipotential->getComponents().end()) return;
|
||||
}
|
||||
_state = InNets;
|
||||
_netsIterator = _equipotential->getNets().begin();
|
||||
}
|
||||
case InNets: {
|
||||
if (_netsIterator != _equipotential->getNets().end()) {
|
||||
if ( not _netsIterator->first->isFused()
|
||||
and _netsIterator->first->getProperty(EquipotentialRelation::staticGetName())) {
|
||||
if (not _componentsLocator) {
|
||||
_componentsLocator = _netsIterator->first->getComponents().getLocator()->getClone();
|
||||
if (_componentsLocator->isValid()) return;
|
||||
} else {
|
||||
_componentsLocator->progress();
|
||||
if (_componentsLocator->isValid()) return;
|
||||
}
|
||||
}
|
||||
|
||||
_componentsLocator = nullptr;
|
||||
++_netsIterator;
|
||||
if (_netsIterator != _equipotential->getNets().end())
|
||||
continue;
|
||||
}
|
||||
_state = InChildEquis;
|
||||
_childsIterator = _equipotential->getChilds().begin();
|
||||
}
|
||||
case InChildEquis: {
|
||||
if (_childsIterator != _equipotential->getChilds().end()) {
|
||||
if (not _childCompsLocator) {
|
||||
Equipotential* child = dynamic_cast<Equipotential*>( (*_childsIterator).getEntity() );
|
||||
_childCompsLocator = child->getFlatComponents().getLocator()->getClone();
|
||||
if (_childCompsLocator->isValid()) return;
|
||||
} else {
|
||||
_childCompsLocator->progress();
|
||||
if (_childCompsLocator->isValid()) return;
|
||||
}
|
||||
|
||||
_childCompsLocator = nullptr;
|
||||
++_childsIterator;
|
||||
if (_childsIterator != _equipotential->getChilds().end())
|
||||
continue;
|
||||
}
|
||||
_state = Finished;
|
||||
}
|
||||
case Finished:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string EquipotentialComponents::Locator::_getString () const
|
||||
{
|
||||
string s = "<EquipotentialComponents::Locator";
|
||||
if (_equipotential) {
|
||||
s += " " + getString(_equipotential);
|
||||
} else {
|
||||
s += " NULL";
|
||||
}
|
||||
s += ">";
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
} // Tramontana namespace.
|
|
@ -0,0 +1,86 @@
|
|||
// -*- C++ -*-
|
||||
//
|
||||
// This file is part of the Coriolis Software.
|
||||
// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved
|
||||
//
|
||||
// +-----------------------------------------------------------------+
|
||||
// | C O R I O L I S |
|
||||
// | T r a m o n t a n a - Extractor & LVX |
|
||||
// | |
|
||||
// | Algorithm : Christian MASSON |
|
||||
// | First impl. : Yifei WU |
|
||||
// | Second impl. : Jean-Paul CHAPUT |
|
||||
// | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
// | =============================================================== |
|
||||
// | C++ Module : "./EquipotentialRelation.cpp" |
|
||||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#include "tramontana/EquipotentialRelation.h"
|
||||
#include "tramontana/TramontanaEngine.h"
|
||||
|
||||
|
||||
namespace Tramontana {
|
||||
|
||||
using std::string;
|
||||
using Hurricane::Property;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "Tramontana::EquipotentialRelation".
|
||||
|
||||
const Name EquipotentialRelationName = "EquipotentialRelation";
|
||||
|
||||
|
||||
EquipotentialRelation::EquipotentialRelation ( Equipotential* owner )
|
||||
: Super(owner)
|
||||
{ }
|
||||
|
||||
|
||||
EquipotentialRelation* EquipotentialRelation::create ( Equipotential* owner )
|
||||
{
|
||||
EquipotentialRelation* relation = new EquipotentialRelation ( owner );
|
||||
relation->_postCreate();
|
||||
return relation;
|
||||
}
|
||||
|
||||
|
||||
void EquipotentialRelation::_preDestroy ()
|
||||
{ Super::_preDestroy(); }
|
||||
|
||||
|
||||
Name EquipotentialRelation::staticGetName ()
|
||||
{ return EquipotentialRelationName; }
|
||||
|
||||
|
||||
Name EquipotentialRelation::getName () const
|
||||
{ return EquipotentialRelationName; }
|
||||
|
||||
|
||||
string EquipotentialRelation::_getTypeName () const
|
||||
{ return "EquipotentialRelation"; }
|
||||
|
||||
|
||||
Record* EquipotentialRelation::_getRecord () const
|
||||
{
|
||||
Record* record = Super::_getRecord();
|
||||
return record;
|
||||
}
|
||||
|
||||
|
||||
EquipotentialRelation* EquipotentialRelation::get ( const Component* component )
|
||||
{
|
||||
if (not component) return nullptr;
|
||||
|
||||
Property* property = component->getProperty( EquipotentialRelationName );
|
||||
if (not property) return nullptr;
|
||||
|
||||
EquipotentialRelation* relation = dynamic_cast<EquipotentialRelation*>( property );
|
||||
if (not relation) return nullptr;
|
||||
return relation;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // Tramontana namespace.
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
// -*- C++ -*-
|
||||
//
|
||||
// This file is part of the Coriolis Software.
|
||||
// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved
|
||||
//
|
||||
// +-----------------------------------------------------------------+
|
||||
// | C O R I O L I S |
|
||||
// | T r a m o n t a n a - Extractor & LVX |
|
||||
// | |
|
||||
// | Algorithm : Christian MASSON |
|
||||
// | First impl. : Yifei WU |
|
||||
// | Second impl. : Jean-Paul CHAPUT |
|
||||
// | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
// | =============================================================== |
|
||||
// | C++ Module : "./EquipotentialsModel.cpp" |
|
||||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#include <QFont>
|
||||
#include <QApplication>
|
||||
#include "hurricane/Name.h"
|
||||
#include "hurricane/Net.h"
|
||||
#include "hurricane/Cell.h"
|
||||
#include "hurricane/viewer/Graphics.h"
|
||||
#include "tramontana/EquipotentialsModel.h"
|
||||
|
||||
|
||||
namespace Tramontana {
|
||||
|
||||
using Hurricane::Graphics;
|
||||
|
||||
|
||||
EquipotentialsModel::EquipotentialsModel ( QObject* parent )
|
||||
: QAbstractTableModel(parent)
|
||||
, _cell (nullptr)
|
||||
, _equipotentials ()
|
||||
{ }
|
||||
|
||||
|
||||
QVariant EquipotentialsModel::data ( const QModelIndex& index, int role ) const
|
||||
{
|
||||
static QFont nameFont = Graphics::getFixedFont ( QFont::Bold );
|
||||
static QFont valueFont = Graphics::getFixedFont ( QFont::Normal, true );
|
||||
|
||||
if (role == Qt::FontRole) {
|
||||
switch (index.column()) {
|
||||
case 0: return nameFont;
|
||||
default: return valueFont;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if (not index.isValid()) return QVariant ();
|
||||
|
||||
if (role == Qt::DisplayRole) {
|
||||
Equipotential* equi = _equipotentials[ index.row() ];
|
||||
switch ( index.column() ) {
|
||||
case 0: return QString::fromStdString( equi->getName() );
|
||||
case 1: return QString::fromStdString( equi->getFlagsAsString() );
|
||||
case 2: return QString::fromStdString( getString( equi->getType() ));
|
||||
case 3: return QString::fromStdString( getString( equi->getDirection() ));
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
|
||||
QVariant EquipotentialsModel::headerData ( int section
|
||||
, Qt::Orientation orientation
|
||||
, int role ) const
|
||||
{
|
||||
if (orientation == Qt::Vertical) return QVariant();
|
||||
|
||||
static QFont headerFont = Graphics::getFixedFont( QFont::Bold, false, false, +0 );
|
||||
|
||||
if (role == Qt::FontRole ) return headerFont;
|
||||
if (role != Qt::DisplayRole) return QVariant();
|
||||
if (section == 0) return QVariant( "Name" );
|
||||
if (section == 1) return QVariant( "Flags" );
|
||||
if (section == 2) return QVariant( "Type" );
|
||||
if (section == 3) return QVariant( "Direction" );
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
|
||||
int EquipotentialsModel::rowCount ( const QModelIndex& parent ) const
|
||||
{ return _equipotentials.size(); }
|
||||
|
||||
|
||||
int EquipotentialsModel::columnCount ( const QModelIndex& parent ) const
|
||||
{ return 4; }
|
||||
|
||||
|
||||
const Equipotential* EquipotentialsModel::getEqui ( int row )
|
||||
{
|
||||
if (row >= (int)_equipotentials.size()) return nullptr;
|
||||
return _equipotentials[ row ];
|
||||
}
|
||||
|
||||
|
||||
void EquipotentialsModel::setCell ( Cell* cell )
|
||||
{
|
||||
if (_cell != cell) {
|
||||
emit layoutAboutToBeChanged ();
|
||||
|
||||
if (_cell) _equipotentials.clear();
|
||||
_cell = cell;
|
||||
|
||||
if (_cell) {
|
||||
TramontanaEngine* tramontana = TramontanaEngine::get( _cell );
|
||||
if (tramontana) {
|
||||
for ( Equipotential* equi : tramontana->getEquipotentials() )
|
||||
_equipotentials.push_back( equi );
|
||||
}
|
||||
}
|
||||
|
||||
emit layoutChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // Tramontana namespace.
|
|
@ -0,0 +1,269 @@
|
|||
// -*- C++ -*-
|
||||
//
|
||||
// This file is part of the Coriolis Software.
|
||||
// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved
|
||||
//
|
||||
// +-----------------------------------------------------------------+
|
||||
// | C O R I O L I S |
|
||||
// | T r a m o n t a n a - Extractor & LVX |
|
||||
// | |
|
||||
// | Algorithm : Christian MASSON |
|
||||
// | First impl. : Yifei WU |
|
||||
// | Second impl. : Jean-Paul CHAPUT |
|
||||
// | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
// | =============================================================== |
|
||||
// | C++ Header : "./EquipotentialsWidget.cpp" |
|
||||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#include <QFontMetrics>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QHeaderView>
|
||||
#include <QKeyEvent>
|
||||
#include <QGroupBox>
|
||||
#include <QVBoxLayout>
|
||||
#include <QAction>
|
||||
#include <QModelIndex>
|
||||
#include "hurricane/Commons.h"
|
||||
#include "hurricane/viewer/Graphics.h"
|
||||
#include "tramontana/EquipotentialsModel.h"
|
||||
#include "tramontana/EquipotentialsWidget.h"
|
||||
|
||||
|
||||
namespace Tramontana {
|
||||
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
using Hurricane::Bug;
|
||||
using Hurricane::Graphics;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "BuriedFilterProxymodel".
|
||||
|
||||
|
||||
EquiFilterProxyModel::EquiFilterProxyModel ( QObject* parent )
|
||||
: Super (parent)
|
||||
, _filter(NoFilter)
|
||||
{ }
|
||||
|
||||
|
||||
void EquiFilterProxyModel::setFilter ( uint32_t filter )
|
||||
{ _filter = filter; invalidateFilter(); }
|
||||
|
||||
|
||||
bool EquiFilterProxyModel::filterAcceptsRow ( int row, const QModelIndex& index ) const
|
||||
{
|
||||
EquipotentialsModel* model = dynamic_cast<EquipotentialsModel*>( sourceModel() );
|
||||
if (not model) return true;
|
||||
|
||||
const Equipotential* equi = model->getEqui( row );
|
||||
if (not (_filter & ShowBuried) and equi->isBuried()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "EquipotentialsWidget".
|
||||
|
||||
|
||||
EquipotentialsWidget::EquipotentialsWidget ( QWidget* parent )
|
||||
: QWidget (parent)
|
||||
, _cellWidget (NULL)
|
||||
, _cell (NULL)
|
||||
, _baseModel (new EquipotentialsModel(this))
|
||||
, _sortModel (new QSortFilterProxyModel(this))
|
||||
, _filterModel (new EquiFilterProxyModel(this))
|
||||
, _view (new QTableView(this))
|
||||
, _rowHeight (20)
|
||||
, _selecteds ()
|
||||
, _forceReselect(false)
|
||||
{
|
||||
setAttribute( Qt::WA_DeleteOnClose );
|
||||
setAttribute( Qt::WA_QuitOnClose, false );
|
||||
setContextMenuPolicy( Qt::ActionsContextMenu );
|
||||
|
||||
_rowHeight = QFontMetrics( Graphics::getFixedFont() ).height() + 4;
|
||||
|
||||
_filterModel->setSourceModel ( _baseModel );
|
||||
//_filterModel->setFilter ( EquiFilterProxyModel::ShowBuried );
|
||||
_sortModel->setSourceModel ( _filterModel );
|
||||
_sortModel->setDynamicSortFilter( true );
|
||||
_sortModel->setFilterKeyColumn ( 0 );
|
||||
|
||||
_view->setShowGrid ( false );
|
||||
_view->setAlternatingRowColors( true );
|
||||
_view->setSelectionBehavior ( QAbstractItemView::SelectRows );
|
||||
_view->setSortingEnabled ( true );
|
||||
_view->setModel ( _sortModel );
|
||||
|
||||
QHeaderView* horizontalHeader = _view->horizontalHeader();
|
||||
horizontalHeader->setDefaultAlignment ( Qt::AlignHCenter );
|
||||
horizontalHeader->setMinimumSectionSize( (Graphics::isHighDpi()) ? 150 : 75 );
|
||||
horizontalHeader->setStretchLastSection( true );
|
||||
|
||||
QHeaderView* verticalHeader = _view->verticalHeader();
|
||||
verticalHeader->setVisible( false );
|
||||
verticalHeader->setDefaultSectionSize( _rowHeight );
|
||||
|
||||
// verticalHeader->setStyleSheet( "QHeaderView::section {"
|
||||
// "padding-bottom: 0px;"
|
||||
// "padding-top: 0px;"
|
||||
// "padding-left: 0px;"
|
||||
// "padding-right: 1px;"
|
||||
// "margin: 0px;"
|
||||
// "}"
|
||||
// );
|
||||
|
||||
_filterPatternLineEdit = new QLineEdit( this );
|
||||
QLabel* filterPatternLabel = new QLabel( tr("&Filter pattern:"), this );
|
||||
filterPatternLabel->setBuddy( _filterPatternLineEdit );
|
||||
|
||||
QGridLayout* gLayout = new QGridLayout();
|
||||
gLayout->addWidget( _view , 1, 0, 1, 2 );
|
||||
gLayout->addWidget( filterPatternLabel , 2, 0 );
|
||||
gLayout->addWidget( _filterPatternLineEdit, 2, 1 );
|
||||
|
||||
setLayout( gLayout );
|
||||
|
||||
QAction* fitAction = new QAction( tr("&Fit to Equi"), this );
|
||||
fitAction->setShortcut ( QKeySequence(tr("CTRL+F")) );
|
||||
fitAction->setStatusTip( tr("Fit the view to the Equipotentials's bounding box") );
|
||||
addAction( fitAction );
|
||||
|
||||
connect( _filterPatternLineEdit , SIGNAL(textChanged(const QString &))
|
||||
, this , SLOT (textFilterChanged()) );
|
||||
connect( _view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&))
|
||||
, this , SLOT (updateSelecteds (const QItemSelection&,const QItemSelection&)) );
|
||||
connect( fitAction, SIGNAL(triggered()), this, SLOT(fitToEqui()) );
|
||||
|
||||
resize( 300, 300 );
|
||||
}
|
||||
|
||||
|
||||
QModelIndex EquipotentialsWidget::mapToSource ( QModelIndex viewIndex ) const
|
||||
{ return _filterModel->mapToSource( _sortModel->mapToSource( viewIndex )); }
|
||||
|
||||
|
||||
void EquipotentialsWidget::setShowBuried ( bool state )
|
||||
{
|
||||
_filterModel->setFilter( (state) ? EquiFilterProxyModel::ShowBuried
|
||||
: EquiFilterProxyModel::NoFilter );
|
||||
}
|
||||
|
||||
|
||||
void EquipotentialsWidget::goTo ( int delta )
|
||||
{
|
||||
if ( delta == 0 ) return;
|
||||
|
||||
QModelIndex newIndex = _sortModel->index( _view->currentIndex().row()+delta, 0, QModelIndex() );
|
||||
if (newIndex.isValid())
|
||||
_view->selectRow( newIndex.row() );
|
||||
}
|
||||
|
||||
|
||||
void EquipotentialsWidget::updateSelecteds ()
|
||||
{
|
||||
_forceReselect = true;
|
||||
|
||||
QItemSelection dummy;
|
||||
updateSelecteds( dummy, dummy );
|
||||
}
|
||||
|
||||
|
||||
void EquipotentialsWidget::updateSelecteds ( const QItemSelection& , const QItemSelection& )
|
||||
{
|
||||
if (_cellWidget) _cellWidget->openRefreshSession ();
|
||||
|
||||
_selecteds.resetAccesses ();
|
||||
|
||||
const Equipotential* equi = nullptr;
|
||||
QModelIndexList iList = _view->selectionModel()->selectedRows();
|
||||
for ( int i=0 ; i<iList.size() ; i++ ) {
|
||||
equi = _baseModel->getEqui( mapToSource(iList[i]).row() );
|
||||
if ( equi )
|
||||
_selecteds.insert( equi );
|
||||
}
|
||||
|
||||
if (_forceReselect) {
|
||||
_selecteds.forceInserteds();
|
||||
_forceReselect = false;
|
||||
}
|
||||
|
||||
SelectedEquiSet::iterator isel = _selecteds.begin ();
|
||||
while ( isel != _selecteds.end() ) {
|
||||
SelectedEquiSet::iterator remove = isel++;
|
||||
if (remove->getAccesses() == 0) {
|
||||
emit equipotentialUnselect ( remove->getEqui()->getFlatComponents() );
|
||||
_selecteds.erase( remove );
|
||||
}
|
||||
}
|
||||
isel = _selecteds.begin ();
|
||||
while ( isel != _selecteds.end() ) {
|
||||
if (isel->getAccesses() == 64) {
|
||||
emit equipotentialSelect ( isel->getEqui()->getFlatComponents() );
|
||||
}
|
||||
++isel;
|
||||
}
|
||||
isel = _selecteds.begin ();
|
||||
|
||||
if (_cellWidget) _cellWidget->closeRefreshSession ();
|
||||
}
|
||||
|
||||
|
||||
void EquipotentialsWidget::textFilterChanged ()
|
||||
{
|
||||
_sortModel->setFilterRegExp( _filterPatternLineEdit->text() );
|
||||
//updateSelecteds ();
|
||||
}
|
||||
|
||||
|
||||
void EquipotentialsWidget::fitToEqui ()
|
||||
{
|
||||
const Equipotential* equi = _baseModel->getEqui( mapToSource(_view->currentIndex()).row() );
|
||||
if (equi) emit reframe ( equi->getBoundingBox() );
|
||||
}
|
||||
|
||||
|
||||
void EquipotentialsWidget::setCellWidget ( CellWidget* cw )
|
||||
{
|
||||
if (_cellWidget) {
|
||||
disconnect( this, 0, _cellWidget, 0 );
|
||||
}
|
||||
|
||||
_cellWidget = cw;
|
||||
if (_cellWidget) {
|
||||
setCell( _cellWidget->getCell() );
|
||||
connect( this, SIGNAL( reframe(const Box&) ), _cellWidget, SLOT( reframe(const Box&) ));
|
||||
} else
|
||||
setCell( nullptr );
|
||||
}
|
||||
|
||||
|
||||
void EquipotentialsWidget::setCell ( Cell* cell )
|
||||
{
|
||||
_cell = cell;
|
||||
_view->setVisible( false );
|
||||
_view->selectionModel()->clear();
|
||||
_baseModel->setCell( cell );
|
||||
|
||||
string windowTitle = "Equis" + getString(cell);
|
||||
setWindowTitle( tr(windowTitle.c_str()) );
|
||||
|
||||
QHeaderView* header = _view->horizontalHeader();
|
||||
|
||||
_view->selectRow( 0 );
|
||||
for ( int i=0 ; i<_baseModel->columnCount() ; ++i ) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
header->setSectionResizeMode( i, QHeaderView::Interactive );
|
||||
#else
|
||||
header->setResizeMode( i, QHeaderView::Interactive );
|
||||
#endif
|
||||
_view->resizeColumnToContents( i );
|
||||
}
|
||||
_view->setVisible( true );
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,258 @@
|
|||
// -*- C++ -*-
|
||||
//
|
||||
// This file is part of the Coriolis Software.
|
||||
// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved
|
||||
//
|
||||
// +-----------------------------------------------------------------+
|
||||
// | C O R I O L I S |
|
||||
// | T r a m o n t a n a - Extractor & LVX |
|
||||
// | |
|
||||
// | Algorithm : Christian MASSON |
|
||||
// | First impl. : Yifei WU |
|
||||
// | Second impl. : Jean-Paul CHAPUT |
|
||||
// | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
// | =============================================================== |
|
||||
// | C++ Module : "./GraphicTramontanaEngine.cpp" |
|
||||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
#include <QMenuBar>
|
||||
#include <QApplication>
|
||||
#include <hurricane/Warning.h>
|
||||
#include <hurricane/Error.h>
|
||||
#include <hurricane/Breakpoint.h>
|
||||
#include <hurricane/DebugSession.h>
|
||||
#include <hurricane/Go.h>
|
||||
#include <hurricane/Net.h>
|
||||
#include <hurricane/Cell.h>
|
||||
#include <hurricane/viewer/Graphics.h>
|
||||
#include <hurricane/viewer/CellWidget.h>
|
||||
#include <hurricane/viewer/CellViewer.h>
|
||||
#include <hurricane/viewer/ControllerWidget.h>
|
||||
#include <hurricane/viewer/ExceptionWidget.h>
|
||||
#include <crlcore/Utilities.h>
|
||||
#include <crlcore/AllianceFramework.h>
|
||||
#include <anabatic/GCell.h>
|
||||
#include <tramontana/TabEquipotentials.h>
|
||||
#include <tramontana/GraphicTramontanaEngine.h>
|
||||
|
||||
|
||||
namespace Tramontana {
|
||||
|
||||
using namespace std;
|
||||
using Hurricane::Error;
|
||||
using Hurricane::Warning;
|
||||
using Hurricane::Exception;
|
||||
using Hurricane::Breakpoint;
|
||||
using Hurricane::DebugSession;
|
||||
using Hurricane::Point;
|
||||
using Hurricane::Entity;
|
||||
using Hurricane::Net;
|
||||
using Hurricane::Graphics;
|
||||
using Hurricane::ColorScale;
|
||||
using Hurricane::DisplayStyle;
|
||||
using Hurricane::ControllerWidget;
|
||||
using Hurricane::ExceptionWidget;
|
||||
using CRL::Catalog;
|
||||
using CRL::AllianceFramework;
|
||||
|
||||
|
||||
size_t GraphicTramontanaEngine::_references = 0;
|
||||
GraphicTramontanaEngine* GraphicTramontanaEngine::_singleton = NULL;
|
||||
|
||||
|
||||
#if THIS_IS_DISABLED
|
||||
void GraphicTramontanaEngine::initGCell ( CellWidget* widget )
|
||||
{
|
||||
widget->getDrawingPlanes().setPen( Qt::NoPen );
|
||||
TramontanaEngine* tramontana = TramontanaEngine::get( widget->getCell() );
|
||||
if (tramontana) tramontana->setDensityMode( GCell::MaxDensity );
|
||||
}
|
||||
|
||||
|
||||
void GraphicTramontanaEngine::drawGCell ( CellWidget* widget
|
||||
, const Go* go
|
||||
, const BasicLayer* basicLayer
|
||||
, const Box& box
|
||||
, const Transformation& transformation
|
||||
)
|
||||
{
|
||||
const GCell* gcell = static_cast<const GCell*>(go);
|
||||
|
||||
QPainter& painter = widget->getPainter();
|
||||
QPen pen = Graphics::getPen ("Anabatic::GCell",widget->getDarkening());
|
||||
Box bb = gcell->getBoundingBox();
|
||||
QRect pixelBb = widget->dbuToScreenRect(bb);
|
||||
|
||||
if (GCell::getDisplayMode() == GCell::Density) {
|
||||
uint32_t density = (unsigned int)( 255.0 * gcell->getDensity() );
|
||||
if (density > 255) density = 255;
|
||||
|
||||
painter.setBrush( Graphics::getColorScale( ColorScale::Fire ).getBrush( density, widget->getDarkening() ) );
|
||||
painter.drawRect( pixelBb );
|
||||
} else {
|
||||
int fontScale = 0;
|
||||
int halfHeight = 20;
|
||||
int halfWidth = 80;
|
||||
if (widget->isPrinter()) {
|
||||
fontScale = -5;
|
||||
halfHeight = 9;
|
||||
halfWidth = 39;
|
||||
}
|
||||
|
||||
painter.setPen ( pen );
|
||||
painter.setBrush( Graphics::getBrush("Anabatic::GCell",widget->getDarkening()) );
|
||||
painter.drawRect( pixelBb );
|
||||
|
||||
if ( (pixelBb.width() > 2*halfWidth) and (pixelBb.height() > 2*halfHeight) ) {
|
||||
QString text = QString("%1").arg(gcell->getId());
|
||||
QFont font = Graphics::getFixedFont( QFont::Normal, false, false, fontScale );
|
||||
painter.setFont(font);
|
||||
|
||||
pen.setWidth( 1 );
|
||||
painter.setPen( pen );
|
||||
|
||||
painter.save ();
|
||||
painter.translate( widget->dbuToScreenPoint(bb.getCenter().getX(), bb.getCenter().getY()) );
|
||||
painter.drawRect ( QRect( -halfWidth, -halfHeight, 2*halfWidth, 2*halfHeight ) );
|
||||
painter.drawText ( QRect( -halfWidth, -halfHeight, 2*halfWidth, 2*halfHeight )
|
||||
, text
|
||||
, QTextOption(Qt::AlignCenter)
|
||||
);
|
||||
painter.restore ();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
TramontanaEngine* GraphicTramontanaEngine::createEngine ()
|
||||
{
|
||||
Cell* cell = getCell ();
|
||||
|
||||
TramontanaEngine* tramontana = TramontanaEngine::get( cell );
|
||||
if (not tramontana) {
|
||||
tramontana = TramontanaEngine::create( cell );
|
||||
tramontana->setViewer( _viewer );
|
||||
} else
|
||||
cerr << Warning( "%s already has a Tramontana engine.", getString(cell).c_str() ) << endl;
|
||||
|
||||
return tramontana;
|
||||
}
|
||||
|
||||
|
||||
TramontanaEngine* GraphicTramontanaEngine::getForFramework ( uint32_t flags )
|
||||
{
|
||||
// Currently, only one framework is avalaible: Alliance.
|
||||
|
||||
TramontanaEngine* tramontana = TramontanaEngine::get( getCell() );
|
||||
if (tramontana) return tramontana;
|
||||
|
||||
if (flags & CreateEngine) {
|
||||
tramontana = createEngine();
|
||||
if (not tramontana)
|
||||
throw Error( "Failed to create Tramontana engine on %s.", getString(getCell()).c_str() );
|
||||
} else {
|
||||
throw Error( "TramontanaEngine not created yet, run the global router first." );
|
||||
}
|
||||
|
||||
return tramontana;
|
||||
}
|
||||
|
||||
|
||||
void GraphicTramontanaEngine::_extract ()
|
||||
{
|
||||
TramontanaEngine* tramontana = getForFramework( CreateEngine );
|
||||
tramontana->extract();
|
||||
|
||||
//Breakpoint::stop( 0, "GraphicTramontanaEngine::_extract() done." );
|
||||
}
|
||||
|
||||
|
||||
void GraphicTramontanaEngine::addToMenu ( CellViewer* viewer )
|
||||
{
|
||||
assert(_viewer == NULL);
|
||||
|
||||
_viewer = viewer;
|
||||
|
||||
if (_viewer->hasMenuAction("tools.extract")) {
|
||||
cerr << Warning( "GraphicTramontanaEngine::addToMenu() - Tramontana extractor already hooked in." ) << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
_viewer->addToMenu( "tools.extract"
|
||||
, "E&xtract . . . . . [Tramontana]"
|
||||
, "Run the extractor"
|
||||
, std::bind(&GraphicTramontanaEngine::_extract,this)
|
||||
);
|
||||
|
||||
ControllerWidget* controller = viewer->getControllerWidget();
|
||||
if (controller) {
|
||||
TabEquipotentials* tabEqui = new TabEquipotentials ();
|
||||
tabEqui->setObjectName( "controller.tabEquipotentials" );
|
||||
tabEqui->setCellWidget( viewer->getCellWidget() );
|
||||
controller->insertTabAfter( "controller.tabNetlist", tabEqui, "Equipotentials" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const Name& GraphicTramontanaEngine::getName () const
|
||||
{ return TramontanaEngine::staticGetName(); }
|
||||
|
||||
|
||||
Cell* GraphicTramontanaEngine::getCell ()
|
||||
{
|
||||
if (not _viewer) {
|
||||
throw Error( "<b>Tramontana:</b> GraphicTramontanaEngine not bound to any Viewer." );
|
||||
return NULL;
|
||||
}
|
||||
if (not _viewer->getCell()) {
|
||||
throw Error( "<b>Tramontana:</b> No Cell is loaded into the Viewer." );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return _viewer->getCell();
|
||||
}
|
||||
|
||||
|
||||
GraphicTramontanaEngine* GraphicTramontanaEngine::grab ()
|
||||
{
|
||||
if (not _references) {
|
||||
_singleton = new GraphicTramontanaEngine ();
|
||||
}
|
||||
_references++;
|
||||
|
||||
return _singleton;
|
||||
}
|
||||
|
||||
|
||||
size_t GraphicTramontanaEngine::release ()
|
||||
{
|
||||
--_references;
|
||||
if (not _references) {
|
||||
delete _singleton;
|
||||
_singleton = NULL;
|
||||
}
|
||||
return _references;
|
||||
}
|
||||
|
||||
|
||||
GraphicTramontanaEngine::GraphicTramontanaEngine ()
|
||||
: GraphicTool()
|
||||
, _viewer (NULL)
|
||||
{
|
||||
#if THIS_IS_DISABLED
|
||||
addDrawGo( "Anabatic::GCell", initGCell, drawGCell );
|
||||
addDrawGo( "Anabatic::Edge" , initEdge , drawEdge );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
GraphicTramontanaEngine::~GraphicTramontanaEngine ()
|
||||
{ }
|
||||
|
||||
|
||||
} // Tramontana namespace.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue