mirror of https://github.com/KLayout/klayout.git
L2N log entries with net references
* Log entries on the L2N object can now have net references
(by expanded name) and the nets will be highlighted
when the log entry is selected in the netlist browser
For an application see drcSimpleTests:147.
* New function ("db") in evaluate_nets
* BUGFIX: proper computation of transformations for multiple
selections of nets in netlist browser
This commit is contained in:
parent
7b002a1815
commit
38ddffc645
|
|
@ -188,7 +188,7 @@ namespace db
|
|||
* scale(<mag>) - magnification (default is 1) [short key: S]
|
||||
*
|
||||
* [message-entry]:
|
||||
* message([severity] [message|message-geometry|message-cell|message-category|any]*) - message entry [short key: H]
|
||||
* message([severity] [message|message-geometry|message-cell|message-category|message-net|any]*) - message entry [short key: H]
|
||||
*
|
||||
* [message]:
|
||||
* description(<name>) - message text [short key: B]
|
||||
|
|
@ -199,6 +199,9 @@ namespace db
|
|||
* [message-cell]:
|
||||
* cell(<name>) - message cell [short key: C]
|
||||
*
|
||||
* [message-net]:
|
||||
* net(<name>) - message net name [short key: N]
|
||||
*
|
||||
* [message-category]:
|
||||
* cat(<name> <name>?) - message category with optional description [short key: X]
|
||||
*
|
||||
|
|
|
|||
|
|
@ -225,6 +225,18 @@ bool LayoutToNetlistStandardReader::read_message_cell (std::string &cell_name)
|
|||
}
|
||||
}
|
||||
|
||||
bool LayoutToNetlistStandardReader::read_message_net (std::string &net_name)
|
||||
{
|
||||
if (test (skeys::net_key) || test (lkeys::net_key)) {
|
||||
Brace br (this);
|
||||
read_word_or_quoted (net_name);
|
||||
br.done ();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool LayoutToNetlistStandardReader::read_message_geometry (db::DPolygon &polygon)
|
||||
{
|
||||
if (test (skeys::polygon_key) || test (lkeys::polygon_key)) {
|
||||
|
|
@ -258,7 +270,7 @@ bool LayoutToNetlistStandardReader::read_message_cat (std::string &category_name
|
|||
void LayoutToNetlistStandardReader::read_message_entry (db::LogEntryData &data)
|
||||
{
|
||||
Severity severity (db::NoSeverity);
|
||||
std::string msg, cell_name, category_name, category_description;
|
||||
std::string msg, cell_name, net_name, category_name, category_description;
|
||||
db::DPolygon geometry;
|
||||
|
||||
Brace br (this);
|
||||
|
|
@ -269,6 +281,8 @@ void LayoutToNetlistStandardReader::read_message_entry (db::LogEntryData &data)
|
|||
// continue
|
||||
} else if (read_message_cell (cell_name)) {
|
||||
// continue
|
||||
} else if (read_message_net (net_name)) {
|
||||
// continue
|
||||
} else if (read_message_cat (category_name, category_description)) {
|
||||
// continue
|
||||
} else if (read_message_geometry (geometry)) {
|
||||
|
|
@ -282,6 +296,7 @@ void LayoutToNetlistStandardReader::read_message_entry (db::LogEntryData &data)
|
|||
data.set_severity (severity);
|
||||
data.set_message (msg);
|
||||
data.set_cell_name (cell_name);
|
||||
data.set_net_name (net_name);
|
||||
data.set_category_description (category_description);
|
||||
data.set_category_name (category_name);
|
||||
data.set_geometry (geometry);
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ private:
|
|||
db::Point read_point ();
|
||||
void read_message_entry (db::LogEntryData &data);
|
||||
bool read_message_cell (std::string &cell_name);
|
||||
bool read_message_net (std::string &net_name);
|
||||
bool read_message_geometry (db::DPolygon &polygon);
|
||||
bool read_message_cat (std::string &category_name, std::string &category_description);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -211,6 +211,10 @@ void std_writer_impl<Keys>::write_log_entry (TokenizedOutput &stream, const LogE
|
|||
TokenizedOutput (stream, Keys::cell_key, true) << tl::to_word_or_quoted_string (le.cell_name ());
|
||||
}
|
||||
|
||||
if (! le.net_name ().empty ()) {
|
||||
TokenizedOutput (stream, Keys::net_key, true) << tl::to_word_or_quoted_string (le.net_name ());
|
||||
}
|
||||
|
||||
if (! le.category_name ().empty ()) {
|
||||
TokenizedOutput o (stream, Keys::cat_key, true);
|
||||
o << tl::to_word_or_quoted_string (le.category_name ());
|
||||
|
|
|
|||
|
|
@ -81,19 +81,25 @@ static LogEntryStringRepository s_strings;
|
|||
// LogEntryData implementation
|
||||
|
||||
LogEntryData::LogEntryData ()
|
||||
: m_severity (NoSeverity), m_cell_name (0), m_message (0), m_category_name (0), m_category_description (0)
|
||||
: m_severity (NoSeverity), m_cell_name (0), m_net_name (0), m_message (0), m_category_name (0), m_category_description (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
LogEntryData::LogEntryData (Severity s, const std::string &msg)
|
||||
: m_severity (s), m_cell_name (0), m_message (s_strings.id_for_string (msg)), m_category_name (0), m_category_description (0)
|
||||
: m_severity (s), m_cell_name (0), m_net_name (0), m_message (s_strings.id_for_string (msg)), m_category_name (0), m_category_description (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
LogEntryData::LogEntryData (Severity s, const std::string &cell_name, const std::string &msg)
|
||||
: m_severity (s), m_cell_name (s_strings.id_for_string (cell_name)), m_message (s_strings.id_for_string (msg)), m_category_name (0), m_category_description (0)
|
||||
: m_severity (s), m_cell_name (s_strings.id_for_string (cell_name)), m_net_name (0), m_message (s_strings.id_for_string (msg)), m_category_name (0), m_category_description (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
LogEntryData::LogEntryData (Severity s, const std::string &cell_name, const std::string &net_name, const std::string &msg)
|
||||
: m_severity (s), m_cell_name (s_strings.id_for_string (cell_name)), m_net_name (s_strings.id_for_string (net_name)), m_message (s_strings.id_for_string (msg)), m_category_name (0), m_category_description (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -104,6 +110,7 @@ LogEntryData::operator== (const LogEntryData &other) const
|
|||
return m_severity == other.m_severity &&
|
||||
m_message == other.m_message &&
|
||||
m_cell_name == other.m_cell_name &&
|
||||
m_net_name == other.m_net_name &&
|
||||
m_geometry == other.m_geometry &&
|
||||
m_category_name == other.m_category_name &&
|
||||
m_category_description == other.m_category_description;
|
||||
|
|
@ -157,6 +164,18 @@ LogEntryData::set_cell_name (const std::string &n)
|
|||
m_cell_name = s_strings.id_for_string (n);
|
||||
}
|
||||
|
||||
const std::string &
|
||||
LogEntryData::net_name () const
|
||||
{
|
||||
return s_strings.string_for_id (m_net_name);
|
||||
}
|
||||
|
||||
void
|
||||
LogEntryData::set_net_name (const std::string &n)
|
||||
{
|
||||
m_net_name = s_strings.id_for_string (n);
|
||||
}
|
||||
|
||||
std::string
|
||||
LogEntryData::to_string (bool with_geometry) const
|
||||
{
|
||||
|
|
@ -179,10 +198,24 @@ LogEntryData::to_string (bool with_geometry) const
|
|||
}
|
||||
}
|
||||
|
||||
if (m_cell_name != 0) {
|
||||
res += tl::to_string (tr ("In cell "));
|
||||
res += cell_name ();
|
||||
res += ": ";
|
||||
if (m_net_name != 0) {
|
||||
if (m_cell_name != 0) {
|
||||
res += tl::to_string (tr ("In net "));
|
||||
res += net_name ();
|
||||
res += tl::to_string (tr (" in circuit "));
|
||||
res += cell_name ();
|
||||
res += ": ";
|
||||
} else {
|
||||
res += tl::to_string (tr ("In net "));
|
||||
res += net_name ();
|
||||
res += ": ";
|
||||
}
|
||||
} else {
|
||||
if (m_cell_name != 0) {
|
||||
res += tl::to_string (tr ("In cell "));
|
||||
res += cell_name ();
|
||||
res += ": ";
|
||||
}
|
||||
}
|
||||
|
||||
res += msg;
|
||||
|
|
|
|||
|
|
@ -68,6 +68,11 @@ public:
|
|||
*/
|
||||
LogEntryData (Severity s, const std::string &cell_name, const std::string &msg);
|
||||
|
||||
/**
|
||||
* @brief Creates an error with the severity, a cell (circuit) name, a net name and a message
|
||||
*/
|
||||
LogEntryData (Severity s, const std::string &cell_name, const std::string &net_name, const std::string &msg);
|
||||
|
||||
/**
|
||||
* @brief Equality
|
||||
*/
|
||||
|
|
@ -158,6 +163,16 @@ public:
|
|||
*/
|
||||
void set_cell_name (const std::string &n);
|
||||
|
||||
/**
|
||||
* @brief Gets the net name the error occurred in
|
||||
*/
|
||||
const std::string &net_name () const;
|
||||
|
||||
/**
|
||||
* @brief Sets the net name
|
||||
*/
|
||||
void set_net_name (const std::string &n);
|
||||
|
||||
/**
|
||||
* @brief Formats this message for printing
|
||||
*/
|
||||
|
|
@ -166,6 +181,7 @@ public:
|
|||
private:
|
||||
Severity m_severity;
|
||||
string_id_type m_cell_name;
|
||||
string_id_type m_net_name;
|
||||
string_id_type m_message;
|
||||
db::DPolygon m_geometry;
|
||||
string_id_type m_category_name, m_category_description;
|
||||
|
|
|
|||
|
|
@ -492,6 +492,28 @@ private:
|
|||
MeasureNetEval *mp_eval;
|
||||
};
|
||||
|
||||
class NetDbFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
NetDbFunction (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 () != 0) {
|
||||
throw tl::EvalError (tl::to_string (tr ("'db' function does not take any argument")), context);
|
||||
}
|
||||
out = mp_eval->db_func ();
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureNetEval *mp_eval;
|
||||
};
|
||||
|
||||
class NetFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
|
|
@ -558,7 +580,7 @@ private:
|
|||
MeasureNetEval *mp_eval;
|
||||
};
|
||||
|
||||
MeasureNetEval::MeasureNetEval (const db::LayoutToNetlist *l2n, double dbu)
|
||||
MeasureNetEval::MeasureNetEval (LayoutToNetlist *l2n, double dbu)
|
||||
: tl::Eval (), mp_l2n (l2n), m_dbu (dbu)
|
||||
{
|
||||
m_copy_merge = false;
|
||||
|
|
@ -588,6 +610,7 @@ MeasureNetEval::init ()
|
|||
define_function ("area", new NetAreaFunction (this));
|
||||
define_function ("perimeter", new NetPerimeterFunction (this));
|
||||
define_function ("net", new NetFunction (this));
|
||||
define_function ("db", new NetDbFunction (this));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -701,4 +724,10 @@ MeasureNetEval::net_func () const
|
|||
}
|
||||
}
|
||||
|
||||
tl::Variant
|
||||
MeasureNetEval::db_func () const
|
||||
{
|
||||
return tl::Variant::make_variant_ref (mp_l2n);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ class DB_PUBLIC MeasureNetEval
|
|||
: public tl::Eval
|
||||
{
|
||||
public:
|
||||
MeasureNetEval (const db::LayoutToNetlist *l2n, double dbu);
|
||||
MeasureNetEval (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);
|
||||
|
|
@ -144,6 +144,7 @@ private:
|
|||
friend class NetAreaFunction;
|
||||
friend class NetPerimeterFunction;
|
||||
friend class NetFunction;
|
||||
friend class NetDbFunction;
|
||||
friend class NetSkipFunction;
|
||||
friend class NetCopyFunction;
|
||||
|
||||
|
|
@ -153,7 +154,7 @@ private:
|
|||
double area, perimeter;
|
||||
};
|
||||
|
||||
const db::LayoutToNetlist *mp_l2n;
|
||||
db::LayoutToNetlist *mp_l2n;
|
||||
double m_dbu;
|
||||
std::vector<unsigned int> m_layers;
|
||||
mutable std::vector<unsigned int> m_copy_layers;
|
||||
|
|
@ -173,6 +174,7 @@ private:
|
|||
tl::Variant perimeter_func (int layer_index) const;
|
||||
void copy_func (const std::vector<unsigned int> &layer_indexes, bool merge, size_t max_polygons) const;
|
||||
tl::Variant net_func () const;
|
||||
tl::Variant db_func () const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1251,6 +1251,7 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
"@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"
|
||||
"@li 'db': the \\LayoutToDatabase object the netlist lives in @/li\n"
|
||||
"@/ul\n"
|
||||
"\n"
|
||||
"If given, the 'dbu' argument gives the database unit to use for converting shape dimensions into micrometer units. "
|
||||
|
|
@ -1294,7 +1295,7 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
"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."
|
||||
"The 'copy' and 'db' functions were 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") +
|
||||
|
|
|
|||
|
|
@ -23,11 +23,53 @@
|
|||
#include "gsiDecl.h"
|
||||
#include "gsiEnums.h"
|
||||
#include "dbLog.h"
|
||||
#include "dbNet.h"
|
||||
#include "dbCircuit.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
db::LogEntryData *new_le1 (db::Severity severity, const std::string &msg)
|
||||
{
|
||||
return new db::LogEntryData (severity, msg);
|
||||
}
|
||||
|
||||
db::LogEntryData *new_le2 (db::Severity severity, const std::string &cell_name, const std::string &msg)
|
||||
{
|
||||
return new db::LogEntryData (severity, cell_name, msg);
|
||||
}
|
||||
|
||||
db::LogEntryData *new_le3 (db::Severity severity, const std::string &cell_name, const std::string &net_name, const std::string &msg)
|
||||
{
|
||||
return new db::LogEntryData (severity, cell_name, net_name, msg);
|
||||
}
|
||||
|
||||
db::LogEntryData *new_le4 (db::Severity severity, const db::Net *net, const std::string &msg)
|
||||
{
|
||||
if (! net || ! net->circuit ()) {
|
||||
return new db::LogEntryData (severity, msg);
|
||||
} else {
|
||||
return new db::LogEntryData (severity, net->circuit ()->name (), net->expanded_name (), msg);
|
||||
}
|
||||
}
|
||||
|
||||
Class<db::LogEntryData> decl_dbNetlistDeviceExtractorError ("db", "LogEntryData",
|
||||
gsi::constructor ("new", &new_le1, gsi::arg ("severity"), gsi::arg ("msg"),
|
||||
"@brief Creates a new LogEntry object with the given severity and message\n"
|
||||
"This convenience constructor has been added in version 0.30.6\n"
|
||||
) +
|
||||
gsi::constructor ("new", &new_le2, gsi::arg ("severity"), gsi::arg ("cell_name"), gsi::arg ("msg"),
|
||||
"@brief Creates a new LogEntry object with the given severity, cell or circuit name and message\n"
|
||||
"This convenience constructor has been added in version 0.30.6\n"
|
||||
) +
|
||||
gsi::constructor ("new", &new_le3, gsi::arg ("severity"), gsi::arg ("cell_name"), gsi::arg ("new_name"), gsi::arg ("msg"),
|
||||
"@brief Creates a new LogEntry object with the given severity, cell or circuit name, net name and message\n"
|
||||
"This convenience constructor has been added in version 0.30.6\n"
|
||||
) +
|
||||
gsi::constructor ("new", &new_le4, gsi::arg ("severity"), gsi::arg ("net"), gsi::arg ("msg"),
|
||||
"@brief Creates a new LogEntry object with the given severity and message and circuit and net name taken from the given \\Net object\n"
|
||||
"This convenience constructor has been added in version 0.30.6\n"
|
||||
) +
|
||||
gsi::method ("severity", &db::LogEntryData::severity,
|
||||
"@brief Gets the severity attribute.\n"
|
||||
) +
|
||||
|
|
@ -51,6 +93,21 @@ Class<db::LogEntryData> decl_dbNetlistDeviceExtractorError ("db", "LogEntryData"
|
|||
"warning generated during device extraction, the cell name is "
|
||||
"the circuit the device should have appeared in."
|
||||
) +
|
||||
gsi::method ("net_name", &db::LogEntryData::net_name,
|
||||
"@brief Gets the net name.\n"
|
||||
"See \\net_name= for details about this attribute."
|
||||
"\n"
|
||||
"The net_name attribute has been introduced in version 0.30.6.\n"
|
||||
) +
|
||||
gsi::method ("net_name=", &db::LogEntryData::set_net_name, gsi::arg ("net_name"),
|
||||
"@brief Sets the net name.\n"
|
||||
"The net (or circuit) name specifies the net the "
|
||||
"log entry is related to.\n"
|
||||
"\n"
|
||||
"By convention, the net name is the expanded net name (see \\Net#expanded_name).\n"
|
||||
"\n"
|
||||
"The net_name attribute has been introduced in version 0.30.6.\n"
|
||||
) +
|
||||
gsi::method ("geometry", &db::LogEntryData::geometry,
|
||||
"@brief Gets the geometry.\n"
|
||||
"See \\geometry= for more details."
|
||||
|
|
|
|||
|
|
@ -807,6 +807,7 @@ module DRC
|
|||
#
|
||||
# @ul
|
||||
# @li "net" - the RBA::Net object of the current net @/li
|
||||
# @li "db" - the RBA::LayoutToNetlist object the netlist lives in @/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
|
||||
|
|
|
|||
|
|
@ -2076,3 +2076,35 @@ TEST(146d_edges_and_corners)
|
|||
run_test (_this, "146", true);
|
||||
}
|
||||
|
||||
TEST(147_MeasureNetsWithL2N)
|
||||
{
|
||||
std::string rs = tl::testdata ();
|
||||
rs += "/drc/drcSimpleTests_147.drc";
|
||||
|
||||
std::string input = tl::testdata ();
|
||||
input += "/drc/drcSimpleTests_147.gds";
|
||||
|
||||
std::string au_output = tl::testdata ();
|
||||
au_output += "/drc/drcSimpleTests_au147.l2n";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.l2n");
|
||||
|
||||
{
|
||||
// Set some variables
|
||||
lym::Macro config;
|
||||
config.set_text (tl::sprintf (
|
||||
"$drc_test_source = '%s'\n"
|
||||
"$drc_test_target = '%s'\n"
|
||||
, input, output)
|
||||
);
|
||||
config.set_interpreter (lym::Macro::Ruby);
|
||||
EXPECT_EQ (config.run (), 0);
|
||||
}
|
||||
|
||||
lym::Macro drc;
|
||||
drc.load_from (rs);
|
||||
EXPECT_EQ (drc.run (), 0);
|
||||
|
||||
compare_text_files (output, au_output);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,6 +75,24 @@ struct test_arg_func<gsi::VariantType>
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct test_arg_func<gsi::StringType>
|
||||
{
|
||||
void operator () (bool *ret, const tl::Variant &arg, const gsi::ArgType & /*atype*/, bool /*loose*/, bool /*object_substitution*/)
|
||||
{
|
||||
*ret = arg.is_a_string ();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct test_arg_func<gsi::ByteArrayType>
|
||||
{
|
||||
void operator () (bool *ret, const tl::Variant &arg, const gsi::ArgType & /*atype*/, bool /*loose*/, bool /*object_substitution*/)
|
||||
{
|
||||
*ret = arg.is_a_bytearray ();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct test_arg_func<gsi::ObjectType>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -816,15 +816,31 @@ NetlistBrowserPage::log_selection_changed ()
|
|||
|
||||
QModelIndexList selection = log_view->selectionModel ()->selectedIndexes ();
|
||||
for (QModelIndexList::const_iterator i = selection.begin (); i != selection.end (); ++i) {
|
||||
if (i->column () == 0) {
|
||||
const db::LogEntryData *le = model->log_entry (*i);
|
||||
if (le && le->geometry () != db::DPolygon () && ! le->cell_name ().empty ()) {
|
||||
const db::Circuit *c = mp_database->netlist ()->circuit_by_name (le->cell_name ());
|
||||
if (c) {
|
||||
m_markers.push_back (std::make_pair (c, le->geometry ()));
|
||||
}
|
||||
|
||||
if (i->column () != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const db::LogEntryData *le = model->log_entry (*i);
|
||||
|
||||
const db::Circuit *c = 0;
|
||||
if (le && ! le->cell_name ().empty ()) {
|
||||
c = mp_database->netlist ()->circuit_by_name (le->cell_name ());
|
||||
}
|
||||
|
||||
// highlight geometries
|
||||
if (c && le->geometry () != db::DPolygon ()) {
|
||||
m_markers.push_back (std::make_pair (c, le->geometry ()));
|
||||
}
|
||||
|
||||
// highlight nets
|
||||
if (c && ! le->net_name ().empty ()) {
|
||||
const db::Net *net = c->net_by_name (le->net_name ());
|
||||
if (net) {
|
||||
m_net_markers.push_back (std::make_pair (c, net));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
update_highlights ();
|
||||
|
|
@ -1291,6 +1307,7 @@ NetlistBrowserPage::clear_highlights ()
|
|||
m_current_path = lay::NetlistObjectsPath ();
|
||||
m_selected_paths.clear ();
|
||||
m_markers.clear ();
|
||||
m_net_markers.clear ();
|
||||
|
||||
update_highlights ();
|
||||
}
|
||||
|
|
@ -1350,6 +1367,31 @@ bbox_for_circuit (const db::Layout *layout, const db::Circuit *circuit)
|
|||
return layout->cell (circuit->cell_index ()).bbox ();
|
||||
}
|
||||
|
||||
static db::Box
|
||||
bbox_for_net (const db::LayoutToNetlist *db, const db::Circuit *circuit, const db::Net *net)
|
||||
{
|
||||
db::Box bbox;
|
||||
|
||||
db::cell_index_type cell_index = circuit->cell_index ();
|
||||
size_t cluster_id = net->cluster_id ();
|
||||
|
||||
const db::Connectivity &conn = db->connectivity ();
|
||||
for (db::Connectivity::all_layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
|
||||
db::Box layer_bbox;
|
||||
db::recursive_cluster_shape_iterator<db::NetShape> shapes (db->net_clusters (), *layer, cell_index, cluster_id);
|
||||
while (! shapes.at_end ()) {
|
||||
layer_bbox += shapes->bbox ().transformed (shapes.trans ());
|
||||
++shapes;
|
||||
}
|
||||
|
||||
bbox += layer_bbox;
|
||||
|
||||
}
|
||||
|
||||
return bbox;
|
||||
}
|
||||
|
||||
void
|
||||
NetlistBrowserPage::adjust_view ()
|
||||
{
|
||||
|
|
@ -1425,22 +1467,7 @@ NetlistBrowserPage::adjust_view ()
|
|||
|
||||
} else if (net) {
|
||||
|
||||
db::cell_index_type cell_index = net->circuit ()->cell_index ();
|
||||
size_t cluster_id = net->cluster_id ();
|
||||
|
||||
const db::Connectivity &conn = mp_database->connectivity ();
|
||||
for (db::Connectivity::all_layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
|
||||
|
||||
db::Box layer_bbox;
|
||||
db::recursive_cluster_shape_iterator<db::NetShape> shapes (mp_database->net_clusters (), *layer, cell_index, cluster_id);
|
||||
while (! shapes.at_end ()) {
|
||||
layer_bbox += shapes->bbox ().transformed (shapes.trans ());
|
||||
++shapes;
|
||||
}
|
||||
|
||||
ebox += layer_bbox;
|
||||
|
||||
}
|
||||
ebox += bbox_for_net (mp_database.get (), circuit, net);
|
||||
|
||||
} else if (circuit) {
|
||||
ebox += bbox_for_circuit (layout, circuit);
|
||||
|
|
@ -1461,6 +1488,17 @@ NetlistBrowserPage::adjust_view ()
|
|||
|
||||
}
|
||||
|
||||
// add net markers boxes
|
||||
|
||||
for (auto marker = m_net_markers.begin (); marker != m_net_markers.end (); ++marker) {
|
||||
|
||||
std::pair<bool, db::DCplxTrans> tr = trans_for (marker->first, *layout, *cell, m_cell_context_cache, cv.context_dtrans ());
|
||||
if (tr.first) {
|
||||
bbox += tr.second * db::CplxTrans (layout->dbu ()) * bbox_for_net (mp_database.get (), marker->first, marker->second);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! bbox.empty ()) {
|
||||
|
||||
std::vector<db::DCplxTrans> tv = mp_view->cv_transform_variants (m_cv_index);
|
||||
|
|
@ -1739,26 +1777,52 @@ NetlistBrowserPage::update_highlights ()
|
|||
// a map of display properties vs. layer properties
|
||||
|
||||
// correct DBU differences between the storage layout and the original layout
|
||||
for (std::vector<db::DCplxTrans>::iterator t = tv.begin (); t != tv.end (); ++t) {
|
||||
std::vector<db::DCplxTrans> tvt = tv;
|
||||
for (std::vector<db::DCplxTrans>::iterator t = tvt.begin (); t != tvt.end (); ++t) {
|
||||
*t = *t * trans * db::DCplxTrans (layout->dbu () / original_layout.dbu ());
|
||||
}
|
||||
|
||||
if (path->net.first) {
|
||||
if (produce_highlights_for_net (path->net.first, n_markers, display_by_lp, tv)) {
|
||||
if (produce_highlights_for_net (path->net.first, n_markers, display_by_lp, tvt)) {
|
||||
not_all_shapes_are_shown = true;
|
||||
}
|
||||
} else if (path->device.first) {
|
||||
if (produce_highlights_for_device (path->device.first, n_markers, tv)) {
|
||||
if (produce_highlights_for_device (path->device.first, n_markers, tvt)) {
|
||||
not_all_shapes_are_shown = true;
|
||||
}
|
||||
} else if (circuit) {
|
||||
if (produce_highlights_for_circuit (circuit, n_markers, tv)) {
|
||||
if (produce_highlights_for_circuit (circuit, n_markers, tvt)) {
|
||||
not_all_shapes_are_shown = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (auto marker = m_net_markers.begin (); marker != m_net_markers.end (); ++marker) {
|
||||
|
||||
// computes the transformation supplied by the path
|
||||
|
||||
std::pair<bool, db::DCplxTrans> tr = trans_for (marker->first, *layout, *cell, m_cell_context_cache, cv.context_dtrans ());
|
||||
if (! tr.first) {
|
||||
continue;
|
||||
}
|
||||
|
||||
db::DCplxTrans trans = tr.second;
|
||||
|
||||
// a map of display properties vs. layer properties
|
||||
|
||||
// correct DBU differences between the storage layout and the original layout
|
||||
std::vector<db::DCplxTrans> tvt = tv;
|
||||
for (std::vector<db::DCplxTrans>::iterator t = tvt.begin (); t != tvt.end (); ++t) {
|
||||
*t = *t * trans * db::DCplxTrans (layout->dbu () / original_layout.dbu ());
|
||||
}
|
||||
|
||||
if (produce_highlights_for_net (marker->second, n_markers, display_by_lp, tvt)) {
|
||||
not_all_shapes_are_shown = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (auto marker = m_markers.begin (); marker != m_markers.end (); ++marker) {
|
||||
|
||||
// computes the transformation supplied by the path
|
||||
|
|
|
|||
|
|
@ -246,6 +246,7 @@ private:
|
|||
lay::NetlistObjectsPath m_current_path;
|
||||
std::vector<lay::NetlistObjectsPath> m_selected_paths;
|
||||
std::vector<std::pair<const db::Circuit *, db::DPolygon> > m_markers;
|
||||
std::vector<std::pair<const db::Circuit *, const db::Net *> > m_net_markers;
|
||||
lay::NetInfoDialog *mp_info_dialog;
|
||||
tl::DeferredMethod<NetlistBrowserPage> dm_update_highlights;
|
||||
tl::DeferredMethod<NetlistBrowserPage> dm_rerun_macro;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
source $drc_test_source
|
||||
report_netlist $drc_test_target
|
||||
|
||||
deep
|
||||
|
||||
l1 = input(1, 0)
|
||||
l2 = input(2, 0)
|
||||
l3 = input(3, 0)
|
||||
l4 = input(4, 0)
|
||||
l5 = input(5, 0)
|
||||
|
||||
connect(l1, l2)
|
||||
connect(l2, l3)
|
||||
connect(l3, l4)
|
||||
connect(l4, l5)
|
||||
|
||||
l1.output(1, 0)
|
||||
l2.output(2, 0)
|
||||
l3.output(3, 0)
|
||||
l4.output(4, 0)
|
||||
l5.output(5, 0)
|
||||
|
||||
netlist
|
||||
|
||||
sec = { "l2" => l2, "l3" => l3, "l4" => l4, "l5" => l5 }
|
||||
|
||||
script = <<"END"
|
||||
skip;
|
||||
var ar=area(l5)/area;
|
||||
db.add_log_entry(LogEntryData.new(Severity.Info, net, 'AR='+to_s(ar)))
|
||||
END
|
||||
|
||||
evaluate_nets(l1, sec, script, { "n" => "NET1" })
|
||||
|
||||
netlist
|
||||
|
||||
Binary file not shown.
|
|
@ -0,0 +1,74 @@
|
|||
#%l2n-klayout
|
||||
W(TOP)
|
||||
U(0.001)
|
||||
L(l1 '1/0')
|
||||
L(l2 '2/0')
|
||||
L(l3 '3/0')
|
||||
L(l4 '4/0')
|
||||
L(l5 '5/0')
|
||||
C(l1 l1 l2)
|
||||
C(l2 l1 l2 l3)
|
||||
C(l3 l2 l3 l4)
|
||||
C(l4 l3 l4 l5)
|
||||
C(l5 l4 l5)
|
||||
H(I B('AR=5') C(B) N(NET1))
|
||||
H(I B('AR=0') C(B) N($4))
|
||||
H(I B('AR=9.875') C(TOP) N($1))
|
||||
H(I B('AR=9.5') C(TOP) N($I2))
|
||||
X(A
|
||||
R((0 0) (38000 12000))
|
||||
N(1 I(NET2)
|
||||
R(l1 (0 8000) (4000 4000))
|
||||
R(l2 (-3000 -3000) (2000 2000))
|
||||
R(l3 (-3000 -11000) (4000 12000))
|
||||
R(l4 (-3000 -11000) (2000 2000))
|
||||
R(l5 (-3000 -3000) (38000 4000))
|
||||
R(l5 (-22000 -2000) (0 0))
|
||||
)
|
||||
P(1 I(NET2))
|
||||
)
|
||||
X(B
|
||||
R((-8000 -14000) (48000 34000))
|
||||
N(1 I(NET1)
|
||||
R(l1 (12000 8000) (4000 4000))
|
||||
R(l1 (-10000 -14000) (4000 4000))
|
||||
R(l2 (3000 7000) (2000 2000))
|
||||
R(l2 (-8000 -12000) (2000 2000))
|
||||
R(l3 (3000 -3000) (4000 14000))
|
||||
R(l3 (-10000 -14000) (10000 4000))
|
||||
R(l4 (-3000 -3000) (2000 2000))
|
||||
R(l5 (-3000 -15000) (4000 16000))
|
||||
R(l5 (14000 -16000) (10000 4000))
|
||||
R(l5 (-6000 -2000) (0 0))
|
||||
)
|
||||
N(2 I($2)
|
||||
R(l3 (25000 -5000) (4000 7000))
|
||||
R(l4 (-3000 -3000) (2000 2000))
|
||||
R(l5 (-3000 -3000) (15000 4000))
|
||||
)
|
||||
N(3 I($4)
|
||||
R(l1 (25000 -5000) (4000 18000))
|
||||
)
|
||||
N(4 I($5)
|
||||
R(l3 (25000 6000) (4000 7000))
|
||||
)
|
||||
N(5 I($6)
|
||||
R(l5 (25000 6000) (15000 4000))
|
||||
)
|
||||
N(6 I(NET2)
|
||||
R(l5 (16000 18000) (0 0))
|
||||
)
|
||||
P(6 I(NET2))
|
||||
X(1 A Y(-8000 -14000) P(0 1))
|
||||
X(2 A M Y(-8000 20000) P(0 6))
|
||||
)
|
||||
X(TOP
|
||||
R((-18000 -51000) (58000 108000))
|
||||
N(1 I($1)
|
||||
R(l5 (0 16000) (4000 11000))
|
||||
)
|
||||
N(2 I($I2))
|
||||
X(1 B Y(0 0) P(0 1))
|
||||
X(2 B O(180) Y(22000 43000) P(0 1))
|
||||
X(3 B O(180) Y(22000 -31000) P(0 2))
|
||||
)
|
||||
|
|
@ -35,6 +35,11 @@ class DBLog_TestClass < TestBase
|
|||
|
||||
le = RBA::LogEntryData::new
|
||||
|
||||
le.severity = RBA::LogEntryData::Error
|
||||
assert_equal(le.severity.to_s, "Error")
|
||||
le.severity = RBA::LogEntryData::NoSeverity
|
||||
assert_equal(le.severity.to_s, "NoSeverity")
|
||||
|
||||
le.message = "message"
|
||||
assert_equal(le.message, "message")
|
||||
|
||||
|
|
@ -52,6 +57,44 @@ class DBLog_TestClass < TestBase
|
|||
|
||||
assert_equal(le.to_s, "[the answer] In cell TOP: message, shape: (1,2;1,4;3,4;3,2)")
|
||||
|
||||
le.net_name = "NET"
|
||||
assert_equal(le.net_name, "NET")
|
||||
|
||||
assert_equal(le.to_s, "[the answer] In net NET in circuit TOP: message, shape: (1,2;1,4;3,4;3,2)")
|
||||
|
||||
end
|
||||
|
||||
def test_2_LogConstructors
|
||||
|
||||
le = RBA::LogEntryData::new(RBA::LogEntryData::Error, "a message")
|
||||
assert_equal(le.to_s, "a message")
|
||||
|
||||
assert_equal(le.severity.to_s, "Error")
|
||||
|
||||
le = RBA::LogEntryData::new(RBA::LogEntryData::Info, "CELL", "a message")
|
||||
assert_equal(le.to_s, "In cell CELL: a message")
|
||||
|
||||
assert_equal(le.severity.to_s, "Info")
|
||||
|
||||
le = RBA::LogEntryData::new(RBA::LogEntryData::Warning, "CELL", "NET", "a message")
|
||||
assert_equal(le.to_s, "In net NET in circuit CELL: a message")
|
||||
|
||||
assert_equal(le.severity.to_s, "Warning")
|
||||
|
||||
# Create a LogEntry from a Net object:
|
||||
|
||||
nl = RBA::Netlist::new
|
||||
c = RBA::Circuit::new
|
||||
c.name = "CIRCUIT"
|
||||
nl.add(c)
|
||||
# NOTE: no explicit name, but ID 0
|
||||
net = c.create_net
|
||||
|
||||
le = RBA::LogEntryData::new(RBA::LogEntryData::Error, net, "a message")
|
||||
assert_equal(le.to_s, "In net $0 in circuit CIRCUIT: a message")
|
||||
|
||||
assert_equal(le.severity.to_s, "Error")
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue