Improvements in frontend by Phil Barker

This commit is contained in:
pnenzi 2007-10-08 21:10:34 +00:00
parent 56626999fc
commit 936cd7a4fc
14 changed files with 3537 additions and 192 deletions

View File

@ -1,3 +1,24 @@
2007-10-8 Paolo Nenzi <p.nenzi@ieee.org>
*src/frontend/{inp.c, inpcom.c, inpcom.h, measure.c, nutimp.c, runcoms.c
subckt.c, ftedefs.c, fteext.c, dctran.c, inp2dot.c, inppas2.c}: added
several improvements mad by Phil Barker:
- .measure statements: trig/targ, max, min, avg, rms, integral, param
- autostop option: which causes the simulation to stop if all .measure
statements are satisfied; option is ignored if any max, min, avg, rms
or integ measurements defined.
- fixed some floating point number comparisons where the code was checking for
equality with '==' by adding a routine called 'AlmostEqualUlps'.
- parametrized subcircuits
- added support for ".lib" syntax
- added ability to recursively call spice netlist parser; this allows for
reading in additional .include and .lib files defined in other netlist files
- changed the flattened netlist names created in 'subckt.c' to match other
spice simulators
- allow for .ic, .nodeset names to be embedded in a subckt;
enhanced subckt.c to created appropriate node names for flattened simulation
netlist
2007-10-8 Paolo Nenzi <p.nenzi@ieee.org>
* src/frontend/{rawfile.c, outitf.c, runcoms.c}, src/include/ftedefs.h:
modified current vectors output amd added struct elements for holding the

View File

@ -120,6 +120,7 @@ libfte_a_SOURCES = \
interp.h \
linear.c \
linear.h \
measure.c \
misccoms.c \
misccoms.h \
miscvars.c \
@ -180,6 +181,6 @@ libfte_a_SOURCES = \
# testcommands_LDADD = libfte.a plotting/libplotting.a ../misc/libmisc.a
INCLUDES = -I$(top_srcdir)/src/include @X_CFLAGS@
INCLUDES = -I$(top_srcdir)/src/include @X_CFLAGS@
MAINTAINERCLEANFILES = Makefile.in

View File

