Unescaping of net names on Spice reader -> writer/reader should be self-compatible.

This commit is contained in:
Matthias Koefferlein 2019-05-31 22:55:09 +02:00
parent 985cffc099
commit 7d6237a90a
7 changed files with 146 additions and 43 deletions

View File

@ -146,8 +146,7 @@ std::string NetlistSpiceReader::get_line ()
tl::Extractor ex (l.c_str ());
if (ex.test_without_case (".include")) {
std::string path;
ex.read_word_or_quoted (path, allowed_name_chars);
std::string path = read_name (ex);
push_stream (path);
@ -398,27 +397,96 @@ db::Net *NetlistSpiceReader::make_net (const std::string &name)
return net;
}
void NetlistSpiceReader::read_subcircuit (tl::Extractor &ex)
void NetlistSpiceReader::read_pin_and_parameters (tl::Extractor &ex, std::vector<std::string> &nn, std::map<std::string, double> &pv)
{
std::string sc_name;
ex.read_word_or_quoted (sc_name, allowed_name_chars);
std::vector<std::string> nn;
std::map<std::string, double> pv;
bool in_params = false;
while (! ex.at_end ()) {
std::string n;
ex.read_word_or_quoted (n, allowed_name_chars);
if (ex.test_without_case ("params:")) {
in_params = true;
if (ex.test ("=")) {
// a parameter
pv.insert (std::make_pair (tl::to_upper_case (n), read_value (ex)));
} else {
nn.push_back (n);
std::string n = read_name (ex);
if (ex.test ("=")) {
// a parameter
pv.insert (std::make_pair (tl::to_upper_case (n), read_value (ex)));
} else {
if (in_params) {
error (tl::to_string (tr ("Missing '=' in parameter assignment")));
}
nn.push_back (n);
}
}
}
}
inline static int hex_num (char c)
{
if (c >= '0' && c <= '9') {
return (int (c - '0'));
} else if (c >= 'a' && c <= 'f') {
return (int (c - 'f') + 10);
} else {
return -1;
}
}
std::string NetlistSpiceReader::read_name (tl::Extractor &ex)
{
std::string n;
ex.read_word_or_quoted (n, allowed_name_chars);
std::string nn;
nn.reserve (n.size ());
const char *cp = n.c_str ();
while (*cp) {
if (*cp == '\\' && cp[1]) {
if (tolower (cp[1]) == 'x') {
cp += 2;
char c = 0;
for (int i = 0; i < 2 && *cp; ++i) {
int n = hex_num (*cp);
if (n >= 0) {
++cp;
c = c * 16 + char (n);
} else {
break;
}
}
nn += c;
} else {
++cp;
nn += *cp++;
}
} else {
nn += *cp++;
}
}
return nn;
}
void NetlistSpiceReader::read_subcircuit (tl::Extractor &ex)
{
std::string sc_name = read_name (ex);
std::vector<std::string> nn;
std::map<std::string, double> pv;
read_pin_and_parameters (ex, nn, pv);
if (nn.empty ()) {
error (tl::to_string (tr ("No circuit name given for subcircuit call")));
@ -461,25 +529,11 @@ void NetlistSpiceReader::read_subcircuit (tl::Extractor &ex)
void NetlistSpiceReader::read_circuit (tl::Extractor &ex)
{
std::string nc;
ex.read_word_or_quoted (nc, allowed_name_chars);
std::string nc = read_name (ex);
std::vector<std::string> nn;
std::map<std::string, double> pv;
while (! ex.at_end ()) {
std::string n;
ex.read_word_or_quoted (n, allowed_name_chars);
if (ex.test ("=")) {
// a parameter
pv.insert (std::make_pair (tl::to_upper_case (n), read_value (ex)));
} else {
nn.push_back (n);
}
}
read_pin_and_parameters (ex, nn, pv);
if (! pv.empty ()) {
warn (tl::to_string (tr ("Circuit parameters are not allowed currently")));
@ -523,14 +577,12 @@ void NetlistSpiceReader::read_circuit (tl::Extractor &ex)
void NetlistSpiceReader::read_device (db::DeviceClass *dev_cls, size_t param_id, tl::Extractor &ex)
{
std::string dn;
ex.read_word_or_quoted (dn, allowed_name_chars);
std::string dn = read_name (ex);
std::vector<std::string> nn;
while (! ex.at_end () && nn.size () < 2) {
nn.push_back (std::string ());
ex.read_word_or_quoted (nn.back (), allowed_name_chars);
nn.push_back (read_name (ex));
}
if (nn.size () != 2) {
@ -554,16 +606,14 @@ void NetlistSpiceReader::read_device (db::DeviceClass *dev_cls, size_t param_id,
void NetlistSpiceReader::read_mos4_device (tl::Extractor &ex)
{
std::string dn;
ex.read_word_or_quoted (dn, allowed_name_chars);
std::string dn = read_name (ex);
std::vector<std::string> nn;
std::map<std::string, double> pv;
while (! ex.at_end ()) {
std::string n;
ex.read_word_or_quoted (n, allowed_name_chars);
std::string n = read_name (ex);
if (ex.test ("=")) {
// a parameter

View File

@ -61,12 +61,14 @@ private:
void push_stream (const std::string &path);
void pop_stream ();
bool at_end ();
void read_pin_and_parameters (tl::Extractor &ex, std::vector<std::string> &nn, std::map<std::string, double> &pv);
void read_subcircuit (tl::Extractor &ex);
void read_circuit (tl::Extractor &ex);
void read_device (db::DeviceClass *dev_cls, size_t param_id, tl::Extractor &ex);
void read_mos4_device (tl::Extractor &ex);
bool read_element ();
double read_value (tl::Extractor &ex);
std::string read_name (tl::Extractor &ex);
double read_atomic_value (tl::Extractor &ex);
double read_dot_expr (tl::Extractor &ex);
double read_bar_expr (tl::Extractor &ex);

View File

@ -152,3 +152,29 @@ TEST(4_ReaderWithUnconnectedPins)
"end;\n"
);
}
TEST(5_CircuitParameters)
{
db::Netlist nl;
std::string path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nreader5.cir");
db::NetlistSpiceReader reader;
tl::InputStream is (path);
reader.read (is, nl);
EXPECT_EQ (nl.to_string (),
"circuit SUBCKT ($1=$1,$2=A,$3='V42(%)',$4=Z,$5=gnd,$6=gnd$1);\n"
" subcircuit HVPMOS D_$1 ($1='V42(%)',$2=$3,$3=Z,$4=$1);\n"
" subcircuit HVPMOS D_$2 ($1='V42(%)',$2=A,$3=$3,$4=$1);\n"
" subcircuit HVNMOS D_$3 ($1=gnd,$2=$3,$3=gnd,$4=gnd$1);\n"
" subcircuit HVNMOS D_$4 ($1=gnd,$2=$3,$3=Z,$4=gnd$1);\n"
" subcircuit HVNMOS D_$5 ($1=gnd,$2=A,$3=$3,$4=gnd$1);\n"
"end;\n"
"circuit HVPMOS ($1=(null),$2=(null),$3=(null),$4=(null));\n"
"end;\n"
"circuit HVNMOS ($1=(null),$2=(null),$3=(null),$4=(null));\n"
"end;\n"
);
}

23
testdata/algo/nreader5.cir vendored Normal file
View File

@ -0,0 +1,23 @@
* written by unit test
* cell SUBCKT
* pin
* pin A
* pin V42
* pin Z
* pin gnd
* pin gnd
.SUBCKT SUBCKT \$1 A V42\x28\x25\x29 Z gnd gnd$1
* device instance $1 r0 *1 0,0 HVPMOS
XD_$1 V42\x28\x25\x29 \$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\x28\x25\x29 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

View File

@ -9,7 +9,7 @@
* pin gnd
.SUBCKT SUBCKT 1 2 4 5 6 7
* net 2 A
* net 4 V42
* net 4 V42(%)
* net 5 Z
* net 6 gnd
* net 7 gnd

View File

@ -7,11 +7,13 @@
* pin Z
* pin gnd
* pin gnd
.SUBCKT SUBCKT \$1 A V42 Z gnd gnd$1
.SUBCKT SUBCKT \$1 A V42\x28\x25\x29 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
XD_$1 V42\x28\x25\x29 \$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
XD_$2 V42\x28\x25\x29 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

View File

@ -28,7 +28,7 @@ X(SUBCKT
)
N(3
)
N(4 I(V42)
N(4 I('V42(%)')
)
N(5 I(Z)
)