mirror of https://github.com/KLayout/klayout.git
Merge pull request #800 from KLayout/issue-798
Issue 798 (Spice reader enhancements for 3-terminal R and C)
This commit is contained in:
commit
1a2054b484
|
|
@ -40,6 +40,62 @@ namespace db
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static const char *allowed_name_chars = "_.:,!+$/&\\#[]|<>";
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string unescape_name (const std::string &n)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
NetlistSpiceReaderDelegate::NetlistSpiceReaderDelegate ()
|
NetlistSpiceReaderDelegate::NetlistSpiceReaderDelegate ()
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
|
|
@ -60,11 +116,21 @@ void NetlistSpiceReaderDelegate::finish (db::Netlist * /*netlist*/)
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NetlistSpiceReaderDelegate::control_statement(const std::string & /*line*/)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool NetlistSpiceReaderDelegate::wants_subcircuit (const std::string & /*circuit_name*/)
|
bool NetlistSpiceReaderDelegate::wants_subcircuit (const std::string & /*circuit_name*/)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string NetlistSpiceReaderDelegate::translate_net_name (const std::string &nn)
|
||||||
|
{
|
||||||
|
return unescape_name (nn);
|
||||||
|
}
|
||||||
|
|
||||||
void NetlistSpiceReaderDelegate::error (const std::string &msg)
|
void NetlistSpiceReaderDelegate::error (const std::string &msg)
|
||||||
{
|
{
|
||||||
throw tl::Exception (msg);
|
throw tl::Exception (msg);
|
||||||
|
|
@ -87,6 +153,270 @@ static db::DeviceClass *make_device_class (db::Circuit *circuit, const std::stri
|
||||||
return cls;
|
return cls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string parse_component (tl::Extractor &ex)
|
||||||
|
{
|
||||||
|
const char *cp = ex.skip ();
|
||||||
|
const char *cp0 = cp;
|
||||||
|
|
||||||
|
char quote = 0;
|
||||||
|
unsigned int brackets = 0;
|
||||||
|
|
||||||
|
while (*cp) {
|
||||||
|
if (quote) {
|
||||||
|
if (*cp == quote) {
|
||||||
|
quote = 0;
|
||||||
|
} else if (*cp == '\\' && cp[1]) {
|
||||||
|
++cp;
|
||||||
|
}
|
||||||
|
} else if ((isspace (*cp) || *cp == '=') && ! brackets) {
|
||||||
|
break;
|
||||||
|
} else if (*cp == '"' || *cp == '\'') {
|
||||||
|
quote = *cp;
|
||||||
|
} else if (*cp == '(') {
|
||||||
|
++brackets;
|
||||||
|
} else if (*cp == ')') {
|
||||||
|
if (brackets > 0) {
|
||||||
|
--brackets;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
ex = tl::Extractor (cp);
|
||||||
|
return std::string (cp0, cp - cp0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetlistSpiceReaderDelegate::parse_element_components (const std::string &s, std::vector<std::string> &strings, std::map<std::string, double> &pv)
|
||||||
|
{
|
||||||
|
tl::Extractor ex (s.c_str ());
|
||||||
|
bool in_params = false;
|
||||||
|
|
||||||
|
while (! ex.at_end ()) {
|
||||||
|
|
||||||
|
if (ex.test_without_case ("params:")) {
|
||||||
|
|
||||||
|
in_params = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
tl::Extractor ex0 = ex;
|
||||||
|
std::string n;
|
||||||
|
|
||||||
|
if (ex.try_read_word (n) && ex.test ("=")) {
|
||||||
|
// a parameter. Note that parameter names are always made upper case.
|
||||||
|
pv.insert (std::make_pair (tl::to_upper_case (n), read_value (ex)));
|
||||||
|
} else {
|
||||||
|
ex = ex0;
|
||||||
|
if (in_params) {
|
||||||
|
ex.error (tl::to_string (tr ("Invalid syntax for parameter assignment - needs keyword followed by '='")));
|
||||||
|
}
|
||||||
|
strings.push_back (parse_component (ex));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double NetlistSpiceReaderDelegate::read_atomic_value (tl::Extractor &ex)
|
||||||
|
{
|
||||||
|
if (ex.test ("(")) {
|
||||||
|
|
||||||
|
double v = read_dot_expr (ex);
|
||||||
|
ex.expect (")");
|
||||||
|
return v;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
double v = 0.0;
|
||||||
|
ex.read (v);
|
||||||
|
|
||||||
|
double f = 1.0;
|
||||||
|
if (*ex == 't' || *ex == 'T') {
|
||||||
|
f = 1e12;
|
||||||
|
} else if (*ex == 'g' || *ex == 'G') {
|
||||||
|
f = 1e9;
|
||||||
|
} else if (*ex == 'k' || *ex == 'K') {
|
||||||
|
f = 1e3;
|
||||||
|
} else if (*ex == 'm' || *ex == 'M') {
|
||||||
|
f = 1e-3;
|
||||||
|
if (ex.test_without_case ("meg")) {
|
||||||
|
f = 1e6;
|
||||||
|
}
|
||||||
|
} else if (*ex == 'u' || *ex == 'U') {
|
||||||
|
f = 1e-6;
|
||||||
|
} else if (*ex == 'n' || *ex == 'N') {
|
||||||
|
f = 1e-9;
|
||||||
|
} else if (*ex == 'p' || *ex == 'P') {
|
||||||
|
f = 1e-12;
|
||||||
|
} else if (*ex == 'f' || *ex == 'F') {
|
||||||
|
f = 1e-15;
|
||||||
|
} else if (*ex == 'a' || *ex == 'A') {
|
||||||
|
f = 1e-18;
|
||||||
|
}
|
||||||
|
while (*ex && isalpha (*ex)) {
|
||||||
|
++ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
v *= f;
|
||||||
|
return v;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double NetlistSpiceReaderDelegate::read_bar_expr (tl::Extractor &ex)
|
||||||
|
{
|
||||||
|
double v = read_atomic_value (ex);
|
||||||
|
while (true) {
|
||||||
|
if (ex.test ("+")) {
|
||||||
|
double vv = read_atomic_value (ex);
|
||||||
|
v += vv;
|
||||||
|
} else if (ex.test ("+")) {
|
||||||
|
double vv = read_atomic_value (ex);
|
||||||
|
v -= vv;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
double NetlistSpiceReaderDelegate::read_dot_expr (tl::Extractor &ex)
|
||||||
|
{
|
||||||
|
double v = read_bar_expr (ex);
|
||||||
|
while (true) {
|
||||||
|
if (ex.test ("*")) {
|
||||||
|
double vv = read_bar_expr (ex);
|
||||||
|
v *= vv;
|
||||||
|
} else if (ex.test ("/")) {
|
||||||
|
double vv = read_bar_expr (ex);
|
||||||
|
v /= vv;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
double NetlistSpiceReaderDelegate::read_value (tl::Extractor &ex)
|
||||||
|
{
|
||||||
|
return read_dot_expr (ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NetlistSpiceReaderDelegate::try_read_value (const std::string &s, double &value)
|
||||||
|
{
|
||||||
|
tl::Extractor ve (s.c_str ());
|
||||||
|
double vv = 0;
|
||||||
|
if (ve.try_read (vv) || ve.test ("(")) {
|
||||||
|
ve = tl::Extractor (s.c_str ());
|
||||||
|
value = read_value (ve);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetlistSpiceReaderDelegate::parse_element (const std::string &s, const std::string &element, std::string &model, double &value, std::vector<std::string> &nn, std::map<std::string, double> &pv)
|
||||||
|
{
|
||||||
|
parse_element_components (s, nn, pv);
|
||||||
|
|
||||||
|
// interpret the parameters according to the code
|
||||||
|
if (element == "X") {
|
||||||
|
|
||||||
|
// subcircuit call:
|
||||||
|
// Xname n1 n2 ... nn circuit [params]
|
||||||
|
|
||||||
|
if (nn.empty ()) {
|
||||||
|
error (tl::to_string (tr ("No circuit name given for subcircuit call")));
|
||||||
|
}
|
||||||
|
|
||||||
|
model = nn.back ();
|
||||||
|
nn.pop_back ();
|
||||||
|
|
||||||
|
} else if (element == "R" || element == "C" || element == "L") {
|
||||||
|
|
||||||
|
// resistor, cap, inductor: two-terminal devices with a value
|
||||||
|
// Rname n1 n2 value
|
||||||
|
// Rname n1 n2 n3 value
|
||||||
|
// Rname n1 n2 value model [params]
|
||||||
|
// Rname n1 n2 n3 value model [params]
|
||||||
|
// Rname n1 n2 [params]
|
||||||
|
// Rname n1 n2 model [params]
|
||||||
|
// Rname n1 n2 n3 model [params]
|
||||||
|
// NOTE: there is no "Rname n1 n2 n3 [params]"!
|
||||||
|
// (same for C, L instead of R)
|
||||||
|
|
||||||
|
if (nn.size () < 2) {
|
||||||
|
error (tl::to_string (tr ("Not enough specs for a R, C or L device")));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, double>::const_iterator rv = pv.find (element);
|
||||||
|
if (rv != pv.end ()) {
|
||||||
|
|
||||||
|
// value given by parameter
|
||||||
|
value = rv->second;
|
||||||
|
|
||||||
|
if (nn.size () >= 3) {
|
||||||
|
// Rname n1 n2 model [params]
|
||||||
|
// Rname n1 n2 n3 model [params]
|
||||||
|
model = nn.back ();
|
||||||
|
nn.pop_back ();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (nn.size () >= 3) {
|
||||||
|
|
||||||
|
if (try_read_value (nn.back (), value)) {
|
||||||
|
|
||||||
|
// Rname n1 n2 value
|
||||||
|
// Rname n1 n2 n3 value
|
||||||
|
nn.pop_back ();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Rname n1 n2 value model [params]
|
||||||
|
// Rname n1 n2 n3 value model [params]
|
||||||
|
model = nn.back ();
|
||||||
|
nn.pop_back ();
|
||||||
|
if (! try_read_value (nn.back (), value)) {
|
||||||
|
error (tl::to_string (tr ("Can't find a value for a R, C or L device")));
|
||||||
|
} else {
|
||||||
|
nn.pop_back ();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// others: n-terminal devices with a model (last node)
|
||||||
|
|
||||||
|
if (nn.empty ()) {
|
||||||
|
error (tl::sprintf (tl::to_string (tr ("No model name given for element '%s'")), element));
|
||||||
|
}
|
||||||
|
|
||||||
|
model = nn.back ();
|
||||||
|
nn.pop_back ();
|
||||||
|
|
||||||
|
if (element == "M") {
|
||||||
|
if (nn.size () != 4) {
|
||||||
|
error (tl::to_string (tr ("'M' element must have four nodes")));
|
||||||
|
}
|
||||||
|
} else if (element == "Q") {
|
||||||
|
if (nn.size () != 3 && nn.size () != 4) {
|
||||||
|
error (tl::to_string (tr ("'Q' element must have three or four nodes")));
|
||||||
|
}
|
||||||
|
} else if (element == "D") {
|
||||||
|
if (nn.size () != 2) {
|
||||||
|
error (tl::to_string (tr ("'D' element must have two nodes")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: other devices?
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::string &element, const std::string &name, const std::string &model, double value, const std::vector<db::Net *> &nets, const std::map<std::string, double> &pv)
|
bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::string &element, const std::string &name, const std::string &model, double value, const std::vector<db::Net *> &nets, const std::map<std::string, double> &pv)
|
||||||
{
|
{
|
||||||
std::map<std::string, double> params = pv;
|
std::map<std::string, double> params = pv;
|
||||||
|
|
@ -106,9 +436,10 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
||||||
|
|
||||||
if (element == "R") {
|
if (element == "R") {
|
||||||
|
|
||||||
|
if (nets.size () == 2) {
|
||||||
if (cls) {
|
if (cls) {
|
||||||
if (! dynamic_cast<db::DeviceClassResistor *>(cls)) {
|
if (! dynamic_cast<db::DeviceClassResistor *>(cls)) {
|
||||||
error (tl::sprintf (tl::to_string (tr ("Class %s not a resistor device class as required by 'R' element")), cn));
|
error (tl::sprintf (tl::to_string (tr ("Class %s is not a resistor device class as required by 'R' element")), cn));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (cn.empty ()) {
|
if (cn.empty ()) {
|
||||||
|
|
@ -116,15 +447,30 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
||||||
}
|
}
|
||||||
cls = make_device_class<db::DeviceClassResistor> (circuit, cn);
|
cls = make_device_class<db::DeviceClassResistor> (circuit, cn);
|
||||||
}
|
}
|
||||||
|
} else if (nets.size () == 3) {
|
||||||
|
if (cls) {
|
||||||
|
if (! dynamic_cast<db::DeviceClassResistorWithBulk *>(cls)) {
|
||||||
|
error (tl::sprintf (tl::to_string (tr ("Class %s is not a three-terminal resistor device class as required by 'R' element")), cn));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cn.empty ()) {
|
||||||
|
cn = "RES3";
|
||||||
|
}
|
||||||
|
cls = make_device_class<db::DeviceClassResistorWithBulk> (circuit, cn);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error (tl::to_string (tr ("A 'R' element requires two or three nets")));
|
||||||
|
}
|
||||||
|
|
||||||
// Apply multiplier
|
// Apply multiplier
|
||||||
value /= mult;
|
value /= mult;
|
||||||
|
|
||||||
} else if (element == "L") {
|
} else if (element == "L") {
|
||||||
|
|
||||||
|
if (nets.size () == 2) {
|
||||||
if (cls) {
|
if (cls) {
|
||||||
if (! dynamic_cast<db::DeviceClassInductor *>(cls)) {
|
if (! dynamic_cast<db::DeviceClassInductor *>(cls)) {
|
||||||
error (tl::sprintf (tl::to_string (tr ("Class %s not a inductor device class as required by 'L' element")), cn));
|
error (tl::sprintf (tl::to_string (tr ("Class %s is not a inductor device class as required by 'L' element")), cn));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (cn.empty ()) {
|
if (cn.empty ()) {
|
||||||
|
|
@ -132,15 +478,19 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
||||||
}
|
}
|
||||||
cls = make_device_class<db::DeviceClassInductor> (circuit, cn);
|
cls = make_device_class<db::DeviceClassInductor> (circuit, cn);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
error (tl::to_string (tr ("A 'L' element requires two nets")));
|
||||||
|
}
|
||||||
|
|
||||||
// Apply multiplier
|
// Apply multiplier
|
||||||
value /= mult;
|
value /= mult;
|
||||||
|
|
||||||
} else if (element == "C") {
|
} else if (element == "C") {
|
||||||
|
|
||||||
|
if (nets.size () == 2) {
|
||||||
if (cls) {
|
if (cls) {
|
||||||
if (! dynamic_cast<db::DeviceClassCapacitor *>(cls)) {
|
if (! dynamic_cast<db::DeviceClassCapacitor *>(cls)) {
|
||||||
error (tl::sprintf (tl::to_string (tr ("Class %s not a capacitor device class as required by 'C' element")), cn));
|
error (tl::sprintf (tl::to_string (tr ("Class %s is not a capacitor device class as required by 'C' element")), cn));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (cn.empty ()) {
|
if (cn.empty ()) {
|
||||||
|
|
@ -148,6 +498,20 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
||||||
}
|
}
|
||||||
cls = make_device_class<db::DeviceClassCapacitor> (circuit, cn);
|
cls = make_device_class<db::DeviceClassCapacitor> (circuit, cn);
|
||||||
}
|
}
|
||||||
|
} else if (nets.size () == 3) {
|
||||||
|
if (cls) {
|
||||||
|
if (! dynamic_cast<db::DeviceClassCapacitorWithBulk *>(cls)) {
|
||||||
|
error (tl::sprintf (tl::to_string (tr ("Class %s is not a three-terminal capacitor device class as required by 'C' element")), cn));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cn.empty ()) {
|
||||||
|
cn = "CAP3";
|
||||||
|
}
|
||||||
|
cls = make_device_class<db::DeviceClassCapacitorWithBulk> (circuit, cn);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error (tl::to_string (tr ("A 'C' element requires two or three nets")));
|
||||||
|
}
|
||||||
|
|
||||||
// Apply multiplier
|
// Apply multiplier
|
||||||
value *= mult;
|
value *= mult;
|
||||||
|
|
@ -156,7 +520,7 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
||||||
|
|
||||||
if (cls) {
|
if (cls) {
|
||||||
if (! dynamic_cast<db::DeviceClassDiode *>(cls)) {
|
if (! dynamic_cast<db::DeviceClassDiode *>(cls)) {
|
||||||
error (tl::sprintf (tl::to_string (tr ("Class %s not a diode device class as required by 'D' element")), cn));
|
error (tl::sprintf (tl::to_string (tr ("Class %s is not a diode device class as required by 'D' element")), cn));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (cn.empty ()) {
|
if (cn.empty ()) {
|
||||||
|
|
@ -179,11 +543,11 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
||||||
} else if (cls) {
|
} else if (cls) {
|
||||||
if (nets.size () == 3) {
|
if (nets.size () == 3) {
|
||||||
if (! dynamic_cast<db::DeviceClassBJT3Transistor *>(cls)) {
|
if (! dynamic_cast<db::DeviceClassBJT3Transistor *>(cls)) {
|
||||||
error (tl::sprintf (tl::to_string (tr ("Class %s not a 3-terminal BJT device class as required by 'Q' element")), cn));
|
error (tl::sprintf (tl::to_string (tr ("Class %s is not a 3-terminal BJT device class as required by 'Q' element")), cn));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (! dynamic_cast<db::DeviceClassBJT4Transistor *>(cls)) {
|
if (! dynamic_cast<db::DeviceClassBJT4Transistor *>(cls)) {
|
||||||
error (tl::sprintf (tl::to_string (tr ("Class %s not a 4-terminal BJT device class as required by 'Q' element")), cn));
|
error (tl::sprintf (tl::to_string (tr ("Class %s is not a 4-terminal BJT device class as required by 'Q' element")), cn));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -211,7 +575,7 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
||||||
|
|
||||||
if (cls) {
|
if (cls) {
|
||||||
if (! dynamic_cast<db::DeviceClassMOS4Transistor *>(cls)) {
|
if (! dynamic_cast<db::DeviceClassMOS4Transistor *>(cls)) {
|
||||||
error (tl::sprintf (tl::to_string (tr ("Class %s not a 4-terminal MOS device class as required by 'M' element")), cn));
|
error (tl::sprintf (tl::to_string (tr ("Class %s is not a 4-terminal MOS device class as required by 'M' element")), cn));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (nets.size () == 4) {
|
if (nets.size () == 4) {
|
||||||
|
|
@ -271,8 +635,6 @@ bool NetlistSpiceReaderDelegate::element (db::Circuit *circuit, const std::strin
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
static const char *allowed_name_chars = "_.:,!+$/&\\#[]|<>";
|
|
||||||
|
|
||||||
NetlistSpiceReader::NetlistSpiceReader (NetlistSpiceReaderDelegate *delegate)
|
NetlistSpiceReader::NetlistSpiceReader (NetlistSpiceReaderDelegate *delegate)
|
||||||
: mp_netlist (0), mp_stream (), mp_delegate (delegate)
|
: mp_netlist (0), mp_stream (), mp_delegate (delegate)
|
||||||
{
|
{
|
||||||
|
|
@ -450,7 +812,8 @@ std::string NetlistSpiceReader::get_line ()
|
||||||
tl::Extractor ex (l.c_str ());
|
tl::Extractor ex (l.c_str ());
|
||||||
if (ex.test_without_case (".include") || ex.test_without_case (".inc")) {
|
if (ex.test_without_case (".include") || ex.test_without_case (".inc")) {
|
||||||
|
|
||||||
std::string path = read_name_with_case (ex);
|
std::string path;
|
||||||
|
ex.read_word_or_quoted (path, allowed_name_chars);
|
||||||
|
|
||||||
push_stream (path);
|
push_stream (path);
|
||||||
|
|
||||||
|
|
@ -504,7 +867,7 @@ bool NetlistSpiceReader::read_card ()
|
||||||
} else if (ex.test_without_case ("global")) {
|
} else if (ex.test_without_case ("global")) {
|
||||||
|
|
||||||
while (! ex.at_end ()) {
|
while (! ex.at_end ()) {
|
||||||
std::string n = read_name (ex);
|
std::string n = mp_delegate->translate_net_name (read_name (ex));
|
||||||
if (m_global_net_names.find (n) == m_global_net_names.end ()) {
|
if (m_global_net_names.find (n) == m_global_net_names.end ()) {
|
||||||
m_global_nets.push_back (n);
|
m_global_nets.push_back (n);
|
||||||
m_global_net_names.insert (n);
|
m_global_net_names.insert (n);
|
||||||
|
|
@ -528,7 +891,7 @@ bool NetlistSpiceReader::read_card ()
|
||||||
|
|
||||||
// ignore end statements
|
// ignore end statements
|
||||||
|
|
||||||
} else {
|
} else if (! mp_delegate->control_statement (l)) {
|
||||||
|
|
||||||
std::string s;
|
std::string s;
|
||||||
ex.read_word (s);
|
ex.read_word (s);
|
||||||
|
|
@ -551,8 +914,6 @@ bool NetlistSpiceReader::read_card ()
|
||||||
warn (tl::sprintf (tl::to_string (tr ("Element type '%c' ignored")), next_char));
|
warn (tl::sprintf (tl::to_string (tr ("Element type '%c' ignored")), next_char));
|
||||||
}
|
}
|
||||||
|
|
||||||
ex.expect_end ();
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
warn (tl::to_string (tr ("Line ignored")));
|
warn (tl::to_string (tr ("Line ignored")));
|
||||||
}
|
}
|
||||||
|
|
@ -571,91 +932,6 @@ void NetlistSpiceReader::warn (const std::string &msg)
|
||||||
tl::warn << fmt_msg;
|
tl::warn << fmt_msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
double NetlistSpiceReader::read_atomic_value (tl::Extractor &ex)
|
|
||||||
{
|
|
||||||
if (ex.test ("(")) {
|
|
||||||
|
|
||||||
double v = read_dot_expr (ex);
|
|
||||||
ex.expect (")");
|
|
||||||
return v;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
double v = 0.0;
|
|
||||||
ex.read (v);
|
|
||||||
|
|
||||||
double f = 1.0;
|
|
||||||
if (*ex == 't' || *ex == 'T') {
|
|
||||||
f = 1e12;
|
|
||||||
} else if (*ex == 'g' || *ex == 'G') {
|
|
||||||
f = 1e9;
|
|
||||||
} else if (*ex == 'k' || *ex == 'K') {
|
|
||||||
f = 1e3;
|
|
||||||
} else if (*ex == 'm' || *ex == 'M') {
|
|
||||||
f = 1e-3;
|
|
||||||
if (ex.test_without_case ("meg")) {
|
|
||||||
f = 1e6;
|
|
||||||
}
|
|
||||||
} else if (*ex == 'u' || *ex == 'U') {
|
|
||||||
f = 1e-6;
|
|
||||||
} else if (*ex == 'n' || *ex == 'N') {
|
|
||||||
f = 1e-9;
|
|
||||||
} else if (*ex == 'p' || *ex == 'P') {
|
|
||||||
f = 1e-12;
|
|
||||||
} else if (*ex == 'f' || *ex == 'F') {
|
|
||||||
f = 1e-15;
|
|
||||||
} else if (*ex == 'a' || *ex == 'A') {
|
|
||||||
f = 1e-18;
|
|
||||||
}
|
|
||||||
while (*ex && isalpha (*ex)) {
|
|
||||||
++ex;
|
|
||||||
}
|
|
||||||
|
|
||||||
v *= f;
|
|
||||||
return v;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double NetlistSpiceReader::read_bar_expr (tl::Extractor &ex)
|
|
||||||
{
|
|
||||||
double v = read_atomic_value (ex);
|
|
||||||
while (true) {
|
|
||||||
if (ex.test ("+")) {
|
|
||||||
double vv = read_atomic_value (ex);
|
|
||||||
v += vv;
|
|
||||||
} else if (ex.test ("+")) {
|
|
||||||
double vv = read_atomic_value (ex);
|
|
||||||
v -= vv;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
double NetlistSpiceReader::read_dot_expr (tl::Extractor &ex)
|
|
||||||
{
|
|
||||||
double v = read_atomic_value (ex);
|
|
||||||
while (true) {
|
|
||||||
if (ex.test ("*")) {
|
|
||||||
double vv = read_atomic_value (ex);
|
|
||||||
v *= vv;
|
|
||||||
} else if (ex.test ("/")) {
|
|
||||||
double vv = read_atomic_value (ex);
|
|
||||||
v /= vv;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
double NetlistSpiceReader::read_value (tl::Extractor &ex)
|
|
||||||
{
|
|
||||||
return read_dot_expr (ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NetlistSpiceReader::ensure_circuit ()
|
void NetlistSpiceReader::ensure_circuit ()
|
||||||
{
|
{
|
||||||
if (! mp_circuit) {
|
if (! mp_circuit) {
|
||||||
|
|
@ -693,92 +969,11 @@ db::Net *NetlistSpiceReader::make_net (const std::string &name)
|
||||||
return net;
|
return net;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetlistSpiceReader::read_pin_and_parameters (tl::Extractor &ex, std::vector<std::string> &nn, std::map<std::string, double> &pv)
|
std::string NetlistSpiceReader::read_name (tl::Extractor &ex)
|
||||||
{
|
|
||||||
bool in_params = false;
|
|
||||||
|
|
||||||
while (! ex.at_end ()) {
|
|
||||||
|
|
||||||
if (ex.test_without_case ("params:")) {
|
|
||||||
|
|
||||||
in_params = true;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
std::string n = read_name (ex);
|
|
||||||
|
|
||||||
if (ex.test ("=")) {
|
|
||||||
// a parameter
|
|
||||||
pv.insert (std::make_pair (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_with_case (tl::Extractor &ex)
|
|
||||||
{
|
{
|
||||||
std::string n;
|
std::string n;
|
||||||
ex.read_word_or_quoted (n, allowed_name_chars);
|
ex.read_word_or_quoted (n, allowed_name_chars);
|
||||||
|
return mp_netlist->normalize_name (n);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string NetlistSpiceReader::read_name (tl::Extractor &ex)
|
|
||||||
{
|
|
||||||
return mp_netlist->normalize_name (read_name_with_case (ex));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NetlistSpiceReader::read_element (tl::Extractor &ex, const std::string &element, const std::string &name)
|
bool NetlistSpiceReader::read_element (tl::Extractor &ex, const std::string &element, const std::string &name)
|
||||||
|
|
@ -786,99 +981,16 @@ bool NetlistSpiceReader::read_element (tl::Extractor &ex, const std::string &ele
|
||||||
// generic parse
|
// generic parse
|
||||||
std::vector<std::string> nn;
|
std::vector<std::string> nn;
|
||||||
std::map<std::string, double> pv;
|
std::map<std::string, double> pv;
|
||||||
|
|
||||||
std::string model;
|
std::string model;
|
||||||
double value = 0.0;
|
double value = 0.0;
|
||||||
|
|
||||||
// interpret the parameters according to the code
|
mp_delegate->parse_element (ex.skip (), element, model, value, nn, pv);
|
||||||
if (element == "X") {
|
|
||||||
|
|
||||||
// subcircuit call:
|
model = mp_netlist->normalize_name (model);
|
||||||
// Xname n1 n2 ... nn circuit [params]
|
|
||||||
|
|
||||||
read_pin_and_parameters (ex, nn, pv);
|
|
||||||
|
|
||||||
if (nn.empty ()) {
|
|
||||||
error (tl::to_string (tr ("No circuit name given for subcircuit call")));
|
|
||||||
}
|
|
||||||
|
|
||||||
model = nn.back ();
|
|
||||||
nn.pop_back ();
|
|
||||||
|
|
||||||
} else if (element == "R" || element == "C" || element == "L") {
|
|
||||||
|
|
||||||
// resistor, cap, inductor: two-terminal devices with a value
|
|
||||||
// Rname n1 n2 value
|
|
||||||
// Rname n1 n2 value model [params]
|
|
||||||
// Rname n1 n2 model [params]
|
|
||||||
// (same for C, L instead of R)
|
|
||||||
|
|
||||||
while (! ex.at_end () && nn.size () < 2) {
|
|
||||||
nn.push_back (read_name (ex));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nn.size () != 2) {
|
|
||||||
error (tl::to_string (tr ("Two-terminal device needs two nets")));
|
|
||||||
}
|
|
||||||
|
|
||||||
tl::Extractor ve (ex);
|
|
||||||
double vv = 0.0;
|
|
||||||
if (ve.try_read (vv) || ve.test ("(")) {
|
|
||||||
value = read_value (ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (! ex.at_end ()) {
|
|
||||||
std::string n = read_name (ex);
|
|
||||||
if (ex.test ("=")) {
|
|
||||||
pv [n] = read_value (ex);
|
|
||||||
} else if (! model.empty ()) {
|
|
||||||
error (tl::sprintf (tl::to_string (tr ("Too many arguments for two-terminal device (additional argumen is '%s')")), n));
|
|
||||||
} else {
|
|
||||||
model = n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// others: n-terminal devices with a model (last node)
|
|
||||||
|
|
||||||
while (! ex.at_end ()) {
|
|
||||||
std::string n = read_name (ex);
|
|
||||||
if (ex.test ("=")) {
|
|
||||||
pv [n] = read_value (ex);
|
|
||||||
} else {
|
|
||||||
nn.push_back (n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nn.empty ()) {
|
|
||||||
error (tl::sprintf (tl::to_string (tr ("No model name given for element '%s'")), element));
|
|
||||||
}
|
|
||||||
|
|
||||||
model = nn.back ();
|
|
||||||
nn.pop_back ();
|
|
||||||
|
|
||||||
if (element == "M") {
|
|
||||||
if (nn.size () != 4) {
|
|
||||||
error (tl::to_string (tr ("'M' element must have four nodes")));
|
|
||||||
}
|
|
||||||
} else if (element == "Q") {
|
|
||||||
if (nn.size () != 3 && nn.size () != 4) {
|
|
||||||
error (tl::to_string (tr ("'Q' element must have three or four nodes")));
|
|
||||||
}
|
|
||||||
} else if (element == "D") {
|
|
||||||
if (nn.size () != 2) {
|
|
||||||
error (tl::to_string (tr ("'D' element must have two nodes")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: other devices?
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<db::Net *> nets;
|
std::vector<db::Net *> nets;
|
||||||
for (std::vector<std::string>::const_iterator i = nn.begin (); i != nn.end (); ++i) {
|
for (std::vector<std::string>::const_iterator i = nn.begin (); i != nn.end (); ++i) {
|
||||||
nets.push_back (make_net (*i));
|
nets.push_back (make_net (mp_delegate->translate_net_name (mp_netlist->normalize_name (*i))));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element == "X" && ! subcircuit_captured (model)) {
|
if (element == "X" && ! subcircuit_captured (model)) {
|
||||||
|
|
@ -946,7 +1058,11 @@ void NetlistSpiceReader::read_circuit (tl::Extractor &ex, const std::string &nc)
|
||||||
{
|
{
|
||||||
std::vector<std::string> nn;
|
std::vector<std::string> nn;
|
||||||
std::map<std::string, double> pv;
|
std::map<std::string, double> pv;
|
||||||
read_pin_and_parameters (ex, nn, pv);
|
mp_delegate->parse_element_components (ex.skip (), nn, pv);
|
||||||
|
|
||||||
|
for (std::vector<std::string>::iterator i = nn.begin (); i != nn.end (); ++i) {
|
||||||
|
*i = mp_delegate->translate_net_name (mp_netlist->normalize_name (*i));
|
||||||
|
}
|
||||||
|
|
||||||
if (! pv.empty ()) {
|
if (! pv.empty ()) {
|
||||||
warn (tl::to_string (tr ("Circuit parameters are not allowed currently")));
|
warn (tl::to_string (tr ("Circuit parameters are not allowed currently")));
|
||||||
|
|
@ -999,8 +1115,6 @@ void NetlistSpiceReader::read_circuit (tl::Extractor &ex, const std::string &nc)
|
||||||
|
|
||||||
mp_nets_by_name.reset (n2n.release ());
|
mp_nets_by_name.reset (n2n.release ());
|
||||||
std::swap (cc, mp_circuit);
|
std::swap (cc, mp_circuit);
|
||||||
|
|
||||||
ex.expect_end ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,13 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void finish (db::Netlist *netlist);
|
virtual void finish (db::Netlist *netlist);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called when an unknown control statement is encountered
|
||||||
|
*
|
||||||
|
* Returns true if the statement is understood.
|
||||||
|
*/
|
||||||
|
virtual bool control_statement (const std::string &line);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns true, if the delegate wants subcircuit elements with this name
|
* @brief Returns true, if the delegate wants subcircuit elements with this name
|
||||||
*
|
*
|
||||||
|
|
@ -85,6 +92,13 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual bool wants_subcircuit (const std::string &circuit_name);
|
virtual bool wants_subcircuit (const std::string &circuit_name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This method translates a raw net name to a valid net name
|
||||||
|
*
|
||||||
|
* The default implementation will unescape backslash sequences into plain characters.
|
||||||
|
*/
|
||||||
|
virtual std::string translate_net_name (const std::string &nn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Makes a device from an element line
|
* @brief Makes a device from an element line
|
||||||
*
|
*
|
||||||
|
|
@ -103,10 +117,42 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual bool element (db::Circuit *circuit, const std::string &element, const std::string &name, const std::string &model, double value, const std::vector<db::Net *> &nets, const std::map<std::string, double> ¶ms);
|
virtual bool element (db::Circuit *circuit, const std::string &element, const std::string &name, const std::string &model, double value, const std::vector<db::Net *> &nets, const std::map<std::string, double> ¶ms);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parses an element from a line
|
||||||
|
*
|
||||||
|
* @param s The line to parse (the part after the element and name)
|
||||||
|
* @param model Out parameter: the model name if given
|
||||||
|
* @param value Out parameter: the value if given (for R, L, C)
|
||||||
|
* @param nn Out parameter: the net names
|
||||||
|
* @param pv Out parameter: the parameter values (key/value pairs)
|
||||||
|
*/
|
||||||
|
virtual void parse_element (const std::string &s, const std::string &element, std::string &model, double &value, std::vector<std::string> &nn, std::map<std::string, double> &pv);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Produces an error with the given message
|
* @brief Produces an error with the given message
|
||||||
*/
|
*/
|
||||||
virtual void error (const std::string &msg);
|
virtual void error (const std::string &msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads a set of string components and parameters from the string
|
||||||
|
* A special key "param:" is recognized for starting a parameter list.
|
||||||
|
*/
|
||||||
|
void parse_element_components (const std::string &s, std::vector<std::string> &strings, std::map<std::string, double> &pv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads a value from the extractor (with formula evaluation)
|
||||||
|
*/
|
||||||
|
double read_value (tl::Extractor &ex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tries to read a value from the extractor (with formula evaluation)
|
||||||
|
*/
|
||||||
|
bool try_read_value (const std::string &s, double &v);
|
||||||
|
|
||||||
|
private:
|
||||||
|
double read_atomic_value (tl::Extractor &ex);
|
||||||
|
double read_dot_expr (tl::Extractor &ex);
|
||||||
|
double read_bar_expr (tl::Extractor &ex);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -138,18 +184,12 @@ private:
|
||||||
void push_stream (const std::string &path);
|
void push_stream (const std::string &path);
|
||||||
void pop_stream ();
|
void pop_stream ();
|
||||||
bool at_end ();
|
bool at_end ();
|
||||||
void read_pin_and_parameters (tl::Extractor &ex, std::vector<std::string> &nn, std::map<std::string, double> &pv);
|
|
||||||
bool read_element (tl::Extractor &ex, const std::string &element, const std::string &name);
|
bool read_element (tl::Extractor &ex, const std::string &element, const std::string &name);
|
||||||
void read_subcircuit (const std::string &sc_name, const std::string &nc_name, const std::vector<db::Net *> &nets);
|
void read_subcircuit (const std::string &sc_name, const std::string &nc_name, const std::vector<db::Net *> &nets);
|
||||||
void read_circuit (tl::Extractor &ex, const std::string &name);
|
void read_circuit (tl::Extractor &ex, const std::string &name);
|
||||||
void skip_circuit (tl::Extractor &ex);
|
void skip_circuit (tl::Extractor &ex);
|
||||||
bool read_card ();
|
bool read_card ();
|
||||||
double read_value (tl::Extractor &ex);
|
|
||||||
std::string read_name_with_case (tl::Extractor &ex);
|
|
||||||
std::string read_name (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);
|
|
||||||
std::string get_line ();
|
std::string get_line ();
|
||||||
void unget_line (const std::string &l);
|
void unget_line (const std::string &l);
|
||||||
void error (const std::string &msg);
|
void error (const std::string &msg);
|
||||||
|
|
|
||||||
|
|
@ -94,8 +94,10 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
|
||||||
{
|
{
|
||||||
const db::DeviceClass *dc = dev.device_class ();
|
const db::DeviceClass *dc = dev.device_class ();
|
||||||
const db::DeviceClassCapacitor *cap = dynamic_cast<const db::DeviceClassCapacitor *> (dc);
|
const db::DeviceClassCapacitor *cap = dynamic_cast<const db::DeviceClassCapacitor *> (dc);
|
||||||
|
const db::DeviceClassCapacitor *cap3 = dynamic_cast<const db::DeviceClassCapacitorWithBulk *> (dc);
|
||||||
const db::DeviceClassInductor *ind = dynamic_cast<const db::DeviceClassInductor *> (dc);
|
const db::DeviceClassInductor *ind = dynamic_cast<const db::DeviceClassInductor *> (dc);
|
||||||
const db::DeviceClassResistor *res = dynamic_cast<const db::DeviceClassResistor *> (dc);
|
const db::DeviceClassResistor *res = dynamic_cast<const db::DeviceClassResistor *> (dc);
|
||||||
|
const db::DeviceClassResistor *res3 = dynamic_cast<const db::DeviceClassResistorWithBulk *> (dc);
|
||||||
const db::DeviceClassDiode *diode = dynamic_cast<const db::DeviceClassDiode *> (dc);
|
const db::DeviceClassDiode *diode = dynamic_cast<const db::DeviceClassDiode *> (dc);
|
||||||
const db::DeviceClassMOS3Transistor *mos3 = dynamic_cast<const db::DeviceClassMOS3Transistor *> (dc);
|
const db::DeviceClassMOS3Transistor *mos3 = dynamic_cast<const db::DeviceClassMOS3Transistor *> (dc);
|
||||||
const db::DeviceClassMOS4Transistor *mos4 = dynamic_cast<const db::DeviceClassMOS4Transistor *> (dc);
|
const db::DeviceClassMOS4Transistor *mos4 = dynamic_cast<const db::DeviceClassMOS4Transistor *> (dc);
|
||||||
|
|
@ -104,13 +106,17 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
|
||||||
|
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
|
|
||||||
if (cap) {
|
if (cap || cap3) {
|
||||||
|
|
||||||
os << "C";
|
os << "C";
|
||||||
os << format_name (dev.expanded_name ());
|
os << format_name (dev.expanded_name ());
|
||||||
os << format_terminals (dev, size_t (2));
|
os << format_terminals (dev, size_t (3));
|
||||||
os << " ";
|
os << " ";
|
||||||
os << tl::sprintf ("%.12g", dev.parameter_value (db::DeviceClassCapacitor::param_id_C));
|
os << tl::sprintf ("%.12g", dev.parameter_value (db::DeviceClassCapacitor::param_id_C));
|
||||||
|
if (! dev.device_class ()->name ().empty ()) {
|
||||||
|
os << " ";
|
||||||
|
os << format_name (dev.device_class ()->name ());
|
||||||
|
}
|
||||||
|
|
||||||
} else if (ind) {
|
} else if (ind) {
|
||||||
|
|
||||||
|
|
@ -119,14 +125,22 @@ void NetlistSpiceWriterDelegate::write_device (const db::Device &dev) const
|
||||||
os << format_terminals (dev, size_t (2));
|
os << format_terminals (dev, size_t (2));
|
||||||
os << " ";
|
os << " ";
|
||||||
os << tl::sprintf ("%.12g", dev.parameter_value (db::DeviceClassInductor::param_id_L));
|
os << tl::sprintf ("%.12g", dev.parameter_value (db::DeviceClassInductor::param_id_L));
|
||||||
|
if (! dev.device_class ()->name ().empty ()) {
|
||||||
|
os << " ";
|
||||||
|
os << format_name (dev.device_class ()->name ());
|
||||||
|
}
|
||||||
|
|
||||||
} else if (res) {
|
} else if (res) {
|
||||||
|
|
||||||
os << "R";
|
os << "R";
|
||||||
os << format_name (dev.expanded_name ());
|
os << format_name (dev.expanded_name ());
|
||||||
os << format_terminals (dev, size_t (2));
|
os << format_terminals (dev, size_t (3));
|
||||||
os << " ";
|
os << " ";
|
||||||
os << tl::sprintf ("%.12g", dev.parameter_value (db::DeviceClassResistor::param_id_R));
|
os << tl::sprintf ("%.12g", dev.parameter_value (db::DeviceClassResistor::param_id_R));
|
||||||
|
if (! dev.device_class ()->name ().empty ()) {
|
||||||
|
os << " ";
|
||||||
|
os << format_name (dev.device_class ()->name ());
|
||||||
|
}
|
||||||
|
|
||||||
} else if (diode) {
|
} else if (diode) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2122,6 +2122,54 @@ Class<db::NetlistReader> db_NetlistReader ("db", "NetlistReader",
|
||||||
"@hide\n"
|
"@hide\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A helper class wrapping the return values for NetlistSpiceReaderDelegateImpl::parse_element
|
||||||
|
*/
|
||||||
|
class ParseElementData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ParseElementData () : m_value (0.0) { }
|
||||||
|
|
||||||
|
const std::string &model_name () const { return m_model; }
|
||||||
|
std::string &model_name_nc () { return m_model; }
|
||||||
|
void set_model_name (const std::string &model) { m_model = model; }
|
||||||
|
double value () const { return m_value; }
|
||||||
|
double &value_nc () { return m_value; }
|
||||||
|
void set_value (double value) { m_value = value; }
|
||||||
|
const std::vector<std::string> &net_names () const { return m_net_names; }
|
||||||
|
std::vector<std::string> &net_names_nc () { return m_net_names; }
|
||||||
|
void set_net_names (const std::vector<std::string> &nn) { m_net_names = nn; }
|
||||||
|
const std::map<std::string, double> ¶meters () const { return m_parameters; }
|
||||||
|
std::map<std::string, double> ¶meters_nc () { return m_parameters; }
|
||||||
|
void set_parameters (const std::map<std::string, double> ¶meters) { m_parameters = parameters; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_model;
|
||||||
|
double m_value;
|
||||||
|
std::vector<std::string> m_net_names;
|
||||||
|
std::map<std::string, double> m_parameters;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A helper class for the return values of NetlistSpiceReaderDelegateImpl::parse_element_components
|
||||||
|
*/
|
||||||
|
class ParseElementComponentsData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ParseElementComponentsData () { }
|
||||||
|
|
||||||
|
const std::vector<std::string> &strings () const { return m_strings; }
|
||||||
|
std::vector<std::string> &strings_nc () { return m_strings; }
|
||||||
|
void set_strings (const std::vector<std::string> &nn) { m_strings = nn; }
|
||||||
|
const std::map<std::string, double> ¶meters () const { return m_parameters; }
|
||||||
|
std::map<std::string, double> ¶meters_nc () { return m_parameters; }
|
||||||
|
void set_parameters (const std::map<std::string, double> ¶meters) { m_parameters = parameters; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::string> m_strings;
|
||||||
|
std::map<std::string, double> m_parameters;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A SPICE reader delegate base class for reimplementation
|
* @brief A SPICE reader delegate base class for reimplementation
|
||||||
*/
|
*/
|
||||||
|
|
@ -2180,6 +2228,25 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool control_statement (const std::string &line)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
m_error.clear ();
|
||||||
|
if (cb_control_statement.can_issue ()) {
|
||||||
|
return cb_control_statement.issue<db::NetlistSpiceReaderDelegate, bool, const std::string &> (&db::NetlistSpiceReaderDelegate::control_statement, line);
|
||||||
|
} else {
|
||||||
|
return db::NetlistSpiceReaderDelegate::control_statement (line);
|
||||||
|
}
|
||||||
|
} catch (tl::Exception &) {
|
||||||
|
if (! m_error.empty ()) {
|
||||||
|
db::NetlistSpiceReaderDelegate::error (m_error);
|
||||||
|
} else {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool wants_subcircuit (const std::string &circuit_name)
|
virtual bool wants_subcircuit (const std::string &circuit_name)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
@ -2199,6 +2266,59 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual std::string translate_net_name (const std::string &nn)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
m_error.clear ();
|
||||||
|
if (cb_translate_net_name.can_issue ()) {
|
||||||
|
return cb_translate_net_name.issue<db::NetlistSpiceReaderDelegate, std::string, const std::string &> (&db::NetlistSpiceReaderDelegate::translate_net_name, nn);
|
||||||
|
} else {
|
||||||
|
return db::NetlistSpiceReaderDelegate::translate_net_name (nn);
|
||||||
|
}
|
||||||
|
} catch (tl::Exception &) {
|
||||||
|
if (! m_error.empty ()) {
|
||||||
|
db::NetlistSpiceReaderDelegate::error (m_error);
|
||||||
|
} else {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
return std::string ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseElementData parse_element_helper (const std::string &s, const std::string &element)
|
||||||
|
{
|
||||||
|
ParseElementData data;
|
||||||
|
db::NetlistSpiceReaderDelegate::parse_element (s, element, data.model_name_nc (), data.value_nc (), data.net_names_nc (), data.parameters_nc ());
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void parse_element (const std::string &s, const std::string &element, std::string &model, double &value, std::vector<std::string> &nn, std::map<std::string, double> &pv)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
|
||||||
|
m_error.clear ();
|
||||||
|
|
||||||
|
ParseElementData data;
|
||||||
|
if (cb_parse_element.can_issue ()) {
|
||||||
|
data = cb_parse_element.issue<NetlistSpiceReaderDelegateImpl, ParseElementData, const std::string &, const std::string &> (&NetlistSpiceReaderDelegateImpl::parse_element_helper, s, element);
|
||||||
|
} else {
|
||||||
|
data = parse_element_helper (s, element);
|
||||||
|
}
|
||||||
|
|
||||||
|
model = data.model_name ();
|
||||||
|
value = data.value ();
|
||||||
|
nn = data.net_names ();
|
||||||
|
pv = data.parameters ();
|
||||||
|
|
||||||
|
} catch (tl::Exception &) {
|
||||||
|
if (! m_error.empty ()) {
|
||||||
|
db::NetlistSpiceReaderDelegate::error (m_error);
|
||||||
|
} else {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool element (db::Circuit *circuit, const std::string &element, const std::string &name, const std::string &model, double value, const std::vector<db::Net *> &nets, const std::map<std::string, double> ¶ms)
|
virtual bool element (db::Circuit *circuit, const std::string &element, const std::string &name, const std::string &model, double value, const std::vector<db::Net *> &nets, const std::map<std::string, double> ¶ms)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
@ -2220,38 +2340,128 @@ public:
|
||||||
|
|
||||||
gsi::Callback cb_start;
|
gsi::Callback cb_start;
|
||||||
gsi::Callback cb_finish;
|
gsi::Callback cb_finish;
|
||||||
|
gsi::Callback cb_control_statement;
|
||||||
gsi::Callback cb_wants_subcircuit;
|
gsi::Callback cb_wants_subcircuit;
|
||||||
|
gsi::Callback cb_translate_net_name;
|
||||||
gsi::Callback cb_element;
|
gsi::Callback cb_element;
|
||||||
|
gsi::Callback cb_parse_element;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_error;
|
std::string m_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void start_fb (db::NetlistSpiceReaderDelegate *delegate, db::Netlist *netlist)
|
static void start_fb (NetlistSpiceReaderDelegateImpl *delegate, db::Netlist *netlist)
|
||||||
{
|
{
|
||||||
delegate->db::NetlistSpiceReaderDelegate::start (netlist);
|
delegate->db::NetlistSpiceReaderDelegate::start (netlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void finish_fb (db::NetlistSpiceReaderDelegate *delegate, db::Netlist *netlist)
|
static void finish_fb (NetlistSpiceReaderDelegateImpl *delegate, db::Netlist *netlist)
|
||||||
{
|
{
|
||||||
delegate->db::NetlistSpiceReaderDelegate::finish (netlist);
|
delegate->db::NetlistSpiceReaderDelegate::finish (netlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool wants_subcircuit_fb (db::NetlistSpiceReaderDelegate *delegate, const std::string &model)
|
static bool wants_subcircuit_fb (NetlistSpiceReaderDelegateImpl *delegate, const std::string &model)
|
||||||
{
|
{
|
||||||
return delegate->db::NetlistSpiceReaderDelegate::wants_subcircuit (model);
|
return delegate->db::NetlistSpiceReaderDelegate::wants_subcircuit (model);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool element_fb (db::NetlistSpiceReaderDelegate *delegate, db::Circuit *circuit, const std::string &element, const std::string &name, const std::string &model, double value, const std::vector<db::Net *> &nets, const std::map<std::string, double> ¶ms)
|
static bool control_statement_fb (NetlistSpiceReaderDelegateImpl *delegate, const std::string &line)
|
||||||
|
{
|
||||||
|
return delegate->db::NetlistSpiceReaderDelegate::control_statement (line);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string translate_net_name_fb (NetlistSpiceReaderDelegateImpl *delegate, const std::string &name)
|
||||||
|
{
|
||||||
|
return delegate->db::NetlistSpiceReaderDelegate::translate_net_name (name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool element_fb (NetlistSpiceReaderDelegateImpl *delegate, db::Circuit *circuit, const std::string &element, const std::string &name, const std::string &model, double value, const std::vector<db::Net *> &nets, const std::map<std::string, double> ¶ms)
|
||||||
{
|
{
|
||||||
return delegate->db::NetlistSpiceReaderDelegate::element (circuit, element, name, model, value, nets, params);
|
return delegate->db::NetlistSpiceReaderDelegate::element (circuit, element, name, model, value, nets, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ParseElementData parse_element_fb (NetlistSpiceReaderDelegateImpl *delegate, const std::string &s, const std::string &element)
|
||||||
|
{
|
||||||
|
return delegate->parse_element_helper (s, element);
|
||||||
|
}
|
||||||
|
|
||||||
|
static tl::Variant value_from_string (NetlistSpiceReaderDelegateImpl *delegate, const std::string &s)
|
||||||
|
{
|
||||||
|
tl::Variant res;
|
||||||
|
double v = 0.0;
|
||||||
|
if (delegate->try_read_value (s, v)) {
|
||||||
|
res = v;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ParseElementComponentsData parse_element_components (NetlistSpiceReaderDelegateImpl *delegate, const std::string &s)
|
||||||
|
{
|
||||||
|
ParseElementComponentsData data;
|
||||||
|
delegate->parse_element_components (s, data.strings_nc (), data.parameters_nc ());
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
Class<ParseElementComponentsData> db_ParseElementComponentsData ("db", "ParseElementComponentsData",
|
||||||
|
gsi::method ("strings", &ParseElementComponentsData::strings,
|
||||||
|
"@brief Gets the string parameters\n"
|
||||||
|
) +
|
||||||
|
gsi::method ("strings=", &ParseElementComponentsData::set_strings, gsi::arg ("list"),
|
||||||
|
"@brief Sets the string parameters\n"
|
||||||
|
) +
|
||||||
|
gsi::method ("parameters", &ParseElementComponentsData::parameters,
|
||||||
|
"@brief Gets the (named) numerical parameters\n"
|
||||||
|
) +
|
||||||
|
gsi::method ("parameters=", &ParseElementComponentsData::set_parameters, gsi::arg ("dict"),
|
||||||
|
"@brief Sets the (named) numerical parameters\n"
|
||||||
|
),
|
||||||
|
"@brief Supplies the return value for \\NetlistSpiceReaderDelegate#parse_element_components.\n"
|
||||||
|
"This is a structure with two members: 'strings' for the string arguments and 'parameters' for the "
|
||||||
|
"named numerical arguments.\n"
|
||||||
|
"\n"
|
||||||
|
"This helper class has been introduced in version 0.27.1.\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
Class<ParseElementData> db_ParseElementData ("db", "ParseElementData",
|
||||||
|
gsi::method ("value", &ParseElementData::value,
|
||||||
|
"@brief Gets the value\n"
|
||||||
|
) +
|
||||||
|
gsi::method ("value=", &ParseElementData::set_value, gsi::arg ("v"),
|
||||||
|
"@brief Sets the value\n"
|
||||||
|
) +
|
||||||
|
gsi::method ("model_name", &ParseElementData::model_name,
|
||||||
|
"@brief Gets the model name\n"
|
||||||
|
) +
|
||||||
|
gsi::method ("model_name=", &ParseElementData::set_model_name, gsi::arg ("m"),
|
||||||
|
"@brief Sets the model name\n"
|
||||||
|
) +
|
||||||
|
gsi::method ("net_names", &ParseElementData::net_names,
|
||||||
|
"@brief Gets the net names\n"
|
||||||
|
) +
|
||||||
|
gsi::method ("net_names=", &ParseElementData::set_net_names, gsi::arg ("list"),
|
||||||
|
"@brief Sets the net names\n"
|
||||||
|
) +
|
||||||
|
gsi::method ("parameters", &ParseElementData::parameters,
|
||||||
|
"@brief Gets the (named) numerical parameters\n"
|
||||||
|
) +
|
||||||
|
gsi::method ("parameters=", &ParseElementData::set_parameters, gsi::arg ("dict"),
|
||||||
|
"@brief Sets the (named) numerical parameters\n"
|
||||||
|
),
|
||||||
|
"@brief Supplies the return value for \\NetlistSpiceReaderDelegate#parse_element.\n"
|
||||||
|
"This is a structure with four members: 'model_name' for the model name, 'value' for the default numerical value, 'net_names' for the net names and 'parameters' for the "
|
||||||
|
"named numerical parameters.\n"
|
||||||
|
"\n"
|
||||||
|
"This helper class has been introduced in version 0.27.1.\n"
|
||||||
|
);
|
||||||
|
|
||||||
Class<NetlistSpiceReaderDelegateImpl> db_NetlistSpiceReaderDelegate ("db", "NetlistSpiceReaderDelegate",
|
Class<NetlistSpiceReaderDelegateImpl> db_NetlistSpiceReaderDelegate ("db", "NetlistSpiceReaderDelegate",
|
||||||
gsi::method_ext ("start", &start_fb, "@hide") +
|
gsi::method_ext ("start", &start_fb, "@hide") +
|
||||||
gsi::method_ext ("finish", &finish_fb, "@hide") +
|
gsi::method_ext ("finish", &finish_fb, "@hide") +
|
||||||
gsi::method_ext ("wants_subcircuit", &wants_subcircuit_fb, "@hide") +
|
gsi::method_ext ("wants_subcircuit", &wants_subcircuit_fb, "@hide") +
|
||||||
gsi::method_ext ("element", &element_fb, "@hide") +
|
gsi::method_ext ("element", &element_fb, "@hide") +
|
||||||
|
gsi::method_ext ("parse_element", &parse_element_fb, "@hide") +
|
||||||
|
gsi::method_ext ("control_statement", &control_statement_fb, "@hide") +
|
||||||
|
gsi::method_ext ("translate_net_name", &translate_net_name_fb, "@hide") +
|
||||||
gsi::callback ("start", &NetlistSpiceReaderDelegateImpl::start, &NetlistSpiceReaderDelegateImpl::cb_start, gsi::arg ("netlist"),
|
gsi::callback ("start", &NetlistSpiceReaderDelegateImpl::start, &NetlistSpiceReaderDelegateImpl::cb_start, gsi::arg ("netlist"),
|
||||||
"@brief This method is called when the reader starts reading a netlist\n"
|
"@brief This method is called when the reader starts reading a netlist\n"
|
||||||
) +
|
) +
|
||||||
|
|
@ -2262,6 +2472,36 @@ Class<NetlistSpiceReaderDelegateImpl> db_NetlistSpiceReaderDelegate ("db", "Netl
|
||||||
"@brief Returns true, if the delegate wants subcircuit elements with this name\n"
|
"@brief Returns true, if the delegate wants subcircuit elements with this name\n"
|
||||||
"The name is always upper case.\n"
|
"The name is always upper case.\n"
|
||||||
) +
|
) +
|
||||||
|
gsi::callback ("control_statement", &NetlistSpiceReaderDelegateImpl::control_statement, &NetlistSpiceReaderDelegateImpl::cb_control_statement, gsi::arg ("line"),
|
||||||
|
"@brief Receives control statements not understood by the standard reader\n"
|
||||||
|
"When the reader encounters a control statement not understood by the parser, it will pass the line to the delegate using this method.\n"
|
||||||
|
"The delegate can decide if it wants to read this statement. It should return true in this case.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.27.1\n"
|
||||||
|
) +
|
||||||
|
gsi::callback ("translate_net_name", &NetlistSpiceReaderDelegateImpl::translate_net_name, &NetlistSpiceReaderDelegateImpl::cb_translate_net_name, gsi::arg ("net_name"),
|
||||||
|
"@brief Translates a net name from the raw net name to the true net name\n"
|
||||||
|
"The default implementation will replace backslash sequences by the corresponding character.\n"
|
||||||
|
"'translate_net_name' is called before a net name is turned into a net object.\n"
|
||||||
|
"The method can be reimplemented to supply a different translation scheme for net names. For example, to translate special characters.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.27.1\n"
|
||||||
|
) +
|
||||||
|
gsi::callback ("parse_element", &NetlistSpiceReaderDelegateImpl::parse_element_helper, &NetlistSpiceReaderDelegateImpl::cb_parse_element,
|
||||||
|
gsi::arg ("s"), gsi::arg ("element"),
|
||||||
|
"@brief Parses an element card\n"
|
||||||
|
"@param s The specification part of the element line (the part after element code and name).\n"
|
||||||
|
"@param element The upper-case element code (\"M\", \"R\", ...).\n"
|
||||||
|
"@return A \\ParseElementData object with the parts of the element.\n"
|
||||||
|
"\n"
|
||||||
|
"This method receives a string with the element specification and the element code. It is supposed to "
|
||||||
|
"parse the element line and return a model name, a value, a list of net names and a parameter value dictionary.\n"
|
||||||
|
"\n"
|
||||||
|
"'parse_element' is called one every element card. The results of this call go into the \\element method "
|
||||||
|
"to actually create the device. This method can be reimplemented to support other flavors of SPICE.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.27.1\n"
|
||||||
|
) +
|
||||||
gsi::callback ("element", &NetlistSpiceReaderDelegateImpl::element, &NetlistSpiceReaderDelegateImpl::cb_element,
|
gsi::callback ("element", &NetlistSpiceReaderDelegateImpl::element, &NetlistSpiceReaderDelegateImpl::cb_element,
|
||||||
gsi::arg ("circuit"), gsi::arg ("element"), gsi::arg ("name"), gsi::arg ("model"), gsi::arg ("value"), gsi::arg ("nets"), gsi::arg ("parameters"),
|
gsi::arg ("circuit"), gsi::arg ("element"), gsi::arg ("name"), gsi::arg ("model"), gsi::arg ("value"), gsi::arg ("nets"), gsi::arg ("parameters"),
|
||||||
"@brief Makes a device from an element line\n"
|
"@brief Makes a device from an element line\n"
|
||||||
|
|
@ -2281,6 +2521,23 @@ Class<NetlistSpiceReaderDelegateImpl> db_NetlistSpiceReaderDelegate ("db", "Netl
|
||||||
gsi::method ("error", &NetlistSpiceReaderDelegateImpl::error, gsi::arg ("msg"),
|
gsi::method ("error", &NetlistSpiceReaderDelegateImpl::error, gsi::arg ("msg"),
|
||||||
"@brief Issues an error with the given message.\n"
|
"@brief Issues an error with the given message.\n"
|
||||||
"Use this method to generate an error."
|
"Use this method to generate an error."
|
||||||
|
) +
|
||||||
|
gsi::method_ext ("value_from_string", &value_from_string, gsi::arg ("s"),
|
||||||
|
"@brief Translates a string into a value\n"
|
||||||
|
"This function simplifies the implementation of SPICE readers by providing a translation of a unit-annotated string "
|
||||||
|
"into double values. For example, '1k' is translated to 1000.0. In addition, simple formula evaluation is supported, e.g "
|
||||||
|
"'(1+3)*2' is translated into 8.0.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.27.1\n"
|
||||||
|
) +
|
||||||
|
gsi::method_ext ("parse_element_components", &parse_element_components, gsi::arg ("s"),
|
||||||
|
"@brief Parses a string into string and parameter components.\n"
|
||||||
|
"This method is provided for simplifying the implementation of 'parse_element'. It takes a string and splits it into "
|
||||||
|
"string arguments and parameter values. For example, 'a b c=6' renders two string arguments in 'nn' and one parameter in pv ('C'->6.0). "
|
||||||
|
"It returns data \\ParseElementComponentsData object with the strings and parameters.\n"
|
||||||
|
"The parameter names are already translated to upper case.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.27.1\n"
|
||||||
),
|
),
|
||||||
"@brief Provides a delegate for the SPICE reader for translating device statements\n"
|
"@brief Provides a delegate for the SPICE reader for translating device statements\n"
|
||||||
"Supply a customized class to provide a specialized reading scheme for devices. "
|
"Supply a customized class to provide a specialized reading scheme for devices. "
|
||||||
|
|
@ -2396,7 +2653,21 @@ Class<db::NetlistSpiceReader> db_NetlistSpiceReader (db_NetlistReader, "db", "Ne
|
||||||
"nl.read(input_file, reader)\n"
|
"nl.read(input_file, reader)\n"
|
||||||
"@/code\n"
|
"@/code\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This class has been introduced in version 0.26."
|
"A somewhat contrived example for using the delegate to translate net names is this:\n"
|
||||||
|
"\n"
|
||||||
|
"@code\n"
|
||||||
|
"class MyDelegate < RBA::NetlistSpiceReaderDelegate\n"
|
||||||
|
"\n"
|
||||||
|
" # translates 'VDD' to 'VXX' and leave all other net names as is:\n"
|
||||||
|
" alias translate_net_name_org translate_net_name\n"
|
||||||
|
" def translate_net_name(n)\n"
|
||||||
|
" return n == \"VDD\" ? \"VXX\" : translate_net_name_org(n)}\n"
|
||||||
|
" end\n"
|
||||||
|
"\n"
|
||||||
|
"end\n"
|
||||||
|
"@/code\n"
|
||||||
|
"\n"
|
||||||
|
"This class has been introduced in version 0.26. It has been extended in version 0.27.1."
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -374,12 +374,20 @@ TEST(9_DeviceMultipliers)
|
||||||
" device RES $2 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
|
" device RES $2 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
|
||||||
" device RMODEL $3 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0);\n"
|
" device RMODEL $3 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0);\n"
|
||||||
" device RMODEL $4 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
|
" device RMODEL $4 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
|
||||||
|
" device RMODEL $5 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
|
||||||
|
" device RMODEL2 $6 (A='3',B='4',W='5') (R=1700,L=0,W=0,A=0,P=0);\n"
|
||||||
|
" device RMODEL2 $7 (A='3',B='4',W='5') (R=1700,L=0,W=0,A=0,P=0);\n"
|
||||||
|
" device RES3 $8 (A='3',B='4',W='5') (R=1700,L=0,W=0,A=0,P=0);\n"
|
||||||
" device NMOS $1 (S='1',G='2',D='3',B='4') (L=7,W=4,AS=0,AD=0,PS=0,PD=0);\n"
|
" device NMOS $1 (S='1',G='2',D='3',B='4') (L=7,W=4,AS=0,AD=0,PS=0,PD=0);\n"
|
||||||
" device PMOS $2 (S='1',G='2',D='3',B='4') (L=7,W=2,AS=0,AD=0,PS=0,PD=0);\n"
|
" device PMOS $2 (S='1',G='2',D='3',B='4') (L=7,W=2,AS=0,AD=0,PS=0,PD=0);\n"
|
||||||
" device CAP $1 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
|
" device CAP $1 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
|
||||||
" device CAP $2 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
|
" device CAP $2 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
|
||||||
" device CMODEL $3 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
|
" device CMODEL $3 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
|
||||||
" device CMODEL $4 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
|
" device CMODEL $4 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
|
||||||
|
" device CMODEL $5 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
|
||||||
|
" device CMODEL2 $6 (A='3',B='4',W='5') (C=1e-09,A=0,P=0);\n"
|
||||||
|
" device CAP3 $7 (A='3',B='4',W='5') (C=1e-09,A=0,P=0);\n"
|
||||||
|
" device CMODEL2 $8 (A='3',B='4',W='5') (C=1e-09,A=0,P=0);\n"
|
||||||
" device IND $1 (A='1',B='2') (L=5e-10);\n"
|
" device IND $1 (A='1',B='2') (L=5e-10);\n"
|
||||||
" device IND $2 (A='3',B='4') (L=1e-09);\n"
|
" device IND $2 (A='3',B='4') (L=1e-09);\n"
|
||||||
" device LMODEL $3 (A='1',B='2') (L=5e-10);\n"
|
" device LMODEL $3 (A='1',B='2') (L=5e-10);\n"
|
||||||
|
|
@ -411,12 +419,20 @@ TEST(9_DeviceMultipliers)
|
||||||
" device RES $2 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
|
" device RES $2 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
|
||||||
" device RMODEL $3 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0);\n"
|
" device RMODEL $3 (A='1',B='2') (R=850,L=0,W=0,A=0,P=0);\n"
|
||||||
" device RMODEL $4 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
|
" device RMODEL $4 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
|
||||||
|
" device RMODEL $5 (A='3',B='4') (R=1700,L=0,W=0,A=0,P=0);\n"
|
||||||
|
" device RMODEL2 $6 (A='3',B='4',W='5') (R=1700,L=0,W=0,A=0,P=0);\n"
|
||||||
|
" device RMODEL2 $7 (A='3',B='4',W='5') (R=1700,L=0,W=0,A=0,P=0);\n"
|
||||||
|
" device RES3 $8 (A='3',B='4',W='5') (R=1700,L=0,W=0,A=0,P=0);\n"
|
||||||
" device NMOS $1 (S='1',G='2',D='3',B='4') (L=7,W=4,AS=0,AD=0,PS=0,PD=0);\n"
|
" device NMOS $1 (S='1',G='2',D='3',B='4') (L=7,W=4,AS=0,AD=0,PS=0,PD=0);\n"
|
||||||
" device PMOS $2 (S='1',G='2',D='3',B='4') (L=7,W=2,AS=0,AD=0,PS=0,PD=0);\n"
|
" device PMOS $2 (S='1',G='2',D='3',B='4') (L=7,W=2,AS=0,AD=0,PS=0,PD=0);\n"
|
||||||
" device CAP $1 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
|
" device CAP $1 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
|
||||||
" device CAP $2 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
|
" device CAP $2 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
|
||||||
" device CMODEL $3 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
|
" device CMODEL $3 (A='1',B='2') (C=2e-09,A=0,P=0);\n"
|
||||||
" device CMODEL $4 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
|
" device CMODEL $4 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
|
||||||
|
" device CMODEL $5 (A='3',B='4') (C=1e-09,A=0,P=0);\n"
|
||||||
|
" device CMODEL2 $6 (A='3',B='4',W='5') (C=1e-09,A=0,P=0);\n"
|
||||||
|
" device CAP3 $7 (A='3',B='4',W='5') (C=1e-09,A=0,P=0);\n"
|
||||||
|
" device CMODEL2 $8 (A='3',B='4',W='5') (C=1e-09,A=0,P=0);\n"
|
||||||
" device IND $1 (A='1',B='2') (L=5e-10);\n"
|
" device IND $1 (A='1',B='2') (L=5e-10);\n"
|
||||||
" device IND $2 (A='3',B='4') (L=1e-09);\n"
|
" device IND $2 (A='3',B='4') (L=1e-09);\n"
|
||||||
" device LMODEL $3 (A='1',B='2') (L=5e-10);\n"
|
" device LMODEL $3 (A='1',B='2') (L=5e-10);\n"
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ TEST(1_WriterResistorDevicesWithBulk)
|
||||||
writer.write (stream, nl, "written by unit test");
|
writer.write (stream, nl, "written by unit test");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string au_path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nwriter1_au.txt");
|
std::string au_path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nwriter1b_au.txt");
|
||||||
|
|
||||||
compare_netlists (_this, path, au_path);
|
compare_netlists (_this, path, au_path);
|
||||||
}
|
}
|
||||||
|
|
@ -224,6 +224,61 @@ TEST(2_WriterCapacitorDevices)
|
||||||
compare_netlists (_this, path, au_path);
|
compare_netlists (_this, path, au_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(2_WriterCapacitorDevicesNoName)
|
||||||
|
{
|
||||||
|
db::Netlist nl;
|
||||||
|
|
||||||
|
db::DeviceClass *ccls = new db::DeviceClassCapacitor ();
|
||||||
|
|
||||||
|
nl.add_device_class (ccls);
|
||||||
|
|
||||||
|
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 ("n2");
|
||||||
|
circuit1->add_net (n2);
|
||||||
|
n3 = new db::Net ();
|
||||||
|
n3->set_name ("n3");
|
||||||
|
circuit1->add_net (n3);
|
||||||
|
|
||||||
|
db::Device *cdev1 = new db::Device (ccls);
|
||||||
|
cdev1->set_parameter_value (db::DeviceClassCapacitor::param_id_C, 1.7e-12);
|
||||||
|
db::Device *cdev2 = new db::Device (ccls);
|
||||||
|
cdev2->set_parameter_value (db::DeviceClassCapacitor::param_id_C, 42e-15);
|
||||||
|
circuit1->add_device (cdev1);
|
||||||
|
circuit1->add_device (cdev2);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
cdev1->connect_terminal (cdev1->device_class ()->terminal_id_for_name ("A"), n1);
|
||||||
|
cdev1->connect_terminal (cdev1->device_class ()->terminal_id_for_name ("B"), n3);
|
||||||
|
cdev2->connect_terminal (cdev2->device_class ()->terminal_id_for_name ("A"), n3);
|
||||||
|
cdev2->connect_terminal (cdev2->device_class ()->terminal_id_for_name ("B"), n2);
|
||||||
|
|
||||||
|
// verify against the input
|
||||||
|
|
||||||
|
std::string path = tmp_file ("tmp_nwriter2.txt");
|
||||||
|
{
|
||||||
|
tl::OutputStream stream (path);
|
||||||
|
db::NetlistSpiceWriter writer;
|
||||||
|
writer.write (stream, nl, "written by unit test");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string au_path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nwriter2b_au.txt");
|
||||||
|
|
||||||
|
compare_netlists (_this, path, au_path);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(2_WriterCapacitorDevicesWithBulk)
|
TEST(2_WriterCapacitorDevicesWithBulk)
|
||||||
{
|
{
|
||||||
db::Netlist nl;
|
db::Netlist nl;
|
||||||
|
|
@ -278,7 +333,64 @@ TEST(2_WriterCapacitorDevicesWithBulk)
|
||||||
writer.write (stream, nl, "written by unit test");
|
writer.write (stream, nl, "written by unit test");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string au_path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nwriter2_au.txt");
|
std::string au_path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nwriter2c_au.txt");
|
||||||
|
|
||||||
|
compare_netlists (_this, path, au_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(2_WriterCapacitorDevicesWithBulkNoName)
|
||||||
|
{
|
||||||
|
db::Netlist nl;
|
||||||
|
|
||||||
|
db::DeviceClass *ccls = new db::DeviceClassCapacitorWithBulk ();
|
||||||
|
|
||||||
|
nl.add_device_class (ccls);
|
||||||
|
|
||||||
|
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 ("n2");
|
||||||
|
circuit1->add_net (n2);
|
||||||
|
n3 = new db::Net ();
|
||||||
|
n3->set_name ("n3");
|
||||||
|
circuit1->add_net (n3);
|
||||||
|
|
||||||
|
db::Device *cdev1 = new db::Device (ccls);
|
||||||
|
cdev1->set_parameter_value (db::DeviceClassCapacitor::param_id_C, 1.7e-12);
|
||||||
|
db::Device *cdev2 = new db::Device (ccls);
|
||||||
|
cdev2->set_parameter_value (db::DeviceClassCapacitor::param_id_C, 42e-15);
|
||||||
|
circuit1->add_device (cdev1);
|
||||||
|
circuit1->add_device (cdev2);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
cdev1->connect_terminal (cdev1->device_class ()->terminal_id_for_name ("A"), n1);
|
||||||
|
cdev1->connect_terminal (cdev1->device_class ()->terminal_id_for_name ("B"), n3);
|
||||||
|
cdev1->connect_terminal (cdev1->device_class ()->terminal_id_for_name ("W"), n3);
|
||||||
|
cdev2->connect_terminal (cdev2->device_class ()->terminal_id_for_name ("A"), n3);
|
||||||
|
cdev2->connect_terminal (cdev2->device_class ()->terminal_id_for_name ("B"), n2);
|
||||||
|
cdev2->connect_terminal (cdev2->device_class ()->terminal_id_for_name ("W"), n3);
|
||||||
|
|
||||||
|
// verify against the input
|
||||||
|
|
||||||
|
std::string path = tmp_file ("tmp_nwriter2.txt");
|
||||||
|
{
|
||||||
|
tl::OutputStream stream (path);
|
||||||
|
db::NetlistSpiceWriter writer;
|
||||||
|
writer.write (stream, nl, "written by unit test");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string au_path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nwriter2d_au.txt");
|
||||||
|
|
||||||
compare_netlists (_this, path, au_path);
|
compare_netlists (_this, path, au_path);
|
||||||
}
|
}
|
||||||
|
|
@ -912,7 +1024,6 @@ TEST(10_WriterLongLines)
|
||||||
db::Netlist nl;
|
db::Netlist nl;
|
||||||
|
|
||||||
db::DeviceClass *rcls = new db::DeviceClassResistor ();
|
db::DeviceClass *rcls = new db::DeviceClassResistor ();
|
||||||
rcls->set_name ("RCLS");
|
|
||||||
nl.add_device_class (rcls);
|
nl.add_device_class (rcls);
|
||||||
|
|
||||||
db::Circuit *circuit1 = new db::Circuit ();
|
db::Circuit *circuit1 = new db::Circuit ();
|
||||||
|
|
|
||||||
|
|
@ -122,13 +122,13 @@ TEST(11_private)
|
||||||
TEST(12_private)
|
TEST(12_private)
|
||||||
{
|
{
|
||||||
// test_is_long_runner ();
|
// test_is_long_runner ();
|
||||||
run_test (_this, "test_12.lvs", "test_12.cir.gz", "test_12.gds.gz", true);
|
run_test (_this, "test_12.lvs", "test_12b.cir.gz", "test_12.gds.gz", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(13_private)
|
TEST(13_private)
|
||||||
{
|
{
|
||||||
// test_is_long_runner ();
|
// test_is_long_runner ();
|
||||||
run_test (_this, "test_13.lvs", "test_13.cir.gz", "test_13.gds.gz", true);
|
run_test (_this, "test_13.lvs", "test_13b.cir.gz", "test_13.gds.gz", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(14_private)
|
TEST(14_private)
|
||||||
|
|
@ -152,7 +152,7 @@ TEST(16_private)
|
||||||
TEST(17_private)
|
TEST(17_private)
|
||||||
{
|
{
|
||||||
test_is_long_runner ();
|
test_is_long_runner ();
|
||||||
run_test (_this, "test_17.lylvs", "test_17.cir.gz", "test_17.gds.gz", true, "test_17.lvsdb");
|
run_test (_this, "test_17.lylvs", "test_17b.cir.gz", "test_17.gds.gz", true, "test_17.lvsdb");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(18_private)
|
TEST(18_private)
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,20 @@ R$1 1 2 1.7k M=2
|
||||||
R$2 3 4 1.7k
|
R$2 3 4 1.7k
|
||||||
R$3 1 2 1.7k RMODEL M=2
|
R$3 1 2 1.7k RMODEL M=2
|
||||||
R$4 3 4 1.7k RMODEL
|
R$4 3 4 1.7k RMODEL
|
||||||
|
R$5 3 4 RMODEL R=1.7k
|
||||||
|
R$6 3 4 5 RMODEL2 R=1.7k
|
||||||
|
R$7 3 4 5 1.7k RMODEL2
|
||||||
|
R$8 3 4 5 1.7k
|
||||||
M$1 1 2 3 4 NMOS W=2u L=7u M=2
|
M$1 1 2 3 4 NMOS W=2u L=7u M=2
|
||||||
M$2 1 2 3 4 PMOS W=2u L=7u
|
M$2 1 2 3 4 PMOS W=2u L=7u
|
||||||
C$1 1 2 1e-9 M=2
|
C$1 1 2 1e-9 M=2
|
||||||
C$2 3 4 1e-9
|
C$2 3 4 1e-9
|
||||||
C$3 1 2 1e-9 CMODEL M=2
|
C$3 1 2 1e-9 CMODEL M=2
|
||||||
C$4 3 4 1e-9 CMODEL
|
C$4 3 4 1e-9 CMODEL
|
||||||
|
C$5 3 4 CMODEL C=1e-9
|
||||||
|
C$6 3 4 5 CMODEL2 C=1e-9
|
||||||
|
C$7 3 4 5 1e-9
|
||||||
|
C$8 3 4 5 1e-9 CMODEL2
|
||||||
L$1 1 2 1e-9 M=2
|
L$1 1 2 1e-9 M=2
|
||||||
L$2 3 4 1e-9
|
L$2 3 4 1e-9
|
||||||
L$3 1 2 1e-9 LMODEL M=2
|
L$3 1 2 1e-9 LMODEL M=2
|
||||||
|
|
|
||||||
|
|
@ -209,205 +209,205 @@
|
||||||
* net 99 n98
|
* net 99 n98
|
||||||
* net 100 n99
|
* net 100 n99
|
||||||
* net 101 n100
|
* net 101 n100
|
||||||
* device instance $1 r0 *1 0,0 RCLS
|
* device instance $1 r0 *1 0,0
|
||||||
R$1 1 2 0
|
R$1 1 2 0
|
||||||
* device instance $2 r0 *1 0,0 RCLS
|
* device instance $2 r0 *1 0,0
|
||||||
R$2 1 3 0
|
R$2 1 3 0
|
||||||
* device instance $3 r0 *1 0,0 RCLS
|
* device instance $3 r0 *1 0,0
|
||||||
R$3 1 4 0
|
R$3 1 4 0
|
||||||
* device instance $4 r0 *1 0,0 RCLS
|
* device instance $4 r0 *1 0,0
|
||||||
R$4 1 5 0
|
R$4 1 5 0
|
||||||
* device instance $5 r0 *1 0,0 RCLS
|
* device instance $5 r0 *1 0,0
|
||||||
R$5 1 6 0
|
R$5 1 6 0
|
||||||
* device instance $6 r0 *1 0,0 RCLS
|
* device instance $6 r0 *1 0,0
|
||||||
R$6 1 7 0
|
R$6 1 7 0
|
||||||
* device instance $7 r0 *1 0,0 RCLS
|
* device instance $7 r0 *1 0,0
|
||||||
R$7 1 8 0
|
R$7 1 8 0
|
||||||
* device instance $8 r0 *1 0,0 RCLS
|
* device instance $8 r0 *1 0,0
|
||||||
R$8 1 9 0
|
R$8 1 9 0
|
||||||
* device instance $9 r0 *1 0,0 RCLS
|
* device instance $9 r0 *1 0,0
|
||||||
R$9 1 10 0
|
R$9 1 10 0
|
||||||
* device instance $10 r0 *1 0,0 RCLS
|
* device instance $10 r0 *1 0,0
|
||||||
R$10 1 11 0
|
R$10 1 11 0
|
||||||
* device instance $11 r0 *1 0,0 RCLS
|
* device instance $11 r0 *1 0,0
|
||||||
R$11 1 12 0
|
R$11 1 12 0
|
||||||
* device instance $12 r0 *1 0,0 RCLS
|
* device instance $12 r0 *1 0,0
|
||||||
R$12 1 13 0
|
R$12 1 13 0
|
||||||
* device instance $13 r0 *1 0,0 RCLS
|
* device instance $13 r0 *1 0,0
|
||||||
R$13 1 14 0
|
R$13 1 14 0
|
||||||
* device instance $14 r0 *1 0,0 RCLS
|
* device instance $14 r0 *1 0,0
|
||||||
R$14 1 15 0
|
R$14 1 15 0
|
||||||
* device instance $15 r0 *1 0,0 RCLS
|
* device instance $15 r0 *1 0,0
|
||||||
R$15 1 16 0
|
R$15 1 16 0
|
||||||
* device instance $16 r0 *1 0,0 RCLS
|
* device instance $16 r0 *1 0,0
|
||||||
R$16 1 17 0
|
R$16 1 17 0
|
||||||
* device instance $17 r0 *1 0,0 RCLS
|
* device instance $17 r0 *1 0,0
|
||||||
R$17 1 18 0
|
R$17 1 18 0
|
||||||
* device instance $18 r0 *1 0,0 RCLS
|
* device instance $18 r0 *1 0,0
|
||||||
R$18 1 19 0
|
R$18 1 19 0
|
||||||
* device instance $19 r0 *1 0,0 RCLS
|
* device instance $19 r0 *1 0,0
|
||||||
R$19 1 20 0
|
R$19 1 20 0
|
||||||
* device instance $20 r0 *1 0,0 RCLS
|
* device instance $20 r0 *1 0,0
|
||||||
R$20 1 21 0
|
R$20 1 21 0
|
||||||
* device instance $21 r0 *1 0,0 RCLS
|
* device instance $21 r0 *1 0,0
|
||||||
R$21 1 22 0
|
R$21 1 22 0
|
||||||
* device instance $22 r0 *1 0,0 RCLS
|
* device instance $22 r0 *1 0,0
|
||||||
R$22 1 23 0
|
R$22 1 23 0
|
||||||
* device instance $23 r0 *1 0,0 RCLS
|
* device instance $23 r0 *1 0,0
|
||||||
R$23 1 24 0
|
R$23 1 24 0
|
||||||
* device instance $24 r0 *1 0,0 RCLS
|
* device instance $24 r0 *1 0,0
|
||||||
R$24 1 25 0
|
R$24 1 25 0
|
||||||
* device instance $25 r0 *1 0,0 RCLS
|
* device instance $25 r0 *1 0,0
|
||||||
R$25 1 26 0
|
R$25 1 26 0
|
||||||
* device instance $26 r0 *1 0,0 RCLS
|
* device instance $26 r0 *1 0,0
|
||||||
R$26 1 27 0
|
R$26 1 27 0
|
||||||
* device instance $27 r0 *1 0,0 RCLS
|
* device instance $27 r0 *1 0,0
|
||||||
R$27 1 28 0
|
R$27 1 28 0
|
||||||
* device instance $28 r0 *1 0,0 RCLS
|
* device instance $28 r0 *1 0,0
|
||||||
R$28 1 29 0
|
R$28 1 29 0
|
||||||
* device instance $29 r0 *1 0,0 RCLS
|
* device instance $29 r0 *1 0,0
|
||||||
R$29 1 30 0
|
R$29 1 30 0
|
||||||
* device instance $30 r0 *1 0,0 RCLS
|
* device instance $30 r0 *1 0,0
|
||||||
R$30 1 31 0
|
R$30 1 31 0
|
||||||
* device instance $31 r0 *1 0,0 RCLS
|
* device instance $31 r0 *1 0,0
|
||||||
R$31 1 32 0
|
R$31 1 32 0
|
||||||
* device instance $32 r0 *1 0,0 RCLS
|
* device instance $32 r0 *1 0,0
|
||||||
R$32 1 33 0
|
R$32 1 33 0
|
||||||
* device instance $33 r0 *1 0,0 RCLS
|
* device instance $33 r0 *1 0,0
|
||||||
R$33 1 34 0
|
R$33 1 34 0
|
||||||
* device instance $34 r0 *1 0,0 RCLS
|
* device instance $34 r0 *1 0,0
|
||||||
R$34 1 35 0
|
R$34 1 35 0
|
||||||
* device instance $35 r0 *1 0,0 RCLS
|
* device instance $35 r0 *1 0,0
|
||||||
R$35 1 36 0
|
R$35 1 36 0
|
||||||
* device instance $36 r0 *1 0,0 RCLS
|
* device instance $36 r0 *1 0,0
|
||||||
R$36 1 37 0
|
R$36 1 37 0
|
||||||
* device instance $37 r0 *1 0,0 RCLS
|
* device instance $37 r0 *1 0,0
|
||||||
R$37 1 38 0
|
R$37 1 38 0
|
||||||
* device instance $38 r0 *1 0,0 RCLS
|
* device instance $38 r0 *1 0,0
|
||||||
R$38 1 39 0
|
R$38 1 39 0
|
||||||
* device instance $39 r0 *1 0,0 RCLS
|
* device instance $39 r0 *1 0,0
|
||||||
R$39 1 40 0
|
R$39 1 40 0
|
||||||
* device instance $40 r0 *1 0,0 RCLS
|
* device instance $40 r0 *1 0,0
|
||||||
R$40 1 41 0
|
R$40 1 41 0
|
||||||
* device instance $41 r0 *1 0,0 RCLS
|
* device instance $41 r0 *1 0,0
|
||||||
R$41 1 42 0
|
R$41 1 42 0
|
||||||
* device instance $42 r0 *1 0,0 RCLS
|
* device instance $42 r0 *1 0,0
|
||||||
R$42 1 43 0
|
R$42 1 43 0
|
||||||
* device instance $43 r0 *1 0,0 RCLS
|
* device instance $43 r0 *1 0,0
|
||||||
R$43 1 44 0
|
R$43 1 44 0
|
||||||
* device instance $44 r0 *1 0,0 RCLS
|
* device instance $44 r0 *1 0,0
|
||||||
R$44 1 45 0
|
R$44 1 45 0
|
||||||
* device instance $45 r0 *1 0,0 RCLS
|
* device instance $45 r0 *1 0,0
|
||||||
R$45 1 46 0
|
R$45 1 46 0
|
||||||
* device instance $46 r0 *1 0,0 RCLS
|
* device instance $46 r0 *1 0,0
|
||||||
R$46 1 47 0
|
R$46 1 47 0
|
||||||
* device instance $47 r0 *1 0,0 RCLS
|
* device instance $47 r0 *1 0,0
|
||||||
R$47 1 48 0
|
R$47 1 48 0
|
||||||
* device instance $48 r0 *1 0,0 RCLS
|
* device instance $48 r0 *1 0,0
|
||||||
R$48 1 49 0
|
R$48 1 49 0
|
||||||
* device instance $49 r0 *1 0,0 RCLS
|
* device instance $49 r0 *1 0,0
|
||||||
R$49 1 50 0
|
R$49 1 50 0
|
||||||
* device instance $50 r0 *1 0,0 RCLS
|
* device instance $50 r0 *1 0,0
|
||||||
R$50 1 51 0
|
R$50 1 51 0
|
||||||
* device instance $51 r0 *1 0,0 RCLS
|
* device instance $51 r0 *1 0,0
|
||||||
R$51 1 52 0
|
R$51 1 52 0
|
||||||
* device instance $52 r0 *1 0,0 RCLS
|
* device instance $52 r0 *1 0,0
|
||||||
R$52 1 53 0
|
R$52 1 53 0
|
||||||
* device instance $53 r0 *1 0,0 RCLS
|
* device instance $53 r0 *1 0,0
|
||||||
R$53 1 54 0
|
R$53 1 54 0
|
||||||
* device instance $54 r0 *1 0,0 RCLS
|
* device instance $54 r0 *1 0,0
|
||||||
R$54 1 55 0
|
R$54 1 55 0
|
||||||
* device instance $55 r0 *1 0,0 RCLS
|
* device instance $55 r0 *1 0,0
|
||||||
R$55 1 56 0
|
R$55 1 56 0
|
||||||
* device instance $56 r0 *1 0,0 RCLS
|
* device instance $56 r0 *1 0,0
|
||||||
R$56 1 57 0
|
R$56 1 57 0
|
||||||
* device instance $57 r0 *1 0,0 RCLS
|
* device instance $57 r0 *1 0,0
|
||||||
R$57 1 58 0
|
R$57 1 58 0
|
||||||
* device instance $58 r0 *1 0,0 RCLS
|
* device instance $58 r0 *1 0,0
|
||||||
R$58 1 59 0
|
R$58 1 59 0
|
||||||
* device instance $59 r0 *1 0,0 RCLS
|
* device instance $59 r0 *1 0,0
|
||||||
R$59 1 60 0
|
R$59 1 60 0
|
||||||
* device instance $60 r0 *1 0,0 RCLS
|
* device instance $60 r0 *1 0,0
|
||||||
R$60 1 61 0
|
R$60 1 61 0
|
||||||
* device instance $61 r0 *1 0,0 RCLS
|
* device instance $61 r0 *1 0,0
|
||||||
R$61 1 62 0
|
R$61 1 62 0
|
||||||
* device instance $62 r0 *1 0,0 RCLS
|
* device instance $62 r0 *1 0,0
|
||||||
R$62 1 63 0
|
R$62 1 63 0
|
||||||
* device instance $63 r0 *1 0,0 RCLS
|
* device instance $63 r0 *1 0,0
|
||||||
R$63 1 64 0
|
R$63 1 64 0
|
||||||
* device instance $64 r0 *1 0,0 RCLS
|
* device instance $64 r0 *1 0,0
|
||||||
R$64 1 65 0
|
R$64 1 65 0
|
||||||
* device instance $65 r0 *1 0,0 RCLS
|
* device instance $65 r0 *1 0,0
|
||||||
R$65 1 66 0
|
R$65 1 66 0
|
||||||
* device instance $66 r0 *1 0,0 RCLS
|
* device instance $66 r0 *1 0,0
|
||||||
R$66 1 67 0
|
R$66 1 67 0
|
||||||
* device instance $67 r0 *1 0,0 RCLS
|
* device instance $67 r0 *1 0,0
|
||||||
R$67 1 68 0
|
R$67 1 68 0
|
||||||
* device instance $68 r0 *1 0,0 RCLS
|
* device instance $68 r0 *1 0,0
|
||||||
R$68 1 69 0
|
R$68 1 69 0
|
||||||
* device instance $69 r0 *1 0,0 RCLS
|
* device instance $69 r0 *1 0,0
|
||||||
R$69 1 70 0
|
R$69 1 70 0
|
||||||
* device instance $70 r0 *1 0,0 RCLS
|
* device instance $70 r0 *1 0,0
|
||||||
R$70 1 71 0
|
R$70 1 71 0
|
||||||
* device instance $71 r0 *1 0,0 RCLS
|
* device instance $71 r0 *1 0,0
|
||||||
R$71 1 72 0
|
R$71 1 72 0
|
||||||
* device instance $72 r0 *1 0,0 RCLS
|
* device instance $72 r0 *1 0,0
|
||||||
R$72 1 73 0
|
R$72 1 73 0
|
||||||
* device instance $73 r0 *1 0,0 RCLS
|
* device instance $73 r0 *1 0,0
|
||||||
R$73 1 74 0
|
R$73 1 74 0
|
||||||
* device instance $74 r0 *1 0,0 RCLS
|
* device instance $74 r0 *1 0,0
|
||||||
R$74 1 75 0
|
R$74 1 75 0
|
||||||
* device instance $75 r0 *1 0,0 RCLS
|
* device instance $75 r0 *1 0,0
|
||||||
R$75 1 76 0
|
R$75 1 76 0
|
||||||
* device instance $76 r0 *1 0,0 RCLS
|
* device instance $76 r0 *1 0,0
|
||||||
R$76 1 77 0
|
R$76 1 77 0
|
||||||
* device instance $77 r0 *1 0,0 RCLS
|
* device instance $77 r0 *1 0,0
|
||||||
R$77 1 78 0
|
R$77 1 78 0
|
||||||
* device instance $78 r0 *1 0,0 RCLS
|
* device instance $78 r0 *1 0,0
|
||||||
R$78 1 79 0
|
R$78 1 79 0
|
||||||
* device instance $79 r0 *1 0,0 RCLS
|
* device instance $79 r0 *1 0,0
|
||||||
R$79 1 80 0
|
R$79 1 80 0
|
||||||
* device instance $80 r0 *1 0,0 RCLS
|
* device instance $80 r0 *1 0,0
|
||||||
R$80 1 81 0
|
R$80 1 81 0
|
||||||
* device instance $81 r0 *1 0,0 RCLS
|
* device instance $81 r0 *1 0,0
|
||||||
R$81 1 82 0
|
R$81 1 82 0
|
||||||
* device instance $82 r0 *1 0,0 RCLS
|
* device instance $82 r0 *1 0,0
|
||||||
R$82 1 83 0
|
R$82 1 83 0
|
||||||
* device instance $83 r0 *1 0,0 RCLS
|
* device instance $83 r0 *1 0,0
|
||||||
R$83 1 84 0
|
R$83 1 84 0
|
||||||
* device instance $84 r0 *1 0,0 RCLS
|
* device instance $84 r0 *1 0,0
|
||||||
R$84 1 85 0
|
R$84 1 85 0
|
||||||
* device instance $85 r0 *1 0,0 RCLS
|
* device instance $85 r0 *1 0,0
|
||||||
R$85 1 86 0
|
R$85 1 86 0
|
||||||
* device instance $86 r0 *1 0,0 RCLS
|
* device instance $86 r0 *1 0,0
|
||||||
R$86 1 87 0
|
R$86 1 87 0
|
||||||
* device instance $87 r0 *1 0,0 RCLS
|
* device instance $87 r0 *1 0,0
|
||||||
R$87 1 88 0
|
R$87 1 88 0
|
||||||
* device instance $88 r0 *1 0,0 RCLS
|
* device instance $88 r0 *1 0,0
|
||||||
R$88 1 89 0
|
R$88 1 89 0
|
||||||
* device instance $89 r0 *1 0,0 RCLS
|
* device instance $89 r0 *1 0,0
|
||||||
R$89 1 90 0
|
R$89 1 90 0
|
||||||
* device instance $90 r0 *1 0,0 RCLS
|
* device instance $90 r0 *1 0,0
|
||||||
R$90 1 91 0
|
R$90 1 91 0
|
||||||
* device instance $91 r0 *1 0,0 RCLS
|
* device instance $91 r0 *1 0,0
|
||||||
R$91 1 92 0
|
R$91 1 92 0
|
||||||
* device instance $92 r0 *1 0,0 RCLS
|
* device instance $92 r0 *1 0,0
|
||||||
R$92 1 93 0
|
R$92 1 93 0
|
||||||
* device instance $93 r0 *1 0,0 RCLS
|
* device instance $93 r0 *1 0,0
|
||||||
R$93 1 94 0
|
R$93 1 94 0
|
||||||
* device instance $94 r0 *1 0,0 RCLS
|
* device instance $94 r0 *1 0,0
|
||||||
R$94 1 95 0
|
R$94 1 95 0
|
||||||
* device instance $95 r0 *1 0,0 RCLS
|
* device instance $95 r0 *1 0,0
|
||||||
R$95 1 96 0
|
R$95 1 96 0
|
||||||
* device instance $96 r0 *1 0,0 RCLS
|
* device instance $96 r0 *1 0,0
|
||||||
R$96 1 97 0
|
R$96 1 97 0
|
||||||
* device instance $97 r0 *1 0,0 RCLS
|
* device instance $97 r0 *1 0,0
|
||||||
R$97 1 98 0
|
R$97 1 98 0
|
||||||
* device instance $98 r0 *1 0,0 RCLS
|
* device instance $98 r0 *1 0,0
|
||||||
R$98 1 99 0
|
R$98 1 99 0
|
||||||
* device instance $99 r0 *1 0,0 RCLS
|
* device instance $99 r0 *1 0,0
|
||||||
R$99 1 100 0
|
R$99 1 100 0
|
||||||
* device instance $100 r0 *1 0,0 RCLS
|
* device instance $100 r0 *1 0,0
|
||||||
R$100 1 101 0
|
R$100 1 101 0
|
||||||
.ENDS
|
.ENDS
|
||||||
+ C1withaverylongextensionthatgoesbeyondmultiplelinesunlessipasteeverythingtogetherwhichmakesithardtoreadbutexactlythatisthereasonwhyiwriteitthisway
|
+ C1withaverylongextensionthatgoesbeyondmultiplelinesunlessipasteeverythingtogetherwhichmakesithardtoreadbutexactlythatisthereasonwhyiwriteitthisway
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
* net 2 n2
|
* net 2 n2
|
||||||
* net 3 n3
|
* net 3 n3
|
||||||
* device instance $1 r0 *1 0,0 RCLS
|
* device instance $1 r0 *1 0,0 RCLS
|
||||||
R$1 1 3 1.7
|
R$1 1 3 1.7 RCLS
|
||||||
* device instance $2 r0 *1 0,0 RCLS
|
* device instance $2 r0 *1 0,0 RCLS
|
||||||
R$2 3 2 4.2e-05
|
R$2 3 2 4.2e-05 RCLS
|
||||||
.ENDS C1
|
.ENDS C1
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
* written by unit test
|
||||||
|
|
||||||
|
* cell C1
|
||||||
|
* pin p1
|
||||||
|
* pin p2
|
||||||
|
.SUBCKT C1 1 2
|
||||||
|
* net 1 n1
|
||||||
|
* net 2 n2
|
||||||
|
* net 3 n3
|
||||||
|
* device instance $1 r0 *1 0,0 RCLS
|
||||||
|
R$1 1 3 3 1.7 RCLS
|
||||||
|
* device instance $2 r0 *1 0,0 RCLS
|
||||||
|
R$2 3 2 3 4.2e-05 RCLS
|
||||||
|
.ENDS C1
|
||||||
|
|
@ -16,10 +16,10 @@
|
||||||
* net 3 n3
|
* net 3 n3
|
||||||
* device instance $1 r0 *1 0,0 RCLS
|
* device instance $1 r0 *1 0,0 RCLS
|
||||||
*** Before device $1
|
*** Before device $1
|
||||||
R$1 1 3 1.7
|
R$1 1 3 1.7 RCLS
|
||||||
*** After device $1
|
*** After device $1
|
||||||
* device instance $2 r0 *1 0,0 RCLS
|
* device instance $2 r0 *1 0,0 RCLS
|
||||||
*** Before device $2
|
*** Before device $2
|
||||||
R$2 3 2 4.2e-05
|
R$2 3 2 4.2e-05 RCLS
|
||||||
*** After device $2
|
*** After device $2
|
||||||
.ENDS C1
|
.ENDS C1
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
* net 2 n2
|
* net 2 n2
|
||||||
* net 3 n3
|
* net 3 n3
|
||||||
* device instance $1 r0 *1 0,0 CCLS
|
* device instance $1 r0 *1 0,0 CCLS
|
||||||
C$1 1 3 1.7e-12
|
C$1 1 3 1.7e-12 CCLS
|
||||||
* device instance $2 r0 *1 0,0 CCLS
|
* device instance $2 r0 *1 0,0 CCLS
|
||||||
C$2 3 2 4.2e-14
|
C$2 3 2 4.2e-14 CCLS
|
||||||
.ENDS C1
|
.ENDS C1
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
* written by unit test
|
||||||
|
|
||||||
|
* cell C1
|
||||||
|
* pin p1
|
||||||
|
* pin p2
|
||||||
|
.SUBCKT C1 1 2
|
||||||
|
* net 1 n1
|
||||||
|
* net 2 n2
|
||||||
|
* net 3 n3
|
||||||
|
* device instance $1 r0 *1 0,0
|
||||||
|
C$1 1 3 1.7e-12
|
||||||
|
* device instance $2 r0 *1 0,0
|
||||||
|
C$2 3 2 4.2e-14
|
||||||
|
.ENDS C1
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
* written by unit test
|
||||||
|
|
||||||
|
* cell C1
|
||||||
|
* pin p1
|
||||||
|
* pin p2
|
||||||
|
.SUBCKT C1 1 2
|
||||||
|
* net 1 n1
|
||||||
|
* net 2 n2
|
||||||
|
* net 3 n3
|
||||||
|
* device instance $1 r0 *1 0,0 CCLS
|
||||||
|
C$1 1 3 3 1.7e-12 CCLS
|
||||||
|
* device instance $2 r0 *1 0,0 CCLS
|
||||||
|
C$2 3 2 3 4.2e-14 CCLS
|
||||||
|
.ENDS C1
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
* written by unit test
|
||||||
|
|
||||||
|
* cell C1
|
||||||
|
* pin p1
|
||||||
|
* pin p2
|
||||||
|
.SUBCKT C1 1 2
|
||||||
|
* net 1 n1
|
||||||
|
* net 2 n2
|
||||||
|
* net 3 n3
|
||||||
|
* device instance $1 r0 *1 0,0
|
||||||
|
C$1 1 3 3 1.7e-12
|
||||||
|
* device instance $2 r0 *1 0,0
|
||||||
|
C$2 3 2 3 4.2e-14
|
||||||
|
.ENDS C1
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
* net 2 n2
|
* net 2 n2
|
||||||
* net 3 n3
|
* net 3 n3
|
||||||
* device instance $1 r0 *1 0,0 LCLS
|
* device instance $1 r0 *1 0,0 LCLS
|
||||||
L$1 1 3 1.7e-10
|
L$1 1 3 1.7e-10 LCLS
|
||||||
* device instance $2 r0 *1 0,0 LCLS
|
* device instance $2 r0 *1 0,0 LCLS
|
||||||
L$2 3 2 4.2e-08
|
L$2 3 2 4.2e-08 LCLS
|
||||||
.ENDS C1
|
.ENDS C1
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,30 @@ class MyNetlistSpiceReaderDelegate < RBA::NetlistSpiceReaderDelegate
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class MyNetlistSpiceReaderDelegate2 < MyNetlistSpiceReaderDelegate
|
||||||
|
|
||||||
|
def start(netlist)
|
||||||
|
netlist.description = "Read by MyDelegate2"
|
||||||
|
end
|
||||||
|
|
||||||
|
def finish(netlist)
|
||||||
|
netlist.description = "Read by MyDelegate2 (sucessfully)"
|
||||||
|
end
|
||||||
|
|
||||||
|
def translate_net_name(n)
|
||||||
|
return n == "VDD" ? "VXX" : super
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_element(s, element)
|
||||||
|
data = super
|
||||||
|
if element == "R"
|
||||||
|
data.model_name = "WIDERSTAND"
|
||||||
|
end
|
||||||
|
data
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
class DBNetlistReaderTests_TestClass < TestBase
|
class DBNetlistReaderTests_TestClass < TestBase
|
||||||
|
|
||||||
def test_1_Basic
|
def test_1_Basic
|
||||||
|
|
@ -107,6 +131,37 @@ END
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_1b_Basic
|
||||||
|
|
||||||
|
nl = RBA::Netlist::new
|
||||||
|
|
||||||
|
input = File.join($ut_testsrc, "testdata", "algo", "nreader6.cir")
|
||||||
|
|
||||||
|
mydelegate = MyNetlistSpiceReaderDelegate2::new
|
||||||
|
reader = RBA::NetlistSpiceReader::new(mydelegate)
|
||||||
|
# the delegate is kept by the SPICE writer ..
|
||||||
|
mydelegate = nil
|
||||||
|
GC.start
|
||||||
|
nl.read(input, reader)
|
||||||
|
|
||||||
|
assert_equal(nl.description, "Read by MyDelegate2 (sucessfully)")
|
||||||
|
|
||||||
|
assert_equal(nl.to_s, <<"END")
|
||||||
|
circuit SUBCKT ($1=$1,A=A,VXX=VXX,Z=Z,GND=GND,GND$1=GND$1);
|
||||||
|
device HVPMOS $1 (S=VXX,G=$3,D=Z,B=$1) (L=0.3,W=1.5,AS=0.27,AD=0.27,PS=3.24,PD=3.24);
|
||||||
|
device HVPMOS $2 (S=VXX,G=A,D=$3,B=$1) (L=0.3,W=1.5,AS=0.27,AD=0.27,PS=3.24,PD=3.24);
|
||||||
|
device HVNMOS $3 (S=GND,G=$3,D=GND,B=GND$1) (L=1.695,W=3.18,AS=0,AD=0,PS=9,PD=9);
|
||||||
|
device HVNMOS $4 (S=GND,G=$3,D=Z,B=GND$1) (L=0.6,W=0.6,AS=0.285,AD=0.285,PS=1.74,PD=1.74);
|
||||||
|
device HVNMOS $5 (S=GND,G=A,D=$3,B=GND$1) (L=0.6,W=0.6,AS=0.285,AD=0.285,PS=2.64,PD=2.64);
|
||||||
|
device WIDERSTAND $1 (A=A,B=Z) (R=100000,L=0,W=0,A=0,P=0);
|
||||||
|
end;
|
||||||
|
circuit .TOP ();
|
||||||
|
subcircuit SUBCKT SUBCKT ($1=IN,A=OUT,VXX=VXX,Z=Z,GND=VSS,GND$1=VSS);
|
||||||
|
end;
|
||||||
|
END
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
def test_2_WithError
|
def test_2_WithError
|
||||||
|
|
||||||
nl = RBA::Netlist::new
|
nl = RBA::Netlist::new
|
||||||
|
|
@ -136,6 +191,50 @@ END
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_3_delegateHelpers
|
||||||
|
|
||||||
|
dg = RBA::NetlistSpiceReaderDelegate::new
|
||||||
|
assert_equal(dg.value_from_string("xy").inspect, "nil")
|
||||||
|
assert_equal(dg.value_from_string("17.5").inspect, "17.5")
|
||||||
|
assert_equal(dg.value_from_string("1k").inspect, "1000.0")
|
||||||
|
assert_equal(dg.value_from_string("1pF*2.5").inspect, "2.5e-12")
|
||||||
|
assert_equal(dg.value_from_string("(1+3)*2").inspect, "8.0")
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_4_ParseElementData
|
||||||
|
|
||||||
|
pd = RBA::ParseElementData::new
|
||||||
|
pd.model_name = "a"
|
||||||
|
assert_equal(pd.model_name, "a")
|
||||||
|
pd.value = 42
|
||||||
|
assert_equal(pd.value, 42)
|
||||||
|
pd.net_names = [ "x", "y", "z" ]
|
||||||
|
assert_equal(pd.net_names.join(","), "x,y,z")
|
||||||
|
pd.parameters = { "A" => 17.5, "B" => 1 }
|
||||||
|
assert_equal(pd.parameters.inspect, "{\"A\"=>17.5, \"B\"=>1.0}")
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_5_ParseElementComponentsData
|
||||||
|
|
||||||
|
pd = RBA::ParseElementComponentsData::new
|
||||||
|
pd.strings = [ "x", "y", "z" ]
|
||||||
|
assert_equal(pd.strings.join(","), "x,y,z")
|
||||||
|
pd.parameters = { "A" => 17.5, "B" => 1 }
|
||||||
|
assert_equal(pd.parameters.inspect, "{\"A\"=>17.5, \"B\"=>1.0}")
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_6_delegateHelpers2
|
||||||
|
|
||||||
|
dg = RBA::NetlistSpiceReaderDelegate::new
|
||||||
|
pd = dg.parse_element_components("17 5 1e-9 a=17 b=1k")
|
||||||
|
assert_equal(pd.strings.join(","), "17,5,1e-9")
|
||||||
|
assert_equal(pd.parameters.inspect, "{\"A\"=>17.0, \"B\"=>1000.0}")
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
load("test_epilogue.rb")
|
load("test_epilogue.rb")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue