mirror of https://github.com/KLayout/klayout.git
WIP: refactoring of LVS/L2N DB readers
This commit is contained in:
parent
c09db62cf6
commit
bee662eea8
|
|
@ -111,6 +111,7 @@ LayoutToNetlistStandardReader::read_double ()
|
|||
bool
|
||||
LayoutToNetlistStandardReader::at_end ()
|
||||
{
|
||||
skip ();
|
||||
return (m_ex.at_end () && m_stream.at_end ());
|
||||
}
|
||||
|
||||
|
|
@ -129,7 +130,7 @@ LayoutToNetlistStandardReader::skip ()
|
|||
void LayoutToNetlistStandardReader::read (db::LayoutToNetlist *l2n)
|
||||
{
|
||||
try {
|
||||
do_read (l2n);
|
||||
do_read (0, l2n);
|
||||
} catch (tl::Exception &ex) {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("%s in line: %d of %s")), ex.msg (), m_stream.line_number (), m_path));
|
||||
}
|
||||
|
|
@ -144,20 +145,28 @@ static db::Region &layer_by_name (db::LayoutToNetlist *l2n, const std::string &n
|
|||
return *l;
|
||||
}
|
||||
|
||||
void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n, bool nested)
|
||||
void LayoutToNetlistStandardReader::do_read (db::Netlist *netlist, db::LayoutToNetlist *l2n, bool nested, std::map<const db::Circuit *, std::map<unsigned int, Net *> > *id2net_per_circuit)
|
||||
{
|
||||
int version = 0;
|
||||
std::string description;
|
||||
|
||||
tl_assert (l2n->internal_layout ());
|
||||
l2n->internal_layout ()->dbu (1.0); // mainly for testing
|
||||
if (l2n) {
|
||||
|
||||
if (l2n->internal_layout ()->cells () == 0) {
|
||||
l2n->internal_layout ()->add_cell ("TOP");
|
||||
tl_assert (netlist == 0);
|
||||
|
||||
tl_assert (l2n->internal_layout ());
|
||||
l2n->internal_layout ()->dbu (1.0); // mainly for testing
|
||||
|
||||
if (l2n->internal_layout ()->cells () == 0) {
|
||||
l2n->internal_layout ()->add_cell ("TOP");
|
||||
}
|
||||
tl_assert (l2n->internal_top_cell () != 0);
|
||||
|
||||
netlist = l2n->make_netlist ();
|
||||
|
||||
} else {
|
||||
tl_assert (netlist != 0);
|
||||
}
|
||||
tl_assert (l2n->internal_top_cell () != 0);
|
||||
|
||||
l2n->make_netlist ();
|
||||
|
||||
while (! at_end ()) {
|
||||
|
||||
|
|
@ -173,14 +182,14 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n, bool nest
|
|||
read_word_or_quoted (description);
|
||||
br.done ();
|
||||
|
||||
} else if (test (skeys::unit_key) || test (lkeys::unit_key)) {
|
||||
} else if (l2n && (test (skeys::unit_key) || test (lkeys::unit_key))) {
|
||||
|
||||
Brace br (this);
|
||||
double dbu = read_double ();
|
||||
l2n->internal_layout ()->dbu (dbu);
|
||||
br.done ();
|
||||
|
||||
} else if (test (skeys::top_key) || test (lkeys::top_key)) {
|
||||
} else if (l2n && (test (skeys::top_key) || test (lkeys::top_key))) {
|
||||
|
||||
Brace br (this);
|
||||
std::string top;
|
||||
|
|
@ -188,7 +197,7 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n, bool nest
|
|||
l2n->internal_layout ()->rename_cell (l2n->internal_top_cell ()->cell_index (), top.c_str ());
|
||||
br.done ();
|
||||
|
||||
} else if (test (skeys::layer_key) || test (lkeys::layer_key)) {
|
||||
} else if (l2n && (test (skeys::layer_key) || test (lkeys::layer_key))) {
|
||||
|
||||
Brace br (this);
|
||||
std::string layer, lspec;
|
||||
|
|
@ -216,7 +225,7 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n, bool nest
|
|||
read_word_or_quoted (templ_name);
|
||||
br.done ();
|
||||
|
||||
if (l2n->netlist ()->device_class_by_name (class_name) != 0) {
|
||||
if (netlist->device_class_by_name (class_name) != 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Device class must be defined before being used in device")));
|
||||
}
|
||||
|
||||
|
|
@ -227,9 +236,9 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n, bool nest
|
|||
|
||||
db::DeviceClass *dc = dct->create ();
|
||||
dc->set_name (class_name);
|
||||
l2n->netlist ()->add_device_class (dc);
|
||||
netlist->add_device_class (dc);
|
||||
|
||||
} else if (test (skeys::connect_key) || test (lkeys::connect_key)) {
|
||||
} else if (l2n && (test (skeys::connect_key) || test (lkeys::connect_key))) {
|
||||
|
||||
Brace br (this);
|
||||
std::string l1;
|
||||
|
|
@ -241,7 +250,7 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n, bool nest
|
|||
}
|
||||
br.done ();
|
||||
|
||||
} else if (test (skeys::global_key) || test (lkeys::global_key)) {
|
||||
} else if (l2n && (test (skeys::global_key) || test (lkeys::global_key))) {
|
||||
|
||||
Brace br (this);
|
||||
std::string l1;
|
||||
|
|
@ -261,26 +270,36 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n, bool nest
|
|||
|
||||
db::Circuit *circuit = new db::Circuit ();
|
||||
circuit->set_name (name);
|
||||
l2n->netlist ()->add_circuit (circuit);
|
||||
netlist->add_circuit (circuit);
|
||||
|
||||
db::Layout *ly = l2n->internal_layout ();
|
||||
std::pair<bool, db::cell_index_type> ci_old = ly->cell_by_name (name.c_str ());
|
||||
db::cell_index_type ci = ci_old.first ? ci_old.second : ly->add_cell (name.c_str ());
|
||||
circuit->set_cell_index (ci);
|
||||
db::cell_index_type device_cell_index = 0;
|
||||
|
||||
if (l2n) {
|
||||
|
||||
db::Layout *ly = l2n->internal_layout ();
|
||||
std::pair<bool, db::cell_index_type> ci_old = ly->cell_by_name (name.c_str ());
|
||||
device_cell_index = ci_old.first ? ci_old.second : ly->add_cell (name.c_str ());
|
||||
circuit->set_cell_index (device_cell_index);
|
||||
|
||||
}
|
||||
|
||||
std::map<db::CellInstArray, std::list<Connections> > connections;
|
||||
std::map<unsigned int, Net *> id2net;
|
||||
std::map<unsigned int, Net *> id2net_local;
|
||||
std::map<unsigned int, Net *> *id2net = &id2net_local;
|
||||
if (id2net_per_circuit) {
|
||||
id2net = &(*id2net_per_circuit)[circuit];
|
||||
}
|
||||
|
||||
while (br) {
|
||||
|
||||
if (test (skeys::net_key) || test (lkeys::net_key)) {
|
||||
read_net (l2n, circuit, id2net);
|
||||
read_net (netlist, l2n, circuit, *id2net);
|
||||
} else if (test (skeys::pin_key) || test (lkeys::pin_key)) {
|
||||
read_pin (l2n, circuit, id2net);
|
||||
read_pin (netlist, l2n, circuit, *id2net);
|
||||
} else if (test (skeys::device_key) || test (lkeys::device_key)) {
|
||||
read_device (l2n, circuit, id2net, connections);
|
||||
read_device (netlist, l2n, circuit, *id2net, connections);
|
||||
} else if (test (skeys::circuit_key) || test (lkeys::circuit_key)) {
|
||||
read_subcircuit (l2n, circuit, id2net, connections);
|
||||
read_subcircuit (netlist, l2n, circuit, *id2net, connections);
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid keyword inside circuit definition (net, pin, device or circuit expected)")));
|
||||
}
|
||||
|
|
@ -288,17 +307,22 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n, bool nest
|
|||
}
|
||||
br.done ();
|
||||
|
||||
db::Cell &ccell = ly->cell (ci);
|
||||
if (l2n) {
|
||||
|
||||
// connections needs to be made after the instances (because in a readonly Instances container
|
||||
// the Instance pointers will invalidate when new instances are added)
|
||||
for (db::Cell::const_iterator i = ccell.begin (); ! i.at_end (); ++i) {
|
||||
std::map<db::CellInstArray, std::list<Connections> >::const_iterator c = connections.find (i->cell_inst ());
|
||||
if (c != connections.end ()) {
|
||||
for (std::list<Connections>::const_iterator j = c->second.begin (); j != c->second.end (); ++j) {
|
||||
l2n->net_clusters ().clusters_per_cell (ci).add_connection (j->from_cluster, db::ClusterInstance (j->to_cluster, i->cell_index (), i->complex_trans (), i->prop_id ()));
|
||||
db::Layout *ly = l2n->internal_layout ();
|
||||
db::Cell &ccell = ly->cell (device_cell_index);
|
||||
|
||||
// connections needs to be made after the instances (because in a readonly Instances container
|
||||
// the Instance pointers will invalidate when new instances are added)
|
||||
for (db::Cell::const_iterator i = ccell.begin (); ! i.at_end (); ++i) {
|
||||
std::map<db::CellInstArray, std::list<Connections> >::const_iterator c = connections.find (i->cell_inst ());
|
||||
if (c != connections.end ()) {
|
||||
for (std::list<Connections>::const_iterator j = c->second.begin (); j != c->second.end (); ++j) {
|
||||
l2n->net_clusters ().clusters_per_cell (device_cell_index).add_connection (j->from_cluster, db::ClusterInstance (j->to_cluster, i->cell_index (), i->complex_trans (), i->prop_id ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if (test (skeys::device_key) || test (lkeys::device_key)) {
|
||||
|
|
@ -309,22 +333,24 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n, bool nest
|
|||
|
||||
db::DeviceAbstract *dm = new db::DeviceAbstract ();
|
||||
dm->set_name (name);
|
||||
l2n->netlist ()->add_device_abstract (dm);
|
||||
netlist->add_device_abstract (dm);
|
||||
|
||||
db::cell_index_type ci = l2n->internal_layout ()->add_cell (name.c_str ());
|
||||
dm->set_cell_index (ci);
|
||||
if (l2n) {
|
||||
db::cell_index_type ci = l2n->internal_layout ()->add_cell (name.c_str ());
|
||||
dm->set_cell_index (ci);
|
||||
}
|
||||
|
||||
std::string cls;
|
||||
read_word_or_quoted (cls);
|
||||
|
||||
db::DeviceClass *dc = l2n->netlist ()->device_class_by_name (cls);
|
||||
db::DeviceClass *dc = netlist->device_class_by_name (cls);
|
||||
|
||||
// use a generic device class unless the right one is registered already.
|
||||
bool gen_dc = (dc == 0);
|
||||
if (gen_dc) {
|
||||
dc = new db::DeviceClass ();
|
||||
dc->set_name (cls);
|
||||
l2n->netlist ()->add_device_class (dc);
|
||||
netlist->add_device_class (dc);
|
||||
}
|
||||
|
||||
dm->set_device_class (dc);
|
||||
|
|
@ -349,7 +375,9 @@ void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n, bool nest
|
|||
|
||||
}
|
||||
|
||||
l2n->set_netlist_extracted ();
|
||||
if (l2n) {
|
||||
l2n->set_netlist_extracted ();
|
||||
}
|
||||
}
|
||||
|
||||
db::Point
|
||||
|
|
@ -429,7 +457,7 @@ LayoutToNetlistStandardReader::read_geometries (Brace &br, db::LayoutToNetlist *
|
|||
}
|
||||
|
||||
void
|
||||
LayoutToNetlistStandardReader::read_net (db::LayoutToNetlist *l2n, db::Circuit *circuit, std::map<unsigned int, Net *> &id2net)
|
||||
LayoutToNetlistStandardReader::read_net (db::Netlist * /*netlist*/, db::LayoutToNetlist *l2n, db::Circuit *circuit, std::map<unsigned int, Net *> &id2net)
|
||||
{
|
||||
Brace br (this);
|
||||
|
||||
|
|
@ -448,18 +476,22 @@ LayoutToNetlistStandardReader::read_net (db::LayoutToNetlist *l2n, db::Circuit *
|
|||
|
||||
id2net.insert (std::make_pair (id, net));
|
||||
|
||||
db::connected_clusters<db::PolygonRef> &cc = l2n->net_clusters ().clusters_per_cell (circuit->cell_index ());
|
||||
db::local_cluster<db::PolygonRef> &lc = *cc.insert ();
|
||||
net->set_cluster_id (lc.id ());
|
||||
if (l2n) {
|
||||
|
||||
db::Cell &cell = l2n->internal_layout ()->cell (circuit->cell_index ());
|
||||
read_geometries (br, l2n, lc, cell);
|
||||
db::connected_clusters<db::PolygonRef> &cc = l2n->net_clusters ().clusters_per_cell (circuit->cell_index ());
|
||||
db::local_cluster<db::PolygonRef> &lc = *cc.insert ();
|
||||
net->set_cluster_id (lc.id ());
|
||||
|
||||
db::Cell &cell = l2n->internal_layout ()->cell (circuit->cell_index ());
|
||||
read_geometries (br, l2n, lc, cell);
|
||||
|
||||
}
|
||||
|
||||
br.done ();
|
||||
}
|
||||
|
||||
void
|
||||
LayoutToNetlistStandardReader::read_pin (db::LayoutToNetlist * /*l2n*/, db::Circuit *circuit, std::map<unsigned int, Net *> &id2net)
|
||||
LayoutToNetlistStandardReader::read_pin (db::Netlist * /*netlist*/, db::LayoutToNetlist * /*l2n*/, db::Circuit *circuit, std::map<unsigned int, Net *> &id2net)
|
||||
{
|
||||
Brace br (this);
|
||||
std::string name;
|
||||
|
|
@ -503,7 +535,7 @@ LayoutToNetlistStandardReader::device_model_by_name (db::Netlist *netlist, const
|
|||
}
|
||||
|
||||
void
|
||||
LayoutToNetlistStandardReader::read_device (db::LayoutToNetlist *l2n, db::Circuit *circuit, std::map<unsigned int, Net *> &id2net, std::map<db::CellInstArray, std::list<Connections> > &connections)
|
||||
LayoutToNetlistStandardReader::read_device (db::Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, std::map<unsigned int, Net *> &id2net, std::map<db::CellInstArray, std::list<Connections> > &connections)
|
||||
{
|
||||
Brace br (this);
|
||||
|
||||
|
|
@ -513,7 +545,7 @@ LayoutToNetlistStandardReader::read_device (db::LayoutToNetlist *l2n, db::Circui
|
|||
std::string dmname;
|
||||
read_word_or_quoted (dmname);
|
||||
|
||||
db::DeviceAbstract *dm = device_model_by_name (l2n->netlist (), dmname);
|
||||
db::DeviceAbstract *dm = device_model_by_name (netlist, dmname);
|
||||
|
||||
db::Device *device = new db::Device ();
|
||||
device->set_device_class (const_cast<db::DeviceClass *> (dm->device_class ()));
|
||||
|
|
@ -549,7 +581,7 @@ LayoutToNetlistStandardReader::read_device (db::LayoutToNetlist *l2n, db::Circui
|
|||
|
||||
br2.done ();
|
||||
|
||||
db::DeviceAbstract *da = device_model_by_name (l2n->netlist (), n);
|
||||
db::DeviceAbstract *da = device_model_by_name (netlist, n);
|
||||
|
||||
device->other_abstracts ().push_back (db::DeviceAbstractRef (da, db::DVector (dbu * dx, dbu * dy)));
|
||||
|
||||
|
|
@ -628,53 +660,57 @@ LayoutToNetlistStandardReader::read_device (db::LayoutToNetlist *l2n, db::Circui
|
|||
|
||||
br.done ();
|
||||
|
||||
db::Cell &ccell = l2n->internal_layout ()->cell (circuit->cell_index ());
|
||||
if (l2n) {
|
||||
|
||||
// make device cell instances
|
||||
std::vector<db::CellInstArray> insts;
|
||||
db::Cell &ccell = l2n->internal_layout ()->cell (circuit->cell_index ());
|
||||
|
||||
db::CellInstArray inst (db::CellInst (dm->cell_index ()), db::Trans (db::Vector (x, y)));
|
||||
ccell.insert (inst);
|
||||
insts.push_back (inst);
|
||||
// make device cell instances
|
||||
std::vector<db::CellInstArray> insts;
|
||||
|
||||
const std::vector<db::DeviceAbstractRef> &other_devices = device->other_abstracts ();
|
||||
for (std::vector<db::DeviceAbstractRef>::const_iterator i = other_devices.begin (); i != other_devices.end (); ++i) {
|
||||
db::CellInstArray inst (db::CellInst (dm->cell_index ()), db::Trans (db::Vector (x, y)));
|
||||
ccell.insert (inst);
|
||||
insts.push_back (inst);
|
||||
|
||||
db::CellInstArray other_inst (db::CellInst (i->device_abstract->cell_index ()), db::Trans (db::Vector (x, y) + dbu_inv * i->offset));
|
||||
ccell.insert (other_inst);
|
||||
insts.push_back (other_inst);
|
||||
const std::vector<db::DeviceAbstractRef> &other_devices = device->other_abstracts ();
|
||||
for (std::vector<db::DeviceAbstractRef>::const_iterator i = other_devices.begin (); i != other_devices.end (); ++i) {
|
||||
|
||||
}
|
||||
db::CellInstArray other_inst (db::CellInst (i->device_abstract->cell_index ()), db::Trans (db::Vector (x, y) + dbu_inv * i->offset));
|
||||
ccell.insert (other_inst);
|
||||
insts.push_back (other_inst);
|
||||
|
||||
// register cluster collections to be made later
|
||||
|
||||
for (size_t tid = 0; tid < max_tid; ++tid) {
|
||||
|
||||
const db::Net *net = device->net_for_terminal (tid);
|
||||
if (! net) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! device->reconnected_terminals ().empty ()) {
|
||||
// register cluster collections to be made later
|
||||
|
||||
const std::vector<db::DeviceReconnectedTerminal> *tr = device->reconnected_terminals_for (tid);
|
||||
if (tr) {
|
||||
|
||||
for (std::vector<db::DeviceReconnectedTerminal>::const_iterator i = tr->begin (); i != tr->end (); ++i) {
|
||||
const db::DeviceAbstract *da = dm;
|
||||
if (i->device_index > 0) {
|
||||
da = device->other_abstracts () [i->device_index - 1].device_abstract;
|
||||
}
|
||||
Connections ref (net->cluster_id (), da->cluster_id_for_terminal (i->other_terminal_id));
|
||||
connections [insts [i->device_index]].push_back (ref);
|
||||
}
|
||||
for (size_t tid = 0; tid < max_tid; ++tid) {
|
||||
|
||||
const db::Net *net = device->net_for_terminal (tid);
|
||||
if (! net) {
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (! device->reconnected_terminals ().empty ()) {
|
||||
|
||||
Connections ref (net->cluster_id (), dm->cluster_id_for_terminal (tid));
|
||||
connections [insts [0]].push_back (ref);
|
||||
const std::vector<db::DeviceReconnectedTerminal> *tr = device->reconnected_terminals_for (tid);
|
||||
if (tr) {
|
||||
|
||||
for (std::vector<db::DeviceReconnectedTerminal>::const_iterator i = tr->begin (); i != tr->end (); ++i) {
|
||||
const db::DeviceAbstract *da = dm;
|
||||
if (i->device_index > 0) {
|
||||
da = device->other_abstracts () [i->device_index - 1].device_abstract;
|
||||
}
|
||||
Connections ref (net->cluster_id (), da->cluster_id_for_terminal (i->other_terminal_id));
|
||||
connections [insts [i->device_index]].push_back (ref);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
Connections ref (net->cluster_id (), dm->cluster_id_for_terminal (tid));
|
||||
connections [insts [0]].push_back (ref);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -682,7 +718,7 @@ LayoutToNetlistStandardReader::read_device (db::LayoutToNetlist *l2n, db::Circui
|
|||
}
|
||||
|
||||
void
|
||||
LayoutToNetlistStandardReader::read_subcircuit (db::LayoutToNetlist *l2n, db::Circuit *circuit, std::map<unsigned int, Net *> &id2net, std::map<db::CellInstArray, std::list<Connections> > &connections)
|
||||
LayoutToNetlistStandardReader::read_subcircuit (db::Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, std::map<unsigned int, Net *> &id2net, std::map<db::CellInstArray, std::list<Connections> > &connections)
|
||||
{
|
||||
Brace br (this);
|
||||
|
||||
|
|
@ -694,7 +730,7 @@ LayoutToNetlistStandardReader::read_subcircuit (db::LayoutToNetlist *l2n, db::Ci
|
|||
std::string xname;
|
||||
read_word_or_quoted (xname);
|
||||
|
||||
db::Circuit *circuit_ref = l2n->netlist ()->circuit_by_name (xname);
|
||||
db::Circuit *circuit_ref = netlist->circuit_by_name (xname);
|
||||
if (! circuit_ref) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid device circuit name: ")) + xname);
|
||||
}
|
||||
|
|
@ -783,14 +819,18 @@ LayoutToNetlistStandardReader::read_subcircuit (db::LayoutToNetlist *l2n, db::Ci
|
|||
|
||||
br.done ();
|
||||
|
||||
double dbu = l2n->internal_layout ()->dbu ();
|
||||
subcircuit->set_trans (db::DCplxTrans (mag, angle, mirror, db::DVector (dbu * x, dbu * y)));
|
||||
if (l2n) {
|
||||
|
||||
db::CellInstArray inst (db::CellInst (circuit_ref->cell_index ()), db::ICplxTrans (mag, angle, mirror, db::Vector (x, y)));
|
||||
db::Cell &ccell = l2n->internal_layout ()->cell (circuit->cell_index ());
|
||||
ccell.insert (inst);
|
||||
double dbu = l2n->internal_layout ()->dbu ();
|
||||
subcircuit->set_trans (db::DCplxTrans (mag, angle, mirror, db::DVector (dbu * x, dbu * y)));
|
||||
|
||||
connections [inst] = refs;
|
||||
db::CellInstArray inst (db::CellInst (circuit_ref->cell_index ()), db::ICplxTrans (mag, angle, mirror, db::Vector (x, y)));
|
||||
db::Cell &ccell = l2n->internal_layout ()->cell (circuit->cell_index ());
|
||||
ccell.insert (inst);
|
||||
|
||||
connections [inst] = refs;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -819,12 +859,16 @@ LayoutToNetlistStandardReader::read_abstract_terminal (db::LayoutToNetlist *l2n,
|
|||
tid = dc->add_terminal_definition (new_td).id ();
|
||||
}
|
||||
|
||||
db::connected_clusters<db::PolygonRef> &cc = l2n->net_clusters ().clusters_per_cell (dm->cell_index ());
|
||||
db::local_cluster<db::PolygonRef> &lc = *cc.insert ();
|
||||
dm->set_cluster_id_for_terminal (tid, lc.id ());
|
||||
if (l2n) {
|
||||
|
||||
db::Cell &cell = l2n->internal_layout ()->cell (dm->cell_index ());
|
||||
read_geometries (br, l2n, lc, cell);
|
||||
db::connected_clusters<db::PolygonRef> &cc = l2n->net_clusters ().clusters_per_cell (dm->cell_index ());
|
||||
db::local_cluster<db::PolygonRef> &lc = *cc.insert ();
|
||||
dm->set_cluster_id_for_terminal (tid, lc.id ());
|
||||
|
||||
db::Cell &cell = l2n->internal_layout ()->cell (dm->cell_index ());
|
||||
read_geometries (br, l2n, lc, cell);
|
||||
|
||||
}
|
||||
|
||||
br.done ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ protected:
|
|||
friend class l2n_std_reader::Brace;
|
||||
typedef l2n_std_reader::Brace Brace;
|
||||
|
||||
void do_read (db::LayoutToNetlist *l2n, bool nested = false);
|
||||
void do_read (Netlist *netlist, db::LayoutToNetlist *l2n, bool nested = false, std::map<const db::Circuit *, std::map<unsigned int, Net *> > *id2net_per_circuit = 0);
|
||||
static size_t terminal_id (const db::DeviceClass *device_class, const std::string &tname);
|
||||
static db::DeviceAbstract *device_model_by_name (db::Netlist *netlist, const std::string &dmname);
|
||||
tl::TextInputStream &stream ();
|
||||
|
|
@ -110,10 +110,10 @@ protected:
|
|||
bool at_end ();
|
||||
void skip ();
|
||||
|
||||
void read_net (db::LayoutToNetlist *l2n, db::Circuit *circuit, std::map<unsigned int, db::Net *> &id2net);
|
||||
void read_pin (db::LayoutToNetlist *l2n, db::Circuit *circuit, std::map<unsigned int, db::Net *> &id2net);
|
||||
void read_device (db::LayoutToNetlist *l2n, db::Circuit *circuit, std::map<unsigned int, db::Net *> &id2net, std::map<db::CellInstArray, std::list<Connections> > &connections);
|
||||
void read_subcircuit (db::LayoutToNetlist *l2n, db::Circuit *circuit, std::map<unsigned int, db::Net *> &id2net, std::map<db::CellInstArray, std::list<Connections> > &connections);
|
||||
void read_net (Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, std::map<unsigned int, db::Net *> &id2net);
|
||||
void read_pin (Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, std::map<unsigned int, db::Net *> &id2net);
|
||||
void read_device (Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, std::map<unsigned int, db::Net *> &id2net, std::map<db::CellInstArray, std::list<Connections> > &connections);
|
||||
void read_subcircuit (Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, std::map<unsigned int, db::Net *> &id2net, std::map<db::CellInstArray, std::list<Connections> > &connections);
|
||||
void read_abstract_terminal (db::LayoutToNetlist *l2n, db::DeviceAbstract *dm, db::DeviceClass *dc);
|
||||
std::pair<unsigned int, db::PolygonRef> read_geometry (db::LayoutToNetlist *l2n);
|
||||
void read_geometries (Brace &br, db::LayoutToNetlist *l2n, db::local_cluster<db::PolygonRef> &lc, db::Cell &cell);
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ LayoutVsSchematic::LayoutVsSchematic ()
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
~LayoutVsSchematic ()
|
||||
LayoutVsSchematic::~LayoutVsSchematic ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -100,7 +100,7 @@ void db::LayoutVsSchematic::load (const std::string &path)
|
|||
db::LayoutVsSchematicStandardReader reader (stream);
|
||||
set_filename (path);
|
||||
set_name (stream.filename ());
|
||||
reader.read (this);
|
||||
reader.read_lvs (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ void LayoutVsSchematicStandardReader::do_read (db::LayoutVsSchematic *lvs)
|
|||
{
|
||||
int version = 0;
|
||||
std::string description;
|
||||
m_id2net_per_circuit_a.clear ();
|
||||
m_id2net_per_circuit_b.clear ();
|
||||
|
||||
tl_assert (lvs->internal_layout ());
|
||||
lvs->internal_layout ()->dbu (1.0); // mainly for testing
|
||||
|
|
@ -76,14 +78,14 @@ void LayoutVsSchematicStandardReader::do_read (db::LayoutVsSchematic *lvs)
|
|||
} else if (test (skeys::layout_key) || test (lkeys::layout_key)) {
|
||||
|
||||
Brace br (this);
|
||||
LayoutToNetlistStandardReader::do_read (lvs, true /*nested*/);
|
||||
LayoutToNetlistStandardReader::do_read (0, lvs, true /*nested*/, &m_id2net_per_circuit_a);
|
||||
br.done ();
|
||||
|
||||
} else if (test (skeys::reference_key) || test (lkeys::reference_key)) {
|
||||
|
||||
Brace br (this);
|
||||
std::auto_ptr<db::Netlist> netlist (new db::Netlist ());
|
||||
read_netlist (netlist.get ());
|
||||
LayoutToNetlistStandardReader::do_read (netlist.get (), 0, true /*nested*/, &m_id2net_per_circuit_b);
|
||||
lvs->set_reference_netlist (netlist.release ());
|
||||
br.done ();
|
||||
|
||||
|
|
@ -105,216 +107,6 @@ void LayoutVsSchematicStandardReader::do_read (db::LayoutVsSchematic *lvs)
|
|||
}
|
||||
}
|
||||
|
||||
void LayoutVsSchematicStandardReader::read_netlist (db::Netlist *netlist)
|
||||
{
|
||||
Brace br (this);
|
||||
while (br) {
|
||||
|
||||
if (test (skeys::circuit_key) || test (lkeys::circuit_key)) {
|
||||
|
||||
Brace br (this);
|
||||
std::string name;
|
||||
read_word_or_quoted (name);
|
||||
|
||||
db::Circuit *circuit = new db::Circuit ();
|
||||
circuit->set_name (name);
|
||||
netlist->add_circuit (circuit);
|
||||
|
||||
std::map<unsigned int, Net *> id2net;
|
||||
|
||||
while (br) {
|
||||
|
||||
if (test (skeys::net_key) || test (lkeys::net_key)) {
|
||||
read_net (netlist, circuit, id2net);
|
||||
} else if (test (skeys::pin_key) || test (lkeys::pin_key)) {
|
||||
read_pin (netlist, circuit, id2net);
|
||||
} else if (test (skeys::device_key) || test (lkeys::device_key)) {
|
||||
read_device (netlist, circuit, id2net);
|
||||
} else if (test (skeys::circuit_key) || test (lkeys::circuit_key)) {
|
||||
read_subcircuit (netlist, circuit, id2net);
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid keyword inside circuit definition (net, pin, device or circuit expected)")));
|
||||
}
|
||||
|
||||
}
|
||||
br.done ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
br.done ();
|
||||
}
|
||||
|
||||
void
|
||||
LayoutVsSchematicStandardReader::read_net (db::Netlist * /*netlist*/, db::Circuit *circuit, std::map<unsigned int, Net *> &id2net)
|
||||
{
|
||||
Brace br (this);
|
||||
|
||||
unsigned int id = (unsigned int) read_int ();
|
||||
std::string name;
|
||||
|
||||
if (test (skeys::name_key) || test (lkeys::name_key)) {
|
||||
Brace br_name (this);
|
||||
read_word_or_quoted (name);
|
||||
br_name.done ();
|
||||
}
|
||||
|
||||
db::Net *net = new db::Net ();
|
||||
net->set_name (name);
|
||||
circuit->add_net (net);
|
||||
|
||||
id2net.insert (std::make_pair (id, net));
|
||||
|
||||
br.done ();
|
||||
}
|
||||
|
||||
void
|
||||
LayoutVsSchematicStandardReader::read_pin (db::Netlist * /*netlist*/, db::Circuit *circuit, std::map<unsigned int, Net *> &id2net)
|
||||
{
|
||||
Brace br (this);
|
||||
std::string name;
|
||||
read_word_or_quoted (name);
|
||||
unsigned int netid = (unsigned int) read_int ();
|
||||
br.done ();
|
||||
|
||||
const db::Pin &pin = circuit->add_pin (name);
|
||||
|
||||
db::Net *net = id2net [netid];
|
||||
if (!net) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid net ID: ")) + tl::to_string (netid));
|
||||
}
|
||||
|
||||
circuit->connect_pin (pin.id (), net);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LayoutVsSchematicStandardReader::read_device (db::Netlist *netlist, db::Circuit *circuit, std::map<unsigned int, Net *> &id2net)
|
||||
{
|
||||
Brace br (this);
|
||||
|
||||
std::string name;
|
||||
read_word_or_quoted (name);
|
||||
|
||||
std::string dmname;
|
||||
read_word_or_quoted (dmname);
|
||||
|
||||
db::DeviceAbstract *dm = device_model_by_name (netlist, dmname);
|
||||
|
||||
db::Device *device = new db::Device ();
|
||||
device->set_device_class (const_cast<db::DeviceClass *> (dm->device_class ()));
|
||||
device->set_device_abstract (dm);
|
||||
device->set_name (name);
|
||||
circuit->add_device (device);
|
||||
|
||||
size_t max_tid = 0;
|
||||
|
||||
while (br) {
|
||||
|
||||
if (test (skeys::terminal_key) || test (lkeys::terminal_key)) {
|
||||
|
||||
Brace br2 (this);
|
||||
std::string tname;
|
||||
read_word_or_quoted (tname);
|
||||
unsigned int netid = (unsigned int) read_int ();
|
||||
br2.done ();
|
||||
|
||||
size_t tid = terminal_id (dm->device_class (), tname);
|
||||
max_tid = std::max (max_tid, tid + 1);
|
||||
|
||||
db::Net *net = id2net [netid];
|
||||
if (!net) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid net ID: ")) + tl::to_string (netid));
|
||||
}
|
||||
|
||||
device->connect_terminal (tid, net);
|
||||
|
||||
} else if (test (skeys::param_key) || test (lkeys::param_key)) {
|
||||
|
||||
Brace br2 (this);
|
||||
std::string pname;
|
||||
read_word_or_quoted (pname);
|
||||
double value = read_double ();
|
||||
br2.done ();
|
||||
|
||||
size_t pid = std::numeric_limits<size_t>::max ();
|
||||
const std::vector<db::DeviceParameterDefinition> &pd = dm->device_class ()->parameter_definitions ();
|
||||
for (std::vector<db::DeviceParameterDefinition>::const_iterator p = pd.begin (); p != pd.end (); ++p) {
|
||||
if (p->name () == pname) {
|
||||
pid = p->id ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if no parameter with this name exists, create one
|
||||
if (pid == std::numeric_limits<size_t>::max ()) {
|
||||
// TODO: this should only happen for generic devices
|
||||
db::DeviceClass *dc = const_cast<db::DeviceClass *> (dm->device_class ());
|
||||
pid = dc->add_parameter_definition (db::DeviceParameterDefinition (pname, std::string ())).id ();
|
||||
}
|
||||
|
||||
device->set_parameter_value (pid, value);
|
||||
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid keyword inside device definition (location, param or terminal expected)")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
br.done ();
|
||||
}
|
||||
|
||||
void
|
||||
LayoutVsSchematicStandardReader::read_subcircuit (db::Netlist *netlist, db::Circuit *circuit, std::map<unsigned int, Net *> &id2net)
|
||||
{
|
||||
Brace br (this);
|
||||
|
||||
std::string name;
|
||||
read_word_or_quoted (name);
|
||||
|
||||
std::string xname;
|
||||
read_word_or_quoted (xname);
|
||||
|
||||
db::Circuit *circuit_ref = netlist->circuit_by_name (xname);
|
||||
if (! circuit_ref) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid device circuit name: ")) + xname);
|
||||
}
|
||||
|
||||
db::SubCircuit *subcircuit = new db::SubCircuit (circuit_ref);
|
||||
subcircuit->set_name (name);
|
||||
circuit->add_subcircuit (subcircuit);
|
||||
|
||||
while (br) {
|
||||
|
||||
if (test (skeys::pin_key) || test (lkeys::pin_key)) {
|
||||
|
||||
Brace br2 (this);
|
||||
std::string pname;
|
||||
read_word_or_quoted (pname);
|
||||
unsigned int netid = (unsigned int) read_int ();
|
||||
br2.done ();
|
||||
|
||||
const db::Pin *sc_pin = circuit_ref->pin_by_name (pname);
|
||||
if (! sc_pin) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid pin name: ")) + pname + tl::to_string (tr (" for circuit: ")) + circuit_ref->name ());
|
||||
}
|
||||
|
||||
db::Net *net = id2net [netid];
|
||||
if (!net) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid net ID: ")) + tl::to_string (netid));
|
||||
}
|
||||
|
||||
subcircuit->connect_pin (sc_pin->id (), net);
|
||||
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid keyword inside subcircuit definition (location, rotation, mirror, scale or pin expected)")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
br.done ();
|
||||
}
|
||||
|
||||
bool LayoutVsSchematicStandardReader::read_status (db::NetlistCrossReference::Status &status)
|
||||
{
|
||||
if (test (skeys::match_key) || test (lkeys::match_key)) {
|
||||
|
|
@ -429,17 +221,26 @@ std::pair<unsigned int, bool> LayoutVsSchematicStandardReader::read_non_numerica
|
|||
}
|
||||
}
|
||||
|
||||
static const db::Net *net_by_numerical_id (const db::Circuit *circuit, const std::pair<unsigned int, bool> &non)
|
||||
|
||||
static const db::Net *net_by_numerical_id (const db::Circuit *circuit, const std::pair<unsigned int, bool> &non, std::map<const db::Circuit *, std::map<unsigned int, Net *> > &id2net_per_circuit)
|
||||
{
|
||||
if (non.second && circuit) {
|
||||
const db::Net *net = 0; // @@@ circuit->net_by_numerical_id (non.first);
|
||||
if (! net) {
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid net id: ")) + tl::to_string (non.first));
|
||||
|
||||
std::map<const db::Circuit *, std::map<unsigned int, Net *> >::const_iterator i = id2net_per_circuit.find (circuit);
|
||||
if (i != id2net_per_circuit.end ()) {
|
||||
|
||||
std::map<unsigned int, Net *>::const_iterator j = i->second.find (non.first);
|
||||
if (j != i->second.end ()) {
|
||||
return j->second;
|
||||
}
|
||||
|
||||
}
|
||||
return net;
|
||||
} else {
|
||||
return 0;
|
||||
|
||||
throw tl::Exception (tl::to_string (tr ("Not a valid net id: ")) + tl::to_string (non.first));
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LayoutVsSchematicStandardReader::read_net_pair (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b)
|
||||
|
|
@ -455,7 +256,7 @@ void LayoutVsSchematicStandardReader::read_net_pair (db::NetlistCrossReference *
|
|||
|
||||
br.done ();
|
||||
|
||||
xref->gen_nets (net_by_numerical_id (circuit_a, non_a), net_by_numerical_id (circuit_b, non_b), status);
|
||||
xref->gen_nets (net_by_numerical_id (circuit_a, non_a, m_id2net_per_circuit_a), net_by_numerical_id (circuit_b, non_b, m_id2net_per_circuit_b), status);
|
||||
}
|
||||
|
||||
static const db::Pin *pin_by_name (const db::Circuit *circuit, const std::pair<std::string, bool> &non)
|
||||
|
|
|
|||
|
|
@ -66,12 +66,7 @@ public:
|
|||
private:
|
||||
void do_read (db::LayoutVsSchematic *lvs);
|
||||
|
||||
void read_netlist (db::Netlist *netlist);
|
||||
bool read_status (db::NetlistCrossReference::Status &status);
|
||||
void read_net (db::Netlist *netlist, db::Circuit *circuit, std::map<unsigned int, Net *> &id2net);
|
||||
void read_subcircuit (db::Netlist *netlist, db::Circuit *circuit, std::map<unsigned int, Net *> &id2net);
|
||||
void read_device (db::Netlist *netlist, db::Circuit *circuit, std::map<unsigned int, Net *> &id2net);
|
||||
void read_pin (db::Netlist *netlist, db::Circuit *circuit, std::map<unsigned int, Net *> &id2net);
|
||||
void read_xref (db::NetlistCrossReference *xref);
|
||||
void read_xrefs_for_circuits (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b);
|
||||
void read_net_pair (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b);
|
||||
|
|
@ -80,6 +75,8 @@ private:
|
|||
void read_subcircuit_pair (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b);
|
||||
std::pair<std::string, bool> read_non_string ();
|
||||
std::pair<unsigned int, bool> read_non_numerical ();
|
||||
|
||||
std::map<const db::Circuit *, std::map<unsigned int, Net *> > m_id2net_per_circuit_a, m_id2net_per_circuit_b;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ void LayoutVsSchematicWriterBase::write (const db::LayoutVsSchematic *l2n)
|
|||
do_write (l2n);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// -------------------------------------------------------------------------------------------
|
||||
|
||||
namespace l2n_std_format
|
||||
|
|
@ -537,6 +538,7 @@ void std_writer_impl<Keys>::write (const db::LayoutVsSchematic *l2n, const db::D
|
|||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// LayoutVsSchematicStandardWriter implementation
|
||||
|
|
@ -547,8 +549,9 @@ LayoutVsSchematicStandardWriter::LayoutVsSchematicStandardWriter (tl::OutputStre
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void LayoutVsSchematicStandardWriter::do_write (const db::LayoutVsSchematic *l2n)
|
||||
void LayoutVsSchematicStandardWriter::do_write (const db::LayoutVsSchematic * /*lvs*/)
|
||||
{
|
||||
#if 0
|
||||
if (m_short_version) {
|
||||
l2n_std_format::std_writer_impl<l2n_std_format::keys<true> > writer (*mp_stream);
|
||||
writer.write (l2n);
|
||||
|
|
@ -556,6 +559,7 @@ void LayoutVsSchematicStandardWriter::do_write (const db::LayoutVsSchematic *l2n
|
|||
l2n_std_format::std_writer_impl<l2n_std_format::keys<false> > writer (*mp_stream);
|
||||
writer.write (l2n);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue