diff --git a/examples/digital/compare/adder-comparison.txt b/examples/digital/compare/adder-comparison.txt index ef3e28e12..56972e94e 100644 --- a/examples/digital/compare/adder-comparison.txt +++ b/examples/digital/compare/adder-comparison.txt @@ -1,4 +1,4 @@ -Compare four different 4-bit full adders, +Compare five different 4-bit full adders, made of NAND gates Simulating for 6400ns @@ -21,3 +21,9 @@ Fully digital, event node based NAND gates digital plotting into vcd file, display with gtkwave Simulation time 0.27s +adder_esource +Uses the NAND variant of the E-type behavioral voltage source. + +There are further variations of adder_Xspice in directory +examples/digital/auto_bridge. + diff --git a/examples/digital/compare/adder_esource.cir b/examples/digital/compare/adder_esource.cir new file mode 100644 index 000000000..62ee85673 --- /dev/null +++ b/examples/digital/compare/adder_esource.cir @@ -0,0 +1,16 @@ + ADDER - 4 BIT BINARY ADDER USING E-SOURCE AND GATES + * behavioral gate description + +*** SUBCIRCUIT DEFINITION + +.SUBCKT 74HC00 in1 in2 out NVCC NVGND vcc1={vcc} tripdt1={tripdt} +.param Rout={60*4.0/(vcc1-0.5)} ; standard output driver +E1 out20 0 nand(2) in1 0 in2 0 ({vcc / 3}, 0) ({2 * vcc / 3}, {vcc}) +Rout out20 out {Rout} +.ends + +.param vcc=3 tripdt=6n + +.include ../adder_common.inc + +.END diff --git a/src/frontend/numparam/numparam.h b/src/frontend/numparam/numparam.h index a294e2a2e..890bf8299 100644 --- a/src/frontend/numparam/numparam.h +++ b/src/frontend/numparam/numparam.h @@ -60,7 +60,7 @@ int donedico(dico_t *); void dico_free_entry(entry_t *); bool defsubckt(dico_t *, const struct card *); int findsubckt(dico_t *, const char *s); -bool nupa_substitute(dico_t *, const char *s, char *r); +bool nupa_substitute(dico_t *, const char *s, char **lp); bool nupa_assignment(dico_t *, const char *s, char mode); bool nupa_subcktcall(dico_t *, const char *s, const char *x, char *inst_name); diff --git a/src/frontend/numparam/spicenum.c b/src/frontend/numparam/spicenum.c index ce1af5153..fc1454759 100644 --- a/src/frontend/numparam/spicenum.c +++ b/src/frontend/numparam/spicenum.c @@ -676,10 +676,12 @@ nupa_eval(struct card *card) #endif if (c == 'P') { /* evaluate parameters */ - // err = nupa_substitute(dico, dico->dynrefptr[linenum], s); nupa_assignment(dicoS, dicoS->dynrefptr[linenum], 'N'); } else if (c == 'B') { /* substitute braces line */ - err = nupa_substitute(dicoS, dicoS->dynrefptr[linenum], s); + /* nupa_substitute() may reallocate line buffer. */ + + err = nupa_substitute(dicoS, dicoS->dynrefptr[linenum], &card->line); + s = card->line; } else if (c == 'X') { /* compute args of subcircuit, if required */ char *inst_name = copy_substring(s, skip_non_ws(s)); diff --git a/src/frontend/numparam/xpressn.c b/src/frontend/numparam/xpressn.c index e7ce0e1ee..346cbfc14 100644 --- a/src/frontend/numparam/xpressn.c +++ b/src/frontend/numparam/xpressn.c @@ -1201,27 +1201,48 @@ evaluate_expr(dico_t *dico, DSTRINGPTR qstr_p, const char *t, const char * const /********* interface functions for spice3f5 extension ***********/ -static char * -insertnumber(dico_t *dico, char * const s, DSTRINGPTR ustr_p) -/* insert u in string s in place of the next placeholder number */ +static bool +insertnumber(dico_t *dico, char **lp, DSTRINGPTR ustr_p) +/* insert *ustr_p in string *lp in place of the next placeholder number */ { const char *u = ds_get_buf(ustr_p); - - char buf[ACT_CHARACTS+1]; - - long id = 0; - int n = 0; + char *s = *lp; // Point to line contents + long id; + int n; char *p = strstr(s, "numparm__________"); if (p && (1 == sscanf(p, "numparm__________%8lx%n", &id, &n)) && (n == ACT_CHARACTS) && - (id > 0) && (id < dynsubst + 1) && - (snprintf(buf, sizeof(buf), "%-25s", u) == ACT_CHARACTS)) - { - memcpy(p, buf, ACT_CHARACTS); - return p + ACT_CHARACTS; + (id > 0) && (id < dynsubst + 1)) { + /* Found a target for substitution. */ + + n = ds_get_length(ustr_p); + if (n <= ACT_CHARACTS) { + char buf[ACT_CHARACTS + 1]; + + /* Replace in place. */ + + snprintf(buf, sizeof buf, "%-*s", ACT_CHARACTS, u); + memcpy(p, buf, ACT_CHARACTS); + } else { + char *newline; + + /* Requires reallocation. */ + + newline = malloc((p - s) + n + strlen(p + ACT_CHARACTS) + 1); + if (!newline) { + message(dico, "nupa_substitute failed: no memory\n"); + return TRUE; + } + memcpy(newline, s, (p - s)); + memcpy(newline + (p - s), u, n); + strcpy(newline + (p - s) + n, p + ACT_CHARACTS); + free(*lp); + *lp = newline; + } + return FALSE; } message @@ -1229,18 +1250,15 @@ insertnumber(dico_t *dico, char * const s, DSTRINGPTR ustr_p) "insertnumber: fails.\n" " s = \"%s\" u=\"%s\" id=%ld\n", s, u, id); - - /* swallow everything on failure */ - return s + strlen(s); + return TRUE; } bool -nupa_substitute(dico_t *dico, const char *s, char *r) +nupa_substitute(dico_t *dico, const char *s, char **lp) /* s: pointer to original source line. - r: pointer to result line, already heavily modified wrt s - anywhere we find a 10-char numstring in r, substitute it. - bug: wont flag overflow! + lp: pointer to result line pointer, line already heavily modified wrt s: + anywhere we find a 25-char numstring in *lp, substitute it. */ { const char * const s_end = s + strlen(s); @@ -1248,9 +1266,7 @@ nupa_substitute(dico_t *dico, const char *s, char *r) DS_CREATE(qstr, 200); /* temp result dynamic string */ - while (s < s_end) { - char c = *s++; if (c == '{') { @@ -1289,14 +1305,14 @@ nupa_substitute(dico_t *dico, const char *s, char *r) } s = kptr + 1; - r = insertnumber(dico, r, &qstr); - + err = insertnumber(dico, lp, &qstr); + if (err) + break; } } Lend: ds_free(&qstr); - return err; } diff --git a/src/spicelib/parser/inppas2.c b/src/spicelib/parser/inppas2.c index c388525be..bfc4b060a 100644 --- a/src/spicelib/parser/inppas2.c +++ b/src/spicelib/parser/inppas2.c @@ -82,7 +82,7 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task) #ifdef HAS_PROGREP if (linecount > 0) { - SetAnalyse( "Circuit2", (int) (1000.*actcount/linecount)); + SetAnalyse( "Parse", (int) (1000.*actcount/linecount)); actcount++; } #endif diff --git a/src/xspice/icm/analog/multi_input_pwl/cfunc.mod b/src/xspice/icm/analog/multi_input_pwl/cfunc.mod index 5758ce546..91e228c2e 100644 --- a/src/xspice/icm/analog/multi_input_pwl/cfunc.mod +++ b/src/xspice/icm/analog/multi_input_pwl/cfunc.mod @@ -174,33 +174,81 @@ get_output( ARGS, double x ) return result; } +static double +get_reverse_output( ARGS, double x ) +{ + int size = PARAM_SIZE(x); + double result = 0; + double slope = 0; + int i; + + /* check if x beyond specified limits */ + if ( x <= PARAM(x[0]) ) return PARAM(y[size-1]); + if ( x >= PARAM(x[size-1]) ) return PARAM(y[0]); + + for ( i = 1; i < size; i++ ) + if ( x > PARAM(x[i-1]) && x <= PARAM(x[i]) ) + { + result = PARAM(y[size - i - 1]) + slope * (x - PARAM(x[i - 1])); + break; + } + return result; +} + void cm_multi_input_pwl(ARGS) { - const char* model = ( PARAM_NULL(model) == 1 ) ? "and" : PARAM(model); + const char* model = PARAM(model); double output; - if ( ANALYSIS == TRANSIENT || ANALYSIS == DC ) - { - if ( strcmp( model, "and" ) != 0 && strcmp( model, "or" ) != 0 && - strcmp( model, "nand" ) != 0 && strcmp( model, "nor" ) != 0 ) - { - fprintf( stderr, "ERROR(cm_multi_input_pwl): unknown gate model type '%s'; expecting 'and|or|nand|nor'.\n", model ); + if (INIT) { + int type; + + if (!strcmp(model, "and")) + type = 0; + else if (!strcmp(model, "nand")) + type = 1; + else if (!strcmp(model, "or")) + type = 2; + else if (!strcmp(model, "nor")) + type = 3; + else { + fprintf(stderr, "ERROR(cm_multi_input_pwl): unknown gate model type " + "'%s'; expecting 'and|or|nand|nor'.\n", model ); exit(-1); - } - if ( PARAM_SIZE(x) != PARAM_SIZE(y) ) - { - fprintf( stderr, "ERROR(cm_multi_input_pwl): 'x' and 'y' input vectors are not the same size!\n" ); - exit(-1); - } + } + STATIC_VAR(type) = type; + if ( PARAM_SIZE(x) != PARAM_SIZE(y) ) { + fprintf(stderr, "ERROR(cm_multi_input_pwl): 'x' and 'y' input vectors are not the same size!\n" ); + if (PARAM_SIZE(x) > PARAM_SIZE(y)) + PARAM_SIZE(x) = PARAM_SIZE(y); + } + } + + if ( ANALYSIS == TRANSIENT || ANALYSIS == DC ) { /* Iterate through each input and find output value and/nand: controlling input is chosen on the basis of the smallest value or/nor: controlling input is chosen on the basis of the largest value */ - if (strstr(model, "and")) output = get_output(mif_private, get_smallest_input(mif_private)); - else output = get_output(mif_private, get_largest_input(mif_private)); + switch (STATIC_VAR(type)) { + case 0: + default: + output = get_output(mif_private, get_smallest_input(mif_private)); + break; + case 1: + output = get_reverse_output(mif_private, + get_smallest_input(mif_private)); + break; + case 2: + output = get_output(mif_private, get_largest_input(mif_private)); + break; + case 3: + output = get_reverse_output(mif_private, + get_largest_input(mif_private)); + break; + } OUTPUT(out) = output; } } diff --git a/src/xspice/icm/analog/multi_input_pwl/ifspec.ifs b/src/xspice/icm/analog/multi_input_pwl/ifspec.ifs index c87b0e471..852c2bda9 100644 --- a/src/xspice/icm/analog/multi_input_pwl/ifspec.ifs +++ b/src/xspice/icm/analog/multi_input_pwl/ifspec.ifs @@ -49,3 +49,11 @@ Limits: - - - Vector: yes yes no Vector_Bounds: [2 -] [2 -] - Null_Allowed: no no yes + +/* This is used internally to cache the model type. */ + +STATIC_VAR_TABLE: + +Static_Var_Name: type +Description: "Internal copy of model type" +Data_Type: int diff --git a/src/xspice/icm/digital/dac_bridge/cfunc.mod b/src/xspice/icm/digital/dac_bridge/cfunc.mod index f94f0c444..6f4a931be 100644 --- a/src/xspice/icm/digital/dac_bridge/cfunc.mod +++ b/src/xspice/icm/digital/dac_bridge/cfunc.mod @@ -63,22 +63,17 @@ NON-STANDARD FEATURES - /*=== MACROS ===========================*/ - /*=== LOCAL VARIABLES & TYPEDEFS =======*/ - /*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ - - /*============================================================================== @@ -123,6 +118,13 @@ NON-STANDARD FEATURES ==============================================================================*/ +/* Instances of this structure track digital input changes. */ + +struct d_data { + Digital_State_t i; // Input value. + double i_changed; // Time of input change. +}; + /*=== CM_DAC_BRIDGE ROUTINE ===*/ /************************************************ @@ -137,41 +139,35 @@ NON-STANDARD FEATURES void cm_dac_bridge(ARGS) { - double out_low, /* analog output value corresponding to '0' + double out_low, /* analog output value corresponding to '0' digital input */ - out_high, /* analog output value corresponding to '1' + out_high, /* analog output value corresponding to '1' digital input */ - out_undef, /* analog output value corresponding to 'U' - digital input */ - t_rise, /* rise time...used to produce d(out)/d(time) - values for gradual change in analog output. */ - t_fall, /* fall time...used to produce d(out)/d(time) - values for gradual change in analog output. */ - *out, /* array holding all output values */ - *out_old, /* array holding previous output values */ - fraction, /* fraction of total rise or fall time to add to - current time value for breakpoint calculation */ - level_inc, /* incremental level value out_high - out_low */ - rise_slope, /* level_inc divided by t_rise */ - fall_slope, /* level_inc divided by t_fall */ - time_inc, /* time increment since last analog call */ - test; /* testing variable */ + out_undef, /* analog output value corresponding to 'U' + digital input */ + t_rise, /* rise time...used to produce d(out)/d(time) + values for gradual change in analog output. */ + t_fall, /* fall time...used to produce d(out)/d(time) + values for gradual change in analog output. */ + *out, /* array holding all output values */ + *out_old, /* array holding previous output values */ + level_inc, /* incremental level value out_high - out_low */ + rise_slope, /* level_inc divided by t_rise */ + fall_slope, /* level_inc divided by t_fall */ + time_inc; /* time increment since last analog call */ - int i, /* generic loop counter index */ - size; /* number of input & output ports */ - - + int i, /* generic loop counter index */ + size; /* number of input & output ports */ - Digital_State_t *in, /* base address of array holding all input - values */ - *in_old; /* array holding previous input values */ + struct d_data *in, /* base address of array holding all input + values */ + *in_old; /* array holding previous input values */ /* determine "width" of the node bridge... */ size = PORT_SIZE(in); - /** Read in remaining model parameters **/ out_low = PARAM(out_low); @@ -179,7 +175,6 @@ void cm_dac_bridge(ARGS) t_rise = PARAM(t_rise); t_fall = PARAM(t_fall); - /* Test to see if out_low and out_high were specified, but */ /* out_undef was not... */ /* if so, take out_undef as mean of out_high and out_low. */ @@ -187,86 +182,64 @@ void cm_dac_bridge(ARGS) if (!PARAM_NULL(out_low) && !PARAM_NULL(out_high) && PARAM_NULL(out_undef) ) { out_undef = out_low + (out_high - out_low) / 2.0; - } - else { + } else { out_undef = PARAM(out_undef); } - - if (INIT) { /*** Test for INIT == TRUE. If so, allocate storage, etc. ***/ - - /* Allocate storage for inputs */ - cm_event_alloc(0, size * (int) sizeof(Digital_State_t)); + cm_event_alloc(0, size * (int) sizeof(struct d_data)); /* Allocate storage for outputs */ - /* retrieve previously-allocated discrete input and */ - /* allocate storage for analog output values. */ - - /* allocate output space and obtain adresses */ cm_analog_alloc(0, size * (int) sizeof(double)); - /* assign discrete addresses */ - in = in_old = (Digital_State_t *) cm_event_get_ptr(0,0); - - /* assign analog addresses */ - out = out_old = (double *) cm_analog_get_ptr(0,0); + /* Retrieve allocated addresses. */ + in = in_old = (struct d_data *) cm_event_get_ptr(0, 0); + out = (double *) cm_analog_get_ptr(0, 0); /* read current input values */ for (i=0; i out_low) { /* output still dropping */ - - out[i] = out_old[i] - fall_slope*time_inc; - if ( out_low > out[i]) out[i]=out_low; - - } - else { /* output at out_low */ - + out[i] = out_old[i] - fall_slope * time_inc; + if ( out_low > out[i]) + out[i] = out_low; + } else { /* output at out_low */ out[i] = out_low; - } break; case ONE: if (out_old[i] < out_high) { /* output still rising */ - - out[i] = out_old[i] + rise_slope*time_inc; - if ( out_high < out[i]) out[i]=out_high; - - } - else { /* output at out_high */ - + out[i] = out_old[i] + rise_slope * time_inc; + if ( out_high < out[i]) + out[i] = out_high; + } else { /* output at out_high */ out[i] = out_high; - } break; - case UNKNOWN: if (out_old[i] < out_undef) { /* output still rising */ - - out[i] = out_old[i] + (rise_slope * time_inc); - if ( out_undef < out[i]) out[i]=out_undef; - - } - else { - - if (out_old[i] > out_undef) { /* output still falling */ - - out[i] = out_old[i] - fall_slope*time_inc; - if ( out_undef > out[i]) out[i]=out_undef; - } - else { /* output at out_undef */ - + out[i] = out_old[i] + rise_slope * time_inc; + if ( out_undef < out[i]) + out[i] = out_undef; + } else { + if (out_old[i] > out_undef) { /* output still falling */ + out[i] = out_old[i] - fall_slope * time_inc; + if ( out_undef > out[i]) + out[i] = out_undef; + } else { /* output at out_undef */ out[i] = out_undef; } - } - break; - } - } - else { /* There HAS been a change in this digital input - since the last analog access...need to use the - old value of input to complete the breakpoint - slope before changing directions... */ + } else { + double when, iota, vout, interval[2]; + int step, step_count; + /* There HAS been a change in this digital input + since the last analog access. Determine when the change + occurred and calculate the current output, then + set a breakpoint for completion of the current transition. + */ - switch (in_old[i]) { + iota = (T(0) - T(1)) * 1e-7; // Ignorable + if (T(0) - in[i].i_changed < iota) { + /* Previous input value in force for whole step. */ - case ZERO: - if (out_old[i] > out_low) { /* output still dropping */ + step_count = 1; + step = 0; + interval[0] = T(0) - T(1); + } else if (in[i].i_changed - T(1) < iota) { + /* New input value in force for whole step. + * Includes common no-change case where new == old. + */ - out[i] = out_old[i] - fall_slope*time_inc; - if ( out_low > out[i]) out[i]=out_low; + step_count = 2; + step = 1; + interval[1] = T(0) - T(1); + } else { + /* Calculate both sides of change. */ - } - else { /* output at out_low */ - - out[i] = out_low; - - } - break; - - case ONE: - if (out_old[i] < out_high) { /* output still rising */ - - out[i] = out_old[i] + rise_slope*time_inc; - if ( out_high < out[i]) out[i]=out_high; - - } - else { /* output at out_high */ - - out[i] = out_high; - - } - break; - - - case UNKNOWN: - if (out_old[i] < out_undef) { /* output still rising */ - - out[i] = out_old[i] + (rise_slope * time_inc); - if ( out_undef < out[i]) out[i]=out_undef; - - } - else { - - if (out_old[i] > out_undef) { /* output still falling */ - - out[i] = out_old[i] - fall_slope*time_inc; - if ( out_undef > out[i]) out[i]=out_undef; - } - else { /* output at out_undef */ - - out[i] = out_undef; - } - - } - - break; - - } - - /* determine required new breakpoint for the end of - the output analog transition & post */ - - switch (in[i]) { - - case ONE: /* rising for all outputs */ - fraction = (out_high - out[i]) / (out_high - out_low); - test = TIME + (fraction * t_rise); - cm_analog_set_perm_bkpt(test); - break; - - case UNKNOWN: /* may be rising or falling */ - - if ( out_undef > out[i] ) { /* rising to U */ - fraction = (out_undef - out[i]) / (out_high - out_low); - test = TIME + (fraction * t_rise); - cm_analog_set_perm_bkpt(test); - } - else { /* falling to U */ - fraction = (out[i] - out_undef) / (out_high - out_low); - test = TIME + (fraction * t_fall); - cm_analog_set_perm_bkpt(test); - } - break; - - case ZERO: /* falling for all outputs */ - fraction = (out[i] - out_low) / (out_high - out_low); - test = TIME + (fraction * t_fall); - cm_analog_set_perm_bkpt(test); - break; + step_count = 2; + step = 0; + interval[0] = in[i].i_changed - T(1); + interval[1] = T(0) - in[i].i_changed; } + + when = -1.0; + vout = out_old[i]; + for (; step < step_count; ++step) { + Digital_State_t drive; + int last_step = (step == step_count - 1); + + if (step == 0) + drive = in_old[i].i; + else + drive = in[i].i; + + switch (drive) { + case ZERO: + if (vout <= out_low) + break; + vout -= fall_slope * interval[step]; + if (vout < out_low) + vout = out_low; + else if (last_step) + when = (vout - out_low) / fall_slope; + break; + case ONE: + if (vout >= out_high) + break; + vout += rise_slope * interval[step]; + if (vout > out_high) + vout = out_high; + else if (last_step) + when = (out_high - vout) / rise_slope; + break; + case UNKNOWN: + if (vout > out_undef) { + vout -= fall_slope * interval[step]; + if (vout < out_undef) + vout = out_undef; + else if (last_step) + when = (vout - out_undef) / fall_slope; + } else { + vout += rise_slope * interval[step]; + if (vout > out_undef) + vout = out_undef; + else if (last_step) + when = (out_undef - vout) / rise_slope; + } + break; + } + } + if (when > 0.0) + cm_analog_set_perm_bkpt(when + TIME); + out[i] = vout; } - } - - /* Output values... */ - - for (i=0; i