Now that checks on actuals and formals have been fixed for X* instances, some older PSpice libraries will not translate correctly in psa mode. This commit removes unnecessary power and ground nodes from X* instances of subcircuits where the nodes are optional. These X* instances occur within the body of another subcircuit which is being translated. MicroCap libraries that we can translate in ngspice do not have such cases. To enable the removal of the power and ground nodes, set ps_global_tmodels=1 in .spiceinit. This is not set by default since an extra pass through the circuit word list is necessary to find the subcircuits whose instances do not require power and ground node removal. Without enabling this feature, errors reporting too many parameters may be reported.

This commit is contained in:
Brian Taylor 2024-11-20 14:03:08 -08:00 committed by Holger Vogt
parent 5980869040
commit 6500caeba1
4 changed files with 137 additions and 5 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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