diff --git a/src/frontend/inpcompat.c b/src/frontend/inpcompat.c index e865997c4..6c3faaa27 100644 --- a/src/frontend/inpcompat.c +++ b/src/frontend/inpcompat.c @@ -463,6 +463,12 @@ static struct card *u_instances(struct card *startcard) BOOL insub = FALSE; int ps_global_tmodels = 0; + /* NOTE: PSpice ref. manual Product Version 16.5 page 105. + Subcircuits can be nested. That is, an X device can appear between + .SUBCKT and .ENDS commands. However, subcircuit definitions cannot + be nested. That is, a .SUBCKT statement cannot appear in the + statements between a .SUBCKT and a .ENDS. + */ if (!cp_getvar("ps_global_tmodels", CP_NUM, &ps_global_tmodels, 0)) { ps_global_tmodels = 0; } @@ -472,6 +478,7 @@ static struct card *u_instances(struct card *startcard) while (c) { char *line = c->line; if (ciprefix(".subckt", line)) { + u_subckt_line(line); insub = TRUE; } else if (ciprefix(".ends", line)) { insub = FALSE; diff --git a/src/frontend/logicexp.c b/src/frontend/logicexp.c index 46b061ac8..dd9509b91 100644 --- a/src/frontend/logicexp.c +++ b/src/frontend/logicexp.c @@ -468,7 +468,7 @@ static void clear_name_list(NAME_ENTRY nelist) } /* End of name entries */ -/* Start of infix to posfix */ +/* Start of infix to postfix */ #define STACK_SIZE 100 #define PUSH_ERROR 1 #define POP_ERROR 2 @@ -987,7 +987,7 @@ err_return: return status; } -/* End of infix to posfix */ +/* End of infix to postfix */ /* Start of logicexp parser */ static void aerror(char *s); diff --git a/src/frontend/udevices.c b/src/frontend/udevices.c index b4018fe12..ecd5dd7d0 100644 --- a/src/frontend/udevices.c +++ b/src/frontend/udevices.c @@ -293,6 +293,7 @@ static NAME_ENTRY input_names_list = NULL; static NAME_ENTRY output_names_list = NULL; static NAME_ENTRY tristate_names_list = NULL; static NAME_ENTRY port_names_list = NULL; +static NAME_ENTRY xsubckt_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; @@ -415,6 +416,15 @@ static void add_port_name(char *name) add_pin_name(name, &port_names_list); } +static void add_xsubckt_name(char *name) +{ + if (!xsubckt_names_list) { + xsubckt_names_list = add_name_entry(name, xsubckt_names_list); + } else { + (void) add_name_entry(name, xsubckt_names_list); + } +} + void u_remember_pin(char *name, int type) { switch (type) { @@ -934,6 +944,8 @@ void initialize_udevice(char *subckt_line) } else { printf("NOTE using global models linear list search\n"); } + clear_name_list(xsubckt_names_list); + xsubckt_names_list = NULL; return; } new_names_list = NULL; @@ -1025,6 +1037,8 @@ void cleanup_udevice(BOOL global) nghash_free(global_model_hash_table, NULL, NULL); } global_model_hash_table = NULL; + clear_name_list(xsubckt_names_list); + xsubckt_names_list = NULL; return; } cleanup_translated_xlator(); @@ -4284,6 +4298,106 @@ BOOL u_check_instance(char *line) } } +void u_subckt_line(char *subckt_line) +{ + /* If the .subckt line contains "optional:", then assume this + refers to dpwr & dgnd or vdd & vss. + Save the names of those subcircuits without "optional:" + */ + char *copy_line, *tok, *pos; + if (!ciprefix(".subckt", subckt_line)) { return; } + pos = strstr(subckt_line, "optional:"); + if (!pos) { + DS_CREATE(ds, 128); + copy_line = tprintf("%s", subckt_line); + ds_clear(&ds); + tok = strtok(copy_line, " \t"); // .subckt + if (tok) { + tok = strtok(NULL, " \t"); // subcircuit name + if (tok) { + ds_cat_str(&ds, tok); + add_xsubckt_name(ds_get_buf(&ds)); + } + } + + ds_free(&ds); + tfree(copy_line); + } + return; +} + +static NAME_ENTRY subcircuit_has_no_optional(char *str) +{ + /* str is the X* subcircuit instance line + Return NAME_ENTRY for matching subcircuit with no optional: + */ + NAME_ENTRY x = NULL, next = NULL; + char *pos; + if (!xsubckt_names_list) { return NULL; } + for (x = xsubckt_names_list; x; x = next) { + pos = strstr(str, x->name); + if (pos) { + char *tail, *tok; + tail = tprintf("%s", pos); + tok = strtok(tail, " \t"); // subcircuit name in X* instance + if (eq(tok, x->name)) { + tfree(tail); + return x; + } + tfree(tail); + } + next = x->next; + } + return NULL; +} + +static int remove_optional(DSTRING *dstrp, char *line) +{ + /* Remove optional: DPWR, DGND, VDD, and VSS from X* subckt instances. + The line string is all lower case. + Return 0 when no removal was attempted. + */ + char *s; + BOOL was_space; + if (!ps_global_tmodels || subcircuit_has_no_optional(line)) { + return 0; + } + ds_clear(dstrp); + s = line; + was_space = FALSE; + while (*s) { + if (isalpha(*s)) { + if (was_space) { + if (strncmp(s, "dpwr ", 5) == 0) { + s += 4; + } else if (strncmp(s, "dgnd ", 5) == 0) { + s += 4; + } else if (strncmp(s, "vdd ", 4) == 0) { + s += 3; + } else if (strncmp(s, "vss ", 4) == 0) { + s += 3; + } else { + ds_cat_char(dstrp, *s); + s++; + } + was_space = FALSE; + } else { + ds_cat_char(dstrp, *s); + s++; + } + } else { + if (isspace(*s)) { + was_space = TRUE; + } else { + was_space = FALSE; + } + ds_cat_char(dstrp, *s); + s++; + } + } + return 1; +} + /* NOTE The input nline is expected to be a card in the deck which contains a Pspice u* instance statement with all the '+' continuations added @@ -4299,15 +4413,25 @@ BOOL u_process_instance(char *nline) if (ciprefix("x", nline)) { - /* An X* instance of a subckt is translated unchanged */ - Xlate_datap xdp = create_xlate_translated(nline); - Xlatorp xlp = create_xlator(); + /* Usually an X* instance of a subckt is translated unchanged */ + /* If ps_global_tmodels!=0, then dpwr, dgnd, vdd, vss maybe removed */ + Xlate_datap xdp = NULL; + Xlatorp xlp = NULL; + DS_CREATE(dstr, 128); + + if (remove_optional(&dstr, nline)) { + xdp = create_xlate_translated(ds_get_buf(&dstr)); + } else { + xdp = create_xlate_translated(nline); + } + xlp = create_xlator(); (void) add_xlator(xlp, xdp); append_xlator(translated_p, xlp); if (ps_ports_and_pins & 4) { printf("TRANS_IN %s\n", nline); } delete_xlator(xlp); + ds_free(&dstr); return TRUE; } hdr = create_instance_header(nline); diff --git a/src/include/ngspice/udevices.h b/src/include/ngspice/udevices.h index 265b578de..f496098c5 100644 --- a/src/include/ngspice/udevices.h +++ b/src/include/ngspice/udevices.h @@ -16,5 +16,6 @@ void u_add_instance(char *str); void u_add_logicexp_model(char *tmodel, char *xspice_gate, char *model_name); void u_remember_pin(char *name, int type); struct udevices_info u_get_udevices_info(void); +void u_subckt_line(char *subckt_line); #endif