@ -15,6 +15,8 @@ $Id$
* the listing routines.
*/
#include <assert.h>
#include <libgen.h>
#include "ngspice.h"
#include "cpdefs.h"
#include "inpdefs.h"
@ -35,6 +37,10 @@ $Id$
/* gtri - end - 12/12/90 */
#endif
#ifdef NUMPARAMS
#include "numparam/numpaif.h"
#endif
#define line_free(line,flag) { line_free_x(line,flag); line = NULL; }
/* static declarations */
@ -42,47 +48,73 @@ static char * upper(register char *string);
static bool doedit(char *filename);
static void line_free_x(struct line * deck, bool recurse);
/* Do a listing. Use is listing [expanded] [logical] [physical] [deck] */
// Initial AlmostEqualULPs version - fast and simple, but
// some limitations.
static bool AlmostEqualUlps(float A, float B, int maxUlps)
{
assert(sizeof(float) == sizeof(int));
if (A == B)
return TRUE;
int intDiff = abs(*(int*)&A - *(int*)&B);
if (intDiff <= maxUlps)
return TRUE;
return FALSE;
}
/* Do a listing. Use is listing [expanded] [logical] [physical] [deck] */
void
com_listing(wordlist *wl)
{
int type = LS_LOGICAL;
bool expand = FALSE;
bool expand = FALSE, do_param_listing = FALSE;
char *s;
if (ft_curckt) { /* if there is a current circuit . . . . */
while (wl) {
s = wl->wl_word;
switch (*s) {
case 'l':
case 'L':
type = LS_LOGICAL;
break;
case 'p':
case 'P':
type = LS_PHYSICAL;
break;
case 'd':
case 'D':
type = LS_DECK;
break;
case 'e':
case 'E':
expand = TRUE;
break;
default:
fprintf(cp_err,
"Error: bad listing type %s\n", s);
return; /* SJB - don't go on after an error */
}
if ( strcmp( s, "param" ) == 0 ) {
do_param_listing = TRUE;
}
else {
switch (*s) {
case 'l':
case 'L':
type = LS_LOGICAL;
break;
case 'p':
case 'P':
type = LS_PHYSICAL;
break;
case 'd':
case 'D':
type = LS_DECK;
break;
case 'e':
case 'E':
expand = TRUE;
break;
default:
fprintf(cp_err,
"Error: bad listing type %s\n", s);
return; /* SJB - don't go on after an error */
}
}
wl = wl->wl_next;
}
if (type != LS_DECK)
if ( do_param_listing ) {
nupa_list_params(cp_out);
}
else {
if (type != LS_DECK)
fprintf(cp_out, "\t%s\n\n", ft_curckt->ci_name);
inp_list(cp_out, expand ? ft_curckt->ci_deck :
ft_curckt->ci_origdeck, ft_curckt->ci_options,
type);
inp_list(cp_out, expand ? ft_curckt->ci_deck :
ft_curckt->ci_origdeck, ft_curckt->ci_options,
type);
}
} else
fprintf(cp_err, "Error: no circuit loaded.\n");
return;
@ -297,16 +329,20 @@ inp_spsource(FILE *fp, bool comfile, char *filename)
* *filename =
*/
{
struct line *deck, *dd, *ld;
struct line *realdeck, *options = NULL;
char *tt = NULL, name[BSIZE_SP], *s, *t;
struct line *deck, *dd, *ld, *prev_param = NULL, *prev_card = NULL;
struct line *realdeck, *options = NULL, *curr_meas = NULL;
char *tt = NULL, name[BSIZE_SP], *s, *t, *temperature = NULL;
bool nosubckts, commands = FALSE;
wordlist *wl = NULL, *end = NULL, *wl_first = NULL;
wordlist *controls = NULL;
FILE *lastin, *lastout, *lasterr;
double temperature_value;
bool autostop;
/* read in the deck from a file */
inp_readall(fp, &deck);
char *filename_dup = ( filename == NULL ) ? strdup(".") : strdup(filename);
inp_readall(fp, &deck, 0, dirname(filename_dup));
tfree(filename_dup);
/* if nothing came back from inp_readall, just close fp and return to caller */
if (!deck) { /* MW. We must close fp always when returning */
@ -469,6 +505,7 @@ inp_spsource(FILE *fp, bool comfile, char *filename)
if (deck->li_next) {
/* There is something left after the controls. */
fprintf(cp_out, "\nCircuit: %s\n\n", tt);
fprintf(stderr, "\nCircuit: %s\n\n", tt);
/* Old location of ENHtranslate_poly. This didn't work, because it
* didn't handle models in .SUBCKTs correctly. Moved to new location below
@ -485,7 +522,6 @@ inp_spsource(FILE *fp, bool comfile, char *filename)
return;
} /* done expanding subcircuit macros */
/* Now handle translation of spice2c6 POLYs. */
/* New location of ENHtranslate_poly. This should handle .SUBCKTs better . . . .
* SDB 4.13.2003. Comments? mailto:sdb@cloud9.net
@ -504,6 +540,63 @@ inp_spsource(FILE *fp, bool comfile, char *filename)
} /* if (deck->li_next) */
/* look for and set temperature; also store param and .meas statements in circuit struct */
ft_curckt->ci_param = NULL;
ft_curckt->ci_meas = NULL;
for (dd = deck; dd; dd = dd->li_next) {
/* get temp after numparam run on deck */
if ( ciprefix(".temp", dd->li_line) ) {
s = dd->li_line + 5;
while ( isspace(*s) ) s++;
if ( temperature != NULL ) {
txfree(temperature);
}
temperature = strdup(s);
}
/*
all parameter lines should be sequentially ordered and placed at
beginning of deck
*/
if ( ciprefix( ".param", dd->li_line ) ) {
ft_curckt->ci_param = dd;
/* find end of .param statements */
while ( ciprefix( ".param", dd->li_line ) ) { prev_param = dd; dd = dd->li_next; }
prev_card->li_next = dd;
prev_param->li_next = NULL;
}
if ( ciprefix( ".meas", dd->li_line ) ) {
if ( cp_getvar( "autostop", VT_BOOL, (bool *) &autostop ) ) {
if ( strstr( dd->li_line, " max " ) || strstr( dd->li_line, " min " ) || strstr( dd->li_line, " avg " ) ||
strstr( dd->li_line, " rms " ) || strstr( dd->li_line, " integ " ) ) {
printf( "Warning: .OPTION AUTOSTOP will not be effective because one of 'max|min|avg|rms|integ' is used in .meas\n" );
printf( " AUTOSTOP being disabled...\n" );
cp_remvar( "autostop" );
}
}
if ( curr_meas == NULL ) {
curr_meas = ft_curckt->ci_meas = dd;
}
else {
curr_meas->li_next = dd;
curr_meas = dd;
}
prev_card->li_next = dd->li_next;
curr_meas->li_next = NULL;
dd = prev_card;
}
prev_card = dd;
}
/* set temperature if defined */
if ( temperature != NULL ) {
temperature_value = atof(temperature);
s = (char *) &temperature_value;
cp_vset("temp", VT_REAL, s );
txfree(temperature);
}
#ifdef TRACE
/* SDB debug statement */
@ -512,8 +605,8 @@ inp_spsource(FILE *fp, bool comfile, char *filename)
/* Now that the deck is loaded, do the commands, if there are any */
if (controls) {
for (end = wl = wl_reverse(controls); wl; wl = wl->wl_next)
cp_evloop(wl->wl_word);
for (end = wl = wl_reverse(controls); wl; wl = wl->wl_next)
cp_evloop(wl->wl_word);
wl_free(end);
}
@ -564,6 +657,7 @@ inp_dodeck(struct line *deck, char *tt, wordlist *end, bool reuse,
struct variable *eev = NULL;
wordlist *wl;
bool noparse, ii;
double brief = 0, i;
/* First throw away any old error messages there might be and fix
* the case of the lines. */
@ -586,6 +680,50 @@ inp_dodeck(struct line *deck, char *tt, wordlist *end, bool reuse,
}
cp_getvar("noparse", VT_BOOL, (char *) &noparse);
if (!noparse) {
for (; options; options = options->li_next) {
for (s = options->li_line; *s && !isspace(*s); s++)
;
ii = cp_interactive;
cp_interactive = FALSE;
wl = cp_lexer(s);
cp_interactive = ii;
if (!wl || !wl->wl_word || !*wl->wl_word)
continue;
if (eev)
eev->va_next = cp_setparse(wl);
else
ct->ci_vars = eev = cp_setparse(wl);
while (eev->va_next)
eev = eev->va_next;
}
for (eev = ct->ci_vars; eev; eev = eev->va_next) {
static int one = 1;
switch (eev->va_type) {
case VT_BOOL:
if_option(ct->ci_ckt, eev->va_name,
eev->va_type, &one);
break;
case VT_NUM:
if_option(ct->ci_ckt, eev->va_name,
eev->va_type, (char *) &eev->va_num);
break;
case VT_REAL:
if ( strcmp("brief",eev->va_name)==0 ){
cp_vset("brief", VT_REAL, (char*) &eev->va_real );
}
if_option(ct->ci_ckt, eev->va_name,
eev->va_type, (char *) &eev->va_real);
break;
case VT_STRING:
if_option(ct->ci_ckt, eev->va_name,
eev->va_type, eev->va_string);
break;
} /* switch . . . */
}
} /* if (!noparse) . . . */
/*----------------------------------------------------
* Now assuming that we wanna parse this deck, we call
* if_inpdeck which takes the deck and returns a
@ -611,7 +749,7 @@ inp_dodeck(struct line *deck, char *tt, wordlist *end, bool reuse,
if (dd->li_error) {
char *p, *q;
#ifdef XSPICE
/* gtri - modify - 12/12/90 - wbk - add setting of ipc syntax error flag */
g_ipc.syntax_error = IPC_TRUE;
@ -638,6 +776,22 @@ inp_dodeck(struct line *deck, char *tt, wordlist *end, bool reuse,
} /* for (dd = deck; dd; dd = dd->li_next) */
if ( cp_getvar( "brief", VT_REAL, (char *) &i ) ) {
brief = i;
}
// only print out netlist if brief == 0
if(AlmostEqualUlps(brief,0,3)) {
/* output deck */
out_printf( "\nProcessed Netlist\n" );
out_printf( "=================\n" );
int print_listing = 1;
for (dd = deck; dd; dd = dd->li_next) {
if ( ciprefix(".prot", dd->li_line) ) print_listing = 0;
if ( print_listing == 1 ) out_printf( "%s\n", dd->li_line );
if ( ciprefix(".unprot", dd->li_line) ) print_listing = 1;
}
out_printf( "\n" );
}
/* Add this circuit to the circuit list. If reuse is TRUE then use
* the ft_curckt structure. */
@ -669,46 +823,6 @@ inp_dodeck(struct line *deck, char *tt, wordlist *end, bool reuse,
else
ct->ci_filename = NULL;
if (!noparse) {
for (; options; options = options->li_next) {
for (s = options->li_line; *s && !isspace(*s); s++)
;
ii = cp_interactive;
cp_interactive = FALSE;
wl = cp_lexer(s);
cp_interactive = ii;
if (!wl || !wl->wl_word || !*wl->wl_word)
continue;
if (eev)
eev->va_next = cp_setparse(wl);
else
ct->ci_vars = eev = cp_setparse(wl);
while (eev->va_next)
eev = eev->va_next;
}
for (eev = ct->ci_vars; eev; eev = eev->va_next) {
static int one = 1;
switch (eev->va_type) {
case VT_BOOL:
if_option(ct->ci_ckt, eev->va_name,
eev->va_type, &one);
break;
case VT_NUM:
if_option(ct->ci_ckt, eev->va_name,
eev->va_type, (char *) &eev->va_num);
break;
case VT_REAL:
if_option(ct->ci_ckt, eev->va_name,
eev->va_type, (char *) &eev->va_real);
break;
case VT_STRING:
if_option(ct->ci_ckt, eev->va_name,
eev->va_type, eev->va_string);
break;
} /* switch . . . */
}
} /* if (!noparse) . . . */
cp_addkword(CT_CKTNAMES, tt);
return;
}
@ -867,11 +981,12 @@ com_source(wordlist *wl)
}
/* Don't print the title if this is a spice initialisation file. */
if (ft_nutmeg || substring(INITSTR, owl->wl_word)
|| substring(ALT_INITSTR, owl->wl_word))
if (ft_nutmeg || substring(INITSTR, owl->wl_word) || substring(ALT_INITSTR, owl->wl_word)) {
inp_spsource(fp, TRUE, tempfile ? (char *) NULL : wl->wl_word);
else
}
else {
inp_spsource(fp, FALSE, tempfile ? (char *) NULL : wl->wl_word);
}
cp_interactive = inter;
if (tempfile)
unlink(tempfile);

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,22 @@
#define INPCOM_H_INCLUDED
FILE * inp_pathopen(char *name, char *mode);
void inp_readall(FILE *fp, struct line **data);
void inp_readall(FILE *fp, struct line **data, int, char *dirname);
void inp_casefix(register char *string);
/* globals -- wanted to avoid complicating inp_readall interface */
static char *library_file[1000];
static char *library_name[1000][1000];
struct line *library_ll_ptr[1000][1000];
struct line *libraries[1000];
int num_libraries;
int num_lib_names[1000];
static char *global;
static char *subckt_w_params[1000];
static int num_subckt_w_params;
static char *func_names[1000];
static char *func_params[1000][1000];
static char *func_macro[5000];
static int num_functions;
static int num_parameters[1000];
#endif

611
src/frontend/measure.c Normal file
View File

@ -0,0 +1,611 @@
#include <assert.h>
#include <stdlib.h>
#include "ngspice.h"
#include "cpdefs.h"
#include "ftedefs.h"
#include "dvec.h"
#include "rawfile.h"
#include "variable.h"
#include "numparam/numpaif.h"
static bool measure_valid[20000];
static bool just_chk_meas;
static bool measures_passed;
// Initial AlmostEqualULPs version - fast and simple, but
// some limitations.
static bool AlmostEqualUlps(float A, float B, int maxUlps)
{
assert(sizeof(float) == sizeof(int));
if (A == B)
return TRUE;
int intDiff = abs(*(int*)&A - *(int*)&B);
if (intDiff <= maxUlps)
return TRUE;
return FALSE;
}
static double
max( double a, double b ) {
if ( a > b ) return a;
else return b;
}
static double
min( double a, double b ) {
if ( a < b ) return a;
else return b;
}
static int
get_measure_precision()
{
char *env_ptr;
int precision = 5;
if ( ( env_ptr = getenv("NGSPICE_MEAS_PRECISION") ) ) {
precision = atoi(env_ptr);
}
return precision;
}
static double
interpolate( struct dvec *time, struct dvec *values, int i, int j, double var_value, char x_or_y ) {
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;
}
static double
get_volt_time( struct dvec *time, struct dvec *values, double value, char polarity, int index, bool *failed )
{
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] ) {
count++;
if ( count == index ) 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] ) {
count++;
if ( count == index ) 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, 3 ) ) *failed = TRUE;
return comp_time;
}
static bool
measure( char *trig_name, double trig_value, char trig_polarity, int trig_index,
char *targ_name, double targ_value, char targ_polarity, int targ_index, double *result,
double *trig_time, double *targ_time ) {
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;
}
/*
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
integral: calculate the integral
*/
static bool
measure2( char *meas_type, char *vec_name, char vec_type, double from, double to, double *result, double *result_time ) {
struct dvec *time = vec_get("time");
struct dvec *vec;
int xy_size = 0;
double *x, *y, *width, sum1 = 0, sum2 = 0, sum3 = 0;
char tmp_vec_name[1000];
double prev_result = 0;
bool failed = FALSE, first_time = TRUE, constant_y = TRUE;
int i;
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, 3 ) ) *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), 3 ) ) 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), 3 ) && AlmostEqualUlps( *(width+i), *(width+i+2), 3 ) ) {
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), 3 ) ) {
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), 3 ) ) {
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 ( 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 ) {
/*
if ( strcmp( an_type, "ac" ) != 0 && strcmp( an_type, "dc" ) != 0 &&
strcmp( an_type, "noise" ) != 0 && strcmp( an_type, "tran" ) != 0 &&
strcmp( an_type, "fft" ) != 0 && strcmp( an_type, "four" ) != 0 )
*/
/* only support tran analysis type for now */
if ( strcmp( an_type, "tran" ) != 0 )
return FALSE;
else return TRUE;
}
static bool
get_int_value( char **line, char *name, int *value ) {
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;
}
static bool
get_double_value( char **line, char *name, double *value ) {
char *token = gettok(line);
bool return_val = TRUE;
char *equal_ptr, *junk;
int err;
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);
junk = token = gettok(line);
*value = INPevaluate( &junk, &err, 1 );
} else {
if ( (equal_ptr = strstr( token, "=" )) ) {
equal_ptr += 1;
*value = INPevaluate( &equal_ptr, &err, 1 );
} else {
if ( just_chk_meas != TRUE ) fprintf( cp_err, "Error: syntax error for measure statement; missing '='!\n" );
return_val = FALSE;
}
}
if ( err ) { if ( just_chk_meas != TRUE ) fprintf( cp_err, "Error: Bad value.\n" ); return_val = FALSE; }
}
txfree(token);
return return_val;
}
static char*
get_vector_name( char **line ) {
char *token, *name;
token = name = gettok(line);
*(name + strlen(name) - 1) = '\0';
name = strdup(name); txfree(token);
return name;
}
static bool
do_delay_measurement( char *resname, char *out_line, char *line, char *o_line, int meas_index, double *result ) {
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 );
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 );
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 );
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 ( !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
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;
}
void
do_measure( char *what, bool chk_only ) {
struct line *meas_card, *meas_results = NULL, *end = NULL, *newcard;
char *line, *an_name, *an_type, *resname, *meastype, *str_ptr, out_line[1000];
int index = 0, ok = 0;
double result = 0;
int precision = get_measure_precision();
bool first_time = TRUE;
just_chk_meas = chk_only;
an_name = strdup( what );
strtolower( an_name );
for ( meas_card = ft_curckt->ci_meas; meas_card != NULL; meas_card = meas_card->li_next ) {
line = meas_card->li_line;
txfree(gettok(&line)); /* discard .meas */
an_type = gettok(&line); resname = gettok(&line); meastype = gettok(&line);
if ( chkAnalysisType( an_type ) != TRUE ) {
if ( just_chk_meas != TRUE ) {
fprintf( cp_err, "Error: unrecognized analysis type '%s' for the following .meas statement on line %d:\n", an_type, meas_card->li_linenum );
fprintf( cp_err, " %s\n", meas_card->li_line );
}
txfree(an_type); txfree(resname); txfree(meastype);
continue;
}
else if ( first_time ) {
first_time = FALSE;
if ( just_chk_meas != TRUE && strcmp( an_type, "tran" ) == 0 ) fprintf( stdout, " Transient Analysis\n\n" );
}
/* skip param|expr measurement types for now -- will be done after other measurements */
if ( strncmp( meastype, "param", 5 ) == 0 || strncmp( meastype, "expr", 4 ) == 0 ) continue;
if ( strcmp( an_name, an_type ) != 0 ) {
txfree(an_type); txfree(resname); txfree(meastype);
continue;
}
if ( strcmp( meastype, "trig" ) == 0 || strcmp( meastype, "delay" ) == 0 ) {
if ( do_delay_measurement( resname, out_line, line, meas_card->li_line, index++, &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 ) {
if ( do_other_measurement( resname, out_line, meastype, line, meas_card->li_line, index++, &result ) && just_chk_meas != TRUE ) {
nupa_add_param( resname, result );
}
}
else {
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 );
}
}
newcard = alloc(struct line);
newcard->li_line = strdup(out_line);
newcard->li_next = NULL;
if ( meas_results == NULL ) meas_results = end = newcard;
else {
end->li_next = newcard;
end = newcard;
}
txfree(an_type); txfree(resname); txfree(meastype);
// see if number of measurements exceeds fixed array size of 20,000
if ( index >= 20000 ) {
fprintf( stderr, "ERROR: number of measurements exceeds 20,000!\nAborting...\n" );
exit(-1);
}
}
// 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 ) {
line = meas_card->li_line;
txfree(gettok(&line)); /* discard .meas */
an_type = gettok(&line); resname = gettok(&line); meastype = gettok(&line);
if ( chkAnalysisType( an_type ) != TRUE ) {
if ( just_chk_meas != TRUE ) {
fprintf( cp_err, "Error: unrecognized analysis type '%s' for the following .meas statement on line %d:\n", an_type, meas_card->li_linenum );
fprintf( cp_err, " %s\n", meas_card->li_line );
}
txfree(an_type); txfree(resname); txfree(meastype);
continue;
}
if ( strcmp( an_name, an_type ) != 0 ) {
txfree(an_type); txfree(resname); txfree(meastype);
continue;
}
if ( strncmp( meastype, "param", 5 ) != 0 && strncmp( meastype, "expr", 4 ) != 0 ) {
if ( just_chk_meas != TRUE ) fprintf( stdout, "%s", newcard->li_line );
end = newcard;
newcard = newcard->li_next;
txfree( end->li_line );
txfree( end );
txfree(an_type); txfree(resname); txfree(meastype);
continue;
}
if ( just_chk_meas != TRUE ) fprintf( stdout, "%-15s=", resname );
if ( just_chk_meas != TRUE ) {
ok = nupa_eval( meas_card->li_line, meas_card->li_linenum );
if ( ok ) {
str_ptr = strstr( meas_card->li_line, meastype );
if ( !get_double_value( &str_ptr, meastype, &result ) ) {
if ( just_chk_meas != TRUE ) fprintf( stdout, " failed\n" );
}
else {
if ( just_chk_meas != TRUE ) fprintf( stdout, " %.*e\n", precision, result );
nupa_add_param( resname, result );
}
}
else {
if ( just_chk_meas != TRUE ) fprintf( stdout, " failed\n" );
}
}
txfree(an_type); txfree(resname); txfree(meastype);
}
if ( just_chk_meas != TRUE ) fprintf( stdout, "\n" );
txfree(an_name);
fflush( stdout );
//nupa_list_params();
}
bool
check_autostop( char* what ) {
bool flag = FALSE;
bool autostop;
measures_passed = TRUE;
if ( cp_getvar( "autostop", VT_BOOL, (bool *) &autostop ) ) {
do_measure( what, TRUE );
if ( measures_passed == TRUE ) flag = TRUE;
}
return flag;
}

View File

@ -33,7 +33,7 @@ inp_nutsource(FILE *fp, bool comfile, char *filename)
wordlist *controls = NULL;
FILE *lastin, *lastout, *lasterr;
inp_readall(fp, &deck);
inp_readall(fp, &deck, 0);
if (!deck)
return;

View File

@ -323,6 +323,9 @@ dosim(char *what, wordlist *wl)
wl->wl_prev = NULL;
tfree(ww);
}
if ( !err ) do_measure( ft_curckt->ci_last_an, FALSE );
return err;
}

View File

@ -64,6 +64,7 @@ $Id$
#ifdef NUMPARAMS
/* Uncomment to turn on tracing for the Numparam */
/*#define TRACE_NUMPARAMS*/
/*#define TRACE*/
#include "numparam/numpaif.h"
#endif
@ -170,22 +171,28 @@ inp_subcktexpand(struct line *deck)
#ifdef NUMPARAMS
(void) cp_getvar("numparams", VT_BOOL, (char *) &use_numparams);
use_numparams = TRUE;
/* deck has .control sections already removed, but not comments */
if ( use_numparams ) {
#ifdef TRACE_NUMPARAMS
printf("Numparams is processing this deck:\n");
fprintf(stderr,"Numparams is processing this deck:\n");
c=deck;
while( c!=NULL) {
printf("%3d:%s\n",c->li_linenum, c->li_line);
fprintf(stderr,"%3d:%s\n",c->li_linenum, c->li_line);
c= c->li_next;
}
#endif /* TRACE_NUMPARAMS */
ok = nupa_signal( NUPADECKCOPY, NULL);
/* get the subckt/model names from the deck */
c=deck;
while ( c != NULL) { /* first Numparam pass */
nupa_scan(c->li_line, c->li_linenum);
if ( ciprefix( ".subckt", c->li_line ) )
nupa_scan(c->li_line, c->li_linenum, TRUE);
if ( ciprefix( ".model", c->li_line ) )
nupa_scan(c->li_line, c->li_linenum, FALSE);
c= c->li_next;
}
c=deck;
@ -193,12 +200,13 @@ inp_subcktexpand(struct line *deck)
c->li_line = nupa_copy(c->li_line, c->li_linenum);
c= c->li_next;
}
/* now copy instances */
#ifdef TRACE_NUMPARAMS
printf("Numparams transformed deck:\n");
fprintf(stderr,"Numparams transformed deck:\n");
c=deck;
while( c!=NULL) {
printf("%3d:%s\n",c->li_linenum, c->li_line);
fprintf(stderr,"%3d:%s\n",c->li_linenum, c->li_line);
c= c->li_next;
}
#endif /* TRACE_NUMPARAMS */
@ -328,18 +336,27 @@ inp_subcktexpand(struct line *deck)
ok= ok && nupa_signal(NUPASUBDONE, NULL);
c= ll;
while (c != NULL) {
ok= ok && nupa_eval( c->li_line, c->li_linenum);
// 'param' .meas statements can have dependencies on measurement values
// need to skip evaluating here and evaluate after other .meas statements
if ( ciprefix( ".meas", c->li_line ) ) {
if ( !strstr( c->li_line, "param" ) ) nupa_eval( c->li_line, c->li_linenum);
} else {
//ok= ok && nupa_eval( c->li_line, c->li_linenum);
nupa_eval( c->li_line, c->li_linenum);
}
c= c->li_next;
}
#ifdef TRACE_NUMPARAMS
printf("Numparams converted deck:\n");
fprintf(stderr,"Numparams converted deck:\n");
c=ll;
while( c!=NULL) {
printf("%3d:%s\n",c->li_linenum, c->li_line);
fprintf(stderr,"%3d:%s\n",c->li_linenum, c->li_line);
c= c->li_next;
}
#endif /* TRACE_NUMPARAMS */
ok= ok && nupa_signal(NUPAEVALDONE, NULL);
//ok= ok && nupa_signal(NUPAEVALDONE, NULL);
//nupa_list_params(stdout);
nupa_copy_inst_dico();
}
#endif /* NUMPARAMS */
return (ll); /* return the spliced deck. */
@ -385,6 +402,7 @@ doit(struct line *deck)
#endif
/* First pass: xtract all the .subckts and stick pointers to them into sss. */
for (last = deck, lc = NULL; last; ) {
if (ciprefix(sbend, last->li_line)) { /* if line == .ends */
fprintf(cp_err, "Error: misplaced %s line: %s\n", sbend,
last->li_line);
@ -504,6 +522,7 @@ doit(struct line *deck)
gotone = FALSE;
for (c = deck, lc = NULL; c; ) {
if (ciprefix(invoke, c->li_line)) { /* found reference to .subckt (i.e. component with refdes X) */
char *tofree, *tofree2;
gotone = TRUE;
t = tofree = s = copy(c->li_line); /* s & t hold copy of component line */
@ -512,7 +531,7 @@ doit(struct line *deck)
* e.g. if invocation is Xreference, *scname = reference
*/
tofree2 = scname = gettok(&s);
scname += strlen(invoke);
/*scname += strlen(invoke); */
while ((*scname == ' ') || (*scname == '\t') ||
(*scname == ':'))
scname++;
@ -659,7 +678,7 @@ inp_deckcopy(struct line *deck)
d->li_linenum = deck->li_linenum;
d->li_line = copy(deck->li_line);
if (deck->li_error)
d->li_error = copy(deck->li_error);
d->li_error = copy(deck->li_error);
d->li_actual = inp_deckcopy(deck->li_actual);
deck = deck->li_next;
}
@ -684,7 +703,7 @@ static int
translate(struct line *deck, char *formal, char *actual, char *scname, char *subname)
{
struct line *c;
char *buffer, *next_name, dev_type, *name, *s, *t, ch, *nametofree;
char *buffer, *next_name, dev_type, *name, *s, *t, ch, *nametofree, *paren_ptr, *new_str;
int nnodes, i, dim, blen;
int rtn=0;
@ -705,9 +724,11 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub
/* now iterate through the .subckt deck and translate the cards. */
for (c = deck; c; c = c->li_next) {
dev_type = *(c->li_line);
#ifdef TRACE
/* SDB debug statement */
printf("\nIn translate, examining line %s \n", c->li_line);
printf("\nIn translate, examining line (dev_type: %c, subname: %s, instance: %s) %s \n", dev_type, subname, scname, c->li_line );
#endif
@ -716,7 +737,7 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub
/* Rename the device. */
switch (dev_type) {
case '\0':
case '*':
case '*': case '$':
case '.':
/* Just a pointer to the line into s and then break */
buffer = tmalloc(2000+strlen(c->li_line)); /* DW,VA */
@ -741,7 +762,7 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub
/* maschmann
sprintf(buffer, "%s:%s ", name, scname); */
buffer = (char *)tmalloc((strlen(scname)+strlen(name)+5)*sizeof(char));
sprintf(buffer, "a:%s:%s ", scname, name+1 );
sprintf(buffer, "a.%s.%s ", scname, name );
@ -808,11 +829,11 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub
if(name[0]=='v' || name[0]=='V') {
blen = strlen(buffer);
buffer = (char *)trealloc(buffer, (blen+strlen(scname)+strlen(name)+5)*sizeof(char));
sprintf(buffer + blen, "v:%s:%s ", scname, name+1);
sprintf(buffer + blen, "v.%s.%s ", scname, name);
} else {
blen = strlen(buffer);
buffer = (char *)trealloc(buffer, (blen+strlen(scname)+strlen(name)+3)*sizeof(char));
sprintf(buffer + blen, "%s:%s ", scname, name);
sprintf(buffer + blen, "%s.%s ", scname, name);
}
}
break;
@ -863,19 +884,9 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub
* and stick the translated name into buffer.
*/
ch = *name; /* ch identifies the type of component */
name++;
if (*name == ':')
name++; /* now name point to the rest of the refdes */
if (*name) {
buffer = (char *)tmalloc((strlen(scname)+strlen(name)+5)*sizeof(char));
sprintf(buffer, "%c:%s:%s ", ch, scname, /* F:subcircuitname:refdesname */
name);
} else {
buffer = (char *)tmalloc((strlen(scname)+4)*sizeof(char));
sprintf(buffer, "%c:%s ", ch, scname); /* F:subcircuitname */
}
buffer = (char *)tmalloc((strlen(scname)+strlen(name)+5)*sizeof(char));
sprintf(buffer, "%c.%s.%s ", ch, scname, name);
tfree(t);
@ -903,7 +914,7 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub
*/
blen = strlen(buffer);
buffer = (char *)trealloc(buffer, (blen+strlen(scname)+strlen(name)+3)*sizeof(char));
sprintf(buffer + blen, "%s:%s ", scname, name);
sprintf(buffer + blen, "%s.%s ", scname, name);
}
tfree(name);
} /* while (nnodes-- . . . . */
@ -975,12 +986,10 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub
#endif
ch = *name; /* ch is the first char of the token. */
name++;
if (*name == ':')
name++; /* name now points to the remainder of the token */
blen = strlen(buffer);
buffer = (char *)trealloc(buffer, (blen+strlen(scname)+strlen(name)+5)*sizeof(char));
sprintf(buffer + blen, "%c:%s:%s ", ch, scname, name);
sprintf(buffer + blen, "%c.%s.%s ", ch, scname, name);
/* From Vsense and Urefdes creates V:Urefdes:sense */
}
else { /* Handle netname */
@ -1003,7 +1012,7 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub
*/
blen = strlen(buffer);
buffer = (char *)trealloc(buffer, (blen+strlen(scname)+strlen(name)+3)*sizeof(char));
sprintf(buffer + blen, "%s:%s ", scname, name);
sprintf(buffer + blen, "%s.%s ", scname, name);
/* From netname and Urefdes creates Urefdes:netname */
}
}
@ -1034,17 +1043,14 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub
*/
ch = *name;
name++;
if (*name == ':')
name++;
if (*name) {
if ( ch != 'x' ) {
buffer = (char *)tmalloc((strlen(scname)+strlen(name)+5)*sizeof(char));
sprintf(buffer, "%c:%s:%s ", ch, scname, name);
sprintf(buffer, "%c.%s.%s ", ch, scname, name);
} else {
buffer = (char *)tmalloc((strlen(scname)+4)*sizeof(char));
sprintf(buffer, "%c:%s ", ch, scname);
buffer = (char *)tmalloc((strlen(scname)+strlen(name)+3)*sizeof(char));
sprintf(buffer, "%s.%s ", scname, name);
}
tfree(nametofree);
@ -1071,7 +1077,7 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub
*/
blen = strlen(buffer);
buffer = (char *)trealloc(buffer, (blen+strlen(scname)+strlen(name)+3)*sizeof(char));
sprintf(buffer + blen, "%s:%s ", scname, name);
sprintf(buffer + blen, "%s.%s ", scname, name);
}
tfree(name);
} /* while (nnodes-- . . . . */
@ -1089,19 +1095,17 @@ translate(struct line *deck, char *formal, char *actual, char *scname, char *sub
goto quit;
}
ch = *name;
name++;
if (*name == ':')
name++;
if (*name) {
if ( ch != 'x' ) {
blen = strlen(buffer);
buffer = (char *)trealloc(buffer, (blen+strlen(scname)+strlen(name)+5)*sizeof(char));
sprintf(buffer + blen, "%c:%s:%s ", ch, scname, name);
sprintf(buffer + blen, "%c.%s.%s ", ch, scname, name);
} else {
blen = strlen(buffer);
buffer = (char *)trealloc(buffer, (blen+strlen(scname)+4)*sizeof(char));
sprintf(buffer + blen, "%c:%s ", ch, scname);
buffer = (char *)trealloc(buffer, (blen+strlen(scname)+strlen(name)+2)*sizeof(char));
sprintf(buffer + blen, "%s ", scname);
}
tfree(t);
} /* while (nnodes--. . . . */
@ -1204,14 +1208,14 @@ finishLine(char *dst, char *src, char *scname)
if ((which == 'i' || which == 'I') &&
(buf[0] == 'v' || buf[0] == 'V')) {
*dst++ = buf[0];
*dst++ = ':';
*dst++ = '.';
i = 1;
} else {
i = 0;
}
for (s = scname; *s; )
*dst++ = *s++;
*dst++ = ':';
*dst++ = '.';
for (s = buf + i; *s; )
*dst++ = *s++;
}
@ -1234,7 +1238,7 @@ finishLine(char *dst, char *src, char *scname)
} else {
for (s = scname; *s; )
*dst++ = *s++;
*dst++ = ':';
*dst++ = '.';
for (s = buf; *s; )
*dst++ = *s++;
}
@ -1870,7 +1874,7 @@ inp_numnodes(char c)
case '\t':
case '.':
case 'x':
case '*':
case '*': case '$':
return (0);
case 'b': return (2);

View File

@ -31,6 +31,8 @@ struct circ {
struct line *ci_deck; /* The input deck. */
struct line *ci_origdeck;/* The input deck, before subckt expansion. */
struct line *ci_options;/* The .option cards from the deck... */
struct line *ci_meas; /* .measure commands to run after simulation */
struct line *ci_param; /* .param statements found in deck */
struct variable *ci_vars; /* ... and the parsed versions. */
bool ci_inprogress; /* We are in a break now. */
bool ci_runonce; /* So com_run can to a reset if necessary... */

View File

@ -393,6 +393,10 @@ extern int raw_prec;
extern void raw_write(char *name, struct plot *pl, bool app, bool binary);
extern struct plot *raw_read();
/* meas.c */
extern void do_measure(char *what, bool chk_only);
extern bool check_autostop(char *what);
/* resource.c */
extern void com_rusage();

View File

@ -7,7 +7,8 @@ Modified: 2000 AlansFixes
/* subroutine to do DC TRANSIENT analysis
--- ONLY, unlike spice2 routine with the same name! */
#include<ngspice.h>
#include <assert.h>
#include <ngspice.h>
#include <config.h>
#include <cktdefs.h>
#include <cktaccept.h>
@ -35,6 +36,22 @@ Modified: 2000 AlansFixes
void SetAnalyse( char * Analyse, int Percent);
#endif
// Initial AlmostEqualULPs version - fast and simple, but
// some limitations.
static bool AlmostEqualUlps(float A, float B, int maxUlps)
{
assert(sizeof(float) == sizeof(int));
if (A == B)
return TRUE;
int intDiff = abs(*(int*)&A - *(int*)&B);
if (intDiff <= maxUlps)
return TRUE;
return FALSE;
}
int
DCtran(CKTcircuit *ckt,
@ -458,9 +475,13 @@ nextTime:
/* gtri - end - wbk - Update event queues/data for accepted timepoint */
#endif
ckt->CKTstat->STAToldIter = ckt->CKTstat->STATnumIter;
if(fabs(ckt->CKTtime - ckt->CKTfinalTime) < ckt->CKTminBreak) {
/*printf(" done: time is %g, final time is %g, and tol is %g\n",*/
/*ckt->CKTtime,ckt->CKTfinalTime,ckt->CKTminBreak);*/
if(check_autostop("tran") ||
fabs(ckt->CKTtime - ckt->CKTfinalTime) < ckt->CKTminBreak ||
AlmostEqualUlps( ckt->CKTtime, ckt->CKTfinalTime, 3 ) ) {
#ifdef STEPDEBUG
printf(" done: time is %g, final time is %g, and tol is %g\n",
ckt->CKTtime,ckt->CKTfinalTime,ckt->CKTminBreak);
#endif
(*(SPfrontEnd->OUTendPlot))( (((TRANan*)ckt->CKTcurJob)->TRANplot));
ckt->CKTcurrentAnalysis = 0;
ckt->CKTstat->STATtranTime += (*(SPfrontEnd->IFseconds))()-startTime;
@ -522,7 +543,8 @@ resume:
MIN(ckt->CKTdelta,ckt->CKTmaxStep);
#ifdef XSPICE
/* gtri - begin - wbk - Cut integration order if first timepoint after breakpoint */
if(ckt->CKTtime == g_mif_info.breakpoint.last)
//if(ckt->CKTtime == g_mif_info.breakpoint.last)
if ( AlmostEqualUlps( ckt->CKTtime, g_mif_info.breakpoint.last, 3 ) )
ckt->CKTorder = 1;
/* gtri - end - wbk - Cut integration order if first timepoint after breakpoint */
@ -530,7 +552,8 @@ resume:
/* are we at a breakpoint, or indistinguishably close? */
if ((ckt->CKTtime == *(ckt->CKTbreaks)) || (*(ckt->CKTbreaks) -
//if ((ckt->CKTtime == *(ckt->CKTbreaks)) || (*(ckt->CKTbreaks) -
if ( AlmostEqualUlps( ckt->CKTtime, *(ckt->CKTbreaks), 3 ) || (*(ckt->CKTbreaks) -
(ckt->CKTtime) <= ckt->CKTdelmin)) {
/* first timepoint after a breakpoint - cut integration order */
/* and limit timestep to .1 times minimum of time to next breakpoint,
@ -581,8 +604,16 @@ resume:
/* gtri - begin - wbk - Modify Breakpoint stuff */
/* Throw out any permanent breakpoint times <= current time */
while(1) {
if(*(ckt->CKTbreaks) <= (ckt->CKTtime + ckt->CKTminBreak))
#ifdef STEPDEBUG
printf(" brk_pt: %g ckt_time: %g ckt_min_break: %g\n",*(ckt->CKTbreaks), ckt->CKTtime, ckt->CKTminBreak);
#endif
if(AlmostEqualUlps(*(ckt->CKTbreaks),ckt->CKTtime,3) || *(ckt->CKTbreaks) <= (ckt->CKTtime + ckt->CKTminBreak)) {
#ifdef STEPDEBUG
printf("throwing out permanent breakpoint times <= current time (brk pt: %g)\n",*(ckt->CKTbreaks));
printf(" ckt_time: %g ckt_min_break: %g\n",ckt->CKTtime, ckt->CKTminBreak);
#endif
CKTclrBreak(ckt);
}
else
break;
}

View File

@ -728,6 +728,14 @@ INP2dot(void *ckt, INPtables *tab, card *current, void *task, void *gnode)
LITERR(" Warning: .global not yet implemented - ignored \n");
goto quit;
}
/* ignore .meas statements -- these will be handled after analysis */
/* also ignore .param statements */
/* ignore .prot, .unprot */
else if (strcmp(token, ".meas") == 0 || strcmp(token, ".param") == 0 || strcmp(token, ".measure") == 0 ||
strcmp(token, ".prot") == 0 || strcmp(token, ".unprot") == 0) {
rtn = 0;
goto quit;
}
LITERR(" unimplemented control card - error \n");
quit:
tfree(token);

View File

@ -215,7 +215,7 @@ void INPpas2(void *ckt, card * data, INPtables * tab, void *task)
INP2K(ckt, tab, current);
break;
case '*':
case '*': case '$':
/* *<anything> - a comment - ignore */
break;