diff --git a/src/frontend/Makefile.am b/src/frontend/Makefile.am index 4306baf69..708120d51 100644 --- a/src/frontend/Makefile.am +++ b/src/frontend/Makefile.am @@ -95,6 +95,8 @@ libfte_la_SOURCES = \ breakp2.h \ circuits.c \ circuits.h \ + compatmode.c \ + compatmode.h \ cpitf.c \ cpitf.h \ define.c \ diff --git a/src/frontend/com_measure2.c b/src/frontend/com_measure2.c index e8fe312f7..4272ca2b7 100644 --- a/src/frontend/com_measure2.c +++ b/src/frontend/com_measure2.c @@ -1,7 +1,7 @@ /* New routines to evaluate the .measure cards. Entry point is function get_measure2(), called by fcn do_measure() from measure.c, if line measure.c:25 is commented out. - Patches by Bill Swartz from 2009-05-18 are included. + Patches by Bill Swartz from 2009-05-18 and 2009-08-21 are included. $Id$ */ @@ -14,12 +14,9 @@ #include "vectors.h" #include +#include "dotcards.h" #include "com_measure2.h" -#ifdef _MSC_VER -#define strcasecmp _stricmp -#endif - typedef enum { MEASUREMENT_OK = 0, MEASUREMENT_FAILURE = 1 @@ -33,42 +30,225 @@ typedef struct measure char *result; char *m_vec; // name of the output variable which determines the beginning of the measurement - char *m_vec2; - int m_rise; - int m_fall; - int m_cross; + char *m_vec2; // second output variable to measure if applicable + int m_rise; // count number of rise events + int m_fall; // count number of fall events + int m_cross; // count number of rise/fall aka cross events double m_val; // value of the m_ver at which the counter for crossing, rises or falls is incremented by one double m_td; // amount of delay before the measurement should start - double m_from; - double m_to; - double m_at; - double m_measured; - double m_measured_at; + double m_from; // measure only in a time window - starting time of window + double m_to; // measurement window - ending time + double m_at; // measure at the specified time + double m_measured; // what we measured + double m_measured_at; //* what we measured at the given time -} measure; +} MEASURE, *MEASUREPTR ; -enum AnalysisType { - AT_DELAY, AT_TRIG, +typedef enum AnalysisType { + AT_UNKNOWN, AT_DELAY, AT_TRIG, AT_FIND, AT_WHEN, AT_AVG, AT_MIN, AT_MAX, AT_RMS, AT_PP, AT_INTEG, AT_DERIV, AT_ERR, AT_ERR1, AT_ERR2, AT_ERR3 -}; +} ANALYSIS_TYPE_T ; /** return precision (either 5 or value of environment variable NGSPICE_MEAS_PRECISION) */ -int get_measure_precision(void) +int +measure_get_precision(void) { - char *env_ptr; - int precision = 5; - - if ( ( env_ptr = getenv("NGSPICE_MEAS_PRECISION") ) ) { - precision = atoi(env_ptr); - } - - return precision; + char *env_ptr; + int precision = 5; + + if ( ( env_ptr = getenv("NGSPICE_MEAS_PRECISION") ) ) { + precision = atoi(env_ptr); + } + + return precision; } /* end measure_get_precision() */ -void com_measure_when(struct measure *meas) { +static void measure_errMessage(char *mName, char *mFunction, char *trigTarg, char *errMsg, int chk_only) +{ + + if(!(chk_only)){ + printf("\tmeasure '%s' failed\n", mName); + printf("Error: measure %s %s(%s) :\n", mName, mFunction, trigTarg); + printf("\t%s\n",errMsg); + } + return; +} /* end measure_errMessage() */ + +static double +measure_interpolate( struct dvec *time, struct dvec *values, int i, int j, double var_value, char x_or_y ) +{ + double slope; + double yint; + double result; + + slope = (values->v_realdata[j] - values->v_realdata[i]) / + (time->v_realdata[j] - time->v_realdata[i]); + + yint = values->v_realdata[i] - slope*time->v_realdata[i]; + + if ( x_or_y == 'x' ) result = (var_value - yint)/slope; + else result = slope*var_value + yint; + + return result; +} /* end measure_interpolate() */ + +/* ----------------------------------------------------------------- + * Function: Given an operation string returns back the measure type - one of + * the enumerated type ANALSYS_TYPE_T. + * ----------------------------------------------------------------- */ +static ANALYSIS_TYPE_T measure_function_type( char *operation ) +{ + char *mFunction ; /* operation */ + ANALYSIS_TYPE_T mFunctionType ; /* type of requested function */ + + mFunction = cp_unquote(operation); + // Functions + if (strcasecmp(mFunction,"DELAY")==0) + mFunctionType = AT_DELAY; + else if (strcasecmp(mFunction,"TRIG")==0) + mFunctionType = AT_DELAY; + else if (strcasecmp(mFunction,"TARG")==0) + mFunctionType = AT_DELAY; + else if (strcasecmp(mFunction,"FIND")==0) + mFunctionType = AT_FIND; + else if (strcasecmp(mFunction,"WHEN")==0) + mFunctionType = AT_WHEN; + else if (strcasecmp(mFunction,"AVG")==0) + mFunctionType = AT_AVG; + else if (strcasecmp(mFunction,"MIN")==0) + mFunctionType = AT_MIN; + else if (strcasecmp(mFunction,"MAX")==0) + mFunctionType = AT_MAX; + else if (strcasecmp(mFunction,"RMS")==0) + mFunctionType = AT_RMS; + else if (strcasecmp(mFunction,"PP")==0) + mFunctionType = AT_PP; + else if (strcasecmp(mFunction,"INTEG")==0) + mFunctionType = AT_INTEG; + else if (strcasecmp(mFunction,"DERIV")==0) + mFunctionType = AT_DERIV; + else if (strcasecmp(mFunction,"ERR")==0) + mFunctionType = AT_ERR; + else if (strcasecmp(mFunction,"ERR1")==0) + mFunctionType = AT_ERR1; + else if (strcasecmp(mFunction,"ERR2") == 0) + mFunctionType = AT_ERR2; + else if (strcasecmp(mFunction,"ERR3") == 0) + mFunctionType = AT_ERR3; + else + mFunctionType = AT_UNKNOWN; + + return( mFunctionType) ; + +} /* end measure_function_type() */ + +/* ----------------------------------------------------------------- + * Function: Parse the measurement line and extract any variables in + * the statement and call com_save2 to instantiate the variable as a + * measurement vector in the transient analysis. + * ----------------------------------------------------------------- */ +int measure_extract_variables( char *line ) +{ + /* Various formats for measure statement: + * .MEASURE {DC|AC|TRAN} result TRIG trig_variable VAL=val + * + + * + + * + TARG targ_variable VAL=val + * + + * + + * + * .MEASURE {DC|AC|TRAN} result WHEN out_variable=val + * + + * + + * + * .MEASURE {DC|AC|TRAN} result WHEN out_variable=out_variable2 + * + + * + + * + * .MEASURE {DC|AC|TRAN} result FIND out_variable WHEN out_variable2=val + * + + * + + * + * .MEASURE {DC|AC|TRAN} result FIND out_variable WHEN out_variable2=out_variable3 + * + + * + + * + * .MEASURE {DC|AC|TRAN} result FIND out_variable AT=val + * + + * + * .MEASURE {DC|AC|TRAN} result {AVG|MIN|MAX|PP|RMS} out_variable + * + + * + * .MEASURE {DC|AC|TRAN} result INTEG out_variable + * + + * + * .MEASURE {DC|AC|TRAN} result DERIV out_variable + * + + * + * .MEASURE {DC|AC|TRAN} result DERIV out_variable + * + + * ----------------------------------------------------------------- */ + + int len ; /* length of string */ + int status ; /* return status */ + char *item ; /* parsing item */ + char *measure ; /* measure keyword */ + char *analysis ; /* analysis option */ + char *variable ; /* variable to trace */ + wordlist *measure_var ; /* wordlist of measurable */ + ANALYSIS_TYPE_T op ; /* measure function type */ + + status = TRUE; + measure = gettok(&line); + if(!(measure)){ + return(status) ; + } + analysis = gettok(&line); + if(!(analysis)){ + return(status) ; + } + if( (strcasecmp(analysis,"DC")==0) || + (strcasecmp(analysis,"AC")==0) || + (strcasecmp(analysis,"TRAN")==0) ){ + analysis = copy(analysis) ; + } else { + /* sometimes operation is optional - for now just pick trans */ + analysis = copy("TRAN") ; + } + do { + item = gettok(&line) ; + if( item ){ + op = measure_function_type(item) ; + if( op != AT_UNKNOWN ){ + /* We have a variable/complex variable coming next */ + variable = gettok(&line) ; + if( variable ){ + len = strlen(item) ; + if( item[len-1] == '=' ){ + } else { + measure_var = gettoks(variable) ; + com_save2(measure_var, analysis); + status = FALSE; + } + } + } + } + } while(line && *line) ; + /* + */ + return( status ) ; +} /* end measure_extract_variables() */ + +/* ----------------------------------------------------------------- + * Function: process a WHEN measurement statement which has been + * parsed into a measurement structure. + * ----------------------------------------------------------------- */ +static void com_measure_when( + MEASUREPTR meas /* in : parsed measurement structure */ +) { int i, first; int riseCnt = 0; @@ -129,7 +309,7 @@ void com_measure_when(struct measure *meas) { crossCnt =1; } } - printf(""); + fflush( stdout ) ; } if (first > 1) { @@ -186,7 +366,15 @@ void com_measure_when(struct measure *meas) { return; } -void measure_at(struct measure *meas, double at) { +/* ----------------------------------------------------------------- + * Function: process an AT measurement statement which has been + * parsed into a measurement structure. We make sure to interpolate + * the value when appropriate. + * ----------------------------------------------------------------- */ +static void measure_at( + MEASUREPTR meas, /* in : parsed "at" data */ + double at /* in: time to perform measurement */ +) { int i; double value, pvalue, svalue, psvalue; @@ -224,13 +412,17 @@ void measure_at(struct measure *meas, double at) { return; } -void measure_avg( ) { - // AVG (Average): - // Calculates the area under the 'out_var' divided by the periods of intrest - return; -} -void measure_minMaxAvg( struct measure *meas, int minMax ) { +/* ----------------------------------------------------------------- + * Function: process an MIN, MAX, or AVG statement which has been + * parsed into a measurement structure. We should make sure to interpolate + * the value here when we have m_from and m_to constraints * so this + * function is slightly wrong. Need to fix in future rev. + * ----------------------------------------------------------------- */ +static void measure_minMaxAvg( + MEASUREPTR meas, /* in : parsed measurement data request */ + ANALYSIS_TYPE_T mFunctionType /* in: one of AT_AVG, AT_MIN, AT_MAX */ +) { int i, avgCnt; struct dvec *d, *dScale; @@ -272,7 +464,7 @@ void measure_minMaxAvg( struct measure *meas, int minMax ) { first =1; } else { - switch (minMax) { + switch (mFunctionType) { case AT_MIN: { if (value <= mValue) { mValue = value; @@ -287,53 +479,195 @@ void measure_minMaxAvg( struct measure *meas, int minMax ) { } break; } - case AT_AVG: - case AT_RMS: { + case AT_AVG: { mValue = mValue + value; avgCnt ++; break; } + default : + fprintf(cp_err, "Error: improper min/max/avg call.\n"); } } } - switch (minMax) + switch (mFunctionType) { case AT_AVG: { meas->m_measured = (mValue / avgCnt); meas->m_measured_at = svalue; break; } - case AT_RMS: { - // printf(" mValue %e svalue %e avgCnt %i, ", mValue, svalue, avgCnt); - meas->m_measured = sqrt(mValue) / avgCnt; - meas->m_measured_at = svalue; - break; - } case AT_MIN: case AT_MAX: { meas->m_measured = mValue; meas->m_measured_at = mValueAt; break; } + default : + fprintf(cp_err, "Error: improper min/max/avg call.\n"); } return; } -void measure_rms( ) { +/* ----------------------------------------------------------------- + * Function: process an RMS or INTEG statement which has been + * parsed into a measurement structure. Here we do interpolate + * the starting and stopping time window so the answer is correct. + * ----------------------------------------------------------------- */ +static void measure_rms_integral( + MEASUREPTR meas, /* in : parsed measurement data request */ + ANALYSIS_TYPE_T mFunctionType /* in: one of AT_RMS, or AT_INTEG */ +) { + int i; /* counter */ + int xy_size ; /* # of temp array elements */ + struct dvec *d, *time; /* value and time vectors */ + float value, tvalue; /* current value and time value */ + double *x ; /* temp x array */ + double *y ; /* temp y array */ + double toVal ; /* to time value */ + double *width ; /* temp width array */ + double sum1 ; /* first sum */ + double sum2 ; /* second sum */ + double sum3 ; /* third sum */ + int first; + + tvalue =0; + meas->m_measured = 0.0e0; + meas->m_measured_at = 0.0e0; + first =0; + + d = vec_get(meas->m_vec); + if (d == NULL) { + fprintf(cp_err, "Error: no such vector as %s.\n", meas->m_vec); + return; + } + + time = vec_get("time"); + if (time == NULL) { + fprintf(cp_err, "Error: no such vector as time.\n"); + return; + } + + // Allocate buffers for calculation. + x = (double *) tmalloc(time->v_length * sizeof(double)); + y = (double *) tmalloc(time->v_length * sizeof(double)); + width = (double *) tmalloc(time->v_length * sizeof(double)); + + xy_size = 0 ; + toVal = -1 ; + // create new set of values over interval [from, to] -- interpolate if necessary + for (i=0; i < d->v_length; i++) { + value = d->v_realdata[i]; + tvalue = time->v_realdata[i]; + + if (tvalue < meas->m_from) + continue; + + if ((meas->m_to != 0.0e0) && (tvalue > meas->m_to) ){ + // interpolate ending value if necessary. + if (!(AlmostEqualUlps( tvalue, meas->m_to, 100))){ + value = measure_interpolate( time, d, i-1, i, meas->m_to, 'y' ); + tvalue = meas->m_to ; + } + x[xy_size] = tvalue ; + if (mFunctionType == AT_RMS) + y[xy_size++] = value * value ; + else + y[xy_size++] = value ; + toVal = tvalue ; + break; + } + + if (first == 0) { + if( meas->m_from != 0.0e0 && (i > 0) ){ + // interpolate starting value. + if (!(AlmostEqualUlps( tvalue, meas->m_from, 100))){ + value = measure_interpolate( time, d, i-1, i, meas->m_from, 'y' ); + tvalue = meas->m_from ; + } + } + meas->m_measured_at = tvalue ; + first = 1; + } + x[xy_size] = tvalue ; + if (mFunctionType == AT_RMS) + y[xy_size++] = value * value ; + else + y[xy_size++] = value ; + } + + // evaluate segment width + for ( i = 0; i < xy_size-1; i++ ) width[i] = x[i+1] - x[i] ; + width[i++] = 0; + width[i++] = 0; + + // Compute Integral (area under curve) + i = 0; + sum1 = sum2 = sum3 = 0.0 ; + while ( i < xy_size-1 ) { + // Simpson's 3/8 Rule + if ( AlmostEqualUlps( width[i], width[i+1], 100 ) && + AlmostEqualUlps( width[i], width[i+2], 100 ) ) { + sum1 += 3*width[i] * (y[i] + 3*(y[i+1] + y[i+2]) + y[i+3]) / 8.0; + i += 3; + } + // Simpson's 1/3 Rule + else if ( AlmostEqualUlps( width[i], width[i+1], 100 ) ) { + sum2 += width[i] * (y[i] + 4*y[i+1] + y[i+2]) / 3.0 ; + i += 2; + } + // Trapezoidal Rule + else if ( !AlmostEqualUlps( width[i], width[i+1], 100 ) ) { + sum3 += width[i] * (y[i] + y[i+1]) / 2; + i++; + } + } + + /* Now set the measurement values if not set */ + if( toVal < 0.0 ){ + toVal = time->v_realdata[d->v_length-1]; + } + meas->m_from = meas->m_measured_at ; + meas->m_to = toVal ; + + if (mFunctionType == AT_RMS) { + meas->m_measured = (sum1 + sum2 + sum3)/ (toVal - meas->m_measured_at) ; + meas->m_measured = sqrt(meas->m_measured); + + } else { + meas->m_measured = ( sum1 + sum2 + sum3 ); + } + txfree(x); txfree(y); txfree(width); + +} /* end measure_rms_integral() */ + +/* ----------------------------------------------------------------- + * Function: Wrapper function to process a RMS measurement. + * ----------------------------------------------------------------- */ +static void measure_rms( + MEASUREPTR meas /* in : parsed measurement data request */ +) { // RMS (root mean squared): // Calculates the square root of the area under the 'out_var2' curve // divided be the period of interest + measure_rms_integral(meas,AT_RMS) ; return; } -void measure_integ( ) { +/* ----------------------------------------------------------------- + * Function: Wrapper function to process a integration measurement. + * ----------------------------------------------------------------- */ +static void measure_integ( + MEASUREPTR meas /* in : parsed measurement data request */ +) { // INTEGRAL INTEG + measure_rms_integral(meas,AT_INTEG) ; return; } +/* still some more work to do.... */ void measure_deriv( ) { // DERIVATIVE DERIV return; @@ -356,13 +690,6 @@ void measure_ERR3( ) { return; } -void measure_errMessage(char *mName, char *mFunction, char *trigTarg, char *errMsg, bool autocheck) { - if (autocheck) return; - printf("\tmeasure '%s' failed\n", mName); - printf("Error: measure %s %s(%s) :\n", mName, mFunction, trigTarg); - printf("\t%s\n",errMsg); - return; -} void com_dotmeasure( ) { @@ -373,20 +700,38 @@ void com_dotmeasure( ) { return; } -int measure_valid_vector(char *vec) { +/* ----------------------------------------------------------------- + * Function: Given a measurement variable name, see if the analysis + * has generated a measure vector for it. Returns TRUE if it exists + * or varname is NULL, Return FALSE otherwise + * ----------------------------------------------------------------- */ +static int measure_valid_vector( + char *varname /* in: requested variable name */ +) { - struct dvec *d; + struct dvec *d; /* measurement vector */ - if(vec == NULL) - return 1; - d = vec_get(vec); + if(varname == NULL) + return TRUE; + d = vec_get(varname); if (d == NULL) - return 0; + return FALSE; - return 1; + return TRUE; } -int measure_parse_stdParams (struct measure *meas, wordlist *wl, wordlist *wlBreak, char *errbuf) { +/* ----------------------------------------------------------------- + * Function: Given a wordlist and measurement structure, parse the + * standard parameters such as RISE, FALL, VAL, TD, FROM, TO, etc. + * in a measurement statement. We also check the appropriate + * variables found in the measurement statement. + * ----------------------------------------------------------------- */ +static int measure_parse_stdParams ( + MEASUREPTR meas, /* in : measurement structure */ + wordlist *wl, /* in : word list to parse */ + wordlist *wlBreak, /* out: where we stopped parsing */ + char *errbuf /* in/out: buffer where we write error messages */ +) { int pCnt; char *p, *pName, *pValue; @@ -475,7 +820,17 @@ int measure_parse_stdParams (struct measure *meas, wordlist *wl, wordlist *wlBre return 1; } -int measure_parse_find (struct measure *meas, wordlist *wl, wordlist *wlBreak, char *errbuf) { +/* ----------------------------------------------------------------- + * Function: Given a wordlist and measurement structure, parse a + * FIND measurement statement. Most of the work is done by calling + * measure_parse_stdParams. + * ----------------------------------------------------------------- */ +static int measure_parse_find ( + MEASUREPTR meas, /* in : measurement structure */ + wordlist *wl, /* in : word list to parse */ + wordlist *wlBreak, /* out: where we stopped parsing */ + char *errbuf /* in/out: buffer where we write error messages */ +) { int pCnt; char *p, *pName, *pVal; @@ -497,9 +852,7 @@ int measure_parse_find (struct measure *meas, wordlist *wl, wordlist *wlBreak, c p = wl->wl_word; if (pCnt == 0 ) { -// meas->m_vec =(char *)tmalloc(strlen(wl->wl_word)+1); - // strcpy(meas->m_vec, cp_unquote(wl->wl_word)); - meas->m_vec= cp_unquote(wl->wl_word); + meas->m_vec= cp_unquote(wl->wl_word); } else if (pCnt == 1) { pName = strtok(p, "="); @@ -537,7 +890,16 @@ int measure_parse_find (struct measure *meas, wordlist *wl, wordlist *wlBreak, c return 1; } -int measure_parse_when (struct measure *meas, wordlist *wl, char *errBuf) { +/* ----------------------------------------------------------------- + * Function: Given a wordlist and measurement structure, parse a + * WHEN measurement statement. Most of the work is done by calling + * measure_parse_stdParams. + * ----------------------------------------------------------------- */ +static int measure_parse_when ( + MEASUREPTR meas, /* in : measurement structure */ + wordlist *wl, /* in : word list to parse */ + char *errBuf /* in/out: buffer where we write error messages */ +) { int pCnt; char *p, *pVar1, *pVar2; @@ -584,7 +946,18 @@ int measure_parse_when (struct measure *meas, wordlist *wl, char *errBuf) { } -int measure_parse_trigtarg (struct measure *meas, wordlist *words, wordlist *wlTarg, char *trigTarg, char *errbuf) { +/* ----------------------------------------------------------------- + * Function: Given a wordlist and measurement structure, parse a + * TRIGGER or TARGET clause of a measurement statement. Most of the + * work is done by calling measure_parse_stdParams. + * ----------------------------------------------------------------- */ +static int measure_parse_trigtarg ( + MEASUREPTR meas, /* in : measurement structure */ + wordlist *words, /* in : word list to parse */ + wordlist *wlTarg, /* out : where we stopped parsing target clause */ + char *trigTarg, /* in : type of clause */ + char *errbuf /* in/out: buffer where we write error messages */ +) { int pcnt; char *p; @@ -634,9 +1007,21 @@ int measure_parse_trigtarg (struct measure *meas, wordlist *words, wordlist *wlT return 1; } +/* ----------------------------------------------------------------- + * Function: Given a wordlist, extract the measurement statement, + * process it, and return a result. If out_line is furnished, we + * format and copy the result it this string buffer. The autocheck + * variable allows us to check for "autostop". This function is + * called from measure.c. We use the functions in this file because + * the parsing is much more complete and thorough. +* ----------------------------------------------------------------- */ int -get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck) -{ +get_measure2( + wordlist *wl, /* in: a word list for us to process */ + double *result, /* out : the result of the measurement */ + char *out_line, /* out: formatted result - may be NULL */ + bool autocheck /* in: TRUE if checking for "autostop"; FALSE otherwise */ +) { wordlist *words, *wlTarg, *wlWhen; char errbuf[100]; char *mType = NULL; // analysis type @@ -673,7 +1058,7 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck) return MEASUREMENT_FAILURE; } - precision = get_measure_precision() ; + precision = measure_get_precision() ; wl_cnt = 0; while (words) { @@ -687,43 +1072,14 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck) break; case 2: { - mFunction = cp_unquote(words->wl_word); - // Functions - if (strcasecmp(mFunction,"DELAY")==0) - mFunctionType = AT_DELAY; - else if (strcasecmp(mFunction,"TRIG")==0) - mFunctionType = AT_DELAY; - else if (strcasecmp(mFunction,"FIND")==0) - mFunctionType = AT_FIND; - else if (strcasecmp(mFunction,"WHEN")==0) - mFunctionType = AT_WHEN; - else if (strcasecmp(mFunction,"AVG")==0) - mFunctionType = AT_AVG; - else if (strcasecmp(mFunction,"MIN")==0) - mFunctionType = AT_MIN; - else if (strcasecmp(mFunction,"MAX")==0) - mFunctionType = AT_MAX; - else if (strcasecmp(mFunction,"RMS")==0) - mFunctionType = AT_RMS; - else if (strcasecmp(mFunction,"PP")==0) - mFunctionType = AT_PP; - else if (strcasecmp(mFunction,"INTEG")==0) - mFunctionType = AT_INTEG; - else if (strcasecmp(mFunction,"DERIV")==0) - mFunctionType = AT_DERIV; - else if (strcasecmp(mFunction,"ERR")==0) - mFunctionType = AT_ERR; - else if (strcasecmp(mFunction,"ERR1")==0) - mFunctionType = AT_ERR1; - else if (strcasecmp(mFunction,"ERR2") == 0) - mFunctionType = AT_ERR2; - else if (strcasecmp(mFunction,"ERR3") == 0) - mFunctionType = AT_ERR3; - else { - printf("\tmeasure '%s' failed\n", mName); - printf("Error: measure %s :\n", mName); - printf("\tno such function as '%s'\n", mFunction); - return MEASUREMENT_FAILURE; + mFunctionType = measure_function_type(words->wl_word); + if ( mFunctionType == AT_UNKNOWN ){ + if(!(autocheck)){ + printf("\tmeasure '%s' failed\n", mName); + printf("Error: measure %s :\n", mName); + printf("\tno such function as '%s'\n", words->wl_word); + } + return MEASUREMENT_FAILURE; } break; } @@ -771,7 +1127,7 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck) case AT_TRIG: { // trig parameters - measure *measTrig, *measTarg; + MEASUREPTR measTrig, measTarg; measTrig = (struct measure*)tmalloc(sizeof(struct measure)); measTarg = (struct measure*)tmalloc(sizeof(struct measure)); @@ -836,7 +1192,7 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck) } case AT_FIND: { - measure *meas, *measFind; + MEASUREPTR meas, measFind; meas = (struct measure*)tmalloc(sizeof(struct measure)); measFind = (struct measure*)tmalloc(sizeof(struct measure)); @@ -891,7 +1247,7 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck) } case AT_WHEN: { - measure *meas; + MEASUREPTR meas; meas = (struct measure*)tmalloc(sizeof(struct measure)); if (measure_parse_when(meas, words, errbuf) ==0) { @@ -918,14 +1274,43 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck) return MEASUREMENT_OK; } case AT_RMS: - printf("\tmeasure '%s' failed\n", mName); - printf("Error: measure %s :\n", mName); - printf("\tfunction '%s' currently not supported\n", mFunction); - break; + case AT_INTEG: + { + // trig parameters + MEASUREPTR meas; + meas = (struct measure*)tmalloc(sizeof(struct measure)); + + if (measure_parse_trigtarg(meas, words , NULL, "trig", errbuf)==0) { + measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck); + return MEASUREMENT_FAILURE; + } + + // measure + measure_rms_integral(meas,mFunctionType); + + if (meas->m_measured == 0.0e0) { + sprintf(errbuf,"out of interval\n"); + measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck); // ?? + return MEASUREMENT_FAILURE; + } + + if (meas->m_at == -1) + meas->m_at = 0.0e0; + + // print results + if( out_line ){ + sprintf(out_line,"%-20s= %.*e from= %.*e to= %.*e\n", mName, precision, meas->m_measured, precision, meas->m_from, precision, meas->m_to); + } else { + printf("%-20s= %.*e from= %.*e to= %.*e\n", mName, precision, meas->m_measured, precision, meas->m_from, precision, meas->m_to); + } + *result=meas->m_measured; + return MEASUREMENT_OK; + + } case AT_AVG: { // trig parameters - measure *meas; + MEASUREPTR meas; meas = (struct measure*)tmalloc(sizeof(struct measure)); if (measure_parse_trigtarg(meas, words , NULL, "trig", errbuf)==0) { @@ -959,7 +1344,7 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck) case AT_MAX: { // trig parameters - measure *measTrig; + MEASUREPTR measTrig; measTrig = (struct measure*)tmalloc(sizeof(struct measure)); if (measure_parse_trigtarg(measTrig, words , NULL, "trig", errbuf)==0) { @@ -993,7 +1378,7 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck) { double minValue, maxValue; - measure *measTrig; + MEASUREPTR measTrig; measTrig = (struct measure*)tmalloc(sizeof(struct measure)); if (measure_parse_trigtarg(measTrig, words , NULL, "trig", errbuf)==0) { @@ -1028,7 +1413,6 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck) *result = (maxValue - minValue); return MEASUREMENT_OK; } - case AT_INTEG: case AT_DERIV: case AT_ERR: case AT_ERR1: diff --git a/src/frontend/com_measure2.h b/src/frontend/com_measure2.h index 2423d94e1..5226e809c 100644 --- a/src/frontend/com_measure2.h +++ b/src/frontend/com_measure2.h @@ -3,8 +3,9 @@ #include - int get_measure_precision(void) ; -/* void com_measure2(wordlist *wl); */ - int get_measure2(wordlist *wl,double *result,char *out_line, bool auto_check) ; +extern int get_measure_precision(void) ; +/* void com_measure2(wordlist *wl); */ +extern int get_measure2(wordlist *wl,double *result,char *out_line, bool auto_check) ; +extern int measure_extract_variables( char *line ) ; #endif diff --git a/src/frontend/dotcards.c b/src/frontend/dotcards.c index 18e206283..a2d2da260 100644 --- a/src/frontend/dotcards.c +++ b/src/frontend/dotcards.c @@ -23,13 +23,13 @@ $Id$ #include "variable.h" #include "fourier.h" #include "breakp2.h" +#include "com_measure2.h" /* Extract all the .save lines */ static void fixdotplot(wordlist *wl); static void fixdotprint(wordlist *wl); static char * fixem(char *string); -static wordlist * gettoks(char *s); static struct plot * @@ -90,6 +90,7 @@ ft_savedotargs(void) static wordlist all = { "all", NULL }; int isaplot; int i; + int status; if (!ft_curckt) /* Shouldn't happen. */ return 0; @@ -137,15 +138,10 @@ ft_savedotargs(void) com_save2(w, "TRAN"); /* A hack */ } } else if (ciprefix(".measure", s)) { - (void) gettok(&s); - name = gettok(&s); - (void) gettok(&s); - (void) gettok(&s); - if (!(w = gettoks(s))) { - fprintf(cp_err, "Warning: no nodes given: %s\n", iline->wl_word); - } - some = 1; - com_save2(w, name); + status = measure_extract_variables( s ) ; + if(!(status)){ + some = 1; + } } else if (ciprefix(".op", s)) { some = 1; com_save2(&all, "OP"); @@ -157,6 +153,24 @@ ft_savedotargs(void) return some; } +void +ft_savemeasure(void) +{ + char *s; + wordlist *iline; + + if (!ft_curckt) /* Shouldn't happen. */ + return ; + + for (iline = ft_curckt->ci_commands; iline; iline = iline->wl_next) { + s = iline->wl_word; + if (ciprefix(".measure", s)) { + (void) measure_extract_variables( s ) ; + } + } + return ; +} + /* Execute the .whatever lines found in the deck, after we are done running. * We'll be cheap and use cp_lexer to get the words... This should make us * spice-2 compatible. If terse is TRUE then there was a rawfile, so don't @@ -506,7 +520,7 @@ fixem(char *string) } -static wordlist * +wordlist * gettoks(char *s) { char *t; diff --git a/src/frontend/dotcards.h b/src/frontend/dotcards.h index 337b2c014..f25dbe5f6 100644 --- a/src/frontend/dotcards.h +++ b/src/frontend/dotcards.h @@ -9,6 +9,7 @@ void ft_dotsaves(void); int ft_savedotargs(void); int ft_cktcoms(bool terse); +wordlist *gettoks(char *s); #endif diff --git a/src/frontend/measure.c b/src/frontend/measure.c index b44c76d8f..2a70230ae 100644 --- a/src/frontend/measure.c +++ b/src/frontend/measure.c @@ -22,11 +22,7 @@ void winmessage(char* new_msg); #endif -#define OLD_WAY /* do not use functions from com_measure2.c */ - -#ifndef OLD_WAY static wordlist *measure_parse_line( char *line ) ; -#endif static bool measure_valid[20000];/* TRUE: if measurement no. [xxx] has been done successfully (not used anywhere)*/ @@ -34,257 +30,7 @@ static bool just_chk_meas; /* TRUE: only check if measurement can be done succ no output generated (if option autostop is set)*/ static bool measures_passed; /* TRUE: stop simulation (if option autostop is set)*/ -/* returns interpolated time point (char x_or_y='x') or interpolated data value */ -static double -interpolate( - struct dvec *time, /*in: vector of time points */ - struct dvec *values, /*in: vector of corresponding data points */ - int i, /*in: index to first time/data couple */ - int j, /*in: index to second time/data couple, i nad j setting the interval */ - double var_value, /*in: either time or data value */ - char x_or_y /*in: set to 'x': requires var_value to be data point, returns time; - otherwise expects var_value to be time, returns data value */ -) { - double slope = (values->v_realdata[j] - values->v_realdata[i])/(time->v_realdata[j] - time->v_realdata[i]); - double yint = values->v_realdata[i] - slope*time->v_realdata[i]; - double result; - - if ( x_or_y == 'x' ) result = (var_value - yint)/slope; - else result = slope*var_value + yint; - - return result; -} - -/* Takes a data value and returns corresponding time, but only after the number of -data crossings given by e.g. 'rise=3' have passed. */ -static double -get_volt_time( - struct dvec *time, /*in: vector of time points */ - struct dvec *values, /*in: vector of corresponding data points */ - double value, /*in: data value, for which time is sought */ - char polarity, /*in: 'r' (rise) or 'f' (fall) */ - int mindex, /*in: no. of times the data sequence has to cross 'value', before measurement commences */ - bool *failed /*out: TRUE if syntax error or time point not found */ -) { - int i = 0, count = 0; - double comp_time = 0; - - for ( i = 0; i < values->v_length-1; i++ ) { - if ( polarity == 'r' ) { - if ( values->v_realdata[i] < value && value <= values->v_realdata[i+1] ) { - /* increase 'count' if rising slope data cross 'value' */ - count++; - /* return interpolated time value only after the data sequence has crossed - 'value' mindex times*/ - if ( count == mindex ) comp_time = interpolate( time, values, i, i+1, value, 'x' ); - } - } - else if ( polarity == 'f' ) { - if ( values->v_realdata[i] >= value && value > values->v_realdata[i+1] ) { - /* increase 'count' if falling slope data cross 'value' */ - count++; - /* return interpolated time value only after the data sequence has crossed - 'value' mindex times*/ - if ( count == mindex ) comp_time = interpolate( time, values, i, i+1, value, 'x' ); - } - } - else { - if ( just_chk_meas != TRUE ) fprintf( stderr, "Error: unknown signal polarity '%c'; valid types are 'r' or 'f'.\n", polarity ); - *failed = TRUE; - } - } - if ( AlmostEqualUlps( comp_time, 0, 100 ) ) *failed = TRUE; - - return comp_time; -} - -/* Evaluate the delay between time values at trig and targ i or v levels. - Called by fcn do_delay_measurement(). - Returns FALSE if successful.*/ -static bool -measure( - char *trig_name, /*in: name (e.g. in) of vector (e.g. v(in)) following trig parameter */ - double trig_value, /*in: i or v value following trig parameter */ - char trig_polarity, /*in: r for rising slope, f for falling slope */ - int trig_index, /*in: time is measured only after this number of rising ( - falling) slopes with trigvalue has been detected*/ - char *targ_name, /*in: name (e.g. in) of vector (e.g. v(in)) following targ parameter */ - double targ_value, /*in: i or v level following targ parameter */ - char targ_polarity, /*in: r for rising slope, f for falling slope */ - int targ_index, /*in: time is measured only after this number of rising ( - falling) slopes with targvalue has been detected */ - double *result, /*out: difference between *targ_time and *trig_time*/ - double *trig_time, /*out: time at given i or v level following trig parameter*/ - double *targ_time /*out: time at given i or v level following targ parameter*/ -) { - struct dvec *time = vec_get("time"); - struct dvec *trig = vec_get(trig_name); - struct dvec *targ = vec_get(targ_name); - bool failed = FALSE; - - if ( !time ) { if ( just_chk_meas != TRUE ) fprintf( stderr, "Error: problem accessing vector 'time'!\n" ); return TRUE; } - if ( !trig ) { if ( just_chk_meas != TRUE ) fprintf( stderr, "Error: problem accessing vector '%s'!\n", trig_name ); return TRUE; } - if ( !targ ) { if ( just_chk_meas != TRUE ) fprintf( stderr, "Error: problem accessing vector '%s'!\n", targ_name ); return TRUE; } - - *trig_time = get_volt_time( time, trig, trig_value, trig_polarity, trig_index, &failed ); - *targ_time = get_volt_time( time, targ, targ_value, targ_polarity, targ_index, &failed ); - *result = *targ_time - *trig_time; - return failed; -} - -/*Do any other measurements: - avg: (average) calculates the area under the out_var divided by the periods of interest - rms: (root mean squared) calculates the square root of the area under the out_var^2 curve - divided by the period of interest - integ(ral): calculate the integral in period of interest - min|max: find min or max value in period of interest - when: get time when an vetor reaches a value. - Called by fcn do_other_measurement(). - Returns FALSE if successful. -*/ -static bool -measure2( - char *meas_type, /* one of avg|rms|integ(ral)|min|max|when*/ - char *vec_name, /*in: name (e.g. 'v0') of vector (e.g. i(v0) )*/ - char vec_type, /*in: type (e.g. 'i') of vector (e.g. i(v0) ), may be 'v' or 'i'*/ - double from, /*in: start value (e.g. of time) defining region of interest */ - double to, /*in: stop value */ - double *result, /*out: measurement result */ - double *result_time /*out: time value where *result occurs (not valid for avg, rms, integ) */ -) { - struct dvec *time = vec_get("time"); - struct dvec *vec; - int xy_size = 0; - double *x, *y, *width, sum1 = 0, sum2 = 0, sum3 = 0; - double init_val; - char tmp_vec_name[1000]; - double prev_result = 0; - bool failed = FALSE, first_time = TRUE, constant_y = TRUE; - int i, idx, upflag ; - - if ( to < from ) { if ( just_chk_meas != TRUE ) fprintf( stderr, "Error: (measure2) 'to' time (%e) < 'from' time (%e).\n", to, from ); return TRUE; } - - if ( vec_type == 'i' ) { - if ( strstr( vec_name, ".v" ) ) sprintf( tmp_vec_name, "v.%s#branch", vec_name ); - else sprintf( tmp_vec_name, "%s#branch", vec_name ); - } - else sprintf( tmp_vec_name, "%s", vec_name ); - - vec = vec_get( tmp_vec_name ); - - if ( !time ) { if ( just_chk_meas != TRUE ) fprintf( stderr, "Error: problem accessing vector 'time'!\n" ); return TRUE; } - if ( !vec ) { if ( just_chk_meas != TRUE ) fprintf( stderr, "Error: problem accessing vector '%s'!\n", tmp_vec_name ); return TRUE; } - - if ( strcmp( meas_type, "max" ) == 0 || strcmp( meas_type, "min" ) == 0 ) { - for ( i = 0; i < vec->v_length; i++ ) { - if ( time->v_realdata[i] >= from && ( i+1 < time->v_length && time->v_realdata[i+1] <= to ) ) { - prev_result = *result; - if ( first_time ) { - first_time = FALSE; - *result = vec->v_realdata[i]; - *result_time = time->v_realdata[i]; - } else { - *result = ( strcmp( meas_type, "max" ) == 0 ) ? MAX( *result, vec->v_realdata[i] ) : MIN( *result, vec->v_realdata[i] ); - if ( !AlmostEqualUlps( prev_result, *result, 100 ) ) *result_time = time->v_realdata[i]; - } - } - } - } - else if ( strcmp( meas_type, "avg" ) == 0 || strcmp( meas_type, "rms" ) == 0 || - strcmp( meas_type, "integral" ) == 0 || strcmp( meas_type, "integ" ) == 0 ) { - x = (double *) tmalloc(time->v_length * sizeof(double)); - y = (double *) tmalloc(time->v_length * sizeof(double)); - width = (double *) tmalloc(time->v_length * sizeof(double)); - - // create new set of values over interval [from, to] -- interpolate if necessary - for ( i = 0; i < vec->v_length; i++ ) { - if ( time->v_realdata[i] >= from && time->v_realdata[i] <= to ) { - *(x+xy_size) = time->v_realdata[i]; - *(y+xy_size++) = ( strcmp( meas_type, "avg" ) == 0 || ciprefix( "integ", meas_type ) ) ? vec->v_realdata[i] : pow(vec->v_realdata[i],2); - } - } - // evaluate segment width - for ( i = 0; i < xy_size-1; i++ ) *(width+i) = *(x+i+1) - *(x+i); - *(width+i++) = 0; - *(width+i++) = 0; - - // see if y-value constant - for ( i = 0; i < xy_size-1; i++ ) - if ( !AlmostEqualUlps( *(y+i), *(y+i+1), 100 ) ) constant_y = FALSE; - - // Compute Integral (area under curve) - i = 0; - while ( i < xy_size-1 ) { - // Simpson's 3/8 Rule - if ( AlmostEqualUlps( *(width+i), *(width+i+1), 100 ) && AlmostEqualUlps( *(width+i), *(width+i+2), 100 ) ) { - sum1 += 3*(*(width+i))*(*(y+i) + 3*(*(y+i+1) + *(y+i+2)) + *(y+i+3))/8; - i += 3; - } - // Simpson's 1/3 Rule - else if ( AlmostEqualUlps( *(width+i), *(width+i+1), 100 ) ) { - sum2 += *(width+i)*(*(y+i) + 4*(*(y+i+1)) + *(y+i+2))/3; - i += 2; - } - // Trapezoidal Rule - else if ( !AlmostEqualUlps( *(width+i), *(width+i+1), 100 ) ) { - sum3 += *(width+i)*(*(y+i) + *(y+i+1))/2; - i++; - } - } - - if ( !ciprefix( "integ", meas_type ) ) { - *result = (sum1 + sum2 + sum3)/(to - from); - - if ( strcmp( meas_type, "rms" ) == 0 ) *result = sqrt(*result); - if ( strcmp( meas_type, "avg" ) == 0 && constant_y == TRUE ) *result = *y; - } - else { - *result = ( sum1 + sum2 + sum3 ); - } - txfree(x); txfree(y); txfree(width); - } - else if ( strcmp( meas_type, "when" ) == 0 ){ - init_val = vec->v_realdata[0] ; - /* 'from' is used as input value */ - if ( AlmostEqualUlps( init_val, from, 100 ) ){ - /* match right out of the gate. */ - *result = vec->v_realdata[0]; - *result_time = time->v_realdata[0]; - return failed ; - } - if( init_val < from ){ - /* search upward */ - upflag = TRUE ; - } else { - /* search downward */ - upflag = FALSE ; - } - idx = -1 ; - for ( i = 0; i < vec->v_length; i++ ) { - if ( AlmostEqualUlps( vec->v_realdata[i], from, 100 ) ){ - idx = i ; - break ; - } else if( upflag && (vec->v_realdata[i] > from) ){ - idx = i ; - break ; - } else if( !(upflag) && (vec->v_realdata[i] < from) ){ - idx = i ; - break ; - } - } - if( idx < 0 ){ - return failed; - } - *result = vec->v_realdata[idx] ; - *result_time = interpolate( time, vec, idx-1, i, from, 'x' ); - } - else { - if ( just_chk_meas != TRUE ) fprintf( cp_err, "Error: (measure2) unknown meas function '%s'.\n", meas_type ); - return TRUE; - } - return failed; -} static bool chkAnalysisType( char *an_type ) { @@ -299,49 +45,13 @@ chkAnalysisType( char *an_type ) { else return TRUE; } -/* Gets pointer to integer value after 'xxx=' and advances pointer of *line. - On error returns FALSE. */ -static bool -get_int_value( - char **line, /*in|out: pointer to line to be parsed */ - char *name, /*in: xxx e.g. 'fall' from example 'fall=2' */ - int *value /*out: return value (e.g. 2 from 'fall=2' */ -) { - /*get token (e.g. 'fall=1' and advance pointer*/ - char *token = gettok(line); - bool return_val = TRUE; - char *equal_ptr; - - if ( strncmp( token, name, strlen(name) ) != 0 ) { - if ( just_chk_meas != TRUE ) fprintf( cp_err, "Error: syntax error for measure statement; expecting next field to be '%s'.\n", name ); - return_val = FALSE; - } else { - /* see if '=' is last char of current token -- implies we need to read value in next token */ - if ( *(token + strlen(token) - 1) == '=' ) { - txfree(token); - token = gettok(line); - *value = atoi(token); - } else { - if ( (equal_ptr = strstr( token, "=" )) ) { - *value = atoi(equal_ptr+1); - } else { - if ( just_chk_meas != TRUE ) fprintf( cp_err, "Error: syntax error for measure statement; missing '='!\n" ); - return_val = FALSE; - } - } - } - txfree(token); - - return return_val; -} - /* Gets pointer to double value after 'xxx=' and advances pointer of *line. On error returns FALSE. */ static bool get_double_value( - char **line, /*in|out: pointer to line to be parsed */ - char *name, /*in: xxx e.g. 'val' from 'val=0.5' */ + char **line, /*in|out: pointer to line to be parsed */ + char *name, /*in: xxx e.g. 'val' from 'val=0.5' */ double *value /*out: return value (e.g. 0.5) from 'val=0.5'*/ ) { char *token = gettok(line); @@ -375,235 +85,6 @@ get_double_value( return return_val; } - /*-------------------------------------------------------------------------* - gettok_paren skips over whitespace and returns the next token found. Here it - is used only to return part of a vector, eg V(in) or I(mynode). - For example v(in) has already been stripped to in) when gettok_paren is called. - gettok_paren returns 'in', leaving ')' as the next character of s. - Only called from fcn get_vector_name(). - *-------------------------------------------------------------------------*/ - static char * - gettok_paren(char **s) - { - char buf[BSIZE_SP]; - int i = 0; - char c; - int paren; - - paren = 0; - /* skip over leading white spaces */ - while (isspace(**s)) - (*s)++; - /* if nothing left (end of line), return NULL */ - if (!**s) - return (NULL); - - while ((c = **s) && !isspace(c)) { - if (c == '('/*)*/) - paren += 1; - else if (c == /*(*/')'){ - paren -= 1; - if( paren <= 0 ) /* added over gettok */ - break ; - } else if (c == ',' && paren < 1) - break; - buf[i++] = *(*s)++; - } - buf[i] = '\0'; - /* skip over trailing white spaces and commas*/ - while (isspace(**s) || **s == ',') - (*s)++; - return (copy(buf)); - } - -static char* -get_vector_name( char **line ) { - char *token, *name; - -// token = name = gettok(line); - token = name = gettok_paren(line); - -// *(name + strlen(name) - 1) = '\0'; - name = strdup(name); txfree(token); - - return name; -} - -/* Evaluate measurement types trig|delay . - Called by do_measure(). - Calls measure(). */ -static bool -do_delay_measurement( - char *resname, /*in: name of result parameter, defined by user*/ - char *out_line, /*out: output for printing */ - char *line, /*in: .meas card, first four parameters stripped */ - char *o_line, /*in: .meas card, complete */ - int meas_index, /*in: number of actual measurement */ - double *result /*out: delay value returned by measure() */ - /*global variable measures_passed - out: set to FALSE if measurement failed (used with autostop)*/ - ) { - char *trig_name, *targ_name, *token; - char trig_type, targ_type, trig_polarity, targ_polarity; - double targ_value, trig_value; - int trig_index, targ_index; - double trig_time = 0, targ_time = 0; - int precision = get_measure_precision(); - bool failed; - - measure_valid[meas_index] = FALSE; - - trig_type = *line; line += 2; /* skip over vector type and open paren */ - trig_name = get_vector_name( &line ); - while(*line && !(*line == ')')) line++; /* find ')' */ - line++; /* move on beyond ')' */ - - if ( trig_type != 'v' && trig_type != 'i' ) { - if ( just_chk_meas != TRUE ) { - fprintf( cp_err, "Error: unexpected vector type '%c' for .meas!\n", trig_type ); - fprintf( cp_err, " %s\n", o_line ); - } - txfree(trig_name); return FALSE; - } - - if ( !get_double_value( &line, "val", &trig_value ) ) { if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line ); txfree(trig_name); return FALSE; } - - if ( strncmp( line, "rise", 4 ) == 0 ) { - trig_polarity = 'r'; - if ( !get_int_value( &line, "rise", &trig_index ) ) { if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line ); txfree(trig_name); return FALSE; } - } - else if ( strncmp( line, "fall", 4 ) == 0 ) { - trig_polarity = 'f'; - if ( !get_int_value( &line, "fall", &trig_index ) ) { if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line ); txfree(trig_name); return FALSE; } - } - else { - if ( just_chk_meas != TRUE ) { - fprintf( cp_err, "Error: expecting next token to be rise|fall for measurement!\n" ); - fprintf( cp_err, " %s\n", o_line ); - } - txfree(trig_name); return FALSE; - } - - token = gettok(&line); - if ( strcmp(token, "targ" ) != 0 ) { - if ( just_chk_meas != TRUE ) { - fprintf( cp_err, "Error: expected 'targ' as next token in .meas statement!\n" ); - fprintf( cp_err, " %s\n", o_line ); - } - txfree(token); txfree(trig_name); return FALSE; - } - txfree(token); - - targ_type = *line; line += 2; /* skip over vector type and open paren */ - targ_name = get_vector_name( &line ); - while(*line && !(*line == ')')) line++; /* find ')' */ - line++; /* move on beyond ')' */ - - if ( targ_type != 'v' && targ_type != 'i' ) { - if ( just_chk_meas != TRUE ) { - fprintf( cp_err, "Error: unexpected vector type '%c' for .meas!\n", targ_type ); - fprintf( cp_err, " %s\n", o_line ); - } - txfree(trig_name); txfree(targ_name); return FALSE; - } - - if ( !get_double_value( &line, "val", &targ_value ) ) { if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line ); txfree(trig_name); txfree(targ_name); return FALSE; } - - if ( strncmp( line, "rise", 4 ) == 0 ) { - targ_polarity = 'r'; - if ( !get_int_value( &line, "rise", &targ_index ) ) { if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line ); txfree(trig_name); txfree(targ_name); return FALSE; } - } - else if ( strncmp( line, "fall", 4 ) == 0 ) { - targ_polarity = 'f'; - if ( !get_int_value( &line, "fall", &targ_index ) ) { if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line ); txfree(trig_name); txfree(targ_name); return FALSE; } - } - else { - if ( just_chk_meas != TRUE ) { - fprintf( cp_err, "Error: expecting next token to be rise|fall for measurement!\n" ); - fprintf( cp_err, " %s\n", o_line ); - } - txfree(trig_name); txfree(targ_name); return FALSE; - } - - failed = measure( trig_name, trig_value, trig_polarity, trig_index, targ_name, targ_value, targ_polarity, - targ_index, result, &trig_time, &targ_time ); - - if ( !failed ) { - sprintf( out_line, "%-15s= %.*e targ= %.*e trig= %.*e\n", resname, precision, *result, precision, targ_time, precision, trig_time ); - measure_valid[meas_index] = TRUE; - } else { - measures_passed = FALSE; - sprintf( out_line, "%-15s= failed\n", resname ); - measure_valid[meas_index] = FALSE; - } - - txfree(trig_name); txfree(targ_name); - - return ( failed ) ? FALSE : TRUE; -} - -static bool -do_other_measurement( char *resname, char *out_line, char *meas_type, char *line, char *o_line, int meas_index, double *result ) { - - char *vec_name; - char vec_type; - double from, to, result_time = 0; - int precision = get_measure_precision(); - bool failed; - - vec_type = *line; line += 2; /* skip over vector type and open paren */ - vec_name = get_vector_name( &line ); - while(*line && !(*line == ')')) line++; /* find ')' */ - line++; /* move on beyond ')' */ - - if ( vec_type != 'v' && vec_type != 'i' ) { - if ( just_chk_meas != TRUE ) { - fprintf( cp_err, "Error: unexpected vector type '%c' for .meas!\n", vec_type ); - fprintf( cp_err, " %s\n", o_line ); - } - txfree(vec_name); - return FALSE; - } - if ( strcmp( meas_type, "when" ) == 0 ){ - if ( !get_double_value( &line, NULL, &from ) ) { - if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line ); - txfree(vec_name); - return FALSE; - } - to = from ; - } else { - if ( !get_double_value( &line, "from", &from ) ) { - if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line ); - txfree(vec_name); - return FALSE; - } - if ( !get_double_value( &line, "to", &to ) ) { - if ( just_chk_meas != TRUE ) fprintf( cp_err, " %s\n", o_line ); - txfree(vec_name); - return FALSE; - } - } - - failed = measure2( meas_type, vec_name, vec_type, from, to, result, &result_time ); - - if ( !failed ) { - if ( strcmp( meas_type, "max" ) == 0 || strcmp( meas_type, "min" ) == 0 ) - sprintf( out_line, "%-15s= %.*e at= %.*e\n", resname, precision, *result, precision, result_time ); - else if ( strcmp( meas_type, "when" ) == 0 ) - sprintf( out_line, "%-15s= %.*e\n", resname, precision, result_time ) ; - else - sprintf( out_line, "%-15s= %.*e from= %.*e to= %.*e\n", resname, precision, *result, precision, from, precision, to ); - measure_valid[meas_index] = TRUE; - } else { - measures_passed = FALSE; - sprintf( out_line, "%-15s= failed\n", resname ); - measure_valid[meas_index] = FALSE; - } - - txfree(vec_name); - - return ( failed ) ? FALSE : TRUE; -} /* Entry point for .meas evaluation. Called in fcn dosim() from runcoms.c:335, after simulation is finished @@ -624,7 +105,7 @@ do_measure( double result = 0; bool first_time = TRUE; wordlist *measure_word_list ; - int precision = get_measure_precision(); + int precision = measure_get_precision() ; just_chk_meas = chk_only; @@ -642,9 +123,8 @@ do_measure( measurement type trig|delay|param|expr|avg|mean|max|min|rms|integ(ral)|when The measurement type determines how to continue the .meas card. - trig|delay are handled in fcn do_delay_measurement(), param|expr are skipped - in first pass through .meas cards and are treated in second pass, - all others are treated in fcn do_other_measurement(). + param|expr are skipped in first pass through .meas cards and are treated in second pass, + all others are treated in fcn get_measure2() (com_measure2.c). */ /* first pass through .meas cards: evaluate everything except param|expr */ @@ -683,42 +163,27 @@ do_measure( continue; } -#ifdef OLD_WAY - if ( strcmp( meastype, "trig" ) == 0 || strcmp( meastype, "delay" ) == 0 ) { - if ( do_delay_measurement( resname, out_line, line, meas_card->li_line, idx++, &result ) && just_chk_meas != TRUE ) { - nupa_add_param( resname, result ); - } - } - else if ( strcmp( meastype, "avg" ) == 0 || strcmp( meastype, "mean" ) == 0 || - strcmp( meastype, "max" ) == 0 || strcmp( meastype, "min" ) == 0 || - strcmp( meastype, "rms" ) == 0 || strcmp( meastype, "integ" ) == 0 || - strcmp( meastype, "integral" ) == 0 || strcmp( meastype, "when" ) == 0 ) { - if ( do_other_measurement( resname, out_line, meastype, line, meas_card->li_line, idx++, &result ) && just_chk_meas != TRUE ) { - nupa_add_param( resname, result ); + /* New way of processing measure statements using common code + in fcn get_measure2() (com_measure2.c)*/ + out_line[0] = EOS ; + measure_word_list = measure_parse_line( meas_card->li_line) ; + if( measure_word_list ){ + fail = get_measure2(measure_word_list,&result,out_line,chk_only) ; + if( fail ){ + measure_valid[idx++] = FALSE; + measures_passed = FALSE; + } else { + if(!(just_chk_meas)){ + nupa_add_param( resname, result ); + } + measure_valid[idx++] = TRUE; } - } - else { + wl_free( measure_word_list ) ; + } else { + measure_valid[idx++] = FALSE; measures_passed = FALSE; - sprintf( out_line, "%-15s= failed\n", resname ); - if ( just_chk_meas != TRUE ) { - fprintf( cp_err, "Error: unsupported measurement type '%s' on line %d:\n", meastype, meas_card->li_linenum ); - fprintf( cp_err, " %s\n", meas_card->li_line ); - } } - -#else /* NEW_WAY */ - out_line[0] = EOS ; - measure_word_list = measure_parse_line( meas_card->li_line) ; - fail = get_measure2(measure_word_list,&result,out_line,chk_only) ; - if( fail ){ - measure_valid[idx++] = FALSE; - measures_passed = FALSE; - } else { - nupa_add_param( resname, result ); - measure_valid[idx++] = TRUE; - } - #endif /* OLD_WAY */ - + newcard = alloc(struct line); newcard->li_line = strdup(out_line); newcard->li_next = NULL; @@ -731,7 +196,7 @@ do_measure( txfree(an_type); txfree(resname); txfree(meastype); - // see if number of measurements exceeds fixed array size of 20,000 + /* see if number of measurements exceeds fixed array size of 20,000 */ if ( idx >= 20000 ) { fprintf( stderr, "ERROR: number of measurements exceeds 20,000!\nAborting...\n" ); #ifdef HAS_WINDOWS @@ -739,8 +204,10 @@ do_measure( #endif exit(-1); } + } /* end of for loop (first pass through .meas lines) */ + /* second pass through .meas cards: now do param|expr .meas statements */ newcard = meas_results; for ( meas_card = ft_curckt->ci_meas; meas_card != NULL; meas_card = meas_card->li_next ) { @@ -777,7 +244,7 @@ do_measure( continue; } - if ( just_chk_meas != TRUE ) fprintf( stdout, "%-15s=", resname ); + if ( just_chk_meas != TRUE ) fprintf( stdout, "%-20s=", resname ); if ( just_chk_meas != TRUE ) { ok = nupa_eval( meas_card->li_line, meas_card->li_linenum ); @@ -788,7 +255,7 @@ do_measure( if ( just_chk_meas != TRUE ) fprintf( stdout, " failed\n" ); } else { - if ( just_chk_meas != TRUE ) fprintf( stdout, " %.*e\n", precision, result ); + if ( just_chk_meas != TRUE ) fprintf( stdout, " %.*e\n", precision, result ); nupa_add_param( resname, result ); } } @@ -830,7 +297,8 @@ check_autostop( char* what ) { return flag; } - static wordlist *measure_parse_line( char *line ) +/* parses the .meas line into a wordlist (without leading .meas) */ +static wordlist *measure_parse_line( char *line ) { int len ; /* length of string */ wordlist *wl ; /* build a word list - head of list */ diff --git a/src/frontend/numparam/numparam.h b/src/frontend/numparam/numparam.h index 0a50fdd2b..8ccc20163 100644 --- a/src/frontend/numparam/numparam.h +++ b/src/frontend/numparam/numparam.h @@ -68,6 +68,7 @@ typedef struct _ttdico { char **dynrefptr; // char category[Maxline]; /* category of each line */ char *dyncategory; + int hspice_compatibility; /* allow hspice keywords */ } tdico; void initdico(tdico * dico); diff --git a/src/frontend/numparam/xpressn.c b/src/frontend/numparam/xpressn.c index 92321093f..ccd3f70e8 100644 --- a/src/frontend/numparam/xpressn.c +++ b/src/frontend/numparam/xpressn.c @@ -9,10 +9,7 @@ #include "general.h" #include "numparam.h" #include "ngspice.h" - -#ifdef _MSC_VER -#define strcasecmp _stricmp -#endif +#include "../compatmode.h" /* random numbers in /maths/misc/randnumb.c */ extern double gauss(); @@ -158,6 +155,8 @@ void initdico (tdico * dico) { int i; + COMPATMODE_T compat_mode; + dico->nbd = 0; sini(dico->option,sizeof(dico->option)-4); sini(dico->srcfile,sizeof(dico->srcfile)-4); @@ -172,6 +171,12 @@ initdico (tdico * dico) dico->tos = 0; dico->stack[dico->tos] = 0; /* global data beneath */ initkeys (); + + compat_mode = ngpsice_compat_mode() ; + if( compat_mode == COMPATMODE_HSPICE ) + dico->hspice_compatibility = 1 ; + else + dico->hspice_compatibility = 0 ; } /* local semantics for parameters inside a subckt */ @@ -1437,7 +1442,11 @@ scanline (tdico * dico, char *s, char *r, unsigned char err) else { pscopy (t, s, i + 1, k - i - 1); - err = evaluate (dico, q, t, 0); + if( dico->hspice_compatibility && (strcasecmp(t,"LAST")==0) ) { + strcpy(q,"last") ; + err=0; + } else + err = evaluate (dico, q, t, 0); } i = k; if (!err) diff --git a/src/include/bool.h b/src/include/bool.h index 8744cb49d..a3869a7d9 100644 --- a/src/include/bool.h +++ b/src/include/bool.h @@ -2,6 +2,7 @@ #define _BOOL_H typedef unsigned char bool; +typedef int BOOL ; #define BOOLEAN int #define TRUE 1 diff --git a/src/include/macros.h b/src/include/macros.h index 9592a8d3c..9c90efe42 100644 --- a/src/include/macros.h +++ b/src/include/macros.h @@ -71,9 +71,17 @@ #ifdef DEBUG #define DEBUGMSG(textargs) printf(textargs) -#else +#define DS(name_xz) { name_xz } +#define DBGDEFINE(func_xz) func_xz +#else /* ! DEBUG */ #define DEBUGMSG(testargs) -#endif +#define DS(name_xz) +#define DBGDEFINE(func_xz) +#endif /* DEBUG */ + +/* A few useful macros - string eq just makes the code easier to read */ +#define STRINGEQ 0 +#define FUNC_NAME(x_xz) char *routine = x_xz /* Macro that queries the system to find the process time. */ diff --git a/src/misc/Makefile.am b/src/misc/Makefile.am index 068f1f1d2..bcfe4cb68 100644 --- a/src/misc/Makefile.am +++ b/src/misc/Makefile.am @@ -11,8 +11,12 @@ libmisc_la_SOURCES = \ alloc.h \ dup2.c \ dup2.h \ + hash.h \ + hash.c \ ivars.c \ ivars.h \ + mempool.c \ + mempool.h \ mktemp.c \ mktemp.h \ printnum.c \ diff --git a/src/tclspice.c b/src/tclspice.c index abc490924..a92501e1d 100755 --- a/src/tclspice.c +++ b/src/tclspice.c @@ -95,6 +95,7 @@ typedef pthread_t threadId_t; #include #include #include +#include #ifndef _MSC_VER /* avoid second definition of VT_BOOL */ #include #else @@ -2115,7 +2116,7 @@ static int listTriggers TCL_CMDPROCARGS(clientData,interp,argc,argv){ static int tmeasure TCL_CMDPROCARGS(clientData,interp,argc,argv){ wordlist *wl= NULL; - float mvalue; + double mvalue; if (argc <= 2) { Tcl_SetResult(interp, "Wrong # args. spice::listTriggers",TCL_STATIC); @@ -2124,7 +2125,7 @@ static int tmeasure TCL_CMDPROCARGS(clientData,interp,argc,argv){ wl =wl_build((char **)argv); - mvalue = get_measure2(wl); + get_measure2(wl,&mvalue,NULL,FALSE); printf(" %e \n", mvalue); diff --git a/visualc/vngspice.sln b/visualc/vngspice.sln index 02117cf6d..31e2c94ca 100644 --- a/visualc/vngspice.sln +++ b/visualc/vngspice.sln @@ -11,8 +11,8 @@ Global GlobalSection(ProjectConfigurationPlatforms) = postSolution {83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Debug|Win32.ActiveCfg = Debug|Win32 {83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Debug|Win32.Build.0 = Debug|Win32 - {83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Release|Win32.ActiveCfg = Release|Win32 - {83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Release|Win32.Build.0 = Release|Win32 + {83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Release|Win32.ActiveCfg = Debug|Win32 + {83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Release|Win32.Build.0 = Debug|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/visualc/vngspice.vcproj b/visualc/vngspice.vcproj index a639bc44b..f216ab314 100644 --- a/visualc/vngspice.vcproj +++ b/visualc/vngspice.vcproj @@ -819,6 +819,10 @@ RelativePath="..\src\frontend\commands.h" > + + @@ -1103,12 +1107,16 @@ RelativePath="..\src\frontend\plotting\graphdb.h" > + + + + @@ -4503,6 +4515,10 @@ RelativePath="..\src\frontend\commands.c" > + + @@ -4999,6 +5015,10 @@ RelativePath="..\src\frontend\plotting\grid.c" > + + @@ -5875,6 +5895,10 @@ RelativePath="..\src\frontend\measure.c" > + +