From 10c6c5c38b6c02dc207219cd78eabc5bf2b281c2 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 1 Jul 2018 16:31:19 +0200 Subject: [PATCH] Convert .param lines containing 'agauss' and others into .func (xxx1() 'agauss()', replace all xxx1 entries by function xxx1(). After subcircuit expansion, replace agauss and others in B-Line by their suitable values. --- src/frontend/inp.c | 156 ++++++++++++++++++++++++++++++- src/frontend/inpcom.c | 210 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 365 insertions(+), 1 deletion(-) diff --git a/src/frontend/inp.c b/src/frontend/inp.c index f4908b4a1..76e4b2d24 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -58,6 +58,7 @@ static void dotifeval(struct card *deck); static wordlist *inp_savecurrents(struct card *deck, struct card *options, wordlist *wl, wordlist *controls); +static void eval_agauss(struct card *deck, char *fcn); void line_free_x(struct card *deck, bool recurse); void create_circbyline(char *line); @@ -378,7 +379,6 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) /* called with *fp == NULL and intfile: we want to load circuit from circarray */ if (fp || intfile) { deck = inp_readall(fp, dir_name, comfile, intfile, &expr_w_temper); - /* files starting with *ng_script are user supplied command files */ if (deck && ciprefix("*ng_script", deck->line)) comfile = TRUE; @@ -599,6 +599,12 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) #ifdef HAS_PROGREP SetAnalyse("Prepare Deck", 0); #endif + /*FIXME This is for the globel param setting only */ + /* replace agauss(x,y,z) in each b-line by suitable value */ + static char *statfcn[] = { "agauss", "gauss", "aunif", "unif", "limit" }; + int ii; + for (ii = 0; ii < 5; ii++) + eval_agauss(deck, statfcn[ii]); /* Now expand subcircuit macros and substitute numparams.*/ if (!cp_getvar("nosubckt", CP_BOOL, NULL, 0)) if ((deck->nextcard = inp_subcktexpand(deck->nextcard)) == NULL) { @@ -678,6 +684,13 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) if (expr_w_temper) inp_parse_temper(deck, &modtlist, &devtlist); + /* replace agauss(x,y,z) in each b-line by suitable value */ + /* FIXME: This is for the local param setting (not yet implemented in + inp_fix_agauss_in_param() for model parameters according to HSPICE manual) + static char *statfcn[] = { "agauss", "gauss", "aunif", "unif", "limit" }; + int ii; + for (ii = 0; ii < 5; ii++) + eval_agauss(deck, statfcn[ii]); */ /* If user wants all currents saved (.options savecurrents), add .save to wl_first with all terminal currents available on selected devices */ wl_first = inp_savecurrents(deck, options, wl_first, controls); @@ -1873,3 +1886,144 @@ inp_savecurrents(struct card *deck, struct card *options, wordlist *wl, wordlist return wl_append(wl, wl_reverse(p)); } + + +static double +agauss(double nominal_val, double abs_variation, double sigma) +{ + double stdvar; + stdvar = abs_variation / sigma; + return (nominal_val + stdvar * gauss1()); +} + + +static double +gauss(double nominal_val, double rel_variation, double sigma) +{ + double stdvar; + stdvar = nominal_val * rel_variation / sigma; + return (nominal_val + stdvar * gauss1()); +} + + +static double +unif(double nominal_val, double rel_variation) +{ + return (nominal_val + nominal_val * rel_variation * drand()); +} + + +static double +aunif(double nominal_val, double abs_variation) +{ + return (nominal_val + abs_variation * drand()); +} + + +static double +limit(double nominal_val, double abs_variation) +{ + return (nominal_val + (drand() > 0 ? abs_variation : -1. * abs_variation)); +} + + +/* Second step to enable functions agauss, gauss, aunif, unif, limit + * in professional parameter decks: + * agauss has been preserved by replacement operation of .func + * (function inp_fix_agauss_in_param() in inpcom.c). + * After subcircuit expansion, agauss may be still existing in b-lines, + * however agauss does not exist in the B source parser, and it would + * not make sense in adding it there, because in each time step a different + * return form agauss would result. + * So we have to do the following in each B-line: + * check for agauss(x,y,z), and replace it by a suitable return value + * of agauss() + * agauss may also occur in .param lines, which have to be treated as well + */ + +static void +eval_agauss(struct card *deck, char *fcn) +{ + struct card *card; + double x, y, z, val; + + card = deck; + for (; card; card = card->nextcard) { + + int skip_control = 0; + char *ap, *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 != 'b') && !ciprefix(".para", curr_line)) + continue; + + while ((ap = search_identifier(curr_line, fcn, curr_line)) != NULL) { + char *lparen, *rparen, *begstr, *contstr = NULL, *new_line, *midstr; + char *tmp1str, *tmp2str, *delstr; + int nerror; + + begstr = copy_substring(curr_line, ap); + + lparen = strchr(ap, '('); + rparen = strchr(ap, ')'); + tmp1str = midstr = copy_substring(lparen + 1, rparen); + if (rparen + 1) + contstr = copy(rparen + 1); + + /* find the parameters */ + delstr = tmp2str = gettok(&tmp1str); + x = INPevaluate(&tmp2str, &nerror, 1); + tfree(delstr); + delstr = tmp2str = gettok(&tmp1str); + y = INPevaluate(&tmp2str, &nerror, 1); + tfree(delstr); + if (cieq(fcn, "agauss")) { + delstr = tmp2str = gettok(&tmp1str); + z = INPevaluate(&tmp2str, &nerror, 1); + tfree(delstr); + val = agauss(x, y, z); + } + else if (cieq(fcn, "gauss")) { + delstr = tmp2str = gettok(&tmp1str); + z = INPevaluate(&tmp2str, &nerror, 1); + tfree(delstr); + val = gauss(x, y, z); + } + else if (cieq(fcn, "aunif")) { + val = aunif(x, y); + } + else if (cieq(fcn, "unif")) { + val = unif(x, y); + } + else if (cieq(fcn, "limit")) { + val = limit(x, y); + } + else { + fprintf(cp_err, "ERROR: Unknown function %s, cannot evaluate\n", fcn); + tfree(begstr); + tfree(contstr); + tfree(midstr); + return; + } + + new_line = tprintf("%s%g%s", begstr, val, contstr); + tfree(card->line); + curr_line = card->line = new_line; + tfree(begstr); + tfree(contstr); + tfree(midstr); + } + } +} diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index c79195fb1..17b5cae1e 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -138,6 +138,7 @@ static void replace_token(char *string, char *token, int where, int total); static void inp_add_series_resistor(struct card *deck); static void subckt_params_to_param(struct card *deck); static void inp_fix_temper_in_param(struct card *deck); +static void inp_fix_agauss_in_param(struct card *deck, char *fcn); static void inp_vdmos_model(struct card *deck); static char *inp_spawn_brace(char *s); @@ -585,6 +586,11 @@ inp_readall(FILE *fp, char *dir_name, bool comfile, bool intfile, bool *expr_w_t rv . line_number = inp_split_multi_param_lines(working, rv . line_number); inp_fix_macro_param_func_paren_io(working); + + static char *statfcn[] = { "agauss", "gauss", "aunif", "unif", "limit" }; + int ii; + for (ii = 0; ii < 5; ii++) + inp_fix_agauss_in_param(working, statfcn[ii]); inp_fix_temper_in_param(working); inp_expand_macros_in_deck(NULL, working); @@ -6040,6 +6046,210 @@ inp_fix_temper_in_param(struct card *deck) } +/* Convert .param lines containing function 'agauss' and others +* (function name handed over by *fcn), into .func lines: +* .param xxx1 = 'aunif()' ---> .func xxx1() 'aunif()' +* Add info about the functions (name, subcircuit depth, number of +* subckt) to linked list new_func. +* Then scan new_func, for each xxx1 scan all lines of deck, +* find all xxx1 and convert them to a function: +* xxx1 ---> xxx1() +* +* In a second step, after subcircuits have been expanded, all occurencies +* of agauss in a b-line are replaced by their suitable value (function +* eval_agauss() in inp.c). +*/ + +static void +inp_fix_agauss_in_param(struct card *deck, char *fcn) +{ + int skip_control = 0, subckt_depth = 0, j, *sub_count; + char *funcbody, *funcname; + struct func_temper *f, *funcs = NULL, **funcs_tail_ptr = &funcs; + struct card *card; + + sub_count = TMALLOC(int, 16); + for (j = 0; j < 16; j++) + sub_count[j] = 0; + + /* first pass: + * determine all .param with agauss inside and replace by .func + * convert + * .param xxx1 = 'agauss(x,y,z) * 25' + * to + * .func xxx1() 'agauss(x,y,z) * 25' + */ + card = deck; + for (; card; card = card->nextcard) { + + char *curr_line = card->line; + + if (*curr_line == '*') + continue; + + /* determine nested depths of subcircuits */ + if (ciprefix(".subckt", curr_line)) { + subckt_depth++; + sub_count[subckt_depth]++; + continue; + } + else if (ciprefix(".ends", curr_line)) { + subckt_depth--; + continue; + } + + /* 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 (ciprefix(".para", curr_line)) { + + char *p, *temper, *equal_ptr, *lhs_b, *lhs_e; + + temper = search_identifier(curr_line, fcn, curr_line); + + if (!temper) + continue; + + equal_ptr = find_assignment(curr_line); + + if (!equal_ptr) { + fprintf(stderr, "ERROR: could not find '=' on parameter line '%s'!\n", curr_line); + controlled_exit(EXIT_FAILURE); + } + + /* .param lines with `,' separated multiple parameters + * must have been split in inp_split_multi_param_lines() + */ + + if (find_assignment(equal_ptr + 1)) { + fprintf(stderr, "ERROR: internal error on line '%s'!\n", curr_line); + controlled_exit(EXIT_FAILURE); + } + + lhs_b = skip_non_ws(curr_line); // eat .param + lhs_b = skip_ws(lhs_b); + + lhs_e = skip_back_ws(equal_ptr, curr_line); + + /* skip if this is a function already */ + p = strpbrk(lhs_b, "(,)"); + if (p && p < lhs_e) + continue; + + if (temper < equal_ptr) { + fprintf(stderr, + "Error: you cannot assign a value to %s\n" + " Line no. %d, %s\n", + fcn, card->linenum, curr_line); + controlled_exit(EXIT_BAD); + } + + funcname = copy_substring(lhs_b, lhs_e); + funcbody = copy(equal_ptr + 1); + + *funcs_tail_ptr = + inp_new_func(funcname, funcbody, card, sub_count, subckt_depth); + funcs_tail_ptr = &(*funcs_tail_ptr)->next; + + tfree(funcbody); + } + } + + /* second pass: + * for each .func entry in `funcs' start the insertion operation: + * search each line from the deck which has the suitable + * subcircuit nesting data. + * for tokens xxx equalling the funcname, replace xxx by xxx(). + */ + + for (f = funcs; f; f = f->next) { + + for (j = 0; j < 16; j++) + sub_count[j] = 0; + + card = deck; + for (; card; card = card->nextcard) { + + char *new_str = NULL; /* string we assemble here */ + char *curr_line = card->line; + char *firsttok_str; + + if (*curr_line == '*') + continue; + + /* determine nested depths of subcircuits */ + if (ciprefix(".subckt", curr_line)) { + subckt_depth++; + sub_count[subckt_depth]++; + continue; + } + else if (ciprefix(".ends", curr_line)) { + subckt_depth--; + continue; + } + + /* 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 function is not at top level, + exclude lines which do not have the same subcircuit + nesting depth and number as found in f */ + if (f->subckt_depth > 0) { + if (subckt_depth != f->subckt_depth) + continue; + if (sub_count[subckt_depth] != f->subckt_count) + continue; + } + + /* remove first token, ignore it here, restore it later */ + firsttok_str = gettok(&curr_line); + if (*curr_line == '\0') { + tfree(firsttok_str); + continue; + } + + new_str = inp_functionalise_identifier(curr_line, f->funcname); + + if (new_str == curr_line) { + tfree(firsttok_str); + continue; + } + + /* restore first part of the line */ + new_str = INPstrCat(firsttok_str, new_str, " "); + new_str = inp_remove_ws(new_str); + + *card->line = '*'; + /* Enter new line into deck */ + insert_new_line(card, new_str, 0, card->linenum); + } + } + /* final memory clearance */ + tfree(sub_count); + inp_delete_funcs(funcs); +} + + /* append "()" to each 'identifier' in 'curr_line', * unless already there */ static char *