From 429326e13945cfee22ffde23c33621116b2a6e15 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 15 May 2018 23:16:22 +0200 Subject: [PATCH] Add current measurement for device XYZ using I(XYZ) --- src/frontend/inpcom.c | 205 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 204 insertions(+), 1 deletion(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 04b3bed46..b064d355f 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -120,6 +120,7 @@ static char *inp_remove_ws(char *s); static void inp_compat(struct card *deck); static void inp_bsource_compat(struct card *deck); static bool inp_temper_compat(struct card *card); +static void inp_meas_current(struct card *card); static void inp_dot_if(struct card *deck); static char *inp_modify_exp(char* expression); static struct func_temper *inp_new_func(char *funcname, char *funcbody, struct card *card, @@ -579,6 +580,7 @@ inp_readall(FILE *fp, char *dir_name, bool comfile, bool intfile, bool *expr_w_t if (inp_compat_mode != COMPATMODE_SPICE3) { /* Do all the compatibility stuff here */ working = cc->nextcard; + inp_meas_current(working); /* E, G, L, R, C compatibility transformations */ inp_compat(working); working = cc->nextcard; @@ -6055,7 +6057,6 @@ inp_quote_params(struct card *c, struct card *end_c, struct dependency *deps, in Assemble all other tokens in a wordlist, and flatten it to become the new .model line. */ - static void inp_vdmos_model(struct card *deck) { @@ -6099,3 +6100,205 @@ inp_vdmos_model(struct card *deck) } } } + + +/* storage for devices which get voltage source added */ +struct replace_currm +{ + struct card *s_start; + struct card *cline; + char *rtoken; + struct replace_currm *next; +} + + +/* Measure current in node 1 of all devices, e.g. I, B, F, and G. + I(V...) will be ignored, however H, E nonlinear voltage + sources may be converted later + to B source, therefore we need to add current measurement here. + First find all ocurrencies of i(XYZ), store their cards, then + search for XYZ, but only within respective subcircuit, or if + all happens at top level. Other hierarchy is ignored for now. + Replace I(XYZ) bx I(V_XYZ), add voltage source V_XYZ with + suitable extra nodes. +*/ +static void +inp_meas_current(struct card *deck) +{ + struct card *card, *subc_start = NULL, *subc_prev = NULL; + struct replace_currm *new_rep, *act_rep = NULL, *rep = NULL; + char *s, *t, *u, *v; + int skip_control = 0, subs = 0; + + /* scan through deck and find i(xyz), replace by i(v_xyz) */ + for (card = deck; card; card = card->nextcard) { + + char *curr_line = card->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 (*curr_line == '.') { + if (ciprefix(".subckt", curr_line)) { + subs++; + subc_prev = subc_start; + subc_start = card; + } + else if (ciprefix(".ends", curr_line)) { + subs--; + subc_start = subc_prev; + } + else + continue; + } + + if (!strstr(curr_line, "i(")) + continue; + + s = v = stripWhiteSpacesInsideParens(curr_line); + while (s) { + /* i( may occur more than once in a line */ + s = u = strstr(s, "i("); + /* we have found it, but not (in error) at the beginning of the line */ + if (s && s > v) { + /* '{' if at beginning of expression */ + if (is_arith_char(s[-1]) || s[-1] == '{') { + s += 2; + if (*s == 'v') { + // printf("i(v...) found in\n%s\n not converted!\n\n", curr_line); + continue; + } + else { + char *beg_str, *new_str; + get_r_paren(&u); + /* token containing name of devices to be measured */ + t = copy_substring(s, --u); + if (ft_ngdebug) + printf("i(%s) found in\n%s\n\n", t, curr_line); + + /* new entry to the end of struct rep */ + new_rep = TMALLOC(struct replace_currm, 1); + new_rep->s_start = subc_start; + new_rep->next = NULL; + new_rep->cline = card; + new_rep->rtoken = t; + if (act_rep) { + act_rep->next = new_rep; + act_rep = act_rep->next; + } + else + rep = act_rep = new_rep; + /* change line, convert i(XXX) to i(v_XXX) */ + beg_str = copy_substring(v, s); + new_str = tprintf("%s%s%s", beg_str, "v_", s); + if (ft_ngdebug) + printf("converted to\n%s\n\n", new_str); + tfree(curr_line); + tfree(v); + card->line = s = v = new_str; + s++; + tfree(beg_str); + } + } + else + s++; + } + } + } + + /* return if we did not find any i( */ + if (rep == NULL) + return; + + /* scan through all the devices, search for xyz, modify node 1 by adding _vmeas, + add a line with zero voltage v_xyz, having original node 1 and modified node 1. + Do this within the top level or the same level of subcircuit only. */ + new_rep = rep; + for (; rep; rep = rep->next) { + card = rep->s_start; + subs = 0; + if (card) + card = card->nextcard; + else + card = deck; + for (; card; card = card->nextcard) { + char *tok, *new_tok, *node1, *new_line; + char *curr_line = card->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 (*curr_line == '.') { + if (ciprefix(".subckt", curr_line)) + subs++; + else if (ciprefix(".ends", curr_line)) + subs--; + else + continue; + } + if (subs > 0) + continue; + /* We are at now top level or in top level of subcircuit + where i(xyz) has been found */ + tok = gettok(&curr_line); + /* done when end of subcircuit is reached */ + if (eq(".ends", tok) && rep->s_start) + break; + if (eq(rep->rtoken, tok)) { + node1 = gettok(&curr_line); + /* Add _vmeas only once to first device node. + Continue if we already have modified device "tok" */ + if (!strstr(node1, "_vmeas")) { + new_line = tprintf("%s %s_vmeas %s", tok, node1, curr_line); + tfree(card->line); + card->line = new_line; + } + + new_tok = tprintf("v_%s", tok); + /* We have already added a line v_xyz to the deck */ + if (!ciprefix(new_tok, card->nextcard->line)) { + /* add new line */ + new_line = tprintf("%s %s %s_vmeas 0", new_tok, node1, node1); + /* insert new_line after card->line */ + insert_new_line(card, new_line, card->linenum + 1, 0); + } + tfree(new_tok); + tfree(node1); + } + tfree(tok); + } + } + + /* free rep */ + while (new_rep) { + struct replace_currm *repn = new_rep->next; + tfree(new_rep->rtoken); + tfree(new_rep); + new_rep = repn; + } +}