Better handling of pin swapping in netlist browser

This commit is contained in:
Matthias Koefferlein 2020-07-11 13:21:23 +02:00
parent aaa8352a40
commit fde90c66e1
9 changed files with 292 additions and 135 deletions

View File

@ -601,6 +601,16 @@ NetlistCrossReference::build_subcircuit_pin_refs (const std::pair<const db::Net
}
// Fallback for swappable pins: match based on the subcircuit alone
if (! pb) {
std::map<std::pair<const db::SubCircuit *, size_t>, const db::NetSubcircuitPinRef *>::iterator b = s2t_b.lower_bound (std::make_pair (sb, 0));
if (b != s2t_b.end () && b->first.first == sb) {
pb = b->second;
// remove the entry so we won't find it again
s2t_b.erase (b);
}
}
}
data.subcircuit_pins.push_back (std::make_pair (a->second, pb));

View File

@ -119,6 +119,17 @@ const Net *SubCircuit::net_for_pin (size_t pin_id) const
return 0;
}
const NetSubcircuitPinRef *SubCircuit::netref_for_pin (size_t pin_id) const
{
if (pin_id < m_pin_refs.size ()) {
Net::subcircuit_pin_iterator p = m_pin_refs [pin_id];
if (p != Net::subcircuit_pin_iterator ()) {
return p.operator-> ();
}
}
return 0;
}
void SubCircuit::connect_pin (size_t pin_id, Net *net)
{
if (net_for_pin (pin_id) == net) {

View File

@ -171,6 +171,21 @@ public:
return const_cast<Net *> (((const SubCircuit *) this)->net_for_pin (pin_id));
}
/**
* @brief Gets the net attached to a specific pin as a subcircuit pin ref object
* Returns 0 if no net is attached.
*/
const NetSubcircuitPinRef *netref_for_pin (size_t pin_id) const;
/**
* @brief Gets the net attached to a specific pin as a subcircuit pin ref object (non-const version)
* Returns 0 if no net is attached.
*/
NetSubcircuitPinRef *netref_for_pin (size_t pin_id)
{
return const_cast<NetSubcircuitPinRef *> (((const SubCircuit *) this)->netref_for_pin (pin_id));
}
/**
* @brief Connects the given pin to the given net
* If the net is 0 the pin is disconnected.

View File

@ -263,6 +263,12 @@ SingleIndexedNetlistModel::device_count (const circuit_pair &circuits) const
return circuits.first->device_count ();
}
size_t
SingleIndexedNetlistModel::subcircuit_pin_count (const subcircuit_pair &subcircuits) const
{
return subcircuits.first->circuit_ref ()->pin_count ();
}
size_t
SingleIndexedNetlistModel::pin_count (const circuit_pair &circuits) const
{
@ -346,6 +352,12 @@ 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
{
return IndexedNetlistModel::net_subcircuit_pin_pair (subcircuits.first->netref_for_pin (index), 0);
}
IndexedNetlistModel::net_terminal_pair
SingleIndexedNetlistModel::net_terminalref_from_index (const net_pair &nets, size_t index) const
{

View File

@ -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;

View File

@ -354,6 +354,20 @@ IndexedNetlistModel::subcircuit_pair subcircuits_from_pinrefs (const IndexedNetl
return std::make_pair (subcircuit1, subcircuit2);
}
static
IndexedNetlistModel::net_pair nets_from_pinrefs (const IndexedNetlistModel::net_subcircuit_pin_pair &pinrefs)
{
const db::Net *net1 = 0, *net2 = 0;
if (pinrefs.first) {
net1 = pinrefs.first->net ();
}
if (pinrefs.second) {
net2 = pinrefs.second->net ();
}
return std::make_pair (net1, net2);
}
static
IndexedNetlistModel::device_pair devices_from_termrefs (const IndexedNetlistModel::net_terminal_pair &termrefs)
{
@ -396,6 +410,20 @@ IndexedNetlistModel::pin_pair pins_from_pinrefs (const IndexedNetlistModel::net_
return std::make_pair (pin1, pin2);
}
static
IndexedNetlistModel::pin_pair pins_from_netrefs (const IndexedNetlistModel::net_subcircuit_pin_pair &netrefs)
{
const db::Pin *pin1 = 0, *pin2 = 0;
if (netrefs.first) {
pin1 = netrefs.first->pin ();
}
if (netrefs.second) {
pin2 = netrefs.second->pin ();
}
return std::make_pair (pin1, pin2);
}
static
IndexedNetlistModel::net_pair nets_from_subcircuit_pins (const IndexedNetlistModel::subcircuit_pair &subcircuits, const IndexedNetlistModel::pin_pair &pins)
{
@ -1080,7 +1108,7 @@ class CircuitNetSubCircuitPinOthersItemData
: public NetlistModelItemData
{
public:
CircuitNetSubCircuitPinOthersItemData (NetlistModelItemData *parent, const IndexedNetlistModel::pin_pair &pp, bool is_self);
CircuitNetSubCircuitPinOthersItemData (NetlistModelItemData *parent, const IndexedNetlistModel::net_subcircuit_pin_pair &pp, bool is_self);
virtual void do_ensure_children (NetlistBrowserModel *);
virtual QIcon icon (NetlistBrowserModel *model);
@ -1089,25 +1117,18 @@ public:
virtual std::string tooltip (NetlistBrowserModel * /*model*/);
virtual db::NetlistCrossReference::Status status (NetlistBrowserModel * /*model*/);
IndexedNetlistModel::pin_pair pp ()
{
CircuitNetSubCircuitPinItemData *p = static_cast<CircuitNetSubCircuitPinItemData *> (parent ());
return p->pp ();
}
const IndexedNetlistModel::net_subcircuit_pin_pair &sp ()
{
CircuitNetSubCircuitPinItemData *p = static_cast<CircuitNetSubCircuitPinItemData *> (parent ());
return p->sp ();
}
virtual std::pair<const db::Pin *, const db::Pin *> pins ()
const IndexedNetlistModel::net_subcircuit_pin_pair &pp ()
{
return m_pp;
}
virtual std::pair<const db::Pin *, const db::Pin *> pins ()
{
return std::pair<const db::Pin *, const db::Pin *> (pins_from_netrefs (m_pp));
}
private:
IndexedNetlistModel::pin_pair m_pp;
IndexedNetlistModel::net_subcircuit_pin_pair m_pp;
bool m_net_seen;
};
@ -1170,7 +1191,7 @@ class CircuitSubCircuitPinItemData
: public NetlistModelItemData
{
public:
CircuitSubCircuitPinItemData (NetlistModelItemData *parent, const IndexedNetlistModel::pin_pair &pp);
CircuitSubCircuitPinItemData (NetlistModelItemData *parent, const IndexedNetlistModel::net_subcircuit_pin_pair &pp);
virtual void do_ensure_children (NetlistBrowserModel *);
virtual QIcon icon (NetlistBrowserModel *model);
@ -1179,19 +1200,18 @@ public:
virtual std::string tooltip (NetlistBrowserModel *model);
virtual db::NetlistCrossReference::Status status (NetlistBrowserModel *model);
const IndexedNetlistModel::subcircuit_pair &sp ()
IndexedNetlistModel::subcircuit_pair sp ()
{
CircuitSubCircuitItemData *p = static_cast<CircuitSubCircuitItemData *> (parent ());
return p->sp ();
return subcircuits_from_pinrefs (m_pp);
}
virtual std::pair<const db::Pin *, const db::Pin *> pins ()
{
return m_pp;
return pins_from_netrefs (m_pp);
}
private:
IndexedNetlistModel::pin_pair m_pp;
IndexedNetlistModel::net_subcircuit_pin_pair m_pp;
};
// ----------------------------------------------------------------------------------
@ -1945,12 +1965,11 @@ void
CircuitNetSubCircuitPinItemData::do_ensure_children (NetlistBrowserModel *model)
{
IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (sp ());
IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits);
size_t n = model->indexer ()->pin_count (circuit_refs);
size_t n = model->indexer ()->subcircuit_pin_count (subcircuits);
for (size_t i = 0; i < n; ++i) {
IndexedNetlistModel::pin_pair pp = model->indexer ()->pin_from_index (circuit_refs, i).first;
bool is_seen = derived_from_nets (nets_from_subcircuit_pins (subcircuits, pp));
IndexedNetlistModel::net_subcircuit_pin_pair pp = model->indexer ()->subcircuit_pinref_from_index (subcircuits, i);
bool is_seen = derived_from_nets (nets_from_pinrefs (pp));
push_back (new CircuitNetSubCircuitPinOthersItemData (this, pp, is_seen));
}
}
@ -2001,7 +2020,7 @@ CircuitNetSubCircuitPinItemData::status (NetlistBrowserModel *model)
// ----------------------------------------------------------------------------------
CircuitNetSubCircuitPinOthersItemData::CircuitNetSubCircuitPinOthersItemData (NetlistModelItemData *parent, const IndexedNetlistModel::pin_pair &pp, bool net_seen)
CircuitNetSubCircuitPinOthersItemData::CircuitNetSubCircuitPinOthersItemData (NetlistModelItemData *parent, const IndexedNetlistModel::net_subcircuit_pin_pair &pp, bool net_seen)
: NetlistModelItemData (parent), m_pp (pp), m_net_seen (net_seen)
{ }
@ -2009,31 +2028,27 @@ void
CircuitNetSubCircuitPinOthersItemData::do_ensure_children (NetlistBrowserModel *)
{
if (! m_net_seen) {
IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (sp ());
IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits);
IndexedNetlistModel::net_pair nets = nets_from_circuit_pins (circuit_refs, m_pp);
push_back (new CircuitNetItemData (this, nets));
push_back (new CircuitNetItemData (this, nets_from_pinrefs (pp ())));
}
}
QIcon
CircuitNetSubCircuitPinOthersItemData::icon (NetlistBrowserModel *model)
{
IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (sp ());
return model->icon_for_connection (nets_from_subcircuit_pins (subcircuits, m_pp));
return model->icon_for_connection (nets_from_pinrefs (pp ()));
}
QString
CircuitNetSubCircuitPinOthersItemData::text (int column, NetlistBrowserModel *model)
{
// circuit/net/device terminal/more: header column = pin name, second column = net link
IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (sp ());
IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (pp ());
IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits);
if (column == model->object_column ()) {
return model->make_link_to (m_pp, circuit_refs) + (m_net_seen ? tr (" (already seen)") : QString ());
return model->make_link_to (pins (), circuit_refs) + (m_net_seen ? tr (" (already seen)") : QString ());
} else if (column == model->first_column () || column == model->second_column ()) {
return model->make_link_to (nets_from_subcircuit_pins (subcircuits, m_pp), column);
return model->make_link_to (nets_from_pinrefs (pp ()), column);
}
return QString ();
@ -2042,19 +2057,15 @@ CircuitNetSubCircuitPinOthersItemData::text (int column, NetlistBrowserModel *mo
QString
CircuitNetSubCircuitPinOthersItemData::search_text ()
{
IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (sp ());
IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits);
IndexedNetlistModel::net_pair nets = nets_from_circuit_pins (circuit_refs, m_pp);
return tl::to_qstring (combine_search_strings (search_string_from_names (m_pp), search_string_from_expanded_names (nets)));
return tl::to_qstring (combine_search_strings (search_string_from_names (pins ()), search_string_from_expanded_names (nets_from_pinrefs (pp ()))));
}
std::string
CircuitNetSubCircuitPinOthersItemData::tooltip (NetlistBrowserModel *model)
{
IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (sp ());
std::string hint;
if (! model->is_valid_net_pair (nets_from_subcircuit_pins (subcircuits, m_pp))) {
if (! model->is_valid_net_pair (nets_from_pinrefs (pp ()))) {
// This indicates a wrong connection: the nets are associated in a way which is a not
// corresponding to a mapped net pair. Report Mismatch here.
hint = rewire_subcircuit_pins_status_hint ();
@ -2066,8 +2077,7 @@ CircuitNetSubCircuitPinOthersItemData::tooltip (NetlistBrowserModel *model)
db::NetlistCrossReference::Status
CircuitNetSubCircuitPinOthersItemData::status (NetlistBrowserModel *model)
{
IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (sp ());
if (! model->is_valid_net_pair (nets_from_subcircuit_pins (subcircuits, m_pp))) {
if (! model->is_valid_net_pair (nets_from_pinrefs (pp ()))) {
// This indicates a wrong connection: the nets are associated in a way which is a not
// corresponding to a mapped net pair. Report Mismatch here.
return db::NetlistCrossReference::NoMatch;
@ -2135,10 +2145,9 @@ CircuitSubCircuitItemData::CircuitSubCircuitItemData (NetlistModelItemData *pare
void
CircuitSubCircuitItemData::do_ensure_children (NetlistBrowserModel *model)
{
size_t n = std::max (rows_for (sp ().first), rows_for (sp ().second));
IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (sp ());
size_t n = model->indexer ()->subcircuit_pin_count (sp ());
for (size_t i = 0; i < n; ++i) {
IndexedNetlistModel::pin_pair pp = model->indexer ()->pin_from_index (circuit_refs, i).first;
IndexedNetlistModel::net_subcircuit_pin_pair pp = model->indexer ()->subcircuit_pinref_from_index (sp (), i);
push_back (new CircuitSubCircuitPinItemData (this, pp));
}
}
@ -2188,14 +2197,14 @@ CircuitSubCircuitItemData::status (NetlistBrowserModel *model)
// ----------------------------------------------------------------------------------
CircuitSubCircuitPinItemData::CircuitSubCircuitPinItemData (NetlistModelItemData *parent, const IndexedNetlistModel::pin_pair &pp)
CircuitSubCircuitPinItemData::CircuitSubCircuitPinItemData (NetlistModelItemData *parent, const IndexedNetlistModel::net_subcircuit_pin_pair &pp)
: NetlistModelItemData (parent), m_pp (pp)
{ }
void
CircuitSubCircuitPinItemData::do_ensure_children (NetlistBrowserModel *)
{
IndexedNetlistModel::net_pair nets = nets_from_subcircuit_pins (sp (), m_pp);
IndexedNetlistModel::net_pair nets = nets_from_pinrefs (m_pp);
push_back (new CircuitNetItemData (this, nets));
}
@ -2208,13 +2217,10 @@ CircuitSubCircuitPinItemData::icon (NetlistBrowserModel * /*model*/)
QString
CircuitSubCircuitPinItemData::text (int column, NetlistBrowserModel *model)
{
// circuit/pin: header column = pin name, other columns net name
const IndexedNetlistModel::subcircuit_pair &sp = static_cast<CircuitSubCircuitItemData *> (parent ())->sp ();
if (column == model->object_column ()) {
return model->make_link_to (m_pp, circuit_refs_from_subcircuits (sp));
return model->make_link_to (pins (), circuit_refs_from_subcircuits (sp ()));
} else if (column == model->first_column () || column == model->second_column ()) {
return model->make_link_to (nets_from_subcircuit_pins (sp, m_pp), column);
return model->make_link_to (nets_from_pinrefs (m_pp), column);
}
return QString ();
@ -2223,23 +2229,17 @@ CircuitSubCircuitPinItemData::text (int column, NetlistBrowserModel *model)
QString
CircuitSubCircuitPinItemData::search_text ()
{
IndexedNetlistModel::net_pair nets = nets_from_subcircuit_pins (sp (), m_pp);
return tl::to_qstring (combine_search_strings (search_string_from_names (m_pp), search_string_from_expanded_names (nets)));
return tl::to_qstring (combine_search_strings (search_string_from_names (pins ()), search_string_from_expanded_names (nets_from_pinrefs (m_pp))));
}
std::string
CircuitSubCircuitPinItemData::tooltip (NetlistBrowserModel *model)
{
IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (sp ());
std::string hint = model->indexer ()->pin_status_hint (circuit_refs, model->indexer ()->pin_index (m_pp, circuit_refs));
if (hint.empty ()) {
// Another test here is to check whether the pins may be attached to an invalid net pair
if (! model->is_valid_net_pair (nets_from_subcircuit_pins (sp (), m_pp))) {
hint = rewire_subcircuit_pins_status_hint ();
}
std::string hint;
// Check whether the pins may be attached to an invalid net pair
if (! model->is_valid_net_pair (nets_from_pinrefs (m_pp))) {
hint = rewire_subcircuit_pins_status_hint ();
}
return hint;
@ -2248,15 +2248,7 @@ CircuitSubCircuitPinItemData::tooltip (NetlistBrowserModel *model)
db::NetlistCrossReference::Status
CircuitSubCircuitPinItemData::status (NetlistBrowserModel *model)
{
IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (sp ());
db::NetlistCrossReference::Status status = model->indexer ()->pin_from_index (circuit_refs, model->indexer ()->pin_index (m_pp, circuit_refs)).second;
if (status == db::NetlistCrossReference::Mismatch || status == db::NetlistCrossReference::NoMatch) {
return status;
}
// Another test here is to check whether the pins may be attached to an invalid net pair
if (! model->is_valid_net_pair (nets_from_subcircuit_pins (sp (), m_pp))) {
if (! model->is_valid_net_pair (nets_from_pinrefs (m_pp))) {
// This indicates a wrong connection: the nets are associated in a way which is a not
// corresponding to a mapped net pair. Report Mismatch here.
return db::NetlistCrossReference::NoMatch;

View File

@ -308,6 +308,103 @@ const db::Circuit *NetlistCrossReferenceModel::second_circuit_for (const db::Cir
return mp_cross_ref->other_circuit_for (first);
}
namespace {
struct CompareNetRefsByPins
{
bool operator () (const std::pair<const db::NetSubcircuitPinRef *, const db::NetSubcircuitPinRef *> &a,
const std::pair<const db::NetSubcircuitPinRef *, const db::NetSubcircuitPinRef *> &b)
{
size_t pin_id1 = a.first ? a.first->pin_id () : (a.second ? a.second->pin_id () : std::numeric_limits<size_t>::max ());
size_t pin_id2 = b.first ? b.first->pin_id () : (b.second ? b.second->pin_id () : std::numeric_limits<size_t>::max ());
return pin_id1 < pin_id2;
}
};
}
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 *> (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);
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 (), CompareNetRefsByPins ());
}
}
}
}
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 (0, 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);

View File

@ -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;
};
}

View File

@ -44,73 +44,79 @@ 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_subcircuits = model->index (2, 0, inv2Index);
// Pins
EXPECT_EQ (tl::to_string (model->data (model->index (0, 0, inv2Index), Qt::UserRole).toString ()), "IN");
EXPECT_EQ (model->parent (model->index (0, 0, inv2Index)) == model->parent (model->index (0, 3, inv2Index)), true);
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");
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 (model->parent (model->index (5, 0, inv2Index)) == model->parent (model->index (5, 3, inv2Index)), true);
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 (model->parent (model->index (10, 0, inv2Index)) == model->parent (model->index (10, 3, inv2Index)), true);
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_subcircuits), Qt::UserRole).toString ()), "$1|PMOS");
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 ()), "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_subcircuits), Qt::DisplayRole).toString ()), "$1");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, sn_subcircuits), 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_subcircuits), Qt::DisplayRole).toString ()), "$2");
EXPECT_EQ (tl::to_string (model->data (model->index (2, 0, sn_subcircuits), 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_subcircuits), Qt::DisplayRole).toString ()), "$3");
EXPECT_EQ (tl::to_string (model->data (model->index (3, 0, sn_subcircuits), 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_subcircuits), 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);
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 (model->parent (model->index (0, 0, ringoIndex)) == model->parent (model->index (0, 3, ringoIndex)), true);
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 (model->parent (model->index (12, 0, ringoIndex)) == model->parent (model->index (12, 3, ringoIndex)), true);
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:circuit?id=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:circuit?id=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);
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");
@ -121,8 +127,8 @@ TEST (1)
EXPECT_EQ (model->rowCount (inv2PinOutIndexNet), 0);
// 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);
@ -143,7 +149,7 @@ TEST (1)
EXPECT_EQ (model->rowCount (inv2NOutPinOutIndex), 0);
// a MOS3 transistor has three other terminals
QModelIndex inv2NOutDeviceIndex = model->index (0, 2, inv2NOutIndex);
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);
@ -154,16 +160,16 @@ 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); // @@@ -> children: nets
EXPECT_EQ (model->rowCount (inv2NOutDeviceGateIndex), 1);
// 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);
@ -178,7 +184,7 @@ TEST (1)
EXPECT_EQ (model->hasChildren (ringoFbSubcircuit2Index), true);
EXPECT_EQ (model->rowCount (ringoFbSubcircuit2Index), 5);
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::UserRole).toString ()), "IN|FB");
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>");