Unique net names for Spice netlist writer

This commit is contained in:
Matthias Koefferlein 2019-05-31 22:19:51 +02:00
parent c684633dd6
commit 985cffc099
11 changed files with 357 additions and 7 deletions

View File

@ -25,8 +25,10 @@
#include "dbNetlistDeviceClasses.h"
#include "tlStream.h"
#include "tlUniqueName.h"
#include <sstream>
#include <set>
namespace db
{
@ -258,7 +260,10 @@ std::string NetlistSpiceWriter::net_to_string (const db::Net *net) const
// It does not like: , ;
// We translate , to | for the net separator
std::string n = net->expanded_name ();
std::map<const db::Net *, std::string>::const_iterator ni = m_net_to_spice_name.find (net);
tl_assert (ni != m_net_to_spice_name.end ());
const std::string &n = ni->second;
std::string nn;
nn.reserve (n.size () + 1);
if (!isalnum (*n.c_str ())) {
@ -369,6 +374,8 @@ void NetlistSpiceWriter::do_write (const std::string &description)
// assign internal node numbers to the nets
m_net_to_spice_id.clear ();
m_net_to_spice_name.clear ();
m_next_net_id = 0;
if (! m_use_net_names) {
@ -378,14 +385,22 @@ void NetlistSpiceWriter::do_write (const std::string &description)
} else {
// create unique names for those nets with a name
std::set<std::string> names;
for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) {
std::string nn = tl::unique_name (n->expanded_name (), names);
names.insert (nn);
m_net_to_spice_name.insert (std::make_pair (n.operator-> (), nn));
}
// determine the next net id for non-connected nets such that there is no clash with
// existing names
size_t prefix_len = strlen (not_connect_prefix);
for (db::Circuit::const_net_iterator n = circuit.begin_nets (); n != circuit.end_nets (); ++n) {
if (n->name ().find (not_connect_prefix) == 0 && n->name ().size () > prefix_len) {
for (std::set<std::string>::const_iterator n = names.begin (); n != names.end (); ++n) {
if (n->find (not_connect_prefix) == 0 && n->size () > prefix_len) {
size_t num = 0;
tl::from_string (n->name ().c_str () + prefix_len, num);
tl::from_string (n->c_str () + prefix_len, num);
m_next_net_id = std::max (m_next_net_id, num);
}
}

View File

@ -105,6 +105,7 @@ private:
tl::OutputStream *mp_stream;
tl::weak_ptr<NetlistSpiceWriterDelegate> mp_delegate;
std::map<const db::Net *, size_t> m_net_to_spice_id;
std::map<const db::Net *, std::string> m_net_to_spice_name;
mutable size_t m_next_net_id;
bool m_use_net_names;
bool m_with_comments;

View File

@ -24,6 +24,7 @@
#include "dbNetlistSpiceWriter.h"
#include "dbNetlist.h"
#include "dbNetlistDeviceClasses.h"
#include "dbLayoutToNetlist.h"
#include "tlUnitTest.h"
#include "tlStream.h"
@ -1024,7 +1025,37 @@ TEST(11_WriterNonConnectedPins)
compare_netlists (_this, path, au_path);
}
TEST(12_UniqueNetNames)
{
db::LayoutToNetlist l2n;
std::string l2n_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "same_net_names.l2n");
l2n.load (l2n_path);
// verify against the input
std::string path = tmp_file ("tmp_nwriter12.txt");
{
tl::OutputStream stream (path);
db::NetlistSpiceWriter writer;
writer.write (stream, *l2n.netlist (), "written by unit test");
}
std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nwriter12_au.txt");
compare_netlists (_this, path, au_path);
path = tmp_file ("tmp_nwriter12b.txt");
{
tl::OutputStream stream (path);
db::NetlistSpiceWriter writer;
writer.set_use_net_names (true);
writer.write (stream, *l2n.netlist (), "written by unit test");
}
au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nwriter12b_au.txt");
compare_netlists (_this, path, au_path);
}
namespace {

View File

@ -44,7 +44,8 @@ SOURCES = \
tlLongInt.cc \
tlUniqueId.cc \
tlList.cc \
tlEquivalenceClusters.cc
tlEquivalenceClusters.cc \
tlUniqueName.cc
HEADERS = \
tlAlgorithm.h \
@ -98,7 +99,8 @@ HEADERS = \
tlLongInt.h \
tlUniqueId.h \
tlList.h \
tlEquivalenceClusters.h
tlEquivalenceClusters.h \
tlUniqueName.h
equals(HAVE_CURL, "1") {

33
src/tl/tl/tlUniqueName.cc Normal file
View File

@ -0,0 +1,33 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "tlUniqueName.h"
namespace tl
{
// .. nothing yet ..
} // namespace tl

64
src/tl/tl/tlUniqueName.h Normal file
View File

@ -0,0 +1,64 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef HDR_tlUniqueName
#define HDR_tlUniqueName
#include "tlCommon.h"
#include "tlString.h"
namespace tl
{
/**
* @brief An object delivering a unique name given a set of existing names
*
* If no object with the given name exists, the original name is returned.
* Otherwise, the unique name is built from the original name plus
* the separator and an integer disambiguator.
*/
template <class Set>
TL_PUBLIC std::string unique_name (const std::string &org_name, const Set &present_names, const std::string &sep = "$")
{
if (present_names.find (org_name) == present_names.end ()) {
return org_name;
}
std::string b;
unsigned int j = 0;
for (unsigned int m = (unsigned int) 1 << (sizeof (unsigned int) * 8 - 2); m > 0; m >>= 1) {
j += m;
b = org_name + sep + tl::to_string (j);
if (present_names.find (b) == present_names.end ()) {
j -= m;
}
}
return org_name + sep + tl::to_string (j + 1);
}
} // namespace tl
#endif

View File

@ -0,0 +1,53 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2019 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "tlUniqueName.h"
#include "tlUnitTest.h"
#include <set>
#include <string>
// basic tests
TEST(1)
{
std::set<std::string> names;
EXPECT_EQ (tl::unique_name ("A", names), "A");
names.insert ("A");
EXPECT_EQ (tl::unique_name ("A", names), "A$1");
EXPECT_EQ (tl::unique_name ("A", names, "_"), "A_1");
names.insert ("A$1");
EXPECT_EQ (tl::unique_name ("A", names), "A$2");
names.insert ("A$2");
names.insert ("A$5");
EXPECT_EQ (tl::unique_name ("A", names), "A$3");
names.insert ("A$3");
EXPECT_EQ (tl::unique_name ("A", names), "A$4");
names.insert ("A$4");
EXPECT_EQ (tl::unique_name ("A", names), "A$6");
names.insert ("A$6");
EXPECT_EQ (tl::unique_name ("B", names), "B");
names.insert ("B");
EXPECT_EQ (tl::unique_name ("", names), "");
names.insert ("");
EXPECT_EQ (tl::unique_name ("", names), "$1");
}

View File

@ -37,7 +37,8 @@ SOURCES = \
tlLongInt.cc \
tlUniqueIdTests.cc \
tlListTests.cc \
tlEquivalenceClustersTests.cc
tlEquivalenceClustersTests.cc \
tlUniqueNameTests.cc
!equals(HAVE_QT, "0") {

26
testdata/algo/nwriter12_au.txt vendored Normal file
View File

@ -0,0 +1,26 @@
* written by unit test
* cell SUBCKT
* pin
* pin A
* pin V42
* pin Z
* pin gnd
* pin gnd
.SUBCKT SUBCKT 1 2 4 5 6 7
* net 2 A
* net 4 V42
* net 5 Z
* net 6 gnd
* net 7 gnd
* device instance $1 r0 *1 0,0 HVPMOS
XD_$1 4 3 5 1 HVPMOS PARAMS: L=0.2 W=1 AS=0.18 AD=0.18 PS=2.16 PD=2.16
* device instance $2 r0 *1 0,0 HVPMOS
XD_$2 4 2 3 1 HVPMOS PARAMS: L=0.2 W=1 AS=0.18 AD=0.18 PS=2.16 PD=2.16
* device instance $3 r0 *1 0,0 HVNMOS
XD_$3 6 3 6 7 HVNMOS PARAMS: L=1.13 W=2.12 PS=6 PD=6 AS=0 AD=0
* device instance $4 r0 *1 0,0 HVNMOS
XD_$4 6 3 5 7 HVNMOS PARAMS: L=0.4 W=0.4 PS=1.16 PD=1.16 AS=0.19 AD=0.19
* device instance $5 r0 *1 0,0 HVNMOS
XD_$5 6 2 3 7 HVNMOS PARAMS: L=0.4 W=0.4 PS=1.76 PD=1.76 AS=0.19 AD=0.19
.ENDS SUBCKT

21
testdata/algo/nwriter12b_au.txt vendored Normal file
View File

@ -0,0 +1,21 @@
* written by unit test
* cell SUBCKT
* pin
* pin A
* pin V42
* pin Z
* pin gnd
* pin gnd
.SUBCKT SUBCKT \$1 A V42 Z gnd gnd$1
* device instance $1 r0 *1 0,0 HVPMOS
XD_$1 V42 \$3 Z \$1 HVPMOS PARAMS: L=0.2 W=1 AS=0.18 AD=0.18 PS=2.16 PD=2.16
* device instance $2 r0 *1 0,0 HVPMOS
XD_$2 V42 A \$3 \$1 HVPMOS PARAMS: L=0.2 W=1 AS=0.18 AD=0.18 PS=2.16 PD=2.16
* device instance $3 r0 *1 0,0 HVNMOS
XD_$3 gnd \$3 gnd gnd$1 HVNMOS PARAMS: L=1.13 W=2.12 PS=6 PD=6 AS=0 AD=0
* device instance $4 r0 *1 0,0 HVNMOS
XD_$4 gnd \$3 Z gnd$1 HVNMOS PARAMS: L=0.4 W=0.4 PS=1.16 PD=1.16 AS=0.19 AD=0.19
* device instance $5 r0 *1 0,0 HVNMOS
XD_$5 gnd A \$3 gnd$1 HVNMOS PARAMS: L=0.4 W=0.4 PS=1.76 PD=1.76 AS=0.19 AD=0.19
.ENDS SUBCKT

103
testdata/algo/same_net_names.l2n vendored Normal file
View File

@ -0,0 +1,103 @@
#%l2n-klayout
W(CIRCUIT)
U(0.001)
D(D$HVPMOS HVPMOS
T(S
)
T(G
)
T(D
)
T(B
)
)
D(D$HVNMOS HVNMOS
T(S
)
T(G
)
T(D
)
T(B
)
)
X(SUBCKT
N(1
)
N(2 I(A)
)
N(3
)
N(4 I(V42)
)
N(5 I(Z)
)
N(6 I(gnd)
)
N(7 I(gnd)
)
P(1)
P(2 I(A))
P(4 I(V42))
P(5 I(Z))
P(6 I(gnd))
P(7 I(gnd))
D(1 D$HVPMOS
E(L 0.2)
E(W 1)
E(AS 0.18)
E(AD 0.18)
E(PS 2.16)
E(PD 2.16)
T(S 4)
T(G 3)
T(D 5)
T(B 1)
)
D(2 D$HVPMOS
E(L 0.2)
E(W 1)
E(AS 0.18)
E(AD 0.18)
E(PS 2.16)
E(PD 2.16)
T(S 4)
T(G 2)
T(D 3)
T(B 1)
)
D(3 D$HVNMOS
E(L 1.13)
E(W 2.12)
E(PS 6)
E(PD 6)
T(S 6)
T(G 3)
T(D 6)
T(B 7)
)
D(4 D$HVNMOS
E(L 0.4)
E(W 0.4)
E(AS 0.19)
E(AD 0.19)
E(PS 1.16)
E(PD 1.16)
T(S 6)
T(G 3)
T(D 5)
T(B 7)
)
D(5 D$HVNMOS
E(L 0.4)
E(W 0.4)
E(AS 0.19)
E(AD 0.19)
E(PS 1.76)
E(PD 1.76)
T(S 6)
T(G 2)
T(D 3)
T(B 7)
)
)