Improvements in frontend by Phil Barker
This commit is contained in:
parent
56626999fc
commit
936cd7a4fc
21
ChangeLog
21
ChangeLog
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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... */
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue