Merge pull request #246 from KLayout/issue-245

Issue 245
This commit is contained in:
Matthias Köfferlein 2019-03-22 21:49:39 +01:00 committed by GitHub
commit d1acd722ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 182 additions and 9 deletions

View File

@ -194,7 +194,7 @@ std::string NetlistSpiceWriterDelegate::format_params (const db::Device &dev) co
// --------------------------------------------------------------------------------
NetlistSpiceWriter::NetlistSpiceWriter (NetlistSpiceWriterDelegate *delegate)
: mp_netlist (0), mp_stream (0), mp_delegate (delegate)
: mp_netlist (0), mp_stream (0), mp_delegate (delegate), m_use_net_names (false)
{
static NetlistSpiceWriterDelegate std_delegate;
if (! delegate) {
@ -207,6 +207,11 @@ NetlistSpiceWriter::~NetlistSpiceWriter ()
// .. nothing yet ..
}
void NetlistSpiceWriter::set_use_net_names (bool use_net_names)
{
m_use_net_names = use_net_names;
}
void NetlistSpiceWriter::write (tl::OutputStream &stream, const db::Netlist &netlist, const std::string &description)
{
mp_stream = &stream;
@ -233,12 +238,48 @@ void NetlistSpiceWriter::write (tl::OutputStream &stream, const db::Netlist &net
std::string NetlistSpiceWriter::net_to_string (const db::Net *net) const
{
std::map<const db::Net *, size_t>::const_iterator n = m_net_to_spice_id.find (net);
if (! net || n == m_net_to_spice_id.end ()) {
// TODO: this should assert or similar
return "0";
if (m_use_net_names) {
if (! net) {
return "0";
} else {
// Tested with ngspice: this tool likes in net names: . $ ! & \ # + : | (but not at beginning)
// It does not like: , ;
// We translate , to | for the net separator
std::string n = net->expanded_name ();
std::string nn;
nn.reserve (n.size () + 1);
if (!isalnum (*n.c_str ())) {
nn += "\\";
}
for (const char *cp = n.c_str (); *cp; ++cp) {
if (! isalnum (*cp) && strchr (".$!&\\#+:,", *cp) == 0) {
nn += tl::sprintf ("\\x%02x", (unsigned char) *cp);
} else if (*cp == ',') {
nn += "|";
} else {
nn += *cp;
}
}
return nn;
}
} else {
return tl::to_string (n->second);
std::map<const db::Net *, size_t>::const_iterator n = m_net_to_spice_id.find (net);
if (! net || n == m_net_to_spice_id.end ()) {
// TODO: this should assert or similar
return "0";
} else {
return tl::to_string (n->second);
}
}
}
@ -389,9 +430,11 @@ void NetlistSpiceWriter::write_circuit_header (const db::Circuit &circuit) const
emit_line (os.str ());
for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) {
if (! n->name ().empty ()) {
emit_comment ("net " + net_to_string (n.operator-> ()) + " " + n->name ());
if (! m_use_net_names) {
for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) {
if (! n->name ().empty ()) {
emit_comment ("net " + net_to_string (n.operator-> ()) + " " + n->name ());
}
}
}
}

View File

@ -86,6 +86,12 @@ public:
virtual void write (tl::OutputStream &stream, const db::Netlist &netlist, const std::string &description);
void set_use_net_names (bool use_net_names);
bool use_net_names () const
{
return m_use_net_names;
}
private:
friend class NetlistSpiceWriterDelegate;
@ -93,6 +99,7 @@ private:
tl::OutputStream *mp_stream;
tl::weak_ptr<NetlistSpiceWriterDelegate> mp_delegate;
std::map<const db::Net *, size_t> m_net_to_spice_id;
bool m_use_net_names;
void do_write (const std::string &description);

View File

@ -1168,6 +1168,13 @@ Class<db::NetlistSpiceWriter> db_NetlistSpiceWriter (db_NetlistWriter, "db", "Ne
) +
gsi::constructor ("new", &new_spice_writer2,
"@brief Creates a new writer with a delegate.\n"
) +
gsi::method ("use_net_names=", &db::NetlistSpiceWriter::set_use_net_names, gsi::arg ("f"),
"@brief Sets a value indicating whether to use net names (true) or net numbers (false).\n"
"The default is to use net numbers."
) +
gsi::method ("use_net_names", &db::NetlistSpiceWriter::use_net_names,
"@brief Gets a value indicating whether to use net names (true) or net numbers (false).\n"
),
"@brief Implements a netlist writer for the SPICE format.\n"
"Provide a delegate for customizing the way devices are written.\n"

View File

@ -728,6 +728,103 @@ TEST(8_WriterSubcircuits)
compare_netlists (_this, path, au_path);
}
TEST(9_WriterNetNamesInsteadOfNumbers)
{
db::Netlist nl;
db::DeviceClass *cls = new db::DeviceClass ();
cls->add_terminal_definition (db::DeviceTerminalDefinition ("A", "a"));
cls->add_terminal_definition (db::DeviceTerminalDefinition ("B", "b"));
cls->add_parameter_definition (db::DeviceParameterDefinition ("U", "u"));
cls->add_parameter_definition (db::DeviceParameterDefinition ("V", "v"));
cls->set_name ("XCLS");
nl.add_device_class (cls);
db::Circuit *circuit1 = new db::Circuit ();
circuit1->set_name ("C1");
nl.add_circuit (circuit1);
{
db::Net *n1, *n2, *n3;
n1 = new db::Net ();
n1->set_name ("N1");
circuit1->add_net (n1);
n2 = new db::Net ();
n2->set_name ("N 2");
circuit1->add_net (n2);
n3 = new db::Net ();
n3->set_name ("n3");
circuit1->add_net (n3);
db::Device *ddev1 = new db::Device (cls);
ddev1->set_parameter_value (0, -17);
ddev1->set_parameter_value (1, 42);
db::Device *ddev2 = new db::Device (cls);
ddev2->set_parameter_value (0, 17);
ddev2->set_parameter_value (1, -42);
circuit1->add_device (ddev1);
circuit1->add_device (ddev2);
size_t pid1 = circuit1->add_pin ("p1").id ();
size_t pid2 = circuit1->add_pin ("p2").id ();
circuit1->connect_pin (pid1, n1);
circuit1->connect_pin (pid2, n2);
ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("A"), n1);
ddev1->connect_terminal (ddev1->device_class ()->terminal_id_for_name ("B"), n3);
ddev2->connect_terminal (ddev2->device_class ()->terminal_id_for_name ("A"), n3);
ddev2->connect_terminal (ddev2->device_class ()->terminal_id_for_name ("B"), n2);
}
db::Circuit *circuit2 = new db::Circuit ();
circuit2->set_name ("C2");
nl.add_circuit (circuit2);
{
db::Net *n1, *n2;
n1 = new db::Net ();
n1->set_name ("n1");
circuit2->add_net (n1);
n2 = new db::Net ();
n2->set_name ("n2");
circuit2->add_net (n2);
db::SubCircuit *sc1 = new db::SubCircuit (circuit1, "SC1");
circuit2->add_subcircuit (sc1);
sc1->connect_pin (0, n1);
sc1->connect_pin (1, n2);
size_t pid1 = circuit2->add_pin ("p1").id ();
size_t pid2 = circuit2->add_pin ("p2").id ();
circuit2->connect_pin (pid1, n1);
circuit2->connect_pin (pid2, n2);
}
// verify against the input
std::string path = tmp_file ("tmp_nwriter9.txt");
{
tl::OutputStream stream (path);
db::NetlistSpiceWriter writer;
writer.set_use_net_names (true);
writer.write (stream, nl, "written by unit test");
}
std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nwriter9_au.txt");
tl::InputStream is (path);
tl::InputStream is_au (au_path);
if (is.read_all () != is_au.read_all ()) {
_this->raise (tl::sprintf ("Compare failed - see\n actual: %s\n golden: %s",
tl::absolute_file_path (path),
tl::absolute_file_path (au_path)));
}
}
TEST(10_WriterLongLines)
{
db::Netlist nl;

19
testdata/algo/nwriter9_au.txt vendored Normal file
View File

@ -0,0 +1,19 @@
* written by unit test
* cell C2
* pin p1
* pin p2
.SUBCKT C2 n1 n2
* cell instance SC1 r0 *1 0,0
XSC1 n1 n2 C1
.ENDS C2
* cell C1
* pin p1
* pin p2
.SUBCKT C1 N1 N\x202
* device instance $1 0,0 XCLS
XD_$1 N1 n3 XCLS PARAMS: U=-17 V=42
* device instance $2 0,0 XCLS
XD_$2 n3 N\x202 XCLS PARAMS: U=17 V=-42
.ENDS C1