mirror of https://github.com/KLayout/klayout.git
More options on 'evaluate_nets' expressions, i.e. 'copy'. See documentation for details.
This commit is contained in:
parent
c0059959b8
commit
407bbbcf62
|
|
@ -1800,40 +1800,87 @@ LayoutToNetlist::compute_area_and_perimeter_of_net_shapes (db::cell_index_type c
|
|||
}
|
||||
|
||||
db::Point
|
||||
LayoutToNetlist::get_merged_shapes_of_net (db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Shapes &shapes, db::properties_id_type prop_id) const
|
||||
LayoutToNetlist::get_shapes_of_net (db::cell_index_type ci, size_t cid, const std::vector<unsigned int> &layer_ids, bool merge, size_t max_polygons, db::Shapes &shapes, db::properties_id_type prop_id) const
|
||||
{
|
||||
const db::Layout *layout = &dss ().const_layout (m_layout_index);
|
||||
|
||||
db::Point ref;
|
||||
// count vertices and polygons and determine label reference point
|
||||
|
||||
size_t n = 0, npoly = 0;
|
||||
bool any_ref = false;
|
||||
db::EdgeProcessor ep;
|
||||
db::Point ref;
|
||||
|
||||
// count vertices and reserve space
|
||||
size_t n = 0;
|
||||
for (db::recursive_cluster_shape_iterator<db::NetShape> rci (m_net_clusters, layer_id, ci, cid); !rci.at_end (); ++rci) {
|
||||
n += rci->polygon_ref ().vertices ();
|
||||
}
|
||||
ep.reserve (n);
|
||||
for (auto l = layer_ids.begin (); l != layer_ids.end (); ++l) {
|
||||
for (db::recursive_cluster_shape_iterator<db::NetShape> rci (m_net_clusters, *l, ci, cid); !rci.at_end (); ++rci) {
|
||||
|
||||
size_t p = 0;
|
||||
for (db::recursive_cluster_shape_iterator<db::NetShape> rci (m_net_clusters, layer_id, ci, cid); !rci.at_end (); ++rci) {
|
||||
db::PolygonRef pr = rci->polygon_ref ();
|
||||
db::PolygonRef::polygon_edge_iterator e = pr.begin_edge ();
|
||||
if (! e.at_end ()) {
|
||||
// pick one reference point for the label
|
||||
auto p1 = (rci.trans () * *e).p1 ();
|
||||
if (! any_ref || p1 < ref) {
|
||||
ref = p1;
|
||||
any_ref = true;
|
||||
db::PolygonRef pr = rci->polygon_ref ();
|
||||
|
||||
n += pr.vertices ();
|
||||
++npoly;
|
||||
|
||||
db::PolygonRef::polygon_edge_iterator e = pr.begin_edge ();
|
||||
if (! e.at_end ()) {
|
||||
// pick one reference point for the label
|
||||
auto p1 = (rci.trans () * *e).p1 ();
|
||||
if (! any_ref || p1 < ref) {
|
||||
ref = p1;
|
||||
any_ref = true;
|
||||
}
|
||||
}
|
||||
ep.insert_with_trans (pr, rci.trans (), ++p);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
db::PolygonRefToShapesGenerator sg (const_cast<db::Layout *> (layout), &shapes, prop_id);
|
||||
db::PolygonGenerator pg (sg, false);
|
||||
db::SimpleMerge op;
|
||||
ep.process (pg, op);
|
||||
if (npoly >= max_polygons) {
|
||||
|
||||
db::Box bbox;
|
||||
|
||||
for (auto l = layer_ids.begin (); l != layer_ids.end (); ++l) {
|
||||
for (db::recursive_cluster_shape_iterator<db::NetShape> rci (m_net_clusters, *l, ci, cid); !rci.at_end (); ++rci) {
|
||||
db::PolygonRef pr = rci->polygon_ref ();
|
||||
bbox += rci.trans () * pr.box ();
|
||||
}
|
||||
}
|
||||
|
||||
if (prop_id != 0) {
|
||||
shapes.insert (db::BoxWithProperties (bbox, prop_id));
|
||||
} else {
|
||||
shapes.insert (bbox);
|
||||
}
|
||||
|
||||
} else if (merge) {
|
||||
|
||||
db::EdgeProcessor ep;
|
||||
ep.reserve (n);
|
||||
|
||||
size_t p = 0;
|
||||
for (auto l = layer_ids.begin (); l != layer_ids.end (); ++l) {
|
||||
for (db::recursive_cluster_shape_iterator<db::NetShape> rci (m_net_clusters, *l, ci, cid); !rci.at_end (); ++rci) {
|
||||
db::PolygonRef pr = rci->polygon_ref ();
|
||||
db::PolygonRef::polygon_edge_iterator e = pr.begin_edge ();
|
||||
if (! e.at_end ()) {
|
||||
ep.insert_with_trans (pr, rci.trans (), ++p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db::PolygonRefToShapesGenerator sg (const_cast<db::Layout *> (layout), &shapes, prop_id);
|
||||
db::PolygonGenerator pg (sg, false);
|
||||
db::SimpleMerge op;
|
||||
ep.process (pg, op);
|
||||
|
||||
} else {
|
||||
|
||||
db::PolygonRefToShapesGenerator sg (const_cast<db::Layout *> (layout), &shapes, prop_id);
|
||||
|
||||
for (auto l = layer_ids.begin (); l != layer_ids.end (); ++l) {
|
||||
for (db::recursive_cluster_shape_iterator<db::NetShape> rci (m_net_clusters, *l, ci, cid); !rci.at_end (); ++rci) {
|
||||
db::PolygonRef pr = rci->polygon_ref ();
|
||||
sg.put (pr.instantiate ().transformed (rci.trans ()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
|
@ -2017,7 +2064,9 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a
|
|||
prop_id = db::properties_id (ps);
|
||||
}
|
||||
|
||||
db::Point ref = get_merged_shapes_of_net (*cid, *c, layer_of (metal), shapes, prop_id);
|
||||
std::vector<unsigned int> layers;
|
||||
layers.push_back (layer_of (metal));
|
||||
db::Point ref = get_shapes_of_net (*cid, *c, layers, true, std::numeric_limits<size_t>::max (), shapes, prop_id);
|
||||
|
||||
if (values) {
|
||||
|
||||
|
|
@ -2074,7 +2123,9 @@ LayoutToNetlist::measure_net (const db::Region &primary, const std::map<std::str
|
|||
eval.set_var (v->first, v->second);
|
||||
}
|
||||
|
||||
eval.set_primary_layer (layer_of (primary));
|
||||
unsigned int primary_layer = layer_of (primary);
|
||||
eval.set_primary_layer (primary_layer);
|
||||
|
||||
for (auto s = secondary.begin (); s != secondary.end (); ++s) {
|
||||
if (s->second) {
|
||||
eval.set_secondary_layer (s->first, layer_of (*s->second));
|
||||
|
|
@ -2088,7 +2139,6 @@ LayoutToNetlist::measure_net (const db::Region &primary, const std::map<std::str
|
|||
eval.parse (compiled_expr, ex);
|
||||
|
||||
db::DeepLayer dl (&dss (), m_layout_index, ly.insert_layer ());
|
||||
unsigned int primary_layer = layer_of (primary);
|
||||
|
||||
for (db::Layout::bottom_up_const_iterator cid = ly.begin_bottom_up (); cid != ly.end_bottom_up (); ++cid) {
|
||||
|
||||
|
|
@ -2113,9 +2163,9 @@ LayoutToNetlist::measure_net (const db::Region &primary, const std::map<std::str
|
|||
eval.reset (*cid, *c);
|
||||
compiled_expr.execute ();
|
||||
|
||||
if (! eval.skip ()) {
|
||||
if (! eval.copy_layers ().empty ()) {
|
||||
db::Shapes &shapes = ly.cell (*cid).shapes (dl.layer ());
|
||||
get_merged_shapes_of_net (*cid, *c, primary_layer, shapes, db::properties_id (eval.prop_set_out ()));
|
||||
get_shapes_of_net (*cid, *c, eval.copy_layers (), eval.copy_merge (), eval.copy_max_polygons (), shapes, db::properties_id (eval.prop_set_out ()));
|
||||
}
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
|
|
|
|||
|
|
@ -1200,9 +1200,14 @@ public:
|
|||
void compute_area_and_perimeter_of_net_shapes (db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Polygon::area_type &area, db::Polygon::perimeter_type &perimeter) const;
|
||||
|
||||
/**
|
||||
* @brief Utility: computes the merged shapes of a net
|
||||
* @brief Utility: computes the shapes of a net
|
||||
*
|
||||
* If 'merged' is true, all polygons will be merged.
|
||||
*
|
||||
* If 'max_polygons' is set to a value less that std::numeric_limits<size_t>::max,
|
||||
* the polygons will be replaced by a bounding box if the number of polygons exceeds the number given by the limit
|
||||
*/
|
||||
db::Point get_merged_shapes_of_net (db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Shapes &shapes, db::properties_id_type prop_id) const;
|
||||
db::Point get_shapes_of_net (db::cell_index_type ci, size_t cid, const std::vector<unsigned int> &layer_ids, bool merged, size_t max_polygons, db::Shapes &shapes, db::properties_id_type prop_id) const;
|
||||
|
||||
private:
|
||||
// no copying
|
||||
|
|
|
|||
|
|
@ -385,10 +385,107 @@ public:
|
|||
|
||||
virtual void execute (const tl::ExpressionParserContext &context, tl::Variant & /*out*/, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*kwargs*/) const
|
||||
{
|
||||
if (args.size () != 1) {
|
||||
throw tl::EvalError (tl::to_string (tr ("'skip' function takes one argument (flag)")), context);
|
||||
bool flag = true;
|
||||
if (args.size () > 1) {
|
||||
throw tl::EvalError (tl::to_string (tr ("'skip' function takes one optional argument (flag)")), context);
|
||||
} else if (args.size () == 1) {
|
||||
flag = args [0].to_bool ();
|
||||
}
|
||||
mp_eval->skip_func (args [0].to_bool ());
|
||||
|
||||
std::vector<unsigned int> layers;
|
||||
if (! flag && ! mp_eval->layer_indexes ().empty ()) {
|
||||
layers.push_back (0);
|
||||
}
|
||||
mp_eval->copy_func (layers, true, std::numeric_limits<size_t>::max ());
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureNetEval *mp_eval;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A function to specify the copy behaviour
|
||||
*
|
||||
* With the copy behavior, the polygons emitted by the "evaluate_nets" method
|
||||
* are specified. The function accepts up to one positional argument and
|
||||
* three optional keyword arguments (limit, layers and merged).
|
||||
* Together with "skip", it maps to the following behavior:
|
||||
*
|
||||
* skip() -> copy(layers=[])
|
||||
* skip(true) -> copy(layers=[])
|
||||
* skip(false) -> copy(layers=[primary], merged=true, limit=unlimited)
|
||||
* copy() -> copy(layers=[all], merged=true, limit=unlimited)
|
||||
* copy(false) -> copy(layers=[])
|
||||
* copy(true) -> copy(layers=[all], merged=true, limit=unlimited)
|
||||
* copy(true, merged=m) -> copy(layers=[all], merged=m, limit=unlimited)
|
||||
* copy(layers=l) -> copy(layers=[l], merged=true, limit=unlimited) (l is a layer symbol)
|
||||
* copy(layers=[l]) -> copy(layers=[l], merged=true, limit=unlimited) ([l] is an array of layer symbols)
|
||||
* copy(layers=.., merged=m) -> copy(layers=.., merged=m, limit=unlimited)
|
||||
* copy(layers=.., merged=.., limit=n) -> copy(layers=.., merged=.., limit=n)
|
||||
*
|
||||
* The primary layer is "0", so "skip(false)" is identical to "copy(layer=0)"
|
||||
*/
|
||||
|
||||
class NetCopyFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
NetCopyFunction (MeasureNetEval *eval)
|
||||
: mp_eval (eval)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual bool supports_keyword_parameters () const { return true; }
|
||||
|
||||
virtual void execute (const tl::ExpressionParserContext &context, tl::Variant & /*out*/, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> *kwargs) const
|
||||
{
|
||||
bool flag = true;
|
||||
size_t limit = std::numeric_limits<size_t>::max ();
|
||||
std::vector<unsigned int> layers;
|
||||
bool merged = true;
|
||||
|
||||
if (args.size () > 1) {
|
||||
throw tl::EvalError (tl::to_string (tr ("'copy' function takes one optional argument (flag) and the following keyword arguments: 'limit', 'layers', 'layer' or 'merged'")), context);
|
||||
} else if (args.size () == 1) {
|
||||
flag = args [0].to_bool ();
|
||||
}
|
||||
|
||||
// default for "layers" is 'all'
|
||||
for (unsigned int i = 0; i < (unsigned int) mp_eval->layer_indexes ().size (); ++i) {
|
||||
layers.push_back (i);
|
||||
}
|
||||
|
||||
if (kwargs) {
|
||||
for (auto k = kwargs->begin (); k != kwargs->end (); ++k) {
|
||||
if (k->first == "limit") {
|
||||
limit = k->second.to<size_t> ();
|
||||
} else if (k->first == "merged") {
|
||||
merged = k->second.to_bool ();
|
||||
} else if (k->first == "layers") {
|
||||
const tl::Variant &v = k->second;
|
||||
if (! v.is_list ()) {
|
||||
throw tl::EvalError (tl::to_string (tr ("'copy' function's 'layers' keyword argument expects an array of layer symbols")), context);
|
||||
}
|
||||
layers.clear ();
|
||||
for (auto l = v.begin (); l != v.end (); ++l) {
|
||||
layers.push_back (l->to_uint ());
|
||||
}
|
||||
} else if (k->first == "layer") {
|
||||
layers.clear ();
|
||||
layers.push_back (k->second.to_uint ());
|
||||
} else {
|
||||
throw tl::EvalError (tl::to_string (tr ("'copy' function takes one optional argument (flag) and the following keyword arguments: 'limit', 'layers', 'layer' or 'merged'")), context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! flag) {
|
||||
// clear layers to indicate we don't want to copy
|
||||
layers.clear ();
|
||||
}
|
||||
|
||||
mp_eval->copy_func (layers, merged, limit);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -464,7 +561,8 @@ private:
|
|||
MeasureNetEval::MeasureNetEval (const db::LayoutToNetlist *l2n, double dbu)
|
||||
: tl::Eval (), mp_l2n (l2n), m_dbu (dbu)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
m_copy_merge = false;
|
||||
m_copy_max_polygons = std::numeric_limits<size_t>::max ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -486,6 +584,7 @@ MeasureNetEval::init ()
|
|||
{
|
||||
define_function ("put", new NetPutFunction (this));
|
||||
define_function ("skip", new NetSkipFunction (this));
|
||||
define_function ("copy", new NetCopyFunction (this));
|
||||
define_function ("area", new NetAreaFunction (this));
|
||||
define_function ("perimeter", new NetPerimeterFunction (this));
|
||||
define_function ("net", new NetFunction (this));
|
||||
|
|
@ -494,7 +593,12 @@ MeasureNetEval::init ()
|
|||
void
|
||||
MeasureNetEval::reset (db::cell_index_type cell_index, size_t cluster_id) const
|
||||
{
|
||||
m_skip = false;
|
||||
// default action: copy primary layer, merged, no limit
|
||||
m_copy_layers.clear ();
|
||||
m_copy_layers.push_back (0);
|
||||
m_copy_merge = true;
|
||||
m_copy_max_polygons = std::numeric_limits<size_t>::max ();
|
||||
|
||||
m_cell_index = cell_index;
|
||||
m_cluster_id = cluster_id;
|
||||
m_area_and_perimeter_cache.clear ();
|
||||
|
|
@ -553,9 +657,11 @@ MeasureNetEval::perimeter_func (int layer_index) const
|
|||
}
|
||||
|
||||
void
|
||||
MeasureNetEval::skip_func (bool f) const
|
||||
MeasureNetEval::copy_func (const std::vector<unsigned int> &layer_indexes, bool merge, size_t max_polygons) const
|
||||
{
|
||||
m_skip = f;
|
||||
m_copy_layers = layer_indexes;
|
||||
m_copy_merge = merge;
|
||||
m_copy_max_polygons = max_polygons;
|
||||
}
|
||||
|
||||
tl::Variant
|
||||
|
|
|
|||
|
|
@ -130,10 +130,9 @@ public:
|
|||
|
||||
void reset (db::cell_index_type cell_index, size_t cluster_id) const;
|
||||
|
||||
bool skip () const
|
||||
{
|
||||
return m_skip;
|
||||
}
|
||||
const std::vector<unsigned int> copy_layers () const { return m_copy_layers; }
|
||||
size_t copy_max_polygons () const { return m_copy_max_polygons; }
|
||||
bool copy_merge () const { return m_copy_merge; }
|
||||
|
||||
db::PropertiesSet &prop_set_out () const
|
||||
{
|
||||
|
|
@ -146,6 +145,7 @@ private:
|
|||
friend class NetPerimeterFunction;
|
||||
friend class NetFunction;
|
||||
friend class NetSkipFunction;
|
||||
friend class NetCopyFunction;
|
||||
|
||||
struct AreaAndPerimeter
|
||||
{
|
||||
|
|
@ -156,7 +156,9 @@ private:
|
|||
const db::LayoutToNetlist *mp_l2n;
|
||||
double m_dbu;
|
||||
std::vector<unsigned int> m_layers;
|
||||
mutable bool m_skip;
|
||||
mutable std::vector<unsigned int> m_copy_layers;
|
||||
mutable bool m_copy_merge;
|
||||
mutable size_t m_copy_max_polygons;
|
||||
mutable db::PropertiesSet m_prop_set_out;
|
||||
mutable db::cell_index_type m_cell_index;
|
||||
mutable size_t m_cluster_id;
|
||||
|
|
@ -164,11 +166,12 @@ private:
|
|||
mutable std::unique_ptr<std::map<std::pair<db::cell_index_type, size_t>, const db::Net *> > m_nets_per_cell_and_cluster_id;
|
||||
|
||||
AreaAndPerimeter compute_area_and_perimeter (int layer_index) const;
|
||||
const std::vector<unsigned int> &layer_indexes () const { return m_layers; }
|
||||
|
||||
void put_func (const tl::Variant &name, const tl::Variant &value) const;
|
||||
tl::Variant area_func (int layer_index) const;
|
||||
tl::Variant perimeter_func (int layer_index) const;
|
||||
void skip_func (bool f) const;
|
||||
void copy_func (const std::vector<unsigned int> &layer_indexes, bool merge, size_t max_polygons) const;
|
||||
tl::Variant net_func () const;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1232,11 +1232,13 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
"arbitrary values without having to encode them into the expression string.\n"
|
||||
"\n"
|
||||
"It will look at nets connecting to shapes on the primary layer and execute the expression for each\n"
|
||||
"of those nets. After that it will copy the primary shapes of the net to the output with the properties\n"
|
||||
"of those nets. After that it will copy the merged primary shapes of the net to the output with the properties\n"
|
||||
"placed by 'put' attached to them.\n"
|
||||
"\n"
|
||||
"It is possible to skip primary shapes of a specific net by calling the 'skip' function with a 'true'\n"
|
||||
"value.\n"
|
||||
"value. It is also possible to configure the output in more detail, i.e. to skip other or all layers, to\n"
|
||||
"replace the output by the net's bounding box above a certain complexity, or to select merged polygons or "
|
||||
"unmerged ones, by using 'copy' instead of 'skip'. See below for more details.\n"
|
||||
"\n"
|
||||
"The expression may use the following functions:\n"
|
||||
"\n"
|
||||
|
|
@ -1246,12 +1248,53 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
"@li 'perimeter': the perimeter of the primary-layer shapes on the net in um @/li\n"
|
||||
"@li 'perimeter(name)': the perimeter of the secondary-layer shapes. 'name' is a symbol with the name given in the secondary-layer map @/li\n"
|
||||
"@li 'put(name, value)': places the value as property 'name' on the output shapes @/li\n"
|
||||
"@li 'skip(flag)': will skip the primary shapes of that net when called with a true value @/li\n"
|
||||
"@li 'skip' or 'skip(flag)': will skip the primary shapes of that net when called with a true value or without one. See also 'copy'. @/li\n"
|
||||
"@li 'copy(...)': see below for details @/li\n"
|
||||
"@li 'net': the \\Net object of the current net @/li\n"
|
||||
"@/ul\n"
|
||||
"\n"
|
||||
"If given, the 'dbu' argument gives the database unit to use for converting shape dimensions into micrometer units. "
|
||||
"If this value is 0, the area and perimeters are calculated in database units. If no DBU is specified, the value is determined automatically."
|
||||
"\n"
|
||||
"'copy' and 'skip' control the polygon output. Here are the options:\n"
|
||||
"\n"
|
||||
"@ul\n"
|
||||
"@li 'skip' or 'skip(true)': skip output, identical to 'copy(layers=[])' @/li\n"
|
||||
"@li 'skip(false)': copy the shapes from the primary layer, identical to 'copy(layer=0)' @/li\n"
|
||||
"@li 'copy' or 'copy(true)': copy all shapes from the net, merged into a single polygon.\n"
|
||||
" Note: this is not equivalent to 'skip(false)', as in the latter case, only the primary layer's\n"
|
||||
" shapes are copied @/li\n"
|
||||
"@li 'copy(false)': equivalent to 'skip(true)' @/li\n"
|
||||
"@li 'copy(merged=false)': copies all shapes from all layers of the net, without merging.\n"
|
||||
" 'merged' is a keyword argument that can be combined with other arguments. @/li\n"
|
||||
"@li 'copy(limit=number)': if the net has less than 'number' polygons on the selected layers, \n"
|
||||
" copy them to the output. For more polygons, emit the bounding box of the net for the \n"
|
||||
" given layers.\n"
|
||||
" 'limit' is a keyword argument that can be combined with other arguments. @/li\n"
|
||||
"@li 'copy(layer=symbol)': copies all shapes from the layer denoted by the symbol.\n"
|
||||
" The primary layer has value zero (0), so 'copy(layer=0)' copies the shapes from the primary layer.\n"
|
||||
" 'layer' is a keyword argument that can be combined with other arguments, except 'layers'. @/li\n"
|
||||
"@li 'copy(layers=[symbol, symbol, ...])': copies all shapes from the layers denoted by the symbols.\n"
|
||||
" 'layers' is a keyword argument that can be combined with other arguments, except 'layer'. @/li\n"
|
||||
"@/ul\n"
|
||||
"\n"
|
||||
"When mixing 'skip' and 'copy', the last active specification controls the output. The following\n"
|
||||
"expressions are equivalent:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"copy(net.name == 'VDD')\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"and\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"skip ; net.name == 'VDD' && copy\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"where the second expression establishes 'skip' as the default and conditionally executes 'copy',\n"
|
||||
"overriding 'skip'.\n"
|
||||
"\n"
|
||||
"The 'copy' function was added and the 'skip' argument was made optional in version 0.30.6."
|
||||
) +
|
||||
// test API
|
||||
gsi::method ("make_soft_connection_diodes=", &db::LayoutToNetlist::set_make_soft_connection_diodes, gsi::arg ("flag"), "@hide") +
|
||||
|
|
|
|||
|
|
@ -355,8 +355,14 @@ It visits each net and evaluates the given expression on the net.
|
|||
The expression needs to be written in KLayout expression notations.
|
||||
</p><p>
|
||||
The default action is to copy the shapes of the primary layer to the
|
||||
output. This action can be modified in some ways: skip shapes of
|
||||
certain nets or attach properties to the shapes during the evaluation.
|
||||
output. It is possible to customize the output further: you can
|
||||
conditionally skip the output or copy all shapes of the net from
|
||||
all layers the output. You can choose to emit individual polygons
|
||||
or merge all polygons from a net (all layers or a subset) into
|
||||
a single polygon. The latter is the default.
|
||||
</p><p>
|
||||
You can also choose to emit the bounding box of the net if the number of polygons
|
||||
on the net exceeds a certain limit.
|
||||
</p><p>
|
||||
Using the "put" function inside the expression, properties can be
|
||||
attached to the output shapes. The properties can be computed using
|
||||
|
|
@ -366,9 +372,6 @@ Also the <class_doc href="Net">Net</class_doc> object representing the net is av
|
|||
'net' function. This allows implementing a more elaborate
|
||||
antenna check for example.
|
||||
</p><p>
|
||||
Also, the expression can choose to drop shapes and not copy them to
|
||||
the output by calling the "skip" function with a "true" argument.
|
||||
</p><p>
|
||||
Arbitrary values can be passed as variables, which removes the need
|
||||
to encode variable values into the expression. For this, use the
|
||||
'variables' argument and pass a hash with names and values. Each of
|
||||
|
|
@ -379,7 +382,8 @@ The following functions are available inside the expressions:
|
|||
</p><p>
|
||||
<ul>
|
||||
<li>"net" - the <class_doc href="Net">Net</class_doc> object of the current net </li>
|
||||
<li>"skip(flag)" - if called with a 'true' argument, the primary layer's shapes are not copied for this net </li>
|
||||
<li>"skip" or "skip(flag)" - if called with a 'true' argument (the default), the primary layer's shapes are not copied for this net </li>
|
||||
<li>"copy(...)" - configures polygon output in a more elaborate way than "skip" (see below) </li>
|
||||
<li>"put(name, value)" - places the value as a property with name 'name' (this must be a string) on the output shapes </li>
|
||||
<li>"area" - the combined area of the primary layer's shapes on the net in square micrometer units </li>
|
||||
<li>"area(symbol)" - the combined area of the secondary layer's shapes on the net in square micrometer units </li>
|
||||
|
|
@ -390,6 +394,46 @@ The following functions are available inside the expressions:
|
|||
Here, 'symbol' is the name given to the secondary layer in the secondary layer
|
||||
dictionary.
|
||||
</p><p>
|
||||
"copy" and "skip" control the polygon output. Here are the options:
|
||||
</p><p>
|
||||
<ul>
|
||||
<li>"skip" or "skip(true): skip output, identical to "copy(layers=[])" </li>
|
||||
<li>"skip(false)": copy the shapes from the primary layer, identical to "copy(layer=0)" </li>
|
||||
<li>"copy" or "copy(true)": copy all shapes from the net, merged into a single polygon.
|
||||
Note: this is not equivalent to "skip(false)", as in the latter case, only the primary layer's
|
||||
shapes are copied </li>
|
||||
<li>"copy(false)": equivalent to "skip(true)" </li>
|
||||
<li>"copy(merged=false)": copies all shapes from all layers of the net, without merging.
|
||||
"merged" is a keyword argument that can be combined with other arguments. </li>
|
||||
<li>"copy(limit=number)": if the net has less than "number" polygons on the selected layers,
|
||||
copy them to the output. For more polygons, emit the bounding box of the net for the
|
||||
given layers.
|
||||
"limit" is a keyword argument that can be combined with other arguments. </li>
|
||||
<li>"copy(layer=symbol)": copies all shapes from the layer denoted by the symbol.
|
||||
The primary layer has value zero (0), so "copy(layer=0)" copies the shapes from the primary layer.
|
||||
"layer" is a keyword argument that can be combined with other arguments, except "layers". </li>
|
||||
<li>"copy(layers=[symbol, symbol, ...])": copies all shapes from the layers denoted by the symbols.
|
||||
"layers" is a keyword argument that can be combined with other arguments, except "layer". </li>
|
||||
</ul>
|
||||
</p><p>
|
||||
When mixing "skip" and "copy", the last active specification controls the output. The following
|
||||
expressions are equivalent:
|
||||
</p><p>
|
||||
<pre>
|
||||
copy(net.name == "VDD")
|
||||
</pre>
|
||||
</p><p>
|
||||
and
|
||||
</p><p>
|
||||
<pre>
|
||||
skip ; net.name == "VDD" && copy
|
||||
</pre>
|
||||
</p><p>
|
||||
where the second expression establishes "skip" as the default and conditionally executes "copy",
|
||||
overriding "skip".
|
||||
</p><p>
|
||||
<h4>Antenna check example </h4>
|
||||
</p><p>
|
||||
The following example emulates an antenna check. It computes the area ratio of metal vs. gate area and
|
||||
attaches the value as a property with name 'AR' to the shapes, copied from the 'gate' layer:
|
||||
</p><p>
|
||||
|
|
|
|||
|
|
@ -780,9 +780,15 @@ module DRC
|
|||
# The expression needs to be written in KLayout expression notations.
|
||||
#
|
||||
# The default action is to copy the shapes of the primary layer to the
|
||||
# output. This action can be modified in some ways: skip shapes of
|
||||
# certain nets or attach properties to the shapes during the evaluation.
|
||||
#
|
||||
# output. It is possible to customize the output further: you can
|
||||
# conditionally skip the output or copy all shapes of the net from
|
||||
# all layers the output. You can choose to emit individual polygons
|
||||
# or merge all polygons from a net (all layers or a subset) into
|
||||
# a single polygon. The latter is the default.
|
||||
#
|
||||
# You can also choose to emit the bounding box of the net if the number of polygons
|
||||
# on the net exceeds a certain limit.
|
||||
#
|
||||
# Using the "put" function inside the expression, properties can be
|
||||
# attached to the output shapes. The properties can be computed using
|
||||
# a number of net attributes - area and perimeter for example.
|
||||
|
|
@ -791,9 +797,6 @@ module DRC
|
|||
# 'net' function. This allows implementing a more elaborate
|
||||
# antenna check for example.
|
||||
#
|
||||
# Also, the expression can choose to drop shapes and not copy them to
|
||||
# the output by calling the "skip" function with a "true" argument.
|
||||
#
|
||||
# Arbitrary values can be passed as variables, which removes the need
|
||||
# to encode variable values into the expression. For this, use the
|
||||
# 'variables' argument and pass a hash with names and values. Each of
|
||||
|
|
@ -804,7 +807,8 @@ module DRC
|
|||
#
|
||||
# @ul
|
||||
# @li "net" - the RBA::Net object of the current net @/li
|
||||
# @li "skip(flag)" - if called with a 'true' argument, the primary layer's shapes are not copied for this net @/li
|
||||
# @li "skip" or "skip(flag)" - if called with a 'true' argument (the default), the primary layer's shapes are not copied for this net @/li
|
||||
# @li "copy(...)" - configures polygon output in a more elaborate way than "skip" (see below) @/li
|
||||
# @li "put(name, value)" - places the value as a property with name 'name' (this must be a string) on the output shapes @/li
|
||||
# @li "area" - the combined area of the primary layer's shapes on the net in square micrometer units @/li
|
||||
# @li "area(symbol)" - the combined area of the secondary layer's shapes on the net in square micrometer units @/li
|
||||
|
|
@ -815,6 +819,46 @@ module DRC
|
|||
# Here, 'symbol' is the name given to the secondary layer in the secondary layer
|
||||
# dictionary.
|
||||
#
|
||||
# "copy" and "skip" control the polygon output. Here are the options:
|
||||
#
|
||||
# @ul
|
||||
# @li "skip" or "skip(true): skip output, identical to "copy(layers=[])" @/li
|
||||
# @li "skip(false)": copy the shapes from the primary layer, identical to "copy(layer=0)" @/li
|
||||
# @li "copy" or "copy(true)": copy all shapes from the net, merged into a single polygon.
|
||||
# Note: this is not equivalent to "skip(false)", as in the latter case, only the primary layer's
|
||||
# shapes are copied @/li
|
||||
# @li "copy(false)": equivalent to "skip(true)" @/li
|
||||
# @li "copy(merged=false)": copies all shapes from all layers of the net, without merging.
|
||||
# "merged" is a keyword argument that can be combined with other arguments. @/li
|
||||
# @li "copy(limit=number)": if the net has less than "number" polygons on the selected layers,
|
||||
# copy them to the output. For more polygons, emit the bounding box of the net for the
|
||||
# given layers.
|
||||
# "limit" is a keyword argument that can be combined with other arguments. @/li
|
||||
# @li "copy(layer=symbol)": copies all shapes from the layer denoted by the symbol.
|
||||
# The primary layer has value zero (0), so "copy(layer=0)" copies the shapes from the primary layer.
|
||||
# "layer" is a keyword argument that can be combined with other arguments, except "layers". @/li
|
||||
# @li "copy(layers=[symbol, symbol, ...])": copies all shapes from the layers denoted by the symbols.
|
||||
# "layers" is a keyword argument that can be combined with other arguments, except "layer". @/li
|
||||
# @/ul
|
||||
#
|
||||
# When mixing "skip" and "copy", the last active specification controls the output. The following
|
||||
# expressions are equivalent:
|
||||
#
|
||||
# @code
|
||||
# copy(net.name == "VDD")
|
||||
# @/code
|
||||
#
|
||||
# and
|
||||
#
|
||||
# @code
|
||||
# skip ; net.name == "VDD" && copy
|
||||
# @/code
|
||||
#
|
||||
# where the second expression establishes "skip" as the default and conditionally executes "copy",
|
||||
# overriding "skip".
|
||||
#
|
||||
# @h4 Antenna check example @/h4
|
||||
#
|
||||
# The following example emulates an antenna check. It computes the area ratio of metal vs. gate area and
|
||||
# attaches the value as a property with name 'AR' to the shapes, copied from the 'gate' layer:
|
||||
#
|
||||
|
|
|
|||
|
|
@ -3993,9 +3993,20 @@ Eval::eval_atomic (ExpressionParserContext &ex, std::unique_ptr<ExpressionNode>
|
|||
|
||||
do {
|
||||
|
||||
std::unique_ptr<ExpressionNode> v;
|
||||
eval_top (ex, v);
|
||||
n->add_child (v.release ());
|
||||
tl::Extractor exn = ex;
|
||||
std::string name;
|
||||
if (exn.try_read_word (name, "_") && exn.test ("=")) {
|
||||
// keyword parameter -> read name again to skip it
|
||||
ex.read_word (name, "_");
|
||||
ex.expect ("=");
|
||||
} else {
|
||||
name.clear ();
|
||||
}
|
||||
|
||||
std::unique_ptr<ExpressionNode> a;
|
||||
eval_assign (ex, a);
|
||||
a->set_name (name);
|
||||
n->add_child (a.release ());
|
||||
|
||||
if (ex.test (")")) {
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -17,19 +17,38 @@ connect(l2, l3)
|
|||
connect(l3, l4)
|
||||
connect(l4, l5)
|
||||
|
||||
l1_measured = evaluate_nets(l1, { "l2" => l2, "l3" => l3, "l4" => l4, "l5" => l5 }, "put(5, area(l5)); put(0, area); put(100, area(l5)/area)")
|
||||
l2_measured = evaluate_nets(l1, {}, "put(0, area*factor)", { "factor" => 1000.0 })
|
||||
l3_measured = evaluate_nets(l1, {}, "put(0, net.name)")
|
||||
l4_measured = evaluate_nets(l1, {}, "skip(net.name == n)", { "n" => "NET1" })
|
||||
|
||||
l1.output(1, 0)
|
||||
l2.output(2, 0)
|
||||
l3.output(3, 0)
|
||||
l4.output(4, 0)
|
||||
l5.output(5, 0)
|
||||
|
||||
l1_measured.output(100, 0)
|
||||
l2_measured.output(101, 0)
|
||||
l3_measured.output(102, 0)
|
||||
l4_measured.output(103, 0)
|
||||
sec = { "l2" => l2, "l3" => l3, "l4" => l4, "l5" => l5 }
|
||||
l100_measured = evaluate_nets(l1, sec, "put(5, area(l5)); put(0, area); put(100, area(l5)/area)")
|
||||
l101_measured = evaluate_nets(l1, sec, "put(0, area*factor)", { "factor" => 1000.0 })
|
||||
l102_measured = evaluate_nets(l1, sec, "put(0, net.name)")
|
||||
l103_measured = evaluate_nets(l1, sec, "skip(net.name == n)", { "n" => "NET1" })
|
||||
l104_measured = evaluate_nets(l1, sec, "copy(net.name == n)", { "n" => "NET1" })
|
||||
# default action is "skip", then copy primary if net name is "NET1"
|
||||
l105_measured = evaluate_nets(l1, sec, "skip ; net.name == n && copy(layer = 0)", { "n" => "NET1" })
|
||||
l106_measured = evaluate_nets(l1, sec, "copy(net.name == n, merged = true)", { "n" => "NET1" })
|
||||
l107_measured = evaluate_nets(l1, sec, "copy(net.name == n, merged = false)", { "n" => "NET1" })
|
||||
l108_measured = evaluate_nets(l1, sec, "copy(net.name == n, merged = false, layers = [l4, l5])", { "n" => "NET1" })
|
||||
l109_measured = evaluate_nets(l1, sec, "copy(net.name == n, merged = false, layer = l5)", { "n" => "NET1" })
|
||||
l110_measured = evaluate_nets(l1, sec, "copy(net.name == n, merged = false, limit = 0)", { "n" => "NET1" })
|
||||
# default action is "skip", then copy all if net name is "NET1"
|
||||
l111_measured = evaluate_nets(l1, sec, "skip ; net.name == n && copy", { "n" => "NET1" })
|
||||
|
||||
l100_measured.output(100, 0)
|
||||
l101_measured.output(101, 0)
|
||||
l102_measured.output(102, 0)
|
||||
l103_measured.output(103, 0)
|
||||
l104_measured.output(104, 0)
|
||||
l105_measured.output(105, 0)
|
||||
l106_measured.output(106, 0)
|
||||
l107_measured.output(107, 0)
|
||||
l108_measured.output(108, 0)
|
||||
l109_measured.output(109, 0)
|
||||
l110_measured.output(110, 0)
|
||||
l111_measured.output(111, 0)
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue