diff --git a/ChangeLog b/ChangeLog index d9f7f2cce..8aa94ffc4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2010-04-23 Holger Vogt + * xpressn.c: agauss is no. 20 + main.c, inp.c, inpcom.c, compatmode.h, inpptree.h, ifeval.c, inpptree.c, ptfuncs.c: + ngspice compatibility mode with various functions + 2010-04-11 Dietmar Warning * Robert Larice patch to allow new operations in control blocks: * examples/new-check-3.sp, new-check-4.sp diff --git a/src/frontend/inp.c b/src/frontend/inp.c index 36f89173b..953d4e3d7 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -536,6 +536,18 @@ inp_spsource(FILE *fp, bool comfile, char *filename) line_free(deck->li_actual,FALSE); deck->li_actual = realdeck; + /* print out the expanded deck into debug-out2.txt */ + if (ft_ngdebug) { + FILE *fdo; + struct line *tmp_ptr1 = NULL; + /*debug: print into file*/ + fdo = fopen("debug-out2.txt", "w"); + for(tmp_ptr1 = deck; tmp_ptr1 != NULL; tmp_ptr1 = tmp_ptr1->li_next) + fprintf(fdo, "%s\n", tmp_ptr1->li_line); + ; + (void) fclose(fdo); + } + /* now load deck into ft_curckt -- the current circuit. */ inp_dodeck(deck, tt, wl_first, FALSE, options, filename); @@ -595,12 +607,12 @@ inp_spsource(FILE *fp, bool comfile, char *filename) printf("In inp_spsource, done with dodeck.\n"); #endif - /* print out the expanded deck into debug-out2.txt */ + /* print out the expanded deck into debug-out3.txt */ if (ft_ngdebug) { FILE *fdo; struct line *tmp_ptr1 = NULL; /*debug: print into file*/ - fdo = fopen("debug-out2.txt", "w"); + fdo = fopen("debug-out3.txt", "w"); for(tmp_ptr1 = deck; tmp_ptr1 != NULL; tmp_ptr1 = tmp_ptr1->li_next) fprintf(fdo, "%s\n", tmp_ptr1->li_line); ; diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 832b1b50f..07fbdfeae 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -47,6 +47,7 @@ Author: 1985 Wayne A. Christopher #include "fteext.h" #include "dvec.h" #include "fteinp.h" +#include "compatmode.h" #include "inpcom.h" #include "variable.h" @@ -81,6 +82,7 @@ static char *func_params[1000][1000]; static char *func_macro[5000]; static int num_functions; static int num_parameters[1000]; +static COMPATMODE_T inp_compat_mode; /* Collect information for dynamic allocation of numparam arrays */ /* number of lines in input deck */ @@ -92,6 +94,8 @@ int dynMaxckt = 0; /* subckt.c 307 */ /* number of parameter substitutions */ long dynsubst; /* spicenum.c 221 */ +extern COMPATMODE_T ngspice_compat_mode(void) ; + /* static declarations */ static char * readline(FILE *fd); static int get_number_terminals( char *c ); @@ -110,6 +114,8 @@ static void inp_reorder_params( struct line *deck, struct line *list_head, struc static int inp_split_multi_param_lines( struct line *deck, int line_number ); static void inp_sort_params( struct line *start_card, struct line *end_card, struct line *card_bf_start, struct line *s_c, struct line *e_c ); static char* inp_remove_ws( char *s ); +static void inp_compat(struct line *deck); +static void inp_bsource_compat(struct line *deck); /*-------------------------------------------------------------------------* * This routine reads a line (of arbitrary length), up to a '\n' or 'EOF' * @@ -465,29 +471,29 @@ inp_fix_macro_param_func_paren_io( struct line *begin_card ) { for ( card = begin_card; card != NULL; card = card->li_next ) { if ( *card->li_line == '*' ) continue; - +/* // zero out any voltage node references on .param lines if ( ciprefix( ".param", card->li_line ) ) { search_ptr = card->li_line; while( ( open_paren_ptr = strstr( search_ptr, "(" ) ) ) { - fcn_name = open_paren_ptr - 1; - while ( *fcn_name != '\0' && fcn_name != search_ptr && (isalnum(*fcn_name) || *fcn_name == '_' ) ) fcn_name--; - if ( fcn_name != search_ptr ) fcn_name++; - *open_paren_ptr = '\0'; - if ( strcmp( fcn_name, "v" ) == 0 ) { - *open_paren_ptr = ' '; - *fcn_name = '0'; - fcn_name++; - while ( *fcn_name != ')' ) { *fcn_name = ' '; fcn_name++; } - *fcn_name = ' '; - } - else { - *open_paren_ptr = '('; - } - search_ptr = open_paren_ptr + 1; + fcn_name = open_paren_ptr - 1; + while ( *fcn_name != '\0' && fcn_name != search_ptr && (isalnum(*fcn_name) || *fcn_name == '_' ) ) fcn_name--; + if ( fcn_name != search_ptr ) fcn_name++; + *open_paren_ptr = '\0'; + if ( strcmp( fcn_name, "v" ) == 0 ) { + *open_paren_ptr = ' '; + *fcn_name = '0'; + fcn_name++; + while ( *fcn_name != ')' ) { *fcn_name = ' '; fcn_name++; } + *fcn_name = ' '; + } + else { + *open_paren_ptr = '('; + } + search_ptr = open_paren_ptr + 1; } } - +*/ if ( ciprefix( ".macro", card->li_line ) || ciprefix( ".eom", card->li_line ) ) { str_ptr = card->li_line; while( !isspace(*str_ptr) ) str_ptr++; @@ -897,6 +903,7 @@ inp_fix_ternary_operator_str( char *line ) *str_ptr = keep; } } + else return line; // hvogt // get conditional str_ptr2 = question = strstr( str_ptr, "?" ); @@ -1592,7 +1599,19 @@ inp_readall(FILE *fp, struct line **data, int call_depth, char *dir_name) if (cp_getvar("addcontrol", VT_BOOL, (char *) &v)) inp_add_control_section(working, &line_number); + inp_compat_mode = ngspice_compat_mode() ; + if (inp_compat_mode == COMPATMODE_ALL) { + /* Do all the compatibility stuff here */ + working = cc->li_next; + /* E, G, L, R, C compatibility transformations */ + inp_compat(working); + working = cc->li_next; + /* B source numparam compatibility transformation */ + inp_bsource_compat(working); + } } + + /* save the return value (via **data) */ *data = cc; /* get max. line length and number of lines in input deck, @@ -2200,6 +2219,9 @@ inp_fix_subckt_multiplier( struct line *subckt_card, for ( card = subckt_card->li_next; card != NULL && !ciprefix( ".ends", card->li_line ); card = card->li_next ) { + /* no 'm' for B line or comment line */ + if ((*(card->li_line) == '*') || (*(card->li_line) == 'b')) + continue; new_str = tmalloc( strlen( card->li_line ) + 7 ); sprintf( new_str, "%s m={m}", card->li_line ); @@ -2558,13 +2580,13 @@ inp_expand_macro_in_str( char *str ) curr_ptr = open_paren_ptr+1; while ( isspace(*curr_ptr) ) curr_ptr++; num_params = 0; - if ( ciprefix( "v(", curr_ptr ) ) { +/* if ( ciprefix( "v(", curr_ptr ) ) { // look for any commas and change to ' ' char *str_ptr = curr_ptr; while ( *str_ptr != '\0' && *str_ptr != ')' ) { if ( *str_ptr == ',' || *str_ptr == '(' ) *str_ptr = ' '; str_ptr++; } if ( *str_ptr == ')' ) *str_ptr = ' '; - } + }*/ num_parens = 0; for (comma_ptr = curr_ptr; *comma_ptr && *comma_ptr != '\0'; comma_ptr++) { if (*comma_ptr == ',' && num_parens == 0) { @@ -3459,3 +3481,453 @@ inp_split_multi_param_lines( struct line *deck, int line_num ) } return line_num; } + + +/* compatibility: + Exxx n1 n2 VCVS n3 n4 gain --> Exxx n1 n2 n3 n4 gain + Gxxx n1 n2 VCCS n3 n4 tr --> Exxx n1 n2 n3 n4 tr + Exxx n1 n2 VOL = {equation} --> BExxx n1 n2 V = {equation} + Gxxx n1 n2 CUR = {equation} --> BGxxx n1 n2 I = {equation} + + Do the following transformations only if {equation} contains + simulation output like v(node), v(node1, node2), i(branch). + Otherwise let do numparam the substitutions (R=const is handled + in inp2r.c). + + Rxxx n1 n2 R = {equation} or Rxxx n1 n2 {equation} + --> + BRxxx n1 n2 I = V(n1,n2)/{equation} + + Unfortunately the capability for ac noise calculation of + resistance may be lost. + + Cxxx n1 n2 C = {equation} or Cxxx n1 n2 {equation} + --> + Cxxx n1 n2-aux 1 + Vxxx n2-aux n2 DC=0 + Bxxx n1 n2 I = ((equation) - 1) * Vxxx#branch + + Lxxx n1 n2 L = {equation} or Lxxx n1 n2 {equation} + --> + Lxxx n1 int 1 + Bxxx int n2 V = ((equation) - 1) * V(n1, int) + */ +static void inp_compat(struct line *deck) +{ + char *curr_line, *str_ptr, *cut_line, *title_tok, *node1, *node2; + char *xline, *linline, *amline, *fline, *eqline; + size_t xlen, i; + char *ckt_array[4]; + struct line *new_line, *tmp_ptr; + + struct line *param_end = NULL, *param_beg = NULL; + struct line *card = deck; + + while ( card != NULL ) + { + curr_line = card->li_line; + if ( *curr_line == '*' ) { card = card->li_next; continue; } + if ( *curr_line == 'e' ) { + /* Exxx n1 n2 VCVS n3 n4 gain --> Exxx n1 n2 n3 n4 gain + remove vcvs */ + if (str_ptr = strstr( curr_line, "vcvs" ) ) { + *str_ptr = ' '; *(str_ptr + 1) = ' '; + *(str_ptr + 2) = ' '; *(str_ptr + 3) = ' '; + } + /* Exxx n1 n2 VOL = {equation} --> BExxx n1 n2 V = {equation} */ + if (str_ptr = strstr( curr_line, "vol" ) ) { + *(str_ptr + 2) = ' '; + while (str_ptr > curr_line) { + *(str_ptr + 1) = *str_ptr; + str_ptr--; + } + *(str_ptr + 1) = *str_ptr; + *str_ptr = 'b'; + } + } + else if ( *curr_line == 'g' ) { + /* Gxxx n1 n2 VCCS n3 n4 tr --> Exxx n1 n2 n3 n4 tr + remove vccs */ + if (str_ptr = strstr( curr_line, "vccs" ) ) { + *str_ptr = ' '; *(str_ptr + 1) = ' '; + *(str_ptr + 2) = ' '; *(str_ptr + 3) = ' '; + } + /* Gxxx n1 n2 CUR = {equation} --> BGxxx n1 n2 I = {equation} */ + if (str_ptr = strstr( curr_line, "cur" ) ) { + *(str_ptr + 2) = ' '; *str_ptr = 'i'; + while (str_ptr > curr_line) { + *(str_ptr + 1) = *str_ptr; + str_ptr--; + } + *(str_ptr + 1) = *str_ptr; + *str_ptr = 'b'; + } + } + /* Rxxx n1 n2 R = {equation} or Rxxx n1 n2 {equation} + --> + BRxxx pos neg I = V(pos, neg)/{equation} + */ + else if ( *curr_line == 'r' ) { + if ((!strstr(curr_line, "v(")) && (!strstr(curr_line, "i("))) + { card = card->li_next; continue; } + cut_line = curr_line; + /* make BRxxx pos neg I = V(pos, neg)/{equation}*/ + title_tok = gettok(&cut_line); + node1 = gettok(&cut_line); + node2 = gettok(&cut_line); + /* Find equation, starts with '{', till end of line */ + str_ptr = strstr(cut_line, "{"); + xlen = strlen(title_tok) + strlen(node1) + strlen(node2) + + strlen(node1) + strlen(node2) + strlen(str_ptr) + 15; + xline = (char*)tmalloc(xlen); + sprintf(xline, "b%s %s %s I = v(%s, %s)/%s", title_tok, node1, node2, + node1, node2, str_ptr); + new_line = alloc(struct line); + new_line->li_next = NULL; + new_line->li_error = NULL; + new_line->li_actual = NULL; + new_line->li_line = xline; + new_line->li_linenum = 0; + // comment out current old R line + *(card->li_line) = '*'; + // insert new B source line immediately after current line + tmp_ptr = card->li_next; + card->li_next = new_line; + new_line->li_next = tmp_ptr; + // point 'card' pointer to the new line + card = new_line; + } + /* Cxxx n1 n2 C = {equation} or Cxxx n1 n2 {equation} + --> + Cxxx n1 n2-aux 1 + Vxxx n2-aux n2 DC=0 + Bxxx n1 n2 I = ((equation) - 1) * Vxxx#branch + */ + else if ( *curr_line == 'c' ) { + if ((!strstr(curr_line, "v(")) && (!strstr(curr_line, "i("))) + { card = card->li_next; continue; } + cut_line = curr_line; + /* title and nodes */ + title_tok = gettok(&cut_line); + node1 = gettok(&cut_line); + node2 = gettok(&cut_line); + /* Find equation, starts with '{', till end of line */ + str_ptr = strstr(cut_line, "{"); + + // Bxxx n1 n2 I = ((equation) - 1) * i(Vxxx) + xlen = 2*strlen(title_tok) + strlen(str_ptr) + strlen(node1) + + strlen(node2) + 25; + eqline = (char*)tmalloc(xlen); + sprintf(eqline, "b%s %s %s i = ((%s) - 1) * i(Vx%s)", + title_tok, node1, node2, str_ptr, title_tok); + // CCxxx node1 Cxxx2 1 + xlen = 2*strlen(title_tok) + strlen(node1) + 11; + linline = (char*)tmalloc(xlen); + sprintf(linline, "c%s %s %s_int2 1", title_tok, node1, title_tok); + // VCxxx Cxxx2 node2 DC 0 + xlen = 2*strlen(title_tok) + strlen(node2) + 16; + amline = (char*)tmalloc(xlen); + sprintf(amline, "vx%s %s_int2 %s dc 0", title_tok, title_tok, node2); + + ckt_array[0] = eqline; + ckt_array[1] = linline; + ckt_array[2] = amline; + // insert new B source line immediately after current line + tmp_ptr = card->li_next; + for ( i = 0; i < 3; i++ ) + { + if ( param_end ) + { + param_end->li_next = alloc(struct line); + param_end = param_end->li_next; + } + else + { + param_end = param_beg = alloc(struct line); + } + param_end->li_next = NULL; + param_end->li_error = NULL; + param_end->li_actual = NULL; + param_end->li_line = ckt_array[i]; + param_end->li_linenum = 0; + } + // comment out current variable capacitor line + *(card->li_line) = '*'; + // insert new param lines immediately after current line + tmp_ptr = card->li_next; + card->li_next = param_beg; + param_end->li_next = tmp_ptr; + // point 'card' pointer to last in scalar list + card = param_end; + + param_beg = param_end = NULL; + } + + /* Lxxx n1 n2 L = {equation} or Lxxx n1 n2 {equation} + --> + Lxxx n1 int 1 + Bxxx int n2 V = ((equation) - 1) * V(n1, int) + */ + else if ( *curr_line == 'l' ) { + if ((!strstr(curr_line, "v(")) && (!strstr(curr_line, "i("))) + { card = card->li_next; continue; } + cut_line = curr_line; + /* title and nodes */ + title_tok = gettok(&cut_line); + node1 = gettok(&cut_line); + node2 = gettok(&cut_line); + /* Find equation, starts with '{', till end of line */ + str_ptr = strstr(cut_line, "{"); + + // Bxxx int1 n2 V = (expression(v(somehting)) - 1) * v(n1, int1) + xlen = 3*strlen(title_tok) + strlen(str_ptr) + strlen(node1) + + strlen(node2) + 34; + eqline = (char*)tmalloc(xlen); + sprintf(eqline, "b%s %s_int1 %s v = ((%s) - 1) * v(%s,%s_int1)", + title_tok, title_tok, node2, str_ptr, node1, title_tok); + // LLxxx n1 int1 1 + xlen = 2*strlen(title_tok) + strlen(node1) + 11; + linline = (char*)tmalloc(xlen); + sprintf(linline, "l%s %s %s_int1 1", title_tok, node1, title_tok); + + ckt_array[0] = eqline; + ckt_array[1] = linline; + // insert new B source line immediately after current line + tmp_ptr = card->li_next; + for ( i = 0; i < 2; i++ ) + { + if ( param_end ) + { + param_end->li_next = alloc(struct line); + param_end = param_end->li_next; + } + else + { + param_end = param_beg = alloc(struct line); + } + param_end->li_next = NULL; + param_end->li_error = NULL; + param_end->li_actual = NULL; + param_end->li_line = ckt_array[i]; + param_end->li_linenum = 0; + } + // comment out current variable capacitor line + *(card->li_line) = '*'; + // insert new param lines immediately after current line + tmp_ptr = card->li_next; + card->li_next = param_beg; + param_end->li_next = tmp_ptr; + // point 'card' pointer to last in scalar list + card = param_end; + + param_beg = param_end = NULL; + } + card = card->li_next; + } +} +/* lines for B sources: no parsing in numparam code, just replacement of parameters. + Parsing done in B source parser. + To achive this, do the following: + Remove all '{' and '}' --> no parsing of equations in numparam + Place '{' and '}' directly around all potential parameters, + thus skip function names like exp (search for exp( to detect fcn name), + functions containing nodes like v(node), v(node1, node2), i(branch) + and other keywords. --> Only parameter replacement in numparam + +*/ + +static void inp_bsource_compat(struct line *deck) +{ + char *curr_line, *equal_ptr, *str_ptr, *tmp_char, *new_str, *final_str; + char actchar, prevchar = ' '; + struct line *card = deck, *new_line, *tmp_ptr; + wordlist *wl = NULL, *wlist = NULL, *cwl; + char buf[512]; + size_t i, xlen, ustate = 0; + + while ( card != NULL ) + { + curr_line = card->li_line; + if ( *curr_line == 'b' ) { + /* store starting point for later parsing, beginning of {expression} */ + equal_ptr = strstr(curr_line, "="); + /* find the m={m} token and remove it */ + if(str_ptr = strstr(curr_line, "m={m}")) + *str_ptr = '\0'; + /* scan the line and remove all '{' and '}' */ + str_ptr = curr_line; + while (*str_ptr) { + if ((*str_ptr == '{') || (*str_ptr == '}')) + *str_ptr = ' '; + str_ptr++; + } + /* scan the expression */ + str_ptr = equal_ptr + 1; + while (*str_ptr != '\0') { + while ((*str_ptr != '\0') && isspace(*str_ptr)) + str_ptr++; + if (*str_ptr == '\0') break; + actchar = *str_ptr; + cwl = alloc(struct wordlist); + cwl->wl_prev = wl; + if (wl) + wl->wl_next = cwl; + else { + wlist = cwl; + cwl->wl_next = NULL; + } + if ((actchar == ',') || (actchar == '(') || (actchar == ')') + || (actchar == '*') || (actchar == '/') || (actchar == '^') + || (actchar == '+') || (actchar == '?') || (actchar == ':')) + { + if ((actchar == '*') && (*(str_ptr+1) == '*')) { + actchar = '^'; + str_ptr++; + } + buf[0] = actchar; + buf[1] = '\0'; + cwl->wl_word = copy(buf); + str_ptr++; + if (actchar == ')') ustate = 0; + else ustate = 1; /* we have an operator */ + } + else if ((actchar == '>') || (actchar == '<') + || (actchar == '!') || (actchar == '=') ) + { + /* >=, <=, !=, == */ + if ((*(str_ptr+1) == '=')) { + buf[0] = actchar; + buf[1] = '='; + buf[2] = '\0'; + str_ptr++; + } + else { + buf[0] = actchar; + buf[1] = '\0'; + } + cwl->wl_word = copy(buf); + str_ptr++; + ustate = 1; /* we have an operator */ + } + else if ((actchar == '-') && (ustate == 0)) { + buf[0] = actchar; + buf[1] = '\0'; + cwl->wl_word = copy(buf); + str_ptr++; + ustate = 1; /* we have an operator */ + } + else if ((actchar == '-') && (ustate == 1)) { + cwl->wl_word = copy(""); + str_ptr++; + ustate = 2; /* place a '-' in front of token */ + } + else if (isalpha(actchar)) + { + /* unary -, change sign */ + if (ustate == 2) { + i = 1; + buf[0] = '-'; + } + else i = 0; + + if (((actchar == 'v') || (actchar == 'i')) && (*(str_ptr+1) == '(')) { + while (*str_ptr != ')') { + buf[i] = *str_ptr; + i++; + str_ptr++; + } + buf[i] = *str_ptr; + buf[i+1] = '\0'; + cwl->wl_word = copy(buf); + str_ptr++; + } + else { + while (isalnum(*str_ptr) || (*str_ptr == '!') || (*str_ptr == '#') + || (*str_ptr == '$')|| (*str_ptr == '%')|| (*str_ptr == '_') + || (*str_ptr == '[')|| (*str_ptr == ']')) { + buf[i] = *str_ptr; + i++; + str_ptr++; + } + buf[i] = '\0'; + if ((*str_ptr == '(') || cieq(buf, "hertz") || cieq(buf, "temper") + || cieq(buf, "time")) + { + cwl->wl_word = copy(buf); + } + else { + xlen = strlen(buf); + tmp_char = tmalloc(xlen + 3); + sprintf(tmp_char, "{%s}", buf); + cwl->wl_word = tmp_char; + } + } + ustate = 0; /* we have a number */ + } + else if (isdigit(actchar)) + { + /* unary -, change sign */ + if (ustate == 2) { + i = 1; + buf[0] = '-'; + } + else i = 0; + while (isdigit(*str_ptr) || (*str_ptr == '.') || (*str_ptr == 'e') + || (*str_ptr == '+')|| (*str_ptr == '-')) + { + if (((*str_ptr == '+')|| (*str_ptr == '-')) && (*(str_ptr-1) != 'e')) + break; + buf[i] = *str_ptr; + i++; + str_ptr++; + } + buf[i] = '\0'; + cwl->wl_word = copy(buf); + ustate = 0; /* we have a number */ + } + else /* strange char */ + { + printf("Preparing B line for numparam\nWhat is this?\n%s\n", str_ptr); + buf[0] = *str_ptr; + buf[1] = '\0'; + cwl->wl_word = copy(buf); + str_ptr++; + } + wl = cwl; + prevchar = actchar; + } + + new_str = wl_flatten(wlist); + wl_free(wlist); + wl = NULL; + + tmp_char = copy(curr_line); + equal_ptr = strstr(tmp_char, "="); + /* cut the tmp_char after the equal sign */ + *(equal_ptr + 1) = '\0'; + xlen = strlen(tmp_char) + strlen(new_str) + 2; + final_str = tmalloc(xlen); + sprintf(final_str, "%s %s", tmp_char, new_str); + + new_line = alloc(struct line); + new_line->li_next = NULL; + new_line->li_error = NULL; + new_line->li_actual = NULL; + new_line->li_line = final_str; + new_line->li_linenum = 0; + // comment out current old R line + *(card->li_line) = '*'; + // insert new B source line immediately after current line + tmp_ptr = card->li_next; + card->li_next = new_line; + new_line->li_next = tmp_ptr; + // point 'card' pointer to the new line + card = new_line; + + tfree(new_str); + tfree(tmp_char); + } /* end of if 'b' */ + + card = card->li_next; + } +} diff --git a/src/frontend/numparam/xpressn.c b/src/frontend/numparam/xpressn.c index cf0b740f4..abebcb3e9 100644 --- a/src/frontend/numparam/xpressn.c +++ b/src/frontend/numparam/xpressn.c @@ -1248,7 +1248,7 @@ formula (tdico * dico, char *s, unsigned char *perror) { if ((fu == 18)) u = ternary_fcn ((int) v, w, u); - else if ((fu == 19)) + else if ((fu == 20)) u = agauss (v, w, u); else u = mathfunction (fu, v, u); diff --git a/src/include/compatmode.h b/src/include/compatmode.h index c59391d0e..96299755d 100644 --- a/src/include/compatmode.h +++ b/src/include/compatmode.h @@ -6,7 +6,8 @@ typedef enum { COMPATMODE_NATIVE = 0, COMPATMODE_HSPICE = 1, - COMPATMODE_SPICE3 = 2 + COMPATMODE_SPICE3 = 2, + COMPATMODE_ALL = 3, } COMPATMODE_T ; #endif diff --git a/src/include/inpptree.h b/src/include/inpptree.h index da87580a6..cd666c57a 100644 --- a/src/include/inpptree.h +++ b/src/include/inpptree.h @@ -107,7 +107,9 @@ typedef struct INPparseNode { #define PTF_LT0 27 #define PTF_GE0 28 #define PTF_LE0 29 - +#define PTF_POW 30 +#define PTF_MIN 31 +#define PTF_MAX 32 /* The following things are used by the parser -- these are the token types the * lexer returns. @@ -177,6 +179,8 @@ extern double PTpwl(); extern double PTpwl_derivative(); extern double PTuramp(); extern double PTuminus(); +extern double PTmin(); +extern double PTmax(); extern double PTeq0(double arg); extern double PTne0(double arg); extern double PTgt0(double arg); diff --git a/src/main.c b/src/main.c index 1677ef313..5c038b417 100644 --- a/src/main.c +++ b/src/main.c @@ -365,6 +365,8 @@ COMPATMODE_T ngspice_compat_mode(void) char behaviour[80] ; if( cp_getvar("ngbehavior", VT_STRING, behaviour)){ + if (strcasecmp(behaviour,"all")==0) + return( COMPATMODE_ALL ) ; if (strcasecmp(behaviour,"hspice")==0) return( COMPATMODE_HSPICE ) ; if (strcasecmp(behaviour,"spice3")==0) diff --git a/src/spicelib/parser/ifeval.c b/src/spicelib/parser/ifeval.c index 20d464af8..85869dc0b 100644 --- a/src/spicelib/parser/ifeval.c +++ b/src/spicelib/parser/ifeval.c @@ -72,18 +72,40 @@ PTeval(INPparseNode * tree, double gmin, double *res, double *vals) break; case PT_FUNCTION: - err = PTeval(tree->left, gmin, &r1, vals); - if (err != OK) - return (err); - if(tree->data == NULL) - *res = (*tree->function) (r1); - else - *res = (*tree->function) (r1, tree->data); - if (*res == HUGE) { - fprintf(stderr, "Error: %g out of range for %s\n", - r1, tree->funcname); - return (E_PARMVAL); - } + switch(tree->funcnum) { + + case PTF_POW: + case PTF_MIN: + case PTF_MAX: + err = PTeval(tree->left->left, gmin, &r1, vals); + if (err != OK) + return (err); + err = PTeval(tree->left->right, gmin, &r2, vals); + if (err != OK) + return (err); + *res = (*tree->function) (r1, r2); + if (*res == HUGE) { + fprintf(stderr, "Error: %g, %g out of range for %s\n", + r1, r2, tree->funcname); + return (E_PARMVAL); + } + break; + /* fcns with single argument */ + default: + err = PTeval(tree->left, gmin, &r1, vals); + if (err != OK) + return (err); + if(tree->data == NULL) + *res = (*tree->function) (r1); + else + *res = (*tree->function) (r1, tree->data); + if (*res == HUGE) { + fprintf(stderr, "Error: %g out of range for %s\n", + r1, tree->funcname); + return (E_PARMVAL); + } + break; + } break; case PT_TERN: diff --git a/src/spicelib/parser/inpptree.c b/src/spicelib/parser/inpptree.c index 0bdaf746e..c27e8a4ae 100644 --- a/src/spicelib/parser/inpptree.c +++ b/src/spicelib/parser/inpptree.c @@ -91,6 +91,9 @@ static struct func { { "lt0", PTF_LT0, PTlt0}, { "ge0", PTF_GE0, PTge0}, { "le0", PTF_LE0, PTle0}, + { "pow", PTF_POW, PTpower}, + { "min", PTF_MIN, PTmin}, + { "max", PTF_MAX, PTmax}, } ; #define NUM_FUNCS (int)(sizeof (funcs) / sizeof (struct func)) @@ -438,6 +441,57 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum) arg1 = mkcon((double) 0.0); break; + case PTF_MIN: + /* + min(a,b) + p->left: ',' p->left->left: a p->left->right: b + */ + newp = mkcon((double) 0); + return (newp); + + case PTF_MAX: + newp = mkcon((double) 0); + return (newp); + + case PTF_POW: + { + /* + pow(a,b) + p->left: ',' p->left->left: a p->left->right: b + */ + + /* Two cases... + The power is constant + */ + if (p->left->right->type == PT_CONSTANT) { + arg1 = PTdifferentiate(p->left->left, varnum); + + newp = mkb(PT_TIMES, mkb(PT_TIMES, + mkcon(p->left->right->constant), + mkb(PT_POWER, p->left->left, + mkcon(p->left->right->constant - 1))), + arg1); + } else { + /* This is complicated. f(x) ^ g(x) -> + exp(y(x) * ln(f(x)) ... + */ + arg1 = PTdifferentiate(p->left->left, varnum); + arg2 = PTdifferentiate(p->left->right, varnum); + newp = mkb(PT_TIMES, mkf(PTF_EXP, mkb(PT_TIMES, + p->left->right, mkf(PTF_LN, + p->left->left))), + mkb(PT_PLUS, + mkb(PT_TIMES, p->left->right, + mkb(PT_DIVIDE, arg1, p->left->left)), + mkb(PT_TIMES, arg2, mkf(PTF_LN, /*arg1*/p->left->left)))); + /*changed by HT, '05/06/29*/ + + } + arg2 = PTdifferentiate(p->left->left, varnum); + newp = mkb(PT_TIMES, arg1, arg2); + return (newp); + } + default: fprintf(stderr, "Internal Error: bad function # %d\n", p->funcnum); diff --git a/src/spicelib/parser/ptfuncs.c b/src/spicelib/parser/ptfuncs.c index 6fd075863..b6cc0d1b7 100644 --- a/src/spicelib/parser/ptfuncs.c +++ b/src/spicelib/parser/ptfuncs.c @@ -84,6 +84,18 @@ PTpower(double arg1, double arg2) return (pow(arg1, arg2)); } +double +PTmin(double arg1, double arg2) +{ + return arg1 > arg2 ? arg2 : arg1; +} + +double +PTmax(double arg1, double arg2) +{ + return arg1 > arg2 ? arg1 : arg2; +} + double PTacos(double arg) {