From f9039ea238d60c7fcaf9fe7b57536abe6c0eb737 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 9 Nov 2022 15:09:52 +0100 Subject: [PATCH 01/16] Don't allocate memory for control array at every time step Use loc instead, setting it up once during INIT --- src/xspice/icm/digital/d_osc/cfunc.mod | 107 ++++++++++++------------ src/xspice/icm/digital/d_osc/ifspec.ifs | 8 +- 2 files changed, 61 insertions(+), 54 deletions(-) diff --git a/src/xspice/icm/digital/d_osc/cfunc.mod b/src/xspice/icm/digital/d_osc/cfunc.mod index c893b888a..2b3b251c3 100644 --- a/src/xspice/icm/digital/d_osc/cfunc.mod +++ b/src/xspice/icm/digital/d_osc/cfunc.mod @@ -19,7 +19,7 @@ MODIFICATIONS 23 Aug 1991 Jeffrey P. Murray 30 Sep 1991 Jeffrey P. Murray - + 09 Nov 2022 Holger Vogt SUMMARY @@ -70,6 +70,10 @@ NON-STANDARD FEATURES /*=== LOCAL VARIABLES & TYPEDEFS =======*/ +typedef struct { + double *x; + double *y; +} Local_Data_t; /*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ @@ -119,6 +123,26 @@ NON-STANDARD FEATURES ==============================================================================*/ +static void cm_d_osc_callback(ARGS, + Mif_Callback_Reason_t reason) +{ + switch (reason) { + case MIF_CB_DESTROY: { + Local_Data_t *loc = STATIC_VAR(locdata); + if (loc) { + if (loc->x) + free(loc->x); + if(loc->y) + free(loc->y); + free(loc); + STATIC_VAR(locdata) = loc = NULL; + } + break; + } /* end of case MIF_CB_DESTROY */ + } /* end of switch over reason being called */ +} /* end of function cm_d_osc_callback */ + + /*=== CM_D_OSC ROUTINE ===*/ /************************************************************* @@ -182,7 +206,8 @@ void cm_d_osc(ARGS) cntl_size, /* control array size */ freq_size; /* frequency array size */ - + Local_Data_t *loc; /* Pointer to local static data, not to be included + in the state vector (save memory!) */ @@ -205,7 +230,6 @@ void cm_d_osc(ARGS) if (INIT) { /*** Test for INIT == TRUE. If so, allocate storage, etc. ***/ - /* Allocate storage for internal variables */ cm_analog_alloc(0, sizeof(double)); cm_analog_alloc(1, sizeof(double)); @@ -218,15 +242,35 @@ void cm_d_osc(ARGS) t3 = (double *) cm_analog_get_ptr(2,0); + /*** allocate static storage for *loc ***/ + STATIC_VAR (locdata) = calloc (1 , sizeof ( Local_Data_t )); + loc = STATIC_VAR (locdata); + CALLBACK = cm_d_osc_callback; + + x = loc->x = (double *) calloc((size_t) cntl_size, sizeof(double)); + if (!x) { + cm_message_send(d_osc_allocation_error); + return; + } + y = loc->y = (double *) calloc((size_t) cntl_size, sizeof(double)); + if (!y) { + cm_message_send(d_osc_allocation_error); + if(x) + free(x); + return; + } + /* Retrieve x and y values. */ + for (i=0; ix; + y = loc->y; /* Retrieve cntl_input value. */ cntl_input = INPUT(cntl_in); @@ -357,9 +377,7 @@ void cm_d_osc(ARGS) if(TIME < *t3) { cm_event_queue(*t3); - } - - + } } else @@ -373,7 +391,6 @@ void cm_d_osc(ARGS) if(TIME < *t1) { cm_event_queue(*t1); - } } else { @@ -388,23 +405,13 @@ void cm_d_osc(ARGS) } *t3 = T(1) + (1 - dphase)/freq; - - } - - - - if(x) free(x); - if(y) free(y); - - } break; case EVENT: /** discrete call...lots to do **/ - test_double = TIME; if ( 0.0 == TIME ) { /* DC analysis...preset values, @@ -426,21 +433,16 @@ void cm_d_osc(ARGS) *t3 = -1; } - - /* Calculate the time variables and the output value for this iteration */ /* Output is always set to STRONG */ OUTPUT_STRENGTH(out) = STRONG; - - if( *t1 == TIME ) { /* rising edge */ OUTPUT_STATE(out) = ONE; OUTPUT_DELAY(out) = PARAM(rise_delay); - } else { @@ -466,7 +468,6 @@ void cm_d_osc(ARGS) } break; - } } diff --git a/src/xspice/icm/digital/d_osc/ifspec.ifs b/src/xspice/icm/digital/d_osc/ifspec.ifs index 8d9e56164..9c65bb89a 100644 --- a/src/xspice/icm/digital/d_osc/ifspec.ifs +++ b/src/xspice/icm/digital/d_osc/ifspec.ifs @@ -9,7 +9,7 @@ Atlanta, Georgia 30332 AUTHORS 30 Sept 1991 Jeffrey P. Murray - + 09 Nov 2022 Holger Vogt SUMMARY @@ -73,3 +73,9 @@ Vector: no no Vector_Bounds: - - Null_Allowed: yes yes + +STATIC_VAR_TABLE: + +Static_Var_Name: locdata +Description: "local static data" +Data_Type: pointer From 0d86539638dbb9ee29fd5825ee97a32457fb13c4 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 9 Nov 2022 15:11:13 +0100 Subject: [PATCH 02/16] Trim trailing spaces --- src/xspice/icm/digital/d_osc/cfunc.mod | 180 ++++++++++++------------ src/xspice/icm/digital/d_osc/ifspec.ifs | 18 +-- 2 files changed, 99 insertions(+), 99 deletions(-) diff --git a/src/xspice/icm/digital/d_osc/cfunc.mod b/src/xspice/icm/digital/d_osc/cfunc.mod index 2b3b251c3..b76386132 100644 --- a/src/xspice/icm/digital/d_osc/cfunc.mod +++ b/src/xspice/icm/digital/d_osc/cfunc.mod @@ -8,14 +8,14 @@ Public Domain Georgia Tech Research Corporation Atlanta, Georgia 30332 PROJECT A-8503-405 - -AUTHORS + +AUTHORS 24 Jul 1991 Jeffrey P. Murray -MODIFICATIONS +MODIFICATIONS 23 Aug 1991 Jeffrey P. Murray 30 Sep 1991 Jeffrey P. Murray @@ -27,12 +27,12 @@ SUMMARY functionally describe the d_osc code model. -INTERFACES +INTERFACES - FILE ROUTINE CALLED + FILE ROUTINE CALLED + + CMmacros.h cm_message_send(); - CMmacros.h cm_message_send(); - CM.c void *cm_analog_alloc() void *cm_analog_get_ptr() @@ -42,7 +42,7 @@ INTERFACES REFERENCED FILES Inputs from and outputs to ARGS structure. - + NON-STANDARD FEATURES @@ -55,7 +55,7 @@ NON-STANDARD FEATURES #include "d_osc.h" /* ...contains macros & type defns. for this model. 7/24/91 - JPM */ - + /*=== CONSTANTS ========================*/ @@ -66,31 +66,31 @@ NON-STANDARD FEATURES - -/*=== LOCAL VARIABLES & TYPEDEFS =======*/ + +/*=== LOCAL VARIABLES & TYPEDEFS =======*/ typedef struct { double *x; double *y; } Local_Data_t; - - + + /*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ - + /*============================================================================== FUNCTION cm_d_osc() -AUTHORS +AUTHORS 24 Jul 1991 Jeffrey P. Murray -MODIFICATIONS +MODIFICATIONS 30 Sep 1991 Jeffrey P. Murray @@ -98,23 +98,23 @@ SUMMARY This function implements the d_osc code model. -INTERFACES +INTERFACES - FILE ROUTINE CALLED + FILE ROUTINE CALLED + + CMmacros.h cm_message_send(); - CMmacros.h cm_message_send(); - CM.c void *cm_analog_alloc() void *cm_analog_get_ptr() CMevt.c void cm_event_queue() RETURNED VALUE - + Returns inputs and outputs via ARGS structure. GLOBAL VARIABLES - + NONE NON-STANDARD FEATURES @@ -165,7 +165,7 @@ static void cm_d_osc_callback(ARGS, * I | | | | * * I | | * * I | | | | * -* I-----------------*-----* - - - - - - - - - -*--------- * +* I-----------------*-----* - - - - - - - - - -*--------- * * t1 t4 * * * * * @@ -182,7 +182,7 @@ static void cm_d_osc_callback(ARGS, #include -void cm_d_osc(ARGS) +void cm_d_osc(ARGS) { double *x, /* analog input value control array */ @@ -190,11 +190,11 @@ void cm_d_osc(ARGS) cntl_input, /* control input value */ *phase, /* instantaneous phase of the model */ *phase_old, /* previous phase of the model */ - *t1, /* pointer to t1 value */ - *t3, /* pointer to t3 value */ - /*time1,*/ /* variable for calculating new time1 value */ - /*time3,*/ /* variable for calculating new time3 value */ - freq = 0.0, /* instantaneous frequency value */ + *t1, /* pointer to t1 value */ + *t3, /* pointer to t3 value */ + /*time1,*/ /* variable for calculating new time1 value */ + /*time3,*/ /* variable for calculating new time3 value */ + freq = 0.0, /* instantaneous frequency value */ dphase, /* fractional part into cycle */ duty_cycle, /* duty_cycle value */ test_double, /* testing variable */ @@ -205,17 +205,17 @@ void cm_d_osc(ARGS) int i, /* generic loop counter index */ cntl_size, /* control array size */ freq_size; /* frequency array size */ - + Local_Data_t *loc; /* Pointer to local static data, not to be included - in the state vector (save memory!) */ + in the state vector (save memory!) */ /**** Retrieve frequently used parameters... ****/ - cntl_size = PARAM_SIZE(cntl_array); - freq_size = PARAM_SIZE(freq_array); + cntl_size = PARAM_SIZE(cntl_array); + freq_size = PARAM_SIZE(freq_array); duty_cycle = PARAM(duty_cycle); @@ -227,7 +227,7 @@ void cm_d_osc(ARGS) return; } - + if (INIT) { /*** Test for INIT == TRUE. If so, allocate storage, etc. ***/ /* Allocate storage for internal variables */ @@ -239,7 +239,7 @@ void cm_d_osc(ARGS) phase = phase_old = (double *) cm_analog_get_ptr(0,0); t1 = (double *) cm_analog_get_ptr(1,0); - + t3 = (double *) cm_analog_get_ptr(2,0); /*** allocate static storage for *loc ***/ @@ -276,20 +276,20 @@ void cm_d_osc(ARGS) phase_old = (double *) cm_analog_get_ptr(0,1); t1 = (double *) cm_analog_get_ptr(1,0); - + t3 = (double *) cm_analog_get_ptr(2,0); } switch (CALL_TYPE) { case ANALOG: /** analog call **/ - - test_double = TIME; - if ( AC == ANALYSIS ) { /* this model does not function + test_double = TIME; + + if ( AC == ANALYSIS ) { /* this model does not function in AC analysis mode. */ - - return; + + return; } else { @@ -299,26 +299,26 @@ void cm_d_osc(ARGS) *phase = PARAM(init_phase); if ( 0 > *phase ) { *phase = *phase + 360.0; - } + } *phase = *phase / 360.0; /* set phase value to init_phase */ *phase_old = *phase; - + /* preset time values to harmless values... */ *t1 = -1; - *t3 = -1; + *t3 = -1; } loc = STATIC_VAR (locdata); x = loc->x; - y = loc->y; - - /* Retrieve cntl_input value. */ + y = loc->y; + + /* Retrieve cntl_input value. */ cntl_input = INPUT(cntl_in); - + /* Determine segment boundaries within which cntl_input resides */ /*** cntl_input below lowest cntl_voltage ***/ if (cntl_input <= x[0]) { @@ -327,59 +327,59 @@ void cm_d_osc(ARGS) freq = y[0] + (cntl_input - x[0]) * slope; } - else + else /*** cntl_input above highest cntl_voltage ***/ - - if (cntl_input >= x[cntl_size-1]) { + + if (cntl_input >= x[cntl_size-1]) { slope = (y[cntl_size-1] - y[cntl_size-2]) / (x[cntl_size-1] - x[cntl_size-2]); freq = y[cntl_size-1] + (cntl_input - x[cntl_size-1]) * slope; - - } - else { /*** cntl_input within bounds of end midpoints... - must determine position progressively & then + + } + else { /*** cntl_input within bounds of end midpoints... + must determine position progressively & then calculate required output. ***/ - + for (i=0; i= x[i]) ) { - + + if ( (cntl_input < x[i+1]) && (cntl_input >= x[i]) ) { + /* Interpolate to the correct frequency value */ - - freq = ( (cntl_input - x[i]) / (x[i+1] - x[i]) ) * - ( y[i+1]-y[i] ) + y[i]; - } + + freq = ( (cntl_input - x[i]) / (x[i+1] - x[i]) ) * + ( y[i+1]-y[i] ) + y[i]; + } } } - + /*** If freq < 0.0, clamp to 1e-16 & issue a warning ***/ if ( 0.0 > freq ) { freq = 1.0e-16; - cm_message_send(d_osc_negative_freq_error); + cm_message_send(d_osc_negative_freq_error); } /* calculate the instantaneous phase */ *phase = *phase_old + freq * (TIME - T(1)); - + /* dphase is the percent into the cycle for - the period */ + the period */ dphase = *phase_old - floor(*phase_old); /* Calculate the time variables and the output value - for this iteration */ - + for this iteration */ + if((*t1 <= TIME) && (TIME <= *t3)) { /* output high */ *t3 = T(1) + (1 - dphase)/freq; - + if(TIME < *t3) { cm_event_queue(*t3); - } - } - else + } + } + else if((*t3 <= TIME) && (TIME <= *t1)) { /* output low */ @@ -387,12 +387,12 @@ void cm_d_osc(ARGS) dphase = dphase - 1.0; } *t1 = T(1) + ( (1.0 - duty_cycle) - dphase)/freq; - + if(TIME < *t1) { cm_event_queue(*t1); } - } + } else { if(dphase > (1.0 - duty_cycle) ) { @@ -408,48 +408,48 @@ void cm_d_osc(ARGS) } } break; - + case EVENT: /** discrete call...lots to do **/ - test_double = TIME; + test_double = TIME; - if ( 0.0 == TIME ) { /* DC analysis...preset values, + if ( 0.0 == TIME ) { /* DC analysis...preset values, as appropriate.... */ /* retrieve & normalize phase value */ *phase = PARAM(init_phase); if ( 0 > *phase ) { *phase = *phase + 360.0; - } + } *phase = *phase / 360.0; /* set phase value to init_phase */ *phase_old = *phase; - + /* preset time values to harmless values... */ *t1 = -1; *t3 = -1; } /* Calculate the time variables and the output value - for this iteration */ - + for this iteration */ + /* Output is always set to STRONG */ - OUTPUT_STRENGTH(out) = STRONG; + OUTPUT_STRENGTH(out) = STRONG; if( *t1 == TIME ) { /* rising edge */ - OUTPUT_STATE(out) = ONE; - OUTPUT_DELAY(out) = PARAM(rise_delay); + OUTPUT_STATE(out) = ONE; + OUTPUT_DELAY(out) = PARAM(rise_delay); } else { if ( *t3 == TIME ) { /* falling edge */ - OUTPUT_STATE(out) = ZERO; - OUTPUT_DELAY(out) = PARAM(fall_delay); + OUTPUT_STATE(out) = ZERO; + OUTPUT_DELAY(out) = PARAM(fall_delay); } else { /* no change in output */ @@ -459,17 +459,17 @@ void cm_d_osc(ARGS) } if ( (*t1 < TIME) && (TIME < *t3) ) { - OUTPUT_STATE(out) = ONE; + OUTPUT_STATE(out) = ONE; } else { - OUTPUT_STATE(out) = ZERO; + OUTPUT_STATE(out) = ZERO; } } } break; } -} +} diff --git a/src/xspice/icm/digital/d_osc/ifspec.ifs b/src/xspice/icm/digital/d_osc/ifspec.ifs index 9c65bb89a..d28b93014 100644 --- a/src/xspice/icm/digital/d_osc/ifspec.ifs +++ b/src/xspice/icm/digital/d_osc/ifspec.ifs @@ -6,14 +6,14 @@ Georgia Tech Research Corporation Atlanta, Georgia 30332 -AUTHORS +AUTHORS 30 Sept 1991 Jeffrey P. Murray 09 Nov 2022 Holger Vogt SUMMARY - This file contains the interface specification file for the + This file contains the interface specification file for the hybrid d_osc code model. ===============================================================================*/ @@ -40,14 +40,14 @@ Null_Allowed: no no PARAMETER_TABLE: -Parameter_Name: cntl_array freq_array +Parameter_Name: cntl_array freq_array Description: "control array" "frequency array" Data_Type: real real -Default_Value: 0.0 1.0e6 -Limits: - [0 -] +Default_Value: 0.0 1.0e6 +Limits: - [0 -] Vector: yes yes -Vector_Bounds: [2 -] [2 -] -Null_Allowed: no no +Vector_Bounds: [2 -] [2 -] +Null_Allowed: no no PARAMETER_TABLE: @@ -59,7 +59,7 @@ Default_Value: 0.5 0 Limits: [1e-6 0.999999] [-180.0 +360.0] Vector: no no Vector_Bounds: - - -Null_Allowed: yes yes +Null_Allowed: yes yes PARAMETER_TABLE: @@ -71,7 +71,7 @@ Default_Value: 1e-9 1e-9 Limits: [0 -] [0 -] Vector: no no Vector_Bounds: - - -Null_Allowed: yes yes +Null_Allowed: yes yes STATIC_VAR_TABLE: From 5adef0cf36e8507470a3fc25a8cd78e0c0a2dfd5 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 11 Nov 2022 11:50:53 +0100 Subject: [PATCH 03/16] AlmostEqualUlps setting has been too strict: it failed in MINGW gcc. 3 --> 10 --- src/spicelib/parser/ptfuncs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spicelib/parser/ptfuncs.c b/src/spicelib/parser/ptfuncs.c index 6abfff6d2..c084350d8 100644 --- a/src/spicelib/parser/ptfuncs.c +++ b/src/spicelib/parser/ptfuncs.c @@ -77,8 +77,8 @@ PTpower(double arg1, double arg2) else { /* If arg2 is quasi an integer, round it to have pow not fail when arg1 is negative. Takes into account the double - representation which sometimes differs in the last digit. */ - if (AlmostEqualUlps(trunc(arg2), arg2, 3)) + representation which sometimes differs in the last digit(s). */ + if (AlmostEqualUlps(trunc(arg2), arg2, 10)) res = pow(arg1, round(arg2)); else /* As per LTSPICE specification for ** */ From d6650e66f09443bb8187b8d2d0ecb52d2e59b5f3 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 11 Nov 2022 13:21:21 +0100 Subject: [PATCH 04/16] To find the nearest integer, use nearbyint(). trunc() has delivered only one-sided answers. --- src/spicelib/parser/ptfuncs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spicelib/parser/ptfuncs.c b/src/spicelib/parser/ptfuncs.c index c084350d8..8f1dc3760 100644 --- a/src/spicelib/parser/ptfuncs.c +++ b/src/spicelib/parser/ptfuncs.c @@ -78,7 +78,7 @@ PTpower(double arg1, double arg2) /* If arg2 is quasi an integer, round it to have pow not fail when arg1 is negative. Takes into account the double representation which sometimes differs in the last digit(s). */ - if (AlmostEqualUlps(trunc(arg2), arg2, 10)) + if (AlmostEqualUlps(nearbyint(arg2), arg2, 10)) res = pow(arg1, round(arg2)); else /* As per LTSPICE specification for ** */ From 539176bf153da239bf21d2842535b543d72613f4 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 11 Nov 2022 13:41:10 +0100 Subject: [PATCH 05/16] remove unused --- src/spicelib/parser/inpptree.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/spicelib/parser/inpptree.c b/src/spicelib/parser/inpptree.c index ea9cb3cac..ca870cffb 100644 --- a/src/spicelib/parser/inpptree.c +++ b/src/spicelib/parser/inpptree.c @@ -158,7 +158,6 @@ static struct func { { "floor", PTF_FLOOR, (void(*)(void)) PTfloor } , { "nint", PTF_NINT, (void(*)(void)) PTnint } , { "-", PTF_UMINUS, (void(*)(void)) PTuminus }, - /* MW. cif function added */ { "u2", PTF_USTEP2, (void(*)(void)) PTustep2}, { "pwl", PTF_PWL, (void(*)(void)) PTpwl}, { "pwl_derivative", PTF_PWL_DERIVATIVE, (void(*)(void)) PTpwl_derivative}, @@ -545,8 +544,6 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum) arg1 = mkcon(0.0); break; - - /* MW. PTF_CIF for new cif function */ case PTF_USTEP2: /* ustep2=uramp(x)-uramp(x-1) ustep2'=ustep(x)-ustep(x-1) */ arg1 = mkb(PT_MINUS, mkf(PTF_USTEP, p->left), From 574737b7b6d4e35fb5d1a0a1d2a8580d4ddd68c0 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Mon, 7 Nov 2022 13:47:45 -0800 Subject: [PATCH 06/16] Check that the bparse gen_tab optimization loop finishes when no more improvements occur. --- src/frontend/logicexp.c | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index 4b4522b17..a0601dc50 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -382,6 +382,7 @@ typedef struct parse_table *PTABLE; struct parse_table { TLINE first; TLINE last; + int num_entries; }; static PTABLE parse_tab = NULL; @@ -392,6 +393,7 @@ static PTABLE new_parse_table(void) PTABLE pt; pt = TMALLOC(struct parse_table, 1); pt->first = pt->last = NULL; + pt->num_entries = 0; return pt; } @@ -462,6 +464,7 @@ static TLINE add_to_parse_table(PTABLE pt, char *line, BOOL ignore_blank) pt->last->next = t; pt->last = t; } + pt->num_entries++; return t; } @@ -1292,6 +1295,10 @@ static BOOL bparse(char *line, BOOL new_lexer) lookahead = lex_scan(); // ':' lookahead = lex_scan(); while (lookahead != '\0') { +#define LOOP_OPT +#ifdef LOOP_OPT + int last_count = 0, curr_count = 0; +#endif init_parse_tables(); adepth = max_adepth = 0; stmt_num++; @@ -1303,6 +1310,41 @@ static BOOL bparse(char *line, BOOL new_lexer) /* generate gates only when optimizations are successful */ opt_tab1 = optimize_gen_tab(gen_tab); +#ifdef LOOP_OPT + last_count = gen_tab->num_entries; + if (opt_tab1) { + int loop_count = 0; + curr_count = opt_tab1->num_entries; +#ifdef TRACE +printf("Start opt last_count %d curr_count %d\n", last_count, curr_count); +#endif + opt_tab2 = opt_tab1; + while (curr_count > 1 && curr_count < last_count) { + loop_count++; + last_count = curr_count; + opt_tab2 = optimize_gen_tab(opt_tab1); + delete_parse_table(opt_tab1); + if (!opt_tab2) { + ret_val = FALSE; + break; + } + opt_tab1 = opt_tab2; + curr_count = opt_tab2->num_entries; +#ifdef TRACE +printf("Next(%d) opt last_count %d curr_count %d\n", loop_count, last_count, curr_count); +#endif + } +#ifdef TRACE +printf("Finish opt last_count %d curr_count %d\n", last_count, curr_count); +#endif + if (opt_tab2) { + gen_gates(opt_tab2, lx->lexer_sym_tab); + delete_parse_table(opt_tab2); + } + } else { + ret_val = FALSE; + } +#else if (opt_tab1) { opt_tab2 = optimize_gen_tab(opt_tab1); if (opt_tab2) { @@ -1313,6 +1355,7 @@ static BOOL bparse(char *line, BOOL new_lexer) } delete_parse_table(opt_tab1); delete_parse_table(opt_tab2); +#endif delete_parse_gen_tables(); if (!ret_val) { break; From a922f797d35ed337c2ea2994d2eeb75ea25459d6 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Tue, 8 Nov 2022 04:42:04 -0800 Subject: [PATCH 07/16] When the gen_tab has only one entry, do not call optimize_gen_tab, it is not necessary. --- src/frontend/logicexp.c | 71 +++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 46 deletions(-) diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index a0601dc50..770ca0945 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -382,7 +382,7 @@ typedef struct parse_table *PTABLE; struct parse_table { TLINE first; TLINE last; - int num_entries; + unsigned int num_entries; }; static PTABLE parse_tab = NULL; @@ -1295,10 +1295,7 @@ static BOOL bparse(char *line, BOOL new_lexer) lookahead = lex_scan(); // ':' lookahead = lex_scan(); while (lookahead != '\0') { -#define LOOP_OPT -#ifdef LOOP_OPT - int last_count = 0, curr_count = 0; -#endif + unsigned int last_count = 0, curr_count = 0; init_parse_tables(); adepth = max_adepth = 0; stmt_num++; @@ -1309,53 +1306,35 @@ static BOOL bparse(char *line, BOOL new_lexer) beval_order(); /* generate gates only when optimizations are successful */ - opt_tab1 = optimize_gen_tab(gen_tab); -#ifdef LOOP_OPT last_count = gen_tab->num_entries; - if (opt_tab1) { - int loop_count = 0; - curr_count = opt_tab1->num_entries; -#ifdef TRACE -printf("Start opt last_count %d curr_count %d\n", last_count, curr_count); -#endif - opt_tab2 = opt_tab1; - while (curr_count > 1 && curr_count < last_count) { - loop_count++; - last_count = curr_count; - opt_tab2 = optimize_gen_tab(opt_tab1); - delete_parse_table(opt_tab1); - if (!opt_tab2) { - ret_val = FALSE; - break; + if (last_count == 1) { + gen_gates(gen_tab, lx->lexer_sym_tab); + } else if (last_count > 1) { + opt_tab1 = optimize_gen_tab(gen_tab); + if (opt_tab1) { + curr_count = opt_tab1->num_entries; + opt_tab2 = opt_tab1; + while (curr_count > 1 && curr_count < last_count) { + last_count = curr_count; + opt_tab2 = optimize_gen_tab(opt_tab1); + delete_parse_table(opt_tab1); + if (!opt_tab2) { + ret_val = FALSE; + break; + } + opt_tab1 = opt_tab2; + curr_count = opt_tab2->num_entries; } - opt_tab1 = opt_tab2; - curr_count = opt_tab2->num_entries; -#ifdef TRACE -printf("Next(%d) opt last_count %d curr_count %d\n", loop_count, last_count, curr_count); -#endif - } -#ifdef TRACE -printf("Finish opt last_count %d curr_count %d\n", last_count, curr_count); -#endif - if (opt_tab2) { - gen_gates(opt_tab2, lx->lexer_sym_tab); - delete_parse_table(opt_tab2); + if (opt_tab2) { + gen_gates(opt_tab2, lx->lexer_sym_tab); + delete_parse_table(opt_tab2); + } + } else { + ret_val = FALSE; } } else { ret_val = FALSE; } -#else - if (opt_tab1) { - opt_tab2 = optimize_gen_tab(opt_tab1); - if (opt_tab2) { - gen_gates(opt_tab2, lx->lexer_sym_tab); - } - } else { - ret_val = FALSE; - } - delete_parse_table(opt_tab1); - delete_parse_table(opt_tab2); -#endif delete_parse_gen_tables(); if (!ret_val) { break; From b0e9874de8d8fb77f3b225435f9400ac1bc7c913 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Tue, 8 Nov 2022 12:09:13 -0800 Subject: [PATCH 08/16] Add more vectors to behavioral 283 circuit. Add tristate buffer circuit which shows glitches until inertial delays are implemented. --- examples/p-to-n-examples/behav-283-1.cir | 91 +++++++++++++++++++ examples/p-to-n-examples/behav-283-1.stim | 39 ++++++++ .../p-to-n-examples/behav-tristate-pulse.cir | 82 +++++++++++++++++ .../p-to-n-examples/behav-tristate-pulse.stim | 30 ++++++ src/frontend/logicexp.c | 10 +- 5 files changed, 248 insertions(+), 4 deletions(-) create mode 100644 examples/p-to-n-examples/behav-283-1.cir create mode 100644 examples/p-to-n-examples/behav-283-1.stim create mode 100644 examples/p-to-n-examples/behav-tristate-pulse.cir create mode 100644 examples/p-to-n-examples/behav-tristate-pulse.stim diff --git a/examples/p-to-n-examples/behav-283-1.cir b/examples/p-to-n-examples/behav-283-1.cir new file mode 100644 index 000000000..7618f70bd --- /dev/null +++ b/examples/p-to-n-examples/behav-283-1.cir @@ -0,0 +1,91 @@ +Behavioral CMOS 283 : 4-bit adder with behav-283-1.stim + +*-------------------------------------------------------------74AC283----- +* +* The 74AC283 4-Bit Binary Full Adder with Fast Carry +* (4 Page Fax) Harris Advanced CMOS Logic, File Number 1912 +* and Philips Semiconductors High-speed CMOS Logic Data Handbook +* for the logic diagram, 1994, page 564 +* jat 7/26/95 + +.SUBCKT 74AC283 ++ A0 A1 A2 A3 B0 B1 B2 B3 CIN COUT S0 S1 S2 S3 ++ OPTIONAL: DPWR=$G_DPWR DGND=$G_DGND ++ PARAMS: MNTYMXDLY=0 IO_LEVEL=0 + +U1 LOGICEXP(9,5) DPWR DGND ++ A0 A1 A2 A3 B0 B1 B2 B3 CIN ++ S_0 S_1 S_2 S_3 C_OUT ++ D0_GATE IO_AC ++ MNTYMXDLY={MNTYMXDLY} IO_LEVEL={IO_LEVEL} ++ LOGIC: ++ S_0 = {A0 ^ B0 ^ CIN} ++ NOR1 = {(A0 | B0) & (CIN | (A0 & B0))} ++ S_1 = {NOR1 ^ A1 ^ B1} ++ NOR2 = {~((~(A1 | B1)) | ((~(A0 | B0)) & (~(A1 & B1))) | ++ ((~(A1 & B1)) & (~(A0 & B0)) & (~CIN)))} ++ S_2 = {NOR2 ^ A2 ^ B2} ++ AND31 = {(~(A2 & B2)) & (~(A1 & B1)) & (~(A0 & B0)) & (~CIN)} ++ AND32 = {(~(A0 | B0)) & (~(A2 & B2)) & (~(A1 & B1))} ++ AND33 = {(~(A1 | B1)) & (~(A2 & B2))} ++ NOR3 = {~(AND31 | AND32 | AND33 | (~(A2 | B2)))} ++ S_3 = {NOR3 ^ A3 ^ B3} ++ ANDC1 = {(~(A3 & B3)) & (~(A2 & B2)) & (~(A1 & B1)) & ++ (~(A0 & B0)) & (~CIN)} ++ ANDC2 = {(~(A0 | B0)) & (~(A3 & B3)) & (~(A2 & B2)) & (~(A1 & B1))} ++ ANDC3 = {(~(A1 | B1)) & (~(A3 & B3)) & (~(A2 & B2))} ++ ANDC4 = {(~(A2 | B2)) & (~(A3 & B3))} ++ C_OUT = {~(ANDC1 | ANDC2 | ANDC3 | ANDC4 | (~(A3 | B3)))} + +U2 PINDLY(5,0,9) DPWR DGND ++ S_0 S_1 S_2 S_3 C_OUT ++ A0 A1 A2 A3 B0 B1 B2 B3 CIN ++ S0 S1 S2 S3 COUT ++ IO_AC ++ MNTYMXDLY={MNTYMXDLY} IO_LEVEL={IO_LEVEL} ++ BOOLEAN: ++ CARRYIN = {CHANGED(CIN,0)} ++ NUMBER = {CHANGED(A0,0) | CHANGED(A1,0) | CHANGED(A2,0) | ++ CHANGED(A3,0) | CHANGED(B0,0) | CHANGED(B1,0) | ++ CHANGED(B2,0) | CHANGED(B3,0)} ++ PINDLY: ++ S0 S1 S2 S3 = { ++ CASE( ++ NUMBER & (TRN_LH | TRN_HL), DELAY(4.7NS,-1,16.5NS), ++ CARRYIN & (TRN_LH | TRN_HL), DELAY(4.5NS,-1,16NS), ++ DELAY(5.7NS,-1,17.5NS))} ++ COUT = { ++ CASE( ++ NUMBER & (TRN_LH | TRN_HL), DELAY(4.5NS,-1,16NS), ++ CARRYIN & (TRN_LH | TRN_HL), DELAY(4.5NS,-1,16NS), ++ DELAY(5.7NS,-1,17.5NS))} + +.ENDS 74AC283 + +X1 a0 a1 a2 a3 b0 b1 b2 b3 cin cout s0 s1 s2 s3 74ac283 +a_1 [ a3 a2 a1 a0 b3 b2 b1 b0 cin ] input_vec1 +.model input_vec1 d_source(input_file = "behav-283-1.stim") + +.tran 0.01ns 4us +.control +run +listing +edisplay +eprint a3 a2 a1 a0 b3 b2 b1 b0 cin +eprint s3 s2 s1 s0 cout +* save data to input directory +cd $inputdir +eprvcd a3 a2 a1 a0 b3 b2 b1 b0 cin s3 s2 s1 s0 cout > behav-283-1.vcd +* plotting the vcd file with GTKWave +if $oscompiled = 1 | $oscompiled = 8 ; MS Windows + shell start gtkwave behav-283-1.vcd --script nggtk.tcl +else + if $oscompiled = 7 ; macOS, manual tweaking required (mark, insert, Zoom Fit) + shell open -a gtkwave behav-283-1.vcd + else ; Linux and others + shell gtkwave behav-283-1.vcd --script nggtk.tcl & + end +end +quit +.endc +.end diff --git a/examples/p-to-n-examples/behav-283-1.stim b/examples/p-to-n-examples/behav-283-1.stim new file mode 100644 index 000000000..2ab1bdea6 --- /dev/null +++ b/examples/p-to-n-examples/behav-283-1.stim @@ -0,0 +1,39 @@ +* T a a a a b b b b c +* i 0 1 2 3 0 1 2 3 i +* m n +* e + +0ns 0s 0s 0s 0s 0s 0s 0s 0s 0s +100ns 0s 0s 0s 1s 0s 0s 0s 1s 0s +200ns 0s 0s 1s 0s 0s 0s 1s 0s 0s +300ns 0s 0s 1s 1s 0s 0s 1s 1s 0s +400ns 0s 1s 0s 0s 0s 1s 0s 0s 0s +500ns 0s 1s 0s 1s 0s 1s 0s 1s 0s +600ns 0s 1s 1s 0s 0s 1s 1s 0s 0s +700ns 0s 1s 1s 1s 0s 1s 1s 1s 0s +800ns 1s 0s 0s 0s 1s 0s 0s 0s 0s +900ns 1s 0s 0s 1s 1s 0s 0s 1s 0s +1.0us 1s 0s 1s 0s 1s 0s 1s 0s 0s +1.1us 1s 0s 1s 1s 1s 0s 1s 1s 0s +1.2us 1s 1s 0s 0s 1s 1s 0s 0s 0s +1.3us 1s 1s 0s 1s 1s 1s 0s 1s 0s +1.4us 1s 1s 1s 0s 1s 1s 1s 0s 0s +1.5us 1s 1s 1s 1s 1s 1s 1s 1s 0s +1.6us 0s 0s 0s 0s 0s 0s 0s 0s 0s +1.7us 0s 0s 0s 0s 0s 0s 0s 0s 1s +1.8us 0s 0s 0s 1s 0s 0s 0s 1s 1s +1.9us 0s 0s 1s 0s 0s 0s 1s 0s 1s +2.0us 0s 0s 1s 1s 0s 0s 1s 1s 1s +2.1us 0s 1s 0s 0s 0s 1s 0s 0s 1s +2.2us 0s 1s 0s 1s 0s 1s 0s 1s 1s +2.3us 0s 1s 1s 0s 0s 1s 1s 0s 1s +2.4us 0s 1s 1s 1s 0s 1s 1s 1s 1s +2.5us 1s 0s 0s 0s 1s 0s 0s 0s 1s +2.6us 1s 0s 0s 1s 1s 0s 0s 1s 1s +2.7us 1s 0s 1s 0s 1s 0s 1s 0s 1s +2.8us 1s 0s 1s 1s 1s 0s 1s 1s 1s +2.9us 1s 1s 0s 0s 1s 1s 0s 0s 1s +3.0us 1s 1s 0s 1s 1s 1s 0s 1s 1s +3.1us 1s 1s 1s 0s 1s 1s 1s 0s 1s +3.2us 1s 1s 1s 1s 1s 1s 1s 1s 1s +3.3us 0s 0s 0s 0s 0s 0s 0s 0s 1s diff --git a/examples/p-to-n-examples/behav-tristate-pulse.cir b/examples/p-to-n-examples/behav-tristate-pulse.cir new file mode 100644 index 000000000..3d08f6fd7 --- /dev/null +++ b/examples/p-to-n-examples/behav-tristate-pulse.cir @@ -0,0 +1,82 @@ +Test behav-tristate.cir + +* -----------------------------------------------------------74HCT125------ +*** This is not quad +* Quad Buffer/Line Driver; Tri-State +* Philips High Speed CMOS Logic Family, 1994, pages 243 to 247 +* jat 9/4/96 + +.SUBCKT 74HCT125 1A 1Y 1OEBAR ++ OPTIONAL: DPWR=$G_DPWR DGND=$G_DGND ++ PARAMS: MNTYMXDLY=0 IO_LEVEL=0 + +U1 PINDLY(1,1,0) DPWR DGND ++ 1A ++ 1OEBAR ++ 1Y ++ IO_HCT MNTYMXDLY={MNTYMXDLY} IO_LEVEL={IO_LEVEL} ++ TRISTATE: ++ ENABLE LO = 1OEBAR ++ 1Y = { ++ CASE( ++ TRN_Z$,DELAY(-1,15NS,28NS), ++ TRN_$Z, DELAY(-1,15NS,25NS), ++ (TRN_LH | TRN_HL), DELAY(-1,15NS,25NS), ++ DELAY(-1,16NS,29NS))} + +.ENDS 74HCT125 +* -----------------------------------------------------------74HC126A------ +*** This is not quad +* Quad Tri-State Noninverting Buffers +* Motorola High-Speed CMOS Data, 1993, pages 5-106 to 5-109 +* jat 9/4/96 + +.SUBCKT 74HC126A A1 Y1 OE1 ++ OPTIONAL: DPWR=$G_DPWR DGND=$G_DGND ++ PARAMS: MNTYMXDLY=0 IO_LEVEL=0 + +U1 PINDLY(1,1,0) DPWR DGND ++ A1 ++ OE1 ++ Y1 ++ IO_HC MNTYMXDLY={MNTYMXDLY} IO_LEVEL={IO_LEVEL} ++ TRISTATE: ++ ENABLE HI = OE1 ++ Y1 = { ++ CASE( ++ TRN_Z$,DELAY(-1,-1,18NS), ++ TRN_$Z, DELAY(-1,-1,24NS), ++ (TRN_LH | TRN_HL), DELAY(-1,-1,18NS), ++ DELAY(-1,-1,25NS))} + +.ENDS 74HC126A + +* .SUBCKT 74HCT125 1A 1Y 1OEBAR +x1 1a 1y oebar 74hct125 +* .SUBCKT 74HC126A A1 Y1 OE1 +x2 a1 y1 oe 74hc126a +a_1 [ 1a oebar a1 oe ] input_vec1 +.model input_vec1 d_source(input_file = "behav-tristate-pulse.stim") + +.tran 0.01ns 1us +.control +run +listing +edisplay +eprint 1a oebar 1y a1 oe y1 +* save data to input directory +cd $inputdir +eprvcd 1a 1y oebar a1 y1 oe > behav-tristate-pulse.vcd +* plotting the vcd file with GTKWave +if $oscompiled = 1 | $oscompiled = 8 ; MS Windows + shell start gtkwave behav-tristate-pulse.vcd --script nggtk.tcl +else + if $oscompiled = 7 ; macOS, manual tweaking required (mark, insert, Zoom Fit) + shell open -a gtkwave behav-tristate-pulse.vcd + else ; Linux and others + shell gtkwave behav-tristate-pulse.vcd --script nggtk.tcl & + end +end +quit +.endc +.end diff --git a/examples/p-to-n-examples/behav-tristate-pulse.stim b/examples/p-to-n-examples/behav-tristate-pulse.stim new file mode 100644 index 000000000..87ef9aa84 --- /dev/null +++ b/examples/p-to-n-examples/behav-tristate-pulse.stim @@ -0,0 +1,30 @@ +* T 1 o a o +* i a e 1 e +* m b +* e a +* r + +0ns 1s 1s 1s 0s +100ns 1s 0s 1s 1s +152ns 0s 0s 0s 1s +154ns 1s 0s 1s 1s +156ns 0s 0s 0s 1s +158ns 1s 0s 1s 1s +160ns 0s 0s 0s 1s +200ns 0s 0s 0s 1s +300ns 0s 1s 0s 0s +400ns 1s 1s 1s 0s +500ns 1s 0s 1s 1s +600ns 0s 0s 0s 1s +650ns 1s 0s 1s 1s +652ns 0s 0s 0s 1s +654ns 1s 0s 1s 1s +656ns 0s 0s 0s 1s +658ns 1s 0s 1s 1s +660ns 0s 0s 0s 1s +700ns 1s 0s 1s 1s +750ns 0s 0s 0s 1s +752ns 1s 0s 1s 1s +754ns 0s 0s 0s 1s +758ns 1s 0s 1s 1s +850ns 0s 0s 0s 1s diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index 770ca0945..4c142b1f6 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -553,13 +553,15 @@ static TLINE tab_find(PTABLE pt, char *str, BOOL start_of_line) return NULL; } -#ifdef TABLE_PRINT -static void table_print(TLINE first) +//#define PTABLE_PRINT +#ifdef PTABLE_PRINT +static void ptable_print(PTABLE pt) { TLINE t; - if (!first) + if (!pt) return; - t = first; + t = pt->first; + printf("num_entries %u\n", pt->num_entries); while (t) { printf("%s\n", t->line); t = t->next; From cd72c7960b91b84eb92155a4466bf41a2fb9fd44 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Tue, 8 Nov 2022 19:28:23 -0800 Subject: [PATCH 09/16] Fix memory leaks. --- src/frontend/logicexp.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index 4c142b1f6..4a30be8f6 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -874,8 +874,13 @@ static PTABLE optimize_gen_tab(PTABLE pt) DS_CREATE(non_tmp_name, 64); DS_CREATE(tmp_name, 64); - if (!pt || !pt->first) + if (!pt || !pt->first) { + ds_free(&scratch); + ds_free(&alias); + ds_free(&non_tmp_name); + ds_free(&tmp_name); return NULL; + } t = pt->first; lxr = new_lexer(t->line); /* Look for tmp... = another_name @@ -1043,6 +1048,10 @@ static PTABLE optimize_gen_tab(PTABLE pt) } // end of while (t) second pass quick_return: + if (new_gen && new_gen->num_entries == 0) { + delete_parse_table(new_gen); + new_gen = NULL; + } ds_free(&alias); ds_free(&scratch); ds_free(&non_tmp_name); @@ -1069,8 +1078,13 @@ static void gen_gates(PTABLE gate_tab, SYM_TAB parser_symbols) DS_CREATE(gate_name, 64); DS_CREATE(instance, 128); - if (!gate_tab || !gate_tab->first) + if (!gate_tab || !gate_tab->first) { + ds_free(&out_name); + ds_free(&in_names); + ds_free(&gate_name); + ds_free(&instance); return; + } t = gate_tab->first; lxr = new_lexer(t->line); while (t) { From e770d9615153993c91c396d9c2d5cbf2b835818f Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Wed, 9 Nov 2022 13:26:44 -0800 Subject: [PATCH 10/16] Tidy up debug tracing code. --- src/frontend/logicexp.c | 62 +++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index 4a30be8f6..7345a27b4 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -21,6 +21,9 @@ #include "ngspice/logicexp.h" #include "ngspice/udevices.h" +#define PRINT_ALL FALSE +//#define PRINT_ALL TRUE + /* Start of btree symbol table */ #define SYM_INPUT 1 #define SYM_OUTPUT 2 @@ -121,7 +124,6 @@ static void delete_sym_tab(SYM_TAB t) tfree(t); } -#ifdef TABLE_PRINT static void print_sym_tab(SYM_TAB t, BOOL with_addr) { if (t == NULL) { return; } @@ -134,7 +136,6 @@ static void print_sym_tab(SYM_TAB t, BOOL with_addr) printf("\n"); print_sym_tab(t->right, with_addr); } -#endif /* End of btree symbol table */ /* Start of lexical scanner */ @@ -382,7 +383,7 @@ typedef struct parse_table *PTABLE; struct parse_table { TLINE first; TLINE last; - unsigned int num_entries; + unsigned int entry_count; }; static PTABLE parse_tab = NULL; @@ -393,7 +394,7 @@ static PTABLE new_parse_table(void) PTABLE pt; pt = TMALLOC(struct parse_table, 1); pt->first = pt->last = NULL; - pt->num_entries = 0; + pt->entry_count = 0; return pt; } @@ -464,7 +465,7 @@ static TLINE add_to_parse_table(PTABLE pt, char *line, BOOL ignore_blank) pt->last->next = t; pt->last = t; } - pt->num_entries++; + pt->entry_count++; return t; } @@ -553,21 +554,18 @@ static TLINE tab_find(PTABLE pt, char *str, BOOL start_of_line) return NULL; } -//#define PTABLE_PRINT -#ifdef PTABLE_PRINT static void ptable_print(PTABLE pt) { TLINE t; if (!pt) return; t = pt->first; - printf("num_entries %u\n", pt->num_entries); + printf("entry_count %u\n", pt->entry_count); while (t) { printf("%s\n", t->line); t = t->next; } } -#endif /* End parse table */ /* Start of logicexp parser */ @@ -868,6 +866,7 @@ static PTABLE optimize_gen_tab(PTABLE pt) int val, idnum = 0, tok_count = 0; SYM_TAB entry = NULL, alias_tab = NULL; BOOL found_tilde = FALSE, starts_with_temp = FALSE; + BOOL prit = PRINT_ALL; PTABLE new_gen = NULL; DS_CREATE(scratch, LEX_BUF_SZ); DS_CREATE(alias, 64); @@ -932,6 +931,10 @@ static PTABLE optimize_gen_tab(PTABLE pt) lxr = new_lexer(t->line); } } + if (prit) { + printf("alias_tab:\n"); + print_sym_tab(alias_tab, FALSE); + } delete_lexer(lxr); @@ -1048,7 +1051,7 @@ static PTABLE optimize_gen_tab(PTABLE pt) } // end of while (t) second pass quick_return: - if (new_gen && new_gen->num_entries == 0) { + if (new_gen && new_gen->entry_count == 0) { delete_parse_table(new_gen); new_gen = NULL; } @@ -1289,7 +1292,7 @@ static void beval_order(void) static BOOL bparse(char *line, BOOL new_lexer) { int stmt_num = 0; - BOOL ret_val = TRUE; + BOOL ret_val = TRUE, prit = PRINT_ALL; LEXER lx; PTABLE opt_tab1 = NULL, opt_tab2 = NULL; DS_CREATE(stmt, LEX_BUF_SZ); @@ -1322,24 +1325,36 @@ static BOOL bparse(char *line, BOOL new_lexer) beval_order(); /* generate gates only when optimizations are successful */ - last_count = gen_tab->num_entries; + if (prit) { + printf("gen_tab "); + ptable_print(gen_tab); + } + last_count = gen_tab->entry_count; if (last_count == 1) { gen_gates(gen_tab, lx->lexer_sym_tab); } else if (last_count > 1) { opt_tab1 = optimize_gen_tab(gen_tab); + if (prit) { + printf("opt_tab1 "); + ptable_print(opt_tab1); + } if (opt_tab1) { - curr_count = opt_tab1->num_entries; + curr_count = opt_tab1->entry_count; opt_tab2 = opt_tab1; while (curr_count > 1 && curr_count < last_count) { last_count = curr_count; opt_tab2 = optimize_gen_tab(opt_tab1); + if (prit) { + printf("opt_tab2 "); + ptable_print(opt_tab2); + } delete_parse_table(opt_tab1); if (!opt_tab2) { ret_val = FALSE; break; } opt_tab1 = opt_tab2; - curr_count = opt_tab2->num_entries; + curr_count = opt_tab2->entry_count; } if (opt_tab2) { gen_gates(opt_tab2, lx->lexer_sym_tab); @@ -1591,13 +1606,12 @@ static void delete_pindly_table(PINTABLE pint) tfree(pint); } -//#define TRACE -#ifdef TRACE static void print_pindly_table(PINTABLE pint) { PLINE p, next; if (!pint) return; + printf("num_entries %d\n", pint->num_entries); next = pint->first; while (next) { p = next; @@ -1608,7 +1622,6 @@ static void print_pindly_table(PINTABLE pint) next = p->next; } } -#endif static PLINE nth_pindly_entry(PINTABLE pint, int n) { @@ -1657,10 +1670,9 @@ static void gen_pindly_buffers(void) { DS_CREATE(dbuf, 128); PLINE pline = NULL; + BOOL prit = PRINT_ALL; -#ifdef TRACE - print_pindly_table(pindly_tab); -#endif + if (prit) print_pindly_table(pindly_tab); pline = pindly_tab->first; while (pline) { char *iname = NULL; @@ -1772,7 +1784,7 @@ static BOOL new_gen_output_models(LEXER lx) { int val, arrlen = 0, idx = 0, i; BOOL in_pindly = FALSE, in_tristate = FALSE, in_delay = FALSE; - BOOL prit = FALSE; + BOOL prit = PRINT_ALL; float typ_max_val = 0.0, typ_val = 0.0; char *units; DS_CREATE(dly, 64); @@ -1782,6 +1794,14 @@ static BOOL new_gen_output_models(LEXER lx) PLINE pline = NULL; PLINE *pline_arr = NULL; + /* NOTE: The delays are specified in a DELAY(t1,t2,t3) function. + Beware if the format of t1, t2, t3 changes! + Expect t1, t2, t3: + -1 or x.y[time_unit] or w[time_unit] + where the time_unit is ns, ps, etc. and the same for t1, t2, t3; + x.y represents a decimal number; w is an integer. + Either numbers can have more that one digit. + */ arrlen = num_pindly_entries(pindly_tab); if (arrlen <= 0) { ds_free(&dly); From b147aa0c3a96712e44478ed81d9fd34217f4c790 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Wed, 9 Nov 2022 14:41:27 -0800 Subject: [PATCH 11/16] Add safety braces. --- src/frontend/logicexp.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index 7345a27b4..e16d32732 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -21,6 +21,7 @@ #include "ngspice/logicexp.h" #include "ngspice/udevices.h" +/* Turn off/on debug tracing */ #define PRINT_ALL FALSE //#define PRINT_ALL TRUE @@ -1672,7 +1673,7 @@ static void gen_pindly_buffers(void) PLINE pline = NULL; BOOL prit = PRINT_ALL; - if (prit) print_pindly_table(pindly_tab); + if (prit) { print_pindly_table(pindly_tab); } pline = pindly_tab->first; while (pline) { char *iname = NULL; @@ -1839,7 +1840,7 @@ static BOOL new_gen_output_models(LEXER lx) } if (in_pindly && val == LEX_ID) { // start in_pindly and LEX_ID while (val == LEX_ID) { - if (prit) printf("pindly out \"%s\"\n", lx->lexer_buf); + if (prit) { printf("pindly out \"%s\"\n", lx->lexer_buf); } pline = find_pindly_out_name(pindly_tab, lx->lexer_buf); if (pline) { pline_arr[idx++] = pline; @@ -1860,7 +1861,7 @@ static BOOL new_gen_output_models(LEXER lx) while (val != '}') { if (val == LEX_ID) { if (eq(lx->lexer_buf, "delay")) { - if (prit) printf("Get pindly delay\n"); + if (prit) { printf("Get pindly delay\n"); } in_delay = TRUE; ds_clear(&dly); } else { @@ -1875,9 +1876,11 @@ static BOOL new_gen_output_models(LEXER lx) if (val == ')') { char *tmps; in_delay = FALSE; - if (prit) printf("%s\n", ds_get_buf(&dly)); - if (prit) printf("estimate \"%s\"\n", - typical_estimate(ds_get_buf(&dly))); + if (prit) { + printf("%s\n", ds_get_buf(&dly)); + printf("estimate \"%s\"\n", + typical_estimate(ds_get_buf(&dly))); + } tmps = typical_estimate(ds_get_buf(&dly)); if (!tmps) { goto err_return; @@ -1922,7 +1925,7 @@ static BOOL new_gen_output_models(LEXER lx) BOOL invert = FALSE; if (eq(lx->lexer_buf, "lo")) invert = TRUE; - if (prit) printf("tristate enable %s ", lx->lexer_buf); + if (prit) { printf("tristate enable %s ", lx->lexer_buf); } val = lexer_scan(lx); if (val != '=') { goto err_return; @@ -1931,7 +1934,7 @@ static BOOL new_gen_output_models(LEXER lx) if (val != LEX_ID) { goto err_return; } - if (prit) printf("ena \"%s\"\n", lx->lexer_buf); + if (prit) { printf("ena \"%s\"\n", lx->lexer_buf); } ds_clear(&enable_name); if (invert) ds_cat_char(&enable_name, '~'); @@ -1952,7 +1955,7 @@ static BOOL new_gen_output_models(LEXER lx) goto err_return; } while (val == LEX_ID) { - if (prit) printf("tristate out \"%s\"\n", lx->lexer_buf); + if (prit) { printf("tristate out \"%s\"\n", lx->lexer_buf); } pline = find_pindly_out_name(pindly_tab, lx->lexer_buf); if (pline) { pline_arr[idx++] = pline; @@ -1974,7 +1977,7 @@ static BOOL new_gen_output_models(LEXER lx) while (val != '}') { if (val == LEX_ID) { if (eq(lx->lexer_buf, "delay")) { - if (prit) printf("Get tristate delay\n"); + if (prit) { printf("Get tristate delay\n"); } in_delay = TRUE; ds_clear(&dly); } else { @@ -1989,9 +1992,11 @@ static BOOL new_gen_output_models(LEXER lx) if (val == ')') { char *tmps; in_delay = FALSE; - if (prit) printf("%s\n", ds_get_buf(&dly)); - if (prit) printf("estimate \"%s\"\n", - typical_estimate(ds_get_buf(&dly))); + if (prit) { + printf("%s\n", ds_get_buf(&dly)); + printf("estimate \"%s\"\n", + typical_estimate(ds_get_buf(&dly))); + } tmps = typical_estimate(ds_get_buf(&dly)); if (!tmps) { goto err_return; From eff183f51e34640307083ee1c3d138ae74fc1757 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 12 Nov 2022 14:35:01 +0100 Subject: [PATCH 12/16] Add new functions for operators x**y or x^y compatmode hs: x>0 pow(x, y), x<0 pow(x, round(y)), X=0 0 compatmode lt: x>0 pow(x, y), x<0 pow(x, y) if y is close to integer, else 0 --- src/frontend/numparam/xpressn.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/frontend/numparam/xpressn.c b/src/frontend/numparam/xpressn.c index 3ce568223..f4732ef74 100644 --- a/src/frontend/numparam/xpressn.c +++ b/src/frontend/numparam/xpressn.c @@ -773,7 +773,31 @@ operate(char op, double x, double y) x = x / y; break; case '^': /* power */ - x = pow(fabs(x), y); + if (newcompat.hs) { + if (x < 0) + x = pow(x, round(y)); + else if (x == 0) + x = 0; + else + x = pow(x, y); + } + else if (newcompat.lt) { + if (x >= 0) + x = pow(x, y); + else { + /* If arg2 is quasi an integer, round it to have pow not fail + when arg1 is negative. Takes into account the double + representation which sometimes differs in the last digit(s). */ + if (AlmostEqualUlps(nearbyint(y), y, 10)) + x = pow(x, round(y)); + else + /* As per LTSPICE specification for ** */ + x = 0; + } + } + else { + x = pow(fabs(x), y); + } break; case 'A': /* && */ x = ((x != 0.0) && (y != 0.0)) ? 1.0 : 0.0; From 743f20d04b8330bd93d68f84998d4b7ae502f682 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 12 Nov 2022 14:35:26 +0100 Subject: [PATCH 13/16] Add new functions for operators x**y or x^y compatmode hs: x>0 pow(x, y), x<0 pow(x, round(y)), X=0 0 compatmode lt: x>0 pow(x, y), x<0 pow(x, y) if y is close to integer, else 0 --- src/spicelib/parser/inpptree.c | 4 ++-- src/spicelib/parser/inpxx.h | 1 + src/spicelib/parser/ptfuncs.c | 36 ++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/spicelib/parser/inpptree.c b/src/spicelib/parser/inpptree.c index ca870cffb..4d725077b 100644 --- a/src/spicelib/parser/inpptree.c +++ b/src/spicelib/parser/inpptree.c @@ -123,7 +123,7 @@ static struct op { PT_MINUS, "-", (void(*)(void)) PTminus}, { PT_TIMES, "*", (void(*)(void)) PTtimes}, { PT_DIVIDE, "/", (void(*)(void)) PTdivide}, { - PT_POWER, "^", (void(*)(void)) PTpower} + PT_POWER, "^", (void(*)(void)) PTpowerH} }; #define NUM_OPS (int)NUMELEMS(ops) @@ -330,7 +330,7 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum) #define b p->right if (b->type == PT_CONSTANT) { arg1 = PTdifferentiate(a, varnum); - if (newcompat.lt) { + if (newcompat.hs || newcompat.lt) { newp = mkb(PT_TIMES, mkb(PT_TIMES, mkcon(b->constant), diff --git a/src/spicelib/parser/inpxx.h b/src/spicelib/parser/inpxx.h index afbb9d162..77e4a2143 100644 --- a/src/spicelib/parser/inpxx.h +++ b/src/spicelib/parser/inpxx.h @@ -43,6 +43,7 @@ double PTminus(double arg1, double arg2); double PTtimes(double arg1, double arg2); double PTdivide(double arg1, double arg2); double PTpower(double arg1, double arg2); +double PTpowerH(double arg1, double arg2); double PTpwr(double arg1, double arg2); double PTacos(double arg); double PTacosh(double arg); diff --git a/src/spicelib/parser/ptfuncs.c b/src/spicelib/parser/ptfuncs.c index 8f1dc3760..a4ed04a3c 100644 --- a/src/spicelib/parser/ptfuncs.c +++ b/src/spicelib/parser/ptfuncs.c @@ -90,6 +90,42 @@ PTpower(double arg1, double arg2) return res; } +double +PTpowerH(double arg1, double arg2) +{ + double res; + + if (newcompat.hs) { + if (arg1 < 0) + res = pow(arg1, round(arg2)); + else if (arg1 == 0){ + res = 0; + } + else + { + res = pow(arg1, arg2); + } + } + else if (newcompat.lt) { + if (arg1 >= 0) + res = pow(arg1, arg2); + else { + /* If arg2 is quasi an integer, round it to have pow not fail + when arg1 is negative. Takes into account the double + representation which sometimes differs in the last digit(s). */ + if (AlmostEqualUlps(nearbyint(arg2), arg2, 10)) + res = pow(arg1, round(arg2)); + else + /* As per LTSPICE specification for ** */ + res = 0; + } + } + else + res = pow(fabs(arg1), arg2); + return res; +} + + double PTpwr(double arg1, double arg2) { From 7cf6b1f12b784eabb91a8376a6668bd760dfe1d9 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 12 Nov 2022 14:47:57 +0100 Subject: [PATCH 14/16] Examples for d_pwm and d_osc --- examples/xspice/pwm-osc/fmcw-dosc.cir | 46 +++++++++++++++++++++++++++ examples/xspice/pwm-osc/pwm-sin.cir | 45 ++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 examples/xspice/pwm-osc/fmcw-dosc.cir create mode 100644 examples/xspice/pwm-osc/pwm-sin.cir diff --git a/examples/xspice/pwm-osc/fmcw-dosc.cir b/examples/xspice/pwm-osc/fmcw-dosc.cir new file mode 100644 index 000000000..64c9945fe --- /dev/null +++ b/examples/xspice/pwm-osc/fmcw-dosc.cir @@ -0,0 +1,46 @@ +Emulate FMCW RADAR +* with two controlled digital oscillators +* signal delay between Vin1 and Vin2 --> frequency shift +* delay 20m --> shift 900 Hz, 10m --> 450 Hz + +.param rdelay = 20m + +* emitted signal (repeated frequency ramp) +Vin1 ain1 0 pulse (-1 1 0 200m 200m 1n 200m) +aosc1 ain1 dout1 var_clock +* emulate backscattered signal with delay (due to distant target) +Vin2 ain2 0 pulse (-1 1 {rdelay} 200m 200m 1n 200m) +aosc2 ain2 dout2 var_clock + +.model var_clock d_osc(cntl_array = [-2 -1 1 2] ++ freq_array = [1e3 1e3 10e3 10e3] ++ duty_cycle = 0.4 init_phase = 180.0 ++ rise_delay = 10e-9 fall_delay=8e-9) + +** generate the beat frequency +* AND gate as analog multiplier with i/o amplitude 1 +aand1 [dout1 dout2] mout and1 +.model and1 d_and(rise_delay = 0.5e-9 fall_delay = 0.3e-9 ++ input_load = 0.5e-12) + +* low pass filter +Rf1 mout afout 1k +Cf1 afout 0 1u + +.tran 10u 1 + +.control +run +rusage +plot ain1 ain2 dout1 dout2 +plot mout afout +plot afout +* measure the beat frequency (aka instantaneous frequency shift) +linearize afout +fft afout +let mafout = mag(afout) +plot mafout xlimit 0 1k ylimit 0 0.2 +meas sp maxout max mafout from=10 to=1k +.endc + +.end diff --git a/examples/xspice/pwm-osc/pwm-sin.cir b/examples/xspice/pwm-osc/pwm-sin.cir new file mode 100644 index 000000000..7a5299a47 --- /dev/null +++ b/examples/xspice/pwm-osc/pwm-sin.cir @@ -0,0 +1,45 @@ +*** XSPICE_PWM for audio demo ***************************** +* sin in --> pwm --> filter --> sin out to load + +* PWM with input frequency 1200k, variable duty cycle +apwm in dout pwm +.model pwm d_pwm( ++ frequency = 1.2Meg ++ cntl_array = [-1 -0.99 0.99 1] ++ dc_array = [0.01 0.01 0.99 0.99] ++ init_phase = 90) + +* D to A including inverted output +aout [~dout dout] [outn outp] dac1 + +.model dac1 dac_bridge(out_low = 0 out_high = 1 out_undef = 0 ++ input_load = 5.0e-12 t_rise = 2e-9 ++ t_fall = 2e-9) + +* LC filter ********************* +L1 outn outflcn 33u +CLfiltern outflcn 0 0.1u + +Cboth outflcn outflcp 0.47u + +L2 outp outflcp 33u +CLfilterp outflcp 0 0.1u +********************************* + +* load +RLooad outflcp outflcn 8 + +* input voltage +Vin in 0 dc 0 sin (0 0.95 1.01k) +* reference for comparison (input shifted by 3.05 degrees for compensating latency) +Vref ref 0 dc 0 sin (0 0.95 1.01k 0 0 -3.05) + +.control +tran 0.5u 20m uic +rusage +plot v(outn) v(outp) v(in)+2 xlimit 11.65m 12.15m ylabel 'digital output versus vin' +plot 0.99 * v(ref) - v(outflcp) + v(outflcn) ylimit -2m 2m ylabel 'Difference between input and output' +plot 0.99 * v(ref) v(outflcp)-v(outflcn) ylabel 'Input and output' +.endc + +.end From 0ea6dd8322f13fc8d63f8aac6ba22b8675ac3aa2 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 12 Nov 2022 14:49:01 +0100 Subject: [PATCH 15/16] Examples moved to folder /various --- examples/xspice/{ => various}/analog_models1_transient.sp | 0 examples/xspice/{ => various}/fstest.sp | 0 examples/xspice/{ => various}/pwlts1.cir | 0 examples/xspice/{ => various}/simple-diode.cir | 0 examples/xspice/{ => various}/sine.m | 0 examples/xspice/{ => various}/vswitch-test-lin.cir | 0 examples/xspice/{ => various}/vswitch-test-log.cir | 0 examples/xspice/{ => various}/xspice_c1.cir | 0 examples/xspice/{ => various}/xspice_c2.cir | 0 examples/xspice/{ => various}/xspice_c3.cir | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename examples/xspice/{ => various}/analog_models1_transient.sp (100%) rename examples/xspice/{ => various}/fstest.sp (100%) rename examples/xspice/{ => various}/pwlts1.cir (100%) rename examples/xspice/{ => various}/simple-diode.cir (100%) rename examples/xspice/{ => various}/sine.m (100%) rename examples/xspice/{ => various}/vswitch-test-lin.cir (100%) rename examples/xspice/{ => various}/vswitch-test-log.cir (100%) rename examples/xspice/{ => various}/xspice_c1.cir (100%) rename examples/xspice/{ => various}/xspice_c2.cir (100%) rename examples/xspice/{ => various}/xspice_c3.cir (100%) diff --git a/examples/xspice/analog_models1_transient.sp b/examples/xspice/various/analog_models1_transient.sp similarity index 100% rename from examples/xspice/analog_models1_transient.sp rename to examples/xspice/various/analog_models1_transient.sp diff --git a/examples/xspice/fstest.sp b/examples/xspice/various/fstest.sp similarity index 100% rename from examples/xspice/fstest.sp rename to examples/xspice/various/fstest.sp diff --git a/examples/xspice/pwlts1.cir b/examples/xspice/various/pwlts1.cir similarity index 100% rename from examples/xspice/pwlts1.cir rename to examples/xspice/various/pwlts1.cir diff --git a/examples/xspice/simple-diode.cir b/examples/xspice/various/simple-diode.cir similarity index 100% rename from examples/xspice/simple-diode.cir rename to examples/xspice/various/simple-diode.cir diff --git a/examples/xspice/sine.m b/examples/xspice/various/sine.m similarity index 100% rename from examples/xspice/sine.m rename to examples/xspice/various/sine.m diff --git a/examples/xspice/vswitch-test-lin.cir b/examples/xspice/various/vswitch-test-lin.cir similarity index 100% rename from examples/xspice/vswitch-test-lin.cir rename to examples/xspice/various/vswitch-test-lin.cir diff --git a/examples/xspice/vswitch-test-log.cir b/examples/xspice/various/vswitch-test-log.cir similarity index 100% rename from examples/xspice/vswitch-test-log.cir rename to examples/xspice/various/vswitch-test-log.cir diff --git a/examples/xspice/xspice_c1.cir b/examples/xspice/various/xspice_c1.cir similarity index 100% rename from examples/xspice/xspice_c1.cir rename to examples/xspice/various/xspice_c1.cir diff --git a/examples/xspice/xspice_c2.cir b/examples/xspice/various/xspice_c2.cir similarity index 100% rename from examples/xspice/xspice_c2.cir rename to examples/xspice/various/xspice_c2.cir diff --git a/examples/xspice/xspice_c3.cir b/examples/xspice/various/xspice_c3.cir similarity index 100% rename from examples/xspice/xspice_c3.cir rename to examples/xspice/various/xspice_c3.cir From fcc3191732b042900b7dff684ec6a77064cf5b68 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 12 Nov 2022 14:52:22 +0100 Subject: [PATCH 16/16] rename example file --- examples/xspice/various/{fstest.sp => filesource-test.sp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/xspice/various/{fstest.sp => filesource-test.sp} (100%) diff --git a/examples/xspice/various/fstest.sp b/examples/xspice/various/filesource-test.sp similarity index 100% rename from examples/xspice/various/fstest.sp rename to examples/xspice/various/filesource-test.sp