From 44c69f5bf53a66917227db2c3e7fd56facb1624e Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Sat, 26 Nov 2022 09:40:35 -0800 Subject: [PATCH] Handle cases where logicexp has a timing model but no pindly. This is rare, only 22 tests from the digital libraries. Move digital examples, add missing .spiceint file. --- examples/digital/digital_devices/.spiceinit | 1 + .../digital_devices}/behav-568.cir | 0 .../digital_devices}/behav-568.stim | 0 src/frontend/logicexp.c | 69 +++++++++++++++++-- src/frontend/udevices.c | 13 ++++ src/include/ngspice/udevices.h | 1 + 6 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 examples/digital/digital_devices/.spiceinit rename examples/{p-to-n-examples => digital/digital_devices}/behav-568.cir (100%) rename examples/{p-to-n-examples => digital/digital_devices}/behav-568.stim (100%) diff --git a/examples/digital/digital_devices/.spiceinit b/examples/digital/digital_devices/.spiceinit new file mode 100644 index 000000000..aeee13ea7 --- /dev/null +++ b/examples/digital/digital_devices/.spiceinit @@ -0,0 +1 @@ +set ngbehavior=ltpsa diff --git a/examples/p-to-n-examples/behav-568.cir b/examples/digital/digital_devices/behav-568.cir similarity index 100% rename from examples/p-to-n-examples/behav-568.cir rename to examples/digital/digital_devices/behav-568.cir diff --git a/examples/p-to-n-examples/behav-568.stim b/examples/digital/digital_devices/behav-568.stim similarity index 100% rename from examples/p-to-n-examples/behav-568.stim rename to examples/digital/digital_devices/behav-568.stim diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index 6bbdfbf87..be7c78b99 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -292,6 +292,32 @@ static char *lex_gate_name(int c, BOOL not) return buf; } +static char *tmodel_gate_name(int c, BOOL not) +{ + /* Returns an XSPICE model name for the case where + logicexp does not have a corresponding pindly + but does have a UGATE timing model (not d0_gate). + */ + static char buf[32]; + switch (c) { + case '&': + if (not) + sprintf(buf, "dxspice_dly_nand"); + else + sprintf(buf, "dxspice_dly_and"); + break; + case '|': + if (not) + sprintf(buf, "dxspice_dly_nor"); + else + sprintf(buf, "dxspice_dly_or"); + break; + default: + return NULL; + } + return buf; +} + static int lex_gate_op(int c) { switch (c) { @@ -584,6 +610,7 @@ static int adepth = 0; static int max_adepth = 0; static DSTRING d_curr_line; static int number_of_instances = 0; +static BOOL use_tmodel_delays = FALSE; static BOOL inverters_needed(void) { @@ -888,7 +915,7 @@ 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 + Usually, optimize_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. */ @@ -1131,7 +1158,7 @@ static void gen_gates(PTABLE gate_tab, SYM_TAB parser_symbols) tok_count = 0; gate_op = 0; in_count = 0; - while (val != '\0') { + while (val != '\0') { // while val loop tok_count++; if (val == LEX_ID) { idnum++; @@ -1170,13 +1197,33 @@ static void gen_gates(PTABLE gate_tab, SYM_TAB parser_symbols) goto quick_return; } val = lexer_scan(lxr); - } + } // end while val loop + if (in_count == 1) { // buffer or inverter 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 if (gate_op == 0) goto quick_return; - ds_cat_str(&gate_name, lex_gate_name(gate_op, found_tilde)); + if (use_tmodel_delays) { + /* This is the case when logicexp has a UGATE + timing model (not d0_gate) and no pindly. + */ + SYM_TAB entry = NULL; + char *nm1 = 0; + entry = member_sym_tab(ds_get_buf(&out_name), parser_symbols); + if (entry && (entry->attribute & SYM_OUTPUT)) { + nm1 = tmodel_gate_name(gate_op, found_tilde); + if (nm1) { + ds_cat_str(&gate_name, nm1); + } + } + if (!nm1) { + nm1 = lex_gate_name(gate_op, found_tilde); + ds_cat_str(&gate_name, nm1); + } + } else { + ds_cat_str(&gate_name, lex_gate_name(gate_op, found_tilde)); + } } else { goto quick_return; } @@ -1537,7 +1584,19 @@ BOOL f_logicexp(char *line) /* timing model */ t = lex_scan(); if (!expect_token(t, LEX_ID, NULL, TRUE, 12)) goto error_return; - //printf("TMODEL: %s\n", parse_lexer->lexer_buf); + if (!eq(parse_lexer->lexer_buf, "d0_gate")) { + u_add_logicexp_model(parse_lexer->lexer_buf, + "d_and", "dxspice_dly_and"); + u_add_logicexp_model(parse_lexer->lexer_buf, + "d_nand", "dxspice_dly_nand"); + u_add_logicexp_model(parse_lexer->lexer_buf, + "d_or", "dxspice_dly_or"); + u_add_logicexp_model(parse_lexer->lexer_buf, + "d_nor", "dxspice_dly_nor"); + use_tmodel_delays = TRUE; + } else { + use_tmodel_delays = FALSE; + } (void) add_sym_tab_entry(parse_lexer->lexer_buf, SYM_TMODEL, &parse_lexer->lexer_sym_tab); ret_val = bparse(line, FALSE); diff --git a/src/frontend/udevices.c b/src/frontend/udevices.c index 1f0dc76cd..14c9b0571 100644 --- a/src/frontend/udevices.c +++ b/src/frontend/udevices.c @@ -777,6 +777,19 @@ void u_add_instance(char *str) } } +static BOOL gen_timing_model( + char *tmodel, char *utype, char *xspice, char *newname, Xlatorp xlp); + +void u_add_logicexp_model(char *tmodel, char *xspice_gate, char *model_name) +{ + Xlatorp xlp = NULL; + xlp = create_xlator(); + if (gen_timing_model(tmodel, "ugate", xspice_gate, model_name, xlp)) { + append_xlator(translated_p, xlp); + } + delete_xlator(xlp); +} + void initialize_udevice(char *subckt_line) { Xlatep xdata; diff --git a/src/include/ngspice/udevices.h b/src/include/ngspice/udevices.h index 6f734e588..0c4ec37e3 100644 --- a/src/include/ngspice/udevices.h +++ b/src/include/ngspice/udevices.h @@ -8,5 +8,6 @@ void initialize_udevice(char *subckt_line); struct card *replacement_udevice_cards(void); void cleanup_udevice(void); void u_add_instance(char *str); +void u_add_logicexp_model(char *tmodel, char *xspice_gate, char *model_name); #endif