diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 920fba5e3..094f0fe0a 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -148,7 +148,10 @@ static char *search_plain_identifier(char *str, const char *identifier); void tprint(struct line *deck, int numb); static struct nscope *inp_add_levels(struct line *deck); static char inp_get_elem_ident(char *type); +static void inp_rem_unused_models(struct nscope *root, struct line *deck); static struct line_assoc *find_subckt(struct nscope *scope, const char *name); +static struct modellist *find_model(struct nscope *scope, const char *name); + struct inp_read_t { struct line *cc; @@ -556,6 +559,7 @@ inp_readall(FILE *fp, char *dir_name, bool comfile, bool intfile, bool *expr_w_t inp_remove_excess_ws(working); comment_out_unused_subckt_models(working); + inp_rem_unused_models(root, working); subckt_params_to_param(working); @@ -6535,6 +6539,38 @@ add_subckt(struct nscope *scope, struct line *subckt_line) } +/* linked list of models, includes use info */ +struct modellist +{ + struct line *model; + char *modelname; + bool used; + char elemb; + struct modellist *next; +}; + + +static struct modellist * +find_model_1(struct nscope *scope, const char *name) { + struct modellist *p = scope->models; + for (; p; p = p->next) + if (model_name_match(name, p->modelname)) + break; + return p; +} + + +static struct modellist * +find_model(struct nscope *scope, const char *name) { + for(; scope; scope = scope->next) { + struct modellist *p = find_model_1(scope, name); + if (p) + return p; + } + return NULL; +} + + /* scan through deck and add level information to all struct line * depending on nested subcircuits */ static struct nscope * @@ -6546,6 +6582,7 @@ inp_add_levels(struct line *deck) struct nscope *root = TMALLOC(struct nscope, 1); root->next = NULL; root->subckts = NULL; + root->models = NULL; struct nscope *lvl = root; @@ -6574,6 +6611,7 @@ inp_add_levels(struct line *deck) // lvl->name = ..., or just point to the deck lvl->next = card->level; lvl->subckts = NULL; + lvl->models = NULL; } else if (ciprefix(".ends", curr_line)) { if (lvl == root) { @@ -6656,3 +6694,148 @@ inp_get_elem_ident(char *type) else return 'a'; } + + +static void +rem_unused_xxx(struct nscope *level) +{ + struct modellist *m = level->models; + while (m) { + struct modellist *next_m = m->next; + if (!m->used) + m->model->li_line[0] = '*'; + tfree(m->modelname); + tfree(m); + m = next_m; + } + level->models = NULL; + + struct line_assoc *p = level->subckts; + for (; p; p = p->next) + rem_unused_xxx(p->line->li_next->level); +} + + +static void +mark_all_binned(struct nscope *scope, char *name) +{ + struct modellist *p = scope->models; + + for (; p; p = p->next) + if (model_name_match(name, p->modelname)) + p->used = TRUE; +} + + +static void +inp_rem_unused_models(struct nscope *root, struct line *deck) +{ + struct line *card; + int skip_control = 0; + + /* create a list of .model */ + for (card = deck; card; card = card->li_next) { + + char *curr_line = card->li_line; + + /* 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; + } + + if (*curr_line == '*') + continue; + + if (ciprefix(".model", curr_line)) { + struct modellist *modl_new; + modl_new = TMALLOC(struct modellist, 1); + char *model_type = get_model_type(curr_line); + modl_new->elemb = inp_get_elem_ident(model_type); + modl_new->modelname = get_subckt_model_name(curr_line); + modl_new->model = card; + modl_new->used = FALSE; + modl_new->next = card->level->models; + card->level->models = modl_new; + tfree(model_type); + } + } + + /* scan through all element lines that require or may need a model */ + for (card = deck; card; card = card->li_next) { + + char *curr_line = card->li_line; + + /* 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; + } + + switch (*curr_line) + { + case '*': + case '.': + case 'v': + case 'i': + case 'b': + case 'x': + case 'e': + case 'h': + case 'g': + case 'f': + case 'k': + case 't': + continue; + break; + default: + break; + } + + /* check if correct model name */ + int num_terminals = get_number_terminals(curr_line); + /* num_terminals may be 0 for a elements */ + if ((num_terminals != 0) || (*curr_line == 'a')) { + char *elem_model_name; + if (*curr_line == 'a') + elem_model_name = get_adevice_model_name(curr_line); + else + elem_model_name = get_model_name(curr_line, num_terminals); + + /* ignore certain cases, for example + * C5 node1 node2 42.0 + */ + if (is_a_modelname(elem_model_name)) { + + struct modellist *m = find_model(card->level, elem_model_name); + if (m) { + if (*curr_line != m->elemb) + fprintf(stderr, "warning, model type mismatch\n"); + mark_all_binned(m->model->level, elem_model_name); + } else { + fprintf(stderr, "warning, can't find model %s\n", elem_model_name); + } + + } + + tfree(elem_model_name); + } + } + + // disable unused .model lines, and free the models assoc lists + rem_unused_xxx(root); +} diff --git a/src/include/ngspice/inpdefs.h b/src/include/ngspice/inpdefs.h index a5ee2649e..c1ede7ea9 100644 --- a/src/include/ngspice/inpdefs.h +++ b/src/include/ngspice/inpdefs.h @@ -61,9 +61,12 @@ struct INPtables{ GENmodel *defZmod; }; +struct modellist; + struct nscope { struct nscope *next; struct line_assoc *subckts; + struct modellist *models; }; struct line_assoc {