mirror of https://github.com/KLayout/klayout.git
WIP: better tooltips and comments for LVS browser.
This commit is contained in:
parent
955d21a656
commit
3310d34cf3
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue