WIP: refactoring of L2N/LVSDB writer

This commit is contained in:
Matthias Koefferlein 2022-08-07 16:56:43 +02:00
parent 0083021220
commit e1882b0de7
11 changed files with 558 additions and 283 deletions

View File

@ -29,6 +29,9 @@
namespace db
{
static const std::string endl ("\n");
static const std::string indent1 (" ");
// -------------------------------------------------------------------------------------------
// LayoutToNetlistWriterBase implementation
@ -47,15 +50,89 @@ void LayoutToNetlistWriterBase::write (const db::LayoutToNetlist *l2n)
do_write (l2n);
}
// -------------------------------------------------------------------------------------------
// TokenizedOutput implementation
TokenizedOutput::TokenizedOutput (tl::OutputStream &s)
: mp_stream (&s), mp_parent (0), m_first (true), m_inline (false), m_newline (false), m_indent (-1)
{
// .. nothing yet ..
}
TokenizedOutput::TokenizedOutput (tl::OutputStream &s, const std::string &token)
: mp_stream (&s), mp_parent (0), m_first (true), m_inline (false), m_newline (false), m_indent (0)
{
stream () << token << "(";
}
TokenizedOutput::TokenizedOutput (tl::OutputStream &s, int indent, const std::string &token)
: mp_stream (&s), mp_parent (0), m_first (true), m_inline (false), m_newline (false)
{
m_indent = indent;
for (int i = 0; i < m_indent; ++i) {
stream () << indent1;
}
stream () << token << "(";
}
TokenizedOutput::TokenizedOutput (TokenizedOutput &output, const std::string &token, bool inl)
: mp_stream (&output.stream ()), mp_parent (&output), m_first (true), m_inline (inl), m_newline (false)
{
m_indent = output.indent () + 1;
output.emit_sep ();
stream () << token << "(";
}
TokenizedOutput::~TokenizedOutput ()
{
if (m_newline) {
for (int i = 0; i < m_indent; ++i) {
stream () << indent1;
}
}
if (m_indent >= 0) {
stream () << ")";
if (! m_inline) {
if (mp_parent) {
*mp_parent << endl;
} else {
stream () << endl;
}
}
}
}
void TokenizedOutput::emit_sep ()
{
if (m_newline) {
for (int i = 0; i <= m_indent; ++i) {
stream () << indent1;
}
m_newline = false;
} else if (! m_first) {
stream () << " ";
}
m_first = false;
}
TokenizedOutput &TokenizedOutput::operator<< (const std::string &s)
{
if (s == endl) {
m_newline = true;
stream () << s;
} else if (! s.empty ()) {
emit_sep ();
stream () << s;
}
return *this;
}
// -------------------------------------------------------------------------------------------
namespace l2n_std_format
{
static const std::string endl ("\n");
static const std::string indent1 (" ");
static const std::string indent2 (" ");
template <class Keys>
std_writer_impl<Keys>::std_writer_impl (tl::OutputStream &stream, double dbu, const std::string &progress_description)
: mp_stream (&stream), m_dbu (dbu), mp_netlist (0),
@ -82,7 +159,10 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n)
mp_netlist = l2n->netlist ();
mp_l2n = l2n;
write (false, 0);
{
TokenizedOutput stream (*mp_stream);
write (false, stream, 0);
}
mp_netlist = 0;
mp_l2n = 0;
@ -95,14 +175,14 @@ void std_writer_impl<Keys>::write (const db::LayoutToNetlist *l2n)
}
template <class Keys>
void std_writer_impl<Keys>::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 std_writer_impl<Keys>::write (TokenizedOutput &stream, bool nested, const db::Netlist *netlist, const db::LayoutToNetlist *l2n, std::map<const db::Circuit *, std::map<const db::Net *, unsigned int> > *net2id_per_circuit)
{
try {
mp_netlist = netlist;
mp_l2n = l2n;
write (nested, net2id_per_circuit);
write (nested, stream, net2id_per_circuit);
mp_netlist = 0;
mp_l2n = 0;
@ -126,16 +206,20 @@ static bool same_parameter (const DeviceParameterDefinition &a, const DevicePara
}
template <class Keys>
void std_writer_impl<Keys>::write_device_class (const std::string &indent, const db::DeviceClass *cls, const std::string &temp_name, const db::DeviceClass *temp_class)
void std_writer_impl<Keys>::write_device_class (TokenizedOutput &stream, const db::DeviceClass *cls, const std::string &temp_name, const db::DeviceClass *temp_class)
{
*mp_stream << indent << Keys::class_key << "(" << tl::to_word_or_quoted_string (cls->name ()) << " " << tl::to_word_or_quoted_string (temp_name);
TokenizedOutput out (stream, Keys::class_key);
out << tl::to_word_or_quoted_string (cls->name ()) << tl::to_word_or_quoted_string (temp_name);
bool any_def = false;
const std::vector<DeviceParameterDefinition> &pd = cls->parameter_definitions ();
for (std::vector<DeviceParameterDefinition>::const_iterator p = pd.begin (); p != pd.end (); ++p) {
if (! temp_class->has_parameter_with_name (p->name ()) || !same_parameter (*p, *temp_class->parameter_definition (temp_class->parameter_id_for_name (p->name ())))) {
*mp_stream << endl << indent << indent1 << Keys::param_key << "(" << tl::to_word_or_quoted_string (p->name ()) << " " << tl::to_string (p->is_primary () ? 1 : 0) << " " << tl::to_string (p->default_value ()) << ")";
if (! any_def) {
out << endl;
}
TokenizedOutput (out, Keys::param_key) << tl::to_word_or_quoted_string (p->name ()) << tl::to_string (p->is_primary () ? 1 : 0) << tl::to_string (p->default_value ());
any_def = true;
}
}
@ -143,73 +227,70 @@ void std_writer_impl<Keys>::write_device_class (const std::string &indent, const
const std::vector<DeviceTerminalDefinition> &td = cls->terminal_definitions ();
for (std::vector<DeviceTerminalDefinition>::const_iterator t = td.begin (); t != td.end (); ++t) {
if (! temp_class->has_terminal_with_name (t->name ())) {
*mp_stream << endl << indent << indent1 << Keys::terminal_key << "(" << tl::to_word_or_quoted_string (t->name ()) << ")";
if (! any_def) {
out << endl;
}
TokenizedOutput (out, Keys::terminal_key) << tl::to_word_or_quoted_string (t->name ());
any_def = true;
}
}
if (any_def) {
*mp_stream << endl << indent << ")" << endl;
} else {
*mp_stream << ")" << endl;
}
}
template <class Keys>
void std_writer_impl<Keys>::write (bool nested, std::map<const db::Circuit *, std::map<const db::Net *, unsigned int> > *net2id_per_circuit)
void std_writer_impl<Keys>::write (bool nested, TokenizedOutput &stream, 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 = mp_l2n ? mp_l2n->internal_layout () : 0;
const std::string indent (nested ? indent1 : "");
if (! nested) {
*mp_stream << Keys::l2n_magic_string << endl;
stream << Keys::l2n_magic_string << endl;
}
if (version > 0) {
*mp_stream << indent << Keys::version_key << "(" << version << ")" << endl;
TokenizedOutput (stream, Keys::version_key) << tl::to_string (version);
stream << endl;
}
if (ly) {
*mp_stream << indent << Keys::top_key << "(" << tl::to_word_or_quoted_string (ly->cell_name (mp_l2n->internal_top_cell ()->cell_index ())) << ")" << endl;
*mp_stream << indent << Keys::unit_key << "(" << m_dbu << ")" << endl;
TokenizedOutput (stream, Keys::top_key) << tl::to_word_or_quoted_string (ly->cell_name (mp_l2n->internal_top_cell ()->cell_index ()));
TokenizedOutput (stream, Keys::unit_key) << tl::to_string (m_dbu);
}
bool any = false;
if (mp_l2n) {
if (! Keys::is_short ()) {
*mp_stream << endl << indent << "# Layer section" << endl;
*mp_stream << indent << "# This section lists the mask layers (drawing or derived) and their connections." << endl;
stream << endl << "# Layer section" << endl;
stream << "# This section lists the mask layers (drawing or derived) and their connections." << endl;
}
if (! Keys::is_short ()) {
*mp_stream << endl << indent << "# Mask layers" << endl;
stream << endl << "# Mask layers" << endl;
}
for (db::Connectivity::layer_iterator l = mp_l2n->connectivity ().begin_layers (); l != mp_l2n->connectivity ().end_layers (); ++l) {
*mp_stream << indent << Keys::layer_key << "(" << name_for_layer (mp_l2n, *l);
TokenizedOutput out (stream, Keys::layer_key);
out << name_for_layer (mp_l2n, *l);
db::LayerProperties lp = ly->get_properties (*l);
if (! lp.is_null ()) {
*mp_stream << " " << tl::to_word_or_quoted_string (lp.to_string ());
out << tl::to_word_or_quoted_string (lp.to_string ());
}
*mp_stream << ")" << endl;
m_progress.set (mp_stream->pos ());
}
if (! Keys::is_short ()) {
*mp_stream << endl << indent << "# Mask layer connectivity" << endl;
stream << endl << "# Mask layer connectivity" << endl;
}
for (db::Connectivity::layer_iterator l = mp_l2n->connectivity ().begin_layers (); l != mp_l2n->connectivity ().end_layers (); ++l) {
db::Connectivity::layer_iterator ce = mp_l2n->connectivity ().end_connected (*l);
db::Connectivity::layer_iterator cb = mp_l2n->connectivity ().begin_connected (*l);
if (cb != ce) {
*mp_stream << indent << Keys::connect_key << "(" << name_for_layer (mp_l2n, *l);
TokenizedOutput out (stream, Keys::connect_key);
out << name_for_layer (mp_l2n, *l);
for (db::Connectivity::layer_iterator c = mp_l2n->connectivity ().begin_connected (*l); c != ce; ++c) {
*mp_stream << " " << name_for_layer (mp_l2n, *c);
out << name_for_layer (mp_l2n, *c);
}
*mp_stream << ")" << endl;
m_progress.set (mp_stream->pos ());
}
@ -223,15 +304,15 @@ void std_writer_impl<Keys>::write (bool nested, std::map<const db::Circuit *, st
if (gb != ge) {
if (! any) {
if (! Keys::is_short ()) {
*mp_stream << endl << indent << "# Global nets and connectivity" << endl;
stream << endl << "# Global nets and connectivity" << endl;
}
any = true;
}
*mp_stream << indent << Keys::global_key << "(" << name_for_layer (mp_l2n, *l);
TokenizedOutput out (stream, Keys::global_key);
out << name_for_layer (mp_l2n, *l);
for (db::Connectivity::global_nets_iterator g = gb; g != ge; ++g) {
*mp_stream << " " << tl::to_word_or_quoted_string (mp_l2n->connectivity ().global_net_name (*g));
out << tl::to_word_or_quoted_string (mp_l2n->connectivity ().global_net_name (*g));
}
*mp_stream << ")" << endl;
m_progress.set (mp_stream->pos ());
}
@ -240,68 +321,64 @@ void std_writer_impl<Keys>::write (bool nested, std::map<const db::Circuit *, st
}
if (mp_netlist->begin_device_classes () != mp_netlist->end_device_classes () && ! Keys::is_short ()) {
*mp_stream << endl << indent << "# Device class section" << endl;
stream << endl << "# Device class section" << endl;
}
for (db::Netlist::const_device_class_iterator c = mp_netlist->begin_device_classes (); c != mp_netlist->end_device_classes (); ++c) {
db::DeviceClassTemplateBase *temp = db::DeviceClassTemplateBase::is_a (c.operator-> ());
if (temp) {
std::unique_ptr<db::DeviceClass> temp_class (temp->create ());
write_device_class (indent, c.operator-> (), temp->name (), temp_class.get ());
write_device_class (stream, c.operator-> (), temp->name (), temp_class.get ());
} else {
db::DeviceClass empty;
write_device_class (indent, c.operator-> (), std::string (), &empty);
write_device_class (stream, c.operator-> (), std::string (), &empty);
}
m_progress.set (mp_stream->pos ());
}
if (mp_netlist->begin_device_abstracts () != mp_netlist->end_device_abstracts () && ! Keys::is_short ()) {
*mp_stream << endl << indent << "# Device abstracts section" << endl;
*mp_stream << indent << "# Device abstracts list the pin shapes of the devices." << endl;
stream << endl << "# Device abstracts section" << endl;
stream << "# Device abstracts list the pin shapes of the devices." << endl;
}
for (db::Netlist::const_abstract_model_iterator m = mp_netlist->begin_device_abstracts (); m != mp_netlist->end_device_abstracts (); ++m) {
if (m->device_class ()) {
*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 (*m, indent);
*mp_stream << indent << ")" << endl;
TokenizedOutput out (stream, Keys::device_key);
out << tl::to_word_or_quoted_string (m->name ()) << tl::to_word_or_quoted_string (m->device_class ()->name ()) << endl;
write (out, *m);
m_progress.set (mp_stream->pos ());
}
}
if (! Keys::is_short ()) {
*mp_stream << endl << indent << "# Circuit section" << endl;
*mp_stream << indent << "# Circuits are the hierarchical building blocks of the netlist." << endl;
stream << endl << "# Circuit section" << endl;
stream << "# Circuits are the hierarchical building blocks of the netlist." << endl;
}
for (db::Netlist::const_bottom_up_circuit_iterator i = mp_netlist->begin_bottom_up (); i != mp_netlist->end_bottom_up (); ++i) {
const db::Circuit *x = i.operator-> ();
*mp_stream << indent << Keys::circuit_key << "(" << tl::to_word_or_quoted_string (x->name ()) << endl;
write (*x, indent, net2id_per_circuit);
*mp_stream << indent << ")" << endl;
TokenizedOutput out (stream, Keys::circuit_key);
out << tl::to_word_or_quoted_string (x->name ()) << endl;
write (out, *x, net2id_per_circuit);
m_progress.set (mp_stream->pos ());
}
}
void write_point (tl::OutputStream &stream, const db::Point &pt, db::Point &ref, bool relative)
static void write_point (TokenizedOutput &out, const db::Point &pt, db::Point &ref, bool relative)
{
if (relative) {
stream << "(";
stream << pt.x () - ref.x ();
stream << " ";
stream << pt.y () - ref.y ();
stream << ")";
TokenizedOutput (out, std::string (), true) << tl::to_string (pt.x () - ref.x ()) << tl::to_string (pt.y () - ref.y ());
} else {
if (pt.x () == 0 || pt.x () != ref.x ()) {
stream << pt.x ();
out << tl::to_string (pt.x ());
} else {
stream << "*";
out << "*";
}
if (pt.y () == 0 || pt.y () != ref.y ()) {
stream << pt.y ();
out << tl::to_string (pt.y ());
} else {
stream << "*";
out << "*";
}
}
@ -310,25 +387,20 @@ void write_point (tl::OutputStream &stream, const db::Point &pt, db::Point &ref,
}
template <class T, class Tr>
void write_points (tl::OutputStream &stream, const T &poly, const Tr &tr, db::Point &ref, bool relative)
static void write_points (TokenizedOutput &out, 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);
write_point (out, tr * *c, ref, relative);
}
}
template <class Keys>
void std_writer_impl<Keys>::write (const db::Circuit &circuit, const std::string &indent, std::map<const db::Circuit *, std::map<const db::Net *, unsigned int> > *net2id_per_circuit)
void std_writer_impl<Keys>::write (TokenizedOutput &stream, const db::Circuit &circuit, std::map<const db::Circuit *, std::map<const db::Net *, unsigned int> > *net2id_per_circuit)
{
if (circuit.boundary ().vertices () > 0) {
if (! Keys::is_short ()) {
*mp_stream << endl << indent << indent1 << "# Circuit boundary" << endl;
stream << endl << "# Circuit boundary" << endl;
}
reset_geometry_ref ();
@ -337,22 +409,20 @@ void std_writer_impl<Keys>::write (const db::Circuit &circuit, const std::string
if (poly.is_box ()) {
db::Box box = poly.box ();
*mp_stream << indent << indent1 << Keys::rect_key << "(";
write_point (*mp_stream, box.p1 (), m_ref, true);
*mp_stream << " ";
write_point (*mp_stream, box.p2 (), m_ref, true);
*mp_stream << ")" << endl;
TokenizedOutput out (stream, Keys::rect_key);
write_point (out, box.p1 (), m_ref, true);
write_point (out, box.p2 (), m_ref, true);
} else {
*mp_stream << indent << indent1 << Keys::polygon_key << "(";
TokenizedOutput out (stream, Keys::polygon_key);
if (poly.holes () > 0) {
db::SimplePolygon sp = db::polygon_to_simple_polygon (poly);
write_points (*mp_stream, sp, db::UnitTrans (), m_ref, true);
write_points (out, sp, db::UnitTrans (), m_ref, true);
} else {
write_points (*mp_stream, poly, db::UnitTrans (), m_ref, true);
write_points (out, poly, db::UnitTrans (), m_ref, true);
}
*mp_stream << ")" << endl;
}
@ -360,9 +430,9 @@ void std_writer_impl<Keys>::write (const db::Circuit &circuit, const std::string
for (db::NetlistObject::property_iterator p = circuit.begin_properties (); p != circuit.end_properties (); ++p) {
if (p == circuit.begin_properties() && ! Keys::is_short ()) {
*mp_stream << endl << indent << indent1 << "# Properties" << endl;
stream << endl << "# Properties" << endl;
}
*mp_stream << indent << indent1 << Keys::property_key << "(" << p->first.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl;
TokenizedOutput (stream, Keys::property_key) << p->first.to_parsable_string () << p->second.to_parsable_string ();
}
std::map<const db::Net *, unsigned int> net2id_local;
@ -379,60 +449,56 @@ void std_writer_impl<Keys>::write (const db::Circuit &circuit, const std::string
if (circuit.begin_nets () != circuit.end_nets ()) {
if (! Keys::is_short ()) {
if (mp_l2n) {
*mp_stream << endl << indent << indent1 << "# Nets with their geometries" << endl;
stream << endl << "# Nets with their geometries" << endl;
} else {
*mp_stream << endl << indent << indent1 << "# Nets" << endl;
stream << endl << "# Nets" << endl;
}
}
for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) {
write (*n, (*net2id) [n.operator-> ()], indent);
write (stream, *n, (*net2id) [n.operator-> ()]);
m_progress.set (mp_stream->pos ());
}
}
if (circuit.begin_pins () != circuit.end_pins ()) {
if (! Keys::is_short ()) {
*mp_stream << endl << indent << indent1 << "# Outgoing pins and their connections to nets" << endl;
stream << endl << "# Outgoing pins and their connections to nets" << endl;
}
for (db::Circuit::const_pin_iterator p = circuit.begin_pins (); p != circuit.end_pins (); ++p) {
*mp_stream << indent << indent1 << Keys::pin_key << "(";
TokenizedOutput out (stream, Keys::pin_key);
const db::Net *net = circuit.net_for_pin (p->id ());
if (net) {
*mp_stream << (*net2id) [net];
out << tl::to_string ((*net2id) [net]);
}
if (! p->name ().empty ()) {
if (net) {
*mp_stream << " ";
}
*mp_stream << Keys::name_key << "(" << tl::to_word_or_quoted_string (p->name ()) << ")";
TokenizedOutput (out, Keys::name_key, true) << tl::to_word_or_quoted_string (p->name ());
}
*mp_stream << ")" << endl;
m_progress.set (mp_stream->pos ());
}
}
if (circuit.begin_devices () != circuit.end_devices ()) {
if (! Keys::is_short ()) {
*mp_stream << endl << indent << indent1 << "# Devices and their connections" << endl;
stream << endl << "# Devices and their connections" << endl;
}
for (db::Circuit::const_device_iterator d = circuit.begin_devices (); d != circuit.end_devices (); ++d) {
write (*d, *net2id, indent);
write (stream, *d, *net2id);
m_progress.set (mp_stream->pos ());
}
}
if (circuit.begin_subcircuits () != circuit.end_subcircuits ()) {
if (! Keys::is_short ()) {
*mp_stream << endl << indent << indent1 << "# Subcircuits and their connections" << endl;
stream << endl << "# Subcircuits and their connections" << endl;
}
for (db::Circuit::const_subcircuit_iterator x = circuit.begin_subcircuits (); x != circuit.end_subcircuits (); ++x) {
write (*x, *net2id, indent);
write (stream, *x, *net2id);
m_progress.set (mp_stream->pos ());
}
}
if (! Keys::is_short ()) {
*mp_stream << endl;
stream << endl;
}
}
@ -443,7 +509,7 @@ void std_writer_impl<Keys>::reset_geometry_ref ()
}
template <class Keys>
void std_writer_impl<Keys>::write (const db::NetShape *s, const db::ICplxTrans &tr, const std::string &lname, bool relative)
void std_writer_impl<Keys>::write (TokenizedOutput &stream, const db::NetShape *s, const db::ICplxTrans &tr, const std::string &lname, bool relative)
{
if (s->type () == db::NetShape::Polygon) {
@ -454,39 +520,36 @@ void std_writer_impl<Keys>::write (const db::NetShape *s, const db::ICplxTrans &
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 << ")";
TokenizedOutput out (stream, Keys::rect_key);
out << lname;
write_point (out, box.p1 (), m_ref, relative);
write_point (out, box.p2 (), m_ref, relative);
} else {
*mp_stream << Keys::polygon_key << "(" << lname;
TokenizedOutput out (stream, Keys::polygon_key);
out << lname;
if (poly.holes () > 0) {
db::SimplePolygon sp = db::polygon_to_simple_polygon (poly);
write_points (*mp_stream, sp, t, m_ref, relative);
write_points (out, sp, t, m_ref, relative);
} else {
write_points (*mp_stream, poly, t, m_ref, relative);
write_points (out, poly, t, m_ref, relative);
}
*mp_stream << ")";
}
} else if (s->type () == db::NetShape::Text) {
*mp_stream << Keys::text_key << "(" << lname;
TokenizedOutput out (stream, Keys::text_key);
out << lname;
db::TextRef txtr = s->text_ref ();
db::ICplxTrans t = tr * db::ICplxTrans (txtr.trans ());
*mp_stream << " " << tl::to_word_or_quoted_string (txtr.obj ().string ()) << " ";
out << tl::to_word_or_quoted_string (txtr.obj ().string ());
db::Point pt = t * (db::Point () + txtr.obj ().trans ().disp ());
write_point (*mp_stream, pt, m_ref, relative);
*mp_stream << ")";
write_point (out, pt, m_ref, relative);
}
}
@ -498,13 +561,13 @@ bool std_writer_impl<Keys>::new_cell (cell_index_type ci) const
}
template <class Keys>
void std_writer_impl<Keys>::write (const db::Net &net, unsigned int id, const std::string &indent)
void std_writer_impl<Keys>::write (TokenizedOutput &stream, const db::Net &net, unsigned int id)
{
const db::hier_clusters<db::NetShape> &clusters = mp_l2n->net_clusters ();
const db::Circuit *circuit = net.circuit ();
const db::Connectivity &conn = mp_l2n->connectivity ();
bool any = false;
std::unique_ptr<TokenizedOutput> outp;
if (mp_l2n) {
@ -527,25 +590,24 @@ void std_writer_impl<Keys>::write (const db::Net &net, unsigned int id, const st
} else {
if (! any) {
if (! outp) {
*mp_stream << indent << indent1 << Keys::net_key << "(" << id;
outp.reset (new TokenizedOutput (stream, Keys::net_key));
*outp << tl::to_string (id);
if (! net.name ().empty ()) {
*mp_stream << " " << Keys::name_key << "(" << tl::to_word_or_quoted_string (net.name ()) << ")";
TokenizedOutput (*outp, Keys::name_key, true) << tl::to_word_or_quoted_string (net.name ());
}
*mp_stream << endl;
*outp << endl;
for (db::NetlistObject::property_iterator p = net.begin_properties (); p != net.end_properties (); ++p) {
*mp_stream << indent << indent2 << Keys::property_key << "(" << p->first.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl;
TokenizedOutput (*outp, Keys::property_key) << p->first.to_parsable_string () << p->second.to_parsable_string ();
}
any = true;
}
*mp_stream << indent << indent2;
write (si.operator-> (), si.trans (), name_for_layer (mp_l2n, *l), true);
*mp_stream << endl;
write (*outp, si.operator-> (), si.trans (), name_for_layer (mp_l2n, *l), true);
m_progress.set (mp_stream->pos ());
prev_ci = ci;
@ -560,80 +622,66 @@ void std_writer_impl<Keys>::write (const db::Net &net, unsigned int id, const st
}
if (any) {
*mp_stream << indent << indent1 << ")" << endl;
} else {
if (! outp) {
outp.reset (new TokenizedOutput (stream, Keys::net_key));
*outp << tl::to_string (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 ()) << ")";
TokenizedOutput (*outp, Keys::name_key, true) << tl::to_word_or_quoted_string (net.name ());
}
if (net.begin_properties () != net.end_properties ()) {
*mp_stream << endl;
*outp << endl;
for (db::NetlistObject::property_iterator p = net.begin_properties (); p != net.end_properties (); ++p) {
*mp_stream << indent << indent2 << Keys::property_key << "(" << p->first.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl;
TokenizedOutput (*outp, Keys::property_key) << p->first.to_parsable_string () << p->second.to_parsable_string ();
}
*mp_stream << indent << ")" << endl;
} else {
*mp_stream << ")" << endl;
}
}
}
template <class Keys>
void std_writer_impl<Keys>::write (const db::SubCircuit &subcircuit, std::map<const db::Net *, unsigned int> &net2id, const std::string &indent)
void std_writer_impl<Keys>::write (TokenizedOutput &stream, const db::SubCircuit &subcircuit, std::map<const db::Net *, unsigned int> &net2id)
{
*mp_stream << indent << indent1 << Keys::circuit_key << "(" << tl::to_string (subcircuit.id ());
*mp_stream << " " << tl::to_word_or_quoted_string (subcircuit.circuit_ref ()->name ());
TokenizedOutput out (stream, Keys::circuit_key);
out << tl::to_string (subcircuit.id ());
out << tl::to_word_or_quoted_string (subcircuit.circuit_ref ()->name ());
if (! subcircuit.name ().empty ()) {
*mp_stream << " " << Keys::name_key << "(" << tl::to_word_or_quoted_string (subcircuit.name ()) << ")";
TokenizedOutput (out, Keys::name_key, true) << tl::to_word_or_quoted_string (subcircuit.name ());
}
if (mp_l2n) {
*mp_stream << " ";
write (subcircuit.trans ());
write (out, subcircuit.trans ());
}
// each pin in one line for more than a few pins
bool separate_lines = (subcircuit.circuit_ref ()->pin_count () > 1) || subcircuit.begin_properties () != subcircuit.end_properties ();
if (separate_lines) {
*mp_stream << endl;
out << endl;
}
for (db::NetlistObject::property_iterator p = subcircuit.begin_properties (); p != subcircuit.end_properties (); ++p) {
*mp_stream << indent << indent2 << Keys::property_key << "(" << p->first.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl;
TokenizedOutput (out, Keys::property_key, ! separate_lines) << p->first.to_parsable_string () << p->second.to_parsable_string ();
}
unsigned int pin_id = 0;
for (db::Circuit::const_pin_iterator p = subcircuit.circuit_ref ()->begin_pins (); p != subcircuit.circuit_ref ()->end_pins (); ++p, ++pin_id) {
const db::Net *net = subcircuit.net_for_pin (p->id ());
if (net) {
if (separate_lines) {
*mp_stream << indent << indent2;
} else {
*mp_stream << " ";
}
*mp_stream << Keys::pin_key << "(" << tl::to_string (pin_id) << " " << net2id [net] << ")";
if (separate_lines) {
*mp_stream << endl;
}
TokenizedOutput (out, Keys::pin_key, ! separate_lines) << tl::to_string (pin_id) << tl::to_string (net2id [net]);
m_progress.set (mp_stream->pos ());
}
}
if (separate_lines) {
*mp_stream << indent << indent1;
}
*mp_stream << ")" << endl;
}
template <class Keys>
void std_writer_impl<Keys>::write (const db::DeviceAbstract &device_abstract, const std::string &indent)
void std_writer_impl<Keys>::write (TokenizedOutput &stream, const db::DeviceAbstract &device_abstract)
{
tl_assert (mp_l2n);
const std::vector<db::DeviceTerminalDefinition> &td = device_abstract.device_class ()->terminal_definitions ();
const db::hier_clusters<db::NetShape> &clusters = mp_l2n->net_clusters ();
@ -641,10 +689,13 @@ void std_writer_impl<Keys>::write (const db::DeviceAbstract &device_abstract, co
for (std::vector<db::DeviceTerminalDefinition>::const_iterator t = td.begin (); t != td.end (); ++t) {
*mp_stream << indent << indent1 << Keys::terminal_key << "(" << t->name () << endl;
TokenizedOutput out (stream, Keys::terminal_key);
out << t->name ();
reset_geometry_ref ();
bool any = false;
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
size_t cid = device_abstract.cluster_id_for_terminal (t->id ());
@ -656,72 +707,62 @@ void std_writer_impl<Keys>::write (const db::DeviceAbstract &device_abstract, co
const db::local_cluster<db::NetShape> &lc = clusters.clusters_per_cell (device_abstract.cell_index ()).cluster_by_id (cid);
for (db::local_cluster<db::NetShape>::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) {
*mp_stream << indent << indent2;
write (s.operator-> (), db::ICplxTrans (), name_for_layer (mp_l2n, *l), true);
*mp_stream << endl;
if (! any) {
out << endl;
}
write (out, s.operator-> (), db::ICplxTrans (), name_for_layer (mp_l2n, *l), true);
m_progress.set (mp_stream->pos ());
any = true;
}
}
*mp_stream << indent << indent1 << ")" << endl;
m_progress.set (mp_stream->pos ());
}
}
template <class Keys>
void std_writer_impl<Keys>::write (const db::DCplxTrans &tr)
void std_writer_impl<Keys>::write (TokenizedOutput &stream, const db::DCplxTrans &tr)
{
bool first = true;
if (tr.is_mag ()) {
*mp_stream << Keys::scale_key << "(" << tr.mag () << ")";
first = false;
TokenizedOutput (stream, Keys::scale_key, true) << tl::to_string (tr.mag ());
}
if (tr.is_mirror ()) {
if (! first) {
*mp_stream << " ";
}
*mp_stream << Keys::mirror_key;
first = false;
stream << Keys::mirror_key;
}
if (fabs (tr.angle ()) > 1e-6) {
if (! first) {
*mp_stream << " ";
}
*mp_stream << Keys::rotation_key << "(" << tr.angle () << ")";
first = false;
TokenizedOutput (stream, Keys::rotation_key, true) << tl::to_string (tr.angle ());
}
if (! first) {
*mp_stream << " ";
}
*mp_stream << Keys::location_key << "(" << floor (0.5 + tr.disp ().x () / m_dbu) << " " << floor (0.5 + tr.disp ().y () / m_dbu) << ")";
TokenizedOutput (stream, Keys::location_key, true) << tl::to_string (floor (0.5 + tr.disp ().x () / m_dbu)) << tl::to_string (floor (0.5 + tr.disp ().y () / m_dbu));
}
template <class Keys>
void std_writer_impl<Keys>::write (const db::Device &device, std::map<const Net *, unsigned int> &net2id, const std::string &indent)
void std_writer_impl<Keys>::write (TokenizedOutput &stream, const db::Device &device, std::map<const Net *, unsigned int> &net2id)
{
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 ();
*mp_stream << indent << indent1 << Keys::device_key << "(" << tl::to_string (device.id ());
TokenizedOutput out (stream, Keys::device_key);
out << tl::to_string (device.id ());
if (device.device_abstract ()) {
*mp_stream << " " << tl::to_word_or_quoted_string (device.device_abstract ()->name ()) << endl;
out << 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) {
*mp_stream << indent << indent2 << Keys::device_key << "(" << tl::to_word_or_quoted_string (a->device_abstract->name ()) << " ";
write (a->trans);
*mp_stream << ")" << endl;
TokenizedOutput o (out, Keys::device_key);
o << tl::to_word_or_quoted_string (a->device_abstract->name ());
write (o, a->trans);
}
@ -729,41 +770,38 @@ void std_writer_impl<Keys>::write (const db::Device &device, std::map<const Net
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 << 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;
TokenizedOutput (out, Keys::connect_key) << tl::to_string (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 ());
}
}
*mp_stream << indent << indent2;
write (device.trans ());
*mp_stream << endl;
write (out, device.trans ());
out << endl;
} else {
*mp_stream << " " << tl::to_word_or_quoted_string (device.device_class ()->name ()) << endl;
out << tl::to_word_or_quoted_string (device.device_class ()->name ()) << endl;
}
if (! device.name ().empty ()) {
*mp_stream << indent << indent2 << Keys::name_key << "(" << tl::to_word_or_quoted_string (device.name ()) << ")" << endl;
TokenizedOutput (out, Keys::name_key) << tl::to_word_or_quoted_string (device.name ());
}
for (db::NetlistObject::property_iterator p = device.begin_properties (); p != device.end_properties (); ++p) {
*mp_stream << indent << indent2 << Keys::property_key << "(" << p->first.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl;
TokenizedOutput (out, Keys::property_key) << p->first.to_parsable_string () << p->second.to_parsable_string ();
}
for (std::vector<DeviceParameterDefinition>::const_iterator i = pd.begin (); i != pd.end (); ++i) {
*mp_stream << indent << indent2 << Keys::param_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << tl::sprintf ("%.12g", device.parameter_value (i->id ())) << ")" << endl;
TokenizedOutput (out, Keys::param_key) << tl::to_word_or_quoted_string (i->name ()) << tl::sprintf ("%.12g", device.parameter_value (i->id ()));
}
for (std::vector<DeviceTerminalDefinition>::const_iterator i = td.begin (); i != td.end (); ++i) {
const db::Net *net = device.net_for_terminal (i->id ());
TokenizedOutput o (out, Keys::terminal_key);
o << tl::to_word_or_quoted_string (i->name ());
if (net) {
*mp_stream << indent << indent2 << Keys::terminal_key << "(" << tl::to_word_or_quoted_string (i->name ()) << " " << net2id [net] << ")" << endl;
} else {
*mp_stream << indent << indent2 << Keys::terminal_key << "(" << tl::to_word_or_quoted_string (i->name ()) << ")" << endl;
o << tl::to_string (net2id [net]);
}
}
*mp_stream << indent << indent1 << ")" << endl;
}
// explicit instantiation

View File

@ -44,6 +44,35 @@ class Netlist;
class LayoutToNetlist;
class NetShape;
/**
* @brief A helper class to produce token/list lines
* Such lines are like:
* token(a b c)
* This class takes care of properly handling separation blanks
*/
class TokenizedOutput
{
public:
TokenizedOutput (tl::OutputStream &stream);
TokenizedOutput (tl::OutputStream &stream, const std::string &token);
TokenizedOutput (tl::OutputStream &stream, int indent, const std::string &token);
TokenizedOutput (TokenizedOutput &output, const std::string &token, bool inl = false);
~TokenizedOutput ();
TokenizedOutput &operator<< (const std::string &s);
tl::OutputStream &stream () { return *mp_stream; }
private:
tl::OutputStream *mp_stream;
TokenizedOutput *mp_parent;
bool m_first, m_inline, m_newline;
int m_indent;
void emit_sep ();
int indent () const { return m_indent; }
};
namespace l2n_std_format
{
@ -55,7 +84,7 @@ public:
std_writer_impl (tl::OutputStream &stream, double dbu, const std::string &progress_description = std::string ());
void write (const db::LayoutToNetlist *l2n);
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 (TokenizedOutput &stream, bool nested, const db::Netlist *netlist, const db::LayoutToNetlist *l2n, std::map<const db::Circuit *, std::map<const db::Net *, unsigned int> > *net2id_per_circuit);
protected:
tl::OutputStream &stream ()
@ -71,15 +100,15 @@ private:
const db::LayoutToNetlist *mp_l2n;
tl::AbsoluteProgress m_progress;
void write (bool nested, std::map<const db::Circuit *, std::map<const db::Net *, unsigned int> > *net2id_per_circuit);
void write (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::Net &net, unsigned int id, const std::string &indent);
void write (const db::SubCircuit &subcircuit, std::map<const Net *, unsigned int> &net2id, const std::string &indent);
void write (const db::Device &device, std::map<const Net *, unsigned int> &net2id, const std::string &indent);
void write (const db::DeviceAbstract &device_abstract, const std::string &indent);
void write (const db::NetShape *s, const db::ICplxTrans &tr, const std::string &lname, bool relative);
void write (const db::DCplxTrans &trans);
void write_device_class (const std::string &indent, const db::DeviceClass *cls, const std::string &name, const db::DeviceClass *temp_class);
void write (bool nested, TokenizedOutput &stream, std::map<const db::Circuit *, std::map<const db::Net *, unsigned int> > *net2id_per_circuit);
void write (TokenizedOutput &stream, const db::Circuit &circuit, std::map<const db::Circuit *, std::map<const db::Net *, unsigned int> > *net2id_per_circuit);
void write (TokenizedOutput &stream, const db::Net &net, unsigned int id);
void write (TokenizedOutput &stream, const db::SubCircuit &subcircuit, std::map<const Net *, unsigned int> &net2id);
void write (TokenizedOutput &stream, const db::Device &device, std::map<const Net *, unsigned int> &net2id);
void write (TokenizedOutput &stream, const db::DeviceAbstract &device_abstract);
void write (TokenizedOutput &stream, const db::NetShape *s, const db::ICplxTrans &tr, const std::string &lname, bool relative);
void write (TokenizedOutput &stream, const db::DCplxTrans &trans);
void write_device_class (TokenizedOutput &stream, const db::DeviceClass *cls, const std::string &name, const db::DeviceClass *temp_class);
void reset_geometry_ref ();
// implementation of CircuitCallback

View File

@ -43,9 +43,9 @@ namespace lvs_std_format
DB_PUBLIC std::string LongKeys::warning_key ("warning");
DB_PUBLIC std::string LongKeys::skipped_key ("skipped");
DB_PUBLIC std::string LongKeys::info_level_key ("info");
DB_PUBLIC std::string LongKeys::warning_level_key ("warning");
DB_PUBLIC std::string LongKeys::error_level_key ("error");
DB_PUBLIC std::string LongKeys::info_severity_key ("info");
DB_PUBLIC std::string LongKeys::warning_severity_key ("warning");
DB_PUBLIC std::string LongKeys::error_severity_key ("error");
// E, H, I, J, L, M, S, W, X, Z, 0, 1
@ -61,9 +61,9 @@ namespace lvs_std_format
DB_PUBLIC std::string ShortKeys::warning_key ("W");
DB_PUBLIC std::string ShortKeys::skipped_key ("S");
DB_PUBLIC std::string ShortKeys::info_level_key ("I");
DB_PUBLIC std::string ShortKeys::warning_level_key ("W");
DB_PUBLIC std::string ShortKeys::error_level_key ("E");
DB_PUBLIC std::string ShortKeys::info_severity_key ("I");
DB_PUBLIC std::string ShortKeys::warning_severity_key ("W");
DB_PUBLIC std::string ShortKeys::error_severity_key ("E");
}
}

View File

@ -80,9 +80,9 @@ namespace db
* log([log-entry]*) - log entries [short key: L]
*
* [log-entry]:
* entry([level] <name> [any]*) - log entry [short key: M]
* entry([severity] [message|any]*) - log entry [short key: M]
*
* [level]:
* [severity]:
* info | - [short key: I]
* warning | - [short key: W]
* error - [short key: E]
@ -92,16 +92,20 @@ namespace db
* - circuit cross-reference part [short key: Z]
*
* [xref-pin]:
* pin([ion] [ion] [status]? [message]? [any]*) - a pin pair [short key: P]
* pin([ion] [ion] [status]? [message]? [any]*)
* - a pin pair [short key: P]
*
* [xref-device]:
* device([ion] [ion] [status]? [message]? [any]*) - a device pair [short key: D]
* device([ion] [ion] [status]? [message]? [any]*)
* - a device pair [short key: D]
*
* [xref-circuit]:
* circuit([ion] [ion] [status]? [message]? [any]*) - a subcircuit pair [short key: X]
* circuit([ion] [ion] [status]? [message]? [any]*)
* - a subcircuit pair [short key: X]
*
* [xref-net]:
* net([ion] [ion] [status]? [message]? [any]*) - a net pair [short key: N]
* net([ion] [ion] [status]? [message]? [any]*)
* - a net pair [short key: N]
*
* [ion]:
* <id> | ()
@ -142,9 +146,9 @@ namespace lvs_std_format
static std::string warning_key;
static std::string skipped_key;
static std::string info_level_key;
static std::string warning_level_key;
static std::string error_level_key;
static std::string info_severity_key;
static std::string warning_severity_key;
static std::string error_severity_key;
};
struct DB_PUBLIC LongKeys
@ -163,9 +167,9 @@ namespace lvs_std_format
static std::string warning_key;
static std::string skipped_key;
static std::string info_level_key;
static std::string warning_level_key;
static std::string error_level_key;
static std::string info_severity_key;
static std::string warning_severity_key;
static std::string error_severity_key;
};
template <bool Short> struct DB_PUBLIC keys;

View File

@ -150,6 +150,59 @@ bool LayoutVsSchematicStandardReader::read_status (db::NetlistCrossReference::St
}
}
bool LayoutVsSchematicStandardReader::read_severity (db::NetlistCrossReference::Severity &severity)
{
if (test (skeys::info_severity_key) || test (lkeys::info_severity_key)) {
severity = db::NetlistCrossReference::Info;
return true;
} else if (test (skeys::warning_severity_key) || test (lkeys::warning_severity_key)) {
severity = db::NetlistCrossReference::Warning;
return true;
} else if (test (skeys::error_severity_key) || test (lkeys::error_severity_key)) {
severity = db::NetlistCrossReference::Error;
return true;
} else {
return false;
}
}
void LayoutVsSchematicStandardReader::read_log_entry (db::NetlistCrossReference *xref)
{
db::NetlistCrossReference::Severity severity = db::NetlistCrossReference::NoSeverity;
std::string msg;
Brace br (this);
while (br) {
if (read_severity (severity)) {
// continue
} else if (read_message (msg)) {
// continue
} else {
skip_element ();
}
}
br.done ();
xref->log_entry (severity, msg);
}
void LayoutVsSchematicStandardReader::read_logs_for_circuits (db::NetlistCrossReference *xref)
{
Brace br (this);
while (br) {
if (test (skeys::log_entry_key) || test (lkeys::log_entry_key)) {
read_log_entry (xref);
} else if (at_end ()) {
throw tl::Exception (tl::to_string (tr ("Unexpected end of file inside circuit definition (net, pin, device or circuit expected)")));
} else {
skip_element ();
}
}
br.done ();
}
void LayoutVsSchematicStandardReader::read_xrefs_for_circuits (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b)
{
Brace br (this);
@ -215,6 +268,8 @@ void LayoutVsSchematicStandardReader::read_xref (db::NetlistCrossReference *xref
// continue
} else if (test (skeys::xref_key) || test (lkeys::xref_key)) {
read_xrefs_for_circuits (xref, circuit_a, circuit_b);
} else if (test (skeys::log_key) || test (lkeys::log_key)) {
read_logs_for_circuits (xref);
} else if (at_end ()) {
throw tl::Exception (tl::to_string (tr ("Unexpected end of file inside circuit definition (status keyword of xrefs expected)")));
} else {

View File

@ -79,6 +79,9 @@ private:
bool read_status (db::NetlistCrossReference::Status &status);
bool read_message (std::string &msg);
void read_log_entry (db::NetlistCrossReference *xref);
void read_logs_for_circuits (db::NetlistCrossReference *xref);
bool read_severity (db::NetlistCrossReference::Severity &severity);
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);

View File

@ -28,6 +28,8 @@
namespace db
{
static const std::string endl ("\n");
// -------------------------------------------------------------------------------------------
// LayoutVsSchematicWriterBase implementation
@ -61,25 +63,22 @@ class std_writer_impl
public:
std_writer_impl (tl::OutputStream &stream, double dbu, const std::string &progress_description = std::string ());
void write (const db::LayoutVsSchematic *l2n);
void write (const db::LayoutVsSchematic *lvs);
private:
tl::OutputStream &stream ()
tl::OutputStream &ostream ()
{
return l2n_std_format::std_writer_impl<typename Keys::l2n_keys>::stream ();
}
std::string status_to_s (const db::NetlistCrossReference::Status status);
std::string severity_to_s (const db::NetlistCrossReference::Severity severity);
std::string message_to_s (const std::string &msg);
void write (const db::NetlistCrossReference *xref);
void write (TokenizedOutput &stream, 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");
static const std::string indent1 (" ");
static const std::string indent2 (" ");
template <class Keys>
std_writer_impl<Keys>::std_writer_impl (tl::OutputStream &stream, double dbu, const std::string &progress_description)
: l2n_std_format::std_writer_impl<typename Keys::l2n_keys> (stream, dbu, progress_description.empty () ? tl::to_string (tr ("Writing LVS database")) : progress_description)
@ -90,39 +89,40 @@ std_writer_impl<Keys>::std_writer_impl (tl::OutputStream &stream, double dbu, co
template <class Keys>
void std_writer_impl<Keys>::write (const db::LayoutVsSchematic *lvs)
{
TokenizedOutput out (ostream ());
out << Keys::lvs_magic_string << endl;
const int version = 0;
stream () << Keys::lvs_magic_string << endl;
if (version > 0) {
stream () << Keys::version_key << "(" << version << ")" << endl;
TokenizedOutput (out, Keys::version_key) << tl::to_string (version);
}
if (lvs->netlist ()) {
if (! Keys::is_short ()) {
stream () << endl << "# Layout" << endl;
out << endl << "# Layout" << endl;
}
stream () << Keys::layout_key << "(" << endl;
l2n_std_format::std_writer_impl<typename Keys::l2n_keys>::write (lvs->netlist (), lvs, true, &m_net2id_per_circuit_a);
stream () << ")" << endl;
TokenizedOutput o (out, Keys::layout_key);
o << endl;
l2n_std_format::std_writer_impl<typename Keys::l2n_keys>::write (o, true, lvs->netlist (), lvs, &m_net2id_per_circuit_a);
}
if (lvs->reference_netlist ()) {
if (! Keys::is_short ()) {
stream () << endl << "# Reference netlist" << endl;
out << endl << "# Reference netlist" << endl;
}
stream () << Keys::reference_key << "(" << endl;
l2n_std_format::std_writer_impl<typename Keys::l2n_keys>::write (lvs->reference_netlist (), 0, true, &m_net2id_per_circuit_b);
stream () << ")" << endl;
TokenizedOutput o (out, Keys::reference_key);
o << endl;
l2n_std_format::std_writer_impl<typename Keys::l2n_keys>::write (o, true, lvs->reference_netlist (), 0, &m_net2id_per_circuit_b);
}
if (lvs->cross_ref ()) {
if (! Keys::is_short ()) {
stream () << endl << "# Cross reference" << endl;
out << endl << "# Cross reference" << endl;
}
stream () << Keys::xref_key << "(" << endl;
write (lvs->cross_ref ());
stream () << ")" << endl;
TokenizedOutput o (out, Keys::xref_key);
o << endl;
write (o, lvs->cross_ref ());
}
}
@ -184,7 +184,7 @@ std::string std_writer_impl<Keys>::message_to_s (const std::string &msg)
if (msg.empty ()) {
return std::string ();
} else {
return " " + Keys::description_key + "(" + tl::to_word_or_quoted_string (msg) + ")";
return Keys::description_key + "(" + tl::to_word_or_quoted_string (msg) + ")";
}
}
@ -192,54 +192,82 @@ template <class Keys>
std::string std_writer_impl<Keys>::status_to_s (const db::NetlistCrossReference::Status status)
{
if (status == db::NetlistCrossReference::Match) {
return " " + Keys::match_key;
return Keys::match_key;
} else if (status == db::NetlistCrossReference::NoMatch) {
return " " + Keys::nomatch_key;
return Keys::nomatch_key;
} else if (status == db::NetlistCrossReference::Mismatch) {
return " " + Keys::mismatch_key;
return Keys::mismatch_key;
} else if (status == db::NetlistCrossReference::MatchWithWarning) {
return " " + Keys::warning_key;
return Keys::warning_key;
} else if (status == db::NetlistCrossReference::Skipped) {
return " " + Keys::skipped_key;
return Keys::skipped_key;
} else {
return std::string ();
}
}
template <class Keys>
void std_writer_impl<Keys>::write (const db::NetlistCrossReference *xref)
std::string std_writer_impl<Keys>::severity_to_s (const db::NetlistCrossReference::Severity severity)
{
if (severity == db::NetlistCrossReference::Info) {
return Keys::info_severity_key;
} else if (severity == db::NetlistCrossReference::Warning) {
return Keys::warning_severity_key;
} else if (severity == db::NetlistCrossReference::Error) {
return Keys::error_severity_key;
} else {
return std::string ();
}
}
template <class Keys>
void std_writer_impl<Keys>::write (TokenizedOutput &stream, const db::NetlistCrossReference *xref)
{
for (db::NetlistCrossReference::circuits_iterator c = xref->begin_circuits (); c != xref->end_circuits (); ++c) {
const db::NetlistCrossReference::PerCircuitData *pcd = xref->per_circuit_data_for (*c);
tl_assert (pcd != 0);
stream () << indent1 << Keys::circuit_key << "(" << name_to_s (c->first) << " " << name_to_s (c->second) << status_to_s (pcd->status) << message_to_s (pcd->msg) << endl;
stream () << indent2 << Keys::xref_key << "(" << endl;
TokenizedOutput out (stream, Keys::circuit_key);
out << name_to_s (c->first) << name_to_s (c->second) << status_to_s (pcd->status) << message_to_s (pcd->msg);
out << endl;
if (! pcd->log_entries.empty ()) {
TokenizedOutput o (out, Keys::log_key);
o << endl;
for (db::NetlistCrossReference::PerCircuitData::log_entries_const_iterator l = pcd->log_entries.begin (); l != pcd->log_entries.end (); ++l) {
TokenizedOutput (o, Keys::log_entry_key, true) << severity_to_s (l->severity) << message_to_s (l->msg);
}
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) << message_to_s (n->msg) << ")" << endl;
}
std::map<const db::Pin *, unsigned int> pin2index_a, pin2index_b;
build_pin_index_map (c->first, pin2index_a);
build_pin_index_map (c->second, pin2index_b);
{
TokenizedOutput o (out, Keys::xref_key);
o << endl;
for (db::NetlistCrossReference::PerCircuitData::pin_pairs_const_iterator n = pcd->pins.begin (); n != pcd->pins.end (); ++n) {
stream () << indent1 << indent2 << Keys::pin_key << "(" << pin_id_to_s (n->pair.first, pin2index_a) << " " << pin_id_to_s (n->pair.second, pin2index_b) << status_to_s (n->status) << message_to_s (n->msg) << ")" << endl;
for (db::NetlistCrossReference::PerCircuitData::net_pairs_const_iterator n = pcd->nets.begin (); n != pcd->nets.end (); ++n) {
TokenizedOutput (o, 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) << message_to_s (n->msg);
}
std::map<const db::Pin *, unsigned int> pin2index_a, pin2index_b;
build_pin_index_map (c->first, pin2index_a);
build_pin_index_map (c->second, pin2index_b);
for (db::NetlistCrossReference::PerCircuitData::pin_pairs_const_iterator n = pcd->pins.begin (); n != pcd->pins.end (); ++n) {
TokenizedOutput (o, Keys::pin_key) << pin_id_to_s (n->pair.first, pin2index_a) << pin_id_to_s (n->pair.second, pin2index_b) << status_to_s (n->status) << message_to_s (n->msg);
}
for (db::NetlistCrossReference::PerCircuitData::device_pairs_const_iterator n = pcd->devices.begin (); n != pcd->devices.end (); ++n) {
TokenizedOutput (o, Keys::device_key) << ion_to_s (n->pair.first) << ion_to_s (n->pair.second) << status_to_s (n->status) << message_to_s (n->msg);
}
for (db::NetlistCrossReference::PerCircuitData::subcircuit_pairs_const_iterator n = pcd->subcircuits.begin (); n != pcd->subcircuits.end (); ++n) {
TokenizedOutput (o, Keys::circuit_key) << ion_to_s (n->pair.first) << ion_to_s (n->pair.second) << status_to_s (n->status) << message_to_s (n->msg);
}
}
for (db::NetlistCrossReference::PerCircuitData::device_pairs_const_iterator n = pcd->devices.begin (); n != pcd->devices.end (); ++n) {
stream () << indent1 << indent2 << Keys::device_key << "(" << ion_to_s (n->pair.first) << " " << ion_to_s (n->pair.second) << status_to_s (n->status) << message_to_s (n->msg) << ")" << endl;
}
for (db::NetlistCrossReference::PerCircuitData::subcircuit_pairs_const_iterator n = pcd->subcircuits.begin (); n != pcd->subcircuits.end (); ++n) {
stream () << indent1 << indent2 << Keys::circuit_key << "(" << ion_to_s (n->pair.first) << " " << ion_to_s (n->pair.second) << status_to_s (n->status) << message_to_s (n->msg) << ")" << endl;
}
stream () << indent2 << ")" << endl;
stream () << indent1 << ")" << endl;
}
}

View File

@ -50,6 +50,16 @@ public:
NetlistCompareLogger () { }
virtual ~NetlistCompareLogger () { }
/**
* @brief An enum describing the severity for the log_entry function
*/
enum Severity {
NoSeverity = 0, // unspecific
Info = 1, // information only
Warning = 2, // a warning
Error = 3 // an error
};
/**
* @brief Begin logging for netlist a and b
*/
@ -88,6 +98,19 @@ public:
*/
virtual void circuit_mismatch (const db::Circuit * /*a*/, const db::Circuit * /*b*/, const std::string & /*msg*/ = std::string ()) { }
/**
* @brief Receives log entries for the current circuit pair
* These events are only generated when the "wants_log_entry" hint returns true.
*/
virtual void log_entry (Severity /*level*/, const std::string & /*msg*/) { }
/**
* @brief Returns a value indicating whether log entries need to be generated
* Log entries may include hints which are expensive to compute. This method tells the
* matching algorithm whether to create such entries or not.
*/
virtual bool wants_log_entries () const { return false; }
/**
* @brief Nets a and b match exactly
*/

View File

@ -416,6 +416,12 @@ NetlistCrossReference::gen_end_circuit (const db::Circuit *, const db::Circuit *
mp_per_circuit_data = 0;
}
void
NetlistCrossReference::gen_log_entry (Severity severity, const std::string &msg)
{
mp_per_circuit_data->log_entries.push_back (LogEntryData (severity, msg));
}
void
NetlistCrossReference::gen_nets (const db::Net *a, const db::Net *b, Status status, const std::string &msg)
{

View File

@ -105,6 +105,15 @@ public:
std::string msg;
};
struct LogEntryData
{
LogEntryData (Severity s, const std::string &m) : severity (s), msg (m) { }
LogEntryData () : severity (NoSeverity) { }
Severity severity;
std::string msg;
};
struct PerCircuitData
{
PerCircuitData () : status (None) { }
@ -117,6 +126,8 @@ public:
typedef pin_pairs_type::const_iterator pin_pairs_const_iterator;
typedef std::vector<SubCircuitPairData> subcircuit_pairs_type;
typedef subcircuit_pairs_type::const_iterator subcircuit_pairs_const_iterator;
typedef std::vector<LogEntryData> log_entries_type;
typedef log_entries_type::const_iterator log_entries_const_iterator;
Status status;
std::string msg;
@ -124,6 +135,7 @@ public:
device_pairs_type devices;
pin_pairs_type pins;
subcircuit_pairs_type subcircuits;
log_entries_type log_entries;
};
struct PerNetData
@ -145,6 +157,7 @@ public:
void gen_end_netlist (const db::Netlist *a, const db::Netlist *b);
void gen_begin_circuit (const db::Circuit *a, const db::Circuit *b);
void gen_end_circuit (const db::Circuit *a, const db::Circuit *b, Status status, const std::string &msg);
void gen_log_entry (Severity severity, const std::string &msg);
void gen_nets (const db::Net *a, const db::Net *b, Status status, const std::string &msg);
void gen_devices (const db::Device *a, const db::Device *b, Status status, const std::string &msg);
void gen_pins (const db::Pin *a, const db::Pin *b, Status status, const std::string &msg);
@ -185,6 +198,11 @@ public:
gen_end_circuit (a, b, Mismatch, msg);
}
virtual void log_entry (Severity severity, const std::string &msg)
{
gen_log_entry (severity, msg);
}
virtual void match_nets (const db::Net *a, const db::Net *b)
{
gen_nets (a, b, Match, std::string ());

View File

@ -21,6 +21,7 @@
*/
#include "gsiDecl.h"
#include "gsiEnums.h"
#include "dbNetlistCompare.h"
namespace {
@ -33,7 +34,7 @@ class GenericNetlistCompareLogger
{
public:
GenericNetlistCompareLogger ()
: db::NetlistCompareLogger ()
: db::NetlistCompareLogger (), m_wants_log (false)
{
// .. nothing yet ..
}
@ -127,7 +128,7 @@ public:
if (cb_circuit_mismatch.can_issue ()) {
cb_circuit_mismatch.issue<GenericNetlistCompareLogger, const db::Circuit *, const db::Circuit *, const std::string &> (&GenericNetlistCompareLogger::circuit_mismatch_fb, a, b, msg);
} else {
db::NetlistCompareLogger::circuit_mismatch (a, b);
db::NetlistCompareLogger::circuit_mismatch (a, b, msg);
}
}
@ -136,6 +137,35 @@ public:
db::NetlistCompareLogger::circuit_mismatch (a, b, msg);
}
virtual void log_entry (db::NetlistCompareLogger::Severity severity, const std::string &msg)
{
if (cb_log_entry.can_issue ()) {
cb_log_entry.issue<GenericNetlistCompareLogger, db::NetlistCompareLogger::Severity, const std::string &> (&GenericNetlistCompareLogger::log_entry, severity, msg);
} else {
db::NetlistCompareLogger::log_entry (severity, msg);
}
}
void log_entry_fb (db::NetlistCompareLogger::Severity severity, const std::string &msg)
{
db::NetlistCompareLogger::log_entry (severity, msg);
}
virtual bool wants_log () const
{
return m_wants_log;
}
bool get_wants_log () const
{
return m_wants_log;
}
void set_wants_log (bool f)
{
m_wants_log = f;
}
virtual void match_nets (const db::Net *a, const db::Net *b)
{
if (cb_match_nets.can_issue ()) {
@ -297,8 +327,10 @@ public:
gsi::Callback cb_end_circuit;
gsi::Callback cb_circuit_skipped;
gsi::Callback cb_match_nets;
gsi::Callback cb_net_mismatch;
gsi::Callback cb_circuit_mismatch;
gsi::Callback cb_log_entry;
gsi::Callback cb_wants_log;
gsi::Callback cb_net_mismatch;
gsi::Callback cb_match_ambiguous_nets;
gsi::Callback cb_match_devices;
gsi::Callback cb_match_devices_with_different_parameters;
@ -312,6 +344,8 @@ public:
private:
GenericNetlistCompareLogger (const GenericNetlistCompareLogger &d);
GenericNetlistCompareLogger &operator= (const GenericNetlistCompareLogger &d);
bool m_wants_log;
};
}
@ -368,6 +402,26 @@ Class<GenericNetlistCompareLogger> decl_GenericNetlistCompareLogger (decl_dbNetl
"\n"
"This method is called instead of \\begin_circuit and \\end_circuit."
) +
gsi::callback ("log_entry", &GenericNetlistCompareLogger::log_entry, &GenericNetlistCompareLogger::cb_log_entry, gsi::arg ("level"), gsi::arg ("msg"),
"@brief Issues an entry for the compare log.\n"
"This method delivers a log message generated during the compare of two circuits.\n"
"It is called between of \\begin_circuit and \\end_circuit and only if \\wants_log returns true.\n"
"\n"
"This method has been added in version 0.28."
) +
gsi::method ("wants_log=", &GenericNetlistCompareLogger::set_wants_log, gsi::arg ("value"),
"@brief Sets a value indicating whether the receiver wants log messages.\n"
"Log messages may include compare hints which are expensive to compute. Hence, by default, log generation is turned off. "
"Set this attribute to true in order to receive log messages.\n"
"\n"
"This method has been added in version 0.28."
) +
gsi::method ("wants_log", &GenericNetlistCompareLogger::get_wants_log,
"@brief Gets a value indicating whether the receiver wants log messages.\n"
"See \\wants_log= for details about this flag.\n"
"\n"
"This method has been added in version 0.28."
) +
gsi::callback ("match_nets", &GenericNetlistCompareLogger::match_nets, &GenericNetlistCompareLogger::cb_match_nets, gsi::arg ("a"), gsi::arg ("b"),
"@brief This function is called when two nets are identified.\n"
"If two nets are identified as a corresponding pair, this method will be called with both nets.\n"
@ -621,4 +675,21 @@ Class<db::NetlistComparer> decl_dbNetlistComparer ("db", "NetlistComparer",
"This class has been introduced in version 0.26."
);
gsi::EnumIn<GenericNetlistCompareLogger, db::NetlistCompareLogger::Severity> decl_CompareLoggerSeverity ("db", "Severity",
gsi::enum_const ("NoSeverity", db::NetlistCompareLogger::NoSeverity,
"@brief Unspecific severity\n"
) +
gsi::enum_const ("Info", db::NetlistCompareLogger::Info,
"@brief Information only\n"
) +
gsi::enum_const ("Warning", db::NetlistCompareLogger::Warning,
"@brief A warning\n"
) +
gsi::enum_const ("Error", db::NetlistCompareLogger::Error,
"@brief An error\n"
),
"@brief This class represents the log severity level for \\GenericNetlistCompareLogger#log_entry.\n"
"This enum has been introduced in version 0.28."
);
}