diff --git a/examples/various/res-value-options.cir b/examples/various/res-value-options.cir new file mode 100644 index 000000000..637dcbe85 --- /dev/null +++ b/examples/various/res-value-options.cir @@ -0,0 +1,25 @@ +ngspice resistor/capacitor value check +* set ngbehavior=lt required in spice.rc +R1 1 0 2m5 +R2 1 0 2meg5 +R3 1 0 2M5 +R4 1 0 2R5 +R5 1 0 27R56 +R6 1 0 1e5 +R7 1 0 56Ohms +R8 1 0 1.7Meg +R9 1 0 1e-3wwww +R10 1 0 -1.7 +V1 1 0 1 +C1 1 0 1u2 +C2 1 0 3m3 +C3 1 0 4f7 +C5 1 0 15p +C6 1 0 2200u +C7 1 0 2200u2nnn + +.control +show r c +.endc + +.end diff --git a/src/include/ngspice/inpdefs.h b/src/include/ngspice/inpdefs.h index 40c9f5494..6de033ad6 100644 --- a/src/include/ngspice/inpdefs.h +++ b/src/include/ngspice/inpdefs.h @@ -116,6 +116,7 @@ char *INPerrCat(char *, char *); char *INPstrCat(char *, char, char *); char *INPerror(int); double INPevaluate(char **, int *, int); +double INPevaluateRKM(char **, int *, int); char *INPfindLev(char *, int *); char *INPgetMod(CKTcircuit *, char *, INPmodel **, INPtables *); char *INPgetModBin(CKTcircuit *, char *, INPmodel **, INPtables *, char *); diff --git a/src/spicelib/parser/inp2c.c b/src/spicelib/parser/inp2c.c index 15eef67e4..0a1b12d51 100644 --- a/src/spicelib/parser/inp2c.c +++ b/src/spicelib/parser/inp2c.c @@ -8,6 +8,7 @@ Author: 1988 Thomas L. Quarles #include "ngspice/inpdefs.h" #include "ngspice/inpmacs.h" #include "ngspice/fteext.h" +#include "ngspice/compatmode.h" #include "inpxx.h" void INP2C(CKTcircuit *ckt, INPtables * tab, struct card *current) @@ -54,7 +55,12 @@ void INP2C(CKTcircuit *ckt, INPtables * tab, struct card *current) INPtermInsert(ckt, &nname1, tab, &node1); INPgetNetTok(&line, &nname2, 1); INPtermInsert(ckt, &nname2, tab, &node2); - val = INPevaluate(&line, &error1, 1); + + /* enable reading values like 4u7 */ + if (newcompat.lt) + val = INPevaluateRKM(&line, &error1, 1); /* [] */ + else + val = INPevaluate(&line, &error1, 1); /* [] */ saveline = line; diff --git a/src/spicelib/parser/inp2r.c b/src/spicelib/parser/inp2r.c index 2b724a3ca..22d6088b1 100644 --- a/src/spicelib/parser/inp2r.c +++ b/src/spicelib/parser/inp2r.c @@ -14,6 +14,7 @@ Remarks: This code is based on a version written by Serban Popescu which #include "ngspice/fteext.h" #include "inpxx.h" #include "ngspice/stringskip.h" +#include "ngspice/compatmode.h" /* undefine to add tracing to this file */ /* #define TRACE */ @@ -63,7 +64,13 @@ void INP2R(CKTcircuit *ckt, INPtables * tab, struct card *current) INPtermInsert(ckt, &nname1, tab, &node1); INPgetNetTok(&line, &nname2, 1); /* */ INPtermInsert(ckt, &nname2, tab, &node2); - val = INPevaluate(&line, &error1, 1); /* [] */ + + /* enable reading values like 4k7 */ + if (newcompat.lt) + val = INPevaluateRKM(&line, &error1, 1); /* [] */ + else + val = INPevaluate(&line, &error1, 1); /* [] */ + /* either not a number -> model, or * follows a number, so must be a model name * -> MUST be a model name (or null) diff --git a/src/spicelib/parser/inpeval.c b/src/spicelib/parser/inpeval.c index bb8fe9d84..5396e1551 100644 --- a/src/spicelib/parser/inpeval.c +++ b/src/spicelib/parser/inpeval.c @@ -197,3 +197,233 @@ INPevaluate(char **line, int *error, int gobble) return (sign * mantis * pow(10.0, (double) (expo1 + expsgn * expo2))); } + + +/* In addition to fcn INPevaluate() above, allow values like 4k7, + similar to the RKM code (used bei inp2c and inp2r) */ +double +INPevaluateRKM(char** line, int* error, int gobble) +/* gobble: non-zero to gobble rest of token, zero to leave it alone */ +{ + char* token; + char* here; + double mantis; + double deci; + int expo1; + int expo2; + int expo3; + int sign; + int expsgn; + char* tmpline; + bool hasmulti = FALSE; + + /* setup */ + tmpline = *line; + + if (gobble) { + /* MW. INPgetUTok should be called with gobble=0 or it make + * errors in v(1,2) exp */ + *error = INPgetUTok(line, &token, 0); + if (*error) + return (0.0); + } + else { + token = *line; + *error = 0; + } + + mantis = 0; + deci = 0; + expo1 = 0; + expo2 = 0; + expo3 = 0; + sign = 1; + expsgn = 1; + + /* loop through all of the input token */ + here = token; + + if (*here == '+') + here++; /* plus, so do nothing except skip it */ + else if (*here == '-') { /* minus, so skip it, and change sign */ + here++; + sign = -1; + } + + if ((*here == '\0') || ((!(isdigit_c(*here))) && (*here != '.'))) { + /* number looks like just a sign! */ + *error = 1; + if (gobble) { + FREE(token); + /* back out the 'gettok' operation */ + *line = tmpline; + } + return (0); + } + + while (isdigit_c(*here)) { + /* digit, so accumulate it. */ + mantis = 10 * mantis + *here - '0'; + here++; + } + + if (*here == '\0') { + /* reached the end of token - done. */ + if (gobble) { + FREE(token); + } + else { + *line = here; + } + return ((double)mantis * sign); + } + + if (*here == ':') { + /* ':' is no longer used for subcircuit node numbering + but is part of ternary function a?b:c + FIXME : subcircuit models still use ':' for model numbering + Will this hurt somewhere? */ + if (gobble) { + FREE(token); + } + else { + *line = here; + } + return ((double)mantis * sign); + } + + /* after decimal point! */ + if (*here == '.') { + /* found a decimal point! */ + here++; /* skip to next character */ + + if (*here == '\0') { + /* number ends in the decimal point */ + if (gobble) { + FREE(token); + } + else { + *line = here; + } + return ((double)mantis * sign); + } + + while (isdigit_c(*here)) { + /* digit, so accumulate it. */ + mantis = 10 * mantis + *here - '0'; + expo1 = expo1 - 1; + here++; + } + } + + /* now look for "E","e",etc to indicate an exponent */ + if ((*here == 'E') || (*here == 'e') || (*here == 'D') || (*here == 'd')) { + + /* have an exponent, so skip the e */ + here++; + + /* now look for exponent sign */ + if (*here == '+') + here++; /* just skip + */ + else if (*here == '-') { + here++; /* skip over minus sign */ + expsgn = -1; /* and make a negative exponent */ + /* now look for the digits of the exponent */ + } + + while (isdigit_c(*here)) { + expo2 = 10 * expo2 + *here - '0'; + here++; + } + } + + /* now we have all of the numeric part of the number, time to + * look for the scale factor (alphabetic) + */ + switch (*here) { + case 't': + case 'T': + expo1 = expo1 + 12; + hasmulti = TRUE; + break; + case 'g': + case 'G': + expo1 = expo1 + 9; + hasmulti = TRUE; + break; + case 'k': + case 'K': + expo1 = expo1 + 3; + hasmulti = TRUE; + break; + case 'u': + case 'U': + expo1 = expo1 - 6; + hasmulti = TRUE; + break; + case 'r': + case 'R': + expo1 = expo1; + hasmulti = TRUE; + break; + case 'n': + case 'N': + expo1 = expo1 - 9; + hasmulti = TRUE; + break; + case 'p': + case 'P': + expo1 = expo1 - 12; + hasmulti = TRUE; + break; + case 'f': + case 'F': + expo1 = expo1 - 15; + hasmulti = TRUE; + break; + case 'm': + case 'M': + if (((here[1] == 'E') || (here[1] == 'e')) && + ((here[2] == 'G') || (here[2] == 'g'))) + { + expo1 = expo1 + 6; /* Meg */ + here += 2; + hasmulti = TRUE; + } + else if (((here[1] == 'I') || (here[1] == 'i')) && + ((here[2] == 'L') || (here[2] == 'l'))) + { + expo1 = expo1 - 6; + mantis *= 25.4; /* Mil */ + } + else { + expo1 = expo1 - 3; /* m, milli */ + hasmulti = TRUE; + } + break; + default: + break; + } + + /* read a digit after multiplier */ + if (hasmulti) { + here++; + while (isdigit_c(*here)) { + deci = 10 * deci + *here - '0'; + expo3 = expo3 - 1; + here++; + } + mantis = mantis + deci * pow(10.0, (double)expo3); + } + + if (gobble) { + FREE(token); + } + else { + *line = here; + } + + return (sign * mantis * + pow(10.0, (double)(expo1 + expsgn * expo2))); +} +