mirror of https://github.com/KLayout/klayout.git
WIP: measure_net function for LayoutToNetlist
This commit is contained in:
parent
8e95f6a8e1
commit
e82ebf6733
|
|
@ -58,6 +58,7 @@ SOURCES = \
|
|||
dbLog.cc \
|
||||
dbManager.cc \
|
||||
dbMatrix.cc \
|
||||
dbMeasureEval.cc \
|
||||
dbMemStatistics.cc \
|
||||
dbMutableEdgePairs.cc \
|
||||
dbMutableEdges.cc \
|
||||
|
|
@ -296,6 +297,7 @@ HEADERS = \
|
|||
dbLog.h \
|
||||
dbManager.h \
|
||||
dbMatrix.h \
|
||||
dbMeasureEval.h \
|
||||
dbMemStatistics.h \
|
||||
dbMetaInfo.h \
|
||||
dbMutableEdgePairs.h \
|
||||
|
|
@ -432,6 +434,7 @@ HEADERS = \
|
|||
dbNetShape.h \
|
||||
dbShapeCollection.h \
|
||||
dbShapeCollectionUtils.h \
|
||||
gsiDeclDbMeasureHelpers.h \
|
||||
gsiDeclDbPropertiesSupport.h
|
||||
|
||||
RESOURCES = \
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "dbLayoutToNetlistSoftConnections.h"
|
||||
#include "dbShapeProcessor.h"
|
||||
#include "dbNetlistDeviceClasses.h"
|
||||
#include "dbMeasureEval.h"
|
||||
#include "dbLog.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
||||
|
|
@ -1772,20 +1773,20 @@ public:
|
|||
|
||||
}
|
||||
|
||||
static void
|
||||
compute_area_and_perimeter_of_net_shapes (const db::hier_clusters<db::NetShape> &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Polygon::area_type &area, db::Polygon::perimeter_type &perimeter)
|
||||
void
|
||||
LayoutToNetlist::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
|
||||
{
|
||||
db::EdgeProcessor ep;
|
||||
|
||||
// count vertices and reserve space
|
||||
size_t n = 0;
|
||||
for (db::recursive_cluster_shape_iterator<db::NetShape> rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) {
|
||||
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);
|
||||
|
||||
size_t p = 0;
|
||||
for (db::recursive_cluster_shape_iterator<db::NetShape> rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) {
|
||||
for (db::recursive_cluster_shape_iterator<db::NetShape> rci (m_net_clusters, layer_id, ci, cid); !rci.at_end (); ++rci) {
|
||||
ep.insert_with_trans (rci->polygon_ref (), rci.trans (), ++p);
|
||||
}
|
||||
|
||||
|
|
@ -1798,49 +1799,24 @@ compute_area_and_perimeter_of_net_shapes (const db::hier_clusters<db::NetShape>
|
|||
perimeter = ap_collector.perimeter ();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class AntennaShapeGenerator
|
||||
: public PolygonSink
|
||||
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
|
||||
{
|
||||
public:
|
||||
AntennaShapeGenerator (db::Layout *layout, db::Shapes &shapes, db::properties_id_type prop_id)
|
||||
: PolygonSink (), mp_layout (layout), mp_shapes (&shapes), m_prop_id (prop_id)
|
||||
{ }
|
||||
const db::Layout *layout = &dss ().const_layout (m_layout_index);
|
||||
|
||||
virtual void put (const db::Polygon &polygon)
|
||||
{
|
||||
if (m_prop_id != 0) {
|
||||
mp_shapes->insert (db::PolygonRefWithProperties (db::PolygonRef (polygon, mp_layout->shape_repository ()), m_prop_id));
|
||||
} else {
|
||||
mp_shapes->insert (db::PolygonRef (polygon, mp_layout->shape_repository ()));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
db::Layout *mp_layout;
|
||||
db::Shapes *mp_shapes;
|
||||
db::properties_id_type m_prop_id;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static db::Point
|
||||
get_merged_shapes_of_net (const db::hier_clusters<db::NetShape> &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Layout *layout, db::Shapes &shapes, db::properties_id_type prop_id)
|
||||
{
|
||||
db::Point ref;
|
||||
bool any_ref = false;
|
||||
db::EdgeProcessor ep;
|
||||
|
||||
// count vertices and reserve space
|
||||
size_t n = 0;
|
||||
for (db::recursive_cluster_shape_iterator<db::NetShape> rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) {
|
||||
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);
|
||||
|
||||
size_t p = 0;
|
||||
for (db::recursive_cluster_shape_iterator<db::NetShape> rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) {
|
||||
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 ()) {
|
||||
|
|
@ -1854,7 +1830,7 @@ get_merged_shapes_of_net (const db::hier_clusters<db::NetShape> &clusters, db::c
|
|||
}
|
||||
}
|
||||
|
||||
db::AntennaShapeGenerator sg (layout, shapes, prop_id);
|
||||
db::PolygonRefToShapesGenerator sg (const_cast<db::Layout *> (layout), &shapes, prop_id);
|
||||
db::PolygonGenerator pg (sg, false);
|
||||
db::SimpleMerge op;
|
||||
ep.process (pg, op);
|
||||
|
|
@ -1968,7 +1944,7 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a
|
|||
db::Polygon::area_type adiode_int = 0;
|
||||
db::Polygon::perimeter_type pdiode_int = 0;
|
||||
|
||||
compute_area_and_perimeter_of_net_shapes (m_net_clusters, *cid, *c, layer_of (*d->first), adiode_int, pdiode_int);
|
||||
compute_area_and_perimeter_of_net_shapes (*cid, *c, layer_of (*d->first), adiode_int, pdiode_int);
|
||||
|
||||
adiodes_int.push_back (adiode_int);
|
||||
|
||||
|
|
@ -1987,7 +1963,7 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a
|
|||
db::Polygon::area_type agate_int = 0;
|
||||
db::Polygon::perimeter_type pgate_int = 0;
|
||||
|
||||
compute_area_and_perimeter_of_net_shapes (m_net_clusters, *cid, *c, layer_of (gate), agate_int, pgate_int);
|
||||
compute_area_and_perimeter_of_net_shapes (*cid, *c, layer_of (gate), agate_int, pgate_int);
|
||||
|
||||
double agate = 0.0;
|
||||
if (fabs (gate_area_factor) > 1e-6) {
|
||||
|
|
@ -2002,7 +1978,7 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a
|
|||
db::Polygon::area_type ametal_int = 0;
|
||||
db::Polygon::perimeter_type pmetal_int = 0;
|
||||
|
||||
compute_area_and_perimeter_of_net_shapes (m_net_clusters, *cid, *c, layer_of (metal), ametal_int, pmetal_int);
|
||||
compute_area_and_perimeter_of_net_shapes (*cid, *c, layer_of (metal), ametal_int, pmetal_int);
|
||||
|
||||
double ametal = 0.0;
|
||||
if (fabs (metal_area_factor) > 1e-6) {
|
||||
|
|
@ -2041,7 +2017,7 @@ 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 (m_net_clusters, *cid, *c, layer_of (metal), &ly, shapes, prop_id);
|
||||
db::Point ref = get_merged_shapes_of_net (*cid, *c, layer_of (metal), shapes, prop_id);
|
||||
|
||||
if (values) {
|
||||
|
||||
|
|
@ -2078,6 +2054,61 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a
|
|||
return db::Region (new db::DeepRegion (dl));
|
||||
}
|
||||
|
||||
db::Region
|
||||
LayoutToNetlist::measure_net (const db::Region &primary, const std::map<std::string, const db::Region *> &secondary, const std::string &expression)
|
||||
{
|
||||
// TODO: that's basically too much .. we only need the clusters
|
||||
if (! m_netlist_extracted) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet")));
|
||||
}
|
||||
|
||||
db::Layout &ly = dss ().layout (m_layout_index);
|
||||
double dbu = ly.dbu ();
|
||||
|
||||
db::DeepLayer dl (&dss (), m_layout_index, ly.insert_layer ());
|
||||
|
||||
for (db::Layout::bottom_up_const_iterator cid = ly.begin_bottom_up (); cid != ly.end_bottom_up (); ++cid) {
|
||||
|
||||
const connected_clusters<db::NetShape> &clusters = m_net_clusters.clusters_per_cell (*cid);
|
||||
if (clusters.empty ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
db::MeasureNetEval eval (this, dbu);
|
||||
|
||||
eval.set_primary_layer (layer_of (primary));
|
||||
for (auto s = secondary.begin (); s != secondary.end (); ++s) {
|
||||
if (s->second) {
|
||||
eval.set_secondary_layer (s->first, layer_of (*s->second));
|
||||
}
|
||||
}
|
||||
|
||||
eval.init ();
|
||||
|
||||
tl::Extractor ex (expression.c_str ());
|
||||
tl::Expression compiled_expr;
|
||||
eval.parse (compiled_expr, ex);
|
||||
|
||||
for (connected_clusters<db::NetShape>::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) {
|
||||
|
||||
if (! clusters.is_root (*c)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
eval.reset (*cid, *c);
|
||||
compiled_expr.execute ();
|
||||
|
||||
if (! eval.skip ()) {
|
||||
db::Shapes &shapes = ly.cell (*cid).shapes (dl.layer ());
|
||||
get_merged_shapes_of_net (*cid, *c, layer_of (primary), shapes, db::properties_id (eval.prop_set_out ()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return db::Region (new db::DeepRegion (dl));
|
||||
}
|
||||
|
||||
void LayoutToNetlist::save (const std::string &path, bool short_format)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1126,6 +1126,30 @@ public:
|
|||
*/
|
||||
db::Region antenna_check (const db::Region &gate, double gate_area_factor, double gate_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector<std::pair<const db::Region *, double> > &diodes = std::vector<std::pair<const db::Region *, double> > (), Texts *values = 0);
|
||||
|
||||
/**
|
||||
* @brief Runs a generic net measurement function
|
||||
*
|
||||
* This method accepts some primary layer, a number of secondary layers with names and an expression.
|
||||
*
|
||||
* It will look at nets connecting to shapes on the primary layer and execute the expression for each
|
||||
* of those nets. After that it will copy the primary shapes of the net to the output with the properties
|
||||
* placed by "put" attached to them.
|
||||
*
|
||||
* It is possible to skip primary shapes of a specific net by calling the "skip" function with a "true"
|
||||
* value.
|
||||
*
|
||||
* The formulas may use the following functions:
|
||||
*
|
||||
* * "area": the area of all primary-layer shapes on the net in square um
|
||||
* * "area(name)": the area of all secondary-layer shapes. 'name' is a symbol with the name given in the secondary-layer map
|
||||
* * "perimeter": the perimeter of the primary-layer shapes on the net in um
|
||||
* * "perimeter(name)": the perimeter of the secondary-layer shapes. 'name' is a symbol with the name given in the secondary-layer map
|
||||
* * "put(name, value)": places the value as property 'name' on the output shapes
|
||||
* * "skip(flag)": will skip the primary shapes of that net when called with a true value
|
||||
* * "net_name": the name of the net
|
||||
*/
|
||||
db::Region measure_net (const db::Region &primary, const std::map<std::string, const db::Region *> &secondary, const std::string &expression);
|
||||
|
||||
/**
|
||||
* @brief Saves the database to the given path
|
||||
*
|
||||
|
|
@ -1170,6 +1194,16 @@ public:
|
|||
m_make_soft_connection_diodes = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility: computes the area and perimeter of a net's shapes
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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;
|
||||
|
||||
private:
|
||||
// no copying
|
||||
LayoutToNetlist (const db::LayoutToNetlist &other);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,561 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "dbMeasureEval.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// MeasureEval implementation
|
||||
|
||||
class ShapeFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
ShapeFunction (MeasureEval *eval)
|
||||
: mp_eval (eval)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
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 () != 0) {
|
||||
throw tl::EvalError (tl::to_string (tr ("'shape' function does not take arguments")), context);
|
||||
}
|
||||
out = mp_eval->shape_func ();
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureEval *mp_eval;
|
||||
};
|
||||
|
||||
class ValueFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
ValueFunction (MeasureEval *eval)
|
||||
: mp_eval (eval)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
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 ("'value' function takes one argument")), context);
|
||||
}
|
||||
out = mp_eval->value_func (args [0]);
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureEval *mp_eval;
|
||||
};
|
||||
|
||||
class ValuesFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
ValuesFunction (MeasureEval *eval)
|
||||
: mp_eval (eval)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
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 ("'values' function takes one argument")), context);
|
||||
}
|
||||
out = mp_eval->values_func (args [0]);
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureEval *mp_eval;
|
||||
};
|
||||
|
||||
class PropertyFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
PropertyFunction (MeasureEval *eval, const tl::Variant &name)
|
||||
: mp_eval (eval), m_name_id (db::property_names_id (name))
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
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 () != 0) {
|
||||
throw tl::EvalError (tl::to_string (tr ("Property getter function does not take arguments")), context);
|
||||
}
|
||||
out = mp_eval->value_func (m_name_id);
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureEval *mp_eval;
|
||||
db::property_names_id_type m_name_id;
|
||||
};
|
||||
|
||||
class PutFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
PutFunction (MeasureEval *eval)
|
||||
: mp_eval (eval)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
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 () != 2) {
|
||||
throw tl::EvalError (tl::to_string (tr ("'put' function takes two arguments (name, value)")), context);
|
||||
}
|
||||
mp_eval->put_func (args [0], args [1]);
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureEval *mp_eval;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// MeasureEval implementation
|
||||
|
||||
MeasureEval::MeasureEval (double dbu, bool with_put)
|
||||
: m_shape_type (None), m_prop_id (0), m_dbu (dbu), m_with_put (with_put)
|
||||
{
|
||||
mp_shape.any = 0;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::init ()
|
||||
{
|
||||
if (m_with_put) {
|
||||
define_function ("put", new PutFunction (this));
|
||||
}
|
||||
|
||||
define_function ("shape", new ShapeFunction (this));
|
||||
define_function ("value", new ValueFunction (this));
|
||||
define_function ("values", new ValuesFunction (this));
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::reset_shape () const
|
||||
{
|
||||
m_shape_type = None;
|
||||
mp_shape.any = 0;
|
||||
m_prop_id = 0;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::set_shape (const db::Polygon *poly) const
|
||||
{
|
||||
m_shape_type = Polygon;
|
||||
mp_shape.poly = poly;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::set_shape (const db::PolygonRef *poly) const
|
||||
{
|
||||
m_shape_type = PolygonRef;
|
||||
mp_shape.poly_ref = poly;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::set_shape (const db::Edge *edge) const
|
||||
{
|
||||
m_shape_type = Edge;
|
||||
mp_shape.edge = edge;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::set_shape (const db::EdgePair *edge_pair) const
|
||||
{
|
||||
m_shape_type = EdgePair;
|
||||
mp_shape.edge_pair = edge_pair;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::set_shape (const db::Text *text) const
|
||||
{
|
||||
m_shape_type = Text;
|
||||
mp_shape.text = text;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::set_prop_id (db::properties_id_type prop_id) const
|
||||
{
|
||||
m_prop_id = prop_id;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::resolve_name (const std::string &name, const tl::EvalFunction *&function, const tl::Variant *&value, tl::Variant *&var)
|
||||
{
|
||||
tl::Eval::resolve_name (name, function, value, var);
|
||||
|
||||
if (!function && !value && !var) {
|
||||
// connect the name with a function getting the property value
|
||||
tl::EvalFunction *f = new PropertyFunction (this, name);
|
||||
define_function (name, f);
|
||||
function = f;
|
||||
}
|
||||
}
|
||||
|
||||
tl::Variant
|
||||
MeasureEval::shape_func () const
|
||||
{
|
||||
if (m_dbu > 1e-10) {
|
||||
|
||||
db::CplxTrans tr (m_dbu);
|
||||
|
||||
switch (m_shape_type)
|
||||
{
|
||||
case None:
|
||||
default:
|
||||
return tl::Variant ();
|
||||
case Polygon:
|
||||
return tl::Variant (tr * *mp_shape.poly);
|
||||
case PolygonRef:
|
||||
{
|
||||
db::Polygon poly;
|
||||
mp_shape.poly_ref->instantiate (poly);
|
||||
return tl::Variant (tr * poly);
|
||||
}
|
||||
case Edge:
|
||||
return tl::Variant (tr * *mp_shape.edge);
|
||||
case EdgePair:
|
||||
return tl::Variant (tr * *mp_shape.edge_pair);
|
||||
case Text:
|
||||
return tl::Variant (tr * *mp_shape.text);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
switch (m_shape_type)
|
||||
{
|
||||
case None:
|
||||
default:
|
||||
return tl::Variant ();
|
||||
case Polygon:
|
||||
return tl::Variant (*mp_shape.poly);
|
||||
case PolygonRef:
|
||||
{
|
||||
db::Polygon poly;
|
||||
mp_shape.poly_ref->instantiate (poly);
|
||||
return tl::Variant (poly);
|
||||
}
|
||||
case Edge:
|
||||
return tl::Variant (*mp_shape.edge);
|
||||
case EdgePair:
|
||||
return tl::Variant (*mp_shape.edge_pair);
|
||||
case Text:
|
||||
return tl::Variant (*mp_shape.text);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
tl::Variant
|
||||
MeasureEval::value_func (db::property_names_id_type name_id) const
|
||||
{
|
||||
const db::PropertiesSet &ps = db::properties (m_prop_id);
|
||||
for (auto i = ps.begin (); i != ps.end (); ++i) {
|
||||
if (i->first == name_id) {
|
||||
return db::property_value (i->second);
|
||||
}
|
||||
}
|
||||
|
||||
return tl::Variant ();
|
||||
}
|
||||
|
||||
tl::Variant
|
||||
MeasureEval::value_func (const tl::Variant &name) const
|
||||
{
|
||||
const db::PropertiesSet &ps = db::properties (m_prop_id);
|
||||
for (auto i = ps.begin (); i != ps.end (); ++i) {
|
||||
if (db::property_name (i->first) == name) {
|
||||
return db::property_value (i->second);
|
||||
}
|
||||
}
|
||||
|
||||
return tl::Variant ();
|
||||
}
|
||||
|
||||
tl::Variant
|
||||
MeasureEval::values_func (const tl::Variant &name) const
|
||||
{
|
||||
tl::Variant res = tl::Variant::empty_list ();
|
||||
|
||||
const db::PropertiesSet &ps = db::properties (m_prop_id);
|
||||
for (auto i = ps.begin (); i != ps.end (); ++i) {
|
||||
if (db::property_name (i->first) == name) {
|
||||
res.push (db::property_value (i->second));
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::put_func (const tl::Variant &name, const tl::Variant &value) const
|
||||
{
|
||||
auto prop_name_id = db::property_names_id (name);
|
||||
m_prop_set_out.erase (prop_name_id);
|
||||
m_prop_set_out.insert (prop_name_id, value);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// MeasureNetEval implementation
|
||||
|
||||
class NetPutFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
NetPutFunction (MeasureNetEval *eval)
|
||||
: mp_eval (eval)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
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 () != 2) {
|
||||
throw tl::EvalError (tl::to_string (tr ("'put' function takes two arguments (name, value)")), context);
|
||||
}
|
||||
mp_eval->put_func (args [0], args [1]);
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureNetEval *mp_eval;
|
||||
};
|
||||
|
||||
class NetSkipFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
NetSkipFunction (MeasureNetEval *eval)
|
||||
: mp_eval (eval)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
mp_eval->skip_func (args [0].to_bool ());
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureNetEval *mp_eval;
|
||||
};
|
||||
|
||||
class NetNameFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
NetNameFunction (MeasureNetEval *eval)
|
||||
: mp_eval (eval)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
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 ("'net_name' function does not take and argument")), context);
|
||||
}
|
||||
out = mp_eval->net_name_func ();
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureNetEval *mp_eval;
|
||||
};
|
||||
|
||||
class NetAreaFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
NetAreaFunction (MeasureNetEval *eval)
|
||||
: mp_eval (eval)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
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 ("'area' function takes one optional argument (layer symbol)")), context);
|
||||
}
|
||||
out = mp_eval->area_func (args.size () == 0 ? 0 : args [0].to_int ());
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureNetEval *mp_eval;
|
||||
};
|
||||
|
||||
class NetPerimeterFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
NetPerimeterFunction (MeasureNetEval *eval)
|
||||
: mp_eval (eval)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
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 ("'perimeter' function takes one optional argument (layer symbol)")), context);
|
||||
}
|
||||
out = mp_eval->perimeter_func (args.size () == 0 ? 0 : args [0].to_int ());
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureNetEval *mp_eval;
|
||||
};
|
||||
|
||||
MeasureNetEval::MeasureNetEval (const db::LayoutToNetlist *l2n, double dbu)
|
||||
: tl::Eval (), mp_l2n (l2n), m_dbu (dbu)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
MeasureNetEval::set_primary_layer (unsigned int layer_index)
|
||||
{
|
||||
tl_assert (m_layers.empty ());
|
||||
m_layers.push_back (layer_index);
|
||||
}
|
||||
|
||||
void
|
||||
MeasureNetEval::set_secondary_layer (const std::string &name, unsigned int layer_index)
|
||||
{
|
||||
set_var (name, tl::Variant (int (m_layers.size ())));
|
||||
m_layers.push_back (layer_index);
|
||||
}
|
||||
|
||||
void
|
||||
MeasureNetEval::init ()
|
||||
{
|
||||
define_function ("put", new NetPutFunction (this));
|
||||
define_function ("skip", new NetSkipFunction (this));
|
||||
define_function ("area", new NetAreaFunction (this));
|
||||
define_function ("perimeter", new NetPerimeterFunction (this));
|
||||
define_function ("net_name", new NetNameFunction (this));
|
||||
}
|
||||
|
||||
void
|
||||
MeasureNetEval::reset (db::cell_index_type cell_index, size_t cluster_id) const
|
||||
{
|
||||
m_skip = false;
|
||||
m_cell_index = cell_index;
|
||||
m_cluster_id = cluster_id;
|
||||
m_area_and_perimeter_cache.clear ();
|
||||
}
|
||||
|
||||
void
|
||||
MeasureNetEval::put_func (const tl::Variant &name, const tl::Variant &value) const
|
||||
{
|
||||
auto prop_name_id = db::property_names_id (name);
|
||||
m_prop_set_out.erase (prop_name_id);
|
||||
m_prop_set_out.insert (prop_name_id, value);
|
||||
}
|
||||
|
||||
MeasureNetEval::AreaAndPerimeter
|
||||
MeasureNetEval::compute_area_and_perimeter (int layer_index) const
|
||||
{
|
||||
if (layer_index < 0 || layer_index >= (unsigned int) m_layers.size ()) {
|
||||
return AreaAndPerimeter ();
|
||||
}
|
||||
|
||||
unsigned int layer = m_layers [layer_index];
|
||||
db::Polygon::area_type area = 0;
|
||||
db::Polygon::perimeter_type perimeter = 0;
|
||||
mp_l2n->compute_area_and_perimeter_of_net_shapes (m_cell_index, m_cluster_id, layer, area, perimeter);
|
||||
|
||||
AreaAndPerimeter ap;
|
||||
ap.area = m_dbu * m_dbu * area;
|
||||
ap.perimeter = m_dbu * perimeter;
|
||||
|
||||
return ap;
|
||||
}
|
||||
|
||||
tl::Variant
|
||||
MeasureNetEval::area_func (int layer_index) const
|
||||
{
|
||||
auto ap = m_area_and_perimeter_cache.find (layer_index);
|
||||
if (ap == m_area_and_perimeter_cache.end ()) {
|
||||
ap = m_area_and_perimeter_cache.insert (std::make_pair (layer_index, compute_area_and_perimeter (layer_index))).first;
|
||||
}
|
||||
return ap->second.area;
|
||||
}
|
||||
|
||||
tl::Variant
|
||||
MeasureNetEval::perimeter_func (int layer_index) const
|
||||
{
|
||||
auto ap = m_area_and_perimeter_cache.find (layer_index);
|
||||
if (ap == m_area_and_perimeter_cache.end ()) {
|
||||
ap = m_area_and_perimeter_cache.insert (std::make_pair (layer_index, compute_area_and_perimeter (layer_index))).first;
|
||||
}
|
||||
return ap->second.perimeter;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureNetEval::skip_func (bool f) const
|
||||
{
|
||||
m_skip = f;
|
||||
}
|
||||
|
||||
tl::Variant
|
||||
MeasureNetEval::net_name_func () const
|
||||
{
|
||||
const db::Netlist *nl = mp_l2n->netlist ();
|
||||
if (! nl) {
|
||||
return tl::Variant ();
|
||||
}
|
||||
|
||||
// build a lookup table of nets vs. cell_index+cluster_id
|
||||
if (! m_nets_per_cell_and_cluster_id.get ()) {
|
||||
m_nets_per_cell_and_cluster_id.reset (new std::map<std::pair<db::cell_index_type, size_t>, const db::Net *> ());
|
||||
for (auto c = nl->begin_circuits (); c != nl->end_circuits (); ++c) {
|
||||
auto ci = c->cell_index ();
|
||||
for (auto n = c->begin_nets (); n != c->end_nets (); ++n) {
|
||||
auto cid = n->cluster_id ();
|
||||
m_nets_per_cell_and_cluster_id->insert (std::make_pair (std::make_pair (ci, cid), n.operator-> ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto n = m_nets_per_cell_and_cluster_id->find (std::make_pair (m_cell_index, m_cluster_id));
|
||||
if (n != m_nets_per_cell_and_cluster_id->end ()) {
|
||||
return tl::Variant (n->second->name ());
|
||||
} else {
|
||||
return tl::Variant ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_dbMeasureEval
|
||||
#define HDR_dbMeasureEval
|
||||
|
||||
#include "dbRegion.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbEdgePairs.h"
|
||||
#include "dbTexts.h"
|
||||
#include "dbLayoutToNetlist.h"
|
||||
#include "tlExpression.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Some utilities
|
||||
|
||||
/**
|
||||
* @brief An evaluation context for the expressions
|
||||
*
|
||||
* This class provides the methods, functions and variables for the expressions.
|
||||
*/
|
||||
class DB_PUBLIC MeasureEval
|
||||
: public tl::Eval
|
||||
{
|
||||
public:
|
||||
MeasureEval (double dbu, bool with_put);
|
||||
|
||||
void init ();
|
||||
|
||||
void reset_shape () const;
|
||||
void set_shape (const db::Polygon *poly) const;
|
||||
void set_shape (const db::PolygonRef *poly) const;
|
||||
void set_shape (const db::Edge *edge) const;
|
||||
void set_shape (const db::EdgePair *edge_pair) const;
|
||||
void set_shape (const db::Text *text) const;
|
||||
void set_prop_id (db::properties_id_type prop_id) const;
|
||||
|
||||
db::PropertiesSet &prop_set_out () const
|
||||
{
|
||||
return m_prop_set_out;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void resolve_name (const std::string &name, const tl::EvalFunction *&function, const tl::Variant *&value, tl::Variant *&var);
|
||||
|
||||
private:
|
||||
friend class ShapeFunction;
|
||||
friend class ValueFunction;
|
||||
friend class ValuesFunction;
|
||||
friend class PropertyFunction;
|
||||
friend class PutFunction;
|
||||
|
||||
union ShapeRef
|
||||
{
|
||||
const db::Polygon *poly;
|
||||
const db::PolygonRef *poly_ref;
|
||||
const db::Edge *edge;
|
||||
const db::EdgePair *edge_pair;
|
||||
const db::Text *text;
|
||||
void *any;
|
||||
};
|
||||
|
||||
enum ShapeType
|
||||
{
|
||||
None,
|
||||
Polygon,
|
||||
PolygonRef,
|
||||
Edge,
|
||||
EdgePair,
|
||||
Text
|
||||
};
|
||||
|
||||
mutable ShapeType m_shape_type;
|
||||
mutable ShapeRef mp_shape;
|
||||
mutable db::properties_id_type m_prop_id;
|
||||
mutable db::PropertiesSet m_prop_set_out;
|
||||
double m_dbu;
|
||||
bool m_with_put;
|
||||
|
||||
tl::Variant shape_func () const;
|
||||
tl::Variant value_func (db::property_names_id_type name_id) const;
|
||||
tl::Variant value_func (const tl::Variant &name) const;
|
||||
tl::Variant values_func (const tl::Variant &name) const;
|
||||
void put_func (const tl::Variant &name, const tl::Variant &value) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An evaluation context for net expressions
|
||||
*
|
||||
* This class provides the methods, functions and variables for the expressions.
|
||||
*/
|
||||
class DB_PUBLIC MeasureNetEval
|
||||
: public tl::Eval
|
||||
{
|
||||
public:
|
||||
MeasureNetEval (const db::LayoutToNetlist *l2n, double dbu);
|
||||
|
||||
void set_primary_layer (unsigned int layer_index);
|
||||
void set_secondary_layer (const std::string &name, unsigned int layer_index);
|
||||
void init ();
|
||||
|
||||
void reset (db::cell_index_type cell_index, size_t cluster_id) const;
|
||||
|
||||
bool skip () const
|
||||
{
|
||||
return m_skip;
|
||||
}
|
||||
|
||||
db::PropertiesSet &prop_set_out () const
|
||||
{
|
||||
return m_prop_set_out;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class NetPutFunction;
|
||||
friend class NetAreaFunction;
|
||||
friend class NetPerimeterFunction;
|
||||
friend class NetNameFunction;
|
||||
friend class NetSkipFunction;
|
||||
|
||||
struct AreaAndPerimeter
|
||||
{
|
||||
AreaAndPerimeter () : area (0.0), perimeter (0.0) { }
|
||||
double area, perimeter;
|
||||
};
|
||||
|
||||
const db::LayoutToNetlist *mp_l2n;
|
||||
double m_dbu;
|
||||
std::vector<unsigned int> m_layers;
|
||||
mutable bool m_skip;
|
||||
mutable db::PropertiesSet m_prop_set_out;
|
||||
mutable db::cell_index_type m_cell_index;
|
||||
mutable size_t m_cluster_id;
|
||||
mutable std::map<unsigned int, AreaAndPerimeter> m_area_and_perimeter_cache;
|
||||
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;
|
||||
|
||||
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;
|
||||
tl::Variant net_name_func () const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -216,6 +216,11 @@ static db::Region antenna_check (db::LayoutToNetlist *l2n, const db::Region &pol
|
|||
return antenna_check3 (l2n, poly, 1, 0, metal, 1, 0, ratio, diodes, texts);
|
||||
}
|
||||
|
||||
static db::Region measure_net (db::LayoutToNetlist *l2n, const db::Region &primary, const std::map<std::string, const db::Region *> &secondary, const std::string &expression)
|
||||
{
|
||||
return l2n->measure_net (primary, secondary, expression);
|
||||
}
|
||||
|
||||
static void join_net_names (db::LayoutToNetlist *l2n, const std::string &s)
|
||||
{
|
||||
l2n->join_net_names (tl::GlobPattern (s));
|
||||
|
|
@ -1131,84 +1136,108 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
"This method has been introduced in version 0.28.13."
|
||||
) +
|
||||
gsi::method_ext ("antenna_check", &antenna_check, gsi::arg ("gate"), gsi::arg ("metal"), gsi::arg ("ratio"), gsi::arg ("diodes", std::vector<tl::Variant> (), "[]"), gsi::arg ("texts", (db::Texts *) 0, "nil"),
|
||||
"@brief Runs an antenna check on the extracted clusters\n"
|
||||
"\n"
|
||||
"The antenna check will traverse all clusters and run an antenna check\n"
|
||||
"for all root clusters. The antenna ratio is defined by the total\n"
|
||||
"area of all \"metal\" shapes divided by the total area of all \"gate\" shapes\n"
|
||||
"on the cluster. Of all clusters where the antenna ratio is larger than\n"
|
||||
"the limit ratio all metal shapes are copied to the output region as\n"
|
||||
"error markers.\n"
|
||||
"\n"
|
||||
"The simple call is:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"l2n = ... # a LayoutToNetlist object\n"
|
||||
"l2n.extract_netlist\n"
|
||||
"# check for antenna ratio 10.0 of metal vs. poly:\n"
|
||||
"errors = l2n.antenna(poly, metal, 10.0)\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"You can include diodes which rectify the antenna effect. "
|
||||
"Provide recognition layers for theses diodes and include them "
|
||||
"in the connections. Then specify the diode layers in the antenna call:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"...\n"
|
||||
"# include diode_layer1:\n"
|
||||
"errors = l2n.antenna(poly, metal, 10.0, [ diode_layer1 ])\n"
|
||||
"# include diode_layer1 and diode_layer2:"
|
||||
"errors = l2n.antenna(poly, metal, 10.0, [ diode_layer1, diode_layer2 ])\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"Diodes can be configured to partially reduce the antenna effect depending "
|
||||
"on their area. This will make the diode_layer1 increase the ratio by 50.0 "
|
||||
"per square micrometer area of the diode:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"...\n"
|
||||
"# diode_layer1 increases the ratio by 50 per square micrometer area:\n"
|
||||
"errors = l2n.antenna(poly, metal, 10.0 [ [ diode_layer, 50.0 ] ])\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"If 'texts' is non-nil, this text collection will receive labels explaining the error in "
|
||||
"terms of area values and relevant ratio.\n"
|
||||
"\n"
|
||||
"The 'texts' parameter has been added in version 0.27.11."
|
||||
"@brief Runs an antenna check on the extracted clusters\n"
|
||||
"\n"
|
||||
"The antenna check will traverse all clusters and run an antenna check\n"
|
||||
"for all root clusters. The antenna ratio is defined by the total\n"
|
||||
"area of all \"metal\" shapes divided by the total area of all \"gate\" shapes\n"
|
||||
"on the cluster. Of all clusters where the antenna ratio is larger than\n"
|
||||
"the limit ratio all metal shapes are copied to the output region as\n"
|
||||
"error markers.\n"
|
||||
"\n"
|
||||
"The simple call is:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"l2n = ... # a LayoutToNetlist object\n"
|
||||
"l2n.extract_netlist\n"
|
||||
"# check for antenna ratio 10.0 of metal vs. poly:\n"
|
||||
"errors = l2n.antenna(poly, metal, 10.0)\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"You can include diodes which rectify the antenna effect. "
|
||||
"Provide recognition layers for theses diodes and include them "
|
||||
"in the connections. Then specify the diode layers in the antenna call:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"...\n"
|
||||
"# include diode_layer1:\n"
|
||||
"errors = l2n.antenna(poly, metal, 10.0, [ diode_layer1 ])\n"
|
||||
"# include diode_layer1 and diode_layer2:"
|
||||
"errors = l2n.antenna(poly, metal, 10.0, [ diode_layer1, diode_layer2 ])\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"Diodes can be configured to partially reduce the antenna effect depending "
|
||||
"on their area. This will make the diode_layer1 increase the ratio by 50.0 "
|
||||
"per square micrometer area of the diode:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"...\n"
|
||||
"# diode_layer1 increases the ratio by 50 per square micrometer area:\n"
|
||||
"errors = l2n.antenna(poly, metal, 10.0 [ [ diode_layer, 50.0 ] ])\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"If 'texts' is non-nil, this text collection will receive labels explaining the error in "
|
||||
"terms of area values and relevant ratio.\n"
|
||||
"\n"
|
||||
"The 'texts' parameter has been added in version 0.27.11."
|
||||
) +
|
||||
gsi::method_ext ("antenna_check", &antenna_check2, gsi::arg ("gate"), gsi::arg ("gate_perimeter_factor"), gsi::arg ("metal"), gsi::arg ("metal_perimeter_factor"), gsi::arg ("ratio"), gsi::arg ("diodes", std::vector<tl::Variant> (), "[]"), gsi::arg ("texts", (db::Texts *) 0, "nil"),
|
||||
"@brief Runs an antenna check on the extracted clusters taking the perimeter into account\n"
|
||||
"\n"
|
||||
"This version of the \\antenna_check method allows taking the perimeter of gate or metal into account. "
|
||||
"The effective area is computed using:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"Aeff = A + P * t\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"Here Aeff is the area used in the check, A is the polygon area, P the perimeter and t the perimeter factor. "
|
||||
"This formula applies to gate polygon area/perimeter with 'gate_perimeter_factor' for t and metal polygon area/perimeter "
|
||||
"with 'metal_perimeter_factor'. The perimeter_factor has the dimension of micrometers and can be thought of as the width "
|
||||
"of the material. Essentially the side walls of the material are taking into account for the surface area as well.\n"
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.26.6.\n"
|
||||
"@brief Runs an antenna check on the extracted clusters taking the perimeter into account\n"
|
||||
"\n"
|
||||
"This version of the \\antenna_check method allows taking the perimeter of gate or metal into account. "
|
||||
"The effective area is computed using:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"Aeff = A + P * t\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"Here Aeff is the area used in the check, A is the polygon area, P the perimeter and t the perimeter factor. "
|
||||
"This formula applies to gate polygon area/perimeter with 'gate_perimeter_factor' for t and metal polygon area/perimeter "
|
||||
"with 'metal_perimeter_factor'. The perimeter_factor has the dimension of micrometers and can be thought of as the width "
|
||||
"of the material. Essentially the side walls of the material are taking into account for the surface area as well.\n"
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.26.6.\n"
|
||||
) +
|
||||
gsi::method_ext ("antenna_check", &antenna_check3, gsi::arg ("gate"), gsi::arg ("gate_area_factor"), gsi::arg ("gate_perimeter_factor"), gsi::arg ("metal"), gsi::arg ("metal_area_factor"), gsi::arg ("metal_perimeter_factor"), gsi::arg ("ratio"), gsi::arg ("diodes", std::vector<tl::Variant> (), "[]"), gsi::arg ("texts", (db::Texts *) 0, "nil"),
|
||||
"@brief Runs an antenna check on the extracted clusters taking the perimeter into account and providing an area factor\n"
|
||||
"\n"
|
||||
"This (most generic) version of the \\antenna_check method allows taking the perimeter of gate or metal into account and also "
|
||||
"provides a scaling factor for the area part.\n"
|
||||
"The effective area is computed using:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"Aeff = A * f + P * t\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"Here f is the area factor and t the perimeter factor. A is the polygon area and P the polygon perimeter. "
|
||||
"A use case for this variant is to set the area factor to zero. This way, only perimeter contributions are "
|
||||
"considered.\n"
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.26.6.\n"
|
||||
"@brief Runs an antenna check on the extracted clusters taking the perimeter into account and providing an area factor\n"
|
||||
"\n"
|
||||
"This (most generic) version of the \\antenna_check method allows taking the perimeter of gate or metal into account and also "
|
||||
"provides a scaling factor for the area part.\n"
|
||||
"The effective area is computed using:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"Aeff = A * f + P * t\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"Here f is the area factor and t the perimeter factor. A is the polygon area and P the polygon perimeter. "
|
||||
"A use case for this variant is to set the area factor to zero. This way, only perimeter contributions are "
|
||||
"considered.\n"
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.26.6.\n"
|
||||
) +
|
||||
gsi::method_ext ("measure_net", &measure_net, gsi::arg ("primary"), gsi::arg ("secondary"), gsi::arg ("expression"),
|
||||
"@brief Runs a generic net measurement function\n"
|
||||
"\n"
|
||||
"This method accepts some primary layer, a number of secondary layers with names and an expression.\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"
|
||||
"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"
|
||||
"\n"
|
||||
"The expression may use the following functions:\n"
|
||||
"\n"
|
||||
"@ul\n"
|
||||
"@li 'area': the area of all primary-layer shapes on the net in square um @/li\n"
|
||||
"@li 'area(name)': the area of all secondary-layer shapes. 'name' is a symbol with the name given in the secondary-layer map @/li\n"
|
||||
"@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 'net_name': the name of the net @/li\n"
|
||||
"@/ul\n"
|
||||
) +
|
||||
// test API
|
||||
gsi::method ("make_soft_connection_diodes=", &db::LayoutToNetlist::set_make_soft_connection_diodes, gsi::arg ("flag"), "@hide") +
|
||||
|
|
|
|||
|
|
@ -20,307 +20,12 @@
|
|||
|
||||
*/
|
||||
|
||||
#include "dbMeasureEval.h"
|
||||
#include "gsiDeclDbMeasureHelpers.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
class ShapeFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
ShapeFunction (MeasureEval *eval)
|
||||
: mp_eval (eval)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
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 () != 0) {
|
||||
throw tl::EvalError (tl::to_string (tr ("'shape' function does not take arguments")), context);
|
||||
}
|
||||
out = mp_eval->shape_func ();
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureEval *mp_eval;
|
||||
};
|
||||
|
||||
class ValueFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
ValueFunction (MeasureEval *eval)
|
||||
: mp_eval (eval)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
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 ("'value' function takes one argument")), context);
|
||||
}
|
||||
out = mp_eval->value_func (args [0]);
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureEval *mp_eval;
|
||||
};
|
||||
|
||||
class ValuesFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
ValuesFunction (MeasureEval *eval)
|
||||
: mp_eval (eval)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
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 ("'values' function takes one argument")), context);
|
||||
}
|
||||
out = mp_eval->values_func (args [0]);
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureEval *mp_eval;
|
||||
};
|
||||
|
||||
class PropertyFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
PropertyFunction (MeasureEval *eval, const tl::Variant &name)
|
||||
: mp_eval (eval), m_name_id (db::property_names_id (name))
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
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 () != 0) {
|
||||
throw tl::EvalError (tl::to_string (tr ("Property getter function does not take arguments")), context);
|
||||
}
|
||||
out = mp_eval->value_func (m_name_id);
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureEval *mp_eval;
|
||||
db::property_names_id_type m_name_id;
|
||||
};
|
||||
|
||||
class PutFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
PutFunction (MeasureEval *eval)
|
||||
: mp_eval (eval)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
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 () != 2) {
|
||||
throw tl::EvalError (tl::to_string (tr ("'put' function takes two arguments (name, value)")), context);
|
||||
}
|
||||
mp_eval->put_func (args [0], args [1]);
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureEval *mp_eval;
|
||||
db::property_names_id_type m_name_id;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// MeasureEval implementation
|
||||
|
||||
MeasureEval::MeasureEval (double dbu, bool with_put)
|
||||
: m_shape_type (None), m_prop_id (0), m_dbu (dbu), m_with_put (with_put)
|
||||
{
|
||||
mp_shape.any = 0;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::init ()
|
||||
{
|
||||
if (m_with_put) {
|
||||
define_function ("put", new PutFunction (this));
|
||||
}
|
||||
|
||||
define_function ("shape", new ShapeFunction (this));
|
||||
define_function ("value", new ValueFunction (this));
|
||||
define_function ("values", new ValuesFunction (this));
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::reset_shape () const
|
||||
{
|
||||
m_shape_type = None;
|
||||
mp_shape.any = 0;
|
||||
m_prop_id = 0;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::set_shape (const db::Polygon *poly) const
|
||||
{
|
||||
m_shape_type = Polygon;
|
||||
mp_shape.poly = poly;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::set_shape (const db::PolygonRef *poly) const
|
||||
{
|
||||
m_shape_type = PolygonRef;
|
||||
mp_shape.poly_ref = poly;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::set_shape (const db::Edge *edge) const
|
||||
{
|
||||
m_shape_type = Edge;
|
||||
mp_shape.edge = edge;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::set_shape (const db::EdgePair *edge_pair) const
|
||||
{
|
||||
m_shape_type = EdgePair;
|
||||
mp_shape.edge_pair = edge_pair;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::set_shape (const db::Text *text) const
|
||||
{
|
||||
m_shape_type = Text;
|
||||
mp_shape.text = text;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::set_prop_id (db::properties_id_type prop_id) const
|
||||
{
|
||||
m_prop_id = prop_id;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::resolve_name (const std::string &name, const tl::EvalFunction *&function, const tl::Variant *&value, tl::Variant *&var)
|
||||
{
|
||||
tl::Eval::resolve_name (name, function, value, var);
|
||||
|
||||
if (!function && !value && !var) {
|
||||
// connect the name with a function getting the property value
|
||||
tl::EvalFunction *f = new PropertyFunction (this, name);
|
||||
define_function (name, f);
|
||||
function = f;
|
||||
}
|
||||
}
|
||||
|
||||
tl::Variant
|
||||
MeasureEval::shape_func () const
|
||||
{
|
||||
if (m_dbu > 1e-10) {
|
||||
|
||||
db::CplxTrans tr (m_dbu);
|
||||
|
||||
switch (m_shape_type)
|
||||
{
|
||||
case None:
|
||||
default:
|
||||
return tl::Variant ();
|
||||
case Polygon:
|
||||
return tl::Variant (tr * *mp_shape.poly);
|
||||
case PolygonRef:
|
||||
{
|
||||
db::Polygon poly;
|
||||
mp_shape.poly_ref->instantiate (poly);
|
||||
return tl::Variant (tr * poly);
|
||||
}
|
||||
case Edge:
|
||||
return tl::Variant (tr * *mp_shape.edge);
|
||||
case EdgePair:
|
||||
return tl::Variant (tr * *mp_shape.edge_pair);
|
||||
case Text:
|
||||
return tl::Variant (tr * *mp_shape.text);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
switch (m_shape_type)
|
||||
{
|
||||
case None:
|
||||
default:
|
||||
return tl::Variant ();
|
||||
case Polygon:
|
||||
return tl::Variant (*mp_shape.poly);
|
||||
case PolygonRef:
|
||||
{
|
||||
db::Polygon poly;
|
||||
mp_shape.poly_ref->instantiate (poly);
|
||||
return tl::Variant (poly);
|
||||
}
|
||||
case Edge:
|
||||
return tl::Variant (*mp_shape.edge);
|
||||
case EdgePair:
|
||||
return tl::Variant (*mp_shape.edge_pair);
|
||||
case Text:
|
||||
return tl::Variant (*mp_shape.text);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
tl::Variant
|
||||
MeasureEval::value_func (db::property_names_id_type name_id) const
|
||||
{
|
||||
const db::PropertiesSet &ps = db::properties (m_prop_id);
|
||||
for (auto i = ps.begin (); i != ps.end (); ++i) {
|
||||
if (i->first == name_id) {
|
||||
return db::property_value (i->second);
|
||||
}
|
||||
}
|
||||
|
||||
return tl::Variant ();
|
||||
}
|
||||
|
||||
tl::Variant
|
||||
MeasureEval::value_func (const tl::Variant &name) const
|
||||
{
|
||||
const db::PropertiesSet &ps = db::properties (m_prop_id);
|
||||
for (auto i = ps.begin (); i != ps.end (); ++i) {
|
||||
if (db::property_name (i->first) == name) {
|
||||
return db::property_value (i->second);
|
||||
}
|
||||
}
|
||||
|
||||
return tl::Variant ();
|
||||
}
|
||||
|
||||
tl::Variant
|
||||
MeasureEval::values_func (const tl::Variant &name) const
|
||||
{
|
||||
tl::Variant res = tl::Variant::empty_list ();
|
||||
|
||||
const db::PropertiesSet &ps = db::properties (m_prop_id);
|
||||
for (auto i = ps.begin (); i != ps.end (); ++i) {
|
||||
if (db::property_name (i->first) == name) {
|
||||
res.push (db::property_value (i->second));
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
MeasureEval::put_func (const tl::Variant &name, const tl::Variant &value) const
|
||||
{
|
||||
auto prop_name_id = db::property_names_id (name);
|
||||
m_prop_set_out.erase (prop_name_id);
|
||||
m_prop_set_out.insert (prop_name_id, value);
|
||||
}
|
||||
// .. nothing yet ..
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,13 +23,9 @@
|
|||
#ifndef HDR_gsiDeclDbMeasureHelpers
|
||||
#define HDR_gsiDeclDbMeasureHelpers
|
||||
|
||||
#include "dbRegion.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbEdgePairs.h"
|
||||
#include "dbTexts.h"
|
||||
#include "dbMeasureEval.h"
|
||||
#include "dbRegionUtils.h"
|
||||
#include "dbEdgesUtils.h"
|
||||
#include "tlExpression.h"
|
||||
#include "gsiClassBase.h"
|
||||
#include "gsiDeclDbContainerHelpers.h"
|
||||
|
||||
|
|
@ -39,76 +35,6 @@ namespace gsi
|
|||
// -------------------------------------------------------------------------------------
|
||||
// Some utilities
|
||||
|
||||
/**
|
||||
* @brief An evaluation context for the expressions
|
||||
*
|
||||
* This class provides the methods, functions and variables for the expressions.
|
||||
*/
|
||||
class DB_PUBLIC MeasureEval
|
||||
: public tl::Eval
|
||||
{
|
||||
public:
|
||||
MeasureEval (double dbu, bool with_put);
|
||||
|
||||
void init ();
|
||||
|
||||
void reset_shape () const;
|
||||
void set_shape (const db::Polygon *poly) const;
|
||||
void set_shape (const db::PolygonRef *poly) const;
|
||||
void set_shape (const db::Edge *edge) const;
|
||||
void set_shape (const db::EdgePair *edge_pair) const;
|
||||
void set_shape (const db::Text *text) const;
|
||||
void set_prop_id (db::properties_id_type prop_id) const;
|
||||
|
||||
db::PropertiesSet &prop_set_out () const
|
||||
{
|
||||
return m_prop_set_out;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void resolve_name (const std::string &name, const tl::EvalFunction *&function, const tl::Variant *&value, tl::Variant *&var);
|
||||
|
||||
private:
|
||||
friend class ShapeFunction;
|
||||
friend class ValueFunction;
|
||||
friend class ValuesFunction;
|
||||
friend class PropertyFunction;
|
||||
friend class PutFunction;
|
||||
|
||||
union ShapeRef
|
||||
{
|
||||
const db::Polygon *poly;
|
||||
const db::PolygonRef *poly_ref;
|
||||
const db::Edge *edge;
|
||||
const db::EdgePair *edge_pair;
|
||||
const db::Text *text;
|
||||
void *any;
|
||||
};
|
||||
|
||||
enum ShapeType
|
||||
{
|
||||
None,
|
||||
Polygon,
|
||||
PolygonRef,
|
||||
Edge,
|
||||
EdgePair,
|
||||
Text
|
||||
};
|
||||
|
||||
mutable ShapeType m_shape_type;
|
||||
mutable ShapeRef mp_shape;
|
||||
mutable db::properties_id_type m_prop_id;
|
||||
mutable db::PropertiesSet m_prop_set_out;
|
||||
double m_dbu;
|
||||
bool m_with_put;
|
||||
|
||||
tl::Variant shape_func () const;
|
||||
tl::Variant value_func (db::property_names_id_type name_id) const;
|
||||
tl::Variant value_func (const tl::Variant &name) const;
|
||||
tl::Variant values_func (const tl::Variant &name) const;
|
||||
void put_func (const tl::Variant &name, const tl::Variant &value) const;
|
||||
};
|
||||
|
||||
inline db::RecursiveShapeIterator
|
||||
begin_iter (const db::Region *region)
|
||||
{
|
||||
|
|
@ -224,7 +150,7 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
MeasureEval m_eval;
|
||||
db::MeasureEval m_eval;
|
||||
std::vector<std::pair<db::property_names_id_type, tl::Expression> > m_expressions;
|
||||
bool m_copy_properties;
|
||||
std::map<tl::Variant, std::string> m_expression_strings;
|
||||
|
|
@ -274,7 +200,7 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
MeasureEval m_eval;
|
||||
db::MeasureEval m_eval;
|
||||
tl::Expression m_expression;
|
||||
bool m_inverse;
|
||||
std::string m_expression_string;
|
||||
|
|
|
|||
Loading…
Reference in New Issue