From 2e064db79a9c7b5a9167bcc388533b90fd264d55 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 7 Nov 2022 12:16:58 +0100 Subject: [PATCH 01/19] Add STATIC_VAR_TABLE locdata Add CALLBACK cm_d_pwm_callback Reserve memory for x, y arrays only once during INIT --- src/xspice/icm/digital/d_pwm/cfunc.mod | 117 +++++++++++------------- src/xspice/icm/digital/d_pwm/ifspec.ifs | 6 ++ 2 files changed, 59 insertions(+), 64 deletions(-) diff --git a/src/xspice/icm/digital/d_pwm/cfunc.mod b/src/xspice/icm/digital/d_pwm/cfunc.mod index af6e323c8..e64d6efcd 100644 --- a/src/xspice/icm/digital/d_pwm/cfunc.mod +++ b/src/xspice/icm/digital/d_pwm/cfunc.mod @@ -19,7 +19,7 @@ MODIFICATIONS 23 Aug 1991 Jeffrey P. Murray 30 Sep 1991 Jeffrey P. Murray - + 06 Oct 2022 Holger Vogt SUMMARY @@ -69,7 +69,10 @@ NON-STANDARD FEATURES /*=== LOCAL VARIABLES & TYPEDEFS =======*/ - +typedef struct { + double *x; + double *y; +} Local_Data_t; /*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ @@ -120,6 +123,27 @@ NON-STANDARD FEATURES ==============================================================================*/ +static void cm_d_pwm_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_pwm_callback */ + + + /*=== CM_D_PWM ROUTINE ===*/ /************************************************************* @@ -179,15 +203,12 @@ void cm_d_pwm(ARGS) slope; /* slope value...used to extrapolate freq values past endpoints. */ - int i, /* generic loop counter index */ cntl_size, /* control array size */ dc_size; /* duty cycle array size */ - - - - + Local_Data_t *loc; /* Pointer to local static data, not to be included + in the state vector (save memory!) */ /**** Retrieve frequently used parameters... ****/ @@ -195,7 +216,6 @@ void cm_d_pwm(ARGS) dc_size = PARAM_SIZE(dc_array); frequency = PARAM(frequency); - /* check and make sure that the control array is the same size as the frequency array */ @@ -204,10 +224,8 @@ void cm_d_pwm(ARGS) return; } - 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)); @@ -220,15 +238,35 @@ void cm_d_pwm(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_pwm_callback; + + x = loc->x = (double *) calloc((size_t) cntl_size, sizeof(double)); + if (!x) { + cm_message_send(d_pwm_allocation_error); + return; + } + y = loc->y = (double *) calloc((size_t) cntl_size, sizeof(double)); + if (!y) { + cm_message_send(d_pwm_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); @@ -346,7 +358,6 @@ void cm_d_pwm(ARGS) // cm_message_send(d_pwm_positive_dc_error); } - /* calculate the instantaneous phase */ *phase = *phase_old + frequency * (TIME - T(1)); @@ -354,7 +365,6 @@ void cm_d_pwm(ARGS) the period */ dphase = *phase_old - floor(*phase_old); - /* Calculate the time variables and the output value for this iteration */ @@ -365,8 +375,6 @@ void cm_d_pwm(ARGS) if(TIME < *t3) { cm_event_queue(*t3); } - - } else @@ -380,7 +388,6 @@ void cm_d_pwm(ARGS) if(TIME < *t1) { cm_event_queue(*t1); - } } else { @@ -395,23 +402,12 @@ void cm_d_pwm(ARGS) } *t3 = T(1) + (1 - dphase)/frequency; - - } - - - - 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, @@ -424,7 +420,6 @@ void cm_d_pwm(ARGS) } *phase = *phase / 360.0; - /* set phase value to init_phase */ *phase_old = *phase; @@ -433,16 +428,12 @@ void cm_d_pwm(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; @@ -471,9 +462,7 @@ void cm_d_pwm(ARGS) } } } - break; - } } diff --git a/src/xspice/icm/digital/d_pwm/ifspec.ifs b/src/xspice/icm/digital/d_pwm/ifspec.ifs index da6ed4da3..cde238f16 100644 --- a/src/xspice/icm/digital/d_pwm/ifspec.ifs +++ b/src/xspice/icm/digital/d_pwm/ifspec.ifs @@ -75,3 +75,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 db81d7ca28dfeb4fbf2a40a4ddcd17ed3187e1a0 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Fri, 21 Oct 2022 11:27:57 -0700 Subject: [PATCH 02/19] Add drive 0/1 for $d_lo/$d_hi. --- src/frontend/udevices.c | 92 +++++++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 31 deletions(-) diff --git a/src/frontend/udevices.c b/src/frontend/udevices.c index 285c8be3e..a4cc2ec02 100644 --- a/src/frontend/udevices.c +++ b/src/frontend/udevices.c @@ -297,6 +297,7 @@ static NAME_ENTRY port_names_list = NULL; static unsigned int num_name_collisions = 0; /* .model d_zero_inv99 d_inverter just once per subckt */ static BOOL add_zero_delay_inverter_model = FALSE; +static BOOL add_drive_hilo = FALSE; static char *current_subckt = NULL; static unsigned int subckt_msg_count = 0; @@ -720,6 +721,29 @@ struct card *replacement_udevice_cards(void) x = create_xlate_translated(".model d_zero_inv99 d_inverter"); translated_p = add_xlator(translated_p, x); } + if (add_drive_hilo) { + x = create_xlate_translated(".subckt hilo_dollar___lo drive___0"); + translated_p = add_xlator(translated_p, x); + x = create_xlate_translated("a1 0 drive___0 dbuf1"); + translated_p = add_xlator(translated_p, x); + x = create_xlate_translated(".model dbuf1 d_buffer"); + translated_p = add_xlator(translated_p, x); + x = create_xlate_translated(".ends hilo_dollar___lo"); + translated_p = add_xlator(translated_p, x); + x = create_xlate_translated(".subckt hilo_dollar___hi drive___1"); + translated_p = add_xlator(translated_p, x); + x = create_xlate_translated("a2 0 drive___1 dinv1"); + translated_p = add_xlator(translated_p, x); + x = create_xlate_translated(".model dinv1 d_inverter"); + translated_p = add_xlator(translated_p, x); + x = create_xlate_translated(".ends hilo_dollar___hi"); + translated_p = add_xlator(translated_p, x); + x = create_xlate_translated("x8100000 hilo_drive___1 hilo_dollar___hi"); + translated_p = add_xlator(translated_p, x); + x = create_xlate_translated("x8100001 hilo_drive___0 hilo_dollar___lo"); + translated_p = add_xlator(translated_p, x); + + } for (x = first_xlator(translated_p); x; x = next_xlator(translated_p)) { if (ps_port_directions >= 2) { printf("TRANS_OUT %s\n", x->translated); @@ -791,6 +815,7 @@ void initialize_udevice(char *subckt_line) (void) add_xlator(default_models, xdata); /* reset for the new subckt */ add_zero_delay_inverter_model = FALSE; + add_drive_hilo = FALSE; } static void determine_port_type(void) @@ -834,6 +859,7 @@ void cleanup_udevice(void) delete_xlator(default_models); default_models = NULL; add_zero_delay_inverter_model = FALSE; + add_drive_hilo = FALSE; clear_name_list(input_names_list, "INPUT_PINS"); input_names_list = NULL; clear_name_list(output_names_list, "OUTPUT_PINS"); @@ -2708,6 +2734,25 @@ static BOOL u_process_model(char *nline, char *original) return retval; } +static char *get_name_hilo(char *tok_str) +{ + char *name = NULL; + + if (eq(tok_str, "$d_hi")) { + name = TMALLOC(char, strlen("hilo_drive___1") + 1); + strcpy(name, "hilo_drive___1"); + add_drive_hilo = TRUE; + } else if (eq(tok_str, "$d_lo")) { + name = TMALLOC(char, strlen("hilo_drive___0") + 1); + strcpy(name, "hilo_drive___0"); + add_drive_hilo = TRUE; + } else { + name = TMALLOC(char, strlen(tok_str) + 1); + (void) memcpy(name, tok_str, strlen(tok_str) + 1); + } + return name; +} + static struct dff_instance *add_dff_inout_timing_model( struct instance_hdr *hdr, char *start) { @@ -2735,9 +2780,7 @@ static struct dff_instance *add_dff_inout_timing_model( arrp = dffip->d_in; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); - name = TMALLOC(char, strlen(tok) + 1); - (void) memcpy(name, tok, strlen(tok) + 1); - arrp[i] = name; + arrp[i] = get_name_hilo(tok); } /* q_out outputs */ dffip->q_out = TMALLOC(char *, num_gates); @@ -2766,7 +2809,7 @@ static struct dff_instance *add_dff_inout_timing_model( /* Reject incompatible inputs */ arrp = dffip->d_in; for (i = 0; i < num_gates; i++) { - if (strncmp(arrp[i], "$d_", 3) == 0) { + if (eq(arrp[i], "$d_nc")) { delete_dff_instance(dffip); return NULL; } @@ -2795,7 +2838,7 @@ static struct dltch_instance *add_dltch_inout_timing_model( dlp->num_gates = num_gates; copyline = TMALLOC(char, strlen(start) + 1); (void) memcpy(copyline, start, strlen(start) + 1); - /* prebar, clrbar, clk */ + /* prebar, clrbar, clk(gate) */ tok = strtok(copyline, " \t"); dlp->prebar = TMALLOC(char, strlen(tok) + 1); (void) memcpy(dlp->prebar, tok, strlen(tok) + 1); @@ -2803,16 +2846,14 @@ static struct dltch_instance *add_dltch_inout_timing_model( dlp->clrbar = TMALLOC(char, strlen(tok) + 1); (void) memcpy(dlp->clrbar, tok, strlen(tok) + 1); tok = strtok(NULL, " \t"); - dlp->gate = TMALLOC(char, strlen(tok) + 1); - (void) memcpy(dlp->gate, tok, strlen(tok) + 1); + dlp->gate = get_name_hilo(tok); + /* d inputs */ dlp->d_in = TMALLOC(char *, num_gates); arrp = dlp->d_in; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); - name = TMALLOC(char, strlen(tok) + 1); - (void) memcpy(name, tok, strlen(tok) + 1); - arrp[i] = name; + arrp[i] = get_name_hilo(tok); } /* q_out outputs */ dlp->q_out = TMALLOC(char *, num_gates); @@ -2841,12 +2882,12 @@ static struct dltch_instance *add_dltch_inout_timing_model( /* Reject incompatible inputs */ arrp = dlp->d_in; for (i = 0; i < num_gates; i++) { - if (strncmp(arrp[i], "$d_", 3) == 0) { + if (eq(arrp[i], "$d_nc")) { delete_dltch_instance(dlp); return NULL; } } - if (strncmp(dlp->gate, "$d_", 3) == 0) { + if (eq(dlp->gate, "$d_nc")) { delete_dltch_instance(dlp); return NULL; } @@ -2888,18 +2929,14 @@ static struct jkff_instance *add_jkff_inout_timing_model( arrp = jkffip->j_in; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); - name = TMALLOC(char, strlen(tok) + 1); - (void) memcpy(name, tok, strlen(tok) + 1); - arrp[i] = name; + arrp[i] = get_name_hilo(tok); } /* k inputs */ jkffip->k_in = TMALLOC(char *, num_gates); arrp = jkffip->k_in; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); - name = TMALLOC(char, strlen(tok) + 1); - (void) memcpy(name, tok, strlen(tok) + 1); - arrp[i] = name; + arrp[i] = get_name_hilo(tok); } /* q_out outputs */ jkffip->q_out = TMALLOC(char *, num_gates); @@ -2929,8 +2966,7 @@ static struct jkff_instance *add_jkff_inout_timing_model( arrp = jkffip->j_in; arrpk = jkffip->k_in; for (i = 0; i < num_gates; i++) { - if (strncmp(arrp[i], "$d_", 3) == 0 || - strncmp(arrpk[i], "$d_", 3) == 0) { + if (eq(arrp[i], "$d_nc") || eq(arrpk[i], "$d_nc")) { delete_jkff_instance(jkffip); return NULL; } @@ -2969,26 +3005,21 @@ static struct srff_instance *add_srff_inout_timing_model( (void) memcpy(srffp->clrbar, tok, strlen(tok) + 1); tok = strtok(NULL, " \t"); - srffp->gate = TMALLOC(char, strlen(tok) + 1); - (void) memcpy(srffp->gate, tok, strlen(tok) + 1); + srffp->gate = get_name_hilo(tok); /* s inputs */ srffp->s_in = TMALLOC(char *, num_gates); arrp = srffp->s_in; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); - name = TMALLOC(char, strlen(tok) + 1); - (void) memcpy(name, tok, strlen(tok) + 1); - arrp[i] = name; + arrp[i] = get_name_hilo(tok); } /* r inputs */ srffp->r_in = TMALLOC(char *, num_gates); arrp = srffp->r_in; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); - name = TMALLOC(char, strlen(tok) + 1); - (void) memcpy(name, tok, strlen(tok) + 1); - arrp[i] = name; + arrp[i] = get_name_hilo(tok); } /* q_out outputs */ srffp->q_out = TMALLOC(char *, num_gates); @@ -3018,13 +3049,12 @@ static struct srff_instance *add_srff_inout_timing_model( arrp = srffp->s_in; arrpr = srffp->r_in; for (i = 0; i < num_gates; i++) { - if (strncmp(arrp[i], "$d_", 3) == 0 || - strncmp(arrpr[i], "$d_", 3) == 0) { + if (eq(arrp[i], "$d_nc") || eq(arrpr[i], "$d_nc")) { delete_srff_instance(srffp); return NULL; } } - if (strncmp(srffp->gate, "$d_", 3) == 0) { + if (eq(srffp->gate, "$d_nc")) { delete_srff_instance(srffp); return NULL; } From 67369f1c678f72ae8e3de6bafb32c3dbfd2b07a9 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Fri, 21 Oct 2022 15:21:18 -0700 Subject: [PATCH 03/19] Initial logicexp parser and gate generator. --- src/frontend/Makefile.am | 3 + src/frontend/logicexp.c | 1358 ++++++++++++++++++++++++++++++++ src/frontend/udevices.c | 9 +- src/include/ngspice/logicexp.h | 9 + 4 files changed, 1378 insertions(+), 1 deletion(-) create mode 100644 src/frontend/logicexp.c create mode 100644 src/include/ngspice/logicexp.h diff --git a/src/frontend/Makefile.am b/src/frontend/Makefile.am index d404077c8..90ac17a57 100644 --- a/src/frontend/Makefile.am +++ b/src/frontend/Makefile.am @@ -136,6 +136,8 @@ libfte_la_SOURCES = \ inventory.c \ linear.c \ linear.h \ + logicexp.c \ + logicexp.h \ measure.c \ misccoms.c \ misccoms.h \ @@ -185,6 +187,7 @@ libfte_la_SOURCES = \ typesdef.c \ typesdef.h \ udevices.c \ + udevices.h \ vectors.c \ vectors.h \ where.c \ diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c new file mode 100644 index 000000000..328347c94 --- /dev/null +++ b/src/frontend/logicexp.c @@ -0,0 +1,1358 @@ +#include +#include +#include +#include + +//#define LOCAL_BUILD +#ifdef LOCAL_BUILD +#include "ngspice/ngspice/memory.h" +#include "ngspice/ngspice/macros.h" +#include "ngspice/ngspice/bool.h" +#include "ngspice/ngspice/ngspice.h" +#include "ngspice/ngspice/stringskip.h" +#include "ngspice/ngspice/stringutil.h" +#include "ngspice/ngspice/dstring.h" +#include "logicexp.h" +#else +#include "ngspice/memory.h" +#include "ngspice/macros.h" +#include "ngspice/bool.h" +#include "ngspice/ngspice.h" +#include "ngspice/stringskip.h" +#include "ngspice/stringutil.h" +#include "ngspice/dstring.h" +#include "ngspice/logicexp.h" +#endif + +/* Start of btree symbol table */ +#define SYM_INPUT 1 +#define SYM_OUTPUT 2 +#define SYM_TMODEL 4 +#define SYM_KEY_WORD 8 +#define SYM_ID 16 +#define SYM_GATE_OP 32 +#define SYM_INVERTER 64 +#define SYM_OTHER 128 + +typedef struct sym_entry *SYM_TAB; +struct sym_entry { + char *name; + char *alias; + int attribute; + int ref_count; // for inverters + SYM_TAB left; + SYM_TAB right; +}; + +static SYM_TAB new_sym_entry(char *name, int attr) +{ + SYM_TAB newp; + newp = TMALLOC(struct sym_entry, 1); + newp->left = NULL; + newp->right = NULL; + newp->name = TMALLOC(char, strlen(name) + 1); + strcpy(newp->name, name); + newp->alias = NULL; + newp->attribute = attr; + newp->ref_count = 0; + return newp; +} + +static SYM_TAB insert_sym_tab(char *name, SYM_TAB t, int attr) +{ + int cmp; + if (t == NULL) { + t = new_sym_entry(name, attr); + return t; + } + cmp = strcmp(name, t->name); + if (cmp < 0) { + t->left = insert_sym_tab(name, t->left, attr); + } else if (cmp > 0) { + t->right = insert_sym_tab(name, t->right, attr); + } else { + printf("NOTE insert_sym_tab %s already there\n", name); + } + return t; +} + +static SYM_TAB member_sym_tab(char *name, SYM_TAB t) +{ + int cmp; + while (t != NULL) { + cmp = strcmp(name, t->name); + if (cmp == 0) { + return t; + } else if (cmp < 0) { + t = t->left; + } else { + t = t->right; + } + } + return NULL; +} + +static SYM_TAB add_sym_tab_entry(char *name, int attr, SYM_TAB *stab) +{ + SYM_TAB entry = NULL; + entry = member_sym_tab(name, *stab); + if (!entry) { + *stab = insert_sym_tab(name, *stab, attr); + entry = member_sym_tab(name, *stab); + } + return entry; +} + +static void alias_sym_tab(char *alias, SYM_TAB t) +{ + if (t == NULL) { return; } + if (t->alias) + tfree(t->alias); + t->alias = TMALLOC(char, strlen(alias) + 1); + strcpy(t->alias, alias); +} + +static void delete_sym_tab(SYM_TAB t) +{ + if (t == NULL) { return; } + delete_sym_tab(t->left); + delete_sym_tab(t->right); + if (t->name) + tfree(t->name); + if (t->alias) + tfree(t->alias); + tfree(t); +} + +static void print_sym_tab(SYM_TAB t, BOOL with_addr) +{ + if (t == NULL) { return; } + print_sym_tab(t->left, with_addr); + if (with_addr) + printf("%p --> \n", t); + printf("\"%s\" %d ref_count=%d", t->name, t->attribute, t->ref_count); + if (t->alias) + printf(" alias = \"%s\"", t->alias); + printf("\n"); + print_sym_tab(t->right, with_addr); +} +/* End of btree symbol table */ + +/* Start of lexical scanner */ +#include +#define LEX_ID 256 +#define LEX_OTHER 257 +#define LEX_BUF_SZ 512 + +typedef struct lexer *LEXER; +struct lexer { + char lexer_buf[LEX_BUF_SZ]; + char *lexer_line; + int lexer_pos; + int lexer_back; + SYM_TAB lexer_sym_tab; +}; + +static LEXER parse_lexer = NULL; + +static LEXER new_lexer(char *line) +{ + LEXER lx; + lx = TMALLOC(struct lexer, 1); + lx->lexer_line = TMALLOC(char, (strlen(line) + 1)); + strcpy(lx->lexer_line, line); + lx->lexer_pos = lx->lexer_back = 0; + lx->lexer_buf[0] = '\0'; + lx->lexer_sym_tab = NULL; + return lx; +} + +static void delete_lexer(LEXER lx) +{ + if (!lx) + return; + if (lx->lexer_line) + tfree(lx->lexer_line); + if (lx->lexer_sym_tab) + delete_sym_tab(lx->lexer_sym_tab); + tfree(lx); +} + +static void lex_init(char *line) +{ + parse_lexer = new_lexer(line); + return; +} + +static int lexer_set_start(char *s, LEXER lx) +{ + char *pos; + if (!lx) + return -1; + pos = strstr(lx->lexer_line, s); + if (!pos) + return -1; + lx->lexer_pos = pos - &lx->lexer_line[0]; + lx->lexer_back = lx->lexer_pos; + return lx->lexer_pos; +} + +static int lex_set_start(char *s) +{ + return lexer_set_start(s, parse_lexer); +} + +static int lexer_getchar(LEXER lx) +{ + int item = 0; + item = lx->lexer_line[lx->lexer_pos]; + lx->lexer_back = lx->lexer_pos; + if (item != 0) + lx->lexer_pos++; + return item; +} + +static void lexer_putback(LEXER lx) +{ + if (lx->lexer_back >= 0) + lx->lexer_pos = lx->lexer_back; +} + +static int lex_punct(int c) +{ + switch (c) { + case ',': + case '{': + case '}': + case '(': + case ')': + case ':': + return c; + default: + break; + } + return 0; +} + +static int lex_oper(int c) +{ + switch (c) { + case '~': + case '&': + case '^': + case '|': + case '=': + return c; + default: + break; + } + return 0; +} + +static char *lex_gate_name(int c, BOOL not) +{ + /* returns an XSPICE gate model name */ + static char buf[32]; + switch (c) { + case '~': + if (not) + sprintf(buf, "d__inverter__1"); + else + sprintf(buf, "d__buffer__1"); + break; + case '&': + if (not) + sprintf(buf, "d__nand__1"); + else + sprintf(buf, "d__and__1"); + break; + case '^': + if (not) + sprintf(buf, "d__xnor__1"); + else + sprintf(buf, "d__xor__1"); + break; + case '|': + if (not) + sprintf(buf, "d__nor__1"); + else + sprintf(buf, "d__or__1"); + break; + default: + sprintf(buf, "UNKNOWN"); + break; + } + return buf; +} + +static int lex_gate_op(int c) +{ + switch (c) { + case '&': + case '^': + case '|': + return c; + default: + break; + } + return 0; +} + +static int lex_ident(int c) +{ + if (isalnum(c) || c == '_' || c == '/' || c == '-') + return c; + else + return 0; +} + +static int lexer_scan(LEXER lx) +{ + int c; + while (1) { + lx->lexer_buf[0] = '\0'; + c = lexer_getchar(lx); + if (c == '\0') + return 0; + else if (isspace(c)) + continue; + else if (lex_punct(c)) + return c; + else if (lex_oper(c)) + return c; + else if (lex_ident(c)) { + int i = 0; + while (lex_ident(c)) { + lx->lexer_buf[i] = c; + assert(i < LEX_BUF_SZ); + i++; + c = lexer_getchar(lx); + } + assert(i < LEX_BUF_SZ); + lx->lexer_buf[i] = '\0'; + if (c != '\0') + lexer_putback(lx); + return LEX_ID; + } else { + lx->lexer_buf[0] = c; + lx->lexer_buf[1] = '\0'; + return LEX_OTHER; + } + } +} + +static int lex_scan(void) +{ + return lexer_scan(parse_lexer); +} + +static BOOL lex_all_digits(char *str) +{ + int i; + if (!str || strlen(str) < 1) + return FALSE; + for (i = 0; i < strlen(str); i++) { + if (!isdigit(str[i])) return FALSE; + } + return TRUE; +} +/* End of lexical scanner */ + +/* Start parse table */ +typedef struct table_line *TLINE; +struct table_line { + char *line; + TLINE next; +}; + +typedef struct parse_table *PTABLE; +struct parse_table { + TLINE first; + TLINE last; +}; + +static PTABLE parse_tab = NULL; +static PTABLE gen_tab = NULL; + +static PTABLE new_parse_table(void) +{ + PTABLE pt; + pt = TMALLOC(struct parse_table, 1); + pt->first = pt->last = NULL; + return pt; +} + +static void delete_parse_table(PTABLE pt) +{ + TLINE t, next; + if (!pt) + return; + next = pt->first; + while (next) { + t = next; + tfree(t->line); + next = t->next; + tfree(t); + } + tfree(pt); +} + +static void delete_parse_gen_tables(void) +{ + delete_parse_table(parse_tab); + delete_parse_table(gen_tab); + parse_tab = gen_tab = NULL; +} + +static void init_parse_tables(void) +{ + parse_tab = new_parse_table(); + gen_tab = new_parse_table(); +} + +static TLINE ptab_new_line(char *line) +{ + TLINE t = NULL; + t = TMALLOC(struct table_line, 1); + t->next = NULL; + t->line = TMALLOC(char, (strlen(line) + 1)); + strcpy(t->line, line); + return t; +} + +static TLINE add_common(char *line, BOOL ignore_blank) +{ + if (!line) + return NULL; + if (ignore_blank) { + if (line[0] == '\0') { + return NULL; + } else if (line[0] == '\n' && strlen(line) < 2) { + return NULL; + } + } + return ptab_new_line(line); +} + +static TLINE add_to_parse_table(PTABLE pt, char *line, BOOL ignore_blank) +{ + TLINE t; + if (!pt) + return NULL; + t = add_common(line, ignore_blank); + if (!t) + return NULL; + t->next = NULL; + if (!pt->first) { + pt->first = pt->last = t; + } else { + pt->last->next = t; + pt->last = t; + } + return t; +} + +static TLINE ptab_add_line(char *line, BOOL ignore_blank) +{ + TLINE t; + t = add_to_parse_table(parse_tab, line, ignore_blank); + return t; +} + +static TLINE gen_tab_add_line(char *line, BOOL ignore_blank) +{ + TLINE t; + t = add_to_parse_table(gen_tab, line, ignore_blank); + return t; +} + +static char *get_temp_from_line(char *line, BOOL begin) +{ + /* First occurrence of "tmp" on the line */ + /* If begin is TRUE then "tmp" must be at the start of line */ + static char lbuf[64]; + char *p, *q; + int j; + p = strstr(line, "tmp"); + if (!p) + return NULL; + if (begin && p != line) + return NULL; + for (q = p, j = 0; isalnum(q[j]) || q[j] == '_'; j++) { + if (j >= 63) + return NULL; + lbuf[j] = q[j]; + } + lbuf[j] = '\0'; + return lbuf; +} + +static char *find_temp_begin(char *line) +{ + return get_temp_from_line(line, TRUE); +} + +static char *find_temp_anywhere(char *line) +{ + return get_temp_from_line(line, FALSE); +} + +static int get_temp_depth(char *line) +{ + char buf[64]; + char *p, *endp; + int depth; + p = find_temp_anywhere(line); + if (p) { + strcpy(buf, p); + p = strstr(buf + strlen("tmp"), "__"); + if (p) { + p = p + 2; + depth = (int) strtol(p, &endp, 10); + return depth; + } + } + return -1; +} + +static TLINE tab_find(PTABLE pt, char *str, BOOL start_of_line) +{ + TLINE t; + size_t len; + + if (!pt) + return NULL; + t = pt->first; + len = strlen(str); + while (t) { + if (start_of_line) { + if (strncmp(t->line, str, len) == 0) + return t; + } else { + if (strstr(t->line, str)) + return t; + } + t = t->next; + } + return NULL; +} +/* End parse table */ + +/* Start of logicexp parser */ +static char *get_inst_name(void); +static char *get_inverter_output_name(char *input); +static void gen_inverters(SYM_TAB t); +static void aerror(char *s); +static void amatch(int t); +static void bexpr(void); +static void bfactor(void); +static void bparse(char *line, BOOL new_lexer); + +static int lookahead = 0; +static int adepth = 0; +static int max_adepth = 0; +static DSTRING d_curr_line; + +static char *get_inst_name(void) +{ + static char name[64]; + static int number = 0; + number++; + (void) sprintf(name, "a_%d", number); + return name; +} + +static char *get_inverter_output_name(char *input) +{ + static char buf[LEX_BUF_SZ]; + LEXER lx = parse_lexer; + // FIX ME keep this name in the symbol table to ensure uniqueness + (void) sprintf(buf, "inv_out__%s", input); + if (member_sym_tab(buf, lx->lexer_sym_tab)) + printf("ERROR %s is already in use\n", buf); + return buf; +} + +static char *get_inv_tail(char *str) +{ + static char lbuf[64]; + char *p = NULL, *q = NULL; + int j; + size_t slen = strlen("inv_out__"); + + p = strstr(str, "inv_out__"); + if (!p) + return NULL; + for (q = p + slen, j = 0; q[j] != '\0' && !isspace(q[j]); j++) { + if (j >= 63) + return NULL; + lbuf[j] = q[j]; + } + lbuf[j] = '\0'; + return lbuf; +} + +static void gen_inverters(SYM_TAB t) +{ + if (t == NULL) + return; + gen_inverters(t->left); + if (t->attribute & SYM_INVERTER) { + if (t->ref_count >= 1) { + printf("%s %s %s d_inv_zero_delay\n", get_inst_name(), + t->name, get_inverter_output_name(t->name)); + } + } + gen_inverters(t->right); +} + +static void gen_models(void) +{ + printf(".model d_inv_zero_delay d_inverter\n"); + printf(".model d__inverter__1 d_inverter\n"); + printf(".model d__buffer__1 d_buffer\n"); + printf(".model d__nand__1 d_nand\n"); + printf(".model d__and__1 d_and\n"); + printf(".model d__xnor__1 d_xnor\n"); + printf(".model d__xor__1 d_xor\n"); + printf(".model d__nor__1 d_nor\n"); + printf(".model d__or__1 d_or\n"); +} + +static void aerror(char *s) +{ + LEXER lx = parse_lexer; + printf("%s [%s]\n", s, lx->lexer_line + lx->lexer_pos); + exit(1); +} + +char *get_temp_name(void) +{ + static char name[64]; + static int number = 0; + number++; + (void) sprintf(name, "tmp%d", number); + return name; +} + +static void amatch(int t) +{ + LEXER lx = parse_lexer; + if (lookahead == t) { + lookahead = lex_scan(); + } else { + printf("t = '%c' [%d] lookahead = '%c' [%d] lexer_buf %s\n", + t, t, lookahead, lookahead, lx->lexer_buf); + aerror("amatch: syntax error"); + } +} + +static void bfactor(void) +{ + /* factor is : [~] (optional) rest + where rest is: id (input_name) | ( expr ) | error + */ + BOOL is_not = FALSE; + SYM_TAB entry = NULL; + LEXER lx = parse_lexer; + + adepth++; + + if (lookahead == '~') { + is_not = TRUE; + lookahead = lex_scan(); + } + + if (lookahead == LEX_ID) { + entry = add_sym_tab_entry(lx->lexer_buf, SYM_ID, &lx->lexer_sym_tab); + if (is_not) { + ds_cat_printf(&d_curr_line, "%s ", + get_inverter_output_name(lx->lexer_buf)); + entry->attribute |= SYM_INVERTER; + entry->ref_count++; + } else { + ds_cat_printf(&d_curr_line, "%s ", lx->lexer_buf); + } + + lookahead = lex_scan(); + + } else if (lookahead == '(') { + DS_CREATE(tmpnam, 64); + + ds_clear(&tmpnam); + if (adepth > max_adepth) + max_adepth = adepth; + + ds_cat_str(&tmpnam, get_temp_name()); + (void) ptab_add_line(ds_get_buf(&d_curr_line), TRUE); + ds_clear(&d_curr_line); + ds_cat_printf(&d_curr_line, "%s__%d <- ", ds_get_buf(&tmpnam), adepth); + + if (is_not) { + ds_cat_printf(&d_curr_line, "~ %c", lookahead); + } else { + ds_cat_printf(&d_curr_line, "%c", lookahead); + } + (void) ptab_add_line(ds_get_buf(&d_curr_line), TRUE); + ds_clear(&d_curr_line); + + lookahead = lex_scan(); + bexpr(); + + (void) ptab_add_line(ds_get_buf(&d_curr_line), TRUE); + ds_clear(&d_curr_line); + + ds_cat_printf(&d_curr_line, "%c -> %s__%d", lookahead, + ds_get_buf(&tmpnam), adepth); + (void) ptab_add_line(ds_get_buf(&d_curr_line), TRUE); + ds_clear(&d_curr_line); + + amatch(')'); + ds_free(&tmpnam); + + } else { + aerror("bfactor: syntax error"); + } + adepth--; +} + +static void bexpr(void) +{ + /* expr is: factor { gate_op factor } (0 or more times). */ + bfactor(); + + while (lex_gate_op(lookahead)) { + ds_cat_printf(&d_curr_line, "%c ", lookahead); + + lookahead = lex_scan(); + bfactor(); + } +} + +static int bstmt(void) +{ + /* A stmt is: output_name = { expr } */ + int end_pos; + SYM_TAB entry = NULL; + LEXER lx = parse_lexer; + DS_CREATE(tname, 64); + DS_CREATE(assign, LEX_BUF_SZ); + + if (lookahead == LEX_ID) { + entry = add_sym_tab_entry(lx->lexer_buf, SYM_ID, &lx->lexer_sym_tab); + } else { + aerror("bstmt: syntax error"); + } + + adepth++; + if (adepth > max_adepth) + max_adepth = adepth; + + amatch(LEX_ID); + amatch('='); + + ds_clear(&assign); + ds_cat_printf(&assign, "%s =", entry->name); + (void) ptab_add_line(ds_get_buf(&assign), TRUE); + + amatch('{'); + + ds_clear(&tname); + ds_cat_str(&tname, get_temp_name()); + ds_cat_printf(&d_curr_line, "%s__%d <- (", ds_get_buf(&tname), adepth); + (void) ptab_add_line(ds_get_buf(&d_curr_line), TRUE); + ds_clear(&d_curr_line); + + bexpr(); + + end_pos = lx->lexer_pos; + if (ds_get_length(&d_curr_line) > 0) { + (void) ptab_add_line(ds_get_buf(&d_curr_line), TRUE); + } + ds_clear(&d_curr_line); + ds_cat_printf(&d_curr_line, ") -> %s__%d", ds_get_buf(&tname), adepth); + (void) ptab_add_line(ds_get_buf(&d_curr_line), TRUE); + ds_clear(&d_curr_line); + + amatch('}'); + + ds_free(&assign); + ds_free(&tname); + adepth--; + return end_pos; +} + +static PTABLE optimize_gen_tab(PTABLE pt) +{ + /* This function compacts the gen_tab, returning a new PTABLE. + Aliases are transformed and removed as described below. + Usually, optimized_gen_tab is called a second time on the + PTABLE created by the first call. The algorithm here will + only transform one level of aliases. + */ + TLINE t = NULL; + LEXER lxr = NULL; + int val, idnum = 0, tok_count = 0; + SYM_TAB entry = NULL, alias_tab = NULL; + BOOL found_tilde = FALSE, starts_with_temp = FALSE; + PTABLE new_gen = NULL; + DS_CREATE(scratch, LEX_BUF_SZ); + DS_CREATE(alias, 64); + DS_CREATE(non_tmp_name, 64); + DS_CREATE(tmp_name, 64); + + if (!pt || !pt->first) + return NULL; + t = pt->first; + lxr = new_lexer(t->line); + /* Look for tmp... = another_name + t1 = name1 (alias for t1) + t2 = name2 (alias for t2) + t3 = t1 op t2 + during second pass transform + ignore t1, t2 + t3 = name1 op name2 + */ + while (t) { + idnum = 0; + val = lexer_scan(lxr); + ds_clear(&alias); + entry = NULL; + found_tilde = FALSE; + if (find_temp_begin(t->line)) + starts_with_temp = TRUE; + else + starts_with_temp = FALSE; + tok_count = 0; + while (val != '\0') { + tok_count++; + if (val == LEX_ID) { + idnum++; + if (idnum == 1) { + entry = add_sym_tab_entry(lxr->lexer_buf, SYM_ID, + &alias_tab); + } else if (idnum == 2) { + ds_cat_str(&alias, lxr->lexer_buf); + } + } else if (val == '~') { + found_tilde = TRUE; + assert(tok_count == 3); + } else if (val == '=') { + assert(tok_count == 2); + } + val = lexer_scan(lxr); + } + if (starts_with_temp && !found_tilde && idnum == 2) + alias_sym_tab(ds_get_buf(&alias), entry); + t = t->next; + if (t) { + delete_lexer(lxr); + lxr = new_lexer(t->line); + } + } + ds_free(&alias); + delete_lexer(lxr); + + + /* Second pass, replace names by their aliases. + Perform transformation as mentioned above. + Transform: + t1 = t2 op t3 {op t4 ...} (t* can also be name*, not just tmps) + lhs = t1 (lhs of original x = { expr } statement) + into: + ignore lhs = t1 + lhs = t2 op t3 {op t4...} + NOTE that lhs_= t1 should be the last entry in gen_tab. + lhs = t1 (from stmt lhs = { expr }) is the top-most level + in the parse tree, and is encountered last in the evaluation order. + */ + new_gen = new_parse_table(); + ds_clear(&scratch); + t = pt->first; + lxr = new_lexer(t->line); + while (t) { // while (t) second pass + BOOL skip = FALSE; + + val = lexer_scan(lxr); + idnum = 0; + entry = NULL; + if (find_temp_begin(t->line)) + starts_with_temp = TRUE; + else + starts_with_temp = FALSE; + tok_count = 0; + ds_clear(&scratch); + ds_clear(&non_tmp_name); + ds_clear(&tmp_name); + while (val != '\0' && !skip) { + tok_count++; + if (val == LEX_ID) { + idnum++; + entry = member_sym_tab(lxr->lexer_buf, alias_tab); + if (entry && entry->alias) { + if (idnum > 1) { + ds_cat_printf(&scratch, "%s ", entry->alias); + } else if (idnum == 1) { + if (starts_with_temp) { + skip = TRUE; + } + } + } else { + ds_cat_printf(&scratch, "%s ", lxr->lexer_buf); + if (tok_count == 1) { + ds_clear(&non_tmp_name); + if (!find_temp_begin(lxr->lexer_buf)) + ds_cat_str(&non_tmp_name, lxr->lexer_buf); + } else if (tok_count == 3) { + if (ds_get_length(&non_tmp_name) > 0) { + char *str1 = NULL; + str1 = find_temp_begin(lxr->lexer_buf); + if (str1) { + ds_clear(&tmp_name); + ds_cat_str(&tmp_name, lxr->lexer_buf); + } + } + } + } + + if (idnum > 2) { + ds_clear(&non_tmp_name); + ds_clear(&tmp_name); + } + } else { + assert(val != LEX_OTHER); + if (val == '~') + found_tilde = TRUE; + ds_cat_printf(&scratch, "%c ", val); + } + val = lexer_scan(lxr); + } + t = t->next; + if (t) { + delete_lexer(lxr); + lxr = new_lexer(t->line); + } + if (!skip) { + TLINE tnamel = NULL; + char *p = NULL; + DS_CREATE(d_buf, 128); + BOOL ignore_lhs = FALSE; + + ds_clear(&d_buf); + if (ds_get_length(&tmp_name) > 0) + tnamel = tab_find(new_gen, ds_get_buf(&tmp_name), TRUE); + if (ds_get_length(&non_tmp_name) > 0 && tnamel) { + ignore_lhs = TRUE; + + ds_clear(&d_buf); + p = strstr(tnamel->line, " = "); + if (p) { + ds_cat_str(&d_buf, ds_get_buf(&non_tmp_name)); + ds_cat_str(&d_buf, p); + tfree(tnamel->line); + tnamel->line = TMALLOC(char, ds_get_length(&d_buf) + 1); + strcpy(tnamel->line, ds_get_buf(&d_buf)); + } + } + if (!ignore_lhs) { + (void) add_to_parse_table(new_gen, + ds_get_buf(&scratch), TRUE); + } + ds_free(&d_buf); + } + } // end of while (t) second pass + ds_free(&scratch); + ds_free(&non_tmp_name); + ds_free(&tmp_name); + delete_lexer(lxr); + { + int print_it = 0; + if (print_it) + print_sym_tab(alias_tab, FALSE); + } + delete_sym_tab(alias_tab); + + return new_gen; +} + +static void gen_gates(PTABLE gate_tab, SYM_TAB parser_symbols) +{ + /* gen_gates is called with PTABLE gate_tab being the final + PTABLE produced by optimize_gen_tab(,..) calls. + If gate tab is the orignal uncompacted gen_tab, then extra + redundant intermediate gates will be created. + */ + TLINE t; + LEXER lxr = NULL; + int val, tok_count = 0, gate_op = 0, idnum = 0, in_count = 0; + BOOL found_tilde = FALSE; + DS_CREATE(out_name, 64); + DS_CREATE(in_names, 64); + DS_CREATE(gate_name, 64); + DS_CREATE(instance, 128); + + if (!gate_tab || !gate_tab->first) + return; + t = gate_tab->first; + lxr = new_lexer(t->line); + while (t) { + ds_clear(&out_name); + ds_clear(&in_names); + ds_clear(&gate_name); + ds_clear(&instance); + idnum = 0; + val = lexer_scan(lxr); + found_tilde = FALSE; + tok_count = 0; + gate_op = 0; + in_count = 0; + while (val != '\0') { + tok_count++; + if (val == LEX_ID) { + idnum++; + if (idnum == 1) { //output name + ds_cat_str(&out_name, lxr->lexer_buf); + } else { // input name + in_count++; + ds_cat_printf(&in_names, " %s", lxr->lexer_buf); + } + } else if (val == '~') { + found_tilde = TRUE; + assert(tok_count == 3); + } else if (val == '=') { + assert(tok_count == 2); + } else if (lex_gate_op(val)) { + if (gate_op != 0) + assert(val == gate_op); + gate_op = val; + } else { + assert(FALSE); + } + val = lexer_scan(lxr); + } + if (in_count == 1) { // buffer or inverter + assert(gate_op == 0); + ds_cat_str(&gate_name, lex_gate_name('~', found_tilde)); + } else if (in_count >= 2) { // AND, OR. XOR and inverses + assert(gate_op != 0); + ds_cat_str(&gate_name, lex_gate_name(gate_op, found_tilde)); + } else { + assert(FALSE); + } + ds_cat_printf(&instance, "%s ", get_inst_name()); + if (in_count == 1) { + /* If the input name is inv_out_ use the + and instantiate an inverter to avoid an extra buffer. + */ + char *tail = NULL; + SYM_TAB ent; + tail = get_inv_tail(ds_get_buf(&in_names)); + if (tail && strlen(tail) > 0) { + ds_clear(&gate_name); + ds_cat_str(&gate_name, lex_gate_name('~', TRUE)); + ds_cat_printf(&instance, "%s %s ", tail, + ds_get_buf(&out_name)); + ent = member_sym_tab(tail, parser_symbols); + assert(ent); + assert(ent->attribute & SYM_INVERTER); + ent->ref_count--; + } else { + ds_cat_printf(&instance, "%s %s ", ds_get_buf(&in_names), + ds_get_buf(&out_name)); + } + + } else { + ds_cat_printf(&instance, "[%s ] %s ", ds_get_buf(&in_names), + ds_get_buf(&out_name)); + } + ds_cat_printf(&instance, "%s", ds_get_buf(&gate_name)); + t = t->next; + if (t) { + delete_lexer(lxr); + lxr = new_lexer(t->line); + } + + printf("%s\n", ds_get_buf(&instance)); + } + delete_lexer(lxr); + ds_free(&out_name); + ds_free(&in_names); + ds_free(&gate_name); + ds_free(&instance); +} + +/* + gen_tab lines format: + name1 = [~] name2 [op name3 {op namei}+] + [] means optional, {}+ means zero or more times. + op is gate type (&, |, ^), ~ means invert output. + name1 is the gate output, and name2,... are inputs. + & is AND, | is OR, ^ is XOR. + ~ & is NAND, ~ | is NOR, ~ ^ is XNOR. + In any given line, all the op values are the same, and don't change. + AND and OR can have >= 2 inputs, XOR can have only 2 inputs. + If there is only a single input, then the gate is BUF or INV(~). +*/ +static void bevaluate(TLINE t, int deep) +{ + /* TLINE t is the entry in the parse_tab and deep is the call depth + where the parse_tab is transformed into the gen_tab. The deeper + calls are evaluated first, bottom-up, as determined by beval_order. + The tokens in the parse_tab are reassembled into gen_tab lines + as described above. + */ + char *s; + int down = 0; + DS_CREATE(this, 64); + DS_CREATE(other, 64); + DS_CREATE(new_line, LEX_BUF_SZ); + + s = find_temp_begin(t->line); + if (!s) + return; + ds_clear(&other); + ds_clear(&new_line); + ds_clear(&this); + ds_cat_str(&this, s); + if (strstr(t->line + ds_get_length(&this), " ~ ")) { + ds_cat_printf(&new_line, "%s = ~ ", ds_get_buf(&this)); + } else { + if (deep == 1) + ds_cat_printf(&new_line, "%s ", parse_tab->first->line); + else + ds_cat_printf(&new_line, "%s = ", ds_get_buf(&this)); + } + t = t->next; + while (t) { + s = find_temp_anywhere(t->line); + if (s) { + if (strcmp(ds_get_buf(&this), s) == 0) { + break; + } else { + if (down == 0) { + s = find_temp_begin(t->line); + ds_clear(&other); + ds_cat_str(&other, s); + down = 1; + ds_cat_printf(&new_line, " %s", ds_get_buf(&other)); + } else if (down == 1) { + s = find_temp_anywhere(t->line); + if (strcmp(ds_get_buf(&other), s) == 0) { + down = 0; + ds_clear(&other); + } + } + } + } else if (down == 0) { + s = find_temp_anywhere(t->line); + if (!s) { + ds_cat_printf(&new_line, " %s", t->line); + } + } + t = t->next; + } + (void) gen_tab_add_line(ds_get_buf(&new_line), TRUE); + ds_free(&this); + ds_free(&other); + ds_free(&new_line); +} + +static void beval_order(void) +{ + /* The parser is top-down recursive descent. The depth is used + so that the parsed data is evaluated bottom-up. Then the + tmp.. regions can be evaluated before they are referenced. + */ + int i, depth; + TLINE t; + size_t slen; + + if (!parse_tab || !parse_tab->first) + return; + slen = strlen("tmp"); + for (i = max_adepth; i > 0; i--) { + t = parse_tab->first; + while (t) { + char *q; + int cmp = 0; + cmp = strncmp(t->line, "tmp", slen); + if (cmp == 0 && ((q = strstr(t->line, " <- ")) != NULL)) { + depth = get_temp_depth(t->line); + if (depth >= 0) { + if (i == depth) { + bevaluate(t, i); + } + } + } + t = t->next; + } + } +} + +static void bparse(char *line, BOOL new_lexer) +{ + int start_pos = 0, end_pos = 0, stmt_num = 0; + LEXER lx; + PTABLE opt_tab1 = NULL, opt_tab2 = NULL; + DS_CREATE(stmt, LEX_BUF_SZ); + char *seed_buf; + + seed_buf = TMALLOC(char, LEX_BUF_SZ); + (void) memcpy(seed_buf, "seed", strlen("seed")); + + ds_init(&d_curr_line, seed_buf, strlen("seed"), + LEX_BUF_SZ, ds_buf_type_heap); + ds_clear(&d_curr_line); + + if (new_lexer) + lex_init(line); + assert(parse_lexer); + lx = parse_lexer; + lookahead = lex_set_start("logic:"); + lookahead = lex_scan(); // "logic" + lookahead = lex_scan(); // ':' + lookahead = lex_scan(); + while (lookahead != '\0') { + init_parse_tables(); + adepth = max_adepth = 0; + stmt_num++; + start_pos = lx->lexer_pos; + ds_clear(&stmt); + ds_cat_str(&stmt, lx->lexer_buf); + end_pos = bstmt(); + + ds_cat_mem(&stmt, &lx->lexer_line[start_pos], end_pos - start_pos); + printf("\n* Stmt(%d): %s\n\n", stmt_num, ds_get_buf(&stmt)); + + beval_order(); + + opt_tab1 = optimize_gen_tab(gen_tab); + opt_tab2 = optimize_gen_tab(opt_tab1); + if (opt_tab2) { + gen_gates(opt_tab2, parse_lexer->lexer_sym_tab); + } + delete_parse_table(opt_tab1); + delete_parse_table(opt_tab2); + delete_parse_gen_tables(); + } + + ds_free(&d_curr_line); + gen_inverters(lx->lexer_sym_tab); + gen_models(); + ds_free(&stmt); +#define TRACE +#ifdef TRACE + if (!new_lexer) + print_sym_tab(lx->lexer_sym_tab, FALSE); +#endif + delete_lexer(lx); +} +/* End of logicexp parser */ + +static BOOL expect_token( + int tok, int expected_tok, char *expected_str, BOOL msg) +{ + if (tok != expected_tok) { + if (msg) { + printf("ERROR expect_token failed tok %d expected_tok %d\n", + tok, expected_tok); + } + delete_lexer(parse_lexer); + return FALSE; + } + if (tok == LEX_ID) { + if (expected_str) { + if (eq(expected_str, parse_lexer->lexer_buf)) + return TRUE; + else { + if (msg) { + printf( + "ERROR expect_token failed lexer_buf %s expected_str %s\n", + parse_lexer->lexer_buf, expected_str); + } + delete_lexer(parse_lexer); + return FALSE; + } + } else { // Any LEX_ID string matches + return TRUE; + } + } + return TRUE; +} + +BOOL f_logicexp(char *line) +{ + int t, num_ins = 0, num_outs = 0, i; + char *endp; + + printf("\nf_logicexp: %s\n", line); + lex_init(line); + (void) add_sym_tab_entry("logic", SYM_KEY_WORD, + &parse_lexer->lexer_sym_tab); + t = lex_scan(); // U* + if (!expect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + /* logicexp ( int , int ) */ + t = lex_scan(); + if (!expect_token(t, LEX_ID, "logicexp", TRUE)) return FALSE; + t = lex_scan(); + if (!expect_token(t, '(', NULL, TRUE)) return FALSE; + t = lex_scan(); + if (!expect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + if (lex_all_digits(parse_lexer->lexer_buf)) { + num_ins = (int) strtol(parse_lexer->lexer_buf, &endp, 10); + } else { + printf("ERROR logicexp input count is not an integer\n"); + return FALSE; + } + t = lex_scan(); + if (!expect_token(t, ',', NULL, TRUE)) return FALSE; + t = lex_scan(); + if (!expect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + if (lex_all_digits(parse_lexer->lexer_buf)) { + num_outs = (int) strtol(parse_lexer->lexer_buf, &endp, 10); + } else { + printf("ERROR logicexp output count is not an integer\n"); + return FALSE; + } + num_outs = (int) strtol(parse_lexer->lexer_buf, &endp, 10); + t = lex_scan(); + if (!expect_token(t, ')', NULL, TRUE)) return FALSE; + t = lex_scan(); // pwr + if (!expect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + t = lex_scan(); // gnd + if (!expect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + /* num_ins input ids */ + for (i = 0; i < num_ins; i++) { + t = lex_scan(); + if (!expect_token(t, LEX_ID, NULL, TRUE)) { + return FALSE; + } + (void) add_sym_tab_entry(parse_lexer->lexer_buf, + SYM_INPUT, &parse_lexer->lexer_sym_tab); + } + /* num_outs output ids */ + for (i = 0; i < num_outs; i++) { + t = lex_scan(); + if (!expect_token(t, LEX_ID, NULL, TRUE)) { + return FALSE; + } + (void) add_sym_tab_entry(parse_lexer->lexer_buf, + SYM_OUTPUT, &parse_lexer->lexer_sym_tab); + } + /* timing model */ + t = lex_scan(); + if (!expect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + printf("TMODEL: %s\n", parse_lexer->lexer_buf); + (void) add_sym_tab_entry(parse_lexer->lexer_buf, + SYM_TMODEL, &parse_lexer->lexer_sym_tab); + bparse(line, FALSE); + + return TRUE; +} + +BOOL f_pindly(char *line) +{ + printf("\nf_pindly: %s\n", line); + return FALSE; +} + diff --git a/src/frontend/udevices.c b/src/frontend/udevices.c index a4cc2ec02..a4ed6539a 100644 --- a/src/frontend/udevices.c +++ b/src/frontend/udevices.c @@ -54,6 +54,7 @@ #include "ngspice/cpextern.h" #include "ngspice/macros.h" #include "ngspice/udevices.h" +#include "ngspice/logicexp.h" extern struct card* insert_new_line( struct card* card, char* line, int linenum, int linenum_orig); @@ -3433,7 +3434,13 @@ BOOL u_check_instance(char *line) printf("WARNING "); printf("Instance %s type %s is not supported\n", hdr->instance_name, itype); - if (ps_udevice_msgs >= 2) { + if (eq(itype, "logicexp")) { + if (ps_udevice_msgs == 3) + (void) f_logicexp(line); + } else if (eq(itype, "pindly")) { + if (ps_udevice_msgs == 3) + (void) f_pindly(line); + } else if (ps_udevice_msgs == 3) { printf("%s\n", line); } } diff --git a/src/include/ngspice/logicexp.h b/src/include/ngspice/logicexp.h new file mode 100644 index 000000000..556835a43 --- /dev/null +++ b/src/include/ngspice/logicexp.h @@ -0,0 +1,9 @@ +/* logicexp.h */ + +#ifndef INCLUDED_LOGICEXP_H +#define INCLUDED_LOGICEXP_H + +BOOL f_logicexp(char *line); +BOOL f_pindly(char *line); + +#endif From a27ae48e27233b0ae7ab2e2a0d45634785e082f5 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Fri, 21 Oct 2022 15:49:12 -0700 Subject: [PATCH 04/19] Fix potential memory leak. --- src/frontend/logicexp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index 328347c94..d41649154 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -1302,6 +1302,7 @@ BOOL f_logicexp(char *line) num_ins = (int) strtol(parse_lexer->lexer_buf, &endp, 10); } else { printf("ERROR logicexp input count is not an integer\n"); + delete_lexer(parse_lexer); return FALSE; } t = lex_scan(); @@ -1312,6 +1313,7 @@ BOOL f_logicexp(char *line) num_outs = (int) strtol(parse_lexer->lexer_buf, &endp, 10); } else { printf("ERROR logicexp output count is not an integer\n"); + delete_lexer(parse_lexer); return FALSE; } num_outs = (int) strtol(parse_lexer->lexer_buf, &endp, 10); From 9d239dc2f7700abcce723d39ae87d550a2645835 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Fri, 21 Oct 2022 22:14:41 -0700 Subject: [PATCH 05/19] Move f_logicexp, f_pindly calls to u_process_instance. Use u_add_instance to copy gate instances and models to the replacement cards. --- src/frontend/logicexp.c | 66 ++++++++++++++++++++++++++-------- src/frontend/udevices.c | 38 +++++++++++++++----- src/include/ngspice/udevices.h | 1 + 3 files changed, 82 insertions(+), 23 deletions(-) diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index d41649154..f7966da51 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -3,17 +3,6 @@ #include #include -//#define LOCAL_BUILD -#ifdef LOCAL_BUILD -#include "ngspice/ngspice/memory.h" -#include "ngspice/ngspice/macros.h" -#include "ngspice/ngspice/bool.h" -#include "ngspice/ngspice/ngspice.h" -#include "ngspice/ngspice/stringskip.h" -#include "ngspice/ngspice/stringutil.h" -#include "ngspice/ngspice/dstring.h" -#include "logicexp.h" -#else #include "ngspice/memory.h" #include "ngspice/macros.h" #include "ngspice/bool.h" @@ -22,7 +11,7 @@ #include "ngspice/stringutil.h" #include "ngspice/dstring.h" #include "ngspice/logicexp.h" -#endif +#include "ngspice/udevices.h" /* Start of btree symbol table */ #define SYM_INPUT 1 @@ -594,6 +583,7 @@ static char *get_inv_tail(char *str) static void gen_inverters(SYM_TAB t) { + DS_CREATE(instance, 128); if (t == NULL) return; gen_inverters(t->left); @@ -601,13 +591,21 @@ static void gen_inverters(SYM_TAB t) if (t->ref_count >= 1) { printf("%s %s %s d_inv_zero_delay\n", get_inst_name(), t->name, get_inverter_output_name(t->name)); + + ds_clear(&instance); + ds_cat_printf(&instance, "%s %s %s d_inv_zero_delay", + get_inst_name(), t->name, get_inverter_output_name(t->name)); + u_add_instance(ds_get_buf(&instance)); } } + ds_free(&instance); gen_inverters(t->right); } static void gen_models(void) { + DS_CREATE(model, 64); + printf(".model d_inv_zero_delay d_inverter\n"); printf(".model d__inverter__1 d_inverter\n"); printf(".model d__buffer__1 d_buffer\n"); @@ -617,6 +615,44 @@ static void gen_models(void) printf(".model d__xor__1 d_xor\n"); printf(".model d__nor__1 d_nor\n"); printf(".model d__or__1 d_or\n"); + + ds_clear(&model); + ds_cat_printf(&model, ".model d_inv_zero_delay d_inverter"); + u_add_instance(ds_get_buf(&model)); + + ds_clear(&model); + ds_cat_printf(&model, ".model d__inverter__1 d_inverter"); + u_add_instance(ds_get_buf(&model)); + + ds_clear(&model); + ds_cat_printf(&model, ".model d__buffer__1 d_buffer"); + u_add_instance(ds_get_buf(&model)); + + ds_clear(&model); + ds_cat_printf(&model, ".model d__nand__1 d_nand"); + u_add_instance(ds_get_buf(&model)); + + ds_clear(&model); + ds_cat_printf(&model, ".model d__and__1 d_and"); + u_add_instance(ds_get_buf(&model)); + + ds_clear(&model); + ds_cat_printf(&model, ".model d__xnor__1 d_xnor"); + u_add_instance(ds_get_buf(&model)); + + ds_clear(&model); + ds_cat_printf(&model, ".model d__xor__1 d_xor"); + u_add_instance(ds_get_buf(&model)); + + ds_clear(&model); + ds_cat_printf(&model, ".model d__nor__1 d_nor"); + u_add_instance(ds_get_buf(&model)); + + ds_clear(&model); + ds_cat_printf(&model, ".model d__or__1 d_or"); + u_add_instance(ds_get_buf(&model)); + + ds_free(&model); } static void aerror(char *s) @@ -1073,6 +1109,8 @@ static void gen_gates(PTABLE gate_tab, SYM_TAB parser_symbols) } printf("%s\n", ds_get_buf(&instance)); + + u_add_instance(ds_get_buf(&instance)); } delete_lexer(lxr); ds_free(&out_name); @@ -1354,7 +1392,7 @@ BOOL f_logicexp(char *line) BOOL f_pindly(char *line) { - printf("\nf_pindly: %s\n", line); - return FALSE; + //printf("\nf_pindly: %s\n", line); + return TRUE; } diff --git a/src/frontend/udevices.c b/src/frontend/udevices.c index a4ed6539a..06c10b70e 100644 --- a/src/frontend/udevices.c +++ b/src/frontend/udevices.c @@ -764,6 +764,16 @@ struct card *replacement_udevice_cards(void) return newcard; } +void u_add_instance(char *str) +{ + Xlatep x; + + if (str && strlen(str) > 0) { + x = create_xlate_translated(str); + (void) add_xlator(translated_p, x); + } +} + void initialize_udevice(char *subckt_line) { Xlatep xdata; @@ -3426,6 +3436,11 @@ BOOL u_check_instance(char *line) itype = hdr->instance_type; xspice = find_xspice_for_delay(itype); if (!xspice) { + if (eq(itype, "logicexp") || eq(itype, "pindly") + || eq(itype, "constraint")) { + delete_instance_hdr(hdr); + return TRUE; + } if (ps_udevice_msgs >= 1) { if (current_subckt && subckt_msg_count == 0) { printf("%s\n", current_subckt); @@ -3434,13 +3449,7 @@ BOOL u_check_instance(char *line) printf("WARNING "); printf("Instance %s type %s is not supported\n", hdr->instance_name, itype); - if (eq(itype, "logicexp")) { - if (ps_udevice_msgs == 3) - (void) f_logicexp(line); - } else if (eq(itype, "pindly")) { - if (ps_udevice_msgs == 3) - (void) f_pindly(line); - } else if (ps_udevice_msgs == 3) { + if (ps_udevice_msgs >= 2) { printf("%s\n", line); } } @@ -3467,8 +3476,19 @@ BOOL u_process_instance(char *nline) itype = hdr->instance_type; xspice = find_xspice_for_delay(itype); if (!xspice) { - delete_instance_hdr(hdr); - return FALSE; + if (eq(itype, "logicexp")) { + delete_instance_hdr(hdr); + return f_logicexp(nline); + } else if (eq(itype, "pindly")) { + delete_instance_hdr(hdr); + return f_pindly(nline); + } else if (eq(itype, "constraint")) { + delete_instance_hdr(hdr); + return TRUE; + } else { + delete_instance_hdr(hdr); + return FALSE; + } } if (ps_port_directions >= 2) { printf("TRANS_IN %s\n", nline); diff --git a/src/include/ngspice/udevices.h b/src/include/ngspice/udevices.h index 2c0a6c085..6f734e588 100644 --- a/src/include/ngspice/udevices.h +++ b/src/include/ngspice/udevices.h @@ -7,5 +7,6 @@ BOOL u_check_instance(char *line); void initialize_udevice(char *subckt_line); struct card *replacement_udevice_cards(void); void cleanup_udevice(void); +void u_add_instance(char *str); #endif From 3eb0a089e581fb25ea7f4eee58d8fa1c27f6bc81 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Sun, 23 Oct 2022 17:04:37 -0700 Subject: [PATCH 06/19] Initial handling of PINDLY. Output buffers without rise/fall delay estimates. --- src/frontend/logicexp.c | 221 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 212 insertions(+), 9 deletions(-) diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index f7966da51..e3f00ea13 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -1,3 +1,9 @@ +/* + logicexp.c + + Convert PSpice LOGICEXP logic expressions into XSPICE gates. + Extract timing delay estimates from PINDLY statements. +*/ #include #include #include @@ -13,6 +19,8 @@ #include "ngspice/logicexp.h" #include "ngspice/udevices.h" +/* #define TRACE */ + /* Start of btree symbol table */ #define SYM_INPUT 1 #define SYM_OUTPUT 2 @@ -525,6 +533,21 @@ static TLINE tab_find(PTABLE pt, char *str, BOOL start_of_line) } return NULL; } + +//#define TABLE_PRINT +#ifdef TABLE_PRINT +static void table_print(TLINE first) +{ + TLINE t; + if (!first) + return; + t = first; + while (t) { + printf("%s\n", t->line); + t = t->next; + } +} +#endif /* End parse table */ /* Start of logicexp parser */ @@ -589,12 +612,12 @@ static void gen_inverters(SYM_TAB t) gen_inverters(t->left); if (t->attribute & SYM_INVERTER) { if (t->ref_count >= 1) { - printf("%s %s %s d_inv_zero_delay\n", get_inst_name(), - t->name, get_inverter_output_name(t->name)); - ds_clear(&instance); ds_cat_printf(&instance, "%s %s %s d_inv_zero_delay", get_inst_name(), t->name, get_inverter_output_name(t->name)); +#ifdef TRACE + printf("%s\n", ds_get_buf(&instance)); +#endif u_add_instance(ds_get_buf(&instance)); } } @@ -606,6 +629,7 @@ static void gen_models(void) { DS_CREATE(model, 64); +#ifdef TRACE printf(".model d_inv_zero_delay d_inverter\n"); printf(".model d__inverter__1 d_inverter\n"); printf(".model d__buffer__1 d_buffer\n"); @@ -615,6 +639,7 @@ static void gen_models(void) printf(".model d__xor__1 d_xor\n"); printf(".model d__nor__1 d_nor\n"); printf(".model d__or__1 d_or\n"); +#endif ds_clear(&model); ds_cat_printf(&model, ".model d_inv_zero_delay d_inverter"); @@ -1107,9 +1132,9 @@ static void gen_gates(PTABLE gate_tab, SYM_TAB parser_symbols) delete_lexer(lxr); lxr = new_lexer(t->line); } - +#ifdef TRACE printf("%s\n", ds_get_buf(&instance)); - +#endif u_add_instance(ds_get_buf(&instance)); } delete_lexer(lxr); @@ -1259,8 +1284,13 @@ static void bparse(char *line, BOOL new_lexer) ds_cat_str(&stmt, lx->lexer_buf); end_pos = bstmt(); +#ifdef TRACE ds_cat_mem(&stmt, &lx->lexer_line[start_pos], end_pos - start_pos); printf("\n* Stmt(%d): %s\n\n", stmt_num, ds_get_buf(&stmt)); +#else + (void) start_pos; + (void) end_pos; +#endif beval_order(); @@ -1278,7 +1308,6 @@ static void bparse(char *line, BOOL new_lexer) gen_inverters(lx->lexer_sym_tab); gen_models(); ds_free(&stmt); -#define TRACE #ifdef TRACE if (!new_lexer) print_sym_tab(lx->lexer_sym_tab, FALSE); @@ -1323,7 +1352,9 @@ BOOL f_logicexp(char *line) int t, num_ins = 0, num_outs = 0, i; char *endp; +#ifdef TRACE printf("\nf_logicexp: %s\n", line); +#endif lex_init(line); (void) add_sym_tab_entry("logic", SYM_KEY_WORD, &parse_lexer->lexer_sym_tab); @@ -1354,7 +1385,6 @@ BOOL f_logicexp(char *line) delete_lexer(parse_lexer); return FALSE; } - num_outs = (int) strtol(parse_lexer->lexer_buf, &endp, 10); t = lex_scan(); if (!expect_token(t, ')', NULL, TRUE)) return FALSE; t = lex_scan(); // pwr @@ -1382,7 +1412,7 @@ BOOL f_logicexp(char *line) /* timing model */ t = lex_scan(); if (!expect_token(t, LEX_ID, NULL, TRUE)) return FALSE; - printf("TMODEL: %s\n", parse_lexer->lexer_buf); + //printf("TMODEL: %s\n", parse_lexer->lexer_buf); (void) add_sym_tab_entry(parse_lexer->lexer_buf, SYM_TMODEL, &parse_lexer->lexer_sym_tab); bparse(line, FALSE); @@ -1390,9 +1420,182 @@ BOOL f_logicexp(char *line) return TRUE; } +/* pindly handling */ +static PTABLE ios_in_tab = NULL; +static PTABLE ios_out_tab = NULL; + +static void init_ios_tab(void) +{ + ios_in_tab = new_parse_table(); + ios_out_tab = new_parse_table(); +} + +static void cleanup_pindly(void) +{ + delete_parse_table(ios_in_tab); + delete_parse_table(ios_out_tab); + ios_in_tab = NULL; + ios_out_tab = NULL; +} + +static TLINE ios_tab_add(char *ioname, BOOL is_input) +{ + if (is_input) + return add_to_parse_table(ios_in_tab, ioname, TRUE); + else + return add_to_parse_table(ios_out_tab, ioname, TRUE); +} + +static void print_ios_tabs(void) +{ +#ifdef TABLE_PRINT + if (ios_in_tab) { + printf("ios_in_tab\n"); + table_print(ios_in_tab->first); + } + if (ios_out_tab) { + printf("ios_out_tab\n"); + table_print(ios_out_tab->first); + } +#endif +} + +static void gen_output_buffers(void) +{ + TLINE tin, tout; + if (ios_in_tab && ios_out_tab) { + if (!ios_in_tab->first || !ios_out_tab->first) { + return; + } else { + DS_CREATE(instance, 128); + tin = ios_in_tab->first; + tout = ios_out_tab->first; + while (tin && tout) { + ds_clear(&instance); + ds_cat_printf(&instance, "%s %s %s d_pindly_buf", + get_inst_name(), tin->line, tout->line); + u_add_instance(ds_get_buf(&instance)); + tin = tin->next; + tout = tout->next; + } + u_add_instance( + ".model d_pindly_buf d_buffer(rise_delay=10ns fall_delay=10ns)"); + ds_free(&instance); + } + } +} + +static BOOL pexpect_token( + int tok, int expected_tok, char *expected_str, BOOL msg) +{ + BOOL val; + val = expect_token(tok, expected_tok, expected_str, msg); + if (!val) + cleanup_pindly(); + return val; +} + BOOL f_pindly(char *line) { - //printf("\nf_pindly: %s\n", line); + int t, num_ios = 0, num_refs = 0, num_ena = 0, i; + char *endp; + +#ifdef TRACE + printf("\nf_pindly: %s\n", line); +#endif + init_ios_tab(); + lex_init(line); + t = lex_scan(); // U* + if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + + /* pindly ( int , int, int ) */ + t = lex_scan(); + if (!pexpect_token(t, LEX_ID, "pindly", TRUE)) return FALSE; + + t = lex_scan(); + if (!pexpect_token(t, '(', NULL, TRUE)) return FALSE; + + t = lex_scan(); + if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + if (lex_all_digits(parse_lexer->lexer_buf)) { + num_ios = (int) strtol(parse_lexer->lexer_buf, &endp, 10); + } else { + printf("ERROR pindly io count is not an integer\n"); + delete_lexer(parse_lexer); + cleanup_pindly(); + return FALSE; + } + + t = lex_scan(); + if (!pexpect_token(t, ',', NULL, TRUE)) return FALSE; + + t = lex_scan(); + if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + if (lex_all_digits(parse_lexer->lexer_buf)) { + num_ena = (int) strtol(parse_lexer->lexer_buf, &endp, 10); + } else { + printf("ERROR pindly enable count is not an integer\n"); + delete_lexer(parse_lexer); + cleanup_pindly(); + return FALSE; + } + if (num_ena != 0) { + delete_lexer(parse_lexer); + cleanup_pindly(); + return FALSE; + } + + t = lex_scan(); + if (!pexpect_token(t, ',', NULL, TRUE)) return FALSE; + + t = lex_scan(); + if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + if (lex_all_digits(parse_lexer->lexer_buf)) { + num_refs = (int) strtol(parse_lexer->lexer_buf, &endp, 10); + } else { + printf("ERROR pindly refs count is not an integer\n"); + delete_lexer(parse_lexer); + cleanup_pindly(); + return FALSE; + } + + t = lex_scan(); + if (!pexpect_token(t, ')', NULL, TRUE)) return FALSE; + + t = lex_scan(); // pwr + if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + t = lex_scan(); // gnd + if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + + /* num_ios input ids */ + for (i = 0; i < num_ios; i++) { + t = lex_scan(); + if (!pexpect_token(t, LEX_ID, NULL, TRUE)) { + return FALSE; + } + (void) ios_tab_add(parse_lexer->lexer_buf, TRUE); + } + + /* num_refs reference nodes which are ignored */ + for (i = 0; i < num_refs; i++) { + t = lex_scan(); + if (!pexpect_token(t, LEX_ID, NULL, TRUE)) { + return FALSE; + } + } + /* num_ios output ids */ + for (i = 0; i < num_ios; i++) { + t = lex_scan(); + if (!pexpect_token(t, LEX_ID, NULL, TRUE)) { + return FALSE; + } + (void) ios_tab_add(parse_lexer->lexer_buf, FALSE); + } + + print_ios_tabs(); + gen_output_buffers(); + delete_lexer(parse_lexer); + cleanup_pindly(); return TRUE; } From 629010b1cb061fe8913a3150818726932cd9be63 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Mon, 24 Oct 2022 15:37:24 -0700 Subject: [PATCH 07/19] Improve delay estimates for pindly output buffers. --- src/frontend/logicexp.c | 305 ++++++++++++++++++++++++++++------------ 1 file changed, 215 insertions(+), 90 deletions(-) diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index e3f00ea13..e23dc2a70 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -224,6 +224,7 @@ static int lex_punct(int c) case '(': case ')': case ':': + case '.': return c; default: break; @@ -1316,6 +1317,8 @@ static void bparse(char *line, BOOL new_lexer) } /* End of logicexp parser */ +static LEXER current_lexer = NULL; + static BOOL expect_token( int tok, int expected_tok, char *expected_str, BOOL msg) { @@ -1324,20 +1327,19 @@ static BOOL expect_token( printf("ERROR expect_token failed tok %d expected_tok %d\n", tok, expected_tok); } - delete_lexer(parse_lexer); return FALSE; } if (tok == LEX_ID) { if (expected_str) { - if (eq(expected_str, parse_lexer->lexer_buf)) + LEXER lx = current_lexer; + if (strcmp(expected_str, lx->lexer_buf) == 0) return TRUE; else { if (msg) { printf( "ERROR expect_token failed lexer_buf %s expected_str %s\n", - parse_lexer->lexer_buf, expected_str); + lx->lexer_buf, expected_str); } - delete_lexer(parse_lexer); return FALSE; } } else { // Any LEX_ID string matches @@ -1356,68 +1358,69 @@ BOOL f_logicexp(char *line) printf("\nf_logicexp: %s\n", line); #endif lex_init(line); + current_lexer = parse_lexer; (void) add_sym_tab_entry("logic", SYM_KEY_WORD, &parse_lexer->lexer_sym_tab); t = lex_scan(); // U* - if (!expect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; /* logicexp ( int , int ) */ t = lex_scan(); - if (!expect_token(t, LEX_ID, "logicexp", TRUE)) return FALSE; + if (!expect_token(t, LEX_ID, "logicexp", TRUE)) goto error_return; t = lex_scan(); - if (!expect_token(t, '(', NULL, TRUE)) return FALSE; + if (!expect_token(t, '(', NULL, TRUE)) goto error_return; t = lex_scan(); - if (!expect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; if (lex_all_digits(parse_lexer->lexer_buf)) { num_ins = (int) strtol(parse_lexer->lexer_buf, &endp, 10); } else { printf("ERROR logicexp input count is not an integer\n"); - delete_lexer(parse_lexer); - return FALSE; + goto error_return; } t = lex_scan(); - if (!expect_token(t, ',', NULL, TRUE)) return FALSE; + if (!expect_token(t, ',', NULL, TRUE)) goto error_return; t = lex_scan(); - if (!expect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; if (lex_all_digits(parse_lexer->lexer_buf)) { num_outs = (int) strtol(parse_lexer->lexer_buf, &endp, 10); } else { printf("ERROR logicexp output count is not an integer\n"); - delete_lexer(parse_lexer); - return FALSE; + goto error_return; } t = lex_scan(); - if (!expect_token(t, ')', NULL, TRUE)) return FALSE; + if (!expect_token(t, ')', NULL, TRUE)) goto error_return; t = lex_scan(); // pwr - if (!expect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; t = lex_scan(); // gnd - if (!expect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; /* num_ins input ids */ for (i = 0; i < num_ins; i++) { t = lex_scan(); - if (!expect_token(t, LEX_ID, NULL, TRUE)) { - return FALSE; - } + if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; (void) add_sym_tab_entry(parse_lexer->lexer_buf, SYM_INPUT, &parse_lexer->lexer_sym_tab); } /* num_outs output ids */ for (i = 0; i < num_outs; i++) { t = lex_scan(); - if (!expect_token(t, LEX_ID, NULL, TRUE)) { - return FALSE; - } + if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; (void) add_sym_tab_entry(parse_lexer->lexer_buf, SYM_OUTPUT, &parse_lexer->lexer_sym_tab); } /* timing model */ t = lex_scan(); - if (!expect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; //printf("TMODEL: %s\n", parse_lexer->lexer_buf); (void) add_sym_tab_entry(parse_lexer->lexer_buf, SYM_TMODEL, &parse_lexer->lexer_sym_tab); bparse(line, FALSE); + current_lexer = NULL; return TRUE; + +error_return: + delete_lexer(parse_lexer); + current_lexer = NULL; + return FALSE; } /* pindly handling */ @@ -1478,124 +1481,246 @@ static void gen_output_buffers(void) tin = tin->next; tout = tout->next; } - u_add_instance( - ".model d_pindly_buf d_buffer(rise_delay=10ns fall_delay=10ns)"); ds_free(&instance); } } } - -static BOOL pexpect_token( - int tok, int expected_tok, char *expected_str, BOOL msg) +static char *get_typ_estimate(char *min, char *typ, char *max) { - BOOL val; - val = expect_token(tok, expected_tok, expected_str, msg); - if (!val) - cleanup_pindly(); - return val; + char *tmpmax = NULL, *tmpmin = NULL; + float valmin, valmax, average; + char *units1, *units2; + static char tbuf[128]; + + if (typ && strlen(typ) > 0 && typ[0] != '-') { + strcpy(tbuf, typ); + return tbuf; + } + if (max && strlen(max) > 0 && max[0] != '-') { + tmpmax = max; + } + if (min && strlen(min) > 0 && min[0] != '-') { + tmpmin = min; + } + if (tmpmin && tmpmax) { + if (strlen(tmpmin) > 0 && strlen(tmpmax) > 0) { + valmin = strtof(tmpmin, &units1); + valmax = strtof(tmpmax, &units2); + average = (valmin + valmax) / (float)2.0; + sprintf(tbuf, "%.2f%s", average, units2); + if (strcmp(units1, units2) != 0) { + printf("WARNING units do not match\n"); + } + return tbuf; + } + } else if (tmpmax && strlen(tmpmax) > 0) { + strcpy(tbuf, tmpmax); + return tbuf; + } else if (tmpmin && strlen(tmpmin) > 0) { + strcpy(tbuf, tmpmin); + return tbuf; + } else { + return NULL; + } + return NULL; +} + +static void gen_output_models(LEXER lx) +{ + int val, which = 0; + BOOL in_delay = FALSE; + float typ_max_val = 0.0, typ_val = 0.0; + char *units; + DS_CREATE(dmin, 16); + DS_CREATE(dtyp, 16); + DS_CREATE(dmax, 16); + DS_CREATE(dtyp_max_str, 16); + DSTRINGPTR dsp = NULL; + + val = lexer_set_start("pindly:", lx); + val = lexer_scan(lx); // "pindly" + val = lexer_scan(lx); // ':' + val = lexer_scan(lx); + while (val != '\0') { + if (val == LEX_ID) { + if (strcmp(lx->lexer_buf, "delay") == 0) { + ds_clear(&dmin); + ds_clear(&dtyp); + ds_clear(&dmax); + in_delay = TRUE; + } +#ifdef TRACE + printf("ID: \"%s\"\n", lx->lexer_buf); + } else if (val == LEX_OTHER) { + printf("OTHER: \"%s\"\n", lx->lexer_buf); + } else { + printf("TOK: %d <%c>\n", val, val); +#endif + } + if (in_delay) { + switch (which) { + case 0: + dsp = &dmin; + break; + case 1: + dsp = &dtyp; + break; + case 2: + dsp = &dmax; + break; + default: + assert(FALSE); + break; + }; + if (val == '.') + ds_cat_printf(dsp, "%c", val); + else if (val == LEX_ID && strcmp(lx->lexer_buf, "delay") != 0) + ds_cat_printf(dsp, "%s", lx->lexer_buf); + if (val == ',') { + which++; + } + } + if (val == ')') { + if (in_delay) { + char *s; + s = get_typ_estimate(ds_get_buf(&dmin), + ds_get_buf(&dtyp), ds_get_buf(&dmax)); +#ifdef TRACE + printf("\tMIN: \"%s\"", ds_get_buf(&dmin)); + printf(" TYP: \"%s\"", ds_get_buf(&dtyp)); + printf(" MAX: \"%s\"", ds_get_buf(&dmax)); + if (s) + printf(" ESTIMATE: \"%s\"\n", s); + else + printf(" ESTIMATE: UNKNOWN\n"); +#endif + if (s) { + typ_val = strtof(s, &units); + if (typ_val > typ_max_val) { + ds_clear(&dtyp_max_str); + ds_cat_str(&dtyp_max_str, s); + typ_max_val = typ_val; + } + } + } + in_delay = FALSE; + which = 0; + } + val = lexer_scan(lx); + } + if (ds_get_length(&dtyp_max_str) > 0) { + ds_clear(&dmax); // dmax was no longer in use + ds_cat_printf(&dmax, + ".model d_pindly_buf d_buffer(rise_delay=%s fall_delay=%s)", + ds_get_buf(&dtyp_max_str), ds_get_buf(&dtyp_max_str)); + u_add_instance(ds_get_buf(&dmax)); + } else { + u_add_instance( + ".model d_pindly_buf d_buffer(rise_delay=10ns fall_delay=10ns)"); + } + ds_free(&dmin); + ds_free(&dtyp); + ds_free(&dmax); + ds_free(&dtyp_max_str); } BOOL f_pindly(char *line) { int t, num_ios = 0, num_refs = 0, num_ena = 0, i; char *endp; + LEXER lxr; #ifdef TRACE printf("\nf_pindly: %s\n", line); #endif init_ios_tab(); - lex_init(line); - t = lex_scan(); // U* - if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + lxr = new_lexer(line); + current_lexer = lxr; + t = lexer_scan(lxr); // U* + if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; /* pindly ( int , int, int ) */ - t = lex_scan(); - if (!pexpect_token(t, LEX_ID, "pindly", TRUE)) return FALSE; + t = lexer_scan(lxr); + if (!expect_token(t, LEX_ID, "pindly", TRUE)) goto error_return; - t = lex_scan(); - if (!pexpect_token(t, '(', NULL, TRUE)) return FALSE; + t = lexer_scan(lxr); + if (!expect_token(t, '(', NULL, TRUE)) goto error_return; - t = lex_scan(); - if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE; - if (lex_all_digits(parse_lexer->lexer_buf)) { - num_ios = (int) strtol(parse_lexer->lexer_buf, &endp, 10); + t = lexer_scan(lxr); + if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (lex_all_digits(lxr->lexer_buf)) { + num_ios = (int) strtol(lxr->lexer_buf, &endp, 10); } else { printf("ERROR pindly io count is not an integer\n"); - delete_lexer(parse_lexer); - cleanup_pindly(); - return FALSE; + goto error_return; } - t = lex_scan(); - if (!pexpect_token(t, ',', NULL, TRUE)) return FALSE; + t = lexer_scan(lxr); + if (!expect_token(t, ',', NULL, TRUE)) goto error_return; - t = lex_scan(); - if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE; - if (lex_all_digits(parse_lexer->lexer_buf)) { - num_ena = (int) strtol(parse_lexer->lexer_buf, &endp, 10); + t = lexer_scan(lxr); + if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (lex_all_digits(lxr->lexer_buf)) { + num_ena = (int) strtol(lxr->lexer_buf, &endp, 10); } else { printf("ERROR pindly enable count is not an integer\n"); - delete_lexer(parse_lexer); - cleanup_pindly(); - return FALSE; + goto error_return; } if (num_ena != 0) { - delete_lexer(parse_lexer); - cleanup_pindly(); - return FALSE; + goto error_return; } - t = lex_scan(); - if (!pexpect_token(t, ',', NULL, TRUE)) return FALSE; + t = lexer_scan(lxr); + if (!expect_token(t, ',', NULL, TRUE)) goto error_return; - t = lex_scan(); - if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE; - if (lex_all_digits(parse_lexer->lexer_buf)) { - num_refs = (int) strtol(parse_lexer->lexer_buf, &endp, 10); + t = lexer_scan(lxr); + if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (lex_all_digits(lxr->lexer_buf)) { + num_refs = (int) strtol(lxr->lexer_buf, &endp, 10); } else { printf("ERROR pindly refs count is not an integer\n"); - delete_lexer(parse_lexer); - cleanup_pindly(); - return FALSE; + goto error_return; } - t = lex_scan(); - if (!pexpect_token(t, ')', NULL, TRUE)) return FALSE; + t = lexer_scan(lxr); + if (!expect_token(t, ')', NULL, TRUE)) goto error_return; - t = lex_scan(); // pwr - if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE; - t = lex_scan(); // gnd - if (!pexpect_token(t, LEX_ID, NULL, TRUE)) return FALSE; + t = lexer_scan(lxr); // pwr + if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + t = lexer_scan(lxr); // gnd + if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; /* num_ios input ids */ for (i = 0; i < num_ios; i++) { - t = lex_scan(); - if (!pexpect_token(t, LEX_ID, NULL, TRUE)) { - return FALSE; - } - (void) ios_tab_add(parse_lexer->lexer_buf, TRUE); + t = lexer_scan(lxr); + if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + (void) ios_tab_add(lxr->lexer_buf, TRUE); } /* num_refs reference nodes which are ignored */ for (i = 0; i < num_refs; i++) { - t = lex_scan(); - if (!pexpect_token(t, LEX_ID, NULL, TRUE)) { - return FALSE; - } + t = lexer_scan(lxr); + if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; } /* num_ios output ids */ for (i = 0; i < num_ios; i++) { - t = lex_scan(); - if (!pexpect_token(t, LEX_ID, NULL, TRUE)) { - return FALSE; - } - (void) ios_tab_add(parse_lexer->lexer_buf, FALSE); + t = lexer_scan(lxr); + if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + (void) ios_tab_add(lxr->lexer_buf, FALSE); } print_ios_tabs(); gen_output_buffers(); - delete_lexer(parse_lexer); + gen_output_models(lxr); + delete_lexer(lxr); cleanup_pindly(); + current_lexer = NULL; return TRUE; + +error_return: + delete_lexer(lxr); + cleanup_pindly(); + current_lexer = NULL; + return FALSE; } From 5717b2b2fc8c704fd3236360710287f5e7128985 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Tue, 25 Oct 2022 10:59:00 -0700 Subject: [PATCH 08/19] Fix visualc compiler warnings. --- src/frontend/logicexp.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index e23dc2a70..da55516db 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -126,7 +126,7 @@ static void print_sym_tab(SYM_TAB t, BOOL with_addr) if (t == NULL) { return; } print_sym_tab(t->left, with_addr); if (with_addr) - printf("%p --> \n", t); + printf("%p --> \n", (void *)t); printf("\"%s\" %d ref_count=%d", t->name, t->attribute, t->ref_count); if (t->alias) printf(" alias = \"%s\"", t->alias); @@ -189,7 +189,7 @@ static int lexer_set_start(char *s, LEXER lx) pos = strstr(lx->lexer_line, s); if (!pos) return -1; - lx->lexer_pos = pos - &lx->lexer_line[0]; + lx->lexer_pos = (int) (pos - &lx->lexer_line[0]); lx->lexer_back = lx->lexer_pos; return lx->lexer_pos; } @@ -321,7 +321,7 @@ static int lexer_scan(LEXER lx) else if (lex_ident(c)) { int i = 0; while (lex_ident(c)) { - lx->lexer_buf[i] = c; + lx->lexer_buf[i] = (char) c; assert(i < LEX_BUF_SZ); i++; c = lexer_getchar(lx); @@ -332,7 +332,7 @@ static int lexer_scan(LEXER lx) lexer_putback(lx); return LEX_ID; } else { - lx->lexer_buf[0] = c; + lx->lexer_buf[0] = (char) c; lx->lexer_buf[1] = '\0'; return LEX_OTHER; } @@ -346,7 +346,7 @@ static int lex_scan(void) static BOOL lex_all_digits(char *str) { - int i; + size_t i; if (!str || strlen(str) < 1) return FALSE; for (i = 0; i < strlen(str); i++) { @@ -791,10 +791,9 @@ static void bexpr(void) } } -static int bstmt(void) +static void bstmt(void) { /* A stmt is: output_name = { expr } */ - int end_pos; SYM_TAB entry = NULL; LEXER lx = parse_lexer; DS_CREATE(tname, 64); @@ -827,7 +826,6 @@ static int bstmt(void) bexpr(); - end_pos = lx->lexer_pos; if (ds_get_length(&d_curr_line) > 0) { (void) ptab_add_line(ds_get_buf(&d_curr_line), TRUE); } @@ -841,7 +839,7 @@ static int bstmt(void) ds_free(&assign); ds_free(&tname); adepth--; - return end_pos; + return; } static PTABLE optimize_gen_tab(PTABLE pt) @@ -1255,7 +1253,7 @@ static void beval_order(void) static void bparse(char *line, BOOL new_lexer) { - int start_pos = 0, end_pos = 0, stmt_num = 0; + int stmt_num = 0; LEXER lx; PTABLE opt_tab1 = NULL, opt_tab2 = NULL; DS_CREATE(stmt, LEX_BUF_SZ); @@ -1280,18 +1278,9 @@ static void bparse(char *line, BOOL new_lexer) init_parse_tables(); adepth = max_adepth = 0; stmt_num++; - start_pos = lx->lexer_pos; ds_clear(&stmt); ds_cat_str(&stmt, lx->lexer_buf); - end_pos = bstmt(); - -#ifdef TRACE - ds_cat_mem(&stmt, &lx->lexer_line[start_pos], end_pos - start_pos); - printf("\n* Stmt(%d): %s\n\n", stmt_num, ds_get_buf(&stmt)); -#else - (void) start_pos; - (void) end_pos; -#endif + bstmt(); beval_order(); From 3bdb6ee1511215459ab281752b8f47d8838990dd Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Wed, 26 Oct 2022 19:31:06 -0700 Subject: [PATCH 09/19] Better estimates of rise/fall delays in PINDLYs with outputs separated by CASE. --- src/frontend/logicexp.c | 325 ++++++++++++++++++++++++++++++---------- 1 file changed, 245 insertions(+), 80 deletions(-) diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index da55516db..42be927d4 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -1413,67 +1413,179 @@ error_return: } /* pindly handling */ -static PTABLE ios_in_tab = NULL; -static PTABLE ios_out_tab = NULL; +/* C++ with templates would generalize the different TABLEs */ +typedef struct pindly_line *PLINE; +struct pindly_line { + char *in_name; + char *out_name; + char *ena_name; + char *delays; + PLINE next; +}; -static void init_ios_tab(void) +typedef struct pindly_table *PINTABLE; +struct pindly_table { + PLINE first; + PLINE last; + int num_entries; +}; + +static PINTABLE new_pindly_table(void) { - ios_in_tab = new_parse_table(); - ios_out_tab = new_parse_table(); + PINTABLE pint; + pint = TMALLOC(struct pindly_table, 1); + pint->first = pint->last = NULL; + pint->num_entries = 0; + return pint; } -static void cleanup_pindly(void) +static int num_pindly_entries(PINTABLE pint) { - delete_parse_table(ios_in_tab); - delete_parse_table(ios_out_tab); - ios_in_tab = NULL; - ios_out_tab = NULL; -} - -static TLINE ios_tab_add(char *ioname, BOOL is_input) -{ - if (is_input) - return add_to_parse_table(ios_in_tab, ioname, TRUE); + if (!pint) + return 0; else - return add_to_parse_table(ios_out_tab, ioname, TRUE); + return pint->num_entries; } -static void print_ios_tabs(void) +static PLINE new_pindly_line(void) { -#ifdef TABLE_PRINT - if (ios_in_tab) { - printf("ios_in_tab\n"); - table_print(ios_in_tab->first); - } - if (ios_out_tab) { - printf("ios_out_tab\n"); - table_print(ios_out_tab->first); + PLINE p = NULL; + p = TMALLOC(struct pindly_line, 1); + p->in_name = p->out_name = p->ena_name = p->delays = NULL; + return p; +} + +static PLINE add_new_pindly_line(PINTABLE pint) +{ + PLINE p; + p = new_pindly_line(); + p->next = NULL; + if (!pint->first) { + pint->first = pint->last = p; + } else { + pint->last->next = p; + pint->last = p; } + pint->num_entries++; + return p; +} + +static PLINE set_in_name(char *s, PLINE p) +{ + if (p->in_name) tfree(p->in_name); + p->in_name = TMALLOC(char, (strlen(s) + 1)); + strcpy(p->in_name, s); + return p; +} + +static PLINE set_out_name(char *s, PLINE p) +{ + if (p->out_name) tfree(p->out_name); + p->out_name = TMALLOC(char, (strlen(s) + 1)); + strcpy(p->out_name, s); + return p; +} + +#if 0 +static PLINE set_ena_name(char *s, PLINE p) +{ + if (p->ena_name) tfree(p->ena_name); + p->ena_name = TMALLOC(char, (strlen(s) + 1)); + strcpy(p->ena_name, s); + return p; +} #endif + +static PLINE set_delays(char *s, PLINE p) +{ + if (p->delays) tfree(p->delays); + p->delays = TMALLOC(char, (strlen(s) + 1)); + strcpy(p->delays, s); + return p; } -static void gen_output_buffers(void) +static void delete_pindly_table(PINTABLE pint) { - TLINE tin, tout; - if (ios_in_tab && ios_out_tab) { - if (!ios_in_tab->first || !ios_out_tab->first) { - return; - } else { - DS_CREATE(instance, 128); - tin = ios_in_tab->first; - tout = ios_out_tab->first; - while (tin && tout) { - ds_clear(&instance); - ds_cat_printf(&instance, "%s %s %s d_pindly_buf", - get_inst_name(), tin->line, tout->line); - u_add_instance(ds_get_buf(&instance)); - tin = tin->next; - tout = tout->next; - } - ds_free(&instance); - } + PLINE p, next; + if (!pint) + return; + next = pint->first; + while (next) { + p = next; + if (p->in_name) tfree(p->in_name); + if (p->out_name) tfree(p->out_name); + if (p->ena_name) tfree(p->ena_name); + if (p->delays) tfree(p->delays); + next = p->next; + tfree(p); + } + tfree(pint); +} + +static PLINE nth_pindly_entry(PINTABLE pint, int n) +{ + /* Entries ore from 0 to num_entries - 1 */ + PLINE p, next; + int count = 0; + if (n < 0) return NULL; + if (n > pint->num_entries - 1) return NULL; + next = pint->first; + while (next) { + p = next; + if (count == n) return p; + count++; + next = p->next; + } + return NULL; +} + +static PLINE find_pindly_out_name(PINTABLE pint, char *name) +{ + PLINE p, next; + if (!pint) return NULL; + next = pint->first; + while (next) { + p = next; + if (strcmp(p->out_name, name) == 0) return p; + next = p->next; + } + return NULL; +} + +static PINTABLE pindly_tab = NULL; + +static void init_pindly_tab(void) +{ + pindly_tab = new_pindly_table(); +} + +static void cleanup_pindly_tab(void) +{ + delete_pindly_table(pindly_tab); + pindly_tab = NULL; +} + +static void gen_pindly_buffers(void) +{ + DS_CREATE(dbuf, 128); + PLINE pline = NULL; + + pline = pindly_tab->first; + while (pline) { + char *iname = NULL; + ds_clear(&dbuf); + iname = get_inst_name(); + ds_cat_printf(&dbuf, "%s %s %s d_pindly_buf_%s", iname, + pline->in_name, pline->out_name, iname); + u_add_instance(ds_get_buf(&dbuf)); + ds_clear(&dbuf); + ds_cat_printf(&dbuf, ".model d_pindly_buf_%s d_buffer%s", + iname, pline->delays); + u_add_instance(ds_get_buf(&dbuf)); + pline = pline->next; } } + static char *get_typ_estimate(char *min, char *typ, char *max) { char *tmpmax = NULL, *tmpmin = NULL; @@ -1516,35 +1628,73 @@ static char *get_typ_estimate(char *min, char *typ, char *max) static void gen_output_models(LEXER lx) { - int val, which = 0; - BOOL in_delay = FALSE; + int val, which = 0, arrlen = 0, idx = 0, i; + BOOL in_delay = FALSE, expect_left = FALSE; float typ_max_val = 0.0, typ_val = 0.0; char *units; + BOOL tracing = FALSE; DS_CREATE(dmin, 16); DS_CREATE(dtyp, 16); DS_CREATE(dmax, 16); DS_CREATE(dtyp_max_str, 16); DSTRINGPTR dsp = NULL; + PLINE pline = NULL; + PLINE *pline_arr = NULL; + arrlen = num_pindly_entries(pindly_tab); + assert(arrlen > 0); + pline_arr = TMALLOC(PLINE, arrlen); val = lexer_set_start("pindly:", lx); val = lexer_scan(lx); // "pindly" val = lexer_scan(lx); // ':' val = lexer_scan(lx); - while (val != '\0') { + idx = 0; + while (val != '\0') { /* while val */ if (val == LEX_ID) { + expect_left = FALSE; if (strcmp(lx->lexer_buf, "delay") == 0) { ds_clear(&dmin); ds_clear(&dtyp); ds_clear(&dmax); in_delay = TRUE; + } else if (strcmp(lx->lexer_buf, "setup_hold") == 0 + || strcmp(lx->lexer_buf, "width") == 0 + || strcmp(lx->lexer_buf, "freq") == 0 + || strcmp(lx->lexer_buf, "general") == 0) { + break; } -#ifdef TRACE - printf("ID: \"%s\"\n", lx->lexer_buf); + pline = find_pindly_out_name(pindly_tab, lx->lexer_buf); + if (pline) { + if (tracing) printf("Case for %s comming\n", pline->out_name); + pline_arr[idx++] = pline; + } + if (tracing) printf("ID: \"%s\"\n", lx->lexer_buf); } else if (val == LEX_OTHER) { - printf("OTHER: \"%s\"\n", lx->lexer_buf); + expect_left = FALSE; + if (tracing) printf("OTHER: \"%s\"\n", lx->lexer_buf); } else { - printf("TOK: %d <%c>\n", val, val); -#endif + if (tracing) printf("TOK: %d <%c>\n", val, val); + if (val == '{') { + if (expect_left) { + if (tracing) printf("Ready for delays\n"); + for (i = 0; i < idx; i++) + if (tracing) + printf("For output %s\n", pline_arr[i]->out_name); + } + expect_left = FALSE; + } else if (val == '=') { + expect_left = TRUE; + } else if (val == '}') { + for (i = 0; i < idx; i++) { + if (tracing) printf("Finished delays for output %s\n", + pline_arr[i]->out_name); + pline_arr[i] = NULL; + } + idx = 0; + expect_left = FALSE; + in_delay = FALSE; + typ_max_val = 0.0; + } } if (in_delay) { switch (which) { @@ -1574,21 +1724,36 @@ static void gen_output_models(LEXER lx) char *s; s = get_typ_estimate(ds_get_buf(&dmin), ds_get_buf(&dtyp), ds_get_buf(&dmax)); -#ifdef TRACE - printf("\tMIN: \"%s\"", ds_get_buf(&dmin)); - printf(" TYP: \"%s\"", ds_get_buf(&dtyp)); - printf(" MAX: \"%s\"", ds_get_buf(&dmax)); - if (s) - printf(" ESTIMATE: \"%s\"\n", s); - else - printf(" ESTIMATE: UNKNOWN\n"); -#endif + if (tracing) printf("\tMIN: \"%s\"", ds_get_buf(&dmin)); + if (tracing) printf(" TYP: \"%s\"", ds_get_buf(&dtyp)); + if (tracing) printf(" MAX: \"%s\"", ds_get_buf(&dmax)); + if (s) { + if (tracing) printf(" ESTIMATE: \"%s\"\n", s); + } else { + if (tracing) printf(" ESTIMATE: UNKNOWN\n"); + } if (s) { typ_val = strtof(s, &units); if (typ_val > typ_max_val) { + DS_CREATE(delay_string, 64); + ds_clear(&delay_string); ds_clear(&dtyp_max_str); ds_cat_str(&dtyp_max_str, s); typ_max_val = typ_val; + if (ds_get_length(&dtyp_max_str) > 0) { + ds_cat_printf(&delay_string, + "(rise_delay=%s fall_delay=%s)", + ds_get_buf(&dtyp_max_str), + ds_get_buf(&dtyp_max_str)); + } else { + ds_cat_printf(&delay_string, + "(rise_delay=10ns fall_delay=10ns)"); + } + for (i = 0; i < idx; i++) { + (void) set_delays(ds_get_buf(&delay_string), + pline_arr[i]); + } + ds_free(&delay_string); } } } @@ -1596,21 +1761,13 @@ static void gen_output_models(LEXER lx) which = 0; } val = lexer_scan(lx); - } - if (ds_get_length(&dtyp_max_str) > 0) { - ds_clear(&dmax); // dmax was no longer in use - ds_cat_printf(&dmax, - ".model d_pindly_buf d_buffer(rise_delay=%s fall_delay=%s)", - ds_get_buf(&dtyp_max_str), ds_get_buf(&dtyp_max_str)); - u_add_instance(ds_get_buf(&dmax)); - } else { - u_add_instance( - ".model d_pindly_buf d_buffer(rise_delay=10ns fall_delay=10ns)"); - } + } /* end while val */ + ds_free(&dmin); ds_free(&dtyp); ds_free(&dmax); ds_free(&dtyp_max_str); + tfree(pline_arr); } BOOL f_pindly(char *line) @@ -1619,10 +1776,13 @@ BOOL f_pindly(char *line) char *endp; LEXER lxr; + PLINE pline = NULL; + #ifdef TRACE printf("\nf_pindly: %s\n", line); #endif - init_ios_tab(); + init_pindly_tab(); + lxr = new_lexer(line); current_lexer = lxr; t = lexer_scan(lxr); // U* @@ -1683,7 +1843,8 @@ BOOL f_pindly(char *line) for (i = 0; i < num_ios; i++) { t = lexer_scan(lxr); if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; - (void) ios_tab_add(lxr->lexer_buf, TRUE); + pline = add_new_pindly_line(pindly_tab); + (void) set_in_name(lxr->lexer_buf, pline); } /* num_refs reference nodes which are ignored */ @@ -1692,23 +1853,27 @@ BOOL f_pindly(char *line) if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; } /* num_ios output ids */ + pline = NULL; for (i = 0; i < num_ios; i++) { t = lexer_scan(lxr); if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; - (void) ios_tab_add(lxr->lexer_buf, FALSE); + if (i == 0) + pline = nth_pindly_entry(pindly_tab, i); + else + pline = pline->next; + (void) set_out_name(lxr->lexer_buf, pline); } - print_ios_tabs(); - gen_output_buffers(); gen_output_models(lxr); + gen_pindly_buffers(); delete_lexer(lxr); - cleanup_pindly(); + cleanup_pindly_tab(); current_lexer = NULL; return TRUE; error_return: delete_lexer(lxr); - cleanup_pindly(); + cleanup_pindly_tab(); current_lexer = NULL; return FALSE; } From 50e3c7eadd2a398d541f639f9224b4b7955e03ac Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Wed, 26 Oct 2022 23:27:06 -0700 Subject: [PATCH 10/19] Fix potential memory leak, clean out debug code. --- src/frontend/logicexp.c | 46 +++++++---------------------------------- 1 file changed, 8 insertions(+), 38 deletions(-) diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index 42be927d4..89d89ef03 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -1584,6 +1584,7 @@ static void gen_pindly_buffers(void) u_add_instance(ds_get_buf(&dbuf)); pline = pline->next; } + ds_free(&dbuf); } static char *get_typ_estimate(char *min, char *typ, char *max) @@ -1629,10 +1630,9 @@ static char *get_typ_estimate(char *min, char *typ, char *max) static void gen_output_models(LEXER lx) { int val, which = 0, arrlen = 0, idx = 0, i; - BOOL in_delay = FALSE, expect_left = FALSE; + BOOL in_delay = FALSE; float typ_max_val = 0.0, typ_val = 0.0; char *units; - BOOL tracing = FALSE; DS_CREATE(dmin, 16); DS_CREATE(dtyp, 16); DS_CREATE(dmax, 16); @@ -1651,7 +1651,6 @@ static void gen_output_models(LEXER lx) idx = 0; while (val != '\0') { /* while val */ if (val == LEX_ID) { - expect_left = FALSE; if (strcmp(lx->lexer_buf, "delay") == 0) { ds_clear(&dmin); ds_clear(&dtyp); @@ -1665,36 +1664,15 @@ static void gen_output_models(LEXER lx) } pline = find_pindly_out_name(pindly_tab, lx->lexer_buf); if (pline) { - if (tracing) printf("Case for %s comming\n", pline->out_name); pline_arr[idx++] = pline; } - if (tracing) printf("ID: \"%s\"\n", lx->lexer_buf); - } else if (val == LEX_OTHER) { - expect_left = FALSE; - if (tracing) printf("OTHER: \"%s\"\n", lx->lexer_buf); - } else { - if (tracing) printf("TOK: %d <%c>\n", val, val); - if (val == '{') { - if (expect_left) { - if (tracing) printf("Ready for delays\n"); - for (i = 0; i < idx; i++) - if (tracing) - printf("For output %s\n", pline_arr[i]->out_name); - } - expect_left = FALSE; - } else if (val == '=') { - expect_left = TRUE; - } else if (val == '}') { - for (i = 0; i < idx; i++) { - if (tracing) printf("Finished delays for output %s\n", - pline_arr[i]->out_name); - pline_arr[i] = NULL; - } - idx = 0; - expect_left = FALSE; - in_delay = FALSE; - typ_max_val = 0.0; + } else if (val == '}') { + for (i = 0; i < idx; i++) { + pline_arr[i] = NULL; } + idx = 0; + in_delay = FALSE; + typ_max_val = 0.0; } if (in_delay) { switch (which) { @@ -1724,14 +1702,6 @@ static void gen_output_models(LEXER lx) char *s; s = get_typ_estimate(ds_get_buf(&dmin), ds_get_buf(&dtyp), ds_get_buf(&dmax)); - if (tracing) printf("\tMIN: \"%s\"", ds_get_buf(&dmin)); - if (tracing) printf(" TYP: \"%s\"", ds_get_buf(&dtyp)); - if (tracing) printf(" MAX: \"%s\"", ds_get_buf(&dmax)); - if (s) { - if (tracing) printf(" ESTIMATE: \"%s\"\n", s); - } else { - if (tracing) printf(" ESTIMATE: UNKNOWN\n"); - } if (s) { typ_val = strtof(s, &units); if (typ_val > typ_max_val) { From 7e4b10a9db811bc36392729a507a6b2602e4052f Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Sat, 29 Oct 2022 16:33:58 -0700 Subject: [PATCH 11/19] Add support for TRISTATE: in PINDLY. --- src/frontend/logicexp.c | 490 ++++++++++++++++++++++++++-------------- 1 file changed, 323 insertions(+), 167 deletions(-) diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index 89d89ef03..588dcc013 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -19,8 +19,6 @@ #include "ngspice/logicexp.h" #include "ngspice/udevices.h" -/* #define TRACE */ - /* Start of btree symbol table */ #define SYM_INPUT 1 #define SYM_OUTPUT 2 @@ -616,9 +614,6 @@ static void gen_inverters(SYM_TAB t) ds_clear(&instance); ds_cat_printf(&instance, "%s %s %s d_inv_zero_delay", get_inst_name(), t->name, get_inverter_output_name(t->name)); -#ifdef TRACE - printf("%s\n", ds_get_buf(&instance)); -#endif u_add_instance(ds_get_buf(&instance)); } } @@ -630,18 +625,6 @@ static void gen_models(void) { DS_CREATE(model, 64); -#ifdef TRACE - printf(".model d_inv_zero_delay d_inverter\n"); - printf(".model d__inverter__1 d_inverter\n"); - printf(".model d__buffer__1 d_buffer\n"); - printf(".model d__nand__1 d_nand\n"); - printf(".model d__and__1 d_and\n"); - printf(".model d__xnor__1 d_xnor\n"); - printf(".model d__xor__1 d_xor\n"); - printf(".model d__nor__1 d_nor\n"); - printf(".model d__or__1 d_or\n"); -#endif - ds_clear(&model); ds_cat_printf(&model, ".model d_inv_zero_delay d_inverter"); u_add_instance(ds_get_buf(&model)); @@ -1131,9 +1114,6 @@ static void gen_gates(PTABLE gate_tab, SYM_TAB parser_symbols) delete_lexer(lxr); lxr = new_lexer(t->line); } -#ifdef TRACE - printf("%s\n", ds_get_buf(&instance)); -#endif u_add_instance(ds_get_buf(&instance)); } delete_lexer(lxr); @@ -1188,7 +1168,7 @@ static void bevaluate(TLINE t, int deep) while (t) { s = find_temp_anywhere(t->line); if (s) { - if (strcmp(ds_get_buf(&this), s) == 0) { + if (eq(ds_get_buf(&this), s)) { break; } else { if (down == 0) { @@ -1199,7 +1179,7 @@ static void bevaluate(TLINE t, int deep) ds_cat_printf(&new_line, " %s", ds_get_buf(&other)); } else if (down == 1) { s = find_temp_anywhere(t->line); - if (strcmp(ds_get_buf(&other), s) == 0) { + if (eq(ds_get_buf(&other), s)) { down = 0; ds_clear(&other); } @@ -1287,7 +1267,7 @@ static void bparse(char *line, BOOL new_lexer) opt_tab1 = optimize_gen_tab(gen_tab); opt_tab2 = optimize_gen_tab(opt_tab1); if (opt_tab2) { - gen_gates(opt_tab2, parse_lexer->lexer_sym_tab); + gen_gates(opt_tab2, lx->lexer_sym_tab); } delete_parse_table(opt_tab1); delete_parse_table(opt_tab2); @@ -1298,10 +1278,6 @@ static void bparse(char *line, BOOL new_lexer) gen_inverters(lx->lexer_sym_tab); gen_models(); ds_free(&stmt); -#ifdef TRACE - if (!new_lexer) - print_sym_tab(lx->lexer_sym_tab, FALSE); -#endif delete_lexer(lx); } /* End of logicexp parser */ @@ -1309,25 +1285,25 @@ static void bparse(char *line, BOOL new_lexer) static LEXER current_lexer = NULL; static BOOL expect_token( - int tok, int expected_tok, char *expected_str, BOOL msg) + int tok, int expected_tok, char *expected_str, BOOL msg, int loc) { if (tok != expected_tok) { if (msg) { - printf("ERROR expect_token failed tok %d expected_tok %d\n", - tok, expected_tok); + printf("ERROR expect_token failed tok %d expected_tok %d loc %d\n", + tok, expected_tok, loc); } return FALSE; } if (tok == LEX_ID) { if (expected_str) { LEXER lx = current_lexer; - if (strcmp(expected_str, lx->lexer_buf) == 0) + if (eq(expected_str, lx->lexer_buf)) return TRUE; else { if (msg) { printf( - "ERROR expect_token failed lexer_buf %s expected_str %s\n", - lx->lexer_buf, expected_str); + "ERROR expect_token failed lexer_buf %s expected_str %s loc %d\n", + lx->lexer_buf, expected_str, loc); } return FALSE; } @@ -1343,22 +1319,19 @@ BOOL f_logicexp(char *line) int t, num_ins = 0, num_outs = 0, i; char *endp; -#ifdef TRACE - printf("\nf_logicexp: %s\n", line); -#endif lex_init(line); current_lexer = parse_lexer; (void) add_sym_tab_entry("logic", SYM_KEY_WORD, &parse_lexer->lexer_sym_tab); t = lex_scan(); // U* - if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, NULL, TRUE, 1)) goto error_return; /* logicexp ( int , int ) */ t = lex_scan(); - if (!expect_token(t, LEX_ID, "logicexp", TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, "logicexp", TRUE, 2)) goto error_return; t = lex_scan(); - if (!expect_token(t, '(', NULL, TRUE)) goto error_return; + if (!expect_token(t, '(', NULL, TRUE, 3)) goto error_return; t = lex_scan(); - if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, NULL, TRUE, 4)) goto error_return; if (lex_all_digits(parse_lexer->lexer_buf)) { num_ins = (int) strtol(parse_lexer->lexer_buf, &endp, 10); } else { @@ -1366,9 +1339,9 @@ BOOL f_logicexp(char *line) goto error_return; } t = lex_scan(); - if (!expect_token(t, ',', NULL, TRUE)) goto error_return; + if (!expect_token(t, ',', NULL, TRUE, 5)) goto error_return; t = lex_scan(); - if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, NULL, TRUE, 6)) goto error_return; if (lex_all_digits(parse_lexer->lexer_buf)) { num_outs = (int) strtol(parse_lexer->lexer_buf, &endp, 10); } else { @@ -1376,28 +1349,28 @@ BOOL f_logicexp(char *line) goto error_return; } t = lex_scan(); - if (!expect_token(t, ')', NULL, TRUE)) goto error_return; + if (!expect_token(t, ')', NULL, TRUE, 7)) goto error_return; t = lex_scan(); // pwr - if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, NULL, TRUE, 8)) goto error_return; t = lex_scan(); // gnd - if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, NULL, TRUE, 9)) goto error_return; /* num_ins input ids */ for (i = 0; i < num_ins; i++) { t = lex_scan(); - if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, NULL, TRUE, 10)) goto error_return; (void) add_sym_tab_entry(parse_lexer->lexer_buf, SYM_INPUT, &parse_lexer->lexer_sym_tab); } /* num_outs output ids */ for (i = 0; i < num_outs; i++) { t = lex_scan(); - if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, NULL, TRUE, 11)) goto error_return; (void) add_sym_tab_entry(parse_lexer->lexer_buf, SYM_OUTPUT, &parse_lexer->lexer_sym_tab); } /* timing model */ t = lex_scan(); - if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, NULL, TRUE, 12)) goto error_return; //printf("TMODEL: %s\n", parse_lexer->lexer_buf); (void) add_sym_tab_entry(parse_lexer->lexer_buf, SYM_TMODEL, &parse_lexer->lexer_sym_tab); @@ -1486,7 +1459,6 @@ static PLINE set_out_name(char *s, PLINE p) return p; } -#if 0 static PLINE set_ena_name(char *s, PLINE p) { if (p->ena_name) tfree(p->ena_name); @@ -1494,7 +1466,6 @@ static PLINE set_ena_name(char *s, PLINE p) strcpy(p->ena_name, s); return p; } -#endif static PLINE set_delays(char *s, PLINE p) { @@ -1522,6 +1493,25 @@ 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; + next = pint->first; + while (next) { + p = next; + printf("in_name \"%s\"", p->in_name); + printf(" out_name \"%s\"", p->out_name); + printf(" ena_name \"%s\"", p->ena_name); + printf(" delays \"%s\"\n", p->delays); + next = p->next; + } +} +#endif + static PLINE nth_pindly_entry(PINTABLE pint, int n) { /* Entries ore from 0 to num_entries - 1 */ @@ -1546,7 +1536,7 @@ static PLINE find_pindly_out_name(PINTABLE pint, char *name) next = pint->first; while (next) { p = next; - if (strcmp(p->out_name, name) == 0) return p; + if (eq(p->out_name, name)) return p; next = p->next; } return NULL; @@ -1570,17 +1560,30 @@ static void gen_pindly_buffers(void) DS_CREATE(dbuf, 128); PLINE pline = NULL; +#ifdef TRACE + print_pindly_table(pindly_tab); +#endif pline = pindly_tab->first; while (pline) { char *iname = NULL; ds_clear(&dbuf); iname = get_inst_name(); - ds_cat_printf(&dbuf, "%s %s %s d_pindly_buf_%s", iname, - pline->in_name, pline->out_name, iname); + if (pline->ena_name && strlen(pline->ena_name) > 0) { + ds_cat_printf(&dbuf, "%s %s %s %s d_tristate_buf_%s", iname, + pline->in_name, pline->ena_name, pline->out_name, iname); + } else { + ds_cat_printf(&dbuf, "%s %s %s d_pindly_buf_%s", iname, + pline->in_name, pline->out_name, iname); + } u_add_instance(ds_get_buf(&dbuf)); ds_clear(&dbuf); - ds_cat_printf(&dbuf, ".model d_pindly_buf_%s d_buffer%s", - iname, pline->delays); + if (pline->ena_name && strlen(pline->ena_name) > 0) { + ds_cat_printf(&dbuf, ".model d_tristate_buf_%s d_tristate%s", + iname, pline->delays); + } else { + ds_cat_printf(&dbuf, ".model d_pindly_buf_%s d_buffer%s", + iname, pline->delays); + } u_add_instance(ds_get_buf(&dbuf)); pline = pline->next; } @@ -1610,7 +1613,7 @@ static char *get_typ_estimate(char *min, char *typ, char *max) valmax = strtof(tmpmax, &units2); average = (valmin + valmax) / (float)2.0; sprintf(tbuf, "%.2f%s", average, units2); - if (strcmp(units1, units2) != 0) { + if (!eq(units1, units2)) { printf("WARNING units do not match\n"); } return tbuf; @@ -1627,146 +1630,298 @@ static char *get_typ_estimate(char *min, char *typ, char *max) return NULL; } -static void gen_output_models(LEXER lx) +static char *typical_estimate(char *delay_str) { - int val, which = 0, arrlen = 0, idx = 0, i; - BOOL in_delay = FALSE; + int which = 0; + size_t i; + char *s; + DS_CREATE(dmin, 32); + DS_CREATE(dtyp, 32); + DS_CREATE(dmax, 32); + + ds_clear(&dmin); + ds_clear(&dtyp); + ds_clear(&dmax); + for (i = 0; i < strlen(delay_str) - 1; i++) { + if (i == 0) continue; + if (delay_str[i] == ',') { + which++; + continue; + } + switch (which) { + case 0: + ds_cat_char(&dmin, delay_str[i]); + break; + case 1: + ds_cat_char(&dtyp, delay_str[i]); + break; + case 2: + ds_cat_char(&dmax, delay_str[i]); + break; + default: + break; + } + } + s = get_typ_estimate(ds_get_buf(&dmin), ds_get_buf(&dtyp), + ds_get_buf(&dmax)); + ds_free(&dmin); + ds_free(&dtyp); + ds_free(&dmax); + return s; +} + +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; float typ_max_val = 0.0, typ_val = 0.0; char *units; - DS_CREATE(dmin, 16); - DS_CREATE(dtyp, 16); - DS_CREATE(dmax, 16); + DS_CREATE(dly, 64); + DS_CREATE(enable_name, 64); + DS_CREATE(last_enable, 64); DS_CREATE(dtyp_max_str, 16); - DSTRINGPTR dsp = NULL; PLINE pline = NULL; PLINE *pline_arr = NULL; arrlen = num_pindly_entries(pindly_tab); assert(arrlen > 0); pline_arr = TMALLOC(PLINE, arrlen); - val = lexer_set_start("pindly:", lx); - val = lexer_scan(lx); // "pindly" - val = lexer_scan(lx); // ':' + ds_clear(&last_enable); val = lexer_scan(lx); - idx = 0; - while (val != '\0') { /* while val */ + while (val != 0) { // Outer while loop if (val == LEX_ID) { - if (strcmp(lx->lexer_buf, "delay") == 0) { - ds_clear(&dmin); - ds_clear(&dtyp); - ds_clear(&dmax); - in_delay = TRUE; - } else if (strcmp(lx->lexer_buf, "setup_hold") == 0 - || strcmp(lx->lexer_buf, "width") == 0 - || strcmp(lx->lexer_buf, "freq") == 0 - || strcmp(lx->lexer_buf, "general") == 0) { - break; + if (eq(lx->lexer_buf, "pindly")) { + in_pindly = TRUE; + in_tristate = FALSE; + val = lexer_scan(lx); + if (val != ':') goto err_return; + } else if (eq(lx->lexer_buf, "tristate")) { + in_pindly = FALSE; + in_tristate = TRUE; + val = lexer_scan(lx); + if (val != ':') goto err_return; + } else if (eq(lx->lexer_buf, "setup_hold") + || eq(lx->lexer_buf, "width") + || eq(lx->lexer_buf, "freq") + || eq(lx->lexer_buf, "general")) { + in_pindly = FALSE; + in_tristate = FALSE; } - pline = find_pindly_out_name(pindly_tab, lx->lexer_buf); - if (pline) { - pline_arr[idx++] = pline; + } + 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); + pline = find_pindly_out_name(pindly_tab, lx->lexer_buf); + if (pline) + pline_arr[idx++] = pline; + else + goto err_return; + val = lexer_scan(lx); } - } else if (val == '}') { - for (i = 0; i < idx; i++) { - pline_arr[i] = NULL; - } - idx = 0; - in_delay = FALSE; typ_max_val = 0.0; - } - if (in_delay) { - switch (which) { - case 0: - dsp = &dmin; - break; - case 1: - dsp = &dtyp; - break; - case 2: - dsp = &dmax; - break; - default: - assert(FALSE); - break; - }; - if (val == '.') - ds_cat_printf(dsp, "%c", val); - else if (val == LEX_ID && strcmp(lx->lexer_buf, "delay") != 0) - ds_cat_printf(dsp, "%s", lx->lexer_buf); - if (val == ',') { - which++; - } - } - if (val == ')') { - if (in_delay) { - char *s; - s = get_typ_estimate(ds_get_buf(&dmin), - ds_get_buf(&dtyp), ds_get_buf(&dmax)); - if (s) { - typ_val = strtof(s, &units); - if (typ_val > typ_max_val) { - DS_CREATE(delay_string, 64); - ds_clear(&delay_string); - ds_clear(&dtyp_max_str); - ds_cat_str(&dtyp_max_str, s); - typ_max_val = typ_val; - if (ds_get_length(&dtyp_max_str) > 0) { - ds_cat_printf(&delay_string, - "(rise_delay=%s fall_delay=%s)", - ds_get_buf(&dtyp_max_str), - ds_get_buf(&dtyp_max_str)); - } else { - ds_cat_printf(&delay_string, - "(rise_delay=10ns fall_delay=10ns)"); + if (val != '=') goto err_return; + val = lexer_scan(lx); + if (val != '{') goto err_return; + val = lexer_scan(lx); + while (val != '}') { + if (val == LEX_ID) { + if (eq(lx->lexer_buf, "delay")) { + if (prit) printf("Get pindly delay\n"); + in_delay = TRUE; + ds_clear(&dly); + } else { + if (in_delay) { + ds_cat_printf(&dly, "%s", lx->lexer_buf); } - for (i = 0; i < idx; i++) { - (void) set_delays(ds_get_buf(&delay_string), - pline_arr[i]); + } + } else { + if (in_delay) { + DS_CREATE(delay_string, 64); + ds_cat_printf(&dly, "%c", val); + 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))); + tmps = typical_estimate(ds_get_buf(&dly)); + if (!tmps) goto err_return; + typ_val = strtof(tmps, &units); + if (typ_val > typ_max_val) { + ds_clear(&delay_string); + ds_clear(&dtyp_max_str); + ds_cat_str(&dtyp_max_str, tmps); + typ_max_val = typ_val; + if (ds_get_length(&dtyp_max_str) > 0) { + ds_cat_printf(&delay_string, + "(rise_delay=%s fall_delay=%s)", + ds_get_buf(&dtyp_max_str), + ds_get_buf(&dtyp_max_str)); + } else { + ds_cat_printf(&delay_string, + "(rise_delay=10ns fall_delay=10ns)"); + } + for (i = 0; i < idx; i++) { + (void) set_delays( + ds_get_buf(&delay_string), + pline_arr[i]); + } + } } ds_free(&delay_string); - } + } // end if in_delay } + val = lexer_scan(lx); + } // end while != '}' + for (i = 0; i < arrlen; i++) { + pline_arr[i] = NULL; } - in_delay = FALSE; - which = 0; + idx = 0; // end in_pindly and LEX_ID + } else if (in_tristate && val == LEX_ID) { + // start in_tristate and LEX_ID + if (eq(lx->lexer_buf, "enable")) { + val = lexer_scan(lx); + if (val == LEX_ID && (eq(lx->lexer_buf, "hi") + || eq(lx->lexer_buf, "lo"))) { + BOOL invert = FALSE; + if (eq(lx->lexer_buf, "lo")) + invert = TRUE; + if (prit) printf("tristate enable %s ", lx->lexer_buf); + val = lexer_scan(lx); + if (val != '=') goto err_return; + val = lexer_scan(lx); + if (val != LEX_ID) goto err_return; + if (prit) printf("ena \"%s\"\n", lx->lexer_buf); + ds_clear(&enable_name); + if (invert) + ds_cat_char(&enable_name, '~'); + ds_cat_str(&enable_name, lx->lexer_buf); + } else { + goto err_return; + } + ds_clear(&last_enable); + ds_cat_ds(&last_enable, &enable_name); + val = lexer_scan(lx); + if (val != LEX_ID) goto err_return; + } else if (ds_get_length(&last_enable) > 0) { + ds_clear(&enable_name); + ds_cat_ds(&enable_name, &last_enable); + } else { + goto err_return; + } + while (val == LEX_ID) { + 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; + (void) set_ena_name(ds_get_buf(&enable_name), pline); + } else { + goto err_return; + } + val = lexer_scan(lx); + } + typ_max_val = 0.0; + if (val != '=') goto err_return; + val = lexer_scan(lx); + if (val != '{') goto err_return; + val = lexer_scan(lx); + while (val != '}') { + if (val == LEX_ID) { + if (eq(lx->lexer_buf, "delay")) { + if (prit) printf("Get tristate delay\n"); + in_delay = TRUE; + ds_clear(&dly); + } else { + if (in_delay) { + ds_cat_printf(&dly, "%s", lx->lexer_buf); + } + } + } else { + if (in_delay) { + DS_CREATE(delay_string, 64); + ds_cat_printf(&dly, "%c", val); + 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))); + tmps = typical_estimate(ds_get_buf(&dly)); + if (!tmps) goto err_return; + typ_val = strtof(tmps, &units); + if (typ_val > typ_max_val) { + ds_clear(&delay_string); + ds_clear(&dtyp_max_str); + ds_cat_str(&dtyp_max_str, tmps); + typ_max_val = typ_val; + if (ds_get_length(&dtyp_max_str) > 0) { + ds_cat_printf(&delay_string, + "(delay=%s)", + ds_get_buf(&dtyp_max_str)); + } else { + ds_cat_printf(&delay_string, + "(delay=10ns)"); + } + for (i = 0; i < idx; i++) { + (void) set_delays( + ds_get_buf(&delay_string), + pline_arr[i]); + } + } + } + ds_free(&delay_string); + } // end if in_delay + } + val = lexer_scan(lx); + } // end while != '}' + for (i = 0; i < arrlen; i++) { + pline_arr[i] = NULL; + } + idx = 0; // end of in_tristate and LEX_ID } val = lexer_scan(lx); - } /* end while val */ - - ds_free(&dmin); - ds_free(&dtyp); - ds_free(&dmax); + } // end of outer while loop + ds_free(&dly); ds_free(&dtyp_max_str); + ds_free(&enable_name); + ds_free(&last_enable); tfree(pline_arr); + return TRUE; + +err_return: + printf("ERROR in new_gen_output_models\n"); + ds_free(&dly); + ds_free(&dtyp_max_str); + ds_free(&enable_name); + ds_free(&last_enable); + tfree(pline_arr); + return FALSE; } BOOL f_pindly(char *line) { - int t, num_ios = 0, num_refs = 0, num_ena = 0, i; + int t, num_ios = 0, num_ena = 0, num_refs = 0, i; char *endp; LEXER lxr; - PLINE pline = NULL; -#ifdef TRACE - printf("\nf_pindly: %s\n", line); -#endif init_pindly_tab(); lxr = new_lexer(line); current_lexer = lxr; t = lexer_scan(lxr); // U* - if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, NULL, TRUE, 50)) goto error_return; /* pindly ( int , int, int ) */ t = lexer_scan(lxr); - if (!expect_token(t, LEX_ID, "pindly", TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, "pindly", TRUE, 51)) goto error_return; t = lexer_scan(lxr); - if (!expect_token(t, '(', NULL, TRUE)) goto error_return; + if (!expect_token(t, '(', NULL, TRUE, 52)) goto error_return; t = lexer_scan(lxr); - if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, NULL, TRUE, 53)) goto error_return; if (lex_all_digits(lxr->lexer_buf)) { num_ios = (int) strtol(lxr->lexer_buf, &endp, 10); } else { @@ -1775,25 +1930,22 @@ BOOL f_pindly(char *line) } t = lexer_scan(lxr); - if (!expect_token(t, ',', NULL, TRUE)) goto error_return; + if (!expect_token(t, ',', NULL, TRUE, 54)) goto error_return; t = lexer_scan(lxr); - if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, NULL, TRUE, 55)) goto error_return; if (lex_all_digits(lxr->lexer_buf)) { num_ena = (int) strtol(lxr->lexer_buf, &endp, 10); } else { printf("ERROR pindly enable count is not an integer\n"); goto error_return; } - if (num_ena != 0) { - goto error_return; - } t = lexer_scan(lxr); - if (!expect_token(t, ',', NULL, TRUE)) goto error_return; + if (!expect_token(t, ',', NULL, TRUE, 56)) goto error_return; t = lexer_scan(lxr); - if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, NULL, TRUE, 57)) goto error_return; if (lex_all_digits(lxr->lexer_buf)) { num_refs = (int) strtol(lxr->lexer_buf, &endp, 10); } else { @@ -1802,31 +1954,32 @@ BOOL f_pindly(char *line) } t = lexer_scan(lxr); - if (!expect_token(t, ')', NULL, TRUE)) goto error_return; + if (!expect_token(t, ')', NULL, TRUE, 58)) goto error_return; t = lexer_scan(lxr); // pwr - if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, NULL, TRUE, 59)) goto error_return; t = lexer_scan(lxr); // gnd - if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, NULL, TRUE, 60)) goto error_return; /* num_ios input ids */ for (i = 0; i < num_ios; i++) { t = lexer_scan(lxr); - if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, NULL, TRUE, 61)) goto error_return; pline = add_new_pindly_line(pindly_tab); (void) set_in_name(lxr->lexer_buf, pline); } + /* num_ena enable nodes which are ignored */ /* num_refs reference nodes which are ignored */ - for (i = 0; i < num_refs; i++) { + for (i = 0; i < num_ena + num_refs; i++) { t = lexer_scan(lxr); - if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, NULL, TRUE, 62)) goto error_return; } /* num_ios output ids */ pline = NULL; for (i = 0; i < num_ios; i++) { t = lexer_scan(lxr); - if (!expect_token(t, LEX_ID, NULL, TRUE)) goto error_return; + if (!expect_token(t, LEX_ID, NULL, TRUE, 63)) goto error_return; if (i == 0) pline = nth_pindly_entry(pindly_tab, i); else @@ -1834,7 +1987,10 @@ BOOL f_pindly(char *line) (void) set_out_name(lxr->lexer_buf, pline); } - gen_output_models(lxr); + if (!new_gen_output_models(lxr)) { + printf("ERROR in \"%s\"\n", line); + goto error_return;; + } gen_pindly_buffers(); delete_lexer(lxr); cleanup_pindly_tab(); From 77d56eb184831b8ec44f03213ae48eb568db02a0 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Sun, 30 Oct 2022 13:03:56 -0700 Subject: [PATCH 12/19] Fix a typo, add more comments. --- src/frontend/logicexp.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index 588dcc013..f5632bf4e 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -3,6 +3,8 @@ Convert PSpice LOGICEXP logic expressions into XSPICE gates. Extract timing delay estimates from PINDLY statements. + + Reference: PSpice A/D Reference Guide version 16.6 */ #include #include @@ -1282,6 +1284,13 @@ static void bparse(char *line, BOOL new_lexer) } /* End of logicexp parser */ +/* Start of f_logicexp which is called from udevices.c + See the PSpice reference which describes the LOGICEXP statement syntax. + Combinational gates are generated and usually have zero delays. + The PINDLY statements generate buffers and tristate buffers + which drive the primary outputs from the LOGICEXP outputs. + These buffers have their delays set. +*/ static LEXER current_lexer = NULL; static BOOL expect_token( @@ -1385,7 +1394,13 @@ error_return: return FALSE; } -/* pindly handling */ +/* Start of f_pindly which is called from udevices.c + See the PSpice reference which describes the PINDLY statement syntax. + Note that only two sections, PINDLY: and TRISTATE:, are considered. + Typical delays are estimated from the DELAY(...) functions. + XSPICE does not have the variety of delays that PSpice supports. + Output buffers and tristate buffers are generated. +*/ /* C++ with templates would generalize the different TABLEs */ typedef struct pindly_line *PLINE; struct pindly_line { @@ -1632,6 +1647,7 @@ static char *get_typ_estimate(char *min, char *typ, char *max) static char *typical_estimate(char *delay_str) { + /* Input string (t1,t2,t2) */ int which = 0; size_t i; char *s; @@ -1642,8 +1658,7 @@ static char *typical_estimate(char *delay_str) ds_clear(&dmin); ds_clear(&dtyp); ds_clear(&dmax); - for (i = 0; i < strlen(delay_str) - 1; i++) { - if (i == 0) continue; + for (i = 1; i < strlen(delay_str) - 1; i++) { if (delay_str[i] == ',') { which++; continue; From ab7634e72e329e4ee4cce7c194923588e84eb202 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Mon, 31 Oct 2022 17:44:07 -0700 Subject: [PATCH 13/19] Reduce the delays of 'zero' delay gates to 1.0e-11. Add decoder test for logicexpr and pindly. --- examples/p-to-n-examples/decoder.cir | 80 +++++++++++++++++++++++++++ examples/p-to-n-examples/decoder.stim | 21 +++++++ src/frontend/logicexp.c | 27 ++++++--- src/frontend/udevices.c | 22 +++++++- visualc/vngspice.vcxproj | 4 +- 5 files changed, 141 insertions(+), 13 deletions(-) create mode 100644 examples/p-to-n-examples/decoder.cir create mode 100644 examples/p-to-n-examples/decoder.stim diff --git a/examples/p-to-n-examples/decoder.cir b/examples/p-to-n-examples/decoder.cir new file mode 100644 index 000000000..86a7eb0c0 --- /dev/null +++ b/examples/p-to-n-examples/decoder.cir @@ -0,0 +1,80 @@ +decoder,cir + +* +* ----------------------------------------------------------- 74145 ------ +* BCD-To-Decimal Decoders/Drivers +* +* The TTL Logic Data Book, 1988, TI Pages 2-447 to 2-449 +* bss 3/17/94 +* +.SUBCKT 74145 A B C D O0 O1 O2 O3 O4 O5 O6 O7 O8 O9 ++ optional: DPWR=$G_DPWR DGND=$G_DGND ++ params: MNTYMXDLY=0 IO_LEVEL=0 + +U1LOG LOGICEXP(4,10) DPWR DGND ++ A B C D ++ O0_O O1_O O2_O O3_O O4_O O5_O O6_O O7_O O8_O O9_O ++ D0_GATE IO_STD MNTYMXDLY={MNTYMXDLY} IO_LEVEL={IO_LEVEL} ++ ++ LOGIC: ++ abar = {~A} ++ bbar = {~B} ++ cbar = {~C} ++ dbar = {~D} ++ O0_O = {~(abar & bbar & cbar & dbar)} ++ O1_O = {~(A & bbar & cbar & dbar)} ++ O2_O = {~(abar & B & cbar & dbar)} ++ O3_O = {~(A & B & cbar & dbar)} ++ O4_O = {~(abar & bbar & C & dbar)} ++ O5_O = {~(A & bbar & C & dbar)} ++ O6_O = {~(abar & B & C & dbar)} ++ O7_O = {~(A & B & C & dbar)} ++ O8_O = {~(abar & bbar & cbar & D)} ++ O9_O = {~(A & bbar & cbar & D)} + +U2DLY PINDLY(10,0,0) DPWR DGND ++ O0_O O1_O O2_O O3_O O4_O O5_O O6_O O7_O O8_O O9_O ++ O0 O1 O2 O3 O4 O5 O6 O7 O8 O9 ++ IO_STD MNTYMXDLY={MNTYMXDLY} IO_LEVEL={IO_LEVEL} ++ ++ PINDLY: ++ O0 O1 O2 O3 O4 O5 O6 O7 O8 O9 = { ++ CASE( ++ DELAY(-1,-1,50ns))} + +.ENDS 74145 +* + +* U1 STIM(4,4) $G_DPWR $G_DGND D C B A +* + IO_STD IO_LEVEL=0 +* + 0NS 0 LABEL=START 100NS INCR BY 1 200NS GOTO START -1 TIMES 1800NS 0 + +X14 A B C D O0 O1 O2 O3 O4 O5 O6 O7 O8 O9 74145 +a1 [d c b a] input_vec1 +.model input_vec1 d_source(input_file = "decoder.stim") + +.TRAN 4e-008 2U 0 +.save all + +.control +listing +run +eprint d c b a +eprint o0 o1 o2 o3 o4 o5 o6 o7 o8 o9 +* save data to input directory +cd $inputdir +eprvcd a b c d o0 o1 o2 o3 o4 o5 o6 o7 o8 o9 > decoder.vcd +* plotting the vcd file with GTKWave +if $oscompiled = 1 | $oscompiled = 8 ; MS Windows + shell start gtkwave decoder.vcd --script nggtk.tcl +else + if $oscompiled = 7 ; macOS, manual tweaking required (mark, insert, Zoom Fit) + shell open -a gtkwave decoder.vcd + else ; Linux and others + shell gtkwave decoder.vcd --script nggtk.tcl & + end +end +quit +.endc + +.END diff --git a/examples/p-to-n-examples/decoder.stim b/examples/p-to-n-examples/decoder.stim new file mode 100644 index 000000000..e220d3a0e --- /dev/null +++ b/examples/p-to-n-examples/decoder.stim @@ -0,0 +1,21 @@ +* T d c b a +* i +* m +* e +0ns 0s 0s 0s 0s +100ns 0s 0s 0s 1s +200ns 0s 0s 1s 0s +300ns 0s 0s 1s 1s +400ns 0s 1s 0s 0s +500ns 0s 1s 0s 1s +600ns 0s 1s 1s 0s +700ns 0s 1s 1s 1s +800ns 1s 0s 0s 0s +900ns 1s 0s 0s 1s +1.0us 1s 0s 1s 0s +1.1us 1s 0s 1s 1s +1.2us 1s 1s 0s 0s +1.3us 1s 1s 0s 1s +1.4us 1s 1s 1s 0s +1.5us 1s 1s 1s 1s +1.6us 0s 0s 0s 0s diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index f5632bf4e..448459cf7 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -628,39 +628,48 @@ static void gen_models(void) DS_CREATE(model, 64); ds_clear(&model); - ds_cat_printf(&model, ".model d_inv_zero_delay d_inverter"); + ds_cat_printf(&model, + ".model d_inv_zero_delay d_inverter(rise_delay=1.0e-11 fall_delay=1.0e-11)"); u_add_instance(ds_get_buf(&model)); ds_clear(&model); - ds_cat_printf(&model, ".model d__inverter__1 d_inverter"); + ds_cat_printf(&model, + ".model d__inverter__1 d_inverter(rise_delay=1.0e-11 fall_delay=1.0e-11)"); u_add_instance(ds_get_buf(&model)); ds_clear(&model); - ds_cat_printf(&model, ".model d__buffer__1 d_buffer"); + ds_cat_printf(&model, + ".model d__buffer__1 d_buffer(rise_delay=1.0e-11 fall_delay=1.0e-11)"); u_add_instance(ds_get_buf(&model)); ds_clear(&model); - ds_cat_printf(&model, ".model d__nand__1 d_nand"); + ds_cat_printf(&model, + ".model d__nand__1 d_nand(rise_delay=1.0e-11 fall_delay=1.0e-11)"); u_add_instance(ds_get_buf(&model)); ds_clear(&model); - ds_cat_printf(&model, ".model d__and__1 d_and"); + ds_cat_printf(&model, + ".model d__and__1 d_and(rise_delay=1.0e-11 fall_delay=1.0e-11)"); u_add_instance(ds_get_buf(&model)); ds_clear(&model); - ds_cat_printf(&model, ".model d__xnor__1 d_xnor"); + ds_cat_printf(&model, + ".model d__xnor__1 d_xnor(rise_delay=1.0e-11 fall_delay=1.0e-11)"); u_add_instance(ds_get_buf(&model)); ds_clear(&model); - ds_cat_printf(&model, ".model d__xor__1 d_xor"); + ds_cat_printf(&model, + ".model d__xor__1 d_xor(rise_delay=1.0e-11 fall_delay=1.0e-11)"); u_add_instance(ds_get_buf(&model)); ds_clear(&model); - ds_cat_printf(&model, ".model d__nor__1 d_nor"); + ds_cat_printf(&model, + ".model d__nor__1 d_nor(rise_delay=1.0e-11 fall_delay=1.0e-11)"); u_add_instance(ds_get_buf(&model)); ds_clear(&model); - ds_cat_printf(&model, ".model d__or__1 d_or"); + ds_cat_printf(&model, + ".model d__or__1 d_or(rise_delay=1.0e-11 fall_delay=1.0e-11)"); u_add_instance(ds_get_buf(&model)); ds_free(&model); diff --git a/src/frontend/udevices.c b/src/frontend/udevices.c index 06c10b70e..000316e37 100644 --- a/src/frontend/udevices.c +++ b/src/frontend/udevices.c @@ -719,7 +719,8 @@ struct card *replacement_udevice_cards(void) return NULL; } if (add_zero_delay_inverter_model) { - x = create_xlate_translated(".model d_zero_inv99 d_inverter"); + x = create_xlate_translated( + ".model d_zero_inv99 d_inverter(rise_delay=1.0e-11 fall_delay=1.0e-11)"); translated_p = add_xlator(translated_p, x); } if (add_drive_hilo) { @@ -727,7 +728,8 @@ struct card *replacement_udevice_cards(void) translated_p = add_xlator(translated_p, x); x = create_xlate_translated("a1 0 drive___0 dbuf1"); translated_p = add_xlator(translated_p, x); - x = create_xlate_translated(".model dbuf1 d_buffer"); + x = create_xlate_translated( + ".model dbuf1 d_buffer(rise_delay=1.0e-11 fall_delay=1.0e-11)"); translated_p = add_xlator(translated_p, x); x = create_xlate_translated(".ends hilo_dollar___lo"); translated_p = add_xlator(translated_p, x); @@ -735,7 +737,8 @@ struct card *replacement_udevice_cards(void) translated_p = add_xlator(translated_p, x); x = create_xlate_translated("a2 0 drive___1 dinv1"); translated_p = add_xlator(translated_p, x); - x = create_xlate_translated(".model dinv1 d_inverter"); + x = create_xlate_translated( + ".model dinv1 d_inverter(rise_delay=1.0e-11 fall_delay=1.0e-11)"); translated_p = add_xlator(translated_p, x); x = create_xlate_translated(".ends hilo_dollar___hi"); translated_p = add_xlator(translated_p, x); @@ -2499,6 +2502,11 @@ static char *get_estimate(struct timing_data *tdp) 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(). */ +static char *get_zero_rise_fall(void) +{ + return tprintf("(rise_delay=1.0e-11 fall_delay=1.0e-11)"); +} + static char *get_delays_ugate(char *rem) { char *rising, *falling, *delays = NULL; @@ -2514,7 +2522,11 @@ static char *get_delays_ugate(char *rem) if (strlen(rising) > 0 && strlen(falling) > 0) { delays = tprintf("(rise_delay = %s fall_delay = %s)", rising, falling); + } else { + delays = get_zero_rise_fall(); } + } else { + delays = get_zero_rise_fall(); } delete_timing_data(tdp1); delete_timing_data(tdp2); @@ -2536,7 +2548,11 @@ static char *get_delays_utgate(char *rem) if (rising && falling) { if (strlen(rising) > 0 && strlen(falling) > 0) { delays = tprintf("(delay = %s)", rising); + } else { + delays = tprintf("(delay=1.0e-11)"); } + } else { + delays = tprintf("(delay=1.0e-11)"); } delete_timing_data(tdp1); delete_timing_data(tdp2); diff --git a/visualc/vngspice.vcxproj b/visualc/vngspice.vcxproj index d709cfd23..31779cdb3 100644 --- a/visualc/vngspice.vcxproj +++ b/visualc/vngspice.vcxproj @@ -1005,6 +1005,7 @@ + @@ -1500,6 +1501,7 @@ + @@ -2755,4 +2757,4 @@ - \ No newline at end of file + From 12000922508235205b0f36130c22b2b604e5395d Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Tue, 1 Nov 2022 11:29:43 -0700 Subject: [PATCH 14/19] Add behavioral (LOGICEXP, PINDLY) test for 283 circuit. There are glitches in the simulation for some of the s* outputs. Probably due to not having inertial delays. And why not set 'zero' delays as close to zero as permitted by XSPICE. --- examples/p-to-n-examples/behav-283.cir | 91 ++++++++++++++++++++++++++ src/frontend/logicexp.c | 18 ++--- src/frontend/udevices.c | 12 ++-- 3 files changed, 106 insertions(+), 15 deletions(-) create mode 100644 examples/p-to-n-examples/behav-283.cir diff --git a/examples/p-to-n-examples/behav-283.cir b/examples/p-to-n-examples/behav-283.cir new file mode 100644 index 000000000..9711a6368 --- /dev/null +++ b/examples/p-to-n-examples/behav-283.cir @@ -0,0 +1,91 @@ +Behavioral CMOS 283 : 4-bit adder + +*-------------------------------------------------------------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 = "ex283.stim") + +.tran 0.01ns 2us +.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.vcd +* plotting the vcd file with GTKWave +if $oscompiled = 1 | $oscompiled = 8 ; MS Windows + shell start gtkwave behav-283.vcd --script nggtk.tcl +else + if $oscompiled = 7 ; macOS, manual tweaking required (mark, insert, Zoom Fit) + shell open -a gtkwave behav-283.vcd + else ; Linux and others + shell gtkwave behav-283.vcd --script nggtk.tcl & + end +end +quit +.endc +.end diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index 448459cf7..ff66e0a2b 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -629,47 +629,47 @@ static void gen_models(void) ds_clear(&model); ds_cat_printf(&model, - ".model d_inv_zero_delay d_inverter(rise_delay=1.0e-11 fall_delay=1.0e-11)"); + ".model d_inv_zero_delay d_inverter(rise_delay=1.0e-12 fall_delay=1.0e-12)"); u_add_instance(ds_get_buf(&model)); ds_clear(&model); ds_cat_printf(&model, - ".model d__inverter__1 d_inverter(rise_delay=1.0e-11 fall_delay=1.0e-11)"); + ".model d__inverter__1 d_inverter(rise_delay=1.0e-12 fall_delay=1.0e-12)"); u_add_instance(ds_get_buf(&model)); ds_clear(&model); ds_cat_printf(&model, - ".model d__buffer__1 d_buffer(rise_delay=1.0e-11 fall_delay=1.0e-11)"); + ".model d__buffer__1 d_buffer(rise_delay=1.0e-12 fall_delay=1.0e-12)"); u_add_instance(ds_get_buf(&model)); ds_clear(&model); ds_cat_printf(&model, - ".model d__nand__1 d_nand(rise_delay=1.0e-11 fall_delay=1.0e-11)"); + ".model d__nand__1 d_nand(rise_delay=1.0e-12 fall_delay=1.0e-12)"); u_add_instance(ds_get_buf(&model)); ds_clear(&model); ds_cat_printf(&model, - ".model d__and__1 d_and(rise_delay=1.0e-11 fall_delay=1.0e-11)"); + ".model d__and__1 d_and(rise_delay=1.0e-12 fall_delay=1.0e-12)"); u_add_instance(ds_get_buf(&model)); ds_clear(&model); ds_cat_printf(&model, - ".model d__xnor__1 d_xnor(rise_delay=1.0e-11 fall_delay=1.0e-11)"); + ".model d__xnor__1 d_xnor(rise_delay=1.0e-12 fall_delay=1.0e-12)"); u_add_instance(ds_get_buf(&model)); ds_clear(&model); ds_cat_printf(&model, - ".model d__xor__1 d_xor(rise_delay=1.0e-11 fall_delay=1.0e-11)"); + ".model d__xor__1 d_xor(rise_delay=1.0e-12 fall_delay=1.0e-12)"); u_add_instance(ds_get_buf(&model)); ds_clear(&model); ds_cat_printf(&model, - ".model d__nor__1 d_nor(rise_delay=1.0e-11 fall_delay=1.0e-11)"); + ".model d__nor__1 d_nor(rise_delay=1.0e-12 fall_delay=1.0e-12)"); u_add_instance(ds_get_buf(&model)); ds_clear(&model); ds_cat_printf(&model, - ".model d__or__1 d_or(rise_delay=1.0e-11 fall_delay=1.0e-11)"); + ".model d__or__1 d_or(rise_delay=1.0e-12 fall_delay=1.0e-12)"); u_add_instance(ds_get_buf(&model)); ds_free(&model); diff --git a/src/frontend/udevices.c b/src/frontend/udevices.c index 000316e37..1f0dc76cd 100644 --- a/src/frontend/udevices.c +++ b/src/frontend/udevices.c @@ -720,7 +720,7 @@ struct card *replacement_udevice_cards(void) } if (add_zero_delay_inverter_model) { x = create_xlate_translated( - ".model d_zero_inv99 d_inverter(rise_delay=1.0e-11 fall_delay=1.0e-11)"); + ".model d_zero_inv99 d_inverter(rise_delay=1.0e-12 fall_delay=1.0e-12)"); translated_p = add_xlator(translated_p, x); } if (add_drive_hilo) { @@ -729,7 +729,7 @@ struct card *replacement_udevice_cards(void) x = create_xlate_translated("a1 0 drive___0 dbuf1"); translated_p = add_xlator(translated_p, x); x = create_xlate_translated( - ".model dbuf1 d_buffer(rise_delay=1.0e-11 fall_delay=1.0e-11)"); + ".model dbuf1 d_buffer(rise_delay=1.0e-12 fall_delay=1.0e-12)"); translated_p = add_xlator(translated_p, x); x = create_xlate_translated(".ends hilo_dollar___lo"); translated_p = add_xlator(translated_p, x); @@ -738,7 +738,7 @@ struct card *replacement_udevice_cards(void) x = create_xlate_translated("a2 0 drive___1 dinv1"); translated_p = add_xlator(translated_p, x); x = create_xlate_translated( - ".model dinv1 d_inverter(rise_delay=1.0e-11 fall_delay=1.0e-11)"); + ".model dinv1 d_inverter(rise_delay=1.0e-12 fall_delay=1.0e-12)"); translated_p = add_xlator(translated_p, x); x = create_xlate_translated(".ends hilo_dollar___hi"); translated_p = add_xlator(translated_p, x); @@ -2504,7 +2504,7 @@ static char *get_estimate(struct timing_data *tdp) */ static char *get_zero_rise_fall(void) { - return tprintf("(rise_delay=1.0e-11 fall_delay=1.0e-11)"); + return tprintf("(rise_delay=1.0e-12 fall_delay=1.0e-12)"); } static char *get_delays_ugate(char *rem) @@ -2549,10 +2549,10 @@ static char *get_delays_utgate(char *rem) if (strlen(rising) > 0 && strlen(falling) > 0) { delays = tprintf("(delay = %s)", rising); } else { - delays = tprintf("(delay=1.0e-11)"); + delays = tprintf("(delay=1.0e-12)"); } } else { - delays = tprintf("(delay=1.0e-11)"); + delays = tprintf("(delay=1.0e-12)"); } delete_timing_data(tdp1); delete_timing_data(tdp2); From f6386bda0c7ff4d8f03530a6ec1018dd1b177859 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Wed, 2 Nov 2022 10:59:25 -0700 Subject: [PATCH 15/19] Remove most asserts. --- src/frontend/logicexp.c | 68 ++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index ff66e0a2b..335f0294b 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -121,6 +121,7 @@ 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; } @@ -133,6 +134,7 @@ 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 */ @@ -535,7 +537,6 @@ static TLINE tab_find(PTABLE pt, char *str, BOOL start_of_line) return NULL; } -//#define TABLE_PRINT #ifdef TABLE_PRINT static void table_print(TLINE first) { @@ -890,9 +891,9 @@ static PTABLE optimize_gen_tab(PTABLE pt) } } else if (val == '~') { found_tilde = TRUE; - assert(tok_count == 3); + if (tok_count != 3) goto quick_return; } else if (val == '=') { - assert(tok_count == 2); + if (tok_count != 2) goto quick_return; } val = lexer_scan(lxr); } @@ -904,7 +905,6 @@ static PTABLE optimize_gen_tab(PTABLE pt) lxr = new_lexer(t->line); } } - ds_free(&alias); delete_lexer(lxr); @@ -974,7 +974,11 @@ static PTABLE optimize_gen_tab(PTABLE pt) ds_clear(&tmp_name); } } else { - assert(val != LEX_OTHER); + if (val == LEX_OTHER) { + delete_parse_table(new_gen); + new_gen = NULL; + goto quick_return; + } if (val == '~') found_tilde = TRUE; ds_cat_printf(&scratch, "%c ", val); @@ -1015,15 +1019,13 @@ static PTABLE optimize_gen_tab(PTABLE pt) ds_free(&d_buf); } } // end of while (t) second pass + +quick_return: + ds_free(&alias); ds_free(&scratch); ds_free(&non_tmp_name); ds_free(&tmp_name); delete_lexer(lxr); - { - int print_it = 0; - if (print_it) - print_sym_tab(alias_tab, FALSE); - } delete_sym_tab(alias_tab); return new_gen; @@ -1072,26 +1074,27 @@ static void gen_gates(PTABLE gate_tab, SYM_TAB parser_symbols) } } else if (val == '~') { found_tilde = TRUE; - assert(tok_count == 3); + if (tok_count != 3) goto quick_return; } else if (val == '=') { - assert(tok_count == 2); + if (tok_count != 2) goto quick_return; } else if (lex_gate_op(val)) { - if (gate_op != 0) - assert(val == gate_op); + if (gate_op != 0) { + if (val != gate_op) goto quick_return; + } gate_op = val; } else { - assert(FALSE); + goto quick_return; } val = lexer_scan(lxr); } if (in_count == 1) { // buffer or inverter - assert(gate_op == 0); + if (gate_op != 0) goto quick_return; ds_cat_str(&gate_name, lex_gate_name('~', found_tilde)); } else if (in_count >= 2) { // AND, OR. XOR and inverses - assert(gate_op != 0); + if (gate_op == 0) goto quick_return; ds_cat_str(&gate_name, lex_gate_name(gate_op, found_tilde)); } else { - assert(FALSE); + goto quick_return; } ds_cat_printf(&instance, "%s ", get_inst_name()); if (in_count == 1) { @@ -1107,8 +1110,8 @@ static void gen_gates(PTABLE gate_tab, SYM_TAB parser_symbols) ds_cat_printf(&instance, "%s %s ", tail, ds_get_buf(&out_name)); ent = member_sym_tab(tail, parser_symbols); - assert(ent); - assert(ent->attribute & SYM_INVERTER); + if (!ent) goto quick_return; + if ((ent->attribute & SYM_INVERTER) == 0) goto quick_return; ent->ref_count--; } else { ds_cat_printf(&instance, "%s %s ", ds_get_buf(&in_names), @@ -1127,11 +1130,14 @@ static void gen_gates(PTABLE gate_tab, SYM_TAB parser_symbols) } u_add_instance(ds_get_buf(&instance)); } + +quick_return: delete_lexer(lxr); ds_free(&out_name); ds_free(&in_names); ds_free(&gate_name); ds_free(&instance); + return; } /* @@ -1208,6 +1214,7 @@ static void bevaluate(TLINE t, int deep) ds_free(&this); ds_free(&other); ds_free(&new_line); + return; } static void beval_order(void) @@ -1240,6 +1247,7 @@ static void beval_order(void) t = t->next; } } + return; } static void bparse(char *line, BOOL new_lexer) @@ -1259,7 +1267,7 @@ static void bparse(char *line, BOOL new_lexer) if (new_lexer) lex_init(line); - assert(parse_lexer); + if (!parse_lexer) return; lx = parse_lexer; lookahead = lex_set_start("logic:"); lookahead = lex_scan(); // "logic" @@ -1275,10 +1283,13 @@ static void bparse(char *line, BOOL new_lexer) beval_order(); + /* generate gates only when optimizations are successful */ opt_tab1 = optimize_gen_tab(gen_tab); - opt_tab2 = optimize_gen_tab(opt_tab1); - if (opt_tab2) { - gen_gates(opt_tab2, lx->lexer_sym_tab); + if (opt_tab1) { + opt_tab2 = optimize_gen_tab(opt_tab1); + if (opt_tab2) { + gen_gates(opt_tab2, lx->lexer_sym_tab); + } } delete_parse_table(opt_tab1); delete_parse_table(opt_tab2); @@ -1290,6 +1301,7 @@ static void bparse(char *line, BOOL new_lexer) gen_models(); ds_free(&stmt); delete_lexer(lx); + return; } /* End of logicexp parser */ @@ -1709,7 +1721,13 @@ static BOOL new_gen_output_models(LEXER lx) PLINE *pline_arr = NULL; arrlen = num_pindly_entries(pindly_tab); - assert(arrlen > 0); + if (arrlen <= 0) { + ds_free(&dly); + ds_free(&enable_name); + ds_free(&last_enable); + ds_free(&dtyp_max_str); + return FALSE; + } pline_arr = TMALLOC(PLINE, arrlen); ds_clear(&last_enable); val = lexer_scan(lx); From d05689eed8c6dbb8879d84aa965fea8e7012fcb0 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Thu, 3 Nov 2022 09:36:56 -0700 Subject: [PATCH 16/19] Add pindly tristate example. Cleanup error handling. --- examples/p-to-n-examples/behav-tristate.cir | 69 ++++++++++++++++++ examples/p-to-n-examples/behav-tristate.stim | 13 ++++ src/frontend/logicexp.c | 76 ++++++++++++++------ 3 files changed, 137 insertions(+), 21 deletions(-) create mode 100644 examples/p-to-n-examples/behav-tristate.cir create mode 100644 examples/p-to-n-examples/behav-tristate.stim diff --git a/examples/p-to-n-examples/behav-tristate.cir b/examples/p-to-n-examples/behav-tristate.cir new file mode 100644 index 000000000..b796c9616 --- /dev/null +++ b/examples/p-to-n-examples/behav-tristate.cir @@ -0,0 +1,69 @@ +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 +x1 a1 y1 oe 74hc126a +a_1 [ 1a oebar a1 oe ] input_vec1 +.model input_vec1 d_source(input_file = "behav-tristate.stim") + +.tran 0.01ns 1us +.control +run +listing +edisplay +eprint 1a oebar 1y a1 oe y1 +quit +.endc +.end diff --git a/examples/p-to-n-examples/behav-tristate.stim b/examples/p-to-n-examples/behav-tristate.stim new file mode 100644 index 000000000..4b3dd558d --- /dev/null +++ b/examples/p-to-n-examples/behav-tristate.stim @@ -0,0 +1,13 @@ +* 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 +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 diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index 335f0294b..f7fae0842 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -560,7 +560,7 @@ static void aerror(char *s); static void amatch(int t); static void bexpr(void); static void bfactor(void); -static void bparse(char *line, BOOL new_lexer); +static BOOL bparse(char *line, BOOL new_lexer); static int lookahead = 0; static int adepth = 0; @@ -891,9 +891,13 @@ static PTABLE optimize_gen_tab(PTABLE pt) } } else if (val == '~') { found_tilde = TRUE; - if (tok_count != 3) goto quick_return; + if (tok_count != 3) { + goto quick_return; + } } else if (val == '=') { - if (tok_count != 2) goto quick_return; + if (tok_count != 2) { + goto quick_return; + } } val = lexer_scan(lxr); } @@ -1250,9 +1254,10 @@ static void beval_order(void) return; } -static void bparse(char *line, BOOL new_lexer) +static BOOL bparse(char *line, BOOL new_lexer) { int stmt_num = 0; + BOOL ret_val = TRUE; LEXER lx; PTABLE opt_tab1 = NULL, opt_tab2 = NULL; DS_CREATE(stmt, LEX_BUF_SZ); @@ -1267,7 +1272,7 @@ static void bparse(char *line, BOOL new_lexer) if (new_lexer) lex_init(line); - if (!parse_lexer) return; + if (!parse_lexer) return FALSE; lx = parse_lexer; lookahead = lex_set_start("logic:"); lookahead = lex_scan(); // "logic" @@ -1290,10 +1295,15 @@ static void bparse(char *line, BOOL new_lexer) 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); delete_parse_gen_tables(); + if (!ret_val) { + break; + } } ds_free(&d_curr_line); @@ -1301,7 +1311,7 @@ static void bparse(char *line, BOOL new_lexer) gen_models(); ds_free(&stmt); delete_lexer(lx); - return; + return ret_val; } /* End of logicexp parser */ @@ -1348,6 +1358,7 @@ BOOL f_logicexp(char *line) { int t, num_ins = 0, num_outs = 0, i; char *endp; + BOOL ret_val = TRUE; lex_init(line); current_lexer = parse_lexer; @@ -1404,10 +1415,10 @@ BOOL f_logicexp(char *line) //printf("TMODEL: %s\n", parse_lexer->lexer_buf); (void) add_sym_tab_entry(parse_lexer->lexer_buf, SYM_TMODEL, &parse_lexer->lexer_sym_tab); - bparse(line, FALSE); + ret_val = bparse(line, FALSE); current_lexer = NULL; - return TRUE; + return ret_val; error_return: delete_lexer(parse_lexer); @@ -1737,12 +1748,16 @@ static BOOL new_gen_output_models(LEXER lx) in_pindly = TRUE; in_tristate = FALSE; val = lexer_scan(lx); - if (val != ':') goto err_return; + if (val != ':') { + goto err_return; + } } else if (eq(lx->lexer_buf, "tristate")) { in_pindly = FALSE; in_tristate = TRUE; val = lexer_scan(lx); - if (val != ':') goto err_return; + if (val != ':') { + goto err_return; + } } else if (eq(lx->lexer_buf, "setup_hold") || eq(lx->lexer_buf, "width") || eq(lx->lexer_buf, "freq") @@ -1755,16 +1770,21 @@ static BOOL new_gen_output_models(LEXER lx) while (val == LEX_ID) { if (prit) printf("pindly out \"%s\"\n", lx->lexer_buf); pline = find_pindly_out_name(pindly_tab, lx->lexer_buf); - if (pline) + if (pline) { pline_arr[idx++] = pline; - else + } else { goto err_return; + } val = lexer_scan(lx); } typ_max_val = 0.0; - if (val != '=') goto err_return; + if (val != '=') { + goto err_return; + } val = lexer_scan(lx); - if (val != '{') goto err_return; + if (val != '{') { + goto err_return; + } val = lexer_scan(lx); while (val != '}') { if (val == LEX_ID) { @@ -1788,7 +1808,9 @@ static BOOL new_gen_output_models(LEXER lx) if (prit) printf("estimate \"%s\"\n", typical_estimate(ds_get_buf(&dly))); tmps = typical_estimate(ds_get_buf(&dly)); - if (!tmps) goto err_return; + if (!tmps) { + goto err_return; + } typ_val = strtof(tmps, &units); if (typ_val > typ_max_val) { ds_clear(&delay_string); @@ -1831,9 +1853,13 @@ static BOOL new_gen_output_models(LEXER lx) invert = TRUE; if (prit) printf("tristate enable %s ", lx->lexer_buf); val = lexer_scan(lx); - if (val != '=') goto err_return; + if (val != '=') { + goto err_return; + } val = lexer_scan(lx); - if (val != LEX_ID) goto err_return; + if (val != LEX_ID) { + goto err_return; + } if (prit) printf("ena \"%s\"\n", lx->lexer_buf); ds_clear(&enable_name); if (invert) @@ -1845,7 +1871,9 @@ static BOOL new_gen_output_models(LEXER lx) ds_clear(&last_enable); ds_cat_ds(&last_enable, &enable_name); val = lexer_scan(lx); - if (val != LEX_ID) goto err_return; + if (val != LEX_ID) { + goto err_return; + } } else if (ds_get_length(&last_enable) > 0) { ds_clear(&enable_name); ds_cat_ds(&enable_name, &last_enable); @@ -1864,9 +1892,13 @@ static BOOL new_gen_output_models(LEXER lx) val = lexer_scan(lx); } typ_max_val = 0.0; - if (val != '=') goto err_return; + if (val != '=') { + goto err_return; + } val = lexer_scan(lx); - if (val != '{') goto err_return; + if (val != '{') { + goto err_return; + } val = lexer_scan(lx); while (val != '}') { if (val == LEX_ID) { @@ -1890,7 +1922,9 @@ static BOOL new_gen_output_models(LEXER lx) if (prit) printf("estimate \"%s\"\n", typical_estimate(ds_get_buf(&dly))); tmps = typical_estimate(ds_get_buf(&dly)); - if (!tmps) goto err_return; + if (!tmps) { + goto err_return; + } typ_val = strtof(tmps, &units); if (typ_val > typ_max_val) { ds_clear(&delay_string); From f9236131ff4138eb498b00f1dd793d883ee24013 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Thu, 3 Nov 2022 11:28:39 -0700 Subject: [PATCH 17/19] Typo, 2 x1 subcircuits. --- examples/p-to-n-examples/behav-tristate.cir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/p-to-n-examples/behav-tristate.cir b/examples/p-to-n-examples/behav-tristate.cir index b796c9616..81341662f 100644 --- a/examples/p-to-n-examples/behav-tristate.cir +++ b/examples/p-to-n-examples/behav-tristate.cir @@ -54,7 +54,7 @@ U1 PINDLY(1,1,0) DPWR DGND * .SUBCKT 74HCT125 1A 1Y 1OEBAR x1 1a 1y oebar 74hct125 * .SUBCKT 74HC126A A1 Y1 OE1 -x1 a1 y1 oe 74hc126a +x2 a1 y1 oe 74hc126a a_1 [ 1a oebar a1 oe ] input_vec1 .model input_vec1 d_source(input_file = "behav-tristate.stim") From 104afe77cbb6de5a837c26f6e339873f11277698 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Sun, 6 Nov 2022 10:09:04 -0800 Subject: [PATCH 18/19] Remove asserts, replace fixed size lexer_buf. --- src/frontend/logicexp.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index f7fae0842..4b4522b17 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -138,18 +138,19 @@ static void print_sym_tab(SYM_TAB t, BOOL with_addr) /* End of btree symbol table */ /* Start of lexical scanner */ -#include -#define LEX_ID 256 -#define LEX_OTHER 257 -#define LEX_BUF_SZ 512 +#define LEX_ID 256 +#define LEX_OTHER 257 +#define LEX_BUF_SZ 512 +#define LEX_INIT_SZ 128 typedef struct lexer *LEXER; struct lexer { - char lexer_buf[LEX_BUF_SZ]; + char *lexer_buf; char *lexer_line; int lexer_pos; int lexer_back; SYM_TAB lexer_sym_tab; + size_t lexer_blen; }; static LEXER parse_lexer = NULL; @@ -161,7 +162,9 @@ static LEXER new_lexer(char *line) lx->lexer_line = TMALLOC(char, (strlen(line) + 1)); strcpy(lx->lexer_line, line); lx->lexer_pos = lx->lexer_back = 0; - lx->lexer_buf[0] = '\0'; + lx->lexer_blen = LEX_INIT_SZ; + lx->lexer_buf = TMALLOC(char, lx->lexer_blen); + (void) memset(lx->lexer_buf, 0, lx->lexer_blen); lx->lexer_sym_tab = NULL; return lx; } @@ -170,6 +173,8 @@ static void delete_lexer(LEXER lx) { if (!lx) return; + if (lx->lexer_buf) + tfree(lx->lexer_buf); if (lx->lexer_line) tfree(lx->lexer_line); if (lx->lexer_sym_tab) @@ -321,14 +326,22 @@ static int lexer_scan(LEXER lx) else if (lex_oper(c)) return c; else if (lex_ident(c)) { - int i = 0; + size_t i = 0; while (lex_ident(c)) { + if (i >= lx->lexer_blen) { + lx->lexer_blen *= 2; + lx->lexer_buf = + TREALLOC(char, lx->lexer_buf, lx->lexer_blen); + } lx->lexer_buf[i] = (char) c; - assert(i < LEX_BUF_SZ); i++; c = lexer_getchar(lx); } - assert(i < LEX_BUF_SZ); + if (i >= lx->lexer_blen) { + lx->lexer_blen *= 2; + lx->lexer_buf = + TREALLOC(char, lx->lexer_buf, lx->lexer_blen); + } lx->lexer_buf[i] = '\0'; if (c != '\0') lexer_putback(lx); From 94a0030fdef08be8b90d488e565aaaae8eee807a Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 7 Nov 2022 17:50:21 +0100 Subject: [PATCH 19/19] Add logicexp.c to fftw and shared project files --- visualc/sharedspice.vcxproj | 2 ++ visualc/vngspice-fftw.vcxproj | 2 ++ 2 files changed, 4 insertions(+) diff --git a/visualc/sharedspice.vcxproj b/visualc/sharedspice.vcxproj index 4a4e6a5ea..ad20b12d3 100644 --- a/visualc/sharedspice.vcxproj +++ b/visualc/sharedspice.vcxproj @@ -497,6 +497,7 @@ + @@ -1041,6 +1042,7 @@ + diff --git a/visualc/vngspice-fftw.vcxproj b/visualc/vngspice-fftw.vcxproj index e3716f983..c3a54f6bd 100644 --- a/visualc/vngspice-fftw.vcxproj +++ b/visualc/vngspice-fftw.vcxproj @@ -944,6 +944,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 + @@ -1492,6 +1493,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 +