Merge branch 'master' into 2.5d-view-devel

This commit is contained in:
Matthias Koefferlein
2020-08-30 23:40:54 +02:00
1156 changed files with 52326 additions and 35239 deletions
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>432</width>
<height>342</height>
<height>349</height>
</rect>
</property>
<property name="windowTitle">
@@ -32,7 +32,7 @@
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Put origin relative to cell's bounding box at ...</string>
<string>Place this cell reference point ...</string>
</property>
</widget>
</item>
@@ -302,6 +302,79 @@
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>... at x:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="x_le"/>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>µm, y:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="y_le"/>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>µm</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="vis_only_cbx">
<property name="text">
@@ -322,7 +395,7 @@
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@@ -403,7 +476,10 @@
<tabstop>lb</tabstop>
<tabstop>cb</tabstop>
<tabstop>rb</tabstop>
<tabstop>x_le</tabstop>
<tabstop>y_le</tabstop>
<tabstop>vis_only_cbx</tabstop>
<tabstop>adjust_calls_cbx</tabstop>
</tabstops>
<resources>
<include location="../../lay/lay/layResources.qrc"/>
+19 -1
View File
@@ -414,9 +414,14 @@ static lay::LayoutView *new_view (QWidget *parent, bool editable, db::Manager *m
}
#endif
static lay::LayoutView *new_view2 (bool editable, db::Manager *manager, unsigned int options)
{
return new lay::LayoutView (manager, editable, 0 /*plugin parent*/, 0 /*parent*/, "view", options);
}
Class<lay::LayoutView> decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "LayoutView",
#if defined(HAVE_QTBINDINGS)
gsi::constructor ("new", &new_view, gsi::arg ("parent", (QWidget *) 0, "nil"), gsi::arg ("editable", false), gsi::arg ("manager", (db::Manager *) 0, "nil"), gsi::arg ("options", (unsigned int) 0),
gsi::constructor ("new", &new_view, gsi::arg ("parent"), gsi::arg ("editable", false), gsi::arg ("manager", (db::Manager *) 0, "nil"), gsi::arg ("options", (unsigned int) 0),
"@brief Creates a standalone view\n"
"\n"
"This constructor is for special purposes only. To create a view in the context of a main window, "
@@ -431,6 +436,19 @@ Class<lay::LayoutView> decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou
"It has been enhanced with the arguments in version 0.27.\n"
) +
#endif
gsi::constructor ("new", &new_view2, gsi::arg ("editable", false), gsi::arg ("manager", (db::Manager *) 0, "nil"), gsi::arg ("options", (unsigned int) 0),
"@brief Creates a standalone view\n"
"\n"
"This constructor is for special purposes only. To create a view in the context of a main window, "
"use \\MainWindow#create_view and related methods.\n"
"\n"
"@param editable True to make the view editable\n"
"@param manager The \\Manager object to enable undo/redo\n"
"@param options A combination of the values in the LV_... constants\n"
"\n"
"This constructor has been introduced in version 0.25.\n"
"It has been enhanced with the arguments in version 0.27.\n"
) +
gsi::constant ("LV_NoLayers", (unsigned int) lay::LayoutView::LV_NoLayers,
"@brief With this option, no layers view will be provided (see \\layer_control_frame)\n"
"Use this value with the constructor's 'options' argument.\n"
+1 -1
View File
@@ -154,7 +154,7 @@ Class<lay::AbstractMenu> decl_AbstractMenu ("lay", "AbstractMenu",
"@param path The path to check\n"
"@return false if the path is not a valid path to an item\n"
) +
method ("insert_item", (void (lay::AbstractMenu::*) (const std::string &, const std::string &, const lay::Action &)) &lay::AbstractMenu::insert_item, gsi::arg ("path"), gsi::arg ("name"), gsi::arg ("action"),
method ("insert_item", (void (lay::AbstractMenu::*) (const std::string &, const std::string &, const lay::Action *)) &lay::AbstractMenu::insert_item, gsi::arg ("path"), gsi::arg ("name"), gsi::arg ("action"),
"@brief Inserts a new item before the one given by the path\n"
"\n"
"The Action object passed as the third parameter references the handler which both implements the "
@@ -0,0 +1,237 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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 "gsiDecl.h"
#include "gsiDeclBasic.h"
#include "gsiSignals.h"
#include "layNetlistBrowserDialog.h"
#include "layLayoutView.h"
namespace tl
{
// disable copy and default constructor for NetlistBrowserDialog
template <> struct type_traits<lay::NetlistBrowserDialog> : public type_traits<void>
{
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
}
namespace gsi
{
static void set_root (lay::NetlistObjectPath *path, db::Circuit *r)
{
path->root = r;
}
static db::Circuit *root (const lay::NetlistObjectPath *path)
{
return const_cast<db::Circuit *> (path->root);
}
static void set_device (lay::NetlistObjectPath *path, db::Device *r)
{
path->device = r;
}
static db::Device *device (const lay::NetlistObjectPath *path)
{
return const_cast<db::Device *> (path->device);
}
static void set_net (lay::NetlistObjectPath *path, db::Net *r)
{
path->net = r;
}
static db::Net *net (const lay::NetlistObjectPath *path)
{
return const_cast<db::Net *> (path->net);
}
static std::vector<db::SubCircuit *> path (const lay::NetlistObjectPath *p)
{
std::vector<db::SubCircuit *> pp;
pp.reserve (p->path.size ());
for (lay::NetlistObjectPath::path_iterator i = p->path.begin (); i != p->path.end (); ++i) {
pp.push_back (const_cast<db::SubCircuit *> (*i));
}
return pp;
}
static void set_path (lay::NetlistObjectPath *p, const std::vector<db::SubCircuit *> &path)
{
p->path = lay::NetlistObjectPath::path_type (path.begin (), path.end ());
}
Class<lay::NetlistObjectPath> decl_NetlistObjectPath ("lay", "NetlistObjectPath",
gsi::method_ext ("root=", &set_root, gsi::arg ("root"),
"@brief Sets the root circuit of the path.\n"
"The root circuit is the circuit from which the path starts.\n"
) +
gsi::method_ext ("root", &root,
"@brief Gets the root circuit of the path.\n"
) +
gsi::method_ext ("path=", &set_path, gsi::arg ("path"),
"@brief Sets the path.\n"
"The path is a list of subcircuits leading from the root to the final object. "
"The final (net, device) object is located in the circuit called by the last subcircuit "
"of the subcircuit chain. If the subcircuit list is empty, the final object is located inside "
"the root object."
) +
gsi::method_ext ("path", &path,
"@brief Gets the path.\n"
) +
gsi::method_ext ("net=", &set_net, gsi::arg ("net"),
"@brief Sets the net the path points to.\n"
"If the path describes the location of a net, this member will indicate it.\n"
"The other way to describe a final object is \\device=. If neither a device nor "
"net is given, the path describes a circuit and how it is referenced from the root."
) +
gsi::method_ext ("net", &net,
"@brief Gets the net the path points to.\n"
) +
gsi::method_ext ("device=", &set_device, gsi::arg ("device"),
"@brief Sets the device the path points to.\n"
"If the path describes the location of a device, this member will indicate it.\n"
"The other way to describe a final object is \\net=. If neither a device nor "
"net is given, the path describes a circuit and how it is referenced from the root."
) +
gsi::method_ext ("device", &device,
"@brief Gets the device the path points to.\n"
) +
gsi::method ("is_null?", &lay::NetlistObjectPath::is_null,
"@brief Returns a value indicating whether the path is an empty one.\n"
),
"@brief An object describing the instantiation of a netlist object.\n"
"This class describes the instantiation of a net or a device or a circuit in terms of "
"a root circuit and a subcircuit chain leading to the indicated object.\n"
"\n"
"See \\net= or \\device= for the indicated object, \\path= for the subcircuit chain.\n"
"\n"
"This class has been introduced in version 0.27.\n"
);
static lay::NetlistObjectPath first (const lay::NetlistObjectsPath *pp)
{
return pp->first ();
}
static lay::NetlistObjectPath second (const lay::NetlistObjectsPath *pp)
{
return pp->second ();
}
Class<lay::NetlistObjectsPath> decl_NetlistObjectsPath ("lay", "NetlistObjectsPath",
gsi::method_ext ("first", &first,
"@brief Gets the first object's path.\n"
"In cases of paired netlists (LVS database), the first path points to the layout netlist object.\n"
"For the single netlist, the first path is the only path supplied."
) +
gsi::method_ext ("second", &second,
"@brief Gets the second object's path.\n"
"In cases of paired netlists (LVS database), the first path points to the schematic netlist object.\n"
"For the single netlist, the scecond path is always a null path."
),
"@brief An object describing the instantiation of a single netlist object or a pair of those.\n"
"This class is basically a pair of netlist object paths (see \\NetlistObjectPath). When derived from a single netlist view, "
"only the first path is valid and will point to the selected object (a net, a device or a circuit). The second path is null.\n"
"\n"
"If the path is derived from a paired netlist view (a LVS report view), the first path corresponds to the object in the layout netlist, "
"the second one to the object in the schematic netlist.\n"
"If the selected object isn't a matched one, either the first or second path may be a null or a partial path without a final net or device object "
"or a partial path.\n"
"\n"
"This class has been introduced in version 0.27.\n"
);
static lay::NetlistObjectPath current_path_first (lay::NetlistBrowserDialog *dialog)
{
return dialog->current_path ().first ();
}
static lay::NetlistObjectPath current_path_second (lay::NetlistBrowserDialog *dialog)
{
return dialog->current_path ().second ();
}
Class<lay::NetlistBrowserDialog> decl_NetlistBrowserDialog ("lay", "NetlistBrowserDialog",
gsi::event ("on_current_db_changed", &lay::NetlistBrowserDialog::current_db_changed_event,
"@brief This event is triggered when the current database is changed.\n"
"The current database can be obtained with \\db."
) +
gsi::event ("on_selection_changed", &lay::NetlistBrowserDialog::selection_changed_event,
"@brief This event is triggered when the selection changed.\n"
"The selection can be obtained with \\current_path_first, \\current_path_second, \\selected_nets, \\selected_devices, \\selected_subcircuits and \\selected_circuits."
) +
gsi::event ("on_probe", &lay::NetlistBrowserDialog::probe_event, gsi::arg ("first_path"), gsi::arg ("second_path"),
"@brief This event is triggered when a net is probed.\n"
"The first path will indicate the location of the probed net in terms of two paths: one describing the instantiation of the "
"net in layout space and one in schematic space. Both objects are \\NetlistObjectPath objects which hold the root circuit, the "
"chain of subcircuits leading to the circuit containing the net and the net itself."
) +
gsi::method ("db", &lay::NetlistBrowserDialog::db,
"@brief Gets the database the browser is connected to.\n"
) +
gsi::method_ext ("current_path_first", &current_path_first,
"@brief Gets the path of the current object on the first (layout in case of LVS database) side.\n"
) +
gsi::method_ext ("current_path_second", &current_path_second,
"@brief Gets the path of the current object on the second (schematic in case of LVS database) side.\n"
) +
gsi::method ("current_path", &lay::NetlistBrowserDialog::current_path,
"@brief Gets the path of the current object as a path pair (combines layout and schematic object paths in case of a LVS database view).\n"
) +
gsi::method ("selected_paths", &lay::NetlistBrowserDialog::selected_paths,
"@brief Gets the nets currently selected objects (paths) in the netlist database browser.\n"
"The result is an array of path pairs. See \\NetlistObjectsPath for details about these pairs."
),
"@brief Represents the netlist browser dialog.\n"
"This dialog is a part of the \\LayoutView class and can be obtained through \\LayoutView#netlist_browser.\n"
"This interface allows to interact with the browser - mainly to get information about state changes.\n"
"\n"
"This class has been introduced in version 0.27.\n"
);
static lay::NetlistBrowserDialog *netlist_browser (lay::LayoutView *lv)
{
return lv->get_plugin<lay::NetlistBrowserDialog> ();
}
// extend lay::LayoutView with the getter for the netlist browser
static
gsi::ClassExt<lay::LayoutView> decl_ext_layout_view (
gsi::method_ext ("netlist_browser", &netlist_browser,
"@brief Gets the netlist browser object for the given layout view\n"
"\n"
"\nThis method has been added in version 0.27.\n"
)
);
}
+3
View File
@@ -1468,6 +1468,9 @@ AbstractMenu::find_item (tl::Extractor &extr)
if (n.empty ()) {
// skip (avoids infinite loops on wrong paths)
while (! extr.at_end () && *extr != ';') {
++extr;
}
} else if (n == "begin") {
@@ -702,7 +702,15 @@ BrowseInstancesForm::fill_cell_instances (const db::ICplxTrans &t, const db::Lay
std::string aref;
if (r > 1 || c > 1) {
aref = tl::sprintf ("[%ld,%ld]", c, r);
aref = "[";
aref += tl::to_string (c);
aref += ",";
aref += tl::to_string (r);
aref += "]";
} else if (parent_inst.size () > 1) {
aref = "(+";
aref += tl::to_string (parent_inst.size () - 1);
aref += "x)";
}
std::string new_path;
+9 -1
View File
@@ -868,7 +868,15 @@ BrowseShapesForm::fill_cell_instances (const db::ICplxTrans &t, const db::Layout
std::string aref;
if (r > 1 || c > 1) {
aref = tl::sprintf ("[%ld,%ld]", c, r);
aref = "[";
aref += tl::to_string (c);
aref += ",";
aref += tl::to_string (r);
aref += "]";
} else if (parent_inst.size () > 1) {
aref = "(+";
aref += tl::to_string (parent_inst.size () - 1);
aref += "x)";
}
std::string new_path;
+29 -9
View File
@@ -900,33 +900,39 @@ AlignCellOptionsDialog::~AlignCellOptionsDialog ()
}
bool
AlignCellOptionsDialog::exec_dialog (int &mode_x, int &mode_y, bool &visible_only, bool &adjust_calls)
AlignCellOptionsDialog::exec_dialog (AlignCellOptions &data)
{
mp_ui->vis_only_cbx->setChecked (visible_only);
mp_ui->adjust_calls_cbx->setChecked (adjust_calls);
mp_ui->vis_only_cbx->setChecked (data.visible_only);
mp_ui->adjust_calls_cbx->setChecked (data.adjust_parents);
QToolButton *buttons[3][3] = { { mp_ui->lb, mp_ui->cb, mp_ui->rb }, { mp_ui->lc, mp_ui->cc, mp_ui->rc }, { mp_ui->lt, mp_ui->ct, mp_ui->rt } };
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
buttons[i][j]->setChecked (j - 1 == mode_x && i - 1 == mode_y);
buttons[i][j]->setChecked (j - 1 == data.mode_x && i - 1 == data.mode_y);
}
}
mp_ui->x_le->setText (tl::to_qstring (tl::micron_to_string (data.xpos)));
mp_ui->y_le->setText (tl::to_qstring (tl::micron_to_string (data.ypos)));
if (QDialog::exec ()) {
visible_only = mp_ui->vis_only_cbx->isChecked ();
adjust_calls = mp_ui->adjust_calls_cbx->isChecked ();
data.visible_only = mp_ui->vis_only_cbx->isChecked ();
data.adjust_parents = mp_ui->adjust_calls_cbx->isChecked ();
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
if (buttons[i][j]->isChecked ()) {
mode_x = j - 1;
mode_y = i - 1;
data.mode_x = j - 1;
data.mode_y = i - 1;
}
}
}
tl::from_string (tl::to_string (mp_ui->x_le->text ()), data.xpos);
tl::from_string (tl::to_string (mp_ui->y_le->text ()), data.ypos);
return true;
} else {
@@ -934,7 +940,21 @@ AlignCellOptionsDialog::exec_dialog (int &mode_x, int &mode_y, bool &visible_onl
}
}
void
void
AlignCellOptionsDialog::accept ()
{
BEGIN_PROTECTED;
double x = 0.0;
tl::from_string (tl::to_string (mp_ui->x_le->text ()), x);
tl::from_string (tl::to_string (mp_ui->y_le->text ()), x);
QDialog::accept ();
END_PROTECTED;
}
void
AlignCellOptionsDialog::button_clicked ()
{
QToolButton *buttons[3][3] = { { mp_ui->lb, mp_ui->cb, mp_ui->rb }, { mp_ui->lc, mp_ui->cc, mp_ui->rc }, { mp_ui->lt, mp_ui->ct, mp_ui->rt } };
+17 -1
View File
@@ -363,6 +363,21 @@ private:
lay::LayoutView *mp_view;
};
/**
* @brief A data structure holding the options for the "align cell" dialog
*/
struct LAYBASIC_PUBLIC AlignCellOptions
{
AlignCellOptions ()
: mode_x (-1), mode_y (-1), xpos (0.0), ypos (0.0), visible_only (false), adjust_parents (true)
{ }
int mode_x, mode_y;
double xpos, ypos;
bool visible_only;
bool adjust_parents;
};
/**
* @brief The merge operation options
*/
@@ -375,10 +390,11 @@ public:
AlignCellOptionsDialog (QWidget *parent);
virtual ~AlignCellOptionsDialog ();
bool exec_dialog (int &mode_x, int &mode_y, bool &visible_only, bool &adjust_calls);
bool exec_dialog (AlignCellOptions &data);
private slots:
void button_clicked ();
void accept ();
private:
Ui::AlignCellOptionsDialog *mp_ui;
+1 -1
View File
@@ -209,7 +209,7 @@ public:
std::vector<std::string> to_strings () const;
private:
uint32_t *(m_pattern[64]);
uint32_t *m_pattern[64];
uint32_t m_buffer [64 * 32];
unsigned int m_width, m_height;
unsigned int m_pattern_stride;
@@ -213,6 +213,7 @@ HierarchyControlPanel::HierarchyControlPanel (lay::LayoutView *view, QWidget *pa
mp_selector = new QComboBox (this);
mp_selector->setObjectName (QString::fromUtf8 ("cellview_selection"));
mp_selector->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Fixed);
ly->addWidget (mp_selector);
mp_search_frame = new QFrame (this);
+45 -11
View File
@@ -236,67 +236,73 @@ SingleIndexedNetlistModel::top_circuit_count () const
size_t
SingleIndexedNetlistModel::net_count (const circuit_pair &circuits) const
{
return circuits.first->net_count ();
return circuits.first ? circuits.first->net_count () : 0;
}
size_t
SingleIndexedNetlistModel::net_terminal_count (const net_pair &nets) const
{
return nets.first->terminal_count ();
return nets.first ? nets.first->terminal_count () : 0;
}
size_t
SingleIndexedNetlistModel::net_subcircuit_pin_count (const net_pair &nets) const
{
return nets.first->subcircuit_pin_count ();
return nets.first ? nets.first->subcircuit_pin_count () : 0;
}
size_t
SingleIndexedNetlistModel::net_pin_count (const net_pair &nets) const
{
return nets.first->pin_count ();
return nets.first ? nets.first->pin_count () : 0;
}
size_t
SingleIndexedNetlistModel::device_count (const circuit_pair &circuits) const
{
return circuits.first->device_count ();
return circuits.first ? circuits.first->device_count () : 0;
}
size_t
SingleIndexedNetlistModel::subcircuit_pin_count (const subcircuit_pair &subcircuits) const
{
return subcircuits.first ? subcircuits.first->circuit_ref ()->pin_count () : 0;
}
size_t
SingleIndexedNetlistModel::pin_count (const circuit_pair &circuits) const
{
return circuits.first->pin_count ();
return circuits.first ? circuits.first->pin_count () : 0;
}
size_t
SingleIndexedNetlistModel::subcircuit_count (const circuit_pair &circuits) const
{
return circuits.first->subcircuit_count ();
return circuits.first ? circuits.first->subcircuit_count () : 0;
}
size_t
SingleIndexedNetlistModel::child_circuit_count (const circuit_pair &circuits) const
{
return circuits.first->end_children () - circuits.first->begin_children ();
return circuits.first ? (circuits.first->end_children () - circuits.first->begin_children ()) : 0;
}
IndexedNetlistModel::circuit_pair
SingleIndexedNetlistModel::parent_of (const net_pair &nets) const
{
return std::make_pair (nets.first->circuit (), (const db::Circuit *) 0);
return std::make_pair (nets.first ? nets.first->circuit () : 0, (const db::Circuit *) 0);
}
IndexedNetlistModel::circuit_pair
SingleIndexedNetlistModel::parent_of (const device_pair &devices) const
{
return std::make_pair (devices.first->circuit (), (const db::Circuit *) 0);
return std::make_pair (devices.first ? devices.first->circuit () : 0, (const db::Circuit *) 0);
}
IndexedNetlistModel::circuit_pair
SingleIndexedNetlistModel::parent_of (const subcircuit_pair &subcircuits) const
{
return std::make_pair (subcircuits.first->circuit (), (const db::Circuit *) 0);
return std::make_pair (subcircuits.first ? subcircuits.first->circuit () : 0, (const db::Circuit *) 0);
}
std::pair<IndexedNetlistModel::circuit_pair, IndexedNetlistModel::Status>
@@ -346,6 +352,34 @@ SingleIndexedNetlistModel::net_subcircuit_pinref_from_index (const net_pair &net
return attr_by_object_and_index (nets, index, nets.first->begin_subcircuit_pins (), nets.first->end_subcircuit_pins (), none, none, m_subcircuit_pinref_by_net_and_index, sort_by_pin_name<db::NetSubcircuitPinRef> ());
}
IndexedNetlistModel::net_subcircuit_pin_pair
SingleIndexedNetlistModel::subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const
{
if (! subcircuits.first) {
return IndexedNetlistModel::net_subcircuit_pin_pair ((const db::NetSubcircuitPinRef *) 0, (const db::NetSubcircuitPinRef *) 0);
}
std::map<subcircuit_pair, std::vector<net_subcircuit_pin_pair> >::iterator i = m_subcircuit_pins_by_index.find (subcircuits);
if (i == m_subcircuit_pins_by_index.end ()) {
i = m_subcircuit_pins_by_index.insert (std::make_pair (subcircuits, std::vector<net_subcircuit_pin_pair> ())).first;
std::vector<net_subcircuit_pin_pair> &refs = i->second;
const db::Circuit *circuit = subcircuits.first->circuit_ref ();
for (db::Circuit::const_pin_iterator p = circuit->begin_pins (); p != circuit->end_pins (); ++p) {
const db::NetSubcircuitPinRef *ref = subcircuits.first->netref_for_pin (p->id ());
if (! ref) {
m_synthetic_pinrefs.push_back (db::NetSubcircuitPinRef (const_cast<db::SubCircuit *> (subcircuits.first), p->id ()));
ref = & m_synthetic_pinrefs.back ();
}
refs.push_back (net_subcircuit_pin_pair (ref, (const db::NetSubcircuitPinRef *) 0));
}
}
return index < i->second.size () ? i->second [index] : IndexedNetlistModel::net_subcircuit_pin_pair ((const db::NetSubcircuitPinRef *) 0, (const db::NetSubcircuitPinRef *) 0);
}
IndexedNetlistModel::net_terminal_pair
SingleIndexedNetlistModel::net_terminalref_from_index (const net_pair &nets, size_t index) const
{
@@ -80,6 +80,7 @@ public:
virtual size_t net_subcircuit_pin_count (const net_pair &nets) const = 0;
virtual size_t net_pin_count (const net_pair &nets) const = 0;
virtual size_t device_count (const circuit_pair &circuits) const = 0;
virtual size_t subcircuit_pin_count (const subcircuit_pair &subcircuits) const = 0;
virtual size_t pin_count (const circuit_pair &circuits) const = 0;
virtual size_t subcircuit_count (const circuit_pair &circuits) const = 0;
virtual size_t child_circuit_count (const circuit_pair &circuits) const = 0;
@@ -95,6 +96,7 @@ public:
virtual const db::Net *second_net_for (const db::Net *first) const = 0;
virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const = 0;
virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const = 0;
virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const = 0;
virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const = 0;
virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const = 0;
virtual std::pair<device_pair, Status> device_from_index (const circuit_pair &circuits, size_t index) const = 0;
@@ -149,6 +151,7 @@ public:
virtual size_t net_pin_count (const net_pair &nets) const;
virtual size_t device_count (const circuit_pair &circuits) const;
virtual size_t pin_count (const circuit_pair &circuits) const;
virtual size_t subcircuit_pin_count (const subcircuit_pair &subcircuits) const;
virtual size_t subcircuit_count (const circuit_pair &circuits) const;
virtual size_t child_circuit_count (const circuit_pair &circuits) const;
@@ -163,6 +166,7 @@ public:
virtual const db::Net *second_net_for (const db::Net *first) const;
virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const;
virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const;
virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const;
virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const;
virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const;
virtual std::pair<device_pair, Status> device_from_index (const circuit_pair &circuits, size_t index) const;
@@ -194,6 +198,8 @@ private:
mutable std::map<pin_pair, size_t> m_pin_index_by_object;
mutable std::map<subcircuit_pair, size_t> m_subcircuit_index_by_object;
mutable std::map<device_pair, size_t> m_device_index_by_object;
mutable std::map<subcircuit_pair, std::vector<net_subcircuit_pin_pair> > m_subcircuit_pins_by_index;
mutable std::list<db::NetSubcircuitPinRef> m_synthetic_pinrefs;
};
}
+12 -13
View File
@@ -51,7 +51,6 @@
#include "layConverters.h"
#include "layGridNet.h"
#include "layMove.h"
#include "layDialogs.h"
#include "layZoomBox.h"
#include "layMouseTracker.h"
#include "layTipDialog.h"
@@ -463,10 +462,6 @@ LayoutView::init (db::Manager *mgr, QWidget * /*parent*/)
m_sel_inside_pcells = false;
m_move_to_origin_mode_x = 0;
m_move_to_origin_mode_y = 0;
m_align_cell_origin_mode_x = -1;
m_align_cell_origin_mode_y = -1;
m_align_cell_origin_visible_layers = false;
m_align_cell_adjust_parents = true;
m_del_cell_mode = 0;
m_layer_hier_mode = 0;
m_add_other_layers = false;
@@ -1675,7 +1670,6 @@ LayoutView::enable_edits (bool enable)
if (m_disabled_edits > 0) {
--m_disabled_edits;
}
enable = (m_disabled_edits == 0);
} else {
++m_disabled_edits;
}
@@ -4740,6 +4734,10 @@ LayoutView::active_library_changed (int /*index*/)
void
LayoutView::cellview_changed (unsigned int index)
{
if (mp_hierarchy_panel) {
mp_hierarchy_panel->do_update_content (index);
}
cellview_changed_event (index);
if (m_title.empty ()) {
@@ -5289,7 +5287,7 @@ LayoutView::cm_align_cell_origin ()
}
lay::AlignCellOptionsDialog dialog (this);
if (dialog.exec_dialog (m_align_cell_origin_mode_x, m_align_cell_origin_mode_y, m_align_cell_origin_visible_layers, m_align_cell_adjust_parents)) {
if (dialog.exec_dialog (m_align_cell_options)) {
clear_selection ();
@@ -5297,7 +5295,7 @@ LayoutView::cm_align_cell_origin ()
db::Box bbox;
if (m_align_cell_origin_visible_layers) {
if (m_align_cell_options.visible_only) {
for (lay::LayerPropertiesConstIterator l = begin_layers (); !l.at_end (); ++l) {
if (! l->has_children () && l->layer_index () >= 0 && l->cellview_index () == cv_index && l->visible (true /*real*/)) {
bbox += cell->bbox (l->layer_index ());
@@ -5308,7 +5306,7 @@ LayoutView::cm_align_cell_origin ()
}
db::Coord refx, refy;
switch (m_align_cell_origin_mode_x) {
switch (m_align_cell_options.mode_x) {
case -1:
refx = bbox.left ();
break;
@@ -5319,7 +5317,7 @@ LayoutView::cm_align_cell_origin ()
refx = bbox.center ().x ();
break;
}
switch (m_align_cell_origin_mode_y) {
switch (m_align_cell_options.mode_y) {
case -1:
refy = bbox.bottom ();
break;
@@ -5331,10 +5329,11 @@ LayoutView::cm_align_cell_origin ()
break;
}
db::Trans t (db::Vector (-refx, -refy));
db::Layout &layout = cellview (cv_index)->layout ();
db::Cell &nc_cell = layout.cell (cell->cell_index ());
db::Trans t (db::Vector (-refx + db::coord_traits<db::Coord>::rounded (m_align_cell_options.xpos / layout.dbu ()), -refy + db::coord_traits<db::Coord>::rounded (m_align_cell_options.ypos / layout.dbu ())));
for (unsigned int i = 0; i < layout.layers (); ++i) {
if (layout.is_valid_layer (i)) {
db::Shapes &shapes = nc_cell.shapes (i);
@@ -5348,7 +5347,7 @@ LayoutView::cm_align_cell_origin ()
nc_cell.transform (*inst, t);
}
if (m_align_cell_adjust_parents) {
if (m_align_cell_options.adjust_parents) {
std::vector<std::pair<db::Cell *, db::Instance> > insts_to_modify;
for (db::Cell::parent_inst_iterator pi = nc_cell.begin_parent_insts (); ! pi.at_end (); ++pi) {
@@ -6815,7 +6814,7 @@ LayoutView::menu_activated (const std::string &symbol)
}
} else if (symbol == "cm_delete_layer") {
if (active_cellview_index () >= 0) {
cm_edit_layer ();
cm_delete_layer ();
}
} else if (symbol == "cm_clear_layer") {
if (active_cellview_index () >= 0) {
+2 -3
View File
@@ -50,6 +50,7 @@
#include "layPlugin.h"
#include "layDisplayState.h"
#include "layBookmarkList.h"
#include "layDialogs.h"
#include "gsi.h"
#include "tlException.h"
#include "tlEvents.h"
@@ -2871,9 +2872,7 @@ private:
db::LayerProperties m_new_layer_props;
db::DVector m_move_dist;
int m_move_to_origin_mode_x, m_move_to_origin_mode_y;
int m_align_cell_origin_mode_x, m_align_cell_origin_mode_y;
bool m_align_cell_origin_visible_layers;
bool m_align_cell_adjust_parents;
lay::AlignCellOptions m_align_cell_options;
int m_del_cell_mode;
int m_layer_hier_mode;
int m_duplicate_hier_mode;
@@ -1131,11 +1131,10 @@ LayoutViewConfigPage6::stipple_button_clicked ()
if (m_palette.stipples () > i) {
unsigned int s = m_palette.stipple_by_index (i);
SelectStippleForm stipples_form (0, m_pattern);
if (stipples_form.exec () && stipples_form.selected () >= 0) {
s = stipples_form.selected ();
unsigned int s = stipples_form.selected ();
m_manager.transaction (tl::to_string (QObject::tr ("Set stipple")));
m_manager.queue (this, new StipplePaletteOp (m_palette, false, true /*before*/));
@@ -1350,11 +1349,10 @@ LayoutViewConfigPage6a::line_style_button_clicked ()
if (m_palette.styles () > i) {
unsigned int s = m_palette.style_by_index (i);
SelectLineStyleForm styles_form (0, m_style);
if (styles_form.exec () && styles_form.selected () >= 0) {
s = styles_form.selected ();
unsigned int s = styles_form.selected ();
m_manager.transaction (tl::to_string (QObject::tr ("Set style")));
m_manager.queue (this, new LineStylePaletteOp (m_palette, true /*before*/));
+5 -3
View File
@@ -210,7 +210,8 @@ LibrariesView::LibrariesView (lay::LayoutView *view, QWidget *parent, const char
ly->setContentsMargins (0, 0, 0, 0);
mp_selector = new QComboBox (this);
mp_selector->setObjectName (QString::fromUtf8 ("cellview_selection"));
mp_selector->setObjectName (QString::fromUtf8 ("library_selection"));
mp_selector->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Fixed);
ly->addWidget (mp_selector);
mp_search_frame = new QFrame (this);
@@ -771,9 +772,10 @@ LibrariesView::display_string (int n) const
if (! lib->get_description ().empty ()) {
text += " - " + lib->get_description ();
}
if (! lib->get_technology ().empty ()) {
if (lib->for_technologies ()) {
text += " ";
text += tl::to_string (QObject::tr ("[Technology %1]").arg (tl::to_qstring (lib->get_technology ())));
std::string tn = tl::join (std::vector<std::string> (lib->get_technologies ().begin (), lib->get_technologies ().end ()), ",");
text += tl::to_string (QObject::tr ("[Technology %1]").arg (tl::to_qstring (tn)));
}
return text;
}
+7 -3
View File
@@ -87,7 +87,7 @@ size_t count_shapes (db::LayoutToNetlist *l2ndb, db::Net *net, unsigned int laye
size_t cluster_id = net->cluster_id ();
size_t n = 0;
for (db::recursive_cluster_shape_iterator<db::PolygonRef> shapes (l2ndb->net_clusters (), layer, cell_index, cluster_id); ! shapes.at_end (); ++shapes) {
for (db::recursive_cluster_shape_iterator<db::NetShape> shapes (l2ndb->net_clusters (), layer, cell_index, cluster_id); ! shapes.at_end (); ++shapes) {
++n;
}
return n;
@@ -278,7 +278,11 @@ void NetInfoDialog::update_info_text ()
std::string l = layer_string (mp_l2ndb.get (), *layer);
for (db::recursive_cluster_shape_iterator<db::PolygonRef> si (mp_l2ndb->net_clusters (), *layer, cell_index, cluster_id); ! si.at_end (); ++si) {
for (db::recursive_cluster_shape_iterator<db::NetShape> si (mp_l2ndb->net_clusters (), *layer, cell_index, cluster_id); ! si.at_end (); ++si) {
if (si->type () != db::NetShape::Polygon) {
continue;
}
if (tot_shapes++ >= max_shapes) {
incomplete = true;
@@ -295,7 +299,7 @@ void NetInfoDialog::update_info_text ()
statinfo_area.insert (std::make_pair (*layer, db::coord_traits<db::Coord>::area_type (0)));
}
s->second.push_back (si->instantiate ());
s->second.push_back (si->polygon_ref ().instantiate ());
std::string c (ly->cell_name (si.cell_index ()));
c += " (with ";
@@ -120,6 +120,8 @@ NetlistBrowserDialog::NetlistBrowserDialog (lay::Dispatcher *root, lay::LayoutVi
connect (sticky_cbx, SIGNAL (clicked ()), this, SLOT (sticky_mode_clicked ()));
cellviews_changed ();
browser_page->selection_changed_event.add (this, &NetlistBrowserDialog::selection_changed);
}
NetlistBrowserDialog::~NetlistBrowserDialog ()
@@ -127,6 +129,34 @@ NetlistBrowserDialog::~NetlistBrowserDialog ()
tl::Object::detach_from_all_events ();
}
db::LayoutToNetlist *
NetlistBrowserDialog::db ()
{
return browser_page->db ();
}
const lay::NetlistObjectsPath &
NetlistBrowserDialog::current_path () const
{
if (browser_page) {
return browser_page->current_path ();
} else {
static lay::NetlistObjectsPath empty;
return empty;
}
}
const std::vector<lay::NetlistObjectsPath> &
NetlistBrowserDialog::selected_paths () const
{
if (browser_page) {
return browser_page->selected_paths ();
} else {
static std::vector<lay::NetlistObjectsPath> empty;
return empty;
}
}
void
NetlistBrowserDialog::configure_clicked ()
{
@@ -254,40 +284,60 @@ NetlistBrowserDialog::probe_net (const db::DPoint &p, bool trace_path)
}
const db::Net *net = 0;
db::Net *net = 0;
db::Circuit *root = 0;
std::vector<db::SubCircuit *> sc_path;
db::LayoutToNetlist *l2ndb = view ()->get_l2ndb (m_l2n_index);
if (l2ndb) {
// determines the corresponding layer inside the database and probe the net from this region and the
// start point.
root = l2ndb->netlist ()->circuit_by_name (cv->layout ().cell_name (cv.cell_index ()));
if (root) {
std::vector<db::Region *> regions;
// determines the corresponding layer inside the database and probe the net from this region and the
// start point.
const db::Connectivity &conn = l2ndb->connectivity ();
for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
db::LayerProperties lp = l2ndb->internal_layout ()->get_properties (*layer);
if (! lp.is_null ()) {
db::Region *region = l2ndb->layer_by_index (*layer);
if (lp == cv->layout ().get_properties (start_layer)) {
// a matching original layer is looked up with higher prio
regions.insert (regions.begin (), region);
} else {
regions.push_back (region);
std::vector<db::Region *> regions;
const db::Connectivity &conn = l2ndb->connectivity ();
for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
db::LayerProperties lp = l2ndb->internal_layout ()->get_properties (*layer);
if (! lp.is_null ()) {
db::Region *region = l2ndb->layer_by_index (*layer);
if (lp == cv->layout ().get_properties (start_layer)) {
// a matching original layer is looked up with higher prio
regions.insert (regions.begin (), region);
} else {
regions.push_back (region);
}
}
}
}
// probe the net
// probe the net
for (std::vector<db::Region *>::const_iterator r = regions.begin (); r != regions.end () && !net; ++r) {
sc_path.clear ();
net = l2ndb->probe_net (**r, start_point, &sc_path, root);
}
for (std::vector<db::Region *>::const_iterator r = regions.begin (); r != regions.end () && !net; ++r) {
net = l2ndb->probe_net (**r, start_point);
}
}
// select the net if one was found
browser_page->select_net (net);
lay::NetlistObjectPath path;
if (net) {
path.root = root;
path.net = net;
path.path = lay::NetlistObjectPath::path_type (sc_path.begin (), sc_path.end ());
}
browser_page->select_path (path);
// emits the probe event
// NOTE: browser_page->current_path () will hold the paired path with the schematic side being
// expanded.
probe_event (browser_page->current_path ().first (), browser_page->current_path ().second ());
}
void
@@ -421,9 +471,15 @@ BEGIN_PROTECTED
tl::log << tl::to_string (QObject::tr ("Loading file: ")) << l2ndb->filename ();
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Loading")));
browser_page->set_l2ndb (0);
l2ndb->load (l2ndb->filename ());
browser_page->set_l2ndb (l2ndb);
browser_page->set_db (0);
try {
l2ndb->load (l2ndb->filename ());
browser_page->set_db (l2ndb);
current_db_changed_event ();
} catch (...) {
current_db_changed_event ();
throw;
}
}
@@ -707,6 +763,8 @@ NetlistBrowserDialog::update_content ()
central_stack->setCurrentIndex (1);
}
bool db_changed = false;
m_saveas_action->setEnabled (l2ndb != 0);
m_export_action->setEnabled (l2ndb != 0);
m_unload_action->setEnabled (l2ndb != 0);
@@ -714,7 +772,10 @@ NetlistBrowserDialog::update_content ()
m_reload_action->setEnabled (l2ndb != 0);
browser_page->enable_updates (false); // Avoid building the internal lists several times ...
browser_page->set_l2ndb (l2ndb);
if (browser_page->db () != l2ndb) {
db_changed = true;
browser_page->set_db (l2ndb);
}
browser_page->set_max_shape_count (m_max_shape_count);
browser_page->set_highlight_style (m_marker_color, m_marker_line_width, m_marker_vertex_size, m_marker_halo, m_marker_dither_pattern, m_marker_intensity, m_use_original_colors, m_auto_color_enabled ? &m_auto_colors : 0);
browser_page->set_window (m_window, m_window_dim);
@@ -740,6 +801,10 @@ NetlistBrowserDialog::update_content ()
if (l2ndb_cb->currentIndex () != m_l2n_index) {
l2ndb_cb->setCurrentIndex (m_l2n_index);
}
if (db_changed) {
current_db_changed_event ();
}
}
void
@@ -751,8 +816,16 @@ NetlistBrowserDialog::deactivated ()
lay::Dispatcher::instance ()->config_set (cfg_l2ndb_window_state, lay::save_dialog_state (this, false /*don't store the section sizes*/).c_str ());
}
browser_page->set_l2ndb (0);
bool db_changed = false;
if (browser_page->db () != 0) {
db_changed = true;
browser_page->set_db (0);
}
browser_page->set_view (0, 0);
if (db_changed) {
current_db_changed_event ();
}
}
void
@@ -29,6 +29,7 @@
#include "layNetlistBrowser.h"
#include "layViewObject.h"
#include "layColorPalette.h"
#include "tlEvents.h"
namespace lay
{
@@ -46,6 +47,38 @@ public:
void load (int lay_index, int cv_index);
/**
* @brief This event is emitted after the current database changed
*/
tl::Event current_db_changed_event;
/**
* @brief This event is emitted when a shape is probed
* The first path is that of the layout, the second that of the schematic in case of a
* LVS database.
*/
tl::event<lay::NetlistObjectPath, lay::NetlistObjectPath> probe_event;
/**
* @brief Gets the current database
*/
db::LayoutToNetlist *db ();
/**
* @brief Gets the current object's path
*/
const lay::NetlistObjectsPath &current_path () const;
/**
* @brief Gets the selected nets
*/
const std::vector<lay::NetlistObjectsPath> &selected_paths () const;
/**
* @brief An event indicating that the selection has changed
*/
tl::Event selection_changed_event;
private:
// implementation of the lay::Browser interface
virtual void activated ();
@@ -64,6 +97,11 @@ private:
void cellview_changed (int index);
void l2ndbs_changed ();
void selection_changed ()
{
selection_changed_event ();
}
public slots:
void cv_index_changed (int);
void l2ndb_index_changed (int);
File diff suppressed because it is too large Load Diff
+222 -71
View File
@@ -30,6 +30,9 @@
#include "dbLayoutToNetlist.h"
#include "dbLayoutVsSchematic.h"
#include "tlList.h"
#include "tlTypeTraits.h"
#include <QAbstractItemModel>
#include <QColor>
@@ -88,6 +91,167 @@ private:
// ----------------------------------------------------------------------------------
// NetlistBrowserModel definition
class NetlistBrowserModel;
class NetlistModelItemData;
class RootItemData;
class CircuitItemData;
class CircuitNetItemData;
class CircuitDeviceItemData;
class CircuitSubCircuitItemData;
}
namespace tl {
// disable copying for NetlistModelItemData
template<> struct type_traits<lay::NetlistModelItemData>
{
typedef false_tag has_copy_constructor;
};
}
namespace lay
{
/**
* @brief A base class for the item data object
*/
class NetlistModelItemData
: public tl::list_node<NetlistModelItemData>
{
public:
typedef tl::list<NetlistModelItemData>::iterator iterator;
NetlistModelItemData ();
NetlistModelItemData (NetlistModelItemData *parent);
virtual ~NetlistModelItemData ();
virtual NetlistModelItemData *parent () { return mp_parent; }
virtual QIcon icon (NetlistBrowserModel *model) = 0;
virtual QString text (int column, NetlistBrowserModel *model) = 0;
virtual QString search_text () = 0;
virtual std::string tooltip (NetlistBrowserModel *model) = 0;
virtual db::NetlistCrossReference::Status status (NetlistBrowserModel *model) = 0;
void ensure_children (NetlistBrowserModel *model);
void push_back (NetlistModelItemData *child);
iterator begin () { return m_children.begin (); }
iterator end () { return m_children.end (); }
size_t child_count () { return m_children_per_index.size (); }
size_t index () { return m_index; }
NetlistModelItemData *child (size_t n);
virtual std::pair<const db::Circuit *, const db::Circuit *> circuits_of_this ();
std::pair<const db::Circuit *, const db::Circuit *> circuits ();
bool derived_from_circuits (const std::pair<const db::Circuit *, const db::Circuit *> &sp);
virtual std::pair<const db::Device *, const db::Device *> devices_of_this ();
std::pair<const db::Device *, const db::Device *> devices ();
bool derived_from_devices (const std::pair<const db::Device *, const db::Device *> &sp);
virtual std::pair<const db::Pin *, const db::Pin *> pins_of_this ();
std::pair<const db::Pin *, const db::Pin *> pins ();
bool derived_from_pins (const std::pair<const db::Pin *, const db::Pin *> &sp);
virtual std::pair<const db::SubCircuit *, const db::SubCircuit *> subcircuits_of_this ();
std::pair<const db::SubCircuit *, const db::SubCircuit *> subcircuits ();
bool derived_from_subcircuits (const std::pair<const db::SubCircuit *, const db::SubCircuit *> &sp);
virtual std::pair<const db::Net *, const db::Net *> nets_of_this ();
std::pair<const db::Net *, const db::Net *> nets ();
bool derived_from_nets (const std::pair<const db::Net *, const db::Net *> &np);
private:
NetlistModelItemData *mp_parent;
tl::list<NetlistModelItemData> m_children;
std::vector<NetlistModelItemData *> m_children_per_index;
bool m_children_made;
size_t m_index;
void set_index (size_t index) { m_index = index; }
virtual void do_ensure_children (NetlistBrowserModel *model) = 0;
};
/**
* @brief An object describing the instantiation path of a net, a device or a (sub)circuit pair
*
* This object applies to pairs of these objects. A class providing a path for a single
* object is NetlistObjectPath
*/
struct LAYBASIC_PUBLIC NetlistObjectPath
{
typedef std::list<const db::SubCircuit *> path_type;
typedef path_type::const_iterator path_iterator;
NetlistObjectPath () : root (0), net (0), device (0) { }
bool is_null () const
{
return ! root;
}
bool operator== (const NetlistObjectPath &other) const
{
return root == other.root && path == other.path && net == other.net && device == other.device;
}
bool operator!= (const NetlistObjectPath &other) const
{
return ! operator== (other);
}
const db::Circuit *root;
std::list<const db::SubCircuit *> path;
const db::Net *net;
const db::Device *device;
};
/**
* @brief An object describing the instantiation path of a net, a device or a (sub)circuit pair
*
* This object applies to pairs of these objects. A class providing a path for a single
* object is NetlistObjectPath
*/
struct LAYBASIC_PUBLIC NetlistObjectsPath
{
typedef std::list<std::pair<const db::SubCircuit *, const db::SubCircuit *> > path_type;
typedef path_type::const_iterator path_iterator;
NetlistObjectsPath () { }
bool is_null () const
{
return ! root.first && ! root.second;
}
static NetlistObjectsPath from_first(const NetlistObjectPath &p);
static NetlistObjectsPath from_second (const NetlistObjectPath &p);
NetlistObjectPath first () const;
NetlistObjectPath second () const;
bool operator== (const NetlistObjectsPath &other) const
{
return root == other.root && path == other.path && net == other.net && device == other.device;
}
bool operator!= (const NetlistObjectsPath &other) const
{
return ! operator== (other);
}
std::pair<const db::Circuit *, const db::Circuit *> root;
std::list<std::pair<const db::SubCircuit *, const db::SubCircuit *> > path;
std::pair<const db::Net *, const db::Net *> net;
std::pair<const db::Device *, const db::Device *> device;
};
/**
* @brief The NetlistBrowserModel
*
@@ -125,31 +289,70 @@ public:
virtual QModelIndex parent (const QModelIndex &index) const;
virtual int rowCount (const QModelIndex &parent) const;
QModelIndex index_from_id (void *id, int column) const;
int status_column () const
{
return m_status_column;
}
std::pair<const db::Net *, const db::Net *> net_from_index (const QModelIndex &index) const;
QModelIndex index_from_net (const std::pair<const db::Net *, const db::Net *> &net) const;
QModelIndex index_from_net (const db::Net *net) const;
std::pair<const db::Circuit *, const db::Circuit *> circuit_from_index (const QModelIndex &index) const;
QModelIndex index_from_circuit (const std::pair<const db::Circuit *, const db::Circuit *> &circuit) const;
QModelIndex index_from_circuit (const db::Circuit *circuit) const;
std::pair<const db::SubCircuit *, const db::SubCircuit *> subcircuit_from_index (const QModelIndex &index) const;
std::pair<const db::Device *, const db::Device *> device_from_index (const QModelIndex &index) const;
bool is_circuit_index (const QModelIndex &index) const
int object_column () const
{
return is_id_circuit (index.internalPointer ());
return m_object_column;
}
int first_column () const
{
return m_first_column;
}
int second_column () const
{
return m_second_column;
}
IndexedNetlistModel *indexer ()
{
return mp_indexer.get ();
}
std::pair<const db::Net *, const db::Net *> net_from_index (const QModelIndex &index, bool include_parents = true) const;
QModelIndex index_from_net (const std::pair<const db::Net *, const db::Net *> &net) const;
QModelIndex index_from_net (const db::Net *net) const;
std::pair<const db::Circuit *, const db::Circuit *> circuit_from_index (const QModelIndex &index, bool include_parents = true) const;
QModelIndex index_from_circuit (const std::pair<const db::Circuit *, const db::Circuit *> &circuit) const;
QModelIndex index_from_circuit (const db::Circuit *circuit) const;
QModelIndex index_from_subcircuit (const std::pair<const db::SubCircuit *, const db::SubCircuit *> &subcircuits) const;
std::pair<const db::SubCircuit *, const db::SubCircuit *> subcircuit_from_index (const QModelIndex &index, bool include_parents = true) const;
std::pair<const db::Device *, const db::Device *> device_from_index (const QModelIndex &index, bool include_parents = true) const;
void set_item_visibility (QTreeView *view, bool show_all, bool with_warnings);
QString make_link_to (const std::pair<const db::Net *, const db::Net *> &nets, int column = 0) const;
QString make_link_to (const std::pair<const db::Device *, const db::Device *> &devices, int column = 0) const;
QString make_link_to (const std::pair<const db::Pin *, const db::Pin *> &pins, const std::pair<const db::Circuit *, const db::Circuit *> &circuits, int column = 0) const;
QString make_link_to (const std::pair<const db::Circuit *, const db::Circuit *> &circuits, int column = 0) const;
QString make_link_to (const std::pair<const db::SubCircuit *, const db::SubCircuit *> &sub_circuits, int column = 0) const;
bool is_valid_net_pair (const std::pair<const db::Net *, const db::Net *> &net) const;
QIcon icon_for_nets (const std::pair<const db::Net *, const db::Net *> &net) const;
QIcon icon_for_connection (const std::pair<const db::Net *, const db::Net *> &net) const;
QModelIndex index_from_url (const QString &url) const;
NetlistObjectsPath path_from_index (const QModelIndex &index) const;
NetlistObjectPath spath_from_index (const QModelIndex &index) const
{
return path_from_index (index).first ();
}
QModelIndex index_from_path (const NetlistObjectsPath &path);
QModelIndex index_from_path (const NetlistObjectPath &path)
{
return index_from_path (NetlistObjectsPath::from_first (path));
}
private slots:
void colors_changed ();
@@ -157,73 +360,18 @@ private:
NetlistBrowserModel (const NetlistBrowserModel &);
NetlistBrowserModel &operator= (const NetlistBrowserModel &);
void *make_id_circuit (size_t circuit_index) const;
void *make_id_circuit_pin (size_t circuit_index, size_t pin_index) const;
void *make_id_circuit_pin_net (size_t circuit_index, size_t pin_index, size_t net_index) const;
void *make_id_circuit_net (size_t circuit_index, size_t net_index) const;
void *make_id_circuit_net_device_terminal (size_t circuit_index, size_t net_index, size_t terminal_ref_index) const;
void *make_id_circuit_net_device_terminal_others (size_t circuit_index, size_t net_index, size_t terminal_ref_index, size_t other_index) const;
void *make_id_circuit_net_pin (size_t circuit_index, size_t net_index, size_t pin_index) const;
void *make_id_circuit_net_subcircuit_pin (size_t circuit_index, size_t net_index, size_t pin_ref_index) const;
void *make_id_circuit_net_subcircuit_pin_others (size_t circuit_index, size_t net_index, size_t pin_ref_index, size_t other_index) const;
void *make_id_circuit_subcircuit (size_t circuit_index, size_t subcircuit_index) const;
void *make_id_circuit_subcircuit_pin (size_t circuit_index, size_t subcircuit_index, size_t pin_index) const;
void *make_id_circuit_device (size_t circuit_index, size_t device_index) const;
void *make_id_circuit_device_terminal (size_t circuit_index, size_t device_index, size_t terminal_index) const;
bool is_id_circuit (void *id) const;
bool is_id_circuit_pin (void *id) const;
bool is_id_circuit_pin_net (void *id) const;
bool is_id_circuit_net (void *id) const;
bool is_id_circuit_net_device_terminal (void *id) const;
bool is_id_circuit_net_device_terminal_others (void *id) const;
bool is_id_circuit_net_pin (void *id) const;
bool is_id_circuit_net_subcircuit_pin (void *id) const;
bool is_id_circuit_net_subcircuit_pin_others (void *id) const;
bool is_id_circuit_subcircuit (void *id) const;
bool is_id_circuit_subcircuit_pin (void *id) const;
bool is_id_circuit_device (void *id) const;
bool is_id_circuit_device_terminal (void *id) const;
size_t circuit_index_from_id (void *id) const;
size_t circuit_pin_index_from_id (void *id) const;
size_t circuit_device_index_from_id (void *id) const;
size_t circuit_device_terminal_index_from_id (void *id) const;
size_t circuit_subcircuit_index_from_id (void *id) const;
size_t circuit_subcircuit_pin_index_from_id (void *id) const;
size_t circuit_net_index_from_id (void *id) const;
size_t circuit_net_pin_index_from_id (void *id) const;
size_t circuit_net_subcircuit_pin_index_from_id (void *id) const;
size_t circuit_net_subcircuit_pin_other_index_from_id (void *id) const;
size_t circuit_net_device_terminal_index_from_id (void *id) const;
size_t circuit_net_device_terminal_other_index_from_id (void *id) const;
std::pair<const db::Circuit *, const db::Circuit *> circuits_from_id (void *id) const;
std::pair<const db::Net *, const db::Net *> nets_from_id (void *id) const;
std::pair<const db::NetSubcircuitPinRef *, const db::NetSubcircuitPinRef *> net_subcircuit_pinrefs_from_id (void *id) const;
std::pair<const db::NetTerminalRef *, const db::NetTerminalRef *> net_terminalrefs_from_id (void *id) const;
std::pair<const db::NetPinRef *, const db::NetPinRef *> net_pinrefs_from_id (void *id) const;
std::pair<const db::Device *, const db::Device *> devices_from_id (void *id) const;
std::pair<const db::Pin *, const db::Pin *> pins_from_id (void *id) const;
std::pair<const db::SubCircuit *, const db::SubCircuit *> subcircuits_from_id (void *id) const;
QString text (const QModelIndex &index) const;
QVariant tooltip (const QModelIndex &index) const;
QString search_text (const QModelIndex &index) const;
db::NetlistCrossReference::Status status (const QModelIndex &index) const;
QIcon icon (const QModelIndex &index) const;
QString make_link_to (const std::pair<const db::Net *, const db::Net *> &nets, int column = 0) const;
QString make_link_to (const std::pair<const db::Device *, const db::Device *> &devices, int column = 0) const;
QString make_link_to (const std::pair<const db::Pin *, const db::Pin *> &pins, const std::pair<const db::Circuit *, const db::Circuit *> &circuits, int column = 0) const;
QString make_link_to (const std::pair<const db::Circuit *, const db::Circuit *> &circuits, int column = 0) const;
QString make_link_to (const std::pair<const db::SubCircuit *, const db::SubCircuit *> &sub_circuits, int column = 0) const;
QString build_url (const QModelIndex &index, const std::string &title) const;
std::pair<const db::Netlist *, const db::Netlist *> netlists () const
{
return std::pair<const db::Netlist *, const db::Netlist *> (mp_l2ndb->netlist (), (const db::Netlist *)0);
}
bool is_valid_net_pair (const std::pair<const db::Net *, const db::Net *> &net) const;
QIcon icon_for_nets (const std::pair<const db::Net *, const db::Net *> &net) const;
QIcon icon_for_connection (const std::pair<const db::Net *, const db::Net *> &net) const;
void show_or_hide_items (QTreeView *view, const QModelIndex &parent, bool show_all, bool with_warnings, bool with_children);
db::LayoutToNetlist *mp_l2ndb;
@@ -236,6 +384,9 @@ private:
int m_status_column;
int m_first_column;
int m_second_column;
std::auto_ptr<NetlistModelItemData> mp_root;
RootItemData *root () const;
};
} // namespace lay
+179 -172
View File
@@ -69,7 +69,7 @@ inline const db::Circuit *deref_circuit (const db::Circuit *obj)
}
template <class Obj>
static db::ICplxTrans
static db::DCplxTrans
trans_for (const Obj *objs, const db::Layout &ly, const db::Cell &cell, db::ContextCache &cc, const db::DCplxTrans &initial = db::DCplxTrans ())
{
db::DCplxTrans t = initial;
@@ -89,7 +89,6 @@ trans_for (const Obj *objs, const db::Layout &ly, const db::Cell &cell, db::Cont
}
db::CplxTrans dbu_trans (ly.dbu ());
db::ICplxTrans it = dbu_trans.inverted () * t * dbu_trans;
// The circuit may not be instantiated and still not be the top cell.
// This happens if the subcell does not have connections. In this case
@@ -98,11 +97,11 @@ trans_for (const Obj *objs, const db::Layout &ly, const db::Cell &cell, db::Cont
if (circuit && ly.is_valid_cell_index (circuit->cell_index ())) {
std::pair<bool, db::ICplxTrans> tc = cc.find_layout_context (circuit->cell_index (), cell.cell_index ());
if (tc.first) {
it = tc.second * it;
t = dbu_trans * tc.second * dbu_trans.inverted () * t;
}
}
return it;
return t;
}
NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/)
@@ -142,7 +141,8 @@ NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/)
QAction *sep;
directory_tree->addAction (m_show_all_action);
directory_tree->addAction (actionCollapseAll);
directory_tree->addAction (actionExpandAll);
// TODO: this gives a too big tree - confine to single branches?
// directory_tree->addAction (actionExpandAll);
sep = new QAction (directory_tree);
sep->setSeparator (true);
directory_tree->addAction (sep);
@@ -306,21 +306,10 @@ NetlistBrowserPage::layer_list_changed (int)
void
NetlistBrowserPage::anchor_clicked (const QString &a)
{
QUrl url (a);
QString ids;
#if QT_VERSION >= 0x050000
ids = QUrlQuery (url.query ()).queryItemValue (QString::fromUtf8 ("id"));
#else
ids = url.queryItemValue (QString::fromUtf8 ("id"));
#endif
if (ids.isEmpty ()) {
return;
NetlistBrowserModel *netlist_model = dynamic_cast<NetlistBrowserModel *> (directory_tree->model ());
if (netlist_model) {
navigate_to (netlist_model->index_from_url (a), true);
}
void *id = reinterpret_cast<void *> (ids.toULongLong ());
navigate_to (id, true);
}
void
@@ -334,6 +323,7 @@ NetlistBrowserPage::current_tree_index_changed (const QModelIndex &index)
return;
}
// TODO: this could give a path ...
std::pair<const db::Circuit *, const db::Circuit *> circuits = tree_model->circuits_from_index (index);
QModelIndex circuit_index = netlist_model->index_from_circuit (circuits);
@@ -355,11 +345,10 @@ NetlistBrowserPage::current_index_changed (const QModelIndex &index)
return;
}
void *id = index.internalPointer ();
add_to_history (id, true);
add_to_history (index, true);
std::pair<const db::Circuit *, const db::Circuit *> circuits = netlist_model->circuit_from_index (index);
QModelIndex circuit_index = tree_model->index_from_circuits (circuits);
NetlistObjectsPath path = netlist_model->path_from_index (index);
QModelIndex circuit_index = tree_model->index_from_netpath (path);
m_signals_enabled = false;
hierarchy_tree->setCurrentIndex (circuit_index);
@@ -380,6 +369,18 @@ NetlistBrowserPage::select_net (const db::Net *net)
}
}
void
NetlistBrowserPage::select_path (const lay::NetlistObjectsPath &path)
{
if (path.is_null ()) {
directory_tree->clearSelection ();
} else {
NetlistBrowserModel *model = dynamic_cast<NetlistBrowserModel *> (directory_tree->model ());
tl_assert (model != 0);
directory_tree->setCurrentIndex (model->index_from_path (path));
}
}
std::vector<const db::Net *>
NetlistBrowserPage::selected_nets ()
{
@@ -411,7 +412,7 @@ NetlistBrowserPage::selected_circuits ()
QModelIndexList selection = directory_tree->selectionModel ()->selectedIndexes ();
for (QModelIndexList::const_iterator i = selection.begin (); i != selection.end (); ++i) {
if (i->column () == 0 && model->is_circuit_index (*i)) {
if (i->column () == 0) {
const db::Circuit *circuit = model->circuit_from_index (*i).first;
if (circuit) {
circuits.push_back (circuit);
@@ -467,18 +468,23 @@ NetlistBrowserPage::selected_devices ()
void
NetlistBrowserPage::selection_changed ()
{
std::vector<const db::Net *> nets = selected_nets ();
if (mp_info_dialog) {
mp_info_dialog->set_nets (mp_database.get (), nets);
NetlistBrowserModel *model = dynamic_cast<NetlistBrowserModel *> (directory_tree->model ());
tl_assert (model != 0);
QModelIndexList selected = directory_tree->selectionModel ()->selectedIndexes ();
std::vector<lay::NetlistObjectsPath> selected_paths;
selected_paths.reserve (selected.size ());
for (QModelIndexList::const_iterator i = selected.begin (); i != selected.end (); ++i) {
if (i->column () == 0) {
selected_paths.push_back (model->path_from_index (*i));
}
}
std::vector<const db::Device *> devices = selected_devices ();
QModelIndex current = directory_tree->selectionModel ()->currentIndex ();
highlight (model->path_from_index (current), selected_paths);
std::vector<const db::SubCircuit *> subcircuits = selected_subcircuits ();
std::vector<const db::Circuit *> circuits = selected_circuits ();
highlight (nets, devices, subcircuits, circuits);
selection_changed_event ();
}
void
@@ -518,15 +524,8 @@ NetlistBrowserPage::select_color_for_net ()
}
void
NetlistBrowserPage::navigate_to (void *id, bool fwd)
NetlistBrowserPage::navigate_to (const QModelIndex &index, bool fwd)
{
NetlistBrowserTreeModel *tree_model = dynamic_cast<NetlistBrowserTreeModel *> (hierarchy_tree->model ());
NetlistBrowserModel *netlist_model = dynamic_cast<NetlistBrowserModel *> (directory_tree->model ());
if (! tree_model || ! netlist_model) {
return;
}
QModelIndex index = netlist_model->index_from_id (id, 0);
if (! index.isValid ()) {
return;
}
@@ -536,35 +535,42 @@ NetlistBrowserPage::navigate_to (void *id, bool fwd)
directory_tree->setCurrentIndex (index);
std::pair<const db::Circuit *, const db::Circuit *> circuits = netlist_model->circuit_from_index (index);
QModelIndex circuit_index = tree_model->index_from_circuits (circuits);
NetlistBrowserTreeModel *tree_model = dynamic_cast<NetlistBrowserTreeModel *> (hierarchy_tree->model ());
NetlistBrowserModel *netlist_model = dynamic_cast<NetlistBrowserModel *> (directory_tree->model ());
if (! tree_model || ! netlist_model) {
return;
}
lay::NetlistObjectsPath path = netlist_model->path_from_index (index);
QModelIndex circuit_index = tree_model->index_from_netpath (path);
hierarchy_tree->setCurrentIndex (circuit_index);
} catch (...) {
}
m_signals_enabled = true;
add_to_history (id, fwd);
add_to_history (index, fwd);
selection_changed ();
}
void
NetlistBrowserPage::add_to_history (void *id, bool fwd)
NetlistBrowserPage::add_to_history (const QModelIndex &index, bool fwd)
{
if (! fwd) {
if (m_history_ptr > 1) {
--m_history_ptr;
m_history [m_history_ptr - 1] = id;
m_history [m_history_ptr - 1] = index;
}
} else if (m_history_ptr >= m_history.size ()) {
m_history.push_back (id);
m_history.push_back (index);
m_history_ptr = m_history.size ();
} else {
if (m_history [m_history_ptr] != id) {
if (m_history [m_history_ptr] != index) {
m_history.erase (m_history.begin () + m_history_ptr + 1, m_history.end ());
}
m_history [m_history_ptr] = id;
m_history [m_history_ptr] = index;
++m_history_ptr;
}
@@ -730,7 +736,7 @@ NetlistBrowserPage::find_button_pressed ()
QModelIndex next = find_next (directory_tree, directory_tree->model (), re, directory_tree->currentIndex ());
if (next.isValid ()) {
navigate_to (next.internalPointer ());
navigate_to (next);
}
}
@@ -795,11 +801,12 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb)
m_signals_enabled = se;
clear_markers ();
highlight (std::vector<const db::Net *> (), std::vector<const db::Device *> (), std::vector<const db::SubCircuit *> (), std::vector<const db::Circuit *> ());
m_cell_context_cache = db::ContextCache (mp_database.get () ? mp_database->internal_layout () : 0);
setup_trees ();
selection_changed_event ();
}
void
@@ -886,21 +893,16 @@ NetlistBrowserPage::setup_trees ()
}
void
NetlistBrowserPage::highlight (const std::vector<const db::Net *> &nets, const std::vector<const db::Device *> &devices, const std::vector<const db::SubCircuit *> &subcircuits, const std::vector<const db::Circuit *> &circuits)
NetlistBrowserPage::highlight (const NetlistObjectsPath &current_path, const std::vector<NetlistObjectsPath> &selected_paths)
{
if (nets != m_current_nets || devices != m_current_devices || subcircuits != m_current_subcircuits || circuits != m_current_circuits) {
if (current_path != m_current_path && selected_paths != m_selected_paths) {
m_current_nets = nets;
m_current_devices = devices;
m_current_subcircuits = subcircuits;
m_current_circuits = circuits;
m_current_path = current_path;
m_selected_paths = selected_paths;
clear_markers ();
if (! nets.empty () || ! devices.empty () || ! subcircuits.empty () || ! circuits.empty ()) {
adjust_view ();
update_highlights ();
}
adjust_view ();
update_highlights ();
}
}
@@ -928,7 +930,8 @@ bbox_for_device_abstract (const db::Layout *layout, const db::DeviceAbstract *de
return db::Box ();
}
return layout->cell (device_abstract->cell_index ()).bbox ().transformed (db::CplxTrans (layout->dbu ()).inverted () * trans * db::CplxTrans (layout->dbu ()));}
return layout->cell (device_abstract->cell_index ()).bbox ().transformed (db::CplxTrans (layout->dbu ()).inverted () * trans * db::CplxTrans (layout->dbu ()));
}
static db::Box
bbox_for_circuit (const db::Layout *layout, const db::Circuit *circuit)
@@ -945,12 +948,6 @@ bbox_for_circuit (const db::Layout *layout, const db::Circuit *circuit)
return layout->cell (circuit->cell_index ()).bbox ();
}
static db::Box
bbox_for_subcircuit (const db::Layout *layout, const db::SubCircuit *subcircuit)
{
return bbox_for_circuit (layout, subcircuit->circuit_ref ());
}
void
NetlistBrowserPage::adjust_view ()
{
@@ -967,57 +964,80 @@ NetlistBrowserPage::adjust_view ()
return;
}
const db::Layout &original_layout = mp_view->cellview (m_cv_index)->layout ();
const db::Circuit *top_circuit = mp_database->netlist ()->circuit_by_name (original_layout.cell_name (mp_view->cellview (m_cv_index).cell_index ()));
const db::Layout *layout = mp_database->internal_layout ();
const db::Cell *cell = mp_database->internal_top_cell ();
const db::Cell *cell = (top_circuit && layout->is_valid_cell_index (top_circuit->cell_index ()) ? &layout->cell (top_circuit->cell_index ()) : mp_database->internal_top_cell ());
if (! layout || ! cell) {
return;
}
db::DBox bbox;
db::Box bbox;
for (std::vector<lay::NetlistObjectsPath>::const_iterator path = m_selected_paths.begin (); path != m_selected_paths.end (); ++path) {
for (std::vector<const db::Net *>::const_iterator net = m_current_nets.begin (); net != m_current_nets.end (); ++net) {
const db::Circuit *circuit = path->root.first;
if (! circuit) {
continue;
}
db::ICplxTrans net_trans = trans_for (*net, *layout, *cell, m_cell_context_cache);
db::DCplxTrans trans;
db::cell_index_type cell_index = (*net)->circuit ()->cell_index ();
size_t cluster_id = (*net)->cluster_id ();
trans = trans_for (circuit, *layout, *cell, m_cell_context_cache, db::DCplxTrans ());
const db::Connectivity &conn = mp_database->connectivity ();
for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) {
for (std::list<std::pair<const db::SubCircuit *, const db::SubCircuit *> >::const_iterator p = path->path.begin (); p != path->path.end () && circuit; ++p) {
if (p->first) {
circuit = p->first->circuit_ref ();
trans = trans * p->first->trans ();
} else {
circuit = 0;
}
}
db::Box layer_bbox;
db::recursive_cluster_shape_iterator<db::PolygonRef> shapes (mp_database->net_clusters (), *layer, cell_index, cluster_id);
while (! shapes.at_end ()) {
layer_bbox += shapes.trans () * shapes->box ();
++shapes;
if (! circuit) {
continue;
}
db::Box ebox;
const db::Device *device = path->device.first;
const db::Net *net = path->net.first;
if (device) {
ebox += bbox_for_device_abstract (layout, device->device_abstract (), db::DCplxTrans ());
const std::vector<db::DeviceAbstractRef> &oda = device->other_abstracts ();
for (std::vector<db::DeviceAbstractRef>::const_iterator a = oda.begin (); a != oda.end (); ++a) {
ebox += bbox_for_device_abstract (layout, a->device_abstract, a->trans);
}
bbox += net_trans * layer_bbox;
} 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::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;
}
} else if (circuit) {
ebox += bbox_for_circuit (layout, circuit);
}
}
bbox += trans * db::CplxTrans (layout->dbu ()) * ebox;
for (std::vector<const db::Device *>::const_iterator device = m_current_devices.begin (); device != m_current_devices.end (); ++device) {
db::ICplxTrans trans = trans_for (*device, *layout, *cell, m_cell_context_cache, (*device)->trans ());
bbox += trans * bbox_for_device_abstract (layout, (*device)->device_abstract (), db::DCplxTrans ());
const std::vector<db::DeviceAbstractRef> &oda = (*device)->other_abstracts ();
for (std::vector<db::DeviceAbstractRef>::const_iterator a = oda.begin (); a != oda.end (); ++a) {
bbox += trans * bbox_for_device_abstract (layout, a->device_abstract, a->trans);
}
}
for (std::vector<const db::SubCircuit *>::const_iterator subcircuit = m_current_subcircuits.begin (); subcircuit != m_current_subcircuits.end (); ++subcircuit) {
bbox += trans_for (*subcircuit, *layout, *cell, m_cell_context_cache, (*subcircuit)->trans ()) * bbox_for_subcircuit (layout, *subcircuit);
}
for (std::vector<const db::Circuit *>::const_iterator circuit = m_current_circuits.begin (); circuit != m_current_circuits.end (); ++circuit) {
bbox += trans_for (*circuit, *layout, *cell, m_cell_context_cache, db::DCplxTrans ()) * bbox_for_circuit (layout, *circuit);
}
if (! bbox.empty ()) {
@@ -1025,9 +1045,8 @@ NetlistBrowserPage::adjust_view ()
std::vector<db::DCplxTrans> tv = mp_view->cv_transform_variants (m_cv_index);
db::DBox tv_bbox;
db::DBox dbu_bbox = db::CplxTrans (layout->dbu ()) * bbox;
for (std::vector<db::DCplxTrans>::const_iterator t = tv.begin (); t != tv.end (); ++t) {
tv_bbox += *t * dbu_bbox;
tv_bbox += *t * bbox;
}
if (m_window == lay::NetlistBrowserConfig::FitNet) {
@@ -1065,12 +1084,10 @@ bool
NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, size_t &n_markers, const std::vector<db::DCplxTrans> &tv)
{
const db::Layout *layout = mp_database->internal_layout ();
const db::Cell *cell = mp_database->internal_top_cell ();
db::ICplxTrans device_trans = trans_for (device, *layout, *cell, m_cell_context_cache, device->trans ());
QColor color = make_valid_color (m_colorizer.marker_color ());
db::Box device_bbox = bbox_for_device_abstract (layout, device->device_abstract (), db::DCplxTrans ());
db::Box device_bbox = bbox_for_device_abstract (layout, device->device_abstract (), device->trans ());
if (! device_bbox.empty ()) {
if (n_markers == m_max_shape_count) {
@@ -1080,7 +1097,7 @@ NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, siz
++n_markers;
mp_markers.push_back (new lay::Marker (mp_view, m_cv_index));
mp_markers.back ()->set (device_bbox, device_trans, tv);
mp_markers.back ()->set (device_bbox, db::ICplxTrans (), tv);
mp_markers.back ()->set_color (color);
mp_markers.back ()->set_frame_color (color);
configure_marker (mp_markers.back (), false);
@@ -1090,7 +1107,7 @@ NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, siz
const std::vector<db::DeviceAbstractRef> &oda = device->other_abstracts ();
for (std::vector<db::DeviceAbstractRef>::const_iterator a = oda.begin (); a != oda.end (); ++a) {
db::Box da_box = bbox_for_device_abstract (layout, a->device_abstract, a->trans);
db::Box da_box = bbox_for_device_abstract (layout, a->device_abstract, device->trans () * a->trans);
if (! da_box.empty ()) {
if (n_markers == m_max_shape_count) {
@@ -1100,7 +1117,7 @@ NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, siz
++n_markers;
mp_markers.push_back (new lay::Marker (mp_view, m_cv_index));
mp_markers.back ()->set (da_box, device_trans, tv);
mp_markers.back ()->set (da_box, db::ICplxTrans (), tv);
mp_markers.back ()->set_color (color);
mp_markers.back ()->set_frame_color (color);
configure_marker (mp_markers.back (), false);
@@ -1112,40 +1129,10 @@ NetlistBrowserPage::produce_highlights_for_device (const db::Device *device, siz
return false;
}
bool
NetlistBrowserPage::produce_highlights_for_subcircuit (const db::SubCircuit *subcircuit, size_t &n_markers, const std::vector<db::DCplxTrans> &tv)
{
const db::Layout *layout = mp_database->internal_layout ();
const db::Cell *cell = mp_database->internal_top_cell ();
db::ICplxTrans subcircuit_trans = trans_for (subcircuit, *layout, *cell, m_cell_context_cache, subcircuit->trans ());
QColor color = make_valid_color (m_colorizer.marker_color ());
db::Box circuit_bbox = bbox_for_subcircuit (layout, subcircuit);
if (circuit_bbox.empty ()) {
return false;
}
if (n_markers == m_max_shape_count) {
return true;
}
++n_markers;
mp_markers.push_back (new lay::Marker (mp_view, m_cv_index));
mp_markers.back ()->set (circuit_bbox, subcircuit_trans, tv);
mp_markers.back ()->set_color (color);
mp_markers.back ()->set_frame_color (color);
configure_marker (mp_markers.back (), false);
return false;
}
bool
NetlistBrowserPage::produce_highlights_for_circuit (const db::Circuit *circuit, size_t &n_markers, const std::vector<db::DCplxTrans> &tv)
{
const db::Layout *layout = mp_database->internal_layout ();
const db::Cell *cell = mp_database->internal_top_cell ();
db::ICplxTrans circuit_trans = trans_for (circuit, *layout, *cell, m_cell_context_cache, db::DCplxTrans ());
QColor color = make_valid_color (m_colorizer.marker_color ());
db::Box circuit_bbox = bbox_for_circuit (layout, circuit);
@@ -1160,7 +1147,7 @@ NetlistBrowserPage::produce_highlights_for_circuit (const db::Circuit *circuit,
++n_markers;
mp_markers.push_back (new lay::Marker (mp_view, m_cv_index));
mp_markers.back ()->set (circuit_bbox, circuit_trans, tv);
mp_markers.back ()->set (circuit_bbox, db::ICplxTrans (), tv);
mp_markers.back ()->set_color (color);
mp_markers.back ()->set_frame_color (color);
configure_marker (mp_markers.back (), false);
@@ -1172,8 +1159,6 @@ bool
NetlistBrowserPage::produce_highlights_for_net (const db::Net *net, size_t &n_markers, const std::map<db::LayerProperties, lay::LayerPropertiesConstIterator> &display_by_lp, const std::vector<db::DCplxTrans> &tv)
{
const db::Layout *layout = mp_database->internal_layout ();
const db::Cell *cell = mp_database->internal_top_cell ();
db::ICplxTrans net_trans = trans_for (net, *layout, *cell, m_cell_context_cache);
db::cell_index_type cell_index = net->circuit ()->cell_index ();
size_t cluster_id = net->cluster_id ();
@@ -1187,15 +1172,19 @@ NetlistBrowserPage::produce_highlights_for_net (const db::Net *net, size_t &n_ma
db::LayerProperties lp = layout->get_properties (*layer);
std::map<db::LayerProperties, lay::LayerPropertiesConstIterator>::const_iterator display = display_by_lp.find (lp);
db::recursive_cluster_shape_iterator<db::PolygonRef> shapes (mp_database->net_clusters (), *layer, cell_index, cluster_id);
db::recursive_cluster_shape_iterator<db::NetShape> shapes (mp_database->net_clusters (), *layer, cell_index, cluster_id);
while (! shapes.at_end ()) {
if (shapes->type () != db::NetShape::Polygon) {
continue;
}
if (n_markers == m_max_shape_count) {
return true;
}
mp_markers.push_back (new lay::Marker (mp_view, m_cv_index));
mp_markers.back ()->set (*shapes, net_trans * shapes.trans (), tv);
mp_markers.back ()->set (shapes->polygon_ref (), shapes.trans (), tv);
if (net_color.isValid ()) {
@@ -1268,14 +1257,14 @@ NetlistBrowserPage::update_highlights ()
}
const db::Layout &original_layout = mp_view->cellview (m_cv_index)->layout ();
const db::Circuit *top_circuit = mp_database->netlist ()->circuit_by_name (original_layout.cell_name (mp_view->cellview (m_cv_index).cell_index ()));
const db::Layout *layout = mp_database->internal_layout ();
if (! layout) {
const db::Cell *cell = (top_circuit && layout->is_valid_cell_index (top_circuit->cell_index ()) ? &layout->cell (top_circuit->cell_index ()) : mp_database->internal_top_cell ());
if (! layout || ! cell) {
return;
}
// a map of display properties vs. layer properties
std::map<db::LayerProperties, lay::LayerPropertiesConstIterator> display_by_lp;
for (lay::LayerPropertiesConstIterator lp = mp_view->begin_layers (); ! lp.at_end (); ++lp) {
if (! lp->has_children () && lp->cellview_index () == int (m_cv_index) && lp->layer_index () >= 0 && (unsigned int) lp->layer_index () < original_layout.layers ()) {
@@ -1283,36 +1272,55 @@ NetlistBrowserPage::update_highlights ()
}
}
std::vector<db::DCplxTrans> tv = mp_view->cv_transform_variants (m_cv_index);
// correct DBU differences between the storage layout and the original layout
for (std::vector<db::DCplxTrans>::iterator t = tv.begin (); t != tv.end (); ++t) {
*t = *t * db::DCplxTrans (layout->dbu () / original_layout.dbu ());
}
size_t n_markers = 0;
bool not_all_shapes_are_shown = false;
for (std::vector<const db::Net *>::const_iterator net = m_current_nets.begin (); net != m_current_nets.end () && ! not_all_shapes_are_shown; ++net) {
if ((*net)->circuit ()) {
not_all_shapes_are_shown = produce_highlights_for_net (*net, n_markers, display_by_lp, tv);
}
}
for (std::vector<lay::NetlistObjectsPath>::const_iterator path = m_selected_paths.begin (); path != m_selected_paths.end (); ++path) {
for (std::vector<const db::Device *>::const_iterator device = m_current_devices.begin (); device != m_current_devices.end () && ! not_all_shapes_are_shown; ++device) {
if ((*device)->circuit ()) {
not_all_shapes_are_shown = produce_highlights_for_device (*device, n_markers, tv);
const db::Circuit *circuit = path->root.first;
if (! circuit) {
continue;
}
}
for (std::vector<const db::SubCircuit *>::const_iterator subcircuit = m_current_subcircuits.begin (); subcircuit != m_current_subcircuits.end () && ! not_all_shapes_are_shown; ++subcircuit) {
if ((*subcircuit)->circuit ()) {
not_all_shapes_are_shown = produce_highlights_for_subcircuit (*subcircuit, n_markers, tv);
// computes the transformation supplied by the path
db::DCplxTrans trans = trans_for (circuit, *layout, *cell, m_cell_context_cache, db::DCplxTrans ());
for (std::list<std::pair<const db::SubCircuit *, const db::SubCircuit *> >::const_iterator p = path->path.begin (); p != path->path.end () && circuit; ++p) {
if (p->first) {
circuit = p->first->circuit_ref ();
trans = trans * p->first->trans ();
} else {
circuit = 0;
}
}
if (! circuit) {
continue;
}
// a map of display properties vs. layer properties
// correct DBU differences between the storage layout and the original layout
std::vector<db::DCplxTrans> tv = mp_view->cv_transform_variants (m_cv_index);
for (std::vector<db::DCplxTrans>::iterator t = tv.begin (); t != tv.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)) {
not_all_shapes_are_shown = true;
}
} else if (path->device.first) {
if (produce_highlights_for_device (path->device.first, n_markers, tv)) {
not_all_shapes_are_shown = true;
}
} else if (circuit) {
if (produce_highlights_for_circuit (circuit, n_markers, tv)) {
not_all_shapes_are_shown = true;
}
}
}
for (std::vector<const db::Circuit *>::const_iterator circuit = m_current_circuits.begin (); circuit != m_current_circuits.end () && ! not_all_shapes_are_shown; ++circuit) {
not_all_shapes_are_shown = produce_highlights_for_circuit (*circuit, n_markers, tv);
}
if (not_all_shapes_are_shown) {
@@ -1323,7 +1331,6 @@ NetlistBrowserPage::update_highlights ()
} else {
info_label->hide ();
}
}
void
+48 -25
View File
@@ -33,6 +33,7 @@
#include "dbLayoutUtils.h"
#include "tlObject.h"
#include "tlEvents.h"
#include <QFrame>
@@ -90,25 +91,14 @@ public:
/**
* @brief Attaches the page to a L2N DB
*/
void set_l2ndb (db::LayoutToNetlist *database)
{
set_db (database);
}
void set_db (db::LayoutToNetlist *database);
/**
* @brief Attaches the page to a LVS DB
* @brief Gets the database the page is connected to
*/
void set_lvsdb (db::LayoutVsSchematic *database)
db::LayoutToNetlist *db ()
{
set_db (database);
}
/**
* @brief Detaches the page from any DB
*/
void reset_db ()
{
set_db (0);
return mp_database.get ();
}
/**
@@ -116,6 +106,22 @@ public:
*/
void select_net (const db::Net *net);
/**
* @brief Selects a netlist object (a circuit, a subcircuit, a net or a device)
*/
void select_path (const lay::NetlistObjectPath &path)
{
select_path (lay::NetlistObjectsPath::from_first (path));
}
/**
* @brief Selects a netlist object (a circuit, a subcircuit, a net or a device)
*
* This variant allows specifying a paired path using either an object from the first,
* the second netlist of both.
*/
void select_path (const lay::NetlistObjectsPath &path);
/**
* @brief Set the window type and window dimensions
*/
@@ -162,6 +168,27 @@ public:
*/
void update_highlights ();
/**
* @brief Gets the current object's path
*/
const lay::NetlistObjectsPath &current_path () const
{
return m_current_path;
}
/**
* @brief Gets the selected nets
*/
const std::vector<lay::NetlistObjectsPath> &selected_paths () const
{
return m_selected_paths;
}
/**
* @brief An event indicating that the selection has changed
*/
tl::Event selection_changed_event;
public slots:
void export_all ();
void export_selected ();
@@ -201,28 +228,25 @@ private:
unsigned int m_cv_index;
lay::Dispatcher *mp_plugin_root;
tl::weak_ptr<db::LayoutToNetlist> mp_database;
std::vector<void *> m_history;
std::vector<QModelIndex> m_history;
size_t m_history_ptr;
bool m_signals_enabled;
std::vector <lay::Marker *> mp_markers;
bool m_enable_updates;
bool m_update_needed;
std::vector<const db::Net *> m_current_nets;
std::vector<const db::Device *> m_current_devices;
std::vector<const db::SubCircuit *> m_current_subcircuits;
std::vector<const db::Circuit *> m_current_circuits;
lay::NetlistObjectsPath m_current_path;
std::vector<lay::NetlistObjectsPath> m_selected_paths;
lay::NetInfoDialog *mp_info_dialog;
tl::DeferredMethod<NetlistBrowserPage> dm_update_highlights;
tl::DeferredMethod<NetlistBrowserPage> dm_rerun_macro;
db::ContextCache m_cell_context_cache;
void set_db (db::LayoutToNetlist *l2ndb);
void setup_trees ();
void add_to_history (void *id, bool fwd);
void navigate_to (void *id, bool forward = true);
void add_to_history (const QModelIndex &index, bool fwd);
void navigate_to (const QModelIndex &index, bool forward = true);
void adjust_view ();
void clear_markers ();
void highlight (const std::vector<const db::Net *> &nets, const std::vector<const db::Device *> &devices, const std::vector<const db::SubCircuit *> &subcircuits, const std::vector<const db::Circuit *> &circuits);
void highlight (const NetlistObjectsPath &current_path, const std::vector<NetlistObjectsPath> &selected_paths);
std::vector<const db::Net *> selected_nets ();
std::vector<const db::Device *> selected_devices ();
std::vector<const db::SubCircuit *> selected_subcircuits ();
@@ -232,7 +256,6 @@ private:
QColor make_valid_color (const QColor &color);
bool produce_highlights_for_net(const db::Net *net, size_t &n_markers, const std::map<db::LayerProperties, lay::LayerPropertiesConstIterator> &display_by_lp, const std::vector<db::DCplxTrans> &tv);
bool produce_highlights_for_device (const db::Device *device, size_t &n_markers, const std::vector<db::DCplxTrans> &tv);
bool produce_highlights_for_subcircuit (const db::SubCircuit *subcircuit, size_t &n_markers, const std::vector<db::DCplxTrans> &tv);
bool produce_highlights_for_circuit (const db::Circuit *circuit, size_t &n_markers, const std::vector<db::DCplxTrans> &tv);
void configure_marker (lay::Marker *marker, bool with_fill);
void rerun_macro ();
@@ -24,6 +24,7 @@
#include "layNetlistBrowserTreeModel.h"
#include "layIndexedNetlistModel.h"
#include "layNetlistCrossReferenceModel.h"
#include "layNetlistBrowserModel.h"
#include <QPainter>
#include <QIcon>
@@ -257,6 +258,45 @@ NetlistBrowserTreeModel::build_circuits_to_index (size_t nprod, const std::pair<
}
}
static bool is_compatible (const std::pair<const db::Circuit *, const db::Circuit *> &a, const std::pair<const db::Circuit *, const db::Circuit *> &b)
{
if (a.first && b.first && a.first == b.first) {
return true;
} else if (a.second && b.second && a.second == b.second) {
return true;
} else {
return false;
}
}
QModelIndex
NetlistBrowserTreeModel::index_from_netpath (const NetlistObjectsPath &path) const
{
QModelIndex idx;
idx = index_from_circuits (path.root);
for (NetlistObjectsPath::path_iterator p = path.path.begin (); p != path.path.end () && idx.isValid (); ++p) {
std::pair<const db::Circuit *, const db::Circuit *> sc (p->first ? p->first->circuit_ref () : 0, p->second ? p->second->circuit_ref (): 0);
std::pair<const db::Circuit *, const db::Circuit *> circuit = circuits_from_index (idx);
size_t count = mp_indexer->child_circuit_count (circuit);
for (size_t n = count; n > 0; ) {
--n;
std::pair<const db::Circuit *, const db::Circuit *> cc = mp_indexer->child_circuit_from_index (circuit, n).first;
if (is_compatible (sc, cc)) {
circuit = cc;
idx = index (n, 0, idx);
break;
}
}
}
return idx;
}
QModelIndex
NetlistBrowserTreeModel::index_from_circuits (const std::pair<const db::Circuit *, const db::Circuit *> &circuits) const
{
@@ -382,7 +422,7 @@ NetlistBrowserTreeModel::parent (const QModelIndex &index) const
nprod /= nnlast;
return createIndex (int (ids / nprod - 1), index.column (), reinterpret_cast<void *> (ids));
return createIndex (int (ids / nprod - 1), 0, reinterpret_cast<void *> (ids));
}
@@ -42,6 +42,7 @@ namespace lay
{
class IndexedNetlistModel;
struct NetlistObjectsPath;
// ----------------------------------------------------------------------------------
// NetlistBrowserTreeModel definition
@@ -77,6 +78,7 @@ public:
std::pair<const db::Circuit *, const db::Circuit *> circuits_from_index (const QModelIndex &index) const;
QModelIndex index_from_circuits (const std::pair<const db::Circuit *, const db::Circuit *> &circuits) const;
QModelIndex index_from_netpath (const NetlistObjectsPath &path) const;
private:
NetlistBrowserTreeModel (const NetlistBrowserTreeModel &);
@@ -308,6 +308,161 @@ const db::Circuit *NetlistCrossReferenceModel::second_circuit_for (const db::Cir
return mp_cross_ref->other_circuit_for (first);
}
namespace {
// TODO: borrowed from dbNetlistCrossReference.cc
static int string_value_compare (const std::string &a, const std::string &b)
{
return a == b ? 0 : (a < b ? -1 : 1);
}
template <class Obj>
struct by_expanded_name_value_compare
{
int operator() (const Obj &a, const Obj &b) const
{
return string_value_compare (a.expanded_name (), b.expanded_name ());
}
};
template <class Obj> struct net_object_compare;
template <>
struct net_object_compare<db::NetSubcircuitPinRef>
{
int operator() (const db::NetSubcircuitPinRef &a, const db::NetSubcircuitPinRef &b) const
{
int ct = by_expanded_name_value_compare<db::SubCircuit> () (*a.subcircuit (), *b.subcircuit ());
if (ct == 0) {
return by_expanded_name_value_compare<db::Pin> () (*a.pin (), *b.pin ());
} else {
return ct;
}
}
};
template <class Obj, class ValueCompare>
struct two_pointer_compare
{
int operator() (const Obj *a, const Obj *b) const
{
if ((a == 0) != (b == 0)) {
return (a == 0) > (b == 0) ? -1 : 1;
}
if (a != 0) {
return ValueCompare () (*a, *b);
} else {
return 0;
}
}
};
template <class Obj, class ValueCompare>
struct two_pair_compare
{
bool operator() (const std::pair<const Obj *, const Obj *> &a, const std::pair<const Obj *, const Obj *> &b)
{
int ct = two_pointer_compare<Obj, ValueCompare> () (a.first, b.first);
if (ct != 0) {
return ct < 0;
}
return two_pointer_compare<Obj, ValueCompare> () (a.second, b.second) < 0;
}
};
struct SortNetSubCircuitPins
: public two_pair_compare<db::NetSubcircuitPinRef, net_object_compare<db::NetSubcircuitPinRef> >
{
// .. nothing yet ..
};
}
void NetlistCrossReferenceModel::ensure_subcircuit_data_built () const
{
if (! m_per_subcircuit_data.empty ()) {
return;
}
// Build the net to subcircuit ref table
for (db::NetlistCrossReference::circuits_iterator c = mp_cross_ref->begin_circuits (); c != mp_cross_ref->end_circuits (); ++c) {
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (*c);
if (! data) {
continue;
}
for (db::NetlistCrossReference::PerCircuitData::subcircuit_pairs_type::const_iterator sc = data->subcircuits.begin (); sc != data->subcircuits.end (); ++sc) {
const std::pair<const db::SubCircuit *, const db::SubCircuit *> &sc_pair = sc->pair;
if (sc_pair.first && sc_pair.second) {
PerSubCircuitCacheData &sc_data = m_per_subcircuit_data [sc_pair];
std::multimap<const db::Net *, const db::NetSubcircuitPinRef *> first_net_to_other_netref;
for (size_t i = 0; i < sc_pair.second->circuit_ref ()->pin_count (); ++i) {
const db::NetSubcircuitPinRef *n2 = sc_pair.second->netref_for_pin (i);
if (n2) {
const db::Net *n1 = mp_cross_ref->other_net_for (n2->net ());
if (n1) {
first_net_to_other_netref.insert (std::make_pair (n1, n2));
} else {
sc_data.nets_per_pins.push_back (std::pair<const db::NetSubcircuitPinRef *, const db::NetSubcircuitPinRef *> ((const db::NetSubcircuitPinRef *) 0, n2));
}
}
}
for (size_t i = 0; i < sc_pair.first->circuit_ref ()->pin_count (); ++i) {
const db::NetSubcircuitPinRef *n1 = sc_pair.first->netref_for_pin (i);
if (n1) {
const db::NetSubcircuitPinRef *n2 = 0;
std::multimap<const db::Net *, const db::NetSubcircuitPinRef *>::iterator m = first_net_to_other_netref.find (n1->net ());
if (m != first_net_to_other_netref.end () && m->first == n1->net ()) {
n2 = m->second;
first_net_to_other_netref.erase (m);
}
sc_data.nets_per_pins.push_back (std::make_pair (n1, n2));
}
}
std::sort (sc_data.nets_per_pins.begin (), sc_data.nets_per_pins.end (), SortNetSubCircuitPins ());
}
}
}
}
size_t NetlistCrossReferenceModel::subcircuit_pin_count (const subcircuit_pair &subcircuits) const
{
ensure_subcircuit_data_built ();
std::map<std::pair<const db::SubCircuit *, const db::SubCircuit *>, PerSubCircuitCacheData>::const_iterator sc = m_per_subcircuit_data.find (subcircuits);
if (sc != m_per_subcircuit_data.end ()) {
return sc->second.nets_per_pins.size ();
} else {
return std::max (subcircuits.first ? subcircuits.first->circuit_ref ()->pin_count () : 0, subcircuits.second ? subcircuits.second->circuit_ref ()->pin_count () : 0);
}
}
IndexedNetlistModel::net_subcircuit_pin_pair NetlistCrossReferenceModel::subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const
{
ensure_subcircuit_data_built ();
std::map<std::pair<const db::SubCircuit *, const db::SubCircuit *>, PerSubCircuitCacheData>::const_iterator sc = m_per_subcircuit_data.find (subcircuits);
if (sc != m_per_subcircuit_data.end ()) {
if (index < sc->second.nets_per_pins.size ()) {
return sc->second.nets_per_pins [index];
} else {
return IndexedNetlistModel::net_subcircuit_pin_pair ((const db::NetSubcircuitPinRef *) 0, (const db::NetSubcircuitPinRef *) 0);
}
} else {
return IndexedNetlistModel::net_subcircuit_pin_pair (subcircuits.first ? subcircuits.first->netref_for_pin (index) : 0, subcircuits.second ? subcircuits.second->netref_for_pin (index) : 0);
}
}
IndexedNetlistModel::net_subcircuit_pin_pair NetlistCrossReferenceModel::net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const
{
const db::NetlistCrossReference::PerNetData *data = mp_cross_ref->per_net_data_for (nets);
@@ -48,6 +48,7 @@ public:
virtual size_t net_count (const circuit_pair &circuits) const;
virtual size_t net_terminal_count (const net_pair &nets) const;
virtual size_t net_subcircuit_pin_count (const net_pair &nets) const;
virtual size_t subcircuit_pin_count (const subcircuit_pair &subcircuits) const;
virtual size_t net_pin_count (const net_pair &nets) const;
virtual size_t device_count (const circuit_pair &circuits) const;
virtual size_t pin_count (const circuit_pair &circuits) const;
@@ -65,6 +66,7 @@ public:
virtual const db::Net *second_net_for (const db::Net *first) const;
virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const;
virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const;
virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &nets, size_t index) const;
virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const;
virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const;
virtual std::pair<device_pair, Status> device_from_index (const circuit_pair &circuits, size_t index) const;
@@ -95,6 +97,11 @@ public:
std::map<std::pair<const db::SubCircuit *, const db::SubCircuit *>, size_t> index_of_subcircuits;
};
struct PerSubCircuitCacheData
{
std::vector<std::pair<const db::NetSubcircuitPinRef *, const db::NetSubcircuitPinRef *> > nets_per_pins;
};
tl::weak_ptr<db::NetlistCrossReference> mp_cross_ref;
mutable std::map<net_pair, circuit_pair> m_parents_of_nets;
mutable std::map<device_pair, circuit_pair> m_parents_of_devices;
@@ -104,6 +111,9 @@ public:
mutable std::vector<circuit_pair> m_top_level_circuits;
mutable std::map<std::pair<const db::Circuit *, const db::Circuit *>, PerCircuitCacheData> m_per_circuit_data;
mutable std::map<std::pair<const db::Circuit *, const db::Circuit *>, size_t> m_index_of_circuits;
mutable std::map<std::pair<const db::SubCircuit *, const db::SubCircuit *>, PerSubCircuitCacheData> m_per_subcircuit_data;
void ensure_subcircuit_data_built () const;
};
}
+76 -15
View File
@@ -809,15 +809,31 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
} else {
// The array (or single instance) must be iterated instance
// by instance
for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ++p) {
size_t qid = 0;
// The array (or single instance) must be iterated instance by instance
for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ) {
test_snapshot (0);
db::ICplxTrans t (cell_inst.complex_trans (*p));
db::Box new_vp = db::Box (t.inverted () * *v);
draw_boxes (drawing_context, new_ci, trans * t, new_vp, level + 1);
if (p.quad_id () > 0 && p.quad_id () != qid) {
qid = p.quad_id ();
// if the quad is very small we don't gain anything from looking further into the quad - skip this one
db::DBox qb = trans * cell_inst.quad_box (p, bc);
if (qb.width () < 1.0 && qb.height () < 1.0) {
p.skip_quad ();
continue;
}
}
++p;
}
}
@@ -986,7 +1002,6 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty
++inst;
}
}
}
@@ -1582,6 +1597,8 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_
db::Shape last_array;
size_t current_quad_id = 0;
size_t current_array_quad_id = 0;
db::ShapeIterator shape (shapes.begin_touching (*v, db::ShapeIterator::Boxes | db::ShapeIterator::Polygons | db::ShapeIterator::Edges | db::ShapeIterator::Paths, mp_prop_sel, m_inv_prop_sel));
while (! shape.at_end ()) {
@@ -1596,16 +1613,18 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_
}
if (skip) {
shape.skip_quad ();
continue;
}
} else {
if (shape.in_array ()) {
bool simplified = false;
if (shape.in_array () && last_array != shape.array ()) {
if (last_array != shape.array ()) {
last_array = shape.array ();
current_array_quad_id = 0;
bool simplified = false;
if (last_array.type () == db::Shape::PolygonPtrArray) {
simplified = draw_array_simplified<db::Shape::polygon_ptr_array_type> (mp_renderer.get (), last_array, frame, vertex, trans);
@@ -1619,17 +1638,42 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_
simplified = draw_array_simplified<db::Shape::short_box_array_type> (mp_renderer.get (), last_array, frame, vertex, trans);
}
if (simplified) {
shape.finish_array ();
// continue with the next shape, array or quad
continue;
}
}
if (simplified) {
shape.finish_array ();
} else {
mp_renderer->draw (*shape, trans, fill, frame, vertex, text);
++shape;
} else {
current_array_quad_id = 0;
}
// try whether the array quad can be simplified
size_t aqid = shape.array_quad_id ();
if (aqid != 0 && aqid != current_array_quad_id) {
current_array_quad_id = aqid;
db::DBox qbbox = trans * shape.array_quad_box ();
if (qbbox.width () < 1.5 && qbbox.height () < 1.5) {
// draw a single box instead of the quad
mp_renderer->draw (qbbox, fill, frame, vertex, text);
shape.skip_array_quad ();
// continue with the next shape, array or quad
continue;
}
}
mp_renderer->draw (*shape, trans, fill, frame, vertex, text);
++shape;
}
}
@@ -1727,7 +1771,9 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_
} else if (anything) {
for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ++p) {
size_t qid = 0;
for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ) {
if (! m_draw_array_border_instances ||
p.index_a () <= 0 || (unsigned long)p.index_a () == amax - 1 || p.index_b () <= 0 || (unsigned long)p.index_b () == bmax - 1) {
@@ -1736,6 +1782,21 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_
db::Box new_vp = db::Box (t.inverted () * *v);
draw_layer (from_level, to_level, new_ci, trans * t, new_vp, level + 1, fill, frame, vertex, text, update_snapshot);
if (p.quad_id () > 0 && p.quad_id () != qid) {
qid = p.quad_id ();
// if the quad is very small we don't gain anything from looking further into the quad - skip this one
db::DBox qb = trans * cell_inst.quad_box (p, bc);
if (qb.width () < 1.0 && qb.height () < 1.0) {
p.skip_quad ();
continue;
}
}
++p;
}
}
+28 -12
View File
@@ -128,12 +128,9 @@ TipDialog::no_pressed ()
accept ();
}
bool
TipDialog::do_exec_dialog (button_type *button)
static std::pair<bool, int>
tip_dialog_status (const std::string &key)
{
bool must_show = true;
mp_res = button;
std::string th;
if (lay::Dispatcher::instance ()) {
lay::Dispatcher::instance ()->config_get (cfg_tip_window_hidden, th);
@@ -148,20 +145,39 @@ TipDialog::do_exec_dialog (button_type *button)
}
int r = -1;
ex.test ("=") && ex.try_read (r);
if (k == m_key) {
if (r >= 0) {
*mp_res = button_type (r);
}
must_show = false;
break;
if (k == key) {
return std::make_pair (false, r);
}
ex.test (",");
}
if (must_show) {
return std::make_pair (true, -1);
}
bool
TipDialog::will_be_shown ()
{
return tip_dialog_status (m_key).first;
}
bool
TipDialog::do_exec_dialog (button_type *button)
{
mp_res = button;
std::string th;
if (lay::Dispatcher::instance ()) {
lay::Dispatcher::instance ()->config_get (cfg_tip_window_hidden, th);
}
std::pair<bool, int> td_status = tip_dialog_status (m_key);
if (td_status.first) {
exec ();
return true;
} else {
if (td_status.second >= 0) {
*mp_res = button_type (td_status.second);
}
return false;
}
}
+5
View File
@@ -65,6 +65,11 @@ public:
*/
~TipDialog ();
/**
* @brief Returns true, if the tip dialog will be shown
*/
bool will_be_shown ();
/**
* @brief Show the dialog
*
+4 -3
View File
@@ -600,15 +600,16 @@ LibrarySelectionComboBox::update_list ()
for (db::LibraryManager::iterator l = db::LibraryManager::instance ().begin (); l != db::LibraryManager::instance ().end (); ++l) {
db::Library *lib = db::LibraryManager::instance ().lib (l->second);
if (! m_tech_set || lib->get_technology ().empty () || m_tech == lib->get_technology ()) {
if (! m_tech_set || !lib->for_technologies ()|| lib->is_for_technology (m_tech)) {
std::string item_text = lib->get_name ();
if (! lib->get_description ().empty ()) {
item_text += " - " + lib->get_description ();
}
if (m_tech_set && !lib->get_technology ().empty ()) {
if (m_tech_set && lib->for_technologies ()) {
item_text += " ";
item_text += tl::to_string (QObject::tr ("[Technology %1]").arg (tl::to_qstring (lib->get_technology ())));
std::string tn = tl::join (std::vector<std::string> (lib->get_technologies ().begin (), lib->get_technologies ().end ()), ",");
item_text += tl::to_string (QObject::tr ("[Technology %1]").arg (tl::to_qstring (tn)));
}
addItem (tl::to_qstring (item_text), QVariant ((unsigned int) lib->get_id ()));
+2 -1
View File
@@ -185,7 +185,8 @@ SOURCES = \
layDispatcher.cc \
laySelectCellViewForm.cc \
layLayoutStatisticsForm.cc \
layD25TechnologyComponent.cc
layD25TechnologyComponent.cc \
gsiDeclLayNetlistBrowserDialog.cc
HEADERS = \
gtf.h \
@@ -44,90 +44,98 @@ TEST (1)
QModelIndex inv2Index = model->index (0, 0, QModelIndex ());
EXPECT_EQ (model->hasChildren (inv2Index), true);
// 4 subnodes
EXPECT_EQ (model->rowCount (inv2Index), 3);
// 5 pins, 5 nets, 0 subcircuits, 4 devices
EXPECT_EQ (model->rowCount (inv2Index), 14);
QModelIndex sn_pins = model->index (0, 0, inv2Index);
QModelIndex sn_nets = model->index (1, 0, inv2Index);
QModelIndex sn_devices = model->index (2, 0, inv2Index);
// Pins
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Index), Qt::UserRole).toString ()), "IN");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Index), Qt::DisplayRole).toString ()), "IN");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Index), Qt::DisplayRole).toString ()), "$1");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, inv2Index), Qt::DisplayRole).toString ()), "OUT");
EXPECT_EQ (tl::to_string (model->data (model->index (3, 0, inv2Index), Qt::DisplayRole).toString ()), "$3");
EXPECT_EQ (tl::to_string (model->data (model->index (4, 0, inv2Index), Qt::DisplayRole).toString ()), "$4");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::UserRole).toString ()), "IN|NIN");
EXPECT_EQ (model->parent (model->index (0, 0, sn_pins)) == model->parent (model->index (0, 3, sn_pins)), true);
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::DisplayRole).toString ()), "IN");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, sn_pins), Qt::DisplayRole).toString ()), "$1");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, sn_pins), Qt::DisplayRole).toString ()), "OUT");
EXPECT_EQ (tl::to_string (model->data (model->index (3, 0, sn_pins), Qt::DisplayRole).toString ()), "$3");
EXPECT_EQ (tl::to_string (model->data (model->index (4, 0, sn_pins), Qt::DisplayRole).toString ()), "$4");
// Nets
EXPECT_EQ (tl::to_string (model->data (model->index (5, 0, inv2Index), Qt::UserRole).toString ()), "NIN");
EXPECT_EQ (tl::to_string (model->data (model->index (5, 0, inv2Index), Qt::DisplayRole).toString ()), "NIN");
EXPECT_EQ (tl::to_string (model->data (model->index (5, 2, inv2Index), Qt::DisplayRole).toString ()), "NIN (3)");
EXPECT_EQ (tl::to_string (model->data (model->index (6, 0, inv2Index), Qt::DisplayRole).toString ()), "NOUT");
EXPECT_EQ (tl::to_string (model->data (model->index (6, 2, inv2Index), Qt::DisplayRole).toString ()), "NOUT (3)");
EXPECT_EQ (tl::to_string (model->data (model->index (7, 0, inv2Index), Qt::DisplayRole).toString ()), "$2");
EXPECT_EQ (tl::to_string (model->data (model->index (7, 2, inv2Index), Qt::DisplayRole).toString ()), "$2 (5)");
EXPECT_EQ (tl::to_string (model->data (model->index (8, 0, inv2Index), Qt::DisplayRole).toString ()), "$4");
EXPECT_EQ (tl::to_string (model->data (model->index (8, 2, inv2Index), Qt::DisplayRole).toString ()), "$4 (3)");
EXPECT_EQ (tl::to_string (model->data (model->index (9, 0, inv2Index), Qt::DisplayRole).toString ()), "$5");
EXPECT_EQ (tl::to_string (model->data (model->index (9, 2, inv2Index), Qt::DisplayRole).toString ()), "$5 (3)");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::UserRole).toString ()), "NIN");
EXPECT_EQ (model->parent (model->index (0, 0, sn_nets)) == model->parent (model->index (0, 3, sn_nets)), true);
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::DisplayRole).toString ()), "NIN");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_nets), Qt::DisplayRole).toString ()), "NIN (3)");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, sn_nets), Qt::DisplayRole).toString ()), "NOUT");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, sn_nets), Qt::DisplayRole).toString ()), "NOUT (3)");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, sn_nets), Qt::DisplayRole).toString ()), "$2");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, sn_nets), Qt::DisplayRole).toString ()), "$2 (5)");
EXPECT_EQ (tl::to_string (model->data (model->index (3, 0, sn_nets), Qt::DisplayRole).toString ()), "$4");
EXPECT_EQ (tl::to_string (model->data (model->index (3, 2, sn_nets), Qt::DisplayRole).toString ()), "$4 (3)");
EXPECT_EQ (tl::to_string (model->data (model->index (4, 0, sn_nets), Qt::DisplayRole).toString ()), "$5");
EXPECT_EQ (tl::to_string (model->data (model->index (4, 2, sn_nets), Qt::DisplayRole).toString ()), "$5 (3)");
// No Subcircuits
// Devices
EXPECT_EQ (tl::to_string (model->data (model->index (10, 0, inv2Index), Qt::UserRole).toString ()), "$1|PMOS");
EXPECT_EQ (tl::to_string (model->data (model->index (10, 0, inv2Index), Qt::DisplayRole).toString ()), "PMOS [L=0.25, W=0.95, AS=0.49875, AD=0.26125, PS=2.95, PD=1.5]");
EXPECT_EQ (tl::to_string (model->data (model->index (10, 2, inv2Index), Qt::DisplayRole).toString ()), "$1");
EXPECT_EQ (tl::to_string (model->data (model->index (11, 0, inv2Index), Qt::DisplayRole).toString ()), "PMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]");
EXPECT_EQ (tl::to_string (model->data (model->index (11, 2, inv2Index), Qt::DisplayRole).toString ()), "$2");
EXPECT_EQ (tl::to_string (model->data (model->index (12, 0, inv2Index), Qt::DisplayRole).toString ()), "NMOS [L=0.25, W=0.95, AS=0.49875, AD=0.26125, PS=2.95, PD=1.5]");
EXPECT_EQ (tl::to_string (model->data (model->index (12, 2, inv2Index), Qt::DisplayRole).toString ()), "$3");
EXPECT_EQ (tl::to_string (model->data (model->index (13, 0, inv2Index), Qt::DisplayRole).toString ()), "NMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]");
EXPECT_EQ (tl::to_string (model->data (model->index (13, 2, inv2Index), Qt::DisplayRole).toString ()), "$4");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_devices), Qt::UserRole).toString ()), "$1|PMOS");
EXPECT_EQ (model->parent (model->index (0, 0, sn_devices)) == model->parent (model->index (0, 3, sn_devices)), true);
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_devices), Qt::DisplayRole).toString ()), "PMOS [L=0.25, W=0.95, AS=0.49875, AD=0.26125, PS=2.95, PD=1.5]");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_devices), Qt::DisplayRole).toString ()), "$1");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, sn_devices), Qt::DisplayRole).toString ()), "PMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, sn_devices), Qt::DisplayRole).toString ()), "$2");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, sn_devices), Qt::DisplayRole).toString ()), "NMOS [L=0.25, W=0.95, AS=0.49875, AD=0.26125, PS=2.95, PD=1.5]");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, sn_devices), Qt::DisplayRole).toString ()), "$3");
EXPECT_EQ (tl::to_string (model->data (model->index (3, 0, sn_devices), Qt::DisplayRole).toString ()), "NMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]");
EXPECT_EQ (tl::to_string (model->data (model->index (3, 2, sn_devices), Qt::DisplayRole).toString ()), "$4");
EXPECT_EQ (model->hasChildren (ringoIndex), true);
// 0 pins, 12 nets, 10 subcircuits, 0 devices
EXPECT_EQ (model->rowCount (ringoIndex), 22);
EXPECT_EQ (model->rowCount (ringoIndex), 2);
sn_nets = model->index (0, 0, ringoIndex);
QModelIndex sn_subcircuits = model->index (1, 0, ringoIndex);
// Pins
// Nets
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoIndex), Qt::UserRole).toString ()), "FB");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, ringoIndex), Qt::DisplayRole).toString ()), "FB (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, ringoIndex), Qt::DisplayRole).toString ()), "VDD (10)");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, ringoIndex), Qt::DisplayRole).toString ()), "VSS (10)");
EXPECT_EQ (tl::to_string (model->data (model->index (3, 2, ringoIndex), Qt::DisplayRole).toString ()), "$4 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (4, 2, ringoIndex), Qt::DisplayRole).toString ()), "$5 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (5, 2, ringoIndex), Qt::DisplayRole).toString ()), "$6 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (6, 2, ringoIndex), Qt::DisplayRole).toString ()), "$7 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (7, 2, ringoIndex), Qt::DisplayRole).toString ()), "$8 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (8, 2, ringoIndex), Qt::DisplayRole).toString ()), "$9 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (9, 2, ringoIndex), Qt::DisplayRole).toString ()), "$10 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (10, 2, ringoIndex), Qt::DisplayRole).toString ()), "$11 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (11, 2, ringoIndex), Qt::DisplayRole).toString ()), "$12 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::UserRole).toString ()), "FB");
EXPECT_EQ (model->parent (model->index (0, 0, sn_nets)) == model->parent (model->index (0, 3, sn_nets)), true);
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_nets), Qt::DisplayRole).toString ()), "FB (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, sn_nets), Qt::DisplayRole).toString ()), "VDD (10)");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, sn_nets), Qt::DisplayRole).toString ()), "VSS (10)");
EXPECT_EQ (tl::to_string (model->data (model->index (3, 2, sn_nets), Qt::DisplayRole).toString ()), "$4 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (4, 2, sn_nets), Qt::DisplayRole).toString ()), "$5 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (5, 2, sn_nets), Qt::DisplayRole).toString ()), "$6 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (6, 2, sn_nets), Qt::DisplayRole).toString ()), "$7 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (7, 2, sn_nets), Qt::DisplayRole).toString ()), "$8 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (8, 2, sn_nets), Qt::DisplayRole).toString ()), "$9 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (9, 2, sn_nets), Qt::DisplayRole).toString ()), "$10 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (10, 2, sn_nets), Qt::DisplayRole).toString ()), "$11 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (11, 2, sn_nets), Qt::DisplayRole).toString ()), "$12 (2)");
// Subcircuits
EXPECT_EQ (tl::to_string (model->data (model->index (12, 0, ringoIndex), Qt::UserRole).toString ()), "INV2|$1");
EXPECT_EQ (tl::to_string (model->data (model->index (12, 0, ringoIndex), Qt::DisplayRole).toString ()), "<a href='int:circuit?id=0'>INV2</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (12, 2, ringoIndex), Qt::DisplayRole).toString ()), "$1");
EXPECT_EQ (tl::to_string (model->data (model->index (21, 0, ringoIndex), Qt::DisplayRole).toString ()), "<a href='int:circuit?id=0'>INV2</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (21, 2, ringoIndex), Qt::DisplayRole).toString ()), "$10");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_subcircuits), Qt::UserRole).toString ()), "INV2|$1");
EXPECT_EQ (model->parent (model->index (0, 0, sn_subcircuits)) == model->parent (model->index (0, 3, sn_subcircuits)), true);
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_subcircuits), Qt::DisplayRole).toString ()), "<a href='int:netlist?path=0'>INV2</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_subcircuits), Qt::DisplayRole).toString ()), "$1");
EXPECT_EQ (tl::to_string (model->data (model->index (9, 0, sn_subcircuits), Qt::DisplayRole).toString ()), "<a href='int:netlist?path=0'>INV2</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (9, 2, sn_subcircuits), Qt::DisplayRole).toString ()), "$10");
// Devices
// OUT pin of INV2 has a single child node which is the "NOUT" net
QModelIndex inv2PinOutIndex = model->index (2, 0, inv2Index);
EXPECT_EQ (model->parent (inv2PinOutIndex) == inv2Index, true);
// OUT pin of INV2 is identical with the "NOUT" net
QModelIndex inv2PinOutIndex = model->index (2, 0, model->index (0, 0, inv2Index));
EXPECT_EQ (model->parent (inv2PinOutIndex) == model->index (0, 0, inv2Index), true);
EXPECT_EQ (model->hasChildren (inv2PinOutIndex), true);
EXPECT_EQ (model->rowCount (inv2PinOutIndex), 1);
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PinOutIndex), Qt::DisplayRole).toString ()), "NOUT");
QModelIndex inv2PinOutIndexNet = model->index (0, 0, inv2PinOutIndex);
EXPECT_EQ (model->parent (inv2PinOutIndexNet) == inv2PinOutIndex, true);
EXPECT_EQ (model->hasChildren (inv2PinOutIndexNet), false);
EXPECT_EQ (model->rowCount (inv2PinOutIndexNet), 0);
EXPECT_EQ (model->rowCount (inv2PinOutIndex), 3);
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PinOutIndex), Qt::DisplayRole).toString ()), "D / PMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]");
// NOUT net has 1 pin, 2 devices, 0 subcircuits
QModelIndex inv2NOutIndex = model->index (6, 0, inv2Index);
EXPECT_EQ (model->parent (inv2NOutIndex) == inv2Index, true);
QModelIndex inv2NOutIndex = model->index (1, 0, model->index (1, 0, inv2Index));
EXPECT_EQ (model->parent (inv2NOutIndex) == model->index (1, 0, inv2Index), true);
EXPECT_EQ (model->hasChildren (inv2NOutIndex), true);
EXPECT_EQ (model->rowCount (inv2NOutIndex), 3);
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2NOutIndex), Qt::UserRole).toString ()), "D|PMOS|$2");
EXPECT_EQ (model->parent (model->index (0, 0, inv2NOutIndex)) == model->parent (model->index (0, 3, inv2NOutIndex)), true);
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2NOutIndex), Qt::DisplayRole).toString ()), "D / PMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2NOutIndex), Qt::DisplayRole).toString ()), "<a href='int:device?id=24'>$2</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2NOutIndex), Qt::DisplayRole).toString ()), "$2");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2NOutIndex), Qt::DisplayRole).toString ()), "D / NMOS [L=0.25, W=0.95, AS=0.26125, AD=0.49875, PS=1.5, PD=2.95]");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2NOutIndex), Qt::DisplayRole).toString ()), "<a href='int:device?id=56'>$4</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, inv2NOutIndex), Qt::DisplayRole).toString ()), "<a href='int:pin?id=18'>OUT</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2NOutIndex), Qt::DisplayRole).toString ()), "$4");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, inv2NOutIndex), Qt::DisplayRole).toString ()), "OUT");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, inv2NOutIndex), Qt::DisplayRole).toString ()), "");
EXPECT_EQ (model->parent (model->index (2, 0, inv2NOutIndex)) == model->parent (model->index (2, 3, inv2NOutIndex)), true);
// no children for pins on nets
QModelIndex inv2NOutPinOutIndex = model->index (2, 0, inv2NOutIndex);
@@ -137,6 +145,9 @@ TEST (1)
// a MOS3 transistor has three other terminals
QModelIndex inv2NOutDeviceIndex = model->index (0, 0, inv2NOutIndex);
QModelIndex b = model->index (0, 0, inv2NOutIndex);
EXPECT_EQ (b.parent () == inv2NOutDeviceIndex.parent (), true);
EXPECT_EQ (b.model () == inv2NOutDeviceIndex.model (), true);
EXPECT_EQ (model->parent (inv2NOutDeviceIndex) == inv2NOutIndex, true);
EXPECT_EQ (model->hasChildren (inv2NOutDeviceIndex), true);
EXPECT_EQ (model->rowCount (inv2NOutDeviceIndex), 3);
@@ -144,67 +155,76 @@ TEST (1)
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2NOutDeviceIndex), Qt::UserRole).toString ()), "S|$5");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2NOutDeviceIndex), Qt::DisplayRole).toString ()), "S");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2NOutDeviceIndex), Qt::DisplayRole).toString ()), "G");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, inv2NOutDeviceIndex), Qt::DisplayRole).toString ()), "D");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, inv2NOutDeviceIndex), Qt::DisplayRole).toString ()), "D (already seen)");
QModelIndex inv2NOutDeviceGateIndex = model->index (1, 0, inv2NOutDeviceIndex);
EXPECT_EQ (model->parent (inv2NOutDeviceGateIndex) == inv2NOutDeviceIndex, true);
EXPECT_EQ (model->hasChildren (inv2NOutDeviceGateIndex), false);
EXPECT_EQ (model->rowCount (inv2NOutDeviceGateIndex), 0);
EXPECT_EQ (model->hasChildren (inv2NOutDeviceGateIndex), true);
EXPECT_EQ (model->rowCount (inv2NOutDeviceGateIndex), 5);
// FB net has 0 pin, 0 devices, 2 subcircuits
QModelIndex ringoFbIndex = model->index (0, 0, ringoIndex);
EXPECT_EQ (model->parent (ringoFbIndex) == ringoIndex, true);
QModelIndex ringoFbIndex = model->index (0, 0, sn_nets);
EXPECT_EQ (model->parent (ringoFbIndex) == sn_nets, true);
EXPECT_EQ (model->hasChildren (ringoFbIndex), true);
EXPECT_EQ (model->rowCount (ringoFbIndex), 2);
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbIndex), Qt::UserRole).toString ()), "IN|INV2|$2");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbIndex), Qt::DisplayRole).toString ()), "<a href='int:pin?id=2'>IN</a> / <a href='int:circuit?id=0'>INV2</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, ringoFbIndex), Qt::DisplayRole).toString ()), "<a href='int:subcircuit?id=23'>$2</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoFbIndex), Qt::DisplayRole).toString ()), "<a href='int:pin?id=34'>$1</a> / <a href='int:circuit?id=0'>INV2</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, ringoFbIndex), Qt::DisplayRole).toString ()), "<a href='int:subcircuit?id=7'>$1</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbIndex), Qt::DisplayRole).toString ()), "IN / <a href='int:netlist?path=0'>INV2</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, ringoFbIndex), Qt::DisplayRole).toString ()), "<a href='int:netlist?path=1,1,1'>$2</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoFbIndex), Qt::DisplayRole).toString ()), "$1 / <a href='int:netlist?path=0'>INV2</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, ringoFbIndex), Qt::DisplayRole).toString ()), "<a href='int:netlist?path=1,1,0'>$1</a>");
QModelIndex ringoFbSubcircuit2Index = model->index (0, 0, ringoFbIndex);
EXPECT_EQ (model->parent (ringoFbSubcircuit2Index) == ringoFbIndex, true);
EXPECT_EQ (model->hasChildren (ringoFbSubcircuit2Index), true);
EXPECT_EQ (model->rowCount (ringoFbSubcircuit2Index), 5);
EXPECT_EQ (model->rowCount (ringoFbSubcircuit2Index), 1);
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbSubcircuit2Index), Qt::UserRole).toString ()), "IN|NIN");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=2'>IN</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:net?id=5'>FB</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=34'>$1</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=18'>OUT</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:net?id=53'>$4</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (3, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=50'>$3</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (3, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:net?id=37'>VSS</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (4, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=66'>$4</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (4, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "<a href='int:net?id=21'>VDD</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbSubcircuit2Index), Qt::UserRole).toString ()), "NIN");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "NIN");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, ringoFbSubcircuit2Index), Qt::DisplayRole).toString ()), "NIN (3)");
QModelIndex ringoFbSubcircuit2InPinIndex = model->index (1, 0, ringoFbSubcircuit2Index);
EXPECT_EQ (model->parent (ringoFbSubcircuit2InPinIndex) == ringoFbSubcircuit2Index, true);
EXPECT_EQ (model->hasChildren (ringoFbSubcircuit2InPinIndex), false);
EXPECT_EQ (model->rowCount (ringoFbSubcircuit2InPinIndex), 0);
QModelIndex ringoFbSubcircuit2InsideNetIndex = model->index (0, 0, ringoFbSubcircuit2Index);
EXPECT_EQ (model->parent (ringoFbSubcircuit2InsideNetIndex) == ringoFbSubcircuit2Index, true);
EXPECT_EQ (model->hasChildren (ringoFbSubcircuit2InsideNetIndex), true);
EXPECT_EQ (model->rowCount (ringoFbSubcircuit2InsideNetIndex), 3);
// Subcircuit 1 of RINGO has 5 pins
QModelIndex ringoSubcircuit1Index = model->index (12, 0, ringoIndex);
EXPECT_EQ (model->parent (ringoSubcircuit1Index) == ringoIndex, true);
QModelIndex ringoSubcircuit1Index = model->index (0, 0, sn_subcircuits);
EXPECT_EQ (model->parent (ringoSubcircuit1Index) == sn_subcircuits, true);
EXPECT_EQ (model->hasChildren (ringoSubcircuit1Index), true);
EXPECT_EQ (model->rowCount (ringoSubcircuit1Index), 5);
EXPECT_EQ (model->rowCount (ringoSubcircuit1Index), 2);
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1Index), Qt::UserRole).toString ()), "OUT");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=18'>OUT</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, ringoSubcircuit1Index), Qt::DisplayRole).toString ()), "");
QModelIndex ringoSubcircuit1PinsIndex = model->index (0, 0, ringoSubcircuit1Index);
EXPECT_EQ (model->rowCount (ringoSubcircuit1PinsIndex), 5);
QModelIndex ringoSubcircuit1OutPinIndex = model->index (2, 0, ringoSubcircuit1Index);
EXPECT_EQ (model->parent (ringoSubcircuit1OutPinIndex) == ringoSubcircuit1Index, true);
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoSubcircuit1PinsIndex), Qt::UserRole).toString ()), "IN|$5");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoSubcircuit1PinsIndex), Qt::UserRole).toString ()), "FB");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1PinsIndex), Qt::UserRole).toString ()), "OUT");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1PinsIndex), Qt::DisplayRole).toString ()), "OUT");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, ringoSubcircuit1PinsIndex), Qt::DisplayRole).toString ()), "");
QModelIndex ringoSubcircuit1NodeIndex = model->index (1, 0, ringoSubcircuit1Index);
EXPECT_EQ (model->rowCount (ringoSubcircuit1NodeIndex), 3);
QModelIndex ringoSubcircuit1InsidePinsIndex = model->index (0, 0, ringoSubcircuit1NodeIndex);
EXPECT_EQ (model->rowCount (ringoSubcircuit1InsidePinsIndex), 5);
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, ringoSubcircuit1InsidePinsIndex), Qt::UserRole).toString ()), "IN|NIN");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, ringoSubcircuit1InsidePinsIndex), Qt::UserRole).toString ()), "$1|$2");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1InsidePinsIndex), Qt::UserRole).toString ()), "OUT|NOUT");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, ringoSubcircuit1InsidePinsIndex), Qt::DisplayRole).toString ()), "OUT");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 2, ringoSubcircuit1InsidePinsIndex), Qt::DisplayRole).toString ()), "NOUT (3)");
QModelIndex ringoSubcircuit1OutPinIndex = model->index (2, 0, ringoSubcircuit1PinsIndex);
EXPECT_EQ (model->parent (ringoSubcircuit1OutPinIndex) == ringoSubcircuit1PinsIndex, true);
EXPECT_EQ (model->hasChildren (ringoSubcircuit1OutPinIndex), false);
EXPECT_EQ (model->rowCount (ringoSubcircuit1OutPinIndex), 0);
// Device 1 of INV2 has 3 pins
// Device 1 of INV2 has 3 terminals
QModelIndex inv2Device1Index = model->index (10, 0, inv2Index);
EXPECT_EQ (model->parent (inv2Device1Index) == inv2Index, true);
QModelIndex inv2Device1Index = model->index (0, 0, sn_devices);
EXPECT_EQ (model->parent (inv2Device1Index) == sn_devices, true);
EXPECT_EQ (model->hasChildren (inv2Device1Index), true);
EXPECT_EQ (model->rowCount (inv2Device1Index), 3);
@@ -213,8 +233,11 @@ TEST (1)
QModelIndex inv2Device1GateIndex = model->index (1, 0, inv2Device1Index);
EXPECT_EQ (model->parent (inv2Device1GateIndex) == inv2Device1Index, true);
EXPECT_EQ (model->hasChildren (inv2Device1GateIndex), false);
EXPECT_EQ (model->rowCount (inv2Device1GateIndex), 0);
EXPECT_EQ (model->hasChildren (inv2Device1GateIndex), true);
EXPECT_EQ (model->rowCount (inv2Device1GateIndex), 3);
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Device1GateIndex), Qt::UserRole).toString ()), "G|PMOS|$1");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Device1GateIndex), Qt::DisplayRole).toString ()), "G / PMOS [L=0.25, W=0.95, AS=0.49875, AD=0.26125, PS=2.95, PD=1.5] (already seen)");
}
TEST (2)
@@ -228,6 +251,7 @@ TEST (2)
EXPECT_EQ (model->hasChildren (QModelIndex ()), true);
// two circuits
EXPECT_EQ (model->rowCount (QModelIndex ()), 4);
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, QModelIndex ()), Qt::UserRole).toString ()), "INV2PAIRX");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, QModelIndex ()), Qt::DisplayRole).toString ()), "- ⇔ INV2PAIRX");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, QModelIndex ()), Qt::DisplayRole).toString ()), "");
@@ -245,26 +269,33 @@ TEST (2)
// INV2 circuit node
EXPECT_EQ (model->hasChildren (inv2Index), true);
EXPECT_EQ (model->rowCount (inv2Index), 14);
EXPECT_EQ (model->rowCount (inv2Index), 3);
EXPECT_EQ (model->parent (inv2Index).isValid (), false);
QModelIndex sn_pins = model->index (0, 0, inv2Index);
QModelIndex sn_nets = model->index (1, 0, inv2Index);
QModelIndex sn_devices = model->index (2, 0, inv2Index);
EXPECT_EQ (model->rowCount (sn_pins), 6);
EXPECT_EQ (model->rowCount (sn_nets), 6);
EXPECT_EQ (model->rowCount (sn_devices), 2);
// first of pins in INV2 circuit
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Index), Qt::UserRole).toString ()), "$0|$0");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Index), Qt::DisplayRole).toString ()), "$0");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2Index), Qt::DisplayRole).toString ()), "$0");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2Index), Qt::DisplayRole).toString ()), "$0");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::UserRole).toString ()), "$0|$0|$1|1");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::DisplayRole).toString ()), "$0");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_pins), Qt::DisplayRole).toString ()), "$1 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_pins), Qt::DisplayRole).toString ()), "1 (2)");
// INV2, pin 0 node
QModelIndex inv2Pin0Index = model->index (0, 0, inv2Index);
QModelIndex inv2Pin0Index = model->index (0, 0, sn_pins);
EXPECT_EQ (model->hasChildren (inv2Pin0Index), true);
EXPECT_EQ (model->rowCount (inv2Pin0Index), 1);
EXPECT_EQ (model->parent (inv2Pin0Index) == inv2Index, true);
EXPECT_EQ (model->rowCount (inv2Pin0Index), 2);
EXPECT_EQ (model->parent (inv2Pin0Index) == sn_pins, true);
// INV2, pin 0 has one net node
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Pin0Index), Qt::UserRole).toString ()), "$1|1");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Pin0Index), Qt::DisplayRole).toString ()), "$1 ⇔ 1");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2Pin0Index), Qt::DisplayRole).toString ()), "<a href='int:net?id=9'>$1</a>");
std::pair<const db::Net *, const db::Net *> nets = model->net_from_index (model->index_from_id ((void *) 9, 0));
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::UserRole).toString ()), "$0|$0|$1|1");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::DisplayRole).toString ()), "$0");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_pins), Qt::DisplayRole).toString ()), "$1 (2)");
std::pair<const db::Net *, const db::Net *> nets = model->net_from_index (model->index (0, 0, sn_pins));
EXPECT_EQ (nets.first != 0, true);
if (nets.first != 0) {
EXPECT_EQ (nets.first->expanded_name (), "$1");
@@ -273,25 +304,25 @@ TEST (2)
if (nets.second != 0) {
EXPECT_EQ (nets.second->expanded_name (), "1");
}
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2Pin0Index), Qt::DisplayRole).toString ()), "<a href='int:net?id=9'>1</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_pins), Qt::DisplayRole).toString ()), "1 (2)");
// first of nets in INV2 circuit
EXPECT_EQ (tl::to_string (model->data (model->index (6, 0, inv2Index), Qt::UserRole).toString ()), "$1|1");
EXPECT_EQ (tl::to_string (model->data (model->index (6, 0, inv2Index), Qt::DisplayRole).toString ()), "$1 ⇔ 1");
EXPECT_EQ (tl::to_string (model->data (model->index (6, 2, inv2Index), Qt::DisplayRole).toString ()), "$1 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (6, 3, inv2Index), Qt::DisplayRole).toString ()), "1 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::UserRole).toString ()), "$1|1");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::DisplayRole).toString ()), "$1 ⇔ 1");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_nets), Qt::DisplayRole).toString ()), "$1 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_nets), Qt::DisplayRole).toString ()), "1 (2)");
// INV2, net 1 node
QModelIndex inv2Net0Index = model->index (6, 0, inv2Index);
QModelIndex inv2Net0Index = model->index (0, 0, sn_nets);
EXPECT_EQ (model->hasChildren (inv2Net0Index), true);
EXPECT_EQ (model->rowCount (inv2Net0Index), 2);
EXPECT_EQ (model->parent (inv2Net0Index) == inv2Index, true);
EXPECT_EQ (model->parent (inv2Net0Index) == sn_nets, true);
// INV2, net 1 has one pin and one terminal at BULK
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Net0Index), Qt::UserRole).toString ()), "B|B|PMOS|PMOS|$1|$1");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Net0Index), Qt::DisplayRole).toString ()), "B / PMOS [L=0.25, W=3.5]");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2Net0Index), Qt::DisplayRole).toString ()), "<a href='int:device?id=17'>$1</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2Net0Index), Qt::DisplayRole).toString ()), "<a href='int:device?id=17'>$1</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2Net0Index), Qt::DisplayRole).toString ()), "$1");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2Net0Index), Qt::DisplayRole).toString ()), "$1");
// This terminal connects to a device with four other terminals ..
QModelIndex inv2Net0TerminalIndex = model->index (0, 0, inv2Net0Index);
@@ -301,14 +332,14 @@ TEST (2)
// .. whose second terminal is gate
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0TerminalIndex), Qt::UserRole).toString ()), "G|G|IN|2");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "G");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "<a href='int:net?id=73'>IN</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "<a href='int:net?id=73'>2</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "IN (3)");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, inv2Net0TerminalIndex), Qt::DisplayRole).toString ()), "2 (3)");
// The Pin
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0Index), Qt::UserRole).toString ()), "");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2Net0Index), Qt::DisplayRole).toString ()), "");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2Net0Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=5'>$0</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, inv2Net0Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=5'>$0</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2Net0Index), Qt::DisplayRole).toString ()), "$0");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, inv2Net0Index), Qt::DisplayRole).toString ()), "$0");
// This pin does not have children
QModelIndex inv2Net0PinIndex = model->index (1, 0, inv2Net0Index);
@@ -317,59 +348,49 @@ TEST (2)
EXPECT_EQ (model->parent (inv2Net0PinIndex) == inv2Net0Index, true);
// second of nets in INV2 circuit
EXPECT_EQ (tl::to_string (model->data (model->index (7, 0, inv2Index), Qt::UserRole).toString ()), "BULK|6");
EXPECT_EQ (tl::to_string (model->data (model->index (7, 0, inv2Index), Qt::DisplayRole).toString ()), "BULK ⇔ 6");
EXPECT_EQ (tl::to_string (model->data (model->index (7, 2, inv2Index), Qt::DisplayRole).toString ()), "BULK (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (7, 3, inv2Index), Qt::DisplayRole).toString ()), "6 (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, sn_nets), Qt::UserRole).toString ()), "BULK|6");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, sn_nets), Qt::DisplayRole).toString ()), "BULK ⇔ 6");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, sn_nets), Qt::DisplayRole).toString ()), "BULK (2)");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, sn_nets), Qt::DisplayRole).toString ()), "6 (2)");
// first of devices in INV2 circuit
EXPECT_EQ (tl::to_string (model->data (model->index (12, 0, inv2Index), Qt::UserRole).toString ()), "$1|$1|PMOS|PMOS");
EXPECT_EQ (tl::to_string (model->data (model->index (12, 0, inv2Index), Qt::DisplayRole).toString ()), "PMOS");
EXPECT_EQ (tl::to_string (model->data (model->index (12, 2, inv2Index), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5]");
EXPECT_EQ (tl::to_string (model->data (model->index (12, 3, inv2Index), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5]");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_devices), Qt::UserRole).toString ()), "$1|$1|PMOS|PMOS");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_devices), Qt::DisplayRole).toString ()), "PMOS");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_devices), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5]");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_devices), Qt::DisplayRole).toString ()), "$1 / PMOS [L=0.25, W=3.5]");
QModelIndex inv2PairIndex = model->index (2, 0, QModelIndex ());
EXPECT_EQ (model->parent (inv2PairIndex).isValid (), false);
// INV2PAIR circuit node
EXPECT_EQ (model->hasChildren (inv2PairIndex), true);
EXPECT_EQ (model->rowCount (inv2PairIndex), 18);
EXPECT_EQ (model->rowCount (inv2PairIndex), 3);
sn_pins = model->index (0, 0, inv2PairIndex);
sn_nets = model->index (1, 0, inv2PairIndex);
// first of pins in INV2 circuit
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairIndex), Qt::UserRole).toString ()), "$4");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairIndex), Qt::DisplayRole).toString ()), "- ⇔ $4");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2PairIndex), Qt::DisplayRole).toString ()), "");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2PairIndex), Qt::DisplayRole).toString ()), "$4");
// INV2, pin 0 node
QModelIndex inv2PairPin0Index = model->index (0, 0, inv2PairIndex);
EXPECT_EQ (model->hasChildren (inv2PairPin0Index), true);
EXPECT_EQ (model->rowCount (inv2PairPin0Index), 1);
EXPECT_EQ (model->parent (inv2PairPin0Index) == inv2PairIndex, true);
// INV2, pin 0 has one net node
// The pin isnt't connected to any net, left side because there is no match, right side because the pin isn't connected
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairPin0Index), Qt::UserRole).toString ()), "");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairPin0Index), Qt::DisplayRole).toString ()), "-");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2PairPin0Index), Qt::DisplayRole).toString ()), "");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2PairPin0Index), Qt::DisplayRole).toString ()), "");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::UserRole).toString ()), "$4");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_pins), Qt::DisplayRole).toString ()), "- ⇔ $4");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_pins), Qt::DisplayRole).toString ()), "");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_pins), Qt::DisplayRole).toString ()), "");
// first of nets in INV2 circuit
EXPECT_EQ (tl::to_string (model->data (model->index (8, 0, inv2PairIndex), Qt::UserRole).toString ()), "$4");
EXPECT_EQ (tl::to_string (model->data (model->index (8, 0, inv2PairIndex), Qt::DisplayRole).toString ()), "$4 ⇔ -");
EXPECT_EQ (tl::to_string (model->data (model->index (8, 2, inv2PairIndex), Qt::DisplayRole).toString ()), "$4 (3)");
EXPECT_EQ (tl::to_string (model->data (model->index (8, 3, inv2PairIndex), Qt::DisplayRole).toString ()), "");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::UserRole).toString ()), "$4");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, sn_nets), Qt::DisplayRole).toString ()), "$4 ⇔ -");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, sn_nets), Qt::DisplayRole).toString ()), "$4 (3)");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, sn_nets), Qt::DisplayRole).toString ()), "");
// This net has only left side which has one pin and two subcircuits
QModelIndex inv2PairNet0Index = model->index (8, 0, inv2PairIndex);
QModelIndex inv2PairNet0Index = model->index (0, 0, sn_nets);
EXPECT_EQ (model->hasChildren (inv2PairNet0Index), true);
EXPECT_EQ (model->rowCount (inv2PairNet0Index), 3);
EXPECT_EQ (model->parent (inv2PairNet0Index) == inv2PairIndex, true);
EXPECT_EQ (model->parent (inv2PairNet0Index) == sn_nets, true);
// The pin
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairNet0Index), Qt::UserRole).toString ()), "");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairNet0Index), Qt::DisplayRole).toString ()), "");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2PairNet0Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=38'>$3</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2PairNet0Index), Qt::DisplayRole).toString ()), "$3");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2PairNet0Index), Qt::DisplayRole).toString ()), "");
// This pin does not have children
@@ -380,18 +401,179 @@ TEST (2)
// The first subcircuit
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2PairNet0Index), Qt::UserRole).toString ()), "OUT|INV2|$1");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2PairNet0Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=101'>OUT ⇔ -</a> / <a href='int:circuit?id=1'>INV2 ⇔ -</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2PairNet0Index), Qt::DisplayRole).toString ()), "<a href='int:subcircuit?id=46'>$1</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, inv2PairNet0Index), Qt::DisplayRole).toString ()), "OUT ⇔ - / <a href='int:netlist?path=1'>INV2 ⇔ -</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, inv2PairNet0Index), Qt::DisplayRole).toString ()), "<a href='int:netlist?path=2,2,1'>$1</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 3, inv2PairNet0Index), Qt::DisplayRole).toString ()), "");
// This subcircuit has 6 other pins
QModelIndex inv2PairNet0SubCircuit0Index = model->index (1, 0, inv2PairNet0Index);
EXPECT_EQ (model->hasChildren (inv2PairNet0SubCircuit0Index), true);
EXPECT_EQ (model->rowCount (inv2PairNet0SubCircuit0Index), 6);
EXPECT_EQ (model->parent (inv2PairNet0SubCircuit0Index) == inv2PairNet0Index, true);
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairNet0SubCircuit0Index), Qt::UserRole).toString ()), "$1");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2PairNet0SubCircuit0Index), Qt::DisplayRole).toString ()), "<a href='int:pin?id=5'>$0</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, inv2PairNet0SubCircuit0Index), Qt::DisplayRole).toString ()), "<a href='int:net?id=170'>$7</a>");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 3, inv2PairNet0SubCircuit0Index), Qt::DisplayRole).toString ()), "");
}
TEST (3)
{
db::LayoutToNetlist l2n;
l2n.load (tl::testsrc () + "/testdata/lay/l2n_browser.l2n");
lay::NetColorizer colorizer;
std::auto_ptr<lay::NetlistBrowserModel> model (new lay::NetlistBrowserModel (0, &l2n, &colorizer));
db::Circuit *root = l2n.netlist ()->circuit_by_name ("RINGO");
EXPECT_EQ (root != 0, true);
lay::NetlistObjectsPath path;
EXPECT_EQ (model->index_from_path (path).isValid (), false);
path.root.first = root;
db::Net *net = root->net_by_name ("FB");
EXPECT_EQ (net != 0, true);
path.net.first = net;
QModelIndex index = model->index_from_path (path);
EXPECT_EQ (index.isValid (), true);
EXPECT_EQ (tl::to_string (model->data (index, Qt::UserRole).toString ()), "FB");
}
TEST (4)
{
db::LayoutToNetlist l2n;
l2n.load (tl::testsrc () + "/testdata/lay/l2n_browser.l2n");
lay::NetColorizer colorizer;
std::auto_ptr<lay::NetlistBrowserModel> model (new lay::NetlistBrowserModel (0, &l2n, &colorizer));
db::Circuit *root = l2n.netlist ()->circuit_by_name ("RINGO");
EXPECT_EQ (root != 0, true);
lay::NetlistObjectsPath path;
path.root.first = root;
db::SubCircuit *sc1 = root->begin_subcircuits ().operator-> ();
EXPECT_EQ (sc1 != 0, true);
path.path.push_back (std::make_pair (sc1, (db::SubCircuit *) 0));
db::Net *net = sc1->circuit_ref ()->net_by_name ("NOUT");
EXPECT_EQ (net != 0, true);
path.net.first = net;
QModelIndex index = model->index_from_path (path);
EXPECT_EQ (index.isValid (), true);
EXPECT_EQ (tl::to_string (model->data (index, Qt::UserRole).toString ()), "NOUT");
}
// Netlist object path: single vs. pairs - first
TEST (5)
{
db::LayoutVsSchematic lvs;
lvs.load (tl::testsrc () + "/testdata/lay/lvsdb_browser.lvsdb");
lay::NetColorizer colorizer;
std::auto_ptr<lay::NetlistBrowserModel> model (new lay::NetlistBrowserModel (0, &lvs, &colorizer));
QModelIndex idx;
db::Circuit *root = lvs.netlist ()->circuit_by_name ("INV2PAIR");
EXPECT_EQ (root != 0, true);
db::Circuit *sc = lvs.netlist ()->circuit_by_name ("INV2");
EXPECT_EQ (sc != 0, true);
lay::NetlistObjectPath path;
EXPECT_EQ (path.is_null (), true);
path.root = root;
EXPECT_EQ (path.is_null (), false);
idx = model->index_from_path (path);
EXPECT_EQ (idx.isValid (), true);
EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "INV2PAIR|INV2PAIR");
EXPECT_EQ (path == model->path_from_index (idx).first (), true);
path.net = root->net_by_cluster_id (5);
idx = model->index_from_path (lay::NetlistObjectsPath::from_first (path));
EXPECT_EQ (idx.isValid (), true);
EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "$5|4");
EXPECT_EQ (path == model->path_from_index (idx).first (), true);
path.path.push_back (root->subcircuit_by_id (1));
EXPECT_EQ (path.path.back () != 0, true);
EXPECT_EQ (path.path.back ()->expanded_name (), "$1");
EXPECT_EQ (path.path.back ()->circuit_ref ()->name (), "INV2");
path.net = 0;
idx = model->index_from_path (lay::NetlistObjectsPath::from_first (path));
EXPECT_EQ (idx.isValid (), true);
// A pure subcircuit path addresses the "Circuit" representative node of the subcircuit
EXPECT_EQ (tl::to_string (model->data (idx, Qt::DisplayRole).toString ()), "Circuit");
EXPECT_EQ (tl::to_string (model->data (model->parent (idx), Qt::UserRole).toString ()), "INV2|$1");
EXPECT_EQ (path == model->path_from_index (idx).first (), true);
path.net = sc->net_by_cluster_id (2);
idx = model->index_from_path (lay::NetlistObjectsPath::from_first (path));
EXPECT_EQ (idx.isValid (), true);
EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "IN|2");
EXPECT_EQ (path == model->path_from_index (idx).first (), true);
path.net = 0;
path.device = sc->device_by_id (1);
idx = model->index_from_path (lay::NetlistObjectsPath::from_first (path));
EXPECT_EQ (idx.isValid (), true);
EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "$1|$1|PMOS|PMOS");
EXPECT_EQ (path == model->path_from_index (idx).first (), true);
}
// Netlist object path: single vs. pairs - second
TEST (6)
{
db::LayoutVsSchematic lvs;
lvs.load (tl::testsrc () + "/testdata/lay/lvsdb_browser.lvsdb");
lay::NetColorizer colorizer;
std::auto_ptr<lay::NetlistBrowserModel> model (new lay::NetlistBrowserModel (0, &lvs, &colorizer));
QModelIndex idx;
db::Circuit *root = lvs.reference_netlist ()->circuit_by_name ("INV2PAIR");
EXPECT_EQ (root != 0, true);
db::Circuit *sc = lvs.reference_netlist ()->circuit_by_name ("INV2");
EXPECT_EQ (sc != 0, true);
lay::NetlistObjectPath path;
EXPECT_EQ (path.is_null (), true);
path.root = root;
EXPECT_EQ (path.is_null (), false);
idx = model->index_from_path (lay::NetlistObjectsPath::from_second (path));
EXPECT_EQ (idx.isValid (), true);
EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "INV2PAIR|INV2PAIR");
EXPECT_EQ (path == model->path_from_index (idx).second (), true);
path.net = root->net_by_name ("4");
idx = model->index_from_path (lay::NetlistObjectsPath::from_second (path));
EXPECT_EQ (idx.isValid (), true);
EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "$5|4");
EXPECT_EQ (path == model->path_from_index (idx).second (), true);
path.path.push_back (root->subcircuit_by_name ("$2"));
EXPECT_EQ (path.path.back () != 0, true);
EXPECT_EQ (path.path.back ()->expanded_name (), "$2");
EXPECT_EQ (path.path.back ()->circuit_ref ()->name (), "INV2");
path.net = 0;
idx = model->index_from_path (lay::NetlistObjectsPath::from_second (path));
EXPECT_EQ (idx.isValid (), true);
// A pure subcircuit path addresses the "Circuit" representative node of the subcircuit
EXPECT_EQ (tl::to_string (model->data (idx, Qt::DisplayRole).toString ()), "Circuit");
EXPECT_EQ (tl::to_string (model->data (model->parent (idx), Qt::UserRole).toString ()), "INV2|$2");
EXPECT_EQ (path == model->path_from_index (idx).second (), true);
path.net = sc->net_by_name ("2");
idx = model->index_from_path (lay::NetlistObjectsPath::from_second (path));
EXPECT_EQ (idx.isValid (), true);
EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "IN|2");
EXPECT_EQ (path == model->path_from_index (idx).second (), true);
path.net = 0;
path.device = sc->device_by_id (1);
idx = model->index_from_path (lay::NetlistObjectsPath::from_second (path));
EXPECT_EQ (idx.isValid (), true);
EXPECT_EQ (tl::to_string (model->data (idx, Qt::UserRole).toString ()), "$1|$1|PMOS|PMOS");
EXPECT_EQ (path == model->path_from_index (idx).second (), true);
}