mirror of https://github.com/KLayout/klayout.git
WIP: refactoring of L2N/LVSDB writer
This commit is contained in:
parent
0083021220
commit
e1882b0de7
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 ());
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue