WIP: LVS DB model

This commit is contained in:
Matthias Koefferlein 2019-05-22 00:46:15 +02:00
parent 252622e3f8
commit f1fc16d55f
15 changed files with 1250 additions and 160 deletions

View File

@ -27,6 +27,10 @@ namespace db
namespace l2n_std_format
{
const char *l2n_magic_string_cstr = "#%l2n-klayout";
template<> DB_PUBLIC const std::string keys<false>::l2n_magic_string (l2n_magic_string_cstr);
template<> DB_PUBLIC const std::string keys<true>::l2n_magic_string (l2n_magic_string_cstr);
template<> DB_PUBLIC const std::string keys<false>::version_key ("version");
template<> DB_PUBLIC const std::string keys<false>::description_key ("description");
template<> DB_PUBLIC const std::string keys<false>::top_key ("top");

View File

@ -134,6 +134,8 @@ namespace l2n_std_format
template <bool Short>
struct DB_PUBLIC keys
{
static const std::string l2n_magic_string;
static const std::string version_key;
static const std::string description_key;
static const std::string top_key;

View File

@ -87,7 +87,7 @@ void std_writer_impl<Keys>::write (const db::Netlist *nl, const db::LayoutToNetl
const std::string indent (nested ? indent1 : "");
if (! nested) {
*mp_stream << "#%l2n-klayout" << endl;
*mp_stream << Keys::l2n_magic_string << endl;
}
if (version > 0) {

View File

@ -27,6 +27,10 @@ namespace db
namespace lvs_std_format
{
const char *lvs_magic_string_cstr = "#%lvsdb-klayout";
template<> DB_PUBLIC const std::string keys<false>::lvs_magic_string (lvs_magic_string_cstr);
template<> DB_PUBLIC const std::string keys<true>::lvs_magic_string (lvs_magic_string_cstr);
template<> DB_PUBLIC const std::string keys<false>::reference_key ("reference");
template<> DB_PUBLIC const std::string keys<false>::layout_key ("layout");
template<> DB_PUBLIC const std::string keys<false>::xref_key ("xref");

View File

@ -49,6 +49,7 @@ namespace db
*
* Global statements:
*
* #%lvsdb-klayout - header line identifies format
* version(<number>) - file format version [short key: V]
* description(<text>) - an arbitrary description text [short key: B]
* layout([layout]) - layout part [short key: J]
@ -126,6 +127,8 @@ namespace lvs_std_format
{
typedef l2n_std_format::keys<Short> l2n_keys;
static const std::string lvs_magic_string;
static const std::string reference_key;
static const std::string layout_key;
static const std::string xref_key;

View File

@ -91,7 +91,7 @@ void std_writer_impl<Keys>::write (const db::LayoutVsSchematic *lvs)
{
const int version = 0;
stream () << "#%lvsdb-klayout" << endl;
stream () << Keys::lvs_magic_string << endl;
if (version > 0) {
stream () << Keys::version_key << "(" << version << ")" << endl;

View File

@ -27,6 +27,7 @@
#include "laybasicCommon.h"
#include <map>
#include <vector>
#include <algorithm>
namespace db

View File

@ -32,6 +32,8 @@
#include "layConfigurationDialog.h"
#include "dbLayoutToNetlist.h"
#include "dbRecursiveShapeIterator.h"
#include "dbLayoutToNetlistFormatDefs.h"
#include "dbLayoutVsSchematicFormatDefs.h"
#include <QMessageBox>
#include <QInputDialog>
@ -442,22 +444,38 @@ NetlistBrowserDialog::open_clicked ()
BEGIN_PROTECTED
std::string fmts = tl::to_string (QObject::tr ("All files (*)"));
#if 0 // @@@ would be good to have this:
#if 0 // TODO: would be good to have this:
// collect the formats available ...
for (tl::Registrar<rdb::FormatDeclaration>::iterator rdr = tl::Registrar<rdb::FormatDeclaration>::begin (); rdr != tl::Registrar<rdb::FormatDeclaration>::end (); ++rdr) {
fmts += ";;" + rdr->file_format ();
}
#else
fmts += ";;L2N DB files (*.l2n)";
// @@@ TODO: add plain spice
fmts += ";;L2N DB files (*.l2n);;LVS DB files (*.lvsdb)";
// TODO: add plain spice
#endif
// prepare and open the file dialog
lay::FileDialog open_dialog (this, tl::to_string (QObject::tr ("Netlist Database File")), fmts);
lay::FileDialog open_dialog (this, tl::to_string (QObject::tr ("Netlist/LVS Database File")), fmts);
if (open_dialog.get_open (m_open_filename)) {
std::auto_ptr <db::LayoutToNetlist> db (new db::LayoutToNetlist ());
db->load (m_open_filename);
std::auto_ptr <db::LayoutToNetlist> db;
// TODO: generic concept to detect format
std::string first_line;
{
tl::InputStream stream (m_open_filename);
tl::TextInputStream text_stream (stream);
first_line = text_stream.get_line ();
}
if (first_line.find (db::lvs_std_format::keys<false>::lvs_magic_string) == 0) {
db::LayoutVsSchematic *lvs_db = new db::LayoutVsSchematic ();
db.reset (lvs_db);
lvs_db->load (m_open_filename);
} else {
db.reset (new db::LayoutToNetlist ());
db->load (m_open_filename);
}
int l2n_index = view ()->add_l2ndb (db.release ());
l2ndb_cb->setCurrentIndex (l2n_index);

View File

@ -23,6 +23,7 @@
#include "layNetlistBrowserModel.h"
#include "layIndexedNetlistModel.h"
#include "layNetlistCrossReferenceModel.h"
#include "dbNetlistDeviceClasses.h"
#include <QPainter>
@ -205,12 +206,19 @@ static inline bool always (bool)
}
NetlistBrowserModel::NetlistBrowserModel (QWidget *parent, db::LayoutToNetlist *l2ndb, NetColorizer *colorizer)
: QAbstractItemModel (parent), mp_l2ndb (l2ndb), mp_colorizer (colorizer)
: QAbstractItemModel (parent), mp_l2ndb (l2ndb), mp_lvsdb (0), mp_colorizer (colorizer)
{
mp_indexer.reset (new SingleIndexedNetlistModel (l2ndb->netlist ()));
connect (mp_colorizer, SIGNAL (colors_changed ()), this, SLOT (colors_changed ()));
}
NetlistBrowserModel::NetlistBrowserModel (QWidget *parent, db::LayoutVsSchematic *lvsdb, NetColorizer *colorizer)
: QAbstractItemModel (parent), mp_l2ndb (0), mp_lvsdb (lvsdb), mp_colorizer (colorizer)
{
mp_indexer.reset (new NetlistCrossReferenceModel (lvsdb->cross_ref ()));
connect (mp_colorizer, SIGNAL (colors_changed ()), this, SLOT (colors_changed ()));
}
NetlistBrowserModel::~NetlistBrowserModel ()
{
// .. nothing yet ..
@ -307,6 +315,10 @@ NetlistBrowserModel::make_id_circuit_device_terminal (size_t circuit_index, size
bool
NetlistBrowserModel::is_id_circuit (void *id) const
{
if (mp_indexer->circuit_count () == 0) {
return false;
}
pop (id, mp_indexer->circuit_count ());
return id == 0;
}
@ -314,6 +326,10 @@ NetlistBrowserModel::is_id_circuit (void *id) const
bool
NetlistBrowserModel::is_id_circuit_pin (void *id) const
{
if (mp_indexer->circuit_count () == 0) {
return false;
}
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
pop (id, mp_indexer->circuit_count ());
return (pop (id, 8) == 1 && always (pop (id, mp_indexer->pin_count (circuits))) && id == 0);
@ -322,6 +338,10 @@ NetlistBrowserModel::is_id_circuit_pin (void *id) const
bool
NetlistBrowserModel::is_id_circuit_pin_net (void *id) const
{
if (mp_indexer->circuit_count () == 0) {
return false;
}
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
pop (id, mp_indexer->circuit_count ());
return (pop (id, 8) == 1 && always (pop (id, mp_indexer->pin_count (circuits))) && id != 0);
@ -330,6 +350,10 @@ NetlistBrowserModel::is_id_circuit_pin_net (void *id) const
bool
NetlistBrowserModel::is_id_circuit_net (void *id) const
{
if (mp_indexer->circuit_count () == 0) {
return false;
}
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
pop (id, mp_indexer->circuit_count ());
return (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && id == 0);
@ -338,24 +362,50 @@ NetlistBrowserModel::is_id_circuit_net (void *id) const
bool
NetlistBrowserModel::is_id_circuit_net_device_terminal (void *id) const
{
if (mp_indexer->circuit_count () == 0) {
return false;
}
void *org_id = id;
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
IndexedNetlistModel::net_pair nets = nets_from_id (id);
pop (id, mp_indexer->circuit_count ());
return (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 1 && always (pop (id, mp_indexer->net_terminal_count (nets))) && id == 0);
if (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 1) {
IndexedNetlistModel::net_pair nets = nets_from_id (org_id);
pop (id, mp_indexer->net_terminal_count (nets));
return id == 0;
}
return false;
}
bool
NetlistBrowserModel::is_id_circuit_net_device_terminal_others (void *id) const
{
if (mp_indexer->circuit_count () == 0) {
return false;
}
void *org_id = id;
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
IndexedNetlistModel::net_pair nets = nets_from_id (id);
pop (id, mp_indexer->circuit_count ());
return (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 1 && always (pop (id, mp_indexer->net_terminal_count (nets))) && id != 0);
if (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 1) {
IndexedNetlistModel::net_pair nets = nets_from_id (org_id);
pop (id, mp_indexer->net_terminal_count (nets));
return id != 0;
}
return false;
}
bool
NetlistBrowserModel::is_id_circuit_net_pin (void *id) const
{
if (mp_indexer->circuit_count () == 0) {
return false;
}
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
pop (id, mp_indexer->circuit_count ());
return (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 2);
@ -364,24 +414,50 @@ NetlistBrowserModel::is_id_circuit_net_pin (void *id) const
bool
NetlistBrowserModel::is_id_circuit_net_subcircuit_pin (void *id) const
{
if (mp_indexer->circuit_count () == 0) {
return false;
}
void *org_id = id;
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
IndexedNetlistModel::net_pair nets = nets_from_id (id);
pop (id, mp_indexer->circuit_count ());
return (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 3 && always (pop (id, mp_indexer->net_subcircuit_pin_count (nets))) && id == 0);
if (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 3) {
IndexedNetlistModel::net_pair nets = nets_from_id (org_id);
pop (id, mp_indexer->net_subcircuit_pin_count (nets));
return id == 0;
}
return false;
}
bool
NetlistBrowserModel::is_id_circuit_net_subcircuit_pin_others (void *id) const
{
if (mp_indexer->circuit_count () == 0) {
return false;
}
void *org_id = id;
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
IndexedNetlistModel::net_pair nets = nets_from_id (id);
pop (id, mp_indexer->circuit_count ());
return (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 3 && always (pop (id, mp_indexer->net_subcircuit_pin_count (nets))) && id != 0);
if (pop (id, 8) == 2 && always (pop (id, mp_indexer->net_count (circuits))) && pop (id, 4) == 3) {
IndexedNetlistModel::net_pair nets = nets_from_id (org_id);
pop (id, mp_indexer->net_subcircuit_pin_count (nets));
return id != 0;
}
return false;
}
bool
NetlistBrowserModel::is_id_circuit_subcircuit (void *id) const
{
if (mp_indexer->circuit_count () == 0) {
return false;
}
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
pop (id, mp_indexer->circuit_count ());
return (pop (id, 8) == 3 && always (pop (id, mp_indexer->subcircuit_count (circuits))) && id == 0);
@ -390,6 +466,10 @@ NetlistBrowserModel::is_id_circuit_subcircuit (void *id) const
bool
NetlistBrowserModel::is_id_circuit_subcircuit_pin (void *id) const
{
if (mp_indexer->circuit_count () == 0) {
return false;
}
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
pop (id, mp_indexer->circuit_count ());
return (pop (id, 8) == 3 && always (pop (id, mp_indexer->subcircuit_count (circuits))) && id != 0);
@ -398,6 +478,10 @@ NetlistBrowserModel::is_id_circuit_subcircuit_pin (void *id) const
bool
NetlistBrowserModel::is_id_circuit_device (void *id) const
{
if (mp_indexer->circuit_count () == 0) {
return false;
}
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
pop (id, mp_indexer->circuit_count ());
return (pop (id, 8) == 4 && always (pop (id, mp_indexer->device_count (circuits))) && id == 0);
@ -406,6 +490,10 @@ NetlistBrowserModel::is_id_circuit_device (void *id) const
bool
NetlistBrowserModel::is_id_circuit_device_terminal (void *id) const
{
if (mp_indexer->circuit_count () == 0) {
return false;
}
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
pop (id, mp_indexer->circuit_count ());
return (pop (id, 8) == 4 && always (pop (id, mp_indexer->device_count (circuits))) && id != 0);
@ -884,7 +972,7 @@ NetlistBrowserModel::text (const QModelIndex &index) const
if (index.column () == 0) {
return tl::to_qstring (str_from_names (circuits, mp_indexer->is_single ()));
} else if (!mp_indexer->is_single ()) {
return tl::to_qstring (str_from_name (index.column () == 2 ? circuits.first : circuits.second));
return tl::to_qstring (str_from_name (index.column () == 1 ? circuits.first : circuits.second));
}
} else if (is_id_circuit_pin (id)) {
@ -896,7 +984,7 @@ NetlistBrowserModel::text (const QModelIndex &index) const
if (index.column () == 0) {
return tl::to_qstring (str_from_expanded_names (pins, mp_indexer->is_single ()));
} else if (!mp_indexer->is_single ()) {
return tl::to_qstring (str_from_expanded_name (index.column () == 2 ? pins.first : pins.second));
return tl::to_qstring (str_from_expanded_name (index.column () == 1 ? pins.first : pins.second));
}
} else if (is_id_circuit_pin_net (id)) {
@ -1468,104 +1556,6 @@ NetlistBrowserModel::flags (const QModelIndex & /*index*/) const
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
static size_t device_rows_for (const db::Circuit *circuit)
{
if (! circuit) {
return 0;
} else {
return circuit->device_count ();
}
}
static size_t device_rows_for (const IndexedNetlistModel::circuit_pair &circuits)
{
return std::max (device_rows_for (circuits.first), device_rows_for (circuits.second));
}
static size_t pin_rows_for (const db::Circuit *circuit)
{
if (! circuit) {
return 0;
} else {
return circuit->pin_count ();
}
}
static size_t pin_rows_for (const IndexedNetlistModel::circuit_pair &circuits)
{
return std::max (pin_rows_for (circuits.first), pin_rows_for (circuits.second));
}
static size_t net_rows_for (const db::Circuit *circuit)
{
if (! circuit) {
return 0;
} else {
return circuit->net_count ();
}
}
static size_t net_rows_for (const IndexedNetlistModel::circuit_pair &circuits)
{
return std::max (net_rows_for (circuits.first), net_rows_for (circuits.second));
}
static size_t subcircuit_rows_for (const db::Circuit *circuit)
{
if (! circuit) {
return 0;
} else {
return circuit->subcircuit_count ();
}
}
static size_t subcircuit_rows_for (const IndexedNetlistModel::circuit_pair &circuits)
{
return std::max (subcircuit_rows_for (circuits.first), subcircuit_rows_for (circuits.second));
}
static size_t pin_rows_for (const db::Net *net)
{
if (! net) {
return 0;
} else {
return net->pin_count ();
}
}
static size_t pin_rows_for (const IndexedNetlistModel::net_pair &nets)
{
return std::max (pin_rows_for (nets.first), pin_rows_for (nets.second));
}
static size_t subcircuit_rows_for (const db::Net *net)
{
if (! net) {
return 0;
} else {
return net->subcircuit_pin_count ();
}
}
static size_t subcircuit_rows_for (const IndexedNetlistModel::net_pair &nets)
{
return std::max (subcircuit_rows_for (nets.first), subcircuit_rows_for (nets.second));
}
static size_t terminal_rows_for (const db::Net *net)
{
if (! net) {
return 0;
} else {
return net->terminal_count ();
}
}
static size_t terminal_rows_for (const IndexedNetlistModel::net_pair &nets)
{
return std::max (terminal_rows_for (nets.first), terminal_rows_for (nets.second));
}
static size_t rows_for (const db::Device *device)
{
if (! device || ! device->device_class ()) {
@ -1607,7 +1597,7 @@ NetlistBrowserModel::hasChildren (const QModelIndex &parent) const
{
if (! parent.isValid ()) {
return mp_l2ndb->netlist () && mp_l2ndb->netlist ()->circuit_count () > 0;
return mp_indexer.get () && mp_indexer->circuit_count () > 0;
} else {
@ -1616,10 +1606,10 @@ NetlistBrowserModel::hasChildren (const QModelIndex &parent) const
if (is_id_circuit (id)) {
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
return device_rows_for (circuits.first) > 0 || device_rows_for (circuits.second) > 0 ||
subcircuit_rows_for (circuits.first) > 0 || subcircuit_rows_for (circuits.second) > 0 ||
pin_rows_for (circuits.first) > 0 || pin_rows_for (circuits.second) > 0 ||
net_rows_for (circuits.first) > 0 || net_rows_for (circuits.second) > 0;
return mp_indexer->device_count (circuits) > 0 ||
mp_indexer->subcircuit_count (circuits) > 0 ||
mp_indexer->pin_count (circuits) > 0 ||
mp_indexer->net_count (circuits) > 0;
} else if (is_id_circuit_pin (id)) {
@ -1638,9 +1628,9 @@ NetlistBrowserModel::hasChildren (const QModelIndex &parent) const
} else if (is_id_circuit_net (id)) {
IndexedNetlistModel::net_pair nets = nets_from_id (id);
return pin_rows_for (nets.first) > 0 || pin_rows_for (nets.second) > 0 ||
terminal_rows_for (nets.first) > 0 || terminal_rows_for (nets.second) > 0 ||
subcircuit_rows_for (nets.first) > 0 || subcircuit_rows_for (nets.second) > 0;
return mp_indexer->net_pin_count (nets) > 0 ||
mp_indexer->net_terminal_count (nets) > 0 ||
mp_indexer->net_subcircuit_pin_count (nets) > 0;
} else if (is_id_circuit_net_subcircuit_pin (id)) {
@ -1691,22 +1681,22 @@ NetlistBrowserModel::index (int row, int column, const QModelIndex &parent) cons
int r = row;
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
int rpins = int (pin_rows_for (circuits));
int rpins = int (mp_indexer->pin_count (circuits));
if (r < rpins) {
new_id = make_id_circuit_pin (circuit_index_from_id (id), size_t (r));
} else {
r -= rpins;
int rnets = int (net_rows_for (circuits));
int rnets = int (mp_indexer->net_count (circuits));
if (r < int (rnets)) {
new_id = make_id_circuit_net (circuit_index_from_id (id), size_t (r));
} else {
r -= int (rnets);
int rsubcircuits = int (subcircuit_rows_for (circuits));
int rsubcircuits = int (mp_indexer->subcircuit_count (circuits));
if (r < rsubcircuits) {
new_id = make_id_circuit_subcircuit (circuit_index_from_id (id), size_t (r));
} else {
r -= rsubcircuits;
if (r < int (device_rows_for (circuits))) {
if (r < int (mp_indexer->device_count (circuits))) {
new_id = make_id_circuit_device (circuit_index_from_id (id), size_t (r));
}
}
@ -1729,17 +1719,17 @@ NetlistBrowserModel::index (int row, int column, const QModelIndex &parent) cons
int r = row;
IndexedNetlistModel::net_pair nets = nets_from_id (id);
int rterminals = int (terminal_rows_for (nets));
int rterminals = int (mp_indexer->net_terminal_count (nets));
if (r < rterminals){
new_id = make_id_circuit_net_device_terminal (circuit_index_from_id (id), circuit_net_index_from_id (id), size_t (r));
} else {
r -= rterminals;
int rpins = int (pin_rows_for (nets));
int rpins = int (mp_indexer->net_pin_count (nets));
if (r < rpins) {
new_id = make_id_circuit_net_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), size_t (r));
} else {
r -= rpins;
if (r < int (subcircuit_rows_for (nets))) {
if (r < int (mp_indexer->net_subcircuit_pin_count (nets))) {
new_id = make_id_circuit_net_subcircuit_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), size_t (r));
}
}
@ -1893,7 +1883,7 @@ NetlistBrowserModel::index_from_id (void *id, int column) const
} else if (is_id_circuit_net (id)) {
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
return createIndex (int (pin_rows_for (circuits) + circuit_net_index_from_id (id)), column, id);
return createIndex (int (mp_indexer->pin_count (circuits) + circuit_net_index_from_id (id)), column, id);
} else if (is_id_circuit_net_device_terminal (id)) {
@ -1906,12 +1896,12 @@ NetlistBrowserModel::index_from_id (void *id, int column) const
} else if (is_id_circuit_net_pin (id)) {
IndexedNetlistModel::net_pair nets = nets_from_id (id);
return createIndex (int (terminal_rows_for (nets) + circuit_net_pin_index_from_id (id)), column, id);
return createIndex (int (mp_indexer->net_terminal_count (nets) + circuit_net_pin_index_from_id (id)), column, id);
} else if (is_id_circuit_net_subcircuit_pin (id)) {
IndexedNetlistModel::net_pair nets = nets_from_id (id);
return createIndex (int (terminal_rows_for (nets) + pin_rows_for (nets) + circuit_net_subcircuit_pin_index_from_id (id)), column, id);
return createIndex (int (mp_indexer->net_terminal_count (nets) + mp_indexer->net_pin_count (nets) + circuit_net_subcircuit_pin_index_from_id (id)), column, id);
} else if (is_id_circuit_net_subcircuit_pin_others (id)) {
@ -1920,7 +1910,7 @@ NetlistBrowserModel::index_from_id (void *id, int column) const
} else if (is_id_circuit_subcircuit (id)) {
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
return createIndex (int (pin_rows_for (circuits) + net_rows_for (circuits) + circuit_subcircuit_index_from_id (id)), column, id);
return createIndex (int (mp_indexer->pin_count (circuits) + mp_indexer->net_count (circuits) + circuit_subcircuit_index_from_id (id)), column, id);
} else if (is_id_circuit_subcircuit_pin (id)) {
@ -1929,7 +1919,7 @@ NetlistBrowserModel::index_from_id (void *id, int column) const
} else if (is_id_circuit_device (id)) {
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
return createIndex (int (pin_rows_for (circuits) + net_rows_for (circuits) + subcircuit_rows_for (circuits) + circuit_device_index_from_id (id)), column, id);
return createIndex (int (mp_indexer->pin_count (circuits) + mp_indexer->net_count (circuits) + mp_indexer->subcircuit_count (circuits) + circuit_device_index_from_id (id)), column, id);
} else if (is_id_circuit_device_terminal (id)) {
@ -1967,17 +1957,17 @@ NetlistBrowserModel::parent (const QModelIndex &index) const
} else if (is_id_circuit_net_device_terminal (id) || is_id_circuit_net_pin (id) || is_id_circuit_net_subcircuit_pin (id)) {
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
return createIndex (int (pin_rows_for (circuits) + circuit_net_index_from_id (id)), column, make_id_circuit_net (circuit_index_from_id (id), circuit_net_index_from_id (id)));
return createIndex (int (mp_indexer->pin_count (circuits) + circuit_net_index_from_id (id)), column, make_id_circuit_net (circuit_index_from_id (id), circuit_net_index_from_id (id)));
} else if (is_id_circuit_subcircuit_pin (id)) {
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
return createIndex (int (pin_rows_for (circuits) + net_rows_for (circuits) + circuit_subcircuit_index_from_id (id)), column, make_id_circuit_subcircuit (circuit_index_from_id (id), circuit_subcircuit_index_from_id (id)));
return createIndex (int (mp_indexer->pin_count (circuits) + mp_indexer->net_count (circuits) + circuit_subcircuit_index_from_id (id)), column, make_id_circuit_subcircuit (circuit_index_from_id (id), circuit_subcircuit_index_from_id (id)));
} else if (is_id_circuit_device_terminal (id)) {
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
return createIndex (int (pin_rows_for (circuits) + net_rows_for (circuits) + subcircuit_rows_for (circuits) + circuit_device_index_from_id (id)), column, make_id_circuit_device (circuit_index_from_id (id), circuit_device_index_from_id (id)));
return createIndex (int (mp_indexer->pin_count (circuits) + mp_indexer->net_count (circuits) + mp_indexer->subcircuit_count (circuits) + circuit_device_index_from_id (id)), column, make_id_circuit_device (circuit_index_from_id (id), circuit_device_index_from_id (id)));
} else if (is_id_circuit_net_device_terminal_others (id)) {
@ -1986,7 +1976,7 @@ NetlistBrowserModel::parent (const QModelIndex &index) const
} else if (is_id_circuit_net_subcircuit_pin_others (id)) {
IndexedNetlistModel::net_pair nets = nets_from_id (id);
return createIndex (size_t (terminal_rows_for (nets) + pin_rows_for (nets) + circuit_net_subcircuit_pin_index_from_id (id)), column, make_id_circuit_net_subcircuit_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), circuit_net_subcircuit_pin_index_from_id (id)));
return createIndex (size_t (mp_indexer->net_terminal_count (nets) + mp_indexer->net_pin_count (nets) + circuit_net_subcircuit_pin_index_from_id (id)), column, make_id_circuit_net_subcircuit_pin (circuit_index_from_id (id), circuit_net_index_from_id (id), circuit_net_subcircuit_pin_index_from_id (id)));
}
@ -2000,7 +1990,7 @@ NetlistBrowserModel::rowCount (const QModelIndex &parent) const
{
if (! parent.isValid ()) {
return int (mp_l2ndb->netlist ()->circuit_count ());
return int (mp_indexer.get () ? mp_indexer->circuit_count () : 0);
} else {
@ -2009,7 +1999,7 @@ NetlistBrowserModel::rowCount (const QModelIndex &parent) const
if (is_id_circuit (id)) {
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
return int (pin_rows_for (circuits) + net_rows_for (circuits) + subcircuit_rows_for (circuits) + device_rows_for (circuits));
return int (mp_indexer->pin_count (circuits) + mp_indexer->net_count (circuits) + mp_indexer->subcircuit_count (circuits) + mp_indexer->device_count (circuits));
} else if (is_id_circuit_pin (id)) {
@ -2038,7 +2028,7 @@ NetlistBrowserModel::rowCount (const QModelIndex &parent) const
} else if (is_id_circuit_net (id)) {
IndexedNetlistModel::net_pair nets = nets_from_id (id);
return int (terminal_rows_for (nets) + pin_rows_for (nets) + subcircuit_rows_for (nets));
return int (mp_indexer->net_terminal_count (nets) + mp_indexer->net_pin_count (nets) + mp_indexer->net_subcircuit_pin_count (nets));
}

View File

@ -28,6 +28,7 @@
#include "laybasicCommon.h"
#include "dbLayoutToNetlist.h"
#include "dbLayoutVsSchematic.h"
#include <QAbstractItemModel>
#include <QColor>
@ -110,6 +111,7 @@ Q_OBJECT
public:
NetlistBrowserModel (QWidget *parent, db::LayoutToNetlist *l2ndb, NetColorizer *colorizer);
NetlistBrowserModel (QWidget *parent, db::LayoutVsSchematic *lvsdb, NetColorizer *colorizer);
~NetlistBrowserModel ();
virtual int columnCount (const QModelIndex &parent) const;
@ -202,6 +204,7 @@ private:
QIcon icon_for_connection (const std::pair<const db::Net *, const db::Net *> &net) const;
db::LayoutToNetlist *mp_l2ndb;
db::LayoutVsSchematic *mp_lvsdb;
NetColorizer *mp_colorizer;
std::auto_ptr<IndexedNetlistModel> mp_indexer;
mutable std::map<lay::color_t, QIcon> m_net_icon_per_color;

View File

@ -617,28 +617,34 @@ NetlistBrowserPage::show_all (bool f)
}
void
NetlistBrowserPage::set_l2ndb (db::LayoutToNetlist *database)
NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb)
{
if (mp_info_dialog) {
delete mp_info_dialog;
mp_info_dialog = 0;
}
mp_database.reset (database);
db::LayoutVsSchematic *lvsdb = dynamic_cast<db::LayoutVsSchematic *> (l2ndb);
mp_database.reset (l2ndb);
clear_markers ();
highlight (std::vector<const db::Net *> (), std::vector<const db::Device *> (), std::vector<const db::SubCircuit *> ());
if (! database) {
if (! mp_database.get ()) {
delete directory_tree->model ();
directory_tree->setModel (0);
return;
}
m_cell_context_cache = db::ContextCache (database->internal_layout ());
m_cell_context_cache = db::ContextCache (mp_database->internal_layout ());
// NOTE: with the tree as the parent, the tree will take over ownership of the model
NetlistBrowserModel *new_model = new NetlistBrowserModel (directory_tree, database, &m_colorizer);
NetlistBrowserModel *new_model = 0;
if (lvsdb) {
new_model = new NetlistBrowserModel (directory_tree, lvsdb, &m_colorizer);
} else {
new_model = new NetlistBrowserModel (directory_tree, l2ndb, &m_colorizer);
}
delete directory_tree->model ();
directory_tree->setModel (new_model);

View File

@ -29,6 +29,7 @@
#include "layNetlistBrowser.h"
#include "laybasicCommon.h"
#include "dbLayoutToNetlist.h"
#include "dbLayoutVsSchematic.h"
#include "dbLayoutUtils.h"
#include "tlObject.h"
@ -82,11 +83,28 @@ public:
void set_view (lay::LayoutView *view, unsigned int cv_index);
/**
* @brief Attach the page to a L2N DB
*
* To detach the page from any L2N DB, pass 0 for the pointer.
* @brief Attaches the page to a L2N DB
*/
void set_l2ndb (db::LayoutToNetlist *database);
void set_l2ndb (db::LayoutToNetlist *database)
{
set_db (database);
}
/**
* @brief Attaches the page to a LVS DB
*/
void set_lvsdb (db::LayoutVsSchematic *database)
{
set_db (database);
}
/**
* @brief Detaches the page from any DB
*/
void reset_db ()
{
set_db (0);
}
/**
* @brief Selects a net or clears the selection if net == 0
@ -188,6 +206,7 @@ private:
tl::DeferredMethod<NetlistBrowserPage> dm_update_highlights;
db::ContextCache m_cell_context_cache;
void set_db (db::LayoutToNetlist *l2ndb);
void add_to_history (void *id, bool fwd);
void navigate_to (void *id, bool forward = true);
void adjust_view ();

View File

@ -39,37 +39,44 @@ size_t NetlistCrossReferenceModel::circuit_count () const
size_t NetlistCrossReferenceModel::net_count (const circuit_pair &circuits) const
{
return std::max (circuits.first ? circuits.first->net_count () : 0, circuits.second ? circuits.second->net_count () : 0);
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
return data ? data->nets.size () : 0;
}
size_t NetlistCrossReferenceModel::net_terminal_count (const net_pair &nets) const
{
return std::max (nets.first ? nets.first->terminal_count () : 0, nets.second ? nets.second->terminal_count () : 0);
const db::NetlistCrossReference::PerNetData *data = mp_cross_ref->per_net_data_for (nets);
return data ? data->terminals.size () : 0;
}
size_t NetlistCrossReferenceModel::net_subcircuit_pin_count (const net_pair &nets) const
{
return std::max (nets.first ? nets.first->subcircuit_pin_count () : 0, nets.second ? nets.second->subcircuit_pin_count () : 0);
const db::NetlistCrossReference::PerNetData *data = mp_cross_ref->per_net_data_for (nets);
return data ? data->subcircuit_pins.size () : 0;
}
size_t NetlistCrossReferenceModel::net_pin_count (const net_pair &nets) const
{
return std::max (nets.first ? nets.first->pin_count () : 0, nets.second ? nets.second->pin_count () : 0);
const db::NetlistCrossReference::PerNetData *data = mp_cross_ref->per_net_data_for (nets);
return data ? data->pins.size () : 0;
}
size_t NetlistCrossReferenceModel::device_count (const circuit_pair &circuits) const
{
return std::max (circuits.first ? circuits.first->device_count () : 0, circuits.second ? circuits.second->device_count () : 0);
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
return data ? data->devices.size () : 0;
}
size_t NetlistCrossReferenceModel::pin_count (const circuit_pair &circuits) const
{
return std::max (circuits.first ? circuits.first->pin_count () : 0, circuits.second ? circuits.second->pin_count () : 0);
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
return data ? data->pins.size () : 0;
}
size_t NetlistCrossReferenceModel::subcircuit_count (const circuit_pair &circuits) const
{
return std::max (circuits.first ? circuits.first->subcircuit_count () : 0, circuits.second ? circuits.second->subcircuit_count () : 0);
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
return data ? data->subcircuits.size () : 0;
}
namespace {

View File

@ -217,3 +217,34 @@ TEST (1)
EXPECT_EQ (model->rowCount (inv2Device1GateIndex), 0);
}
TEST (2)
{
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));
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, 1, QModelIndex ()), Qt::DisplayRole).toString ()), "");
EXPECT_EQ (tl::to_string (model->data (model->index (0, 2, QModelIndex ()), Qt::DisplayRole).toString ()), "INV2PAIRX");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 0, QModelIndex ()), Qt::DisplayRole).toString ()), "INV2/INV2");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 1, QModelIndex ()), Qt::DisplayRole).toString ()), "INV2");
EXPECT_EQ (tl::to_string (model->data (model->index (1, 2, QModelIndex ()), Qt::DisplayRole).toString ()), "INV2");
EXPECT_EQ (model->parent (model->index (0, 0, QModelIndex ())).isValid (), false);
EXPECT_EQ (model->parent (model->index (1, 0, QModelIndex ())).isValid (), false);
EXPECT_EQ (model->hasChildren (model->index (0, 0, QModelIndex ())), false);
EXPECT_EQ (model->rowCount (model->index (0, 0, QModelIndex ())), 0);
QModelIndex inv2Index = model->index (1, 0, QModelIndex ());
EXPECT_EQ (model->hasChildren (inv2Index), true);
EXPECT_EQ (model->rowCount (inv2Index), 14);
// ...
}

1002
testdata/lay/lvsdb_browser.lvsdb vendored Normal file

File diff suppressed because it is too large Load Diff