mirror of https://github.com/KLayout/klayout.git
Unescaping of net names on Spice reader -> writer/reader should be self-compatible.
This commit is contained in:
parent
985cffc099
commit
7d6237a90a
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ X(SUBCKT
|
|||
)
|
||||
N(3
|
||||
)
|
||||
N(4 I(V42)
|
||||
N(4 I('V42(%)')
|
||||
)
|
||||
N(5 I(Z)
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue