Skip to content

Commit

Permalink
Merge pull request #1744 from KLayout/wip
Browse files Browse the repository at this point in the history
OASIS reader: avoiding slight rounding of DBU In python read/write cy…
  • Loading branch information
klayoutmatthias authored Jun 29, 2024
2 parents f0fcba4 + 0a453b0 commit 6e2c114
Show file tree
Hide file tree
Showing 26 changed files with 554 additions and 122 deletions.
3 changes: 3 additions & 0 deletions src/buddies/src/bd/strmxor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,9 @@ bool run_deep_xor (const XORData &xor_data)
{
db::DeepShapeStore dss;
dss.set_threads (xor_data.threads);

// TODO: this conflicts with the "set_for_merged_input" optimization below.
// It seems not to be very effective then. Why?
dss.set_wants_all_cells (true); // saves time for less cell mapping operations

double dbu = std::min (xor_data.layout_a->dbu (), xor_data.layout_b->dbu ());
Expand Down
119 changes: 111 additions & 8 deletions src/db/db/dbDeepRegion.cc
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ DeepRegion::begin_iter () const
} else {

const db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
db::RecursiveShapeIterator iter (deep_layer ().layout (), top_cell, deep_layer ().layer ());
db::RecursiveShapeIterator iter (layout, top_cell, deep_layer ().layer ());
return std::make_pair (iter, db::ICplxTrans ());

}
Expand Down Expand Up @@ -803,7 +803,7 @@ DeepRegion::and_with (const Region &other, PropertyConstraint property_constrain

} else {

return new DeepRegion (and_or_not_with (other_deep, true, property_constraint));
return new DeepRegion (and_with_impl (other_deep, property_constraint));

}
}
Expand All @@ -827,7 +827,7 @@ DeepRegion::not_with (const Region &other, PropertyConstraint property_constrain

} else {

return new DeepRegion (and_or_not_with (other_deep, false, property_constraint));
return new DeepRegion (not_with_impl (other_deep, property_constraint));

}
}
Expand Down Expand Up @@ -875,13 +875,13 @@ DeepRegion::andnot_with (const Region &other, PropertyConstraint property_constr
}

DeepLayer
DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op, db::PropertyConstraint property_constraint) const
DeepRegion::and_with_impl (const DeepRegion *other, db::PropertyConstraint property_constraint) const
{
DeepLayer dl_out (deep_layer ().derived ());

if (pc_skip (property_constraint)) {

db::BoolAndOrNotLocalOperation op (and_op);
db::BoolAndOrNotLocalOperation op (true);

db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
configure_proc (proc);
Expand All @@ -893,7 +893,7 @@ DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op, db::PropertyC

} else {

db::BoolAndOrNotLocalOperationWithProperties op (and_op, &dl_out.layout ().properties_repository (), &deep_layer ().layout ().properties_repository (), &other->deep_layer ().layout ().properties_repository (), property_constraint);
db::BoolAndOrNotLocalOperationWithProperties op (true, &dl_out.layout ().properties_repository (), &deep_layer ().layout ().properties_repository (), &other->deep_layer ().layout ().properties_repository (), property_constraint);

db::local_processor<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRefWithProperties> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
configure_proc (proc);
Expand All @@ -908,6 +908,109 @@ DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op, db::PropertyC
return dl_out;
}

DeepLayer
DeepRegion::not_with_impl (const DeepRegion *other, db::PropertyConstraint property_constraint) const
{
DeepLayer dl_out (deep_layer ().derived ());
DeepLayer dl_prep;

// first run a local-only task, which is trivial if the layouts are the same
// TODO: consider property constraints too.

if (deep_layer ().layout_index () == other->deep_layer ().layout_index () && pc_skip (property_constraint)) {

dl_prep = deep_layer ().derived ();

unsigned int layer_this = deep_layer ().layer ();
unsigned int layer_other = other->deep_layer ().layer ();
unsigned int layer_out = dl_prep.layer ();

db::Layout &layout = dl_prep.layout ();

bool any = false;

if (layer_this != layer_other) {

std::set<db::cell_index_type> called;
deep_layer ().initial_cell ().collect_called_cells (called);
called.insert (deep_layer ().initial_cell ().cell_index ());

for (auto ci = called.begin (); ci != called.end (); ++ci) {

db::Cell &cell = layout.cell (*ci);
db::Shapes &shapes_out = cell.shapes (layer_out);
const db::Shapes &shapes_this = cell.shapes (layer_this);
const db::Shapes &shapes_other = cell.shapes (layer_other);

db::Box overlap = (shapes_this.bbox () & shapes_other.bbox ());

if (! overlap.empty ()) {

std::set<db::PolygonRef> others;
for (auto si = shapes_other.begin (db::ShapeIterator::Polygons); ! si.at_end (); ++si) {
if (si->type () == db::Shape::PolygonRef) {
others.insert (si->polygon_ref ());
}
}

for (auto si = shapes_this.begin (db::ShapeIterator::Polygons); ! si.at_end (); ++si) {
if (si->type () == db::Shape::PolygonRef && others.find (si->polygon_ref ()) != others.end ()) {
// drop duplicate
} else {
any = true;
shapes_out.insert (*si);
}
}

} else if (! shapes_this.empty ()) {

any = true;
shapes_out = shapes_this;

}

}

}

// stop if empty
if (! any) {
return dl_prep;
}

} else {
dl_prep = deep_layer ();
}

if (pc_skip (property_constraint)) {

db::BoolAndOrNotLocalOperation op (false);

db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
configure_proc (proc);
proc.set_threads (deep_layer ().store ()->threads ());
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());

proc.run (&op, dl_prep.layer (), other->deep_layer ().layer (), dl_out.layer ());

} else {

db::BoolAndOrNotLocalOperationWithProperties op (false, &dl_out.layout ().properties_repository (), &deep_layer ().layout ().properties_repository (), &other->deep_layer ().layout ().properties_repository (), property_constraint);

db::local_processor<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::PolygonRefWithProperties> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
configure_proc (proc);
proc.set_threads (deep_layer ().store ()->threads ());
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());

proc.run (&op, dl_prep.layer (), other->deep_layer ().layer (), dl_out.layer ());

}

return dl_out;
}

std::pair<DeepLayer, DeepLayer>
DeepRegion::and_and_not_with (const DeepRegion *other, PropertyConstraint property_constraint) const
{
Expand Down Expand Up @@ -1008,8 +1111,8 @@ DeepRegion::xor_with (const Region &other, db::PropertyConstraint property_const
other_deep_mapped->disable_progress ();
}

DeepLayer n1 (and_or_not_with (other_deep_mapped.get (), false, property_constraint));
DeepLayer n2 (other_deep_mapped->and_or_not_with (this, false, property_constraint));
DeepLayer n1 (not_with_impl (other_deep_mapped.get (), property_constraint));
DeepLayer n2 (other_deep_mapped->not_with_impl (this, property_constraint));
n1.add_from (n2);

return new DeepRegion (n1);
Expand Down
3 changes: 2 additions & 1 deletion src/db/db/dbDeepRegion.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@ class DB_PUBLIC DeepRegion

void init ();
void ensure_merged_polygons_valid () const;
DeepLayer and_or_not_with(const DeepRegion *other, bool and_op, PropertyConstraint property_constraint) const;
DeepLayer not_with_impl (const DeepRegion *other, PropertyConstraint property_constraint) const;
DeepLayer and_with_impl (const DeepRegion *other, PropertyConstraint property_constraint) const;
std::pair<DeepLayer, DeepLayer> and_and_not_with (const DeepRegion *other, PropertyConstraint property_constraint) const;
DeepRegion *apply_filter (const PolygonFilterBase &filter) const;

Expand Down
7 changes: 5 additions & 2 deletions src/db/db/dbHierProcessor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1737,12 +1737,14 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
CRONOLOGY_COLLECTION_BRACKET(event_compute_contexts_unlocked)
std::map<unsigned int, const db::Shapes *> intruder_shapes;
if (intruder_cell) {

for (std::vector<unsigned int>::const_iterator l = contexts.intruder_layers ().begin (); l != contexts.intruder_layers ().end (); ++l) {
const db::Shapes *s = &intruder_cell->shapes (contexts.actual_intruder_layer (*l));
if (! s->empty ()) {
intruder_shapes.insert (std::make_pair (*l, s));
}
}

}

db::box_convert <db::CellInstArray, true> inst_bcs (*mp_subject_layout, contexts.subject_layer ());
Expand Down Expand Up @@ -1824,8 +1826,8 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,

}

// TODO: can we shortcut this if interactions is empty?
{
if (! intruders.second.empty () || ! intruder_shapes.empty ()) {

db::box_scanner2<db::CellInstArray, int, TI, int> scanner;
db::addressable_object_from_shape<TI> heap;
interaction_registration_inst2shape<TS, TI, TR> rec (mp_subject_layout, contexts.subject_layer (), dist, &interactions);
Expand All @@ -1849,6 +1851,7 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
}

scanner.process (rec, dist, inst_bcs, db::box_convert<TI> ());

}

// produce the tasks for computing the next-level interactions
Expand Down
10 changes: 7 additions & 3 deletions src/db/db/dbLayoutToNetlist.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1008,7 +1008,7 @@ std::string LayoutToNetlist::name (const ShapeCollection &coll) const
}
}

void LayoutToNetlist::register_layer (const ShapeCollection &collection, const std::string &n_in)
unsigned int LayoutToNetlist::register_layer (const ShapeCollection &collection, const std::string &n_in)
{
if (m_region_by_original.find (tl::id_of (collection.get_delegate ())) != m_region_by_original.end ()) {
throw tl::Exception (tl::to_string (tr ("The layer is already registered")));
Expand Down Expand Up @@ -1042,10 +1042,14 @@ void LayoutToNetlist::register_layer (const ShapeCollection &collection, const s

}

unsigned int layer = dl.layer ();

m_region_by_original [tl::id_of (collection.get_delegate ())] = dl;
m_region_of_layer [dl.layer ()] = dl;
m_region_of_layer [layer] = dl;
m_named_regions [n] = dl;
m_name_of_layer [dl.layer ()] = n;
m_name_of_layer [layer] = n;

return layer;
}

db::DeepLayer LayoutToNetlist::deep_layer_of (const db::ShapeCollection &coll) const
Expand Down
2 changes: 1 addition & 1 deletion src/db/db/dbLayoutToNetlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ class DB_PUBLIC LayoutToNetlist
* In addition to regions, text collections can be registered too.
* Including texts in "connect" makes net names begin assigned from the text strings.
*/
void register_layer (const ShapeCollection &collection, const std::string &name = std::string ());
unsigned int register_layer (const ShapeCollection &collection, const std::string &name = std::string ());

/**
* @brief Gets the name of the given collection
Expand Down
1 change: 1 addition & 0 deletions src/db/db/dbRecursiveShapeIterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class RecursiveShapeReceiver;
* shape classes and shape properties.
*/
class DB_PUBLIC RecursiveShapeIterator
: public gsi::ObjectBase
{
public:
typedef db::Layout layout_type;
Expand Down
9 changes: 7 additions & 2 deletions src/db/db/gsiDeclDbLayoutToNetlist.cc
Original file line number Diff line number Diff line change
Expand Up @@ -330,11 +330,16 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
gsi::method ("layer_name", (std::string (db::LayoutToNetlist::*) (const db::ShapeCollection &region) const) &db::LayoutToNetlist::name, gsi::arg ("l"),
"@brief Gets the name of the given layer\n"
) +
gsi::method ("layer_index", (unsigned int (db::LayoutToNetlist::*) (const db::ShapeCollection &region) const) &db::LayoutToNetlist::layer_of<db::ShapeCollection>, gsi::arg ("l"),
"@brief Gets the layer index for the given data object\n"
"This method has been introduced in version 0.29.3.\n"
) +
gsi::method ("layer_name", (std::string (db::LayoutToNetlist::*) (unsigned int) const) &db::LayoutToNetlist::name, gsi::arg ("l"),
"@brief Gets the name of the given layer (by index)\n"
) +
gsi::method ("register", (void (db::LayoutToNetlist::*) (const db::ShapeCollection &collection, const std::string &)) &db::LayoutToNetlist::register_layer, gsi::arg ("l"), gsi::arg ("n", std::string ()),
gsi::method ("register", (unsigned int (db::LayoutToNetlist::*) (const db::ShapeCollection &collection, const std::string &)) &db::LayoutToNetlist::register_layer, gsi::arg ("l"), gsi::arg ("n", std::string ()),
"@brief Names the given layer\n"
"@return The index of the layer registered\n"
"'l' must be a \\Region or \\Texts object.\n"
"Flat regions or text collections must be registered with this function, before they can be used in \\connect. "
"Registering will copy the shapes into the LayoutToNetlist object in this step to enable "
Expand All @@ -346,7 +351,7 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
"\n"
"If required, the system will assign a name automatically."
"\n"
"This method has been generalized in version 0.27.\n"
"This method has been generalized in version 0.27. Starting with version 0.29.3, the index of the layer is returned.\n"
) +
gsi::method_ext ("layer_names", &l2n_layer_names,
"@brief Returns a list of names of the layers kept inside the LayoutToNetlist object."
Expand Down
41 changes: 37 additions & 4 deletions src/drc/drc/built-in-macros/_drc_netter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,8 @@ def extract_devices(devex, layer_selection)
# @name name
# @brief Assigns a name to a layer
# @synopsis name(layer, name)
# @synopsis name(layer, name, layer_number, datatype_number)
# @synopsis name(layer, name, layer_info)
# Layer names are listed in the LayoutToNetlist (L2N) or LVS database. They
# are used to identify the layers, the net or device terminal geometries are
# on. It is usual to have computed layers, so it is necessary to indicate the
Expand All @@ -325,20 +327,46 @@ def extract_devices(devex, layer_selection)
#
# \name can only be used once on a layer and the layer names must be
# unique (not taken by another layer).
#
# The layer/datatype or LayerInfo specification is optional and will
# be used to configure the internal layout. This information is also
# persisted inside database files. Specifying a layer/datatype information
# is useful, if a layer is not an original layer, but is to be restored
# to an actual layout layer later.

# %DRC%
# @name name_prefix
# @brief Specifies the name prefix for auto-generated layer names
# @synopsis name_prefix(prefix)
# See \\name for details. The default prefix is "l".

def name(l, name)
def name(*args)

@engine._context("name") do

if args.size < 2 || args.size > 4
raise("Two to four arguments expected (layer, name, [layer, datatype / layer properties])")
end

l = args[0]
l.is_a?(DRC::DRCLayer) || raise("First argument must be a layer")

name = args[1]
(name.is_a?(String) && name != "") || raise("Second argument must be a non-empty string")

lp = args[2]
if lp
if !lp.is_a?(RBA::LayerInfo)
lnum = args[2]
dnum = args[3] || 0
lnum.is_a?(1.class) || raise("Layer argument needs to be a RBA::LayerInfo object or a layer number")
dnum.is_a?(1.class) || raise("Datatype argument needs to be an integer")
lp = RBA::LayerInfo::new(lnum, dnum)
elsif args[3]
raise("Three arguments are enough with RBA::LayerInfo")
end
end

id = l.data.data_id

if @layers && @layers[id]
Expand All @@ -349,7 +377,7 @@ def name(l, name)
return
end

self._register_layer(l.data, "name", name)
self._register_layer(l.data, "name", name, lp)

end

Expand Down Expand Up @@ -828,7 +856,7 @@ def _make_soft_connection_diodes(f)

protected

def _register_layer(data, context, name = nil)
def _register_layer(data, context, name = nil, lp = nil)

id = data.data_id
ensure_data
Expand All @@ -846,7 +874,12 @@ def _register_layer(data, context, name = nil)
@layers[id] = [ data, name, context ]

# every layer gets registered and intra-layer connections are made
@l2n.register(data, name)
index = @l2n.register(data, name)

# set the layer properties if requested
if lp
@l2n.internal_layout.set_info(index, lp)
end

end

Expand Down
Loading

0 comments on commit 6e2c114

Please sign in to comment.