new code for .measurement

This commit is contained in:
h_vogt 2009-08-23 10:02:28 +00:00
parent 4692651211
commit 9f1ee290a4
14 changed files with 628 additions and 710 deletions

View File

@ -95,6 +95,8 @@ libfte_la_SOURCES = \
breakp2.h \ breakp2.h \
circuits.c \ circuits.c \
circuits.h \ circuits.h \
compatmode.c \
compatmode.h \
cpitf.c \ cpitf.c \
cpitf.h \ cpitf.h \
define.c \ define.c \

View File

@ -1,7 +1,7 @@
/* New routines to evaluate the .measure cards. /* New routines to evaluate the .measure cards.
Entry point is function get_measure2(), called by fcn do_measure() Entry point is function get_measure2(), called by fcn do_measure()
from measure.c, if line measure.c:25 is commented out. 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$ $Id$
*/ */
@ -14,12 +14,9 @@
#include "vectors.h" #include "vectors.h"
#include <math.h> #include <math.h>
#include "dotcards.h"
#include "com_measure2.h" #include "com_measure2.h"
#ifdef _MSC_VER
#define strcasecmp _stricmp
#endif
typedef enum { typedef enum {
MEASUREMENT_OK = 0, MEASUREMENT_OK = 0,
MEASUREMENT_FAILURE = 1 MEASUREMENT_FAILURE = 1
@ -33,42 +30,225 @@ typedef struct measure
char *result; char *result;
char *m_vec; // name of the output variable which determines the beginning of the measurement char *m_vec; // name of the output variable which determines the beginning of the measurement
char *m_vec2; char *m_vec2; // second output variable to measure if applicable
int m_rise; int m_rise; // count number of rise events
int m_fall; int m_fall; // count number of fall events
int m_cross; 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_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_td; // amount of delay before the measurement should start
double m_from; double m_from; // measure only in a time window - starting time of window
double m_to; double m_to; // measurement window - ending time
double m_at; double m_at; // measure at the specified time
double m_measured; double m_measured; // what we measured
double m_measured_at; double m_measured_at; //* what we measured at the given time
} measure; } MEASURE, *MEASUREPTR ;
enum AnalysisType { typedef enum AnalysisType {
AT_DELAY, AT_TRIG, AT_UNKNOWN, AT_DELAY, AT_TRIG,
AT_FIND, AT_WHEN, AT_FIND, AT_WHEN,
AT_AVG, AT_MIN, AT_MAX, AT_RMS, AT_PP, AT_AVG, AT_MIN, AT_MAX, AT_RMS, AT_PP,
AT_INTEG, AT_DERIV, AT_INTEG, AT_DERIV,
AT_ERR, AT_ERR1, AT_ERR2, AT_ERR3 AT_ERR, AT_ERR1, AT_ERR2, AT_ERR3
}; } ANALYSIS_TYPE_T ;
/** return precision (either 5 or value of environment variable NGSPICE_MEAS_PRECISION) */ /** 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; char *env_ptr;
int precision = 5; int precision = 5;
if ( ( env_ptr = getenv("NGSPICE_MEAS_PRECISION") ) ) { if ( ( env_ptr = getenv("NGSPICE_MEAS_PRECISION") ) ) {
precision = atoi(env_ptr); precision = atoi(env_ptr);
} }
return precision; return precision;
} /* end measure_get_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
* + <TD=td> <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
* + <TRIG AT=time>
* + TARG targ_variable VAL=val
* + <TD=td> <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
* + <TRIG AT=time>
*
* .MEASURE {DC|AC|TRAN} result WHEN out_variable=val
* + <TD=td> <FROM=val> <TO=val>
* + <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
*
* .MEASURE {DC|AC|TRAN} result WHEN out_variable=out_variable2
* + <TD=td> <FROM=val> <TO=val>
* + <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
*
* .MEASURE {DC|AC|TRAN} result FIND out_variable WHEN out_variable2=val
* + <TD=td> <FROM=val> <TO=val>
* + <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
*
* .MEASURE {DC|AC|TRAN} result FIND out_variable WHEN out_variable2=out_variable3
* + <TD=td>
* + <CROSS=# | CROSS=LAST> <RISE=#|RISE=LAST> <FALL=#|FALL=LAST>
*
* .MEASURE {DC|AC|TRAN} result FIND out_variable AT=val
* + <FROM=val> <TO=val>
*
* .MEASURE {DC|AC|TRAN} result {AVG|MIN|MAX|PP|RMS} out_variable
* + <TD=td> <FROM=val> <TO=val>
*
* .MEASURE {DC|AC|TRAN} result INTEG<RAL> out_variable
* + <TD=td> <FROM=val> <TO=val>
*
* .MEASURE {DC|AC|TRAN} result DERIV<ATIVE> out_variable
* + <TD=td> <FROM=val> <TO=val> <AT=val>
*
* .MEASURE {DC|AC|TRAN} result DERIV<ATIVE> out_variable
* + <TD=td> <FROM=val> <TO=val> <AT=val>
* ----------------------------------------------------------------- */
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 i, first;
int riseCnt = 0; int riseCnt = 0;
@ -129,7 +309,7 @@ void com_measure_when(struct measure *meas) {
crossCnt =1; crossCnt =1;
} }
} }
printf(""); fflush( stdout ) ;
} }
if (first > 1) { if (first > 1) {
@ -186,7 +366,15 @@ void com_measure_when(struct measure *meas) {
return; 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; int i;
double value, pvalue, svalue, psvalue; double value, pvalue, svalue, psvalue;
@ -224,13 +412,17 @@ void measure_at(struct measure *meas, double at) {
return; 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; int i, avgCnt;
struct dvec *d, *dScale; struct dvec *d, *dScale;
@ -272,7 +464,7 @@ void measure_minMaxAvg( struct measure *meas, int minMax ) {
first =1; first =1;
} else { } else {
switch (minMax) { switch (mFunctionType) {
case AT_MIN: { case AT_MIN: {
if (value <= mValue) { if (value <= mValue) {
mValue = value; mValue = value;
@ -287,53 +479,195 @@ void measure_minMaxAvg( struct measure *meas, int minMax ) {
} }
break; break;
} }
case AT_AVG: case AT_AVG: {
case AT_RMS: {
mValue = mValue + value; mValue = mValue + value;
avgCnt ++; avgCnt ++;
break; break;
} }
default :
fprintf(cp_err, "Error: improper min/max/avg call.\n");
} }
} }
} }
switch (minMax) switch (mFunctionType)
{ {
case AT_AVG: { case AT_AVG: {
meas->m_measured = (mValue / avgCnt); meas->m_measured = (mValue / avgCnt);
meas->m_measured_at = svalue; meas->m_measured_at = svalue;
break; 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_MIN:
case AT_MAX: { case AT_MAX: {
meas->m_measured = mValue; meas->m_measured = mValue;
meas->m_measured_at = mValueAt; meas->m_measured_at = mValueAt;
break; break;
} }
default :
fprintf(cp_err, "Error: improper min/max/avg call.\n");
} }
return; 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): // RMS (root mean squared):
// Calculates the square root of the area under the 'out_var2' curve // Calculates the square root of the area under the 'out_var2' curve
// divided be the period of interest // divided be the period of interest
measure_rms_integral(meas,AT_RMS) ;
return; 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 // INTEGRAL INTEG
measure_rms_integral(meas,AT_INTEG) ;
return; return;
} }
/* still some more work to do.... */
void measure_deriv( ) { void measure_deriv( ) {
// DERIVATIVE DERIV // DERIVATIVE DERIV
return; return;
@ -356,13 +690,6 @@ void measure_ERR3( ) {
return; 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( ) { void com_dotmeasure( ) {
@ -373,20 +700,38 @@ void com_dotmeasure( ) {
return; 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) if(varname == NULL)
return 1; return TRUE;
d = vec_get(vec); d = vec_get(varname);
if (d == NULL) 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; int pCnt;
char *p, *pName, *pValue; char *p, *pName, *pValue;
@ -475,7 +820,17 @@ int measure_parse_stdParams (struct measure *meas, wordlist *wl, wordlist *wlBre
return 1; 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; int pCnt;
char *p, *pName, *pVal; char *p, *pName, *pVal;
@ -497,9 +852,7 @@ int measure_parse_find (struct measure *meas, wordlist *wl, wordlist *wlBreak, c
p = wl->wl_word; p = wl->wl_word;
if (pCnt == 0 ) { if (pCnt == 0 ) {
// meas->m_vec =(char *)tmalloc(strlen(wl->wl_word)+1); meas->m_vec= cp_unquote(wl->wl_word);
// strcpy(meas->m_vec, cp_unquote(wl->wl_word));
meas->m_vec= cp_unquote(wl->wl_word);
} else if (pCnt == 1) { } else if (pCnt == 1) {
pName = strtok(p, "="); pName = strtok(p, "=");
@ -537,7 +890,16 @@ int measure_parse_find (struct measure *meas, wordlist *wl, wordlist *wlBreak, c
return 1; 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; int pCnt;
char *p, *pVar1, *pVar2; 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; int pcnt;
char *p; char *p;
@ -634,9 +1007,21 @@ int measure_parse_trigtarg (struct measure *meas, wordlist *words, wordlist *wlT
return 1; 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 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; wordlist *words, *wlTarg, *wlWhen;
char errbuf[100]; char errbuf[100];
char *mType = NULL; // analysis type char *mType = NULL; // analysis type
@ -673,7 +1058,7 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck)
return MEASUREMENT_FAILURE; return MEASUREMENT_FAILURE;
} }
precision = get_measure_precision() ; precision = measure_get_precision() ;
wl_cnt = 0; wl_cnt = 0;
while (words) { while (words) {
@ -687,43 +1072,14 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck)
break; break;
case 2: case 2:
{ {
mFunction = cp_unquote(words->wl_word); mFunctionType = measure_function_type(words->wl_word);
// Functions if ( mFunctionType == AT_UNKNOWN ){
if (strcasecmp(mFunction,"DELAY")==0) if(!(autocheck)){
mFunctionType = AT_DELAY; printf("\tmeasure '%s' failed\n", mName);
else if (strcasecmp(mFunction,"TRIG")==0) printf("Error: measure %s :\n", mName);
mFunctionType = AT_DELAY; printf("\tno such function as '%s'\n", words->wl_word);
else if (strcasecmp(mFunction,"FIND")==0) }
mFunctionType = AT_FIND; return MEASUREMENT_FAILURE;
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;
} }
break; break;
} }
@ -771,7 +1127,7 @@ get_measure2(wordlist *wl,double *result,char *out_line, bool autocheck)
case AT_TRIG: case AT_TRIG:
{ {
// trig parameters // trig parameters
measure *measTrig, *measTarg; MEASUREPTR measTrig, measTarg;
measTrig = (struct measure*)tmalloc(sizeof(struct measure)); measTrig = (struct measure*)tmalloc(sizeof(struct measure));
measTarg = (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: case AT_FIND:
{ {
measure *meas, *measFind; MEASUREPTR meas, measFind;
meas = (struct measure*)tmalloc(sizeof(struct measure)); meas = (struct measure*)tmalloc(sizeof(struct measure));
measFind = (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: case AT_WHEN:
{ {
measure *meas; MEASUREPTR meas;
meas = (struct measure*)tmalloc(sizeof(struct measure)); meas = (struct measure*)tmalloc(sizeof(struct measure));
if (measure_parse_when(meas, words, errbuf) ==0) { 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; return MEASUREMENT_OK;
} }
case AT_RMS: case AT_RMS:
printf("\tmeasure '%s' failed\n", mName); case AT_INTEG:
printf("Error: measure %s :\n", mName); {
printf("\tfunction '%s' currently not supported\n", mFunction); // trig parameters
break; 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: case AT_AVG:
{ {
// trig parameters // trig parameters
measure *meas; MEASUREPTR meas;
meas = (struct measure*)tmalloc(sizeof(struct measure)); meas = (struct measure*)tmalloc(sizeof(struct measure));
if (measure_parse_trigtarg(meas, words , NULL, "trig", errbuf)==0) { 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: case AT_MAX:
{ {
// trig parameters // trig parameters
measure *measTrig; MEASUREPTR measTrig;
measTrig = (struct measure*)tmalloc(sizeof(struct measure)); measTrig = (struct measure*)tmalloc(sizeof(struct measure));
if (measure_parse_trigtarg(measTrig, words , NULL, "trig", errbuf)==0) { 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; double minValue, maxValue;
measure *measTrig; MEASUREPTR measTrig;
measTrig = (struct measure*)tmalloc(sizeof(struct measure)); measTrig = (struct measure*)tmalloc(sizeof(struct measure));
if (measure_parse_trigtarg(measTrig, words , NULL, "trig", errbuf)==0) { 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); *result = (maxValue - minValue);
return MEASUREMENT_OK; return MEASUREMENT_OK;
} }
case AT_INTEG:
case AT_DERIV: case AT_DERIV:
case AT_ERR: case AT_ERR:
case AT_ERR1: case AT_ERR1:

View File

@ -3,8 +3,9 @@
#include <config.h> #include <config.h>
int get_measure_precision(void) ; extern int get_measure_precision(void) ;
/* void com_measure2(wordlist *wl); */ /* void com_measure2(wordlist *wl); */
int get_measure2(wordlist *wl,double *result,char *out_line, bool auto_check) ; extern int get_measure2(wordlist *wl,double *result,char *out_line, bool auto_check) ;
extern int measure_extract_variables( char *line ) ;
#endif #endif

View File

@ -23,13 +23,13 @@ $Id$
#include "variable.h" #include "variable.h"
#include "fourier.h" #include "fourier.h"
#include "breakp2.h" #include "breakp2.h"
#include "com_measure2.h"
/* Extract all the .save lines */ /* Extract all the .save lines */
static void fixdotplot(wordlist *wl); static void fixdotplot(wordlist *wl);
static void fixdotprint(wordlist *wl); static void fixdotprint(wordlist *wl);
static char * fixem(char *string); static char * fixem(char *string);
static wordlist * gettoks(char *s);
static struct plot * static struct plot *
@ -90,6 +90,7 @@ ft_savedotargs(void)
static wordlist all = { "all", NULL }; static wordlist all = { "all", NULL };
int isaplot; int isaplot;
int i; int i;
int status;
if (!ft_curckt) /* Shouldn't happen. */ if (!ft_curckt) /* Shouldn't happen. */
return 0; return 0;
@ -137,15 +138,10 @@ ft_savedotargs(void)
com_save2(w, "TRAN"); /* A hack */ com_save2(w, "TRAN"); /* A hack */
} }
} else if (ciprefix(".measure", s)) { } else if (ciprefix(".measure", s)) {
(void) gettok(&s); status = measure_extract_variables( s ) ;
name = gettok(&s); if(!(status)){
(void) gettok(&s); some = 1;
(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);
} else if (ciprefix(".op", s)) { } else if (ciprefix(".op", s)) {
some = 1; some = 1;
com_save2(&all, "OP"); com_save2(&all, "OP");
@ -157,6 +153,24 @@ ft_savedotargs(void)
return some; 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. /* 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 * 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 * 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) gettoks(char *s)
{ {
char *t; char *t;

View File

@ -9,6 +9,7 @@
void ft_dotsaves(void); void ft_dotsaves(void);
int ft_savedotargs(void); int ft_savedotargs(void);
int ft_cktcoms(bool terse); int ft_cktcoms(bool terse);
wordlist *gettoks(char *s);
#endif #endif

View File

@ -22,11 +22,7 @@
void winmessage(char* new_msg); void winmessage(char* new_msg);
#endif #endif
#define OLD_WAY /* do not use functions from com_measure2.c */
#ifndef OLD_WAY
static wordlist *measure_parse_line( char *line ) ; static wordlist *measure_parse_line( char *line ) ;
#endif
static bool measure_valid[20000];/* TRUE: if measurement no. [xxx] has been done successfully static bool measure_valid[20000];/* TRUE: if measurement no. [xxx] has been done successfully
(not used anywhere)*/ (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)*/ no output generated (if option autostop is set)*/
static bool measures_passed; /* TRUE: stop simulation (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 static bool
chkAnalysisType( char *an_type ) { chkAnalysisType( char *an_type ) {
@ -299,49 +45,13 @@ chkAnalysisType( char *an_type ) {
else return TRUE; 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. /* Gets pointer to double value after 'xxx=' and advances pointer of *line.
On error returns FALSE. */ On error returns FALSE. */
static bool static bool
get_double_value( get_double_value(
char **line, /*in|out: pointer to line to be parsed */ char **line, /*in|out: pointer to line to be parsed */
char *name, /*in: xxx e.g. 'val' from 'val=0.5' */ char *name, /*in: xxx e.g. 'val' from 'val=0.5' */
double *value /*out: return value (e.g. 0.5) from 'val=0.5'*/ double *value /*out: return value (e.g. 0.5) from 'val=0.5'*/
) { ) {
char *token = gettok(line); char *token = gettok(line);
@ -375,235 +85,6 @@ get_double_value(
return return_val; 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. /* Entry point for .meas evaluation.
Called in fcn dosim() from runcoms.c:335, after simulation is finished Called in fcn dosim() from runcoms.c:335, after simulation is finished
@ -624,7 +105,7 @@ do_measure(
double result = 0; double result = 0;
bool first_time = TRUE; bool first_time = TRUE;
wordlist *measure_word_list ; wordlist *measure_word_list ;
int precision = get_measure_precision(); int precision = measure_get_precision() ;
just_chk_meas = chk_only; 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 measurement type trig|delay|param|expr|avg|mean|max|min|rms|integ(ral)|when
The measurement type determines how to continue the .meas card. The measurement type determines how to continue the .meas card.
trig|delay are handled in fcn do_delay_measurement(), param|expr are skipped param|expr are skipped in first pass through .meas cards and are treated in second pass,
in first pass through .meas cards and are treated in second pass, all others are treated in fcn get_measure2() (com_measure2.c).
all others are treated in fcn do_other_measurement().
*/ */
/* first pass through .meas cards: evaluate everything except param|expr */ /* first pass through .meas cards: evaluate everything except param|expr */
@ -683,42 +163,27 @@ do_measure(
continue; continue;
} }
#ifdef OLD_WAY /* New way of processing measure statements using common code
if ( strcmp( meastype, "trig" ) == 0 || strcmp( meastype, "delay" ) == 0 ) { in fcn get_measure2() (com_measure2.c)*/
if ( do_delay_measurement( resname, out_line, line, meas_card->li_line, idx++, &result ) && just_chk_meas != TRUE ) { out_line[0] = EOS ;
nupa_add_param( resname, result ); 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;
} }
} wl_free( measure_word_list ) ;
else if ( strcmp( meastype, "avg" ) == 0 || strcmp( meastype, "mean" ) == 0 || } else {
strcmp( meastype, "max" ) == 0 || strcmp( meastype, "min" ) == 0 || measure_valid[idx++] = FALSE;
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 );
}
}
else {
measures_passed = 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 = alloc(struct line);
newcard->li_line = strdup(out_line); newcard->li_line = strdup(out_line);
newcard->li_next = NULL; newcard->li_next = NULL;
@ -731,7 +196,7 @@ do_measure(
txfree(an_type); txfree(resname); txfree(meastype); 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 ) { if ( idx >= 20000 ) {
fprintf( stderr, "ERROR: number of measurements exceeds 20,000!\nAborting...\n" ); fprintf( stderr, "ERROR: number of measurements exceeds 20,000!\nAborting...\n" );
#ifdef HAS_WINDOWS #ifdef HAS_WINDOWS
@ -739,8 +204,10 @@ do_measure(
#endif #endif
exit(-1); exit(-1);
} }
} /* end of for loop (first pass through .meas lines) */ } /* end of for loop (first pass through .meas lines) */
/* second pass through .meas cards: now do param|expr .meas statements */ /* second pass through .meas cards: now do param|expr .meas statements */
newcard = meas_results; newcard = meas_results;
for ( meas_card = ft_curckt->ci_meas; meas_card != NULL; meas_card = meas_card->li_next ) { for ( meas_card = ft_curckt->ci_meas; meas_card != NULL; meas_card = meas_card->li_next ) {
@ -777,7 +244,7 @@ do_measure(
continue; continue;
} }
if ( just_chk_meas != TRUE ) fprintf( stdout, "%-15s=", resname ); if ( just_chk_meas != TRUE ) fprintf( stdout, "%-20s=", resname );
if ( just_chk_meas != TRUE ) { if ( just_chk_meas != TRUE ) {
ok = nupa_eval( meas_card->li_line, meas_card->li_linenum ); 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" ); if ( just_chk_meas != TRUE ) fprintf( stdout, " failed\n" );
} }
else { 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 ); nupa_add_param( resname, result );
} }
} }
@ -830,7 +297,8 @@ check_autostop( char* what ) {
return flag; 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 */ int len ; /* length of string */
wordlist *wl ; /* build a word list - head of list */ wordlist *wl ; /* build a word list - head of list */

View File

@ -68,6 +68,7 @@ typedef struct _ttdico {
char **dynrefptr; char **dynrefptr;
// char category[Maxline]; /* category of each line */ // char category[Maxline]; /* category of each line */
char *dyncategory; char *dyncategory;
int hspice_compatibility; /* allow hspice keywords */
} tdico; } tdico;
void initdico(tdico * dico); void initdico(tdico * dico);

View File

@ -9,10 +9,7 @@
#include "general.h" #include "general.h"
#include "numparam.h" #include "numparam.h"
#include "ngspice.h" #include "ngspice.h"
#include "../compatmode.h"
#ifdef _MSC_VER
#define strcasecmp _stricmp
#endif
/* random numbers in /maths/misc/randnumb.c */ /* random numbers in /maths/misc/randnumb.c */
extern double gauss(); extern double gauss();
@ -158,6 +155,8 @@ void
initdico (tdico * dico) initdico (tdico * dico)
{ {
int i; int i;
COMPATMODE_T compat_mode;
dico->nbd = 0; dico->nbd = 0;
sini(dico->option,sizeof(dico->option)-4); sini(dico->option,sizeof(dico->option)-4);
sini(dico->srcfile,sizeof(dico->srcfile)-4); sini(dico->srcfile,sizeof(dico->srcfile)-4);
@ -172,6 +171,12 @@ initdico (tdico * dico)
dico->tos = 0; dico->tos = 0;
dico->stack[dico->tos] = 0; /* global data beneath */ dico->stack[dico->tos] = 0; /* global data beneath */
initkeys (); 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 */ /* local semantics for parameters inside a subckt */
@ -1437,7 +1442,11 @@ scanline (tdico * dico, char *s, char *r, unsigned char err)
else else
{ {
pscopy (t, s, i + 1, k - i - 1); 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; i = k;
if (!err) if (!err)

View File

@ -2,6 +2,7 @@
#define _BOOL_H #define _BOOL_H
typedef unsigned char bool; typedef unsigned char bool;
typedef int BOOL ;
#define BOOLEAN int #define BOOLEAN int
#define TRUE 1 #define TRUE 1

View File

@ -71,9 +71,17 @@
#ifdef DEBUG #ifdef DEBUG
#define DEBUGMSG(textargs) printf(textargs) #define DEBUGMSG(textargs) printf(textargs)
#else #define DS(name_xz) { name_xz }
#define DBGDEFINE(func_xz) func_xz
#else /* ! DEBUG */
#define DEBUGMSG(testargs) #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. */ /* Macro that queries the system to find the process time. */

View File

@ -11,8 +11,12 @@ libmisc_la_SOURCES = \
alloc.h \ alloc.h \
dup2.c \ dup2.c \
dup2.h \ dup2.h \
hash.h \
hash.c \
ivars.c \ ivars.c \
ivars.h \ ivars.h \
mempool.c \
mempool.h \
mktemp.c \ mktemp.c \
mktemp.h \ mktemp.h \
printnum.c \ printnum.c \

View File

@ -95,6 +95,7 @@ typedef pthread_t threadId_t;
#include <spicelib/analysis/analysis.h> #include <spicelib/analysis/analysis.h>
#include <misc/ivars.h> #include <misc/ivars.h>
#include <frontend/resource.h> #include <frontend/resource.h>
#include <frontend/com_measure2.h>
#ifndef _MSC_VER /* avoid second definition of VT_BOOL */ #ifndef _MSC_VER /* avoid second definition of VT_BOOL */
#include <frontend/variable.h> #include <frontend/variable.h>
#else #else
@ -2115,7 +2116,7 @@ static int listTriggers TCL_CMDPROCARGS(clientData,interp,argc,argv){
static int tmeasure TCL_CMDPROCARGS(clientData,interp,argc,argv){ static int tmeasure TCL_CMDPROCARGS(clientData,interp,argc,argv){
wordlist *wl= NULL; wordlist *wl= NULL;
float mvalue; double mvalue;
if (argc <= 2) { if (argc <= 2) {
Tcl_SetResult(interp, "Wrong # args. spice::listTriggers",TCL_STATIC); 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); wl =wl_build((char **)argv);
mvalue = get_measure2(wl); get_measure2(wl,&mvalue,NULL,FALSE);
printf(" %e \n", mvalue); printf(" %e \n", mvalue);

View File

@ -11,8 +11,8 @@ Global
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Debug|Win32.ActiveCfg = Debug|Win32 {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}.Debug|Win32.Build.0 = Debug|Win32
{83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Release|Win32.ActiveCfg = Release|Win32 {83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Release|Win32.ActiveCfg = Debug|Win32
{83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Release|Win32.Build.0 = Release|Win32 {83E315C7-EDD3-4F6B-AF28-87A92A4FA49A}.Release|Win32.Build.0 = Debug|Win32
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -819,6 +819,10 @@
RelativePath="..\src\frontend\commands.h" RelativePath="..\src\frontend\commands.h"
> >
</File> </File>
<File
RelativePath="..\src\frontend\compatmode.h"
>
</File>
<File <File
RelativePath="..\src\frontend\parser\complete.h" RelativePath="..\src\frontend\parser\complete.h"
> >
@ -1103,12 +1107,16 @@
RelativePath="..\src\frontend\plotting\graphdb.h" RelativePath="..\src\frontend\plotting\graphdb.h"
> >
</File> </File>
<File
RelativePath="..\src\frontend\plotting\grid.h"
>
</File>
<File <File
RelativePath="..\src\include\grid.h" RelativePath="..\src\include\grid.h"
> >
</File> </File>
<File <File
RelativePath="..\src\frontend\plotting\grid.h" RelativePath="..\src\misc\hash.h"
> >
</File> </File>
<File <File
@ -1212,11 +1220,11 @@
> >
</File> </File>
<File <File
RelativePath="..\src\frontend\inp.h" RelativePath="..\src\spicelib\parser\inp.h"
> >
</File> </File>
<File <File
RelativePath="..\src\spicelib\parser\inp.h" RelativePath="..\src\frontend\inp.h"
> >
</File> </File>
<File <File
@ -1375,6 +1383,10 @@
RelativePath="..\src\include\memory.h" RelativePath="..\src\include\memory.h"
> >
</File> </File>
<File
RelativePath="..\src\misc\mempool.h"
>
</File>
<File <File
RelativePath="..\src\spicelib\devices\mesa\mesadefs.h" RelativePath="..\src\spicelib\devices\mesa\mesadefs.h"
> >
@ -4503,6 +4515,10 @@
RelativePath="..\src\frontend\commands.c" RelativePath="..\src\frontend\commands.c"
> >
</File> </File>
<File
RelativePath="..\src\frontend\compatmode.c"
>
</File>
<File <File
RelativePath="..\src\frontend\parser\complete.c" RelativePath="..\src\frontend\parser\complete.c"
> >
@ -4999,6 +5015,10 @@
RelativePath="..\src\frontend\plotting\grid.c" RelativePath="..\src\frontend\plotting\grid.c"
> >
</File> </File>
<File
RelativePath="..\src\misc\hash.c"
>
</File>
<File <File
RelativePath="..\src\frontend\hcomp.c" RelativePath="..\src\frontend\hcomp.c"
> >
@ -5875,6 +5895,10 @@
RelativePath="..\src\frontend\measure.c" RelativePath="..\src\frontend\measure.c"
> >
</File> </File>
<File
RelativePath="..\src\misc\mempool.c"
>
</File>
<File <File
RelativePath="..\src\spicelib\devices\mes\mes.c" RelativePath="..\src\spicelib\devices\mes\mes.c"
> >