From 78405474083b267d6782d34018c034c21795190e Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Sat, 5 Aug 2023 10:34:16 -0700 Subject: [PATCH 01/17] Add support for PSpice DLYLINE. --- src/frontend/udevices.c | 98 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 92 insertions(+), 6 deletions(-) diff --git a/src/frontend/udevices.c b/src/frontend/udevices.c index e7ae3b90b..c06184a01 100644 --- a/src/frontend/udevices.c +++ b/src/frontend/udevices.c @@ -10,7 +10,7 @@ using the previously stored delays. Some limitations are: - No support for DLYLINE, CONSTRAINT, RAM, ROM, STIM, PLAs. + No support for CONSTRAINT, RAM, ROM, STIM, PLAs. Approximations to the Pspice timing delays. Typical values for delays are estimated. Pspice has a rich set of timing simulation features, such as checks for setup/hold violations, minimum pulse width, and @@ -22,7 +22,7 @@ First pass through a subcircuit. Call initialize_udevice() and read the .model cards by calling u_process_model_line() (or similar) for each card, - The delays for the different types (ugate, utgate, ueff, ugff) are stored + The delays for the different types (ugate, utgate, ueff, ugff, udly) are stored by get_delays_...() and add_delays_to_model_xlator(). Also, during the first pass, check that each U* instance can be translated to Xspice. If there are any .model or U* instance cards that cannot be processed @@ -85,7 +85,8 @@ extern struct card* insert_new_line( #define D_UP 16 #define D_DOWN 17 #define D_TRI 18 -#define XSPICESZ 19 +#define D_DLYLINE 19 +#define XSPICESZ 20 /* structs for parsed gate U... instances */ struct instance_hdr { @@ -173,7 +174,7 @@ typedef struct s_xlate { Xlatep next; char *translated; // the translated instance line char *delays; // the delays from the pspice timing model - char *utype; // pspice model type ugate, utgate, ueff, ugff + char *utype; // pspice model type ugate, utgate, ueff, ugff, udly char *xspice; // xspice device type such as d_and, d_dff, etc. char *tmodel; // timing model name of pspice instance or model char *mname; // name of the xspice timing model of the instance @@ -472,6 +473,7 @@ static char *xspice_tab[XSPICESZ] = { "d_pullup", // D_UP "d_pulldown", // D_DOWN "d_tristate", // D_TRI + "d_buffer", // D_DLYLINE uses buffer with transport delay }; static char *find_xspice_for_delay(char *itype) @@ -502,6 +504,7 @@ static char *find_xspice_for_delay(char *itype) case 'd': { if (eq(itype, "dff")) { return xspice_tab[D_DFF]; } if (eq(itype, "dltch")) { return xspice_tab[D_DLTCH]; } + if (eq(itype, "dlyline")) { return xspice_tab[D_DLYLINE]; } break; } case 'i': { @@ -2793,7 +2796,7 @@ static char *larger_delay(char *delay1, char *delay2) /* NOTE The get_delays_...() functions calculate estimates of typical delays - from the Pspice ugate, utgate, ueff, and ugff timing models. + from the Pspice ugate, udly, utgate, ueff, and ugff timing models. These functions are called from u_process_model(), and the delay strings are added to the timing model Xlator by add_delays_to_model_xlator(). */ @@ -2836,6 +2839,26 @@ static char *get_delays_ugate(char *rem) return delays; } +static char *get_delays_udly(char *rem) +{ + char *udelay, *delays = NULL; + struct timing_data *tdp1; + + tdp1 = create_min_typ_max("dly", rem); + estimate_typ(tdp1); + udelay = get_estimate(tdp1); + if (udelay) { + delays = tprintf( + "(inertial_delay=false rise_delay = %s fall_delay = %s)", + udelay, udelay); + } else { + delays = tprintf( + "(inertial_delay=false rise_delay = 1.0e-12 fall_delay = 1.0e-12)"); + } + delete_timing_data(tdp1); + return delays; +} + static char *get_delays_utgate(char *rem) { /* Return estimate of tristate delay (delay = val3) */ @@ -3145,6 +3168,11 @@ static BOOL u_process_model(char *nline, char *original) /* skip uio models */ retval = TRUE; delays = NULL; + } else if (eq(utype, "udly")) { + delays = get_delays_udly(remainder); + add_delays_to_model_xlator((delays ? delays : ""), + utype, "", tmodel); + if (delays) { tfree(delays); } } else { retval = FALSE; delays = NULL; @@ -3835,7 +3863,7 @@ static Xlatorp translate_pull(struct instance_hdr *hdr, char *start) xspice = find_xspice_for_delay(itype); newline = TMALLOC(char, strlen(start) + 1); (void) memcpy(newline, start, strlen(start) + 1); - model_name = tprintf("d_%s_%s", iname, itype); + model_name = tprintf("d_a%s_%s", iname, itype); for (i = 0; i < numpulls; i++) { if (i == 0) { tok = strtok(newline, " \t"); @@ -3863,6 +3891,62 @@ end_of_function: return xp; } +static Xlatorp translate_dlyline(struct instance_hdr *hdr, char *start) +{ + char *itype, *iname, *newline = NULL, *tok; + char *model_name = NULL, *tmodel = NULL; + Xlatorp xp = NULL; + Xlatep xdata = NULL; + DS_CREATE(statement, 128); + + itype = hdr->instance_type; + iname = hdr->instance_name; + newline = TMALLOC(char, strlen(start) + 1); + (void) memcpy(newline, start, strlen(start) + 1); + model_name = tprintf("d_a%s_%s", iname, itype); + ds_clear(&statement); + + /* input name */ + tok = strtok(newline, " \t"); + if (!tok) { + fprintf(stderr, "ERROR input missing from dlyline\n"); + goto end_of_function; + } + ds_cat_printf(&statement, "a%s %s", iname, tok); + + /* output name */ + tok = strtok(NULL, " \t"); + if (!tok) { + fprintf(stderr, "ERROR output missing from dlyline\n"); + goto end_of_function; + } + ds_cat_printf(&statement, " %s %s", tok, model_name); + + xp = create_xlator(); + xdata = create_xlate_translated(ds_get_buf(&statement)); + xp = add_xlator(xp, xdata); + + /* tmodel */ + tmodel = strtok(NULL, " \t"); + if (!tmodel) { + fprintf(stderr, "ERROR timing model missing from dlyline\n"); + delete_xlator(xp); + xp = NULL; + goto end_of_function; + } + if (!gen_timing_model(tmodel, "udly", "d_buffer", model_name, xp)) { + printf("WARNING unable to find tmodel %s for %s dlyline\n", + tmodel, model_name); + } + +end_of_function: + if (model_name) { tfree(model_name); } + if (newline) { tfree(newline); } + delete_instance_hdr(hdr); + ds_free(&statement); + return xp; +} + static Xlatorp translate_ff_latch(struct instance_hdr *hdr, char *start) { /* If OK return Xlatorp else return NULL */ @@ -4062,6 +4146,8 @@ BOOL u_process_instance(char *nline) xp = translate_ff_latch(hdr, p1); } else if (eq(itype, "pullup") || eq(itype, "pulldn")) { xp = translate_pull(hdr, p1); + } else if (eq(itype, "dlyline")) { + xp = translate_dlyline(hdr, p1); } else { delete_instance_hdr(hdr); if (ps_udevice_exit) { From c02de13e10e0b511f7bf6279bbd329805557c545 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Tue, 8 Aug 2023 11:56:13 +0100 Subject: [PATCH 02/17] Fix an infinite loop bug that may be seen with "stop whan a>b" or "stop when a<>b". --- src/frontend/breakp.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/frontend/breakp.c b/src/frontend/breakp.c index cf1e410b4..c35549384 100644 --- a/src/frontend/breakp.c +++ b/src/frontend/breakp.c @@ -63,6 +63,7 @@ com_stop(wordlist *wl) d->db_also = TMALLOC(struct dbcomm, 1); d = d->db_also; } + d->db_also = NULL; /* Figure out what the first condition is. */ d->db_analysis = NULL; @@ -127,13 +128,24 @@ com_stop(wordlist *wl) /* Now get the condition */ if (eq(wl->wl_word, "eq") || eq(wl->wl_word, "=")) d->db_op = DBC_EQU; - else if (eq(wl->wl_word, "ne") || eq(wl->wl_word, "<>")) + else if (eq(wl->wl_word, "ne")) d->db_op = DBC_NEQ; else if (eq(wl->wl_word, "gt") || eq(wl->wl_word, ">")) d->db_op = DBC_GT; - else if (eq(wl->wl_word, "lt") || eq(wl->wl_word, "<")) + else if (eq(wl->wl_word, "lt")) d->db_op = DBC_LT; - else if (eq(wl->wl_word, "ge") || eq(wl->wl_word, ">=")) + else if (eq(wl->wl_word, "<")) { + /* "<>" is parsed as two words. */ + + if (eq(wl->wl_next->wl_word, ">")) { + if (!wl->wl_next->wl_next) + goto bad; + d->db_op = DBC_NEQ; + wl = wl->wl_next; + } else { + d->db_op = DBC_LT; + } + } else if (eq(wl->wl_word, "ge") || eq(wl->wl_word, ">=")) d->db_op = DBC_GTE; else if (eq(wl->wl_word, "le") || eq(wl->wl_word, "<=")) d->db_op = DBC_LTE; @@ -150,15 +162,16 @@ com_stop(wordlist *wl) d->db_value2 = val; } else { - d->db_nodename2 = copy(wl->wl_word); + d->db_nodename2 = copy(wl->wl_word); } } wl = wl->wl_next; - } - else { + } else { // Neither "after" nor "when". goto bad; } - } /* end of case of word "when" */ + } else { + goto bad; + } } /* end of loop over wordlist */ if (thisone) { @@ -178,7 +191,12 @@ com_stop(wordlist *wl) bad: fprintf(cp_err, "Syntax error parsing breakpoint specification.\n"); -} /* end of funtion com_stop */ + while (thisone) { + d = thisone->db_also; + txfree(thisone); + thisone = d; + } +} /* end of function com_stop */ From 5638008a7f3f56a2131ccf236105f72b45dd57ee Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Tue, 8 Aug 2023 13:14:25 +0100 Subject: [PATCH 03/17] Complete version of intertial delay for d_tristate. The State and Strength members are treated independently and combined in the output. --- src/xspice/icm/digital/d_tristate/cfunc.mod | 338 ++++++++++++++++--- src/xspice/icm/digital/d_tristate/ifspec.ifs | 6 +- 2 files changed, 296 insertions(+), 48 deletions(-) diff --git a/src/xspice/icm/digital/d_tristate/cfunc.mod b/src/xspice/icm/digital/d_tristate/cfunc.mod index ac9cb086b..8f5d67bd5 100644 --- a/src/xspice/icm/digital/d_tristate/cfunc.mod +++ b/src/xspice/icm/digital/d_tristate/cfunc.mod @@ -107,24 +107,22 @@ NON-STANDARD FEATURES * Last Modified 11/26/91 * ************************************************/ +#define DEBUG 0 +#if DEBUG +const char * const Image[] = {"Idle", "Normal", "Same", "Revert", "Both"}; +#endif + void cm_d_tristate(ARGS) { - Digital_t *out; - Digital_State_t val, enable; + Digital_State_t val; Digital_Strength_t str; + Digital_t *out; struct idata *idp; if (INIT) { /* initial pass */ - /* define input loading... */ - LOAD(in) = PARAM(input_load); - LOAD(enable) = PARAM(enable_load); - OUTPUT_DELAY(out) = PARAM(delay); - - /* allocate storage for the previous output. */ + /* allocate storage for the outputs */ cm_event_alloc(0, sizeof (Digital_t)); - out = (Digital_t *)cm_event_get_ptr(0, 0); - out->state = (Digital_State_t)(UNKNOWN + 1); // Force initial output. /* Inertial delay? */ @@ -132,72 +130,324 @@ void cm_d_tristate(ARGS) cm_is_inertial(PARAM_NULL(inertial_delay) ? Not_set : PARAM(inertial_delay)); if (STATIC_VAR(is_inertial)) { - /* Allocate storage for event time. */ + /* Allocate storage for event times. A little rude, + * as strength values will be stored in idp[1].prev. + */ cm_event_alloc(1, 2 * sizeof (struct idata)); idp = (struct idata *)cm_event_get_ptr(1, 0); idp[1].when = idp[0].when = -1.0; } - /* Prepare initial output. */ - - out = (Digital_t *)cm_event_get_ptr(0, 0); + out = (Digital_t *) cm_event_get_ptr(0,0); out->state = (Digital_State_t)(UNKNOWN + 1); // Force initial output. + + /* define input loading... */ + LOAD(in) = PARAM(input_load); + LOAD(enable) = PARAM(enable_load); + OUTPUT_DELAY(out) = PARAM(delay); // Never changes, unless inertial. } else { out = (Digital_t *)cm_event_get_ptr(0, 0); } - /* Retrieve input values and static variables */ + /* Retrieve input values. */ val = INPUT_STATE(in); - - enable = INPUT_STATE(enable); - if (ZERO == enable) { + switch (INPUT_STATE(enable)) { + case ZERO: str = HI_IMPEDANCE; - } else if (UNKNOWN == enable) { - str = UNDETERMINED; - } else { + break; + case ONE: str = STRONG; + break; + default: + str = UNDETERMINED; + break; } - if (val == out->state && str == out->strength) { + /*** Check for change and output appropriate values ***/ + + if (val == out->state && str == out->strength) { /* output not changing */ OUTPUT_CHANGED(out) = FALSE; } else { if (STATIC_VAR(is_inertial) && ANALYSIS == TRANSIENT) { - int d_cancel, s_cancel; + /* Each channel (State, Strength) of the output has three values, + * that set by the input, the current node value and its value + * following a pending change. The channel is in one of + * five states: + * Idle - no new value and no pending output; + * Normal - there is a new value with no pending output; + * Same - no new value, there is pending output; + * Revert - new value same as current, conflicting pending output; + * Both - new value differs from both current and pending. + */ + + enum {Idle, Normal, Same, Revert, Both} + d_ctl, s_ctl, ctl1, ctl2; + struct idata *idp; + double first_time, second_time; /* Scheduled changes */ + double delay_1; /* Delay to first output. */ + double cancel_delay; /* Delay to canclling. */ + int d_first; + Digital_t reversion, restoration; idp = (struct idata *)cm_event_get_ptr(1, 0); - d_cancel = (idp[0].when > TIME && val == idp[0].prev); - s_cancel = (idp[1].when > TIME && - str == (Digital_Strength_t)idp[1].prev); - if ((d_cancel && s_cancel) || - (d_cancel && str == out->strength && TIME >= idp[1].when) || - (s_cancel && val == out->state && TIME >= idp[0].when)) { - double when; - /* Changing back: override pending change. */ + /* Combine two independent streams (state and strength) into + * a sequence of output events. Earlier changes cancel later ones + * that may need to be restored. + */ - when = d_cancel ? idp[0].when : idp[1].when; - if (s_cancel && when > idp[1].when) - when = idp[1].when; + /* Identify earlier change. */ - OUTPUT_DELAY(out) = (when - TIME) / 2.0; // Override - idp[1].when = idp[0].when = -1.0; + if (idp[0].when <= idp[1].when) { + first_time = idp[0].when; + second_time = idp[1].when; + d_first = 1; } else { - /* Normal transition, or third value during delay, - * or needs cancel followed by restore of - * the other component (fudge). - */ + first_time = idp[1].when; + second_time = idp[0].when; + d_first = 0; + } - OUTPUT_DELAY(out) = PARAM(delay); - if (val != out->state) { + /* What happens to state? */ + + OUTPUT_DELAY(out) = PARAM(delay); + if (idp[0].when <= TIME) { + if (val == out->state) { + d_ctl = Idle; /* Output is stable and no change. */ + idp[0].prev = val; + } else { + d_ctl = Normal; /* Output was stable, changing now. */ idp[0].prev = out->state; idp[0].when = TIME + OUTPUT_DELAY(out); } - if (str != out->strength) { - idp[1].prev = (Digital_State_t)out->strength; + } else { + if (val == out->state) { + d_ctl = Same; /* Output pending, no change. */ + } else if (val == idp[0].prev) { + d_ctl = Revert; /* Returning to previous state. */ + idp[0].when = -1.0; + } else { + d_ctl = Both; /* Output pending, now changing. */ + idp[0].when = TIME + OUTPUT_DELAY(out); + } + } + + /* Strength? */ + + if (idp[1].when <= TIME) { + if (str == out->strength) { + s_ctl = Idle; + idp[1].prev = str; + } else { + s_ctl = Normal; + idp[1].prev = out->strength; idp[1].when = TIME + OUTPUT_DELAY(out); } + } else { + if (str == out->strength) { + s_ctl = Same; + } else if (str == (Digital_Strength_t)idp[1].prev) { + s_ctl = Revert; + idp[1].when = -1.0; + } else { + s_ctl = Both; + idp[1].when = TIME + OUTPUT_DELAY(out); + } + } + + if (d_first) { + ctl1 = d_ctl; + ctl2 = s_ctl; + } else { + ctl1 = s_ctl; + ctl2 = d_ctl; + } +#if DEBUG + cm_message_printf("%g: %s first, " + "state ctl %s %d->%d->%d @ %g, " + "strength ctl %s %d->%d->%d @ %g", + TIME, d_first ? "state" : "strength", + Image[d_ctl], idp[0].prev, out->state, val, + idp[0].when, + Image[s_ctl], idp[1].prev, out->strength, str, + idp[1].when); +#endif + switch (ctl1) { + case Idle: + switch (ctl2) { + default: + break; + case Revert: + /* Normal output is used to revert. */ + + delay_1 = (second_time - TIME) / 2.0; +direct_revert: + if (d_first) { + str = (Digital_Strength_t)idp[1].prev; + } else { + val = idp[0].prev; + } + OUTPUT_DELAY(out) = delay_1; + break; + + case Both: + /* Push out reversion before normal output. */ + + cancel_delay = (second_time - TIME) / 2.0; +push_revert: + if (d_first) { + reversion.state = out->state; + reversion.strength = (Digital_Strength_t)idp[1].prev; + } else { + reversion.state = idp[0].prev; + reversion.strength = out->strength; + } + cm_schedule_output(2, 0, cancel_delay, &reversion); + break; + } + break; + case Normal: + switch (ctl2) { + default: + break; + case Revert: + /* Push out reversion before normal output. */ + + if (d_first) { + reversion.state = out->state; + reversion.strength = (Digital_Strength_t)idp[1].prev; + str = reversion.strength; + } else { + reversion.state = idp[0].prev; + val = reversion.state; + reversion.strength = out->strength; + } + cancel_delay = (second_time - TIME) / 2.0; + cm_schedule_output(2, 0, cancel_delay, &reversion); + break; + case Both: + /* Push out reversion before normal output. */ + + cancel_delay = (second_time - TIME) / 2.0; + goto push_revert; + break; + } + break; + case Same: + switch (ctl2) { + default: + break; + case Revert: + /* Normal output is used to revert. */ + + delay_1 = (first_time + second_time) / 2.0 - TIME; + goto direct_revert; + break; + case Both: + /* Push out reversion before normal output. */ + + cancel_delay = (first_time + second_time) / 2.0 - TIME; + goto push_revert; + break; + } + break; + case Revert: + switch (ctl2) { + default: + /* Ordinary reversion. */ + + delay_1 = (first_time - TIME) / 2.0; + d_first = !d_first; + goto direct_revert; + break; + + case Normal: + /* Push out state reversion before normal output. */ + + cancel_delay = (first_time - TIME) / 2.0; + d_first = !d_first; + goto push_revert; + break; + + case Same: + /* Set normal output time to restore scheduled output + * and push out reversion. + */ + + reversion.state = idp[0].prev; + reversion.strength = (Digital_Strength_t)idp[1].prev; + cancel_delay = (first_time - TIME) / 2.0; + cm_schedule_output(2, 0, cancel_delay, &reversion); + OUTPUT_DELAY(out) = second_time - TIME; + break; + + case Revert: + /* Revert both together. */ + + val = idp[0].prev; + str = (Digital_Strength_t)idp[1].prev; + OUTPUT_DELAY(out) = (first_time - TIME) / 2.0; + break; + + case Both: + /* Double revert with normal output. */ + + reversion.state = idp[0].prev; + reversion.strength = (Digital_Strength_t)idp[1].prev; + cancel_delay = (first_time - TIME) / 2.0; + cm_schedule_output(2, 0, cancel_delay, &reversion); + + if (d_first) { + val = reversion.state; + } else { + str = reversion.strength; + } + break; + } + break; + + case Both: + switch (ctl2) { + default: + /* Push out state reversion before normal output. */ + + cancel_delay = (first_time - TIME) / 2.0; + d_first = !d_first; + goto push_revert; + break; + + case Same: + /* Push out reversion, then restore scheduled change, + * then normal output. + */ + + reversion.state = idp[0].prev; + reversion.strength = (Digital_Strength_t)idp[1].prev; + cancel_delay = (first_time - TIME) / 2.0; + cm_schedule_output(2, 0, cancel_delay, &reversion); + + if (d_first) { + restoration.state = reversion.state; + restoration.strength = out->strength; + } else { + restoration.state = out->state; + restoration.strength = reversion.strength; + } + cm_schedule_output(2, 0, second_time - TIME, &restoration); + break; + + case Revert: + case Both: + /* Push out double reversion, then normal output. */ + + reversion.state = idp[0].prev; + reversion.strength = (Digital_Strength_t)idp[1].prev; + cancel_delay = (first_time - TIME) / 2.0; + cm_schedule_output(2, 0, cancel_delay, &reversion); + break; + } } } out->state = val; diff --git a/src/xspice/icm/digital/d_tristate/ifspec.ifs b/src/xspice/icm/digital/d_tristate/ifspec.ifs index 20fe5eef9..30f34631d 100644 --- a/src/xspice/icm/digital/d_tristate/ifspec.ifs +++ b/src/xspice/icm/digital/d_tristate/ifspec.ifs @@ -45,8 +45,8 @@ Description: "delay" Data_Type: real Default_Value: 1.0e-9 Limits: [1e-12 -] -Vector: no -Vector_Bounds: - +Vector: no +Vector_bounds: - Null_Allowed: yes @@ -61,10 +61,8 @@ Vector: no no Vector_Bounds: - - Null_Allowed: yes yes - PARAMETER_TABLE: - Parameter_Name: inertial_delay family Description: "swallow short pulses" "Logic family for bridging" Data_Type: boolean string From 51e8f4311e2b293de3736d74ca6371e143a6a3d6 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 12 Aug 2023 12:25:35 +0200 Subject: [PATCH 04/17] Activate callback, remove memory leak --- src/xspice/icm/digital/d_osc/cfunc.mod | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/xspice/icm/digital/d_osc/cfunc.mod b/src/xspice/icm/digital/d_osc/cfunc.mod index 01e268f74..e4361e783 100644 --- a/src/xspice/icm/digital/d_osc/cfunc.mod +++ b/src/xspice/icm/digital/d_osc/cfunc.mod @@ -15,7 +15,7 @@ struct pwl { /* Called at end to free memory. */ -static void callback(ARGS, Mif_Callback_Reason_t reason) +static void cm_d_osc_callback(ARGS, Mif_Callback_Reason_t reason) { struct panel_instance *instance; @@ -70,6 +70,8 @@ void cm_d_osc(ARGS) double ctl, delta, when; int csize, i; + CALLBACK = cm_d_osc_callback; + csize = PARAM_SIZE(cntl_array); if (INIT) { From 550f563e0d53be80a6f07cad213b07a50b3d2087 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 12 Aug 2023 12:30:47 +0200 Subject: [PATCH 05/17] Remove gcc compiler warnings --- src/frontend/plotting/plotit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/plotting/plotit.c b/src/frontend/plotting/plotit.c index 0b8b9a951..449b0fec1 100644 --- a/src/frontend/plotting/plotit.c +++ b/src/frontend/plotting/plotit.c @@ -1318,10 +1318,10 @@ static struct dvec *vec_scale(struct dvec *v) * vec_scale for its scale vector (for x range of scale). * lims: Address of an array of 2 double values to receive the limits. **/ -static void find_axis_limits(double lim[2], bool oneval, bool f_real, +static void find_axis_limits(double *lim, bool oneval, bool f_real, struct dvec *vecs, struct dvec *(*p_get_axis_dvec)(struct dvec *dvec), - double lims[2]) + double *lims) { if (lim != (double *) NULL) { lims[0] = lim[0]; From c33bcafb340f9237a1c42af1963540ebf49fd63b Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 12 Aug 2023 13:55:51 +0200 Subject: [PATCH 06/17] Remove buggy if clause, add safeguards against buggy input --- src/frontend/inp.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/frontend/inp.c b/src/frontend/inp.c index 0cbbf0425..74e457b33 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -2411,7 +2411,6 @@ limit(double nominal_val, double abs_variation) * of agauss() * agauss in .param lines has been treated already */ - static void eval_agauss(struct card *deck, char *fcn) { @@ -2448,14 +2447,30 @@ eval_agauss(struct card *deck, char *fcn) begstr = copy_substring(curr_line, ap); lparen = strchr(ap, '('); tmp1str = midstr = gettok_char(&lparen, ')', FALSE, TRUE); - if (lparen + 1) - contstr = copy(lparen + 1); + if (!tmp1str) { + fprintf(cp_err, "ERROR: Incomplete function %s in line %s\n", fcn, curr_line); + tfree(begstr); + return; + } + contstr = copy(lparen + 1); tmp1str++; /* skip '(' */ /* find the parameters, ignore ( ) , */ delstr = tmp2str = gettok_np(&tmp1str); + if (!tmp2str) { + fprintf(cp_err, "ERROR: Incomplete function %s in line %s\n", fcn, curr_line); + tfree(begstr); + tfree(contstr); + return; + } x = INPevaluate(&tmp2str, &nerror, 1); tfree(delstr); delstr = tmp2str = gettok_np(&tmp1str); + if (!tmp2str) { + fprintf(cp_err, "ERROR: Incomplete function %s in line %s\n", fcn, curr_line); + tfree(begstr); + tfree(contstr); + return; + } y = INPevaluate(&tmp2str, &nerror, 1); tfree(delstr); if (cieq(fcn, "agauss")) { From 2f369d5435c84bcbeaf6652392d6e22331460a4d Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 12 Aug 2023 14:19:29 +0200 Subject: [PATCH 07/17] Remove gcc compiler warning: remove needless code --- src/frontend/inpcom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index d7b178151..c871e58e4 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -5490,7 +5490,7 @@ static char* eval_tc(char* line, char *tline) { if (error == 0) { tc1_str = tprintf("tc1=%15.8e", tc1); } - else if (error == 1 && *tc1_ptr == '{' && tc1_ptr + 1 && *(tc1_ptr + 1) != '}') { + else if (error == 1 && *tc1_ptr == '{' && *(tc1_ptr + 1) != '}') { char* bra = gettok_char(&tc1_ptr, '}', TRUE, TRUE); if (bra) { tc1_str = tprintf("tc1=%s", bra); @@ -5522,7 +5522,7 @@ static char* eval_tc(char* line, char *tline) { if (error == 0) { tc2_str = tprintf("tc2=%15.8e", tc2); } - else if (error == 1 && *tc2_ptr == '{' && tc2_ptr + 1 && *(tc2_ptr + 1) != '}') { + else if (error == 1 && *tc2_ptr == '{' && *(tc2_ptr + 1) != '}') { char* bra = gettok_char(&tc2_ptr, '}', TRUE, TRUE); if (bra) { tc2_str = tprintf("tc2=%s", bra); From 0db8d3b956a7f4f73d4c47fa11370b512bd0584c Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 12 Aug 2023 14:55:48 +0200 Subject: [PATCH 08/17] Reemove needless code, check for '}0', don't do anything here if not true m=something --- src/frontend/inpcom.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index c871e58e4..ebe3f319b 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -5556,18 +5556,18 @@ static char* eval_m(char* line, char* tline) { double m; char* str_ptr, * m_ptr, * m_str = NULL; char* cut_line = line; - str_ptr = strstr(cut_line, "m="); + str_ptr = strstr(cut_line, " m="); if (str_ptr) { /* We need to have 'm=something */ - if (str_ptr[2]) { - m_ptr = str_ptr + 2; + if (str_ptr[3]) { + m_ptr = str_ptr + 3; int error = 0; m = INPevaluate(&m_ptr, &error, 1); /*We have a value and create the m string */ if (error == 0) { m_str = tprintf("m=%15.8e", m); } - else if (error == 1 && *m_ptr == '{' && m_ptr + 1 && *(m_ptr + 1) != '}') { + else if (error == 1 && *m_ptr == '{' && *(m_ptr + 1) != '\0' && *(m_ptr + 1) != '}') { char* bra = gettok_char(&m_ptr, '}', TRUE, TRUE); if (bra) { m_str = tprintf("m=%s", bra); @@ -5598,18 +5598,18 @@ static char* eval_mvalue(char* line, char* tline) { double m; char* str_ptr, * m_ptr, * m_str = NULL; char* cut_line = line; - str_ptr = strstr(cut_line, "m="); + str_ptr = strstr(cut_line, " m="); if (str_ptr) { /* We need to have 'm=something */ - if (str_ptr[2]) { - m_ptr = str_ptr + 2; + if (str_ptr[3]) { + m_ptr = str_ptr + 3; int error = 0; m = INPevaluate(&m_ptr, &error, 1); /*We have a value and create the m string */ if (error == 0) { m_str = tprintf("%15.8e", m); } - else if (error == 1 && *m_ptr == '{' && m_ptr + 1 && *(m_ptr + 1) != '}') { + else if (error == 1 && *m_ptr == '{' && *(m_ptr + 1) != '\0' && *(m_ptr + 1) != '}') { char* bra = gettok_char(&m_ptr, '}', TRUE, TRUE); if (bra) { m_str = tprintf("%s", bra); From 62b724708725a2cd4d953ce74d104c414038a689 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Sat, 12 Aug 2023 18:11:35 +0100 Subject: [PATCH 09/17] Remove duplicate definition of variable idp, as compiler may warn. --- src/xspice/icm/digital/d_tristate/cfunc.mod | 1 - 1 file changed, 1 deletion(-) diff --git a/src/xspice/icm/digital/d_tristate/cfunc.mod b/src/xspice/icm/digital/d_tristate/cfunc.mod index 8f5d67bd5..1cfe07d3f 100644 --- a/src/xspice/icm/digital/d_tristate/cfunc.mod +++ b/src/xspice/icm/digital/d_tristate/cfunc.mod @@ -184,7 +184,6 @@ void cm_d_tristate(ARGS) enum {Idle, Normal, Same, Revert, Both} d_ctl, s_ctl, ctl1, ctl2; - struct idata *idp; double first_time, second_time; /* Scheduled changes */ double delay_1; /* Delay to first output. */ double cancel_delay; /* Delay to canclling. */ From ddd0effd2759bb0124cd29d8e3c771cf4072c50f Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 12 Aug 2023 23:57:38 +0200 Subject: [PATCH 10/17] Set brackets to remove gcc compiler warning --- src/xspice/evt/evtshared.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xspice/evt/evtshared.c b/src/xspice/evt/evtshared.c index c381195b0..ca3375745 100644 --- a/src/xspice/evt/evtshared.c +++ b/src/xspice/evt/evtshared.c @@ -73,12 +73,13 @@ static void delete_ret(void) { int i; - if (return_all) + if (return_all) { for (i = 0; i < return_all->num_steps; i++) { tfree(return_all->evt_dect[i]->node_value); tfree(return_all->evt_dect[i]); } tfree(return_all); + } } pevt_shared_data From 443298791990f7c9101c14276e6dea7be8d424d0 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 13 Aug 2023 10:01:12 +0200 Subject: [PATCH 11/17] Initialize to remove VS2022 linker warnings --- src/frontend/inpcom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index ebe3f319b..67b1e0fe4 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -2177,8 +2177,8 @@ static int inp_chk_for_multi_in_vcvs(struct card *c, int *line_number) static void replace_freq(struct card *c, int *line_number) { #ifdef XSPICE - char *line, *e, *e_e, *n1, *n1_e, *n2, *n2_e, *freq; - char *expr, *expr_e, *in, *in_e, *keywd, *cp, *list, *list_e; + char *line, *e, *e_e, *n1, *n1_e, *n2, *n2_e=NULL, *freq; + char *expr, *expr_e, *in, *in_e=NULL, *keywd, *cp, *list, *list_e; int db, ri, rad, got_key, diff; char pt, key[4]; From bd85b273494b714cd619cbcf5e56dcfc845a21e5 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 13 Aug 2023 11:04:19 +0200 Subject: [PATCH 12/17] Replace | by ||, bug detected by code analysis --- src/ciderlib/twod/twoproj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ciderlib/twod/twoproj.c b/src/ciderlib/twod/twoproj.c index a2a9c7c1a..1905a1bd3 100644 --- a/src/ciderlib/twod/twoproj.c +++ b/src/ciderlib/twod/twoproj.c @@ -153,7 +153,7 @@ void NBJT2project(TWOdevice *pDevice, double delVce, double delVbe) } } if ( pElem->elemType == SEMICON - && (!OneCarrier | (OneCarrier == P_TYPE)) ) { + && (!OneCarrier || (OneCarrier == P_TYPE)) ) { delP = incVce[ pNode->pEqn ] * delVce; newP = pNode->pConc + delP; if ( newP <= 0.0 ) { From 563aa2917a17f95bf1f43c9c8bb3b43538b45db6 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 13 Aug 2023 11:04:34 +0200 Subject: [PATCH 13/17] Remove unused variable --- src/osdi/osdiload.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/osdi/osdiload.c b/src/osdi/osdiload.c index 6fe4b4f40..b27f1218e 100644 --- a/src/osdi/osdiload.c +++ b/src/osdi/osdiload.c @@ -120,7 +120,6 @@ extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) { GENinstance *gen_inst; bool is_init_smsig = ckt->CKTmode & MODEINITSMSIG; - bool is_sweep = ckt->CKTmode & MODEDCTRANCURVE; bool is_dc = ckt->CKTmode & (MODEDCOP | MODEDCTRANCURVE); bool is_ac = ckt->CKTmode & (MODEAC | MODEINITSMSIG); bool is_tran = ckt->CKTmode & (MODETRAN); From 43c7d5061c62353aa70b4eaad5871b1715f3af12 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 13 Aug 2023 11:30:10 +0200 Subject: [PATCH 14/17] Add missing pwlts cfunc.mod and ifspec.ifs --- visualc/xspice/analog.vcxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/visualc/xspice/analog.vcxproj b/visualc/xspice/analog.vcxproj index fd8097bc4..57074ec99 100644 --- a/visualc/xspice/analog.vcxproj +++ b/visualc/xspice/analog.vcxproj @@ -281,6 +281,8 @@ + + From 9ee9f9262b5ce8d49f92d11a516006687c368f91 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 13 Aug 2023 11:31:01 +0200 Subject: [PATCH 15/17] Prevent buffer overflow, remove unused --- src/xspice/icm/analog/pwlts/cfunc.mod | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/xspice/icm/analog/pwlts/cfunc.mod b/src/xspice/icm/analog/pwlts/cfunc.mod index 45d74b4d6..8aaf26d45 100644 --- a/src/xspice/icm/analog/pwlts/cfunc.mod +++ b/src/xspice/icm/analog/pwlts/cfunc.mod @@ -155,9 +155,6 @@ void cm_pwlts(ARGS) /* structure holding parms, double test1; /* debug testing value */ double test2; /* debug testing value */ double *last_x_value; /* static variable for limiting */ - double test; /* temp storage variable for limit testing */ - - Mif_Complex_t ac_gain; CALLBACK = cm_pwlts_callback; @@ -283,7 +280,7 @@ void cm_pwlts(ARGS) /* structure holding parms, /*** must determine position progressively & then ***/ /*** calculate required output. ***/ - for (i=1; i Date: Mon, 14 Aug 2023 15:38:25 +0200 Subject: [PATCH 16/17] Do not set a breakpoint at current time, as this may lead to trigger a "breakpoint in the past" message and stop the simulation, depending on double precision details during comparison. --- src/spicelib/analysis/cktsetbk.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/spicelib/analysis/cktsetbk.c b/src/spicelib/analysis/cktsetbk.c index 659abcdf5..86f2cd764 100644 --- a/src/spicelib/analysis/cktsetbk.c +++ b/src/spicelib/analysis/cktsetbk.c @@ -27,6 +27,13 @@ CKTsetBreak(CKTcircuit *ckt, double time) printf("[t:%e] \t want breakpoint for t = %e\n", ckt->CKTtime, time); #endif + if (AlmostEqualUlps(time, ckt->CKTtime, 3)) { +#ifdef TRACE_BREAKPOINT // #if (1) + fprintf(stderr, "Warning: Setting a new breakpoint at %e is ignored,\n as current time is %e\n", time, ckt->CKTtime); +#endif + return (OK); + } + if(ckt->CKTtime > time) { SPfrontEnd->IFerrorf (ERR_PANIC, "breakpoint in the past - HELP!"); return(E_INTERN); From ca4ddf6bbcaf4ff54f1f4107d1e7344235998962 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Thu, 17 Aug 2023 17:18:18 +0200 Subject: [PATCH 17/17] Fix bug 642 by replacing strstr() by search_plain_identifier() --- src/frontend/inpcom.c | 82 ++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 67b1e0fe4..f5f1c1e73 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -7963,53 +7963,55 @@ static int inp_vdmos_model(struct card *deck) for (card = deck; card; card = card->nextcard) { - char* curr_line, * cut_line, * token, * new_line; + char* curr_line, * cut_line = NULL, * token, * new_line; wordlist* wl = NULL, * wlb; - curr_line = cut_line = card->line; + curr_line = card->line; - if (ciprefix(".model", curr_line) && strstr(curr_line, "vdmos")) { - cut_line = strstr(curr_line, "vdmos"); - wl_append_word(&wl, &wl, copy_substring(curr_line, cut_line)); - wlb = wl; - if (strstr(cut_line, "pchan")) { - wl_append_word(NULL, &wl, copy("vdmosp (")); - } - else { - wl_append_word(NULL, &wl, copy("vdmosn (")); - } - cut_line = cut_line + 5; + if (ciprefix(".model", curr_line)) { + cut_line = search_plain_identifier(curr_line, "vdmos"); + if (cut_line) { + wl_append_word(&wl, &wl, copy_substring(curr_line, cut_line)); + wlb = wl; + if (strstr(cut_line, "pchan")) { + wl_append_word(NULL, &wl, copy("vdmosp (")); + } + else { + wl_append_word(NULL, &wl, copy("vdmosn (")); + } + cut_line = cut_line + 5; - cut_line = skip_ws(cut_line); - if (*cut_line == '(') - cut_line = cut_line + 1; - new_line = NULL; - while (cut_line && *cut_line) { - token = gettok_model(&cut_line); - if (!ciprefix("pchan", token) && !ciprefix("ron=", token) && - !ciprefix("vds=", token) && !ciprefix("qg=", token) && - !ciprefix("mfg=", token) && !ciprefix("nchan", token)) - wl_append_word(NULL, &wl, token); - else - tfree(token); - if (*cut_line == ')') { - wl_append_word(NULL, &wl, copy(")")); + cut_line = skip_ws(cut_line); + if (*cut_line == '(') + cut_line = cut_line + 1; + new_line = NULL; + while (cut_line && *cut_line) { + token = gettok_model(&cut_line); + if (!ciprefix("pchan", token) && !ciprefix("ron=", token) && + !ciprefix("vds=", token) && !ciprefix("qg=", token) && + !ciprefix("mfg=", token) && !ciprefix("nchan", token)) + wl_append_word(NULL, &wl, token); + else + tfree(token); + if (*cut_line == ')') { + wl_append_word(NULL, &wl, copy(")")); + break; + } + } + new_line = wl_flatten(wlb); + tfree(card->line); + card->line = new_line; + wl_free(wlb); + + /* add model card pointer to list */ + vmodels[j] = card; + j++; + if (j == MODNUMBERS) { + vmodels[j - 1] = NULL; break; } + vmodels[j] = NULL; } - new_line = wl_flatten(wlb); - tfree(card->line); - card->line = new_line; - wl_free(wlb); - - /* add model card pointer to list */ - vmodels[j] = card; - j++; - if (j == MODNUMBERS) { - vmodels[j - 1] = NULL; - break; - } - vmodels[j] = NULL; } }