From f570b04d6cd878021f3705da4f0903cb1da650b3 Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Thu, 26 Jan 2023 15:49:18 -0800 Subject: [PATCH] For unspecified gate delays (logic and tristate gates), which PSpice would consider as zero, set the rise and fall delays to 1.e-12s (the minimum for Xspice). For dff, jkff, dlatch, and srlatch use the Xspice default 1.0ns for rise and fall delays. If the ngspice variable (ps_port_directions & 2) is true, write the translated subckt to stdout, with TRANS_OUT prefix, for debugging purposes. The user could edit and replace the translated subckt if desired. --- src/frontend/udevices.c | 159 ++++++++++++++++++++++++++++++++++------ 1 file changed, 138 insertions(+), 21 deletions(-) diff --git a/src/frontend/udevices.c b/src/frontend/udevices.c index 7a6cf0d36..9da22f51f 100644 --- a/src/frontend/udevices.c +++ b/src/frontend/udevices.c @@ -58,10 +58,13 @@ #include "ngspice/macros.h" #include "ngspice/udevices.h" #include "ngspice/logicexp.h" +#include "ngspice/dstring.h" extern struct card* insert_new_line( struct card* card, char* line, int linenum, int linenum_orig); +#define USE_SHORTEST_DELAYS +#define FF_LATCH_DEFAULT_DELAYS //#define TRACE /* device types */ @@ -207,6 +210,8 @@ struct name_entry { NAME_ENTRY next; }; +static char *get_zero_rise_fall(void); + #ifdef TRACE static void print_name_list(NAME_ENTRY nelist); #endif @@ -393,7 +398,7 @@ static void add_all_port_names(char *subckt_line) if (!subckt_line) { return; } - if (ps_port_directions >= 2) { + if (ps_port_directions & 4) { printf("TRANS_IN %s\n", subckt_line); } else if (ps_port_directions) { printf("%s\n", subckt_line); @@ -757,8 +762,25 @@ struct card *replacement_udevice_cards(void) translated_p = add_xlator(translated_p, x); } + if (ps_port_directions & 2) { + char *tmp = NULL, *pos = NULL, *posp = NULL; + tmp = TMALLOC(char, strlen(current_subckt) + 1); + (void) memcpy(tmp, current_subckt, strlen(current_subckt) + 1); + pos = strstr(tmp, "optional:"); + posp = strstr(tmp, "params:"); + /* If there is an optional: and a param: then posp > pos */ + if (pos) { + /* Remove the optional: section if present */ + *pos = '\0'; + if (posp) { + strcat(tmp, posp); + } + } + printf("\nTRANS_OUT %s\n", tmp); + tfree(tmp); + } for (x = first_xlator(translated_p); x; x = next_xlator(translated_p)) { - if (ps_port_directions >= 2) { + if (ps_port_directions & 2) { printf("TRANS_OUT %s\n", x->translated); } new_str = copy(x->translated); @@ -773,6 +795,18 @@ struct card *replacement_udevice_cards(void) nextcard = insert_new_line(nextcard, new_str, 0, 0); } } + if (ps_port_directions & 2) { + char *p1 = NULL, *p2 = NULL; + DS_CREATE(tmpds, 64); + p1 = strstr(current_subckt, ".subckt"); + p1 += strlen(".subckt"); + p1 = skip_ws(p1); + p2 = p1; + p2 = skip_non_ws(p2); + ds_cat_mem(&tmpds, p1, (p2 - p1)); + printf("TRANS_OUT .ends %s\n\n", ds_get_buf(&tmpds)); + ds_free(&tmpds); + } return newcard; } @@ -811,8 +845,9 @@ void initialize_udevice(char *subckt_line) num_name_collisions = 0; /* Variable ps_port_directions != 0 to turn on pins and ports. - If ps_port_directions >= 2 also print the Pspice input lines with - prefix TRANS_IN, and the translated Xspice equivalent lines + If (ps_port_directions & 4) also print the Pspice input lines with + prefix TRANS_IN. + If (ps_port_directions & 2) print translated Xspice equivalent lines with prefix TRANS_OUT. */ if (!cp_getvar("ps_port_directions", CP_NUM, &ps_port_directions, 0)) { @@ -842,7 +877,12 @@ void initialize_udevice(char *subckt_line) model_xlatorp = create_xlator(); default_models = create_xlator(); /* .model d0_gate ugate () */ +#ifdef USE_SHORTEST_DELAYS + xdata = create_xlate("", "(rise_delay=1.0e-12 fall_delay=1.0e-12)", + "ugate", "", "d0_gate", ""); +#else xdata = create_xlate("", "", "ugate", "", "d0_gate", ""); +#endif (void) add_xlator(default_models, xdata); /* .model d0_gff ugff () */ xdata = create_xlate("", "", "ugff", "d_dlatch", "d0_gff", ""); @@ -853,7 +893,12 @@ void initialize_udevice(char *subckt_line) xdata = create_xlate("", "", "ueff", "", "d0_eff", ""); (void) add_xlator(default_models, xdata); /* .model d0_tgate utgate () */ +#ifdef USE_SHORTEST_DELAYS + xdata = create_xlate("", "(delay=1.0e-12)", + "utgate", "", "d0_tgate", ""); +#else xdata = create_xlate("", "", "utgate", "", "d0_tgate", ""); +#endif (void) add_xlator(default_models, xdata); /* reset for the new subckt */ add_zero_delay_inverter_model = FALSE; @@ -1939,6 +1984,9 @@ static Xlatorp gen_compound_instance(struct compound_instance *compi) char *new_inst = NULL, *model_stmt = NULL, *final_model_name = NULL; char *new_stmt = NULL, *instance_name = NULL; char *tmp; +#ifdef USE_SHORTEST_DELAYS + char *zero_delay_str = NULL; +#endif size_t sz = 0; Xlatorp xxp = NULL; Xlatep xdata = NULL; @@ -2016,10 +2064,19 @@ static Xlatorp gen_compound_instance(struct compound_instance *compi) } } /* .model statement for the input gates */ +#ifdef USE_SHORTEST_DELAYS + zero_delay_str = get_zero_rise_fall(); + model_stmt = tprintf(".model %s %s%s", + model_name, ingates, zero_delay_str); +#else model_stmt = tprintf(".model %s %s", model_name, ingates); +#endif xdata = create_xlate_translated(model_stmt); xxp = add_xlator(xxp, xdata); tfree(model_stmt); +#ifdef USE_SHORTEST_DELAYS + tfree(zero_delay_str); +#endif /* Final OR/NOR, AND/NAND gate */ final_model_name = tprintf("%s_out", model_name); @@ -2185,6 +2242,9 @@ static Xlatorp gen_gate_instance(struct gate_instance *gip) } else { char *new_model_nm = NULL; char *new_stmt = NULL; +#ifdef USE_SHORTEST_DELAYS + char *zero_rise_fall = NULL; +#endif /* Use connector as original gate output and tristate input; tristate has original gate output and utgate delay; @@ -2198,10 +2258,19 @@ static Xlatorp gen_gate_instance(struct gate_instance *gip) xxp = add_xlator(xxp, xdata); tfree(new_stmt); /* new model statement e.g. .model d_au2nand3 d_nand */ +#ifdef USE_SHORTEST_DELAYS + zero_rise_fall = get_zero_rise_fall(); + new_stmt = tprintf(".model %s %s%s", modelnm, xspice, + zero_rise_fall); +#else new_stmt = tprintf(".model %s %s", modelnm, xspice); +#endif xdata = create_xlate_translated(new_stmt); xxp = add_xlator(xxp, xdata); tfree(new_stmt); +#ifdef USE_SHORTEST_DELAYS + tfree(zero_rise_fall); +#endif /* now the added tristate */ /* model name of added tristate */ new_model_nm = tprintf("d_a%s_tribuf", iname); @@ -2342,10 +2411,19 @@ static Xlatorp gen_gate_instance(struct gate_instance *gip) char *str1 = NULL, *modname = NULL; if (i == 0) { /* Zero delay model for all original array instances */ - str1 = tprintf(".model %s %s", primary_model, xspice); +#ifdef USE_SHORTEST_DELAYS + char *zero_delay_str = get_zero_rise_fall(); + str1 = tprintf(".model %s %s%s", + primary_model, xspice, zero_delay_str); +#else + str1 = tprintf(".model %s %s", primary_model, xspice); +#endif xdata = create_xlate_translated(str1); xxp = add_xlator(xxp, xdata); tfree(str1); +#ifdef USE_SHORTEST_DELAYS + tfree(zero_delay_str); +#endif } /* model name of added tristate */ modname = tprintf("d_a%s_tribuf", iname); @@ -2714,19 +2792,35 @@ static char *get_delays_ueff(char *rem) } if (clkd && setd) { delays = tprintf("(clk_delay = %s " - "set_delay = %s reset_delay = %s " - "rise_delay = 1.0ns fall_delay = 2.0ns)", + "set_delay = %s reset_delay = %s" +#ifdef FF_LATCH_DEFAULT_DELAYS + " rise_delay = 1.0ns fall_delay = 1.0ns)", +#else + " rise_delay = 1.0ns fall_delay = 2.0ns)", +#endif clkd, setd, resetd); } else if (clkd) { - delays = tprintf("(clk_delay = %s " - "rise_delay = 1.0ns fall_delay = 2.0ns)", + delays = tprintf("(clk_delay = %s" +#ifdef FF_LATCH_DEFAULT_DELAYS + " rise_delay = 1.0ns fall_delay = 1.0ns)", +#else + " rise_delay = 1.0ns fall_delay = 2.0ns)", +#endif clkd); } else if (setd) { - delays = tprintf("(set_delay = %s reset_delay = %s " - "rise_delay = 1.0ns fall_delay = 2.0ns)", + delays = tprintf("(set_delay = %s reset_delay = %s" +#ifdef FF_LATCH_DEFAULT_DELAYS + " rise_delay = 1.0ns fall_delay = 1.0ns)", +#else + " rise_delay = 1.0ns fall_delay = 2.0ns)", +#endif setd, resetd); } else { +#ifdef FF_LATCH_DEFAULT_DELAYS + delays = tprintf("(rise_delay = 1.0ns fall_delay = 1.0ns)"); +#else delays = tprintf("(rise_delay = 1.0ns fall_delay = 2.0ns)"); +#endif } delete_timing_data(tdp1); delete_timing_data(tdp2); @@ -2793,14 +2887,14 @@ static char *get_delays_ugff(char *rem, char *d_name) s1 = NULL; if (enab) { if (d_delay) { - s1 = tprintf("%s = %s enable_delay = %s ", + s1 = tprintf("%s = %s enable_delay = %s", dname, d_delay, enab); } else { - s1 = tprintf("enable_delay = %s ", enab); + s1 = tprintf("enable_delay = %s", enab); } } else { if (d_delay) { - s1 = tprintf("%s = %s ", dname, d_delay); + s1 = tprintf("%s = %s", dname, d_delay); } } setd = NULL; @@ -2816,18 +2910,35 @@ static char *get_delays_ugff(char *rem, char *d_name) } else if (tppcqhl && strlen(tppcqhl) > 0) { setd = resetd = tppcqhl; } + s2 = NULL; if (setd) { - s2 = tprintf("set_delay = %s reset_delay = %s " - "rise_delay = 1.0ns fall_delay = 2.0ns)", + s2 = tprintf("set_delay = %s reset_delay = %s" +#ifdef FF_LATCH_DEFAULT_DELAYS + " rise_delay = 1.0ns fall_delay = 1.0ns", +#else + " rise_delay = 1.0ns fall_delay = 2.0ns", +#endif setd, resetd); } else { - s2 = tprintf("rise_delay = 1.0ns fall_delay = 2.0ns)"); +#ifdef FF_LATCH_DEFAULT_DELAYS + s2 = tprintf("rise_delay = 1.0ns fall_delay = 1.0ns"); +#else + s2 = tprintf("rise_delay = 1.0ns fall_delay = 2.0ns"); +#endif } if (s1) { - delays = tprintf("(%s%s", s1, s2); + if (s2) { + delays = tprintf("(%s %s)", s1, s2); + } else { + delays = tprintf("(%s)", s1); + } tfree(s1); } else { - delays = tprintf("(%s", s2); + if (s2) { + delays = tprintf("(%s)", s2); + } else { + delays = NULL; + } } tfree(s2); delete_timing_data(tdp1); @@ -3632,6 +3743,9 @@ BOOL u_process_instance(char *nline) if (!xspice) { if (eq(itype, "logicexp")) { delete_instance_hdr(hdr); + if (ps_port_directions & 4) { + printf("TRANS_IN %s\n", nline); + } behav_ret = f_logicexp(nline); if (!behav_ret && current_subckt) { fprintf(stderr, "ERROR in %s\n", current_subckt); @@ -3644,6 +3758,9 @@ BOOL u_process_instance(char *nline) return behav_ret; } else if (eq(itype, "pindly")) { delete_instance_hdr(hdr); + if (ps_port_directions & 4) { + printf("TRANS_IN %s\n", nline); + } behav_ret = f_pindly(nline); if (!behav_ret && current_subckt) { fprintf(stderr, "ERROR in %s\n", current_subckt); @@ -3662,7 +3779,7 @@ BOOL u_process_instance(char *nline) return FALSE; } } - if (ps_port_directions >= 2) { + if (ps_port_directions & 4) { printf("TRANS_IN %s\n", nline); } /* Skip past instance name, type, pwr, gnd */ @@ -3722,7 +3839,7 @@ BOOL u_process_model_line(char *line) if (n > 0 && line[n] == '\n') line[n] = '\0'; if (strncmp(line, ".model ", strlen(".model ")) == 0) { - if (ps_port_directions >= 2) { + if (ps_port_directions & 4) { printf("TRANS_IN %s\n", line); } newline = TMALLOC(char, strlen(line) + 1);