ngspice compatibility mode

This commit is contained in:
h_vogt 2010-04-23 22:00:40 +00:00
parent 49aadcca58
commit e66ef33c57
10 changed files with 620 additions and 36 deletions

View File

@ -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

View File

@ -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);
;

View File

@ -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;
}
}

View File

@ -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);

View File

@ -6,7 +6,8 @@
typedef enum {
COMPATMODE_NATIVE = 0,
COMPATMODE_HSPICE = 1,
COMPATMODE_SPICE3 = 2
COMPATMODE_SPICE3 = 2,
COMPATMODE_ALL = 3,
} COMPATMODE_T ;
#endif

View File

@ -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);

View File

@ -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)

View File

@ -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:

View File

@ -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);

View File

@ -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)
{