diff --git a/src/db/db/dbNetlistSpiceReader.cc b/src/db/db/dbNetlistSpiceReader.cc index 7da814a50..28128ab63 100644 --- a/src/db/db/dbNetlistSpiceReader.cc +++ b/src/db/db/dbNetlistSpiceReader.cc @@ -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 &nn, std::map &pv) { - std::string sc_name; - ex.read_word_or_quoted (sc_name, allowed_name_chars); - - std::vector nn; - std::map 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 nn; + std::map 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 nn; std::map 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 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 nn; std::map 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 diff --git a/src/db/db/dbNetlistSpiceReader.h b/src/db/db/dbNetlistSpiceReader.h index 73185fad6..cd0ce274e 100644 --- a/src/db/db/dbNetlistSpiceReader.h +++ b/src/db/db/dbNetlistSpiceReader.h @@ -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 &nn, std::map &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); diff --git a/src/db/unit_tests/dbNetlistReaderTests.cc b/src/db/unit_tests/dbNetlistReaderTests.cc index a7fc9f069..d48d0cf85 100644 --- a/src/db/unit_tests/dbNetlistReaderTests.cc +++ b/src/db/unit_tests/dbNetlistReaderTests.cc @@ -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" + ); +} + diff --git a/testdata/algo/nreader5.cir b/testdata/algo/nreader5.cir new file mode 100644 index 000000000..3d020b0bd --- /dev/null +++ b/testdata/algo/nreader5.cir @@ -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 diff --git a/testdata/algo/nwriter12_au.txt b/testdata/algo/nwriter12_au.txt index ab467a1dc..9e984e400 100644 --- a/testdata/algo/nwriter12_au.txt +++ b/testdata/algo/nwriter12_au.txt @@ -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 diff --git a/testdata/algo/nwriter12b_au.txt b/testdata/algo/nwriter12b_au.txt index 69036b585..3d020b0bd 100644 --- a/testdata/algo/nwriter12b_au.txt +++ b/testdata/algo/nwriter12b_au.txt @@ -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 diff --git a/testdata/algo/same_net_names.l2n b/testdata/algo/same_net_names.l2n index 4ad796f7f..3e88d38bf 100644 --- a/testdata/algo/same_net_names.l2n +++ b/testdata/algo/same_net_names.l2n @@ -28,7 +28,7 @@ X(SUBCKT ) N(3 ) - N(4 I(V42) + N(4 I('V42(%)') ) N(5 I(Z) )