WIP: netlist browser - net object paths, single + pairs, tests

This commit is contained in:
Matthias Koefferlein 2020-07-13 22:11:10 +02:00
parent 2762daf14f
commit a10d56e6b6
7 changed files with 259 additions and 24 deletions

View File

@ -36,6 +36,67 @@
namespace lay
{
// ----------------------------------------------------------------------------------
// NetlistObjectPath implementation
NetlistObjectsPath
NetlistObjectsPath::from_first (const NetlistObjectPath &p)
{
NetlistObjectsPath pp;
pp.root.first = p.root;
for (NetlistObjectPath::path_iterator i = p.path.begin (); i != p.path.end (); ++i) {
pp.path.push_back (std::make_pair (*i, (const db::SubCircuit *) 0));
}
pp.device.first = p.device;
pp.net.first = p.net;
return pp;
}
NetlistObjectsPath
NetlistObjectsPath::from_second (const NetlistObjectPath &p)
{
NetlistObjectsPath pp;
pp.root.second = p.root;
for (NetlistObjectPath::path_iterator i = p.path.begin (); i != p.path.end (); ++i) {
pp.path.push_back (std::make_pair ((const db::SubCircuit *) 0, *i));
}
pp.device.second = p.device;
pp.net.second = p.net;
return pp;
}
NetlistObjectPath
NetlistObjectsPath::first () const
{
NetlistObjectPath p;
p.root = root.first;
for (NetlistObjectsPath::path_iterator i = path.begin (); i != path.end (); ++i) {
if (! i->first) {
return NetlistObjectPath ();
}
p.path.push_back (i->first);
}
p.device = device.first;
p.net = net.first;
return p;
}
NetlistObjectPath
NetlistObjectsPath::second () const
{
NetlistObjectPath p;
p.root = root.second;
for (NetlistObjectsPath::path_iterator i = path.begin (); i != path.end (); ++i) {
if (! i->second) {
return NetlistObjectPath ();
}
p.path.push_back (i->second);
}
p.device = device.second;
p.net = net.second;
return p;
}
// ----------------------------------------------------------------------------------
// NetColorizer implementation
@ -2435,10 +2496,10 @@ NetlistBrowserModel::data (const QModelIndex &index, int role) const
return QVariant ();
}
NetlistObjectPath
NetlistBrowserModel::netpath_from_index (const QModelIndex &index) const
NetlistObjectsPath
NetlistBrowserModel::path_from_index (const QModelIndex &index) const
{
NetlistObjectPath np;
NetlistObjectsPath np;
np.net = net_from_index (index, false);
np.device = device_from_index (index, false);
@ -2463,7 +2524,7 @@ NetlistBrowserModel::netpath_from_index (const QModelIndex &index) const
}
QModelIndex
NetlistBrowserModel::index_from_netpath (const NetlistObjectPath &path)
NetlistBrowserModel::index_from_path (const NetlistObjectsPath &path)
{
QModelIndex index = index_from_circuit (path.root);

View File

@ -179,14 +179,22 @@ private:
};
/**
* @brief An object describing the instantiation path of a net
* @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<std::pair<const db::SubCircuit *, const db::SubCircuit *> > path_type;
typedef std::list<const db::SubCircuit *> path_type;
typedef path_type::const_iterator path_iterator;
NetlistObjectPath () { }
NetlistObjectPath () : root (0), net (0), device (0) { }
bool is_null () const
{
return ! root;
}
bool operator== (const NetlistObjectPath &other) const
{
@ -198,6 +206,46 @@ struct LAYBASIC_PUBLIC NetlistObjectPath
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;
@ -292,8 +340,18 @@ public:
QIcon icon_for_connection (const std::pair<const db::Net *, const db::Net *> &net) const;
QModelIndex index_from_url (const QString &url) const;
NetlistObjectPath netpath_from_index (const QModelIndex &index) const;
QModelIndex index_from_netpath (const NetlistObjectPath &path);
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 ();

View File

@ -347,7 +347,7 @@ NetlistBrowserPage::current_index_changed (const QModelIndex &index)
add_to_history (index, true);
NetlistObjectPath path = netlist_model->netpath_from_index (index);
NetlistObjectsPath path = netlist_model->path_from_index (index);
QModelIndex circuit_index = tree_model->index_from_netpath (path);
m_signals_enabled = false;
@ -460,7 +460,7 @@ NetlistBrowserPage::selection_changed ()
tl_assert (model != 0);
QModelIndex current = directory_tree->selectionModel ()->currentIndex ();
highlight (model->netpath_from_index (current));
highlight (model->path_from_index (current));
}
void
@ -517,7 +517,7 @@ NetlistBrowserPage::navigate_to (const QModelIndex &index, bool fwd)
return;
}
lay::NetlistObjectPath path = netlist_model->netpath_from_index (index);
lay::NetlistObjectsPath path = netlist_model->path_from_index (index);
QModelIndex circuit_index = tree_model->index_from_netpath (path);
hierarchy_tree->setCurrentIndex (circuit_index);
@ -874,7 +874,7 @@ NetlistBrowserPage::setup_trees ()
}
void
NetlistBrowserPage::highlight (const NetlistObjectPath &path)
NetlistBrowserPage::highlight (const NetlistObjectsPath &path)
{
if (path != m_current_path) {

View File

@ -235,7 +235,7 @@ private:
bool m_enable_updates;
bool m_update_needed;
// @@@ TODO: make multiple ...
lay::NetlistObjectPath m_current_path;
lay::NetlistObjectsPath m_current_path;
// @@@ TODO: remove
std::vector<const db::Net *> m_current_nets;
std::vector<const db::Device *> m_current_devices;
@ -251,7 +251,7 @@ private:
void navigate_to (const QModelIndex &index, bool forward = true);
void adjust_view ();
void clear_markers ();
void highlight (const lay::NetlistObjectPath &path);
void highlight (const lay::NetlistObjectsPath &path);
std::vector<const db::Net *> selected_nets ();
std::vector<const db::Device *> selected_devices ();
std::vector<const db::SubCircuit *> selected_subcircuits ();

View File

@ -270,13 +270,13 @@ static bool is_compatible (const std::pair<const db::Circuit *, const db::Circui
}
QModelIndex
NetlistBrowserTreeModel::index_from_netpath (const NetlistObjectPath &path) const
NetlistBrowserTreeModel::index_from_netpath (const NetlistObjectsPath &path) const
{
QModelIndex idx;
idx = index_from_circuits (path.root);
for (NetlistObjectPath::path_iterator p = path.path.begin (); p != path.path.end () && idx.isValid (); ++p) {
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);

View File

@ -42,7 +42,7 @@ namespace lay
{
class IndexedNetlistModel;
struct NetlistObjectPath;
struct NetlistObjectsPath;
// ----------------------------------------------------------------------------------
// NetlistBrowserTreeModel definition
@ -78,7 +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 NetlistObjectPath &path) const;
QModelIndex index_from_netpath (const NetlistObjectsPath &path) const;
private:
NetlistBrowserTreeModel (const NetlistBrowserTreeModel &);

View File

@ -417,8 +417,8 @@ TEST (3)
db::Circuit *root = l2n.netlist ()->circuit_by_name ("RINGO");
EXPECT_EQ (root != 0, true);
lay::NetlistObjectPath path;
EXPECT_EQ (model->index_from_netpath (path).isValid (), false);
lay::NetlistObjectsPath path;
EXPECT_EQ (model->index_from_path (path).isValid (), false);
path.root.first = root;
@ -427,7 +427,7 @@ TEST (3)
path.net.first = net;
QModelIndex index = model->index_from_netpath (path);
QModelIndex index = model->index_from_path (path);
EXPECT_EQ (index.isValid (), true);
EXPECT_EQ (tl::to_string (model->data (index, Qt::UserRole).toString ()), "FB");
@ -444,7 +444,7 @@ TEST (4)
db::Circuit *root = l2n.netlist ()->circuit_by_name ("RINGO");
EXPECT_EQ (root != 0, true);
lay::NetlistObjectPath path;
lay::NetlistObjectsPath path;
path.root.first = root;
db::SubCircuit *sc1 = root->begin_subcircuits ().operator-> ();
@ -456,8 +456,124 @@ TEST (4)
path.net.first = net;
QModelIndex index = model->index_from_netpath (path);
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);
}