diff --git a/src/frontend/inp.c b/src/frontend/inp.c index 6c6d878df..9b0453521 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -64,6 +64,7 @@ static wordlist *inp_savecurrents(struct card *deck, struct card *options, void line_free_x(struct card *deck, bool recurse); static void recifeval(struct card *pdeck); static char *upper(register char *string); +static void rem_unused_mos_models(struct card* deck); @@ -75,6 +76,11 @@ void eval_seed_opt(struct card *deck); extern bool ft_batchmode; +/* from inpcom.c */ +extern struct nscope* inp_add_levels(struct card *deck); +extern void comment_out_unused_subckt_models(struct card *deck); +extern void inp_rem_unused_models(struct nscope *root, struct card *deck); + #ifdef SHARED_MODULE extern void exec_controls(wordlist *controls); #endif @@ -864,6 +870,13 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) to wl_first with all terminal currents available on selected devices */ wl_first = inp_savecurrents(deck, options, wl_first, controls); + /* Circuit is flat, all numbers expanded. + So again try to remove unused MOS models. + All binning models are still here when w or l have been + determined by an expression. */ + if (newcompat.hs || newcompat.spe) + rem_unused_mos_models(deck->nextcard); + /* now load deck into ft_curckt -- the current circuit. */ if(inp_dodeck(deck, tt, wl_first, FALSE, options, filename) != 0) return 1; @@ -972,6 +985,21 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) fprintf(stderr, "Warning: Cannot open file debug-out3.txt for saving debug info\n"); } + /* Remove comment lines + if (newcompat.hs || newcompat.spe) { + struct card *prev, *fcard, *tmpdeck; + prev = deck; + tmpdeck = deck->nextcard; + for (fcard = tmpdeck; fcard; fcard = fcard->nextcard) { + if (*(prev->nextcard->line) == '*') { + struct card* tmpcard = fcard->nextcard; + line_free_x(prev->nextcard, FALSE); + fcard = prev->nextcard = tmpcard; + } + prev = fcard; + } + }*/ + /* Now the circuit is defined, so generate the parse trees */ inp_parse_temper_trees(ft_curckt); /* Get the actual data for model and device instance parameters */ @@ -2310,3 +2338,189 @@ eval_agauss(struct card *deck, char *fcn) } } } + +struct mlist { + struct card* mod; + struct card* prevmod; + struct card* prevcard; + char* mname; + float wmin; + float wmax; + float lmin; + float lmax; + struct mlist* nextm; + bool used; + bool checked; +}; + +/* Finally get rid of unused MOS models */ +static void rem_unused_mos_models(struct card* deck) { + struct card *tmpc, *tmppc = NULL; + struct mlist* modellist = NULL, *tmplist; + double scale; + if (!cp_getvar("scale", CP_REAL, &scale, 0)) + scale = 1; + /* the old way to remove unused models */ + struct nscope* root = inp_add_levels(deck); + comment_out_unused_subckt_models(deck); + inp_rem_unused_models(root, deck); + /* remove unused binning models */ + for (tmpc = deck; tmpc; tmppc = tmpc, tmpc = tmpc->nextcard) { + char* curr_line; + char* nline = curr_line = tmpc->line; + if (ciprefix(".model", nline)) { + float fwmin, fwmax, flmin, flmax; + char* wmin = strstr(curr_line, " wmin="); + if (wmin) { + int err; + wmin = wmin + 6; + wmin = skip_ws(wmin); + fwmin = (float)INPevaluate(&wmin, &err, 0); + if (err) { + continue; + } + } + else { + continue; + } + char* wmax = strstr(curr_line, " wmax="); + if (wmax) { + int err; + wmax = wmax + 6; + wmax = skip_ws(wmax); + fwmax = (float)INPevaluate(&wmax, &err, 0); + if (err) { + continue; + } + } + else { + continue; + } + + char* lmin = strstr(curr_line, " lmin="); + if (lmin) { + int err; + lmin = lmin + 6; + lmin = skip_ws(lmin); + flmin = (float)INPevaluate(&lmin, &err, 0); + if (err) { + continue; + } + } + else { + continue; + } + char* lmax = strstr(curr_line, " lmax="); + if (lmax) { + int err; + lmax = lmax + 6; + lmax = skip_ws(lmax); + flmax = (float)INPevaluate(&lmax, &err, 0); + if (err) { + continue; + } + } + else { + continue; + } + + nline = nexttok(nline); + char* modname = gettok(&nline); + struct mlist* newm = TMALLOC(struct mlist, 1); + newm->mname = modname; + newm->mod = tmpc; + newm->prevmod = tmppc; + newm->wmin = newm->wmax = newm->lmin = newm->lmax = 0.; + newm->nextm = NULL; + newm->used = FALSE; + newm->checked = FALSE; + newm->lmax = flmax; + newm->lmin = flmin; + newm->wmax = fwmax; + newm->wmin = fwmin; + + if (!modellist) { + modellist = newm; + } + else { + struct mlist* tmpl = modellist; + modellist = newm; + modellist->nextm = tmpl; + } + modellist->prevcard = tmppc; + } + } + for (tmpc = deck; tmpc; tmpc = tmpc->nextcard) { + char* curr_line = tmpc->line; + /* We only look for MOS devices and extract W and L */ + if (*curr_line == 'm') { + float w = 0., l = 0.; + char* wstr = strstr(curr_line, " w="); + if (wstr) { + int err; + wstr = wstr + 3; + wstr = skip_ws(wstr); + w = (float)INPevaluate(&wstr, &err, 0); + if (err) { + continue; + } + } + char* lstr = strstr(curr_line, " l="); + if (lstr) { + int err; + lstr = lstr + 3; + lstr = skip_ws(lstr); + l = (float)INPevaluate(&lstr, &err, 0); + if (err) { + continue; + } + } + /* what is the device's model name? */ + char* mname = nexttok(curr_line); + int nonodes = 4; + int jj; + for (jj = 0; jj < nonodes; jj++) { + mname = nexttok(mname); + } + mname = gettok(&mname); + /* We now check all models */ + for (tmplist = modellist; tmplist; tmplist = tmplist->nextm) { + if (strstr(tmplist->mname, mname)) { + float ls = l * (float)scale; + float ws = w * (float)scale; + if (tmplist->lmin <= ls && tmplist->lmax >= ls && tmplist->wmin <= ws && tmplist->wmax >= ws) + tmplist->used = TRUE; + else + tmplist->checked = TRUE; + } + else { + tmplist->checked = TRUE; + } + } + tfree(mname); + } + } + + /* Delete the models that have been checked, but are unused */ + for (tmplist = modellist; tmplist; tmplist = tmplist->nextm) { + if (tmplist->checked && !tmplist->used) { + if (tmplist->prevcard == NULL) { + struct card* tmpcard = tmplist->mod; + tmplist->mod = tmplist->mod->nextcard; + line_free_x(tmpcard, FALSE); + } + else { + struct card* tmpcard = tmplist->prevcard; + tmpcard->nextcard = tmplist->mod->nextcard; + line_free_x(tmplist->mod, FALSE); + } + } + } + /* Remove modellist */ + while (modellist) { + struct mlist* tlist = modellist->nextm; + tfree(modellist->mname); + tfree(modellist); + modellist = tlist; + } +}