mirror of https://github.com/KLayout/klayout.git
WIP: LVS DB writer.
This commit is contained in:
parent
bee662eea8
commit
b2fee5da3d
|
|
@ -127,10 +127,10 @@ LayoutToNetlistStandardReader::skip ()
|
|||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlistStandardReader::read (db::LayoutToNetlist *l2n)
|
||||
void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n)
|
||||
{
|
||||
try {
|
||||
do_read (0, l2n);
|
||||
read_netlist (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));
|
||||
}
|
||||
|
|
@ -145,7 +145,7 @@ static db::Region &layer_by_name (db::LayoutToNetlist *l2n, const std::string &n
|
|||
return *l;
|
||||
}
|
||||
|
||||
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)
|
||||
void LayoutToNetlistStandardReader::read_netlist (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;
|
||||
|
|
|
|||
|
|
@ -68,7 +68,13 @@ public:
|
|||
LayoutToNetlistReaderBase () { }
|
||||
virtual ~LayoutToNetlistReaderBase () { }
|
||||
|
||||
virtual void read (db::LayoutToNetlist *l2n) = 0;
|
||||
void read (db::LayoutToNetlist *l2n)
|
||||
{
|
||||
do_read (l2n);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void do_read (db::LayoutToNetlist *l2n) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -80,13 +86,13 @@ class DB_PUBLIC LayoutToNetlistStandardReader
|
|||
public:
|
||||
LayoutToNetlistStandardReader (tl::InputStream &stream);
|
||||
|
||||
void read (db::LayoutToNetlist *l2n);
|
||||
void do_read (db::LayoutToNetlist *l2n);
|
||||
|
||||
protected:
|
||||
friend class l2n_std_reader::Brace;
|
||||
typedef l2n_std_reader::Brace Brace;
|
||||
|
||||
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);
|
||||
void read_netlist (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 ();
|
||||
|
|
|
|||
|
|
@ -50,29 +50,8 @@ void LayoutToNetlistWriterBase::write (const db::LayoutToNetlist *l2n)
|
|||
namespace l2n_std_format
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// std_writer_impl<Keys> implementation
|
||||
|
||||
template <class Keys>
|
||||
class std_writer_impl
|
||||
{
|
||||
public:
|
||||
std_writer_impl (tl::OutputStream &stream);
|
||||
|
||||
void write (const db::LayoutToNetlist *l2n);
|
||||
|
||||
private:
|
||||
tl::OutputStream *mp_stream;
|
||||
db::Point m_ref;
|
||||
|
||||
void write (const db::LayoutToNetlist *l2n, const db::Circuit &circuit);
|
||||
void write (const db::LayoutToNetlist *l2n, const db::Net &net, unsigned int id);
|
||||
void write (const db::LayoutToNetlist *l2n, const db::SubCircuit &subcircuit, std::map<const Net *, unsigned int> &net2id);
|
||||
void write (const db::LayoutToNetlist *l2n, const db::Device &device, std::map<const Net *, unsigned int> &net2id);
|
||||
void write (const db::LayoutToNetlist *l2n, const db::DeviceAbstract &device_abstract);
|
||||
void write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname, bool relative);
|
||||
void reset_geometry_ref ();
|
||||
};
|
||||
template class std_writer_impl<l2n_std_format::keys<false> >;
|
||||
template class std_writer_impl<l2n_std_format::keys<true> >;
|
||||
|
||||
static const std::string endl ("\n");
|
||||
static const std::string indent1 (" ");
|
||||
|
|
@ -96,100 +75,117 @@ static std::string name_for_layer (const db::LayoutToNetlist *l2n, unsigned int
|
|||
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n)
|
||||
{
|
||||
write (l2n->netlist (), l2n, false, 0);
|
||||
|
||||
}
|
||||
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::Netlist *nl, const db::LayoutToNetlist *l2n, bool nested, std::map<const db::Circuit *, std::map<const db::Net *, unsigned int> > *net2id_per_circuit)
|
||||
{
|
||||
bool any = false;
|
||||
|
||||
const int version = 0;
|
||||
|
||||
const db::Layout *ly = l2n->internal_layout ();
|
||||
const db::Netlist *nl = l2n->netlist ();
|
||||
const db::Layout *ly = l2n ? l2n->internal_layout () : 0;
|
||||
const std::string indent (nested ? indent1 : "");
|
||||
|
||||
*mp_stream << "#%l2n-klayout" << endl;
|
||||
if (! nested) {
|
||||
*mp_stream << "#%l2n-klayout" << endl;
|
||||
}
|
||||
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# General section" << endl << endl;
|
||||
*mp_stream << endl << indent << "# General section" << endl << endl;
|
||||
}
|
||||
|
||||
if (version > 0) {
|
||||
*mp_stream << Keys::version_key << "(" << version << ")" << endl;
|
||||
*mp_stream << indent << Keys::version_key << "(" << version << ")" << endl;
|
||||
}
|
||||
*mp_stream << Keys::top_key << "(" << tl::to_word_or_quoted_string (ly->cell_name (l2n->internal_top_cell ()->cell_index ())) << ")" << endl;
|
||||
*mp_stream << Keys::unit_key << "(" << ly->dbu () << ")" << endl;
|
||||
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# Layer section" << endl;
|
||||
*mp_stream << "# This section lists the mask layers (drawing or derived) and their connections." << endl;
|
||||
if (ly) {
|
||||
*mp_stream << indent << Keys::top_key << "(" << tl::to_word_or_quoted_string (ly->cell_name (l2n->internal_top_cell ()->cell_index ())) << ")" << endl;
|
||||
*mp_stream << indent << Keys::unit_key << "(" << ly->dbu () << ")" << endl;
|
||||
}
|
||||
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# Mask layers" << endl;
|
||||
*mp_stream << endl << indent << "# Layer section" << endl;
|
||||
*mp_stream << indent << "# This section lists the mask layers (drawing or derived) and their connections." << endl;
|
||||
}
|
||||
for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) {
|
||||
*mp_stream << Keys::layer_key << "(" << name_for_layer (l2n, *l);
|
||||
db::LayerProperties lp = ly->get_properties (*l);
|
||||
if (! lp.is_null ()) {
|
||||
*mp_stream << " " << tl::to_word_or_quoted_string (lp.to_string ());
|
||||
|
||||
if (ly) {
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << indent << "# Mask layers" << endl;
|
||||
}
|
||||
*mp_stream << ")" << endl;
|
||||
}
|
||||
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# Mask layer connectivity" << endl;
|
||||
}
|
||||
for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) {
|
||||
|
||||
db::Connectivity::layer_iterator ce = l2n->connectivity ().end_connected (*l);
|
||||
db::Connectivity::layer_iterator cb = l2n->connectivity ().begin_connected (*l);
|
||||
if (cb != ce) {
|
||||
*mp_stream << Keys::connect_key << "(" << name_for_layer (l2n, *l);
|
||||
for (db::Connectivity::layer_iterator c = l2n->connectivity ().begin_connected (*l); c != ce; ++c) {
|
||||
*mp_stream << " " << name_for_layer (l2n, *c);
|
||||
for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) {
|
||||
*mp_stream << indent << Keys::layer_key << "(" << name_for_layer (l2n, *l);
|
||||
db::LayerProperties lp = ly->get_properties (*l);
|
||||
if (! lp.is_null ()) {
|
||||
*mp_stream << indent << " " << tl::to_word_or_quoted_string (lp.to_string ());
|
||||
}
|
||||
*mp_stream << ")" << endl;
|
||||
*mp_stream << indent << ")" << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
any = false;
|
||||
for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) {
|
||||
if (l2n) {
|
||||
|
||||
db::Connectivity::global_nets_iterator ge = l2n->connectivity ().end_global_connections (*l);
|
||||
db::Connectivity::global_nets_iterator gb = l2n->connectivity ().begin_global_connections (*l);
|
||||
if (gb != ge) {
|
||||
if (! any) {
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# Global nets and connectivity" << endl;
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << indent << "# Mask layer connectivity" << endl;
|
||||
}
|
||||
for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) {
|
||||
|
||||
db::Connectivity::layer_iterator ce = l2n->connectivity ().end_connected (*l);
|
||||
db::Connectivity::layer_iterator cb = l2n->connectivity ().begin_connected (*l);
|
||||
if (cb != ce) {
|
||||
*mp_stream << indent << Keys::connect_key << "(" << name_for_layer (l2n, *l);
|
||||
for (db::Connectivity::layer_iterator c = l2n->connectivity ().begin_connected (*l); c != ce; ++c) {
|
||||
*mp_stream << indent << " " << name_for_layer (l2n, *c);
|
||||
}
|
||||
any = true;
|
||||
*mp_stream << indent << ")" << endl;
|
||||
}
|
||||
*mp_stream << Keys::global_key << "(" << name_for_layer (l2n, *l);
|
||||
for (db::Connectivity::global_nets_iterator g = gb; g != ge; ++g) {
|
||||
*mp_stream << " " << tl::to_word_or_quoted_string (l2n->connectivity ().global_net_name (*g));
|
||||
|
||||
}
|
||||
|
||||
any = false;
|
||||
for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) {
|
||||
|
||||
db::Connectivity::global_nets_iterator ge = l2n->connectivity ().end_global_connections (*l);
|
||||
db::Connectivity::global_nets_iterator gb = l2n->connectivity ().begin_global_connections (*l);
|
||||
if (gb != ge) {
|
||||
if (! any) {
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# Global nets and connectivity" << endl;
|
||||
}
|
||||
any = true;
|
||||
}
|
||||
*mp_stream << indent << Keys::global_key << "(" << name_for_layer (l2n, *l);
|
||||
for (db::Connectivity::global_nets_iterator g = gb; g != ge; ++g) {
|
||||
*mp_stream << indent << " " << tl::to_word_or_quoted_string (l2n->connectivity ().global_net_name (*g));
|
||||
}
|
||||
*mp_stream << indent << ")" << endl;
|
||||
}
|
||||
*mp_stream << ")" << endl;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (nl->begin_device_classes () != nl->end_device_classes () && ! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# Device class section" << endl;
|
||||
*mp_stream << endl << indent << "# Device class section" << endl;
|
||||
for (db::Netlist::const_device_class_iterator c = nl->begin_device_classes (); c != nl->end_device_classes (); ++c) {
|
||||
db::DeviceClassTemplateBase *temp = db::DeviceClassTemplateBase::is_a (c.operator-> ());
|
||||
if (temp) {
|
||||
*mp_stream << Keys::class_key << "(" << tl::to_word_or_quoted_string (c->name ()) << " " << tl::to_word_or_quoted_string (temp->name ()) << ")" << endl;
|
||||
*mp_stream << indent << Keys::class_key << "(" << tl::to_word_or_quoted_string (c->name ()) << " " << tl::to_word_or_quoted_string (temp->name ()) << ")" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nl->begin_device_abstracts () != nl->end_device_abstracts () && ! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# Device abstracts section" << endl;
|
||||
*mp_stream << "# Device abstracts list the pin shapes of the devices." << endl;
|
||||
*mp_stream << endl << indent << "# Device abstracts section" << endl;
|
||||
*mp_stream << indent << "# Device abstracts list the pin shapes of the devices." << endl;
|
||||
}
|
||||
for (db::Netlist::const_abstract_model_iterator m = nl->begin_device_abstracts (); m != nl->end_device_abstracts (); ++m) {
|
||||
if (m->device_class ()) {
|
||||
*mp_stream << Keys::device_key << "(" << tl::to_word_or_quoted_string (m->name ()) << " " << tl::to_word_or_quoted_string (m->device_class ()->name ()) << endl;
|
||||
write (l2n, *m);
|
||||
*mp_stream << ")" << endl;
|
||||
*mp_stream << indent << Keys::device_key << "(" << tl::to_word_or_quoted_string (m->name ()) << " " << tl::to_word_or_quoted_string (m->device_class ()->name ()) << endl;
|
||||
write (l2n, *m, indent);
|
||||
*mp_stream << indent << ")" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -199,55 +195,60 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n)
|
|||
}
|
||||
for (db::Netlist::const_bottom_up_circuit_iterator i = nl->begin_bottom_up (); i != nl->end_bottom_up (); ++i) {
|
||||
const db::Circuit *x = *i;
|
||||
*mp_stream << Keys::circuit_key << "(" << tl::to_word_or_quoted_string (x->name ()) << endl;
|
||||
write (l2n, *x);
|
||||
*mp_stream << ")" << endl;
|
||||
*mp_stream << indent << Keys::circuit_key << "(" << tl::to_word_or_quoted_string (x->name ()) << endl;
|
||||
write (l2n, *x, indent, net2id_per_circuit);
|
||||
*mp_stream << indent << ")" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Circuit &circuit)
|
||||
void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Circuit &circuit, const std::string &indent, std::map<const db::Circuit *, std::map<const db::Net *, unsigned int> > *net2id_per_circuit)
|
||||
{
|
||||
std::map<const db::Net *, unsigned int> net2id;
|
||||
std::map<const db::Net *, unsigned int> net2id_local;
|
||||
std::map<const db::Net *, unsigned int> *net2id = &net2id_local;
|
||||
if (net2id_per_circuit) {
|
||||
net2id = &(*net2id_per_circuit) [&circuit];
|
||||
}
|
||||
|
||||
unsigned int id = 0;
|
||||
|
||||
if (circuit.begin_nets () != circuit.end_nets ()) {
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << indent1 << "# Nets with their geometries" << endl;
|
||||
*mp_stream << endl << indent << indent1 << "# Nets with their geometries" << endl;
|
||||
}
|
||||
for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) {
|
||||
net2id.insert (std::make_pair (n.operator-> (), ++id));
|
||||
write (l2n, *n, id);
|
||||
net2id->insert (std::make_pair (n.operator-> (), ++id));
|
||||
write (l2n, *n, id, indent);
|
||||
}
|
||||
}
|
||||
|
||||
if (circuit.begin_pins () != circuit.end_pins ()) {
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << indent1 << "# Outgoing pins and their connections to nets" << endl;
|
||||
*mp_stream << endl << indent << indent1 << "# Outgoing pins and their connections to nets" << endl;
|
||||
}
|
||||
for (db::Circuit::const_pin_iterator p = circuit.begin_pins (); p != circuit.end_pins (); ++p) {
|
||||
const db::Net *net = circuit.net_for_pin (p->id ());
|
||||
if (net) {
|
||||
*mp_stream << indent1 << Keys::pin_key << "(" << tl::to_word_or_quoted_string (p->expanded_name ()) << " " << net2id [net] << ")" << endl;
|
||||
*mp_stream << indent << indent1 << Keys::pin_key << "(" << tl::to_word_or_quoted_string (p->expanded_name ()) << " " << (*net2id) [net] << ")" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (circuit.begin_devices () != circuit.end_devices ()) {
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << indent1 << "# Devices and their connections" << endl;
|
||||
*mp_stream << endl << indent << indent1 << "# Devices and their connections" << endl;
|
||||
}
|
||||
for (db::Circuit::const_device_iterator d = circuit.begin_devices (); d != circuit.end_devices (); ++d) {
|
||||
write (l2n, *d, net2id);
|
||||
write (l2n, *d, *net2id, indent);
|
||||
}
|
||||
}
|
||||
|
||||
if (circuit.begin_subcircuits () != circuit.end_subcircuits ()) {
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << indent1 << "# Subcircuits and their connections" << endl;
|
||||
*mp_stream << endl << indent << indent1 << "# Subcircuits and their connections" << endl;
|
||||
}
|
||||
for (db::Circuit::const_subcircuit_iterator x = circuit.begin_subcircuits (); x != circuit.end_subcircuits (); ++x) {
|
||||
write (l2n, *x, net2id);
|
||||
write (l2n, *x, *net2id, indent);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -335,7 +336,7 @@ void std_writer_impl<Keys>::write (const db::PolygonRef *s, const db::ICplxTrans
|
|||
}
|
||||
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Net &net, unsigned int id)
|
||||
void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Net &net, unsigned int id, const std::string &indent)
|
||||
{
|
||||
if (! l2n->netlist ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Can't write annotated netlist before extraction has been done")));
|
||||
|
|
@ -367,7 +368,7 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Net
|
|||
} else {
|
||||
|
||||
if (! any) {
|
||||
*mp_stream << indent1 << Keys::net_key << "(" << id;
|
||||
*mp_stream << indent << indent1 << Keys::net_key << "(" << id;
|
||||
if (! net.name ().empty ()) {
|
||||
*mp_stream << " " << Keys::name_key << "(" << tl::to_word_or_quoted_string (net.name ()) << ")";
|
||||
}
|
||||
|
|
@ -390,7 +391,7 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Net
|
|||
}
|
||||
|
||||
if (any) {
|
||||
*mp_stream << indent1 << ")" << endl;
|
||||
*mp_stream << indent << indent1 << ")" << endl;
|
||||
} else {
|
||||
|
||||
*mp_stream << indent1 << Keys::net_key << "(" << id;
|
||||
|
|
@ -403,12 +404,12 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Net
|
|||
}
|
||||
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::SubCircuit &subcircuit, std::map<const Net *, unsigned int> &net2id)
|
||||
void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::SubCircuit &subcircuit, std::map<const Net *, unsigned int> &net2id, const std::string &indent)
|
||||
{
|
||||
const db::Layout *ly = l2n->internal_layout ();
|
||||
double dbu = ly->dbu ();
|
||||
|
||||
*mp_stream << indent1 << Keys::circuit_key << "(" << tl::to_word_or_quoted_string (subcircuit.expanded_name ());
|
||||
*mp_stream << indent << indent1 << Keys::circuit_key << "(" << tl::to_word_or_quoted_string (subcircuit.expanded_name ());
|
||||
*mp_stream << " " << tl::to_word_or_quoted_string (subcircuit.circuit_ref ()->name ());
|
||||
|
||||
const db::DCplxTrans &tr = subcircuit.trans ();
|
||||
|
|
@ -434,7 +435,7 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Sub
|
|||
const db::Net *net = subcircuit.net_for_pin (p->id ());
|
||||
if (net) {
|
||||
if (separate_lines) {
|
||||
*mp_stream << indent2;
|
||||
*mp_stream << indent << indent2;
|
||||
} else {
|
||||
*mp_stream << " ";
|
||||
}
|
||||
|
|
@ -446,14 +447,14 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Sub
|
|||
}
|
||||
|
||||
if (separate_lines) {
|
||||
*mp_stream << indent1;
|
||||
*mp_stream << indent << indent1;
|
||||
}
|
||||
|
||||
*mp_stream << ")" << endl;
|
||||
}
|
||||
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::DeviceAbstract &device_abstract)
|
||||
void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::DeviceAbstract &device_abstract, const std::string &indent)
|
||||
{
|
||||
const std::vector<db::DeviceTerminalDefinition> &td = device_abstract.device_class ()->terminal_definitions ();
|
||||
|
||||
|
|
@ -462,7 +463,7 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Dev
|
|||
|
||||
for (std::vector<db::DeviceTerminalDefinition>::const_iterator t = td.begin (); t != td.end (); ++t) {
|
||||
|
||||
*mp_stream << indent1 << Keys::terminal_key << "(" << t->name () << endl;
|
||||
*mp_stream << indent << indent1 << Keys::terminal_key << "(" << t->name () << endl;
|
||||
|
||||
reset_geometry_ref ();
|
||||
|
||||
|
|
@ -471,7 +472,7 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Dev
|
|||
const db::local_cluster<db::PolygonRef> &lc = clusters.clusters_per_cell (device_abstract.cell_index ()).cluster_by_id (device_abstract.cluster_id_for_terminal (t->id ()));
|
||||
for (db::local_cluster<db::PolygonRef>::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) {
|
||||
|
||||
*mp_stream << indent2;
|
||||
*mp_stream << indent << indent2;
|
||||
write (s.operator-> (), db::ICplxTrans (), name_for_layer (l2n, *l), true);
|
||||
*mp_stream << endl;
|
||||
|
||||
|
|
@ -479,13 +480,13 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Dev
|
|||
|
||||
}
|
||||
|
||||
*mp_stream << indent1 << ")" << endl;
|
||||
*mp_stream << indent << indent1 << ")" << endl;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Device &device, std::map<const Net *, unsigned int> &net2id)
|
||||
void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Device &device, std::map<const Net *, unsigned int> &net2id, const std::string &indent)
|
||||
{
|
||||
const db::Layout *ly = l2n->internal_layout ();
|
||||
double dbu = ly->dbu ();
|
||||
|
|
@ -495,7 +496,7 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Dev
|
|||
const std::vector<DeviceTerminalDefinition> &td = device.device_class ()->terminal_definitions ();
|
||||
const std::vector<DeviceParameterDefinition> &pd = device.device_class ()->parameter_definitions ();
|
||||
|
||||
*mp_stream << indent1 << Keys::device_key << "(" << tl::to_word_or_quoted_string (device.expanded_name ());
|
||||
*mp_stream << indent << indent1 << Keys::device_key << "(" << tl::to_word_or_quoted_string (device.expanded_name ());
|
||||
|
||||
tl_assert (device.device_abstract () != 0);
|
||||
*mp_stream << " " << tl::to_word_or_quoted_string (device.device_abstract ()->name ()) << endl;
|
||||
|
|
@ -505,7 +506,7 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Dev
|
|||
|
||||
db::Vector pos = dbu_inv * a->offset;
|
||||
|
||||
*mp_stream << " " << Keys::device_key << "(" << tl::to_word_or_quoted_string (a->device_abstract->name ()) << " " << pos.x () << " " << pos.y () << ")" << endl;
|
||||
*mp_stream << indent << indent2 << Keys::device_key << "(" << tl::to_word_or_quoted_string (a->device_abstract->name ()) << " " << pos.x () << " " << pos.y () << ")" << endl;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -513,27 +514,27 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n, const db::Dev
|
|||
for (std::map<unsigned int, std::vector<db::DeviceReconnectedTerminal> >::const_iterator t = reconnected_terminals.begin (); t != reconnected_terminals.end (); ++t) {
|
||||
|
||||
for (std::vector<db::DeviceReconnectedTerminal>::const_iterator c = t->second.begin (); c != t->second.end (); ++c) {
|
||||
*mp_stream << " " << Keys::connect_key << "(" << c->device_index << " " << tl::to_word_or_quoted_string (td [t->first].name ()) << " " << tl::to_word_or_quoted_string (td [c->other_terminal_id].name ()) << ")" << endl;
|
||||
*mp_stream << indent << indent2 << Keys::connect_key << "(" << c->device_index << " " << tl::to_word_or_quoted_string (td [t->first].name ()) << " " << tl::to_word_or_quoted_string (td [c->other_terminal_id].name ()) << ")" << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
db::Point pos = dbu_inv * device.position ();
|
||||
|
||||
*mp_stream << indent2 << Keys::location_key << "(" << pos.x () << " " << pos.y () << ")" << endl;
|
||||
*mp_stream << indent << indent2 << Keys::location_key << "(" << pos.x () << " " << pos.y () << ")" << endl;
|
||||
|
||||
for (std::vector<DeviceParameterDefinition>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
|
||||
*mp_stream << indent2 << Keys::param_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << device.parameter_value (i->id ()) << ")" << endl;
|
||||
*mp_stream << indent << indent2 << Keys::param_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << device.parameter_value (i->id ()) << ")" << endl;
|
||||
}
|
||||
|
||||
for (std::vector<DeviceTerminalDefinition>::const_iterator i = td.begin (); i != td.end (); ++i) {
|
||||
const db::Net *net = device.net_for_terminal (i->id ());
|
||||
if (net) {
|
||||
*mp_stream << indent2 << Keys::terminal_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << net2id [net] << ")" << endl;
|
||||
*mp_stream << indent << indent2 << Keys::terminal_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << net2id [net] << ")" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
*mp_stream << indent1 << ")" << endl;
|
||||
*mp_stream << indent << indent1 << ")" << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,11 +24,55 @@
|
|||
#define HDR_dbLayoutToNetlistWriter
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbPoint.h"
|
||||
#include "dbTrans.h"
|
||||
#include "dbPolygon.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
class Circuit;
|
||||
class SubCircuit;
|
||||
class Device;
|
||||
class DeviceAbstract;
|
||||
class Net;
|
||||
class Netlist;
|
||||
class LayoutToNetlist;
|
||||
|
||||
namespace l2n_std_format
|
||||
{
|
||||
|
||||
template <class Keys>
|
||||
class std_writer_impl
|
||||
{
|
||||
public:
|
||||
std_writer_impl (tl::OutputStream &stream);
|
||||
|
||||
void write (const db::LayoutToNetlist *l2n);
|
||||
|
||||
protected:
|
||||
void write (const db::Netlist *netlist, const db::LayoutToNetlist *l2n, bool nested, std::map<const db::Circuit *, std::map<const db::Net *, unsigned int> > *net2id_per_circuit);
|
||||
void write (const db::LayoutToNetlist *l2n, const db::Circuit &circuit, const std::string &indent, std::map<const db::Circuit *, std::map<const db::Net *, unsigned int> > *net2id_per_circuit);
|
||||
void write (const db::LayoutToNetlist *l2n, const db::Net &net, unsigned int id, const std::string &indent);
|
||||
void write (const db::LayoutToNetlist *l2n, const db::SubCircuit &subcircuit, std::map<const Net *, unsigned int> &net2id, const std::string &indent);
|
||||
void write (const db::LayoutToNetlist *l2n, const db::Device &device, std::map<const Net *, unsigned int> &net2id, const std::string &indent);
|
||||
void write (const db::LayoutToNetlist *l2n, const db::DeviceAbstract &device_abstract, const std::string &indent);
|
||||
void write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname, bool relative);
|
||||
void reset_geometry_ref ();
|
||||
|
||||
tl::OutputStream &stream ()
|
||||
{
|
||||
return *mp_stream;
|
||||
}
|
||||
|
||||
private:
|
||||
tl::OutputStream *mp_stream;
|
||||
db::Point m_ref;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class LayoutToNetlist;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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_lvs (this);
|
||||
reader.read (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,22 +29,25 @@ namespace db
|
|||
typedef lvs_std_format::keys<true> skeys;
|
||||
typedef lvs_std_format::keys<false> lkeys;
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// LayoutVsSchematicStandardReader implementation
|
||||
|
||||
LayoutVsSchematicStandardReader::LayoutVsSchematicStandardReader (tl::InputStream &stream)
|
||||
: LayoutToNetlistStandardReader (stream)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void LayoutVsSchematicStandardReader::read_lvs (db::LayoutVsSchematic *l2n)
|
||||
void LayoutVsSchematicStandardReader::do_read_lvs (db::LayoutVsSchematic *l2n)
|
||||
{
|
||||
try {
|
||||
do_read (l2n);
|
||||
read_netlist (l2n);
|
||||
} catch (tl::Exception &ex) {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("%s in line: %d of %s")), ex.msg (), stream ().line_number (), path ()));
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutVsSchematicStandardReader::do_read (db::LayoutVsSchematic *lvs)
|
||||
void LayoutVsSchematicStandardReader::read_netlist (db::LayoutVsSchematic *lvs)
|
||||
{
|
||||
int version = 0;
|
||||
std::string description;
|
||||
|
|
@ -78,14 +81,14 @@ void LayoutVsSchematicStandardReader::do_read (db::LayoutVsSchematic *lvs)
|
|||
} else if (test (skeys::layout_key) || test (lkeys::layout_key)) {
|
||||
|
||||
Brace br (this);
|
||||
LayoutToNetlistStandardReader::do_read (0, lvs, true /*nested*/, &m_id2net_per_circuit_a);
|
||||
LayoutToNetlistStandardReader::read_netlist (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 ());
|
||||
LayoutToNetlistStandardReader::do_read (netlist.get (), 0, true /*nested*/, &m_id2net_per_circuit_b);
|
||||
LayoutToNetlistStandardReader::read_netlist (netlist.get (), 0, true /*nested*/, &m_id2net_per_circuit_b);
|
||||
lvs->set_reference_netlist (netlist.release ());
|
||||
br.done ();
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,13 @@ public:
|
|||
LayoutVsSchematicReaderBase () { }
|
||||
virtual ~LayoutVsSchematicReaderBase () { }
|
||||
|
||||
virtual void read_lvs (db::LayoutVsSchematic *lvs) = 0;
|
||||
void read (db::LayoutVsSchematic *lvs)
|
||||
{
|
||||
do_read_lvs (lvs);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void do_read_lvs (db::LayoutVsSchematic *lvs) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -61,10 +67,15 @@ class DB_PUBLIC LayoutVsSchematicStandardReader
|
|||
public:
|
||||
LayoutVsSchematicStandardReader (tl::InputStream &stream);
|
||||
|
||||
void read_lvs (db::LayoutVsSchematic *lvs);
|
||||
void read (db::LayoutVsSchematic *lvs)
|
||||
{
|
||||
do_read_lvs (lvs);
|
||||
}
|
||||
|
||||
virtual void do_read_lvs (db::LayoutVsSchematic *lvs);
|
||||
|
||||
private:
|
||||
void do_read (db::LayoutVsSchematic *lvs);
|
||||
void read_netlist (db::LayoutVsSchematic *lvs);
|
||||
|
||||
bool read_status (db::NetlistCrossReference::Status &status);
|
||||
void read_xref (db::NetlistCrossReference *xref);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
*/
|
||||
|
||||
#include "dbLayoutToNetlistWriter.h"
|
||||
#include "dbLayoutVsSchematicWriter.h"
|
||||
#include "dbLayoutVsSchematic.h"
|
||||
#include "dbLayoutVsSchematicFormatDefs.h"
|
||||
|
|
@ -40,15 +41,14 @@ LayoutVsSchematicWriterBase::~LayoutVsSchematicWriterBase ()
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void LayoutVsSchematicWriterBase::write (const db::LayoutVsSchematic *l2n)
|
||||
void LayoutVsSchematicWriterBase::write (const db::LayoutVsSchematic *lvs)
|
||||
{
|
||||
do_write (l2n);
|
||||
do_write_lvs (lvs);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// -------------------------------------------------------------------------------------------
|
||||
|
||||
namespace l2n_std_format
|
||||
namespace lvs_std_format
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
|
|
@ -56,6 +56,7 @@ namespace l2n_std_format
|
|||
|
||||
template <class Keys>
|
||||
class std_writer_impl
|
||||
: public l2n_std_format::std_writer_impl<Keys>
|
||||
{
|
||||
public:
|
||||
std_writer_impl (tl::OutputStream &stream);
|
||||
|
|
@ -63,16 +64,15 @@ public:
|
|||
void write (const db::LayoutVsSchematic *l2n);
|
||||
|
||||
private:
|
||||
tl::OutputStream *mp_stream;
|
||||
db::Point m_ref;
|
||||
tl::OutputStream &stream ()
|
||||
{
|
||||
return l2n_std_format::std_writer_impl<Keys>::stream ();
|
||||
}
|
||||
|
||||
void write (const db::LayoutVsSchematic *l2n, const db::Circuit &circuit);
|
||||
void write (const db::LayoutVsSchematic *l2n, const db::Net &net, unsigned int id);
|
||||
void write (const db::LayoutVsSchematic *l2n, const db::SubCircuit &subcircuit, std::map<const Net *, unsigned int> &net2id);
|
||||
void write (const db::LayoutVsSchematic *l2n, const db::Device &device, std::map<const Net *, unsigned int> &net2id);
|
||||
void write (const db::LayoutVsSchematic *l2n, const db::DeviceAbstract &device_abstract);
|
||||
void write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname, bool relative);
|
||||
void reset_geometry_ref ();
|
||||
std::string status_to_s (const db::NetlistCrossReference::Status status);
|
||||
void write (const db::NetlistCrossReference *xref);
|
||||
|
||||
std::map<const db::Circuit *, std::map<const db::Net *, unsigned int> > m_net2id_per_circuit_a, m_net2id_per_circuit_b;
|
||||
};
|
||||
|
||||
static const std::string endl ("\n");
|
||||
|
|
@ -81,464 +81,135 @@ static const std::string indent2 (" ");
|
|||
|
||||
template <class Keys>
|
||||
std_writer_impl<Keys>::std_writer_impl (tl::OutputStream &stream)
|
||||
: mp_stream (&stream)
|
||||
: l2n_std_format::std_writer_impl<Keys> (stream)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
static std::string name_for_layer (const db::LayoutVsSchematic *l2n, unsigned int l)
|
||||
{
|
||||
std::string n = l2n->name (l);
|
||||
if (n.empty ()) {
|
||||
n = "L" + tl::to_string (l);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutVsSchematic *l2n)
|
||||
void std_writer_impl<Keys>::write (const db::LayoutVsSchematic *lvs)
|
||||
{
|
||||
bool any = false;
|
||||
|
||||
const int version = 0;
|
||||
|
||||
const db::Layout *ly = l2n->internal_layout ();
|
||||
const db::Netlist *nl = l2n->netlist ();
|
||||
|
||||
*mp_stream << "#%l2n-klayout" << endl;
|
||||
stream () << "#%lvs-klayout" << endl;
|
||||
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# General section" << endl << endl;
|
||||
stream () << endl << "# General section" << endl << endl;
|
||||
}
|
||||
|
||||
if (version > 0) {
|
||||
*mp_stream << Keys::version_key << "(" << version << ")" << endl;
|
||||
}
|
||||
*mp_stream << Keys::top_key << "(" << tl::to_word_or_quoted_string (ly->cell_name (l2n->internal_top_cell ()->cell_index ())) << ")" << endl;
|
||||
*mp_stream << Keys::unit_key << "(" << ly->dbu () << ")" << endl;
|
||||
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# Layer section" << endl;
|
||||
*mp_stream << "# This section lists the mask layers (drawing or derived) and their connections." << endl;
|
||||
stream () << Keys::version_key << "(" << version << ")" << endl;
|
||||
}
|
||||
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# Mask layers" << endl;
|
||||
}
|
||||
for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) {
|
||||
*mp_stream << Keys::layer_key << "(" << name_for_layer (l2n, *l);
|
||||
db::LayerProperties lp = ly->get_properties (*l);
|
||||
if (! lp.is_null ()) {
|
||||
*mp_stream << " " << tl::to_word_or_quoted_string (lp.to_string ());
|
||||
}
|
||||
*mp_stream << ")" << endl;
|
||||
stream () << endl << "# Layout" << endl;
|
||||
}
|
||||
stream () << Keys::layout_key << "(" << endl;
|
||||
l2n_std_format::std_writer_impl<Keys>::write (0, lvs, true, &m_net2id_per_circuit_a);
|
||||
stream () << ")" << endl;
|
||||
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# Mask layer connectivity" << endl;
|
||||
}
|
||||
for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) {
|
||||
|
||||
db::Connectivity::layer_iterator ce = l2n->connectivity ().end_connected (*l);
|
||||
db::Connectivity::layer_iterator cb = l2n->connectivity ().begin_connected (*l);
|
||||
if (cb != ce) {
|
||||
*mp_stream << Keys::connect_key << "(" << name_for_layer (l2n, *l);
|
||||
for (db::Connectivity::layer_iterator c = l2n->connectivity ().begin_connected (*l); c != ce; ++c) {
|
||||
*mp_stream << " " << name_for_layer (l2n, *c);
|
||||
}
|
||||
*mp_stream << ")" << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
any = false;
|
||||
for (db::Connectivity::layer_iterator l = l2n->connectivity ().begin_layers (); l != l2n->connectivity ().end_layers (); ++l) {
|
||||
|
||||
db::Connectivity::global_nets_iterator ge = l2n->connectivity ().end_global_connections (*l);
|
||||
db::Connectivity::global_nets_iterator gb = l2n->connectivity ().begin_global_connections (*l);
|
||||
if (gb != ge) {
|
||||
if (! any) {
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# Global nets and connectivity" << endl;
|
||||
}
|
||||
any = true;
|
||||
}
|
||||
*mp_stream << Keys::global_key << "(" << name_for_layer (l2n, *l);
|
||||
for (db::Connectivity::global_nets_iterator g = gb; g != ge; ++g) {
|
||||
*mp_stream << " " << tl::to_word_or_quoted_string (l2n->connectivity ().global_net_name (*g));
|
||||
}
|
||||
*mp_stream << ")" << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (nl->begin_device_classes () != nl->end_device_classes () && ! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# Device class section" << endl;
|
||||
for (db::Netlist::const_device_class_iterator c = nl->begin_device_classes (); c != nl->end_device_classes (); ++c) {
|
||||
db::DeviceClassTemplateBase *temp = db::DeviceClassTemplateBase::is_a (c.operator-> ());
|
||||
if (temp) {
|
||||
*mp_stream << Keys::class_key << "(" << tl::to_word_or_quoted_string (c->name ()) << " " << tl::to_word_or_quoted_string (temp->name ()) << ")" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nl->begin_device_abstracts () != nl->end_device_abstracts () && ! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# Device abstracts section" << endl;
|
||||
*mp_stream << "# Device abstracts list the pin shapes of the devices." << endl;
|
||||
}
|
||||
for (db::Netlist::const_abstract_model_iterator m = nl->begin_device_abstracts (); m != nl->end_device_abstracts (); ++m) {
|
||||
if (m->device_class ()) {
|
||||
*mp_stream << Keys::device_key << "(" << tl::to_word_or_quoted_string (m->name ()) << " " << tl::to_word_or_quoted_string (m->device_class ()->name ()) << endl;
|
||||
write (l2n, *m);
|
||||
*mp_stream << ")" << endl;
|
||||
}
|
||||
stream () << endl << "# Reference netlist" << endl;
|
||||
}
|
||||
stream () << Keys::reference_key << "(" << endl;
|
||||
l2n_std_format::std_writer_impl<Keys>::write (lvs->reference_netlist (), 0, true, &m_net2id_per_circuit_b);
|
||||
stream () << ")" << endl;
|
||||
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << "# Circuit section" << endl;
|
||||
*mp_stream << "# Circuits are the hierarchical building blocks of the netlist." << endl;
|
||||
stream () << endl << "# Cross reference" << endl;
|
||||
}
|
||||
for (db::Netlist::const_bottom_up_circuit_iterator i = nl->begin_bottom_up (); i != nl->end_bottom_up (); ++i) {
|
||||
const db::Circuit *x = *i;
|
||||
*mp_stream << Keys::circuit_key << "(" << tl::to_word_or_quoted_string (x->name ()) << endl;
|
||||
write (l2n, *x);
|
||||
*mp_stream << ")" << endl;
|
||||
stream () << Keys::xref_key << "(" << endl;
|
||||
write (lvs->cross_ref ());
|
||||
stream () << ")" << endl;
|
||||
|
||||
if (! Keys::is_short ()) {
|
||||
stream () << endl;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutVsSchematic *l2n, const db::Circuit &circuit)
|
||||
template <class Obj>
|
||||
std::string name_to_s (const Obj *obj)
|
||||
{
|
||||
std::map<const db::Net *, unsigned int> net2id;
|
||||
unsigned int id = 0;
|
||||
|
||||
if (circuit.begin_nets () != circuit.end_nets ()) {
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << indent1 << "# Nets with their geometries" << endl;
|
||||
}
|
||||
for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) {
|
||||
net2id.insert (std::make_pair (n.operator-> (), ++id));
|
||||
write (l2n, *n, id);
|
||||
}
|
||||
}
|
||||
|
||||
if (circuit.begin_pins () != circuit.end_pins ()) {
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << indent1 << "# Outgoing pins and their connections to nets" << endl;
|
||||
}
|
||||
for (db::Circuit::const_pin_iterator p = circuit.begin_pins (); p != circuit.end_pins (); ++p) {
|
||||
const db::Net *net = circuit.net_for_pin (p->id ());
|
||||
if (net) {
|
||||
*mp_stream << indent1 << Keys::pin_key << "(" << tl::to_word_or_quoted_string (p->expanded_name ()) << " " << net2id [net] << ")" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (circuit.begin_devices () != circuit.end_devices ()) {
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << indent1 << "# Devices and their connections" << endl;
|
||||
}
|
||||
for (db::Circuit::const_device_iterator d = circuit.begin_devices (); d != circuit.end_devices (); ++d) {
|
||||
write (l2n, *d, net2id);
|
||||
}
|
||||
}
|
||||
|
||||
if (circuit.begin_subcircuits () != circuit.end_subcircuits ()) {
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl << indent1 << "# Subcircuits and their connections" << endl;
|
||||
}
|
||||
for (db::Circuit::const_subcircuit_iterator x = circuit.begin_subcircuits (); x != circuit.end_subcircuits (); ++x) {
|
||||
write (l2n, *x, net2id);
|
||||
}
|
||||
}
|
||||
|
||||
if (! Keys::is_short ()) {
|
||||
*mp_stream << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void write_point (tl::OutputStream &stream, const db::Point &pt, db::Point &ref, bool relative)
|
||||
{
|
||||
if (relative) {
|
||||
|
||||
stream << "(";
|
||||
stream << pt.x () - ref.x ();
|
||||
stream << " ";
|
||||
stream << pt.y () - ref.y ();
|
||||
stream << ")";
|
||||
|
||||
if (obj) {
|
||||
return tl::to_word_or_quoted_string (obj->name ());
|
||||
} else {
|
||||
|
||||
if (pt.x () == 0 || pt.x () != ref.x ()) {
|
||||
stream << pt.x ();
|
||||
} else {
|
||||
stream << "*";
|
||||
}
|
||||
|
||||
if (pt.y () == 0 || pt.y () != ref.y ()) {
|
||||
stream << pt.y ();
|
||||
} else {
|
||||
stream << "*";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ref = pt;
|
||||
}
|
||||
|
||||
template <class T, class Tr>
|
||||
void write_points (tl::OutputStream &stream, const T &poly, const Tr &tr, db::Point &ref, bool relative)
|
||||
{
|
||||
for (typename T::polygon_contour_iterator c = poly.begin_hull (); c != poly.end_hull (); ++c) {
|
||||
|
||||
typename T::point_type pt = tr * *c;
|
||||
|
||||
stream << " ";
|
||||
write_point (stream, pt, ref, relative);
|
||||
|
||||
return "()";
|
||||
}
|
||||
}
|
||||
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::reset_geometry_ref ()
|
||||
template <class Obj>
|
||||
std::string expanded_name_to_s (const Obj *obj)
|
||||
{
|
||||
m_ref = db::Point ();
|
||||
}
|
||||
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname, bool relative)
|
||||
{
|
||||
db::ICplxTrans t = tr * db::ICplxTrans (s->trans ());
|
||||
|
||||
const db::Polygon &poly = s->obj ();
|
||||
if (poly.is_box ()) {
|
||||
|
||||
db::Box box = t * poly.box ();
|
||||
*mp_stream << Keys::rect_key << "(" << lname;
|
||||
*mp_stream << " ";
|
||||
write_point (*mp_stream, box.p1 (), m_ref, relative);
|
||||
*mp_stream << " ";
|
||||
write_point (*mp_stream, box.p2 (), m_ref, relative);
|
||||
*mp_stream << ")";
|
||||
|
||||
if (obj) {
|
||||
return tl::to_word_or_quoted_string (obj->expanded_name ());
|
||||
} else {
|
||||
|
||||
*mp_stream << Keys::polygon_key << "(" << lname;
|
||||
if (poly.holes () > 0) {
|
||||
db::SimplePolygon sp (poly);
|
||||
write_points (*mp_stream, sp, t, m_ref, relative);
|
||||
} else {
|
||||
write_points (*mp_stream, poly, t, m_ref, relative);
|
||||
}
|
||||
*mp_stream << ")";
|
||||
|
||||
return "()";
|
||||
}
|
||||
}
|
||||
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutVsSchematic *l2n, const db::Net &net, unsigned int id)
|
||||
std::string net_id_to_s (const db::Net *net, const std::map<const db::Net *, unsigned int> &net2id)
|
||||
{
|
||||
if (! l2n->netlist ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Can't write annotated netlist before extraction has been done")));
|
||||
}
|
||||
|
||||
const db::hier_clusters<db::PolygonRef> &clusters = l2n->net_clusters ();
|
||||
const db::Circuit *circuit = net.circuit ();
|
||||
const db::Connectivity &conn = l2n->connectivity ();
|
||||
|
||||
bool any = false;
|
||||
|
||||
reset_geometry_ref ();
|
||||
|
||||
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
|
||||
|
||||
db::cell_index_type cci = circuit->cell_index ();
|
||||
db::cell_index_type prev_ci = cci;
|
||||
|
||||
for (db::recursive_cluster_shape_iterator<db::PolygonRef> si (clusters, *l, cci, net.cluster_id ()); ! si.at_end (); ) {
|
||||
|
||||
// NOTE: we don't recursive into circuits which will later be output. However, as circuits may
|
||||
// vanish in "purge" but the clusters will still be there we need to recursive into clusters from
|
||||
// unknown cells.
|
||||
db::cell_index_type ci = si.cell_index ();
|
||||
if (ci != prev_ci && ci != cci && (l2n->netlist ()->circuit_by_cell_index (ci) || l2n->netlist ()->device_abstract_by_cell_index (ci))) {
|
||||
|
||||
si.skip_cell ();
|
||||
|
||||
} else {
|
||||
|
||||
if (! any) {
|
||||
*mp_stream << indent1 << Keys::net_key << "(" << id;
|
||||
if (! net.name ().empty ()) {
|
||||
*mp_stream << " " << Keys::name_key << "(" << tl::to_word_or_quoted_string (net.name ()) << ")";
|
||||
}
|
||||
*mp_stream << endl;
|
||||
any = true;
|
||||
}
|
||||
|
||||
*mp_stream << indent2;
|
||||
write (si.operator-> (), si.trans (), name_for_layer (l2n, *l), true);
|
||||
*mp_stream << endl;
|
||||
|
||||
prev_ci = ci;
|
||||
|
||||
++si;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (any) {
|
||||
*mp_stream << indent1 << ")" << endl;
|
||||
if (net) {
|
||||
std::map<const db::Net *, unsigned int>::const_iterator i = net2id.find (net);
|
||||
tl_assert (i != net2id.end ());
|
||||
return tl::to_string (i->second);
|
||||
} else {
|
||||
|
||||
*mp_stream << indent1 << Keys::net_key << "(" << id;
|
||||
if (! net.name ().empty ()) {
|
||||
*mp_stream << " " << Keys::name_key << "(" << tl::to_word_or_quoted_string (net.name ()) << ")";
|
||||
}
|
||||
*mp_stream << ")" << endl;
|
||||
|
||||
return "()";
|
||||
}
|
||||
}
|
||||
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutVsSchematic *l2n, const db::SubCircuit &subcircuit, std::map<const Net *, unsigned int> &net2id)
|
||||
std::string std_writer_impl<Keys>::status_to_s (const db::NetlistCrossReference::Status status)
|
||||
{
|
||||
const db::Layout *ly = l2n->internal_layout ();
|
||||
double dbu = ly->dbu ();
|
||||
|
||||
*mp_stream << indent1 << Keys::circuit_key << "(" << tl::to_word_or_quoted_string (subcircuit.expanded_name ());
|
||||
*mp_stream << " " << tl::to_word_or_quoted_string (subcircuit.circuit_ref ()->name ());
|
||||
|
||||
const db::DCplxTrans &tr = subcircuit.trans ();
|
||||
if (tr.is_mag ()) {
|
||||
*mp_stream << " " << Keys::scale_key << "(" << tr.mag () << ")";
|
||||
}
|
||||
if (tr.is_mirror ()) {
|
||||
*mp_stream << " " << Keys::mirror_key;
|
||||
}
|
||||
if (fabs (tr.angle ()) > 1e-6) {
|
||||
*mp_stream << " " << Keys::rotation_key << "(" << tr.angle () << ")";
|
||||
}
|
||||
*mp_stream << " " << Keys::location_key << "(" << tr.disp ().x () / dbu << " " << tr.disp ().y () / dbu << ")";
|
||||
|
||||
// each pin in one line for more than a few pins
|
||||
bool separate_lines = (subcircuit.circuit_ref ()->pin_count () > 1);
|
||||
|
||||
if (separate_lines) {
|
||||
*mp_stream << endl;
|
||||
}
|
||||
|
||||
for (db::Circuit::const_pin_iterator p = subcircuit.circuit_ref ()->begin_pins (); p != subcircuit.circuit_ref ()->end_pins (); ++p) {
|
||||
const db::Net *net = subcircuit.net_for_pin (p->id ());
|
||||
if (net) {
|
||||
if (separate_lines) {
|
||||
*mp_stream << indent2;
|
||||
} else {
|
||||
*mp_stream << " ";
|
||||
}
|
||||
*mp_stream << Keys::pin_key << "(" << tl::to_word_or_quoted_string (p->expanded_name ()) << " " << net2id [net] << ")";
|
||||
if (separate_lines) {
|
||||
*mp_stream << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (separate_lines) {
|
||||
*mp_stream << indent1;
|
||||
}
|
||||
|
||||
*mp_stream << ")" << endl;
|
||||
}
|
||||
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutVsSchematic *l2n, const db::DeviceAbstract &device_abstract)
|
||||
{
|
||||
const std::vector<db::DeviceTerminalDefinition> &td = device_abstract.device_class ()->terminal_definitions ();
|
||||
|
||||
const db::hier_clusters<db::PolygonRef> &clusters = l2n->net_clusters ();
|
||||
const db::Connectivity &conn = l2n->connectivity ();
|
||||
|
||||
for (std::vector<db::DeviceTerminalDefinition>::const_iterator t = td.begin (); t != td.end (); ++t) {
|
||||
|
||||
*mp_stream << indent1 << Keys::terminal_key << "(" << t->name () << endl;
|
||||
|
||||
reset_geometry_ref ();
|
||||
|
||||
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
|
||||
|
||||
const db::local_cluster<db::PolygonRef> &lc = clusters.clusters_per_cell (device_abstract.cell_index ()).cluster_by_id (device_abstract.cluster_id_for_terminal (t->id ()));
|
||||
for (db::local_cluster<db::PolygonRef>::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) {
|
||||
|
||||
*mp_stream << indent2;
|
||||
write (s.operator-> (), db::ICplxTrans (), name_for_layer (l2n, *l), true);
|
||||
*mp_stream << endl;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*mp_stream << indent1 << ")" << endl;
|
||||
|
||||
if (status == db::NetlistCrossReference::Match) {
|
||||
return " " + Keys::match_key;
|
||||
} else if (status == db::NetlistCrossReference::NoMatch) {
|
||||
return " " + Keys::nomatch_key;
|
||||
} else if (status == db::NetlistCrossReference::Mismatch) {
|
||||
return " " + Keys::mismatch_key;
|
||||
} else if (status == db::NetlistCrossReference::MatchWithWarning) {
|
||||
return " " + Keys::warning_key;
|
||||
} else if (status == db::NetlistCrossReference::Skipped) {
|
||||
return " " + Keys::skipped_key;
|
||||
} else {
|
||||
return std::string ();
|
||||
}
|
||||
}
|
||||
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::LayoutVsSchematic *l2n, const db::Device &device, std::map<const Net *, unsigned int> &net2id)
|
||||
void std_writer_impl<Keys>::write (const db::NetlistCrossReference *xref)
|
||||
{
|
||||
const db::Layout *ly = l2n->internal_layout ();
|
||||
double dbu = ly->dbu ();
|
||||
db::VCplxTrans dbu_inv (1.0 / dbu);
|
||||
for (db::NetlistCrossReference::circuits_iterator c = xref->begin_circuits (); c != xref->end_circuits (); ++c) {
|
||||
|
||||
tl_assert (device.device_class () != 0);
|
||||
const std::vector<DeviceTerminalDefinition> &td = device.device_class ()->terminal_definitions ();
|
||||
const std::vector<DeviceParameterDefinition> &pd = device.device_class ()->parameter_definitions ();
|
||||
const db::NetlistCrossReference::PerCircuitData *pcd = xref->per_circuit_data_for (*c);
|
||||
tl_assert (pcd != 0);
|
||||
|
||||
*mp_stream << indent1 << Keys::device_key << "(" << tl::to_word_or_quoted_string (device.expanded_name ());
|
||||
stream () << indent1 << Keys::circuit_key << "(" << name_to_s (c->first) << " " << name_to_s (c->second) << status_to_s (pcd->status) << endl;
|
||||
stream () << indent2 << Keys::xref_key << endl;
|
||||
|
||||
tl_assert (device.device_abstract () != 0);
|
||||
*mp_stream << " " << tl::to_word_or_quoted_string (device.device_abstract ()->name ()) << endl;
|
||||
|
||||
const std::vector<db::DeviceAbstractRef> &other_abstracts = device.other_abstracts ();
|
||||
for (std::vector<db::DeviceAbstractRef>::const_iterator a = other_abstracts.begin (); a != other_abstracts.end (); ++a) {
|
||||
|
||||
db::Vector pos = dbu_inv * a->offset;
|
||||
|
||||
*mp_stream << " " << Keys::device_key << "(" << tl::to_word_or_quoted_string (a->device_abstract->name ()) << " " << pos.x () << " " << pos.y () << ")" << endl;
|
||||
|
||||
}
|
||||
|
||||
const std::map<unsigned int, std::vector<db::DeviceReconnectedTerminal> > &reconnected_terminals = device.reconnected_terminals ();
|
||||
for (std::map<unsigned int, std::vector<db::DeviceReconnectedTerminal> >::const_iterator t = reconnected_terminals.begin (); t != reconnected_terminals.end (); ++t) {
|
||||
|
||||
for (std::vector<db::DeviceReconnectedTerminal>::const_iterator c = t->second.begin (); c != t->second.end (); ++c) {
|
||||
*mp_stream << " " << Keys::connect_key << "(" << c->device_index << " " << tl::to_word_or_quoted_string (td [t->first].name ()) << " " << tl::to_word_or_quoted_string (td [c->other_terminal_id].name ()) << ")" << endl;
|
||||
for (db::NetlistCrossReference::PerCircuitData::net_pairs_const_iterator n = pcd->nets.begin (); n != pcd->nets.end (); ++n) {
|
||||
stream () << indent1 << indent2 << Keys::net_key << "(" << net_id_to_s (n->pair.first, m_net2id_per_circuit_a [c->first]) << " " << net_id_to_s (n->pair.second, m_net2id_per_circuit_b [c->second]) << status_to_s (n->status) << ")" << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
db::Point pos = dbu_inv * device.position ();
|
||||
|
||||
*mp_stream << indent2 << Keys::location_key << "(" << pos.x () << " " << pos.y () << ")" << endl;
|
||||
|
||||
for (std::vector<DeviceParameterDefinition>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
|
||||
*mp_stream << indent2 << Keys::param_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << device.parameter_value (i->id ()) << ")" << endl;
|
||||
}
|
||||
|
||||
for (std::vector<DeviceTerminalDefinition>::const_iterator i = td.begin (); i != td.end (); ++i) {
|
||||
const db::Net *net = device.net_for_terminal (i->id ());
|
||||
if (net) {
|
||||
*mp_stream << indent2 << Keys::terminal_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << net2id [net] << ")" << endl;
|
||||
for (db::NetlistCrossReference::PerCircuitData::pin_pairs_const_iterator n = pcd->pins.begin (); n != pcd->pins.end (); ++n) {
|
||||
stream () << indent1 << indent2 << Keys::pin_key << "(" << expanded_name_to_s (n->pair.first) << " " << expanded_name_to_s (n->pair.second) << status_to_s (n->status) << ")" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
*mp_stream << indent1 << ")" << endl;
|
||||
for (db::NetlistCrossReference::PerCircuitData::device_pairs_const_iterator n = pcd->devices.begin (); n != pcd->devices.end (); ++n) {
|
||||
stream () << indent1 << indent2 << Keys::device_key << "(" << expanded_name_to_s (n->pair.first) << " " << expanded_name_to_s (n->pair.second) << status_to_s (n->status) << ")" << endl;
|
||||
}
|
||||
|
||||
for (db::NetlistCrossReference::PerCircuitData::subcircuit_pairs_const_iterator n = pcd->subcircuits.begin (); n != pcd->subcircuits.end (); ++n) {
|
||||
stream () << indent1 << indent2 << Keys::circuit_key << "(" << expanded_name_to_s (n->pair.first) << " " << expanded_name_to_s (n->pair.second) << status_to_s (n->status) << ")" << endl;
|
||||
}
|
||||
|
||||
stream () << indent2 << ")" << endl;
|
||||
stream () << indent1 << ")" << endl;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// LayoutVsSchematicStandardWriter implementation
|
||||
|
|
@ -549,17 +220,15 @@ LayoutVsSchematicStandardWriter::LayoutVsSchematicStandardWriter (tl::OutputStre
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void LayoutVsSchematicStandardWriter::do_write (const db::LayoutVsSchematic * /*lvs*/)
|
||||
void LayoutVsSchematicStandardWriter::do_write_lvs (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);
|
||||
lvs_std_format::std_writer_impl<lvs_std_format::keys<true> > writer (*mp_stream);
|
||||
writer.write (lvs);
|
||||
} else {
|
||||
l2n_std_format::std_writer_impl<l2n_std_format::keys<false> > writer (*mp_stream);
|
||||
writer.write (l2n);
|
||||
lvs_std_format::std_writer_impl<lvs_std_format::keys<false> > writer (*mp_stream);
|
||||
writer.write (lvs);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,12 +24,16 @@
|
|||
#define HDR_dbLayoutVsSchematicWriter
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbLayoutToNetlistWriter.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
class Circuit;
|
||||
class Net;
|
||||
class LayoutVsSchematic;
|
||||
class NetlistCrossReference;
|
||||
|
||||
/**
|
||||
* @brief The base class for a LayoutVsSchematic writer
|
||||
|
|
@ -43,7 +47,7 @@ public:
|
|||
void write (const db::LayoutVsSchematic *lvs);
|
||||
|
||||
protected:
|
||||
virtual void do_write (const db::LayoutVsSchematic *lvs) = 0;
|
||||
virtual void do_write_lvs (const db::LayoutVsSchematic *lvs) = 0;
|
||||
|
||||
private:
|
||||
std::string m_filename;
|
||||
|
|
@ -59,7 +63,7 @@ public:
|
|||
LayoutVsSchematicStandardWriter (tl::OutputStream &stream, bool short_version);
|
||||
|
||||
protected:
|
||||
void do_write (const db::LayoutVsSchematic *lvs);
|
||||
void do_write_lvs (const db::LayoutVsSchematic *lvs);
|
||||
|
||||
private:
|
||||
tl::OutputStream *mp_stream;
|
||||
|
|
|
|||
Loading…
Reference in New Issue