Browse Source

Reduce the memory requirements if there is a PDK with

a lot of binning models.
This is a hack and needs testing!
inpcom.c: If an x line, add w and l to the netlist card,
if available.
subckt.c: select a suitable model bin, discard the rest
for each subcircuit, depending on w and l from above.
inpgmod.c: less restrictive equal for real numbers,
allow both min and max boundaries (problem of equating
real numbers), when the selected device has w or l on
the boundary between two model bins.
pre-master-46
Holger Vogt 5 years ago
parent
commit
777cfcf477
  1. 24
      src/frontend/inp.c
  2. 96
      src/frontend/inpcom.c
  3. 169
      src/frontend/subckt.c
  4. 1
      src/frontend/subckt.h
  5. 2
      src/include/ngspice/inpdefs.h
  6. 4
      src/spicelib/parser/inpgmod.c

24
src/frontend/inp.c

@ -41,7 +41,7 @@ Author: 1985 Wayne A. Christopher
#include "numparam/numpaif.h" #include "numparam/numpaif.h"
#include "ngspice/stringskip.h" #include "ngspice/stringskip.h"
#include "ngspice/randnumb.h" #include "ngspice/randnumb.h"
#include "ngspice/compatmode.h"
#define line_free(line, flag) \ #define line_free(line, flag) \
do { \ do { \
@ -749,6 +749,28 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile)
for (ii = 0; ii < 5; ii++) for (ii = 0; ii < 5; ii++)
eval_agauss(deck, statfcn[ii]); eval_agauss(deck, statfcn[ii]);
} }
/* If we have large PDK deck, search for scale option and set
the variable 'scale'*/
if (newcompat.hs || newcompat.spe) {
struct card* scan;
double dscale = 1;
struct card* scoptions = line_reverse(line_nconc(options, inp_deckcopy(com_options)));
for (scan = scoptions; scan; scan = scan->nextcard) {
char* tmpscale = strstr(scan->line, "scale=");
if (tmpscale) {
int err;
tmpscale = tmpscale + 6;
dscale = INPevaluate(&tmpscale, &err, 1);
if (err == 0)
cp_vset("scale", CP_REAL, &dscale);
else
fprintf(stderr, "\nError: Could not set 'scale' variable\n");
break;
}
}
}
/* Now expand subcircuit macros and substitute numparams.*/ /* Now expand subcircuit macros and substitute numparams.*/
if (!cp_getvar("nosubckt", CP_BOOL, NULL, 0)) if (!cp_getvar("nosubckt", CP_BOOL, NULL, 0))
if ((deck->nextcard = inp_subcktexpand(deck->nextcard)) == NULL) { if ((deck->nextcard = inp_subcktexpand(deck->nextcard)) == NULL) {

96
src/frontend/inpcom.c

@ -180,6 +180,7 @@ static struct card *ltspice_compat(struct card *oldcard);
static void ltspice_compat_a(struct card *oldcard); static void ltspice_compat_a(struct card *oldcard);
static void inp_repair_dc_ps(struct card* oldcard); static void inp_repair_dc_ps(struct card* oldcard);
static void inp_get_w_l_x(struct card* oldcard);
#ifndef EXT_ASC #ifndef EXT_ASC
static void utf8_syntax_check(struct card *deck); static void utf8_syntax_check(struct card *deck);
@ -563,6 +564,66 @@ static void new_compat_mode(void)
} }
} }
/* We check x lines for w= and l= and fill in their values.
To be used when expanding subcircuits with binned model cards. */
void inp_get_w_l_x(struct card* card) {
for (; card; card = card->nextcard) {
char* curr_line = card->line;
int skip_control = 0;
char* w = NULL, * l = NULL;
/* exclude any command inside .control ... .endc */
if (ciprefix(".control", curr_line)) {
skip_control++;
continue;
}
else if (ciprefix(".endc", curr_line)) {
skip_control--;
continue;
}
else if (skip_control > 0) {
continue;
}
/* only subcircuit invocations */
if (*curr_line != 'x' && !newcompat.hs && !newcompat.spe) {
card->w = card->l = 0;
continue;
}
w = strstr(curr_line, " w=");
if (w) {
int err;
w = w + 3;
card->w = (float)INPevaluate(&w, &err, 0);
if(err) {
card->w = card->l = 0;
continue;
}
}
else {
card->w = card->l = 0;
continue;
}
l = strstr(curr_line, " l=");
if (l) {
int err;
l = l + 3;
card->l = (float)INPevaluate(&l, &err, 0);
if(err) {
card->w = card->l = 0;
continue;
}
}
else {
card->w = card->l = 0;
continue;
}
}
}
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
Read the entire input file and return a pointer to the first line of Read the entire input file and return a pointer to the first line of
the linked list of 'card' records in data. The pointer is stored in the linked list of 'card' records in data. The pointer is stored in
@ -680,6 +741,10 @@ struct card *inp_readall(FILE *fp, const char *dir_name,
inp_reorder_params(subckt_w_params, cc); inp_reorder_params(subckt_w_params, cc);
/* Special handling for large PDKs: We need to know W and L of
transistor subcircuits by checking their x invokcation */
inp_get_w_l_x(working);
inp_fix_inst_calls_for_numparam(subckt_w_params, working); inp_fix_inst_calls_for_numparam(subckt_w_params, working);
// tprint(working); // tprint(working);
delete_names(subckt_w_params); delete_names(subckt_w_params);
@ -2107,7 +2172,6 @@ static const char *nlist_find(const struct nlist *nlist, const char *name)
return NULL; return NULL;
} }
#if 0
static const char *nlist_model_find( static const char *nlist_model_find(
const struct nlist *nlist, const char *name) const struct nlist *nlist, const char *name)
{ {
@ -2117,7 +2181,6 @@ static const char *nlist_model_find(
return nlist->names[i]; return nlist->names[i];
return NULL; return NULL;
} }
#endif
static void nlist_adjoin(struct nlist *nlist, char *name) static void nlist_adjoin(struct nlist *nlist, char *name)
{ {
@ -2247,7 +2310,7 @@ static void comment_out_unused_subckt_models(struct card *start_card)
char *line = card->line; char *line = card->line;
/* no models embedded in these lines */ /* no models embedded in these lines */
if (strchr("*vibefghkt", *line))
if (strchr(".*vibefghkt", *line))
continue; continue;
/* there is no .subckt, .model or .param inside .control ... .endc */ /* there is no .subckt, .model or .param inside .control ... .endc */
@ -2323,26 +2386,34 @@ static void comment_out_unused_subckt_models(struct card *start_card)
if (remove_subckt) if (remove_subckt)
*line = '*'; /* make line a comment */ *line = '*'; /* make line a comment */
#if 0
else if (has_models &&
(ciprefix(".model", line) || ciprefix(".cmodel", line))) {
char *model_type = get_model_type(line);
char *model_name = get_subckt_model_name(line);
}
/* comment out any unused models */
for (card = start_card; card; card = card->nextcard) {
char* line = card->line;
if (*line == '*')
continue;
if (has_models &&
(ciprefix(".model", line) || ciprefix(".cmodel", line))) {
char* model_type = get_model_type(line);
char* model_name = get_subckt_model_name(line);
/* keep R, L, C models because in addition to no. of terminals the /* keep R, L, C models because in addition to no. of terminals the
value may be given, as in RE1 1 2 800 newres dtemp=5, so model value may be given, as in RE1 1 2 800 newres dtemp=5, so model
name may be token no. 4 or 5, and, if 5, will not be detected name may be token no. 4 or 5, and, if 5, will not be detected
by get_subckt_model_name()*/ by get_subckt_model_name()*/
if (!cieq(model_type, "c") && !cieq(model_type, "l") && if (!cieq(model_type, "c") && !cieq(model_type, "l") &&
!cieq(model_type, "r") &&
!nlist_model_find(used_models, model_name)) {
!cieq(model_type, "r") &&
!nlist_model_find(used_models, model_name)) {
*line = '*'; *line = '*';
} }
tfree(model_type); tfree(model_type);
tfree(model_name); tfree(model_name);
} }
#endif
} }
nlist_destroy(used_subckts); nlist_destroy(used_subckts);
@ -8058,6 +8129,9 @@ static struct card *pspice_compat(struct card *oldcard)
card->line = tprintf( card->line = tprintf(
".model a%s aswitch(%s %s %s %s log=TRUE limit=TRUE)", modname, ".model a%s aswitch(%s %s %s %s log=TRUE limit=TRUE)", modname,
modpar[0], modpar[1], modpar[2], modpar[3]); modpar[0], modpar[1], modpar[2], modpar[3]);
// card->line = tprintf(
// ".model a%s pswitch(%s %s %s %s log=TRUE)", modname,
// modpar[0], modpar[1], modpar[2], modpar[3]);
} }
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
tfree(modpar[i]); tfree(modpar[i]);

169
src/frontend/subckt.c

@ -60,6 +60,7 @@ Modified: 2000 AlansFixes
#include "ngspice/ftedefs.h" #include "ngspice/ftedefs.h"
#include "ngspice/fteinp.h" #include "ngspice/fteinp.h"
#include "ngspice/stringskip.h" #include "ngspice/stringskip.h"
#include "ngspice/compatmode.h"
#include <stdarg.h> #include <stdarg.h>
@ -557,6 +558,10 @@ doit(struct card *deck, wordlist *modnames) {
} }
#endif #endif
double scale;
if (!cp_getvar("scale", CP_REAL, &scale, 0))
scale = 1;
error = 0; error = 0;
/* Second pass: do the replacements. */ /* Second pass: do the replacements. */
do { /* while (!error && numpasses-- && gotone) */ do { /* while (!error && numpasses-- && gotone) */
@ -608,8 +613,114 @@ doit(struct card *deck, wordlist *modnames) {
* instance of a subckt that is defined above at higher level. * instance of a subckt that is defined above at higher level.
*/ */
if (sss) { if (sss) {
// tprint(sss->su_def);
struct card *su_deck = inp_deckcopy_ln(sss->su_def);
/* If we have modern PDKs, we have to reduce the amount of memory required.
We try to reduce the models to the one really used.
Otherwise su_deck is full of unused binning models.*/
// struct card* su_deck = NULL;
if ((newcompat.hs || newcompat.spe) && c->w > 0 && c->l > 0) {
/* extract wmin, wmax, lmin, lmax */
struct card* new_deck = su_deck;
struct card* prev = NULL;
while (su_deck) {
if (!ciprefix(".model", su_deck->line)) {
prev = su_deck;
su_deck = su_deck->nextcard;
continue;
}
char* curr_line = su_deck->line;
float fwmin, fwmax, flmin, flmax;
char *wmin = strstr(curr_line, " wmin=");
if (wmin) {
int err;
wmin = wmin + 6;
fwmin = (float)INPevaluate(&wmin, &err, 0);
if (err) {
prev = su_deck;
su_deck = su_deck->nextcard;
continue;
}
}
else {
prev = su_deck;
su_deck = su_deck->nextcard;
continue;
}
char *wmax = strstr(curr_line, " wmax=");
if (wmax) {
int err;
wmax = wmax + 6;
fwmax = (float)INPevaluate(&wmax, &err, 0);
if (err) {
prev = su_deck;
su_deck = su_deck->nextcard;
continue;
}
}
else {
prev = su_deck;
su_deck = su_deck->nextcard;
continue;
}
char* lmin = strstr(curr_line, " lmin=");
if (lmin) {
int err;
lmin = lmin + 6;
flmin = (float)INPevaluate(&lmin, &err, 0);
if (err) {
prev = su_deck;
su_deck = su_deck->nextcard;
continue;
}
}
else {
prev = su_deck;
su_deck = su_deck->nextcard;
continue;
}
char* lmax = strstr(curr_line, " lmax=");
if (lmax) {
int err;
lmax = lmax + 6;
flmax = (float)INPevaluate(&lmax, &err, 0);
if (err) {
prev = su_deck;
su_deck = su_deck->nextcard;
continue;
}
}
else {
prev = su_deck;
su_deck = su_deck->nextcard;
continue;
}
float csl = (float)scale * c->l;
float csw = (float)scale * c->w;
if (csl >= flmin && csl < flmax && csw >= fwmin && csw < fwmax) {
/* use the current .model card */
prev = su_deck;
su_deck = su_deck->nextcard;
continue;
}
else {
struct card* tmpcard = su_deck->nextcard;
line_free_x(prev->nextcard, FALSE);
su_deck = prev->nextcard = tmpcard;
}
}
su_deck = new_deck;
}
if (!su_deck) {
fprintf(stderr, "\nError: Could not find a model for device %s in subcircuit %s\n",
scname, sss->su_name);
controlled_exit(1);
}
struct card *su_deck = inp_deckcopy(sss->su_def);
struct card *rest_of_c = c->nextcard; struct card *rest_of_c = c->nextcard;
/* Now we have to replace this line with the /* Now we have to replace this line with the
@ -711,6 +822,8 @@ struct card * inp_deckcopy(struct card *deck) {
nd = d = TMALLOC(struct card, 1); nd = d = TMALLOC(struct card, 1);
} }
d->linenum = deck->linenum; d->linenum = deck->linenum;
d->w = deck->w;
d->l = deck->l;
d->line = copy(deck->line); d->line = copy(deck->line);
if (deck->error) if (deck->error)
d->error = copy(deck->error); d->error = copy(deck->error);
@ -720,7 +833,6 @@ struct card * inp_deckcopy(struct card *deck) {
return (nd); return (nd);
} }
/* /*
* Copy a deck, without the ->actualLine lines, without comment lines, and * Copy a deck, without the ->actualLine lines, without comment lines, and
* without .control section(s). * without .control section(s).
@ -754,6 +866,8 @@ struct card *inp_deckcopy_oc(struct card * deck)
else { /* This is the first card */ else { /* This is the first card */
nd = d = TMALLOC(struct card, 1); nd = d = TMALLOC(struct card, 1);
} }
d->w = deck->w;
d->l = deck->l;
d->linenum_orig = deck->linenum; d->linenum_orig = deck->linenum;
d->linenum = i++; d->linenum = i++;
d->line = copy(deck->line); d->line = copy(deck->line);
@ -770,6 +884,57 @@ struct card *inp_deckcopy_oc(struct card * deck)
return nd; return nd;
} /* end of function inp_deckcopy_oc */ } /* end of function inp_deckcopy_oc */
/*
* Copy a deck, without the ->actualLine lines, without comment lines, and
* without .control section(s).
* First line is always copied (except being .control).
* Keep the line numbers.
*/
struct card* inp_deckcopy_ln(struct card* deck)
{
struct card* d = NULL, * nd = NULL;
int skip_control = 0;
while (deck) {
/* exclude any command inside .control ... .endc */
if (ciprefix(".control", deck->line)) {
skip_control++;
deck = deck->nextcard;
continue;
}
else if (ciprefix(".endc", deck->line)) {
skip_control--;
deck = deck->nextcard;
continue;
}
else if (skip_control > 0) {
deck = deck->nextcard;
continue;
}
if (nd) { /* First card already found */
/* d is the card at the end of the deck */
d = d->nextcard = TMALLOC(struct card, 1);
}
else { /* This is the first card */
nd = d = TMALLOC(struct card, 1);
}
d->w = deck->w;
d->l = deck->l;
d->linenum_orig = deck->linenum_orig;
d->linenum = deck->linenum;
d->line = copy(deck->line);
if (deck->error) {
d->error = copy(deck->error);
}
d->actualLine = NULL;
deck = deck->nextcard;
while (deck && *(deck->line) == '*') { /* skip comments */
deck = deck->nextcard;
}
} /* end of loop over cards in the source deck */
return nd;
} /* end of function inp_deckcopy_ln */
/*------------------------------------------------------------------- /*-------------------------------------------------------------------

1
src/frontend/subckt.h

@ -9,5 +9,6 @@
struct card *inp_subcktexpand(struct card *deck); struct card *inp_subcktexpand(struct card *deck);
struct card *inp_deckcopy(struct card *deck); struct card *inp_deckcopy(struct card *deck);
struct card *inp_deckcopy_oc(struct card *deck); struct card *inp_deckcopy_oc(struct card *deck);
struct card *inp_deckcopy_ln(struct card *deck);
#endif #endif

2
src/include/ngspice/inpdefs.h

@ -82,6 +82,8 @@ struct card {
struct card *nextcard; struct card *nextcard;
struct card *actualLine; struct card *actualLine;
struct nscope *level; struct nscope *level;
float w;
float l;
}; };
/* structure used to save models in after they are read during pass 1 */ /* structure used to save models in after they are read during pass 1 */

4
src/spicelib/parser/inpgmod.c

@ -208,7 +208,7 @@ parse_line(char *line, char *tokens[], int num_tokens, double values[], bool fou
static bool static bool
is_equal(double result, double expectedResult) is_equal(double result, double expectedResult)
{ {
return fabs(result - expectedResult) < 1e-15;
return fabs(result - expectedResult) < 1e-9;
} }
@ -216,7 +216,7 @@ static bool
in_range(double value, double min, double max) in_range(double value, double min, double max)
{ {
/* the standard binning rule is: min <= value < max */ /* the standard binning rule is: min <= value < max */
return is_equal(value, min) || (min < value && value < max);
return is_equal(value, min) || is_equal(value, max) || (min < value && value < max);
} }

Loading…
Cancel
Save