WIP: better tooltips and comments for LVS browser.

This commit is contained in:
Matthias Koefferlein 2019-06-27 00:14:18 +02:00
parent 955d21a656
commit 3310d34cf3
8 changed files with 266 additions and 3 deletions

View File

@ -32,13 +32,13 @@
// TODO: make this a feature?
// #define PRINT_DEBUG_NETCOMPARE
namespace db
{
// Add this define for case insensitive compare
// (applies to circuits, device classes)
#define COMPARE_CASE_INSENSITIVE
namespace db
{
// --------------------------------------------------------------------------------------------------------------------
// DeviceCompare definition and implementation

View File

@ -98,6 +98,15 @@ public:
virtual std::pair<pin_pair, Status> pin_from_index (const circuit_pair &circuits, size_t index) const = 0;
virtual std::pair<subcircuit_pair, Status> subcircuit_from_index (const circuit_pair &circuits, size_t index) const = 0;
virtual std::string top_circuit_status_hint (size_t /*index*/) const { return std::string (); }
virtual std::string circuit_status_hint (size_t /*index*/) const { return std::string (); }
virtual std::string child_circuit_status_hint (const circuit_pair &/*circuits*/, size_t /*index*/) const { return std::string (); }
virtual std::string circuit_pair_status_hint (const std::pair<circuit_pair, Status> & /*cp*/) const { return std::string (); }
virtual std::string net_status_hint (const circuit_pair &/*circuits*/, size_t /*index*/) const { return std::string (); }
virtual std::string device_status_hint (const circuit_pair &/*circuits*/, size_t /*index*/) const { return std::string (); }
virtual std::string pin_status_hint (const circuit_pair &/*circuits*/, size_t /*index*/) const { return std::string (); }
virtual std::string subcircuit_status_hint (const circuit_pair & /*circuits*/, size_t /*index*/) const { return std::string (); }
virtual size_t circuit_index (const circuit_pair &circuits) const = 0;
virtual size_t net_index (const net_pair &nets) const = 0;
virtual size_t device_index (const device_pair &devices) const = 0;

View File

@ -664,6 +664,8 @@ NetlistBrowserModel::data (const QModelIndex &index, int role) const
return QVariant (icon_for_status (status (index)));
} else if (role == Qt::DisplayRole) {
return QVariant (text (index));
} else if (role == Qt::ToolTipRole && index.column () == m_status_column) {
return tooltip (index);
} else if (role == Qt::UserRole) {
return QVariant (search_text (index));
} else if (role == Qt::FontRole) {
@ -1339,17 +1341,109 @@ NetlistBrowserModel::status (const QModelIndex &index) const
size_t index = circuit_subcircuit_index_from_id (id);
return mp_indexer->subcircuit_from_index (circuits, index).second;
} else if (is_id_circuit_subcircuit_pin (id)) {
IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_id (id);
IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits);
IndexedNetlistModel::pin_pair pins = pins_from_id (id);
return mp_indexer->pin_from_index (circuit_refs, mp_indexer->pin_index (pins, circuit_refs)).second;
} else if (is_id_circuit_net (id)) {
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
size_t index = circuit_net_index_from_id (id);
return mp_indexer->net_from_index (circuits, index).second;
} else if (is_id_circuit_net_device_terminal (id)) {
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
IndexedNetlistModel::net_terminal_pair termrefs = net_terminalrefs_from_id (id);
IndexedNetlistModel::device_pair devices = devices_from_termrefs (termrefs);
return mp_indexer->device_from_index (circuits, mp_indexer->device_index (devices)).second;
} else if (is_id_circuit_net_subcircuit_pin (id)) {
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
IndexedNetlistModel::net_subcircuit_pin_pair pinrefs = net_subcircuit_pinrefs_from_id (id);
IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (pinrefs);
return mp_indexer->subcircuit_from_index (circuits, mp_indexer->subcircuit_index (subcircuits)).second;
}
return db::NetlistCrossReference::None;
}
QVariant
NetlistBrowserModel::tooltip (const QModelIndex &index) const
{
void *id = index.internalPointer ();
std::string hint;
if (is_id_circuit (id)) {
size_t index = circuit_index_from_id (id);
hint = mp_indexer->circuit_status_hint (index);
} else if (is_id_circuit_pin (id)) {
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
size_t index = circuit_pin_index_from_id (id);
hint = mp_indexer->pin_status_hint (circuits, index);
} else if (is_id_circuit_device (id)) {
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
size_t index = circuit_device_index_from_id (id);
hint = mp_indexer->device_status_hint (circuits, index);
} else if (is_id_circuit_subcircuit (id)) {
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
size_t index = circuit_subcircuit_index_from_id (id);
hint = mp_indexer->subcircuit_status_hint (circuits, index);
} else if (is_id_circuit_subcircuit_pin (id)) {
IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_id (id);
IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits);
IndexedNetlistModel::pin_pair pins = pins_from_id (id);
hint = mp_indexer->pin_status_hint (circuit_refs, mp_indexer->pin_index (pins, circuit_refs));
} else if (is_id_circuit_net (id)) {
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
size_t index = circuit_net_index_from_id (id);
hint = mp_indexer->net_status_hint (circuits, index);
} else if (is_id_circuit_net_device_terminal (id)) {
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
IndexedNetlistModel::net_terminal_pair termrefs = net_terminalrefs_from_id (id);
IndexedNetlistModel::device_pair devices = devices_from_termrefs (termrefs);
hint = mp_indexer->device_status_hint (circuits, mp_indexer->device_index (devices));
} else if (is_id_circuit_net_subcircuit_pin (id)) {
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
IndexedNetlistModel::net_subcircuit_pin_pair pinrefs = net_subcircuit_pinrefs_from_id (id);
IndexedNetlistModel::subcircuit_pair subcircuits = subcircuits_from_pinrefs (pinrefs);
hint = mp_indexer->subcircuit_status_hint (circuits, mp_indexer->subcircuit_index (subcircuits));
}
if (hint.empty ()) {
return QVariant ();
} else {
return QVariant (tl::to_qstring (hint));
}
}
QString
NetlistBrowserModel::search_text (const QModelIndex &index) const
{

View File

@ -204,6 +204,7 @@ private:
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;

View File

@ -163,6 +163,8 @@ NetlistBrowserTreeModel::data (const QModelIndex &index, int role) const
return QVariant (icon_for_status (status (index)));
} else if (role == Qt::DisplayRole) {
return QVariant (text (index));
} else if (role == Qt::ToolTipRole && index.column () == m_status_column) {
return tooltip (index);
} else if (role == Qt::UserRole) {
return QVariant (search_text (index));
} else if (role == Qt::FontRole) {
@ -285,6 +287,35 @@ NetlistBrowserTreeModel::status (const QModelIndex &index) const
return cp_status_from_index (index, nprod, nlast, nnlast).second;
}
QVariant
NetlistBrowserTreeModel::tooltip (const QModelIndex &index) const
{
typedef std::pair<std::pair<const db::Circuit *, const db::Circuit *>, db::NetlistCrossReference::Status> cp_status;
size_t nlast = 0;
std::string hint;
void *id = index.internalPointer ();
tl_assert (id != 0);
nlast = mp_indexer->top_circuit_count () + 1;
size_t i = pop (id, nlast);
hint = mp_indexer->top_circuit_status_hint (i - 1);
cp_status cps = mp_indexer->top_circuit_from_index (i - 1);
while (id != 0) {
nlast = mp_indexer->child_circuit_count (cps.first) + 1;
i = pop (id, nlast);
hint = mp_indexer->child_circuit_status_hint (cps.first, i - 1);
cps = mp_indexer->child_circuit_from_index (cps.first, i - 1);
}
if (! hint.empty ()) {
return QVariant (tl::to_qstring (hint));
} else {
return QVariant ();
}
}
Qt::ItemFlags
NetlistBrowserTreeModel::flags (const QModelIndex & /*index*/) const
{

View File

@ -83,6 +83,7 @@ private:
NetlistBrowserTreeModel &operator= (const NetlistBrowserTreeModel &);
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;
std::pair<std::pair<const db::Circuit *, const db::Circuit *>, db::NetlistCrossReference::Status> cp_status_from_index (const QModelIndex &index, size_t &nprod, size_t &nlast, size_t &nnlast) const;

View File

@ -431,4 +431,122 @@ size_t NetlistCrossReferenceModel::subcircuit_index (const subcircuit_pair &subc
return get_index_of (subcircuits, org_data->subcircuits.begin (), org_data->subcircuits.end (), data->index_of_subcircuits);
}
std::string NetlistCrossReferenceModel::circuit_pair_status_hint (const std::pair<IndexedNetlistModel::circuit_pair, NetlistCrossReferenceModel::Status> &cps) const
{
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
if (! cps.first.first || ! cps.first.second) {
return tl::to_string (tr ("No matching circuit found in the other netlist.\n"
"By default, circuits are identified by their name. "
"A missing circuit probably means there is no circuit in the other netlist with this name.\n"
"If circuits with different names need to be associated, use 'same_circuits' in the "
"LVS script to establish such an association."));
} else {
return tl::to_string (tr ("Circuits could be paired, but there is a mismatch inside.\n"
"Browse the circuit's component list to identify the mismatching elements."));
}
} else if (cps.second == db::NetlistCrossReference::Skipped) {
return tl::to_string (tr ("Circuits can only be matched if their child circuits have a known counterpart and a pin-to-pin "
"correspondence could be established for each child circuit.\n"
"This is not the case here. Browse the child circuits to identify the blockers.\n"
"Potential blockers are subcircuits without a corresponding other circuit or circuits "
"where some pins could not be mapped to pins from the corresponding other circuit."));
}
return std::string ();
}
std::string NetlistCrossReferenceModel::top_circuit_status_hint (size_t index) const
{
return circuit_pair_status_hint (top_circuit_from_index (index));
}
std::string NetlistCrossReferenceModel::circuit_status_hint (size_t index) const
{
return circuit_pair_status_hint (circuit_from_index (index));
}
std::string NetlistCrossReferenceModel::child_circuit_status_hint (const circuit_pair &circuits, size_t index) const
{
std::pair<IndexedNetlistModel::circuit_pair, NetlistCrossReferenceModel::Status> cps = child_circuit_from_index (circuits, index);
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
if (!cps.first.first || !cps.first.second) {
return tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin assignment "
"could not be derived from the nets connected to the pins.\n"
"Check, if the pins are attached properly. If pins need to be swappable, consider using 'equivalent_pins' "
"in the LVS script."));
} else {
return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not "
"originating from equivalent circuits.\n"
"If the circuits behind the subcircuits are identical, using 'same_circuits' in the LVS script "
"helps to associate them."));
}
}
return std::string ();
}
std::string NetlistCrossReferenceModel::net_status_hint (const circuit_pair &circuits, size_t index) const
{
std::pair<IndexedNetlistModel::net_pair, NetlistCrossReferenceModel::Status> cps = net_from_index (circuits, index);
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
return tl::to_string (tr ("Nets don't match. Nets match, if connected subcircuit pins and device terminals match to a counterpart in "
"the other netlist (component-wise and pin/terminal-wise).\n"
"If there already is a net candidate from the other netlist, scan the net members for "
"mismatching items (with errors or warnings) and fix these issues.\n"
"Otherwise, look for the corresponding other net.\n"
"Net items not found in the reference netlist indicate additional connections.\n"
"Net items only found in the reference netlist indicate missing connections."));
}
return std::string ();
}
std::string NetlistCrossReferenceModel::device_status_hint (const circuit_pair &circuits, size_t index) const
{
std::pair<IndexedNetlistModel::device_pair, NetlistCrossReferenceModel::Status> cps = device_from_index (circuits, index);
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
if (!cps.first.first || !cps.first.second) {
return tl::to_string (tr ("No matching device was found in the other netlist.\n"
"Devices are identified by the nets they are attached to. Unmatched devices mean that "
"at least one terminal net isn't matched with a corresponding net from the other netlist.\n"
"Make all terminal nets match and the devices will match too."));
}
} else if (cps.second == db::NetlistCrossReference::MatchWithWarning) {
return tl::to_string (tr ("Topologically matching devices are found here but either the parameters or the "
"device classes don't match.\n"
"If the device class is different but should be considered the same, "
"using 'same_device_class' in the LVS script will solve this issue."));
}
return std::string ();
}
std::string NetlistCrossReferenceModel::pin_status_hint (const circuit_pair &circuits, size_t index) const
{
std::pair<IndexedNetlistModel::pin_pair, NetlistCrossReferenceModel::Status> cps = pin_from_index (circuits, index);
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
if (!cps.first.first || !cps.first.second) {
return tl::to_string (tr ("No matching pin was found in the other netlist.\n"
"Pins are identified by the nets they are attached to - pins on equivalent nets are also equivalent.\n"
"Making the nets match will make the pins match too."));
}
}
return std::string ();
}
std::string NetlistCrossReferenceModel::subcircuit_status_hint (const circuit_pair &circuits, size_t index) const
{
std::pair<IndexedNetlistModel::subcircuit_pair, NetlistCrossReferenceModel::Status> cps = subcircuit_from_index (circuits, index);
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
if (!cps.first.first || !cps.first.second) {
return tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin assignment "
"could not be derived from the nets connected to the pins.\n"
"Check, if the pins are attached properly. If pins need to be swappable, consider using 'equivalent_pins' "
"in the LVS script."));
} else {
return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not "
"originating from equivalent circuits.\n"
"If the circuits behind the subcircuits are identical, using 'same_circuits' in the LVS script "
"helps to associate them."));
}
}
return std::string ();
}
}

View File

@ -71,6 +71,15 @@ public:
virtual std::pair<pin_pair, Status> pin_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::pair<subcircuit_pair, Status> subcircuit_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::string top_circuit_status_hint (size_t index) const;
virtual std::string circuit_status_hint (size_t index) const;
virtual std::string child_circuit_status_hint (const circuit_pair &circuits, size_t index) const;
virtual std::string circuit_pair_status_hint (const std::pair<circuit_pair, Status> &cp) const;
virtual std::string net_status_hint (const circuit_pair &circuits, size_t index) const;
virtual std::string device_status_hint (const circuit_pair &circuits, size_t index) const;
virtual std::string pin_status_hint (const circuit_pair &circuits, size_t index) const;
virtual std::string subcircuit_status_hint (const circuit_pair &circuits, size_t index) const;
virtual size_t circuit_index (const circuit_pair &circuits) const;
virtual size_t net_index (const net_pair &nets) const;
virtual size_t device_index (const device_pair &devices) const;