Skip to content

Commit

Permalink
Merge pull request #1811 from KLayout/wip
Browse files Browse the repository at this point in the history
Wip
  • Loading branch information
klayoutmatthias authored Jul 30, 2024
2 parents a126c8f + fec6143 commit 8ab398d
Show file tree
Hide file tree
Showing 55 changed files with 1,294 additions and 334 deletions.
15 changes: 9 additions & 6 deletions src/db/db/dbLayout.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2887,15 +2887,18 @@ Layout::get_context_info (cell_index_type cell_index, LayoutOrCellContextInfo &i
if (pcell_variant) {

const db::PCellDeclaration *pcell_decl = ly->pcell_declaration (pcell_variant->pcell_id ());

const std::vector<db::PCellParameterDeclaration> &pcp = pcell_decl->parameter_declarations ();
std::vector<db::PCellParameterDeclaration>::const_iterator pd = pcp.begin ();
for (std::vector<tl::Variant>::const_iterator p = pcell_variant->parameters ().begin (); p != pcell_variant->parameters ().end () && pd != pcp.end (); ++p, ++pd) {
info.pcell_parameters.insert (std::make_pair (pd->get_name (), *p));
if (pcell_decl) {
const std::vector<db::PCellParameterDeclaration> &pcp = pcell_decl->parameter_declarations ();
std::vector<db::PCellParameterDeclaration>::const_iterator pd = pcp.begin ();
for (std::vector<tl::Variant>::const_iterator p = pcell_variant->parameters ().begin (); p != pcell_variant->parameters ().end () && pd != pcp.end (); ++p, ++pd) {
info.pcell_parameters.insert (std::make_pair (pd->get_name (), *p));
}
}

const db::PCellHeader *header = ly->pcell_header (pcell_variant->pcell_id ());
info.pcell_name = header->get_name ();
if (header) {
info.pcell_name = header->get_name ();
}

} else if (ly != this) {
info.cell_name = ly->cell_name (cptr->cell_index ());
Expand Down
101 changes: 101 additions & 0 deletions src/db/db/dbLayoutUtils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -683,5 +683,106 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db
}
}


// ------------------------------------------------------------
// break_polygons implementation

static bool split_polygon (bool first, db::Polygon &poly, size_t max_vertex_count, double max_area_ratio, std::vector<db::Polygon> &parts)
{
if ((max_vertex_count > 0 && poly.vertices () > max_vertex_count) ||
(max_area_ratio > 0 && poly.area_ratio () > max_area_ratio)) {

std::vector<db::Polygon> sp;
db::split_polygon (poly, sp);
for (auto p = sp.begin (); p != sp.end (); ++p) {
split_polygon (false, *p, max_vertex_count, max_area_ratio, parts);
}

return true;

} else {

if (! first) {
parts.push_back (db::Polygon ());
parts.back ().swap (poly);
}

return false;

}
}

void
break_polygons (db::Shapes &shapes, size_t max_vertex_count, double max_area_ratio)
{
if (shapes.is_editable ()) {

std::vector<db::Polygon> new_polygons;
std::vector<db::Shape> to_delete;

for (auto s = shapes.begin (db::ShapeIterator::Polygons | db::ShapeIterator::Paths); ! s.at_end (); ++s) {
db::Polygon poly;
s->instantiate (poly);
if (split_polygon (true, poly, max_vertex_count, max_area_ratio, new_polygons)) {
to_delete.push_back (*s);
}
}

shapes.erase_shapes (to_delete);

for (auto p = new_polygons.begin (); p != new_polygons.end (); ++p) {
shapes.insert (*p);
}

} else {

// In non-editable mode we cannot do "erase", so we use a temporary, editable Shapes container
db::Shapes tmp (true);
tmp.insert (shapes);

shapes.clear ();
break_polygons (tmp, max_vertex_count, max_area_ratio);
shapes.insert (tmp);

tl_assert (!shapes.is_editable ());

}
}

void
break_polygons (db::Layout &layout, db::cell_index_type cell_index, unsigned int layer, size_t max_vertex_count, double max_area_ratio)
{
if (layout.is_valid_cell_index (cell_index) && layout.is_valid_layer (layer)) {
db::Cell &cell = layout.cell (cell_index);
break_polygons (cell.shapes (layer), max_vertex_count, max_area_ratio);
}
}

void
break_polygons (db::Layout &layout, unsigned int layer, size_t max_vertex_count, double max_area_ratio)
{
for (db::cell_index_type ci = 0; ci < layout.cells (); ++ci) {
if (layout.is_valid_cell_index (ci)) {
db::Cell &cell = layout.cell (ci);
break_polygons (cell.shapes (layer), max_vertex_count, max_area_ratio);
}
}
}

void
break_polygons (db::Layout &layout, size_t max_vertex_count, double max_area_ratio)
{
for (db::cell_index_type ci = 0; ci < layout.cells (); ++ci) {
if (layout.is_valid_cell_index (ci)) {
db::Cell &cell = layout.cell (ci);
for (unsigned int li = 0; li < layout.layers (); ++li) {
if (layout.is_valid_layer (li)) {
break_polygons (cell.shapes (li), max_vertex_count, max_area_ratio);
}
}
}
}
}

}

27 changes: 27 additions & 0 deletions src/db/db/dbLayoutUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,33 @@ class DB_PUBLIC ContextCache
*/
DB_PUBLIC void scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db::Coord d);

/**
* @brief Breaks polygons according to max_vertex_count and max_area_ratio
*
* This method will investigate all polygons on the given layer and cell and split them in case they
* have more than the specified vertices and an bounding-box area to polygon area ratio larget
* than the specified max_area_ratio. This serves optimization for algorithms needing a good
* bounding box approximation.
*
* Setting max_vertex_count or max_area_ratio to 0 disables the respective check.
*/
DB_PUBLIC void break_polygons (db::Layout &layout, db::cell_index_type cell_index, unsigned int layer, size_t max_vertex_count, double max_area_ratio);

/**
* @brief Like "break_polygons" before, but applies it to all cells.
*/
DB_PUBLIC void break_polygons (db::Layout &layout, unsigned int layer, size_t max_vertex_count, double max_area_ratio);

/**
* @brief Like "break_polygons" before, but applies it to all cells and all layers.
*/
DB_PUBLIC void break_polygons (db::Layout &layout, size_t max_vertex_count, double max_area_ratio);

/**
* @brief Like "break_polygons" before, but applies it to the given Shapes container.
*/
DB_PUBLIC void break_polygons (db::Shapes &shapes, size_t max_vertex_count, double max_area_ratio);

} // namespace db

#endif
Expand Down
41 changes: 41 additions & 0 deletions src/db/db/dbNetlist.cc
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,47 @@ size_t Netlist::top_circuit_count () const
return m_top_circuits;
}

Circuit *Netlist::top_circuit ()
{
size_t ntop = top_circuit_count ();
if (ntop == 0) {
return 0;
} else if (ntop > 1) {
throw tl::Exception (tl::to_string (tr ("Netlist contains more than a single top circuit")));
} else {
return begin_top_down ().operator-> ();
}
}

const Circuit *Netlist::top_circuit () const
{
return const_cast<Netlist *> (this)->top_circuit ();
}

std::vector<Circuit *> Netlist::top_circuits ()
{
size_t ntop = top_circuit_count ();
std::vector<Circuit *> result;
result.reserve (ntop);
for (auto c = begin_top_down (); ntop > 0 && c != end_top_down (); ++c) {
result.push_back (c.operator-> ());
--ntop;
}
return result;
}

std::vector<const Circuit *> Netlist::top_circuits () const
{
size_t ntop = top_circuit_count ();
std::vector<const Circuit *> result;
result.reserve (ntop);
for (auto c = begin_top_down (); ntop > 0 && c != end_top_down (); ++c) {
result.push_back (c.operator-> ());
--ntop;
}
return result;
}

Netlist::bottom_up_circuit_iterator Netlist::begin_bottom_up ()
{
if (! m_valid_topology) {
Expand Down
26 changes: 26 additions & 0 deletions src/db/db/dbNetlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,32 @@ class DB_PUBLIC Netlist
return m_circuit_by_cell_index.object_by (cell_index);
}

/**
* @brief Gets the top circuit if there is one
* This method will assert if there is more than a single top circuit.
* It will return 0 if there is no top circuit.
*/
Circuit *top_circuit ();

/**
* @brief Gets the top circuit if there is one (const version)
* This method will assert if there is more than a single top circuit.
* It will return 0 if there is no top circuit.
*/
const Circuit *top_circuit () const;

/**
* @brief Gets the top circuits
* This convenience method will return a list of top circuits.
*/
std::vector<Circuit *> top_circuits ();

/**
* @brief Gets the top circuits (const version)
* This convenience method will return a list of top circuits.
*/
std::vector<const Circuit *> top_circuits () const;

/**
* @brief Gets the top-down circuits iterator (begin)
* This iterator will deliver the circuits in a top-down way - i.e. child circuits
Expand Down
1 change: 1 addition & 0 deletions src/db/db/dbRecursiveShapeIterator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ namespace db
// Recursive shape iterator implementation

RecursiveShapeIterator::RecursiveShapeIterator (const RecursiveShapeIterator &d)
: gsi::ObjectBase (d)
{
operator= (d);
}
Expand Down
58 changes: 55 additions & 3 deletions src/db/db/gsiDeclDbCell.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1104,14 +1104,14 @@ static void set_cell_property (db::Cell *c, const tl::Variant &key, const tl::Va
c->prop_id (layout->properties_repository ().properties_id (props));
}

static tl::Variant get_cell_property (db::Cell *c, const tl::Variant &key)
static tl::Variant get_cell_property (const db::Cell *c, const tl::Variant &key)
{
db::properties_id_type id = c->prop_id ();
if (id == 0) {
return tl::Variant ();
}

db::Layout *layout = c->layout ();
const db::Layout *layout = c->layout ();
if (! layout) {
throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot retrieve properties")));
}
Expand All @@ -1130,6 +1130,26 @@ static tl::Variant get_cell_property (db::Cell *c, const tl::Variant &key)
}
}

static tl::Variant get_cell_properties (const db::Cell *c)
{
db::properties_id_type id = c->prop_id ();
if (id == 0) {
return tl::Variant::empty_array ();
}

const db::Layout *layout = c->layout ();
if (! layout) {
throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot retrieve properties")));
}

tl::Variant res = tl::Variant::empty_array ();
const db::PropertiesRepository::properties_set &props = layout->properties_repository ().properties (id);
for (auto i = props.begin (); i != props.end (); ++i) {
res.insert (layout->properties_repository ().prop_name (i->first), i->second);
}
return res;
}

static bool is_pcell_variant (const db::Cell *cell)
{
tl_assert (cell->layout () != 0);
Expand Down Expand Up @@ -1841,10 +1861,16 @@ Class<db::Cell> decl_Cell ("db", "Cell",
"@brief Gets the user property with the given key\n"
"This method is a convenience method that gets the property with the given key. "
"If no property with that key exists, it will return nil. Using that method is more "
"convenient than using the layout object and the properties ID to retrieve the property value. "
"convenient than using the layout object and the properties ID to retrieve the property value.\n"
"\n"
"This method has been introduced in version 0.23."
) +
gsi::method_ext ("properties", &get_cell_properties,
"@brief Gets the user properties as a hash\n"
"This method is a convenience method that gets all user properties as a single hash.\n"
"\n"
"This method has been introduced in version 0.29.5."
) +
gsi::method_ext ("add_meta_info", &cell_add_meta_info, gsi::arg ("info"),
"@brief Adds meta information to the cell\n"
"See \\LayoutMetaInfo for details about cells and meta information.\n"
Expand Down Expand Up @@ -3539,6 +3565,26 @@ static tl::Variant get_property (const db::Instance *i, const tl::Variant &key)
}
}

static tl::Variant get_properties (const db::Instance *i)
{
db::properties_id_type id = i->prop_id ();
if (id == 0) {
return tl::Variant::empty_array ();
}

const db::Layout *layout = layout_ptr_const (i);
if (! layout) {
throw tl::Exception (tl::to_string (tr ("Instance does not reside inside a layout - cannot retrieve properties")));
}

tl::Variant res = tl::Variant::empty_array ();
const db::PropertiesRepository::properties_set &props = layout->properties_repository ().properties (id);
for (auto i = props.begin (); i != props.end (); ++i) {
res.insert (layout->properties_repository ().prop_name (i->first), i->second);
}
return res;
}

static bool inst_is_valid (const db::Instance *inst)
{
return inst->instances () && inst->instances ()->is_valid (*inst);
Expand Down Expand Up @@ -4011,6 +4057,12 @@ Class<db::Instance> decl_Instance ("db", "Instance",
"\n"
"This method has been introduced in version 0.22."
) +
gsi::method_ext ("properties", &get_properties,
"@brief Gets the user properties as a hash\n"
"This method is a convenience method that gets all user properties as a single hash.\n"
"\n"
"This method has been introduced in version 0.29.5."
) +
method_ext ("[]", &inst_index, gsi::arg ("key"),
"@brief Gets the user property with the given key or, if available, the PCell parameter with the name given by the key\n"
"Getting the PCell parameter has priority over the user property."
Expand Down
Loading

0 comments on commit 8ab398d

Please sign in to comment.