Check for name collisions between nodes generated during translation from Pspice to Xspice and instance pin or subckt port names. These are reported as ERRRORs.

This commit is contained in:
Brian Taylor 2022-07-26 10:56:56 -07:00 committed by Holger Vogt
parent e9b5a9a957
commit 2d9f86c742
3 changed files with 406 additions and 4 deletions

View File

@ -8362,7 +8362,7 @@ static struct card *u_instances(struct card *startcard)
if (create_called) {
cleanup_udevice();
}
initialize_udevice();
initialize_udevice(subcktcard->line);
create_called = TRUE;
} else {
/* Pspice definition of .subckt card:
@ -8405,6 +8405,9 @@ static struct card *u_instances(struct card *startcard)
if (last_newcard) {
last_newcard->nextcard = card; // the .ends card
}
} else {
models_ok = models_not_ok = 0;
udev_ok = udev_not_ok = 0;
}
}
if (models_not_ok > 0 || udev_not_ok > 0) {

View File

@ -57,6 +57,22 @@
extern struct card* insert_new_line(
struct card* card, char* line, int linenum, int linenum_orig);
/*
When TRACE is defined, the Pspice input lines are printed with
prefix TRANS_IN, and the translated Xspice equivalent lines are
printed with prefix TRANS_OUT. Also, the name lists or btrees
are dumped.
*/
//#define TRACE
/*
Choose name lists or btrees. Which is more efficient depends on
whether the names are entered in almost sorted order. Usuually there
will be < 20 entries.
*/
static int use_lists = 0;
static int use_btrees = 1;
/* device types */
#define D_AND 0
#define D_AO 1
@ -193,13 +209,287 @@ struct timing_data {
int estimate;
};
/* btree */
typedef struct nnode *TREE;
struct nnode {
char *name;
TREE left;
TREE right;
};
static TREE new_nnode(char *name)
{
TREE newp;
newp = TMALLOC(struct nnode, 1);
newp->left = NULL;
newp->right = NULL;
newp->name = TMALLOC(char, strlen(name) + 1);
strcpy(newp->name, name);
return newp;
}
static TREE tinsert(char *name, TREE t)
{
int cmp;
if (t == NULL) {
t = new_nnode(name);
return t;
}
cmp = strcmp(name, t->name);
if (cmp < 0) {
t->left = tinsert(name, t->left);
} else if (cmp > 0) {
t->right = tinsert(name, t->right);
}
return t;
}
static int tmember(char *name, TREE t)
{
int cmp;
while (t != NULL) {
cmp = strcmp(name, t->name);
if (cmp == 0) {
return 1;
} else if (cmp < 0) {
t = t->left;
} else {
t = t->right;
}
}
return 0;
}
static void delete_btree(TREE t)
{
if (t == NULL) { return; }
delete_btree(t->left);
delete_btree(t->right);
tfree(t->name);
tfree(t);
}
#ifdef TRACE
static void print_btree(TREE t)
{
if (t == NULL) { return; }
print_btree(t->left);
printf("%s\n", t->name);
print_btree(t->right);
}
#endif
/* name entries */
typedef struct name_entry *NAME_ENTRY;
struct name_entry {
char *name;
NAME_ENTRY next;
};
static NAME_ENTRY new_name_entry(char *name)
{
NAME_ENTRY newp;
newp = TMALLOC(struct name_entry, 1);
newp->next = NULL;
newp->name = TMALLOC(char, strlen(name) + 1);
strcpy(newp->name, name);
return newp;
}
static NAME_ENTRY add_name_entry(char *name, NAME_ENTRY nelist)
{
NAME_ENTRY newlist = NULL, x = NULL, last = NULL;
if (nelist == NULL) {
newlist = new_name_entry(name);
return newlist;
}
for (x = nelist; x; x = x->next) {
/* No duplicates */
if (eq(x->name, name)) {
return nelist;
}
last = x;
}
x = new_name_entry(name);
last->next = x;
return nelist;
}
static NAME_ENTRY find_name_entry(char *name, NAME_ENTRY nelist)
{
NAME_ENTRY x = NULL;
if (!nelist) {
return NULL;
}
for (x = nelist; x; x = x->next) {
/* No duplicates */
if (eq(x->name, name)) {
return x;
}
}
return NULL;
}
static void clear_name_list(NAME_ENTRY nelist)
{
NAME_ENTRY x = NULL, next = NULL;
if (!nelist) { return; }
for (x = nelist; x; x = next) {
next = x->next;
if (x->name) { tfree(x->name); }
tfree(x);
}
}
#ifdef TRACE
static void print_name_list(NAME_ENTRY nelist)
{
NAME_ENTRY x = NULL;
if (!nelist) { return; }
for (x = nelist; x; x = x->next) {
printf("%s\n", x->name);
}
}
#endif
/*
static data cleared and reset by initialize_udevice(),
cleared by cleanup_udevice().
*/
static TREE new_names_btree = NULL;
static TREE pin_names_btree = NULL;
static NAME_ENTRY new_names_list = NULL;
static NAME_ENTRY pin_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 void check_name_unused(char *name)
{
if (use_btrees) {
if (tmember(name, new_names_btree)) {
printf("ERROR udevice name %s already used\n", name);
num_name_collisions++;
} else {
if (!new_names_btree) {
new_names_btree = tinsert(name, new_names_btree);
} else {
(void) tinsert(name, new_names_btree);
}
}
}
if (use_lists) {
if (find_name_entry(name, new_names_list)) {
printf("ERROR udevice name %s already used\n", name);
num_name_collisions++;
} else {
if (!new_names_list) {
new_names_list = add_name_entry(name, new_names_list);
} else {
(void) add_name_entry(name, new_names_list);
}
}
}
}
static void tree1_in_tree2(TREE t1, TREE t2)
{
if (t1 == NULL) { return; }
tree1_in_tree2(t1->left, t2);
if (tmember(t1->name, t2)) {
printf("ERROR name collision: internal node %s "
"collides with a pin or port\n", t1->name);
num_name_collisions++;
}
tree1_in_tree2(t1->right, t2);
}
static BOOL there_are_name_collisions(void)
{
if (use_btrees) {
if (new_names_btree && pin_names_btree) {
tree1_in_tree2(new_names_btree, pin_names_btree);
}
}
if (use_lists) {
if (new_names_list && pin_names_list) {
NAME_ENTRY x = NULL;
for (x = new_names_list; x; x = x->next) {
if (find_name_entry(x->name, pin_names_list)) {
printf("ERROR name collision: internal node %s "
"collides with a pin or port\n", x->name);
num_name_collisions++;
}
}
}
}
//#define IGNORE_COLLISIONS
#ifdef IGNORE_COLLISIONS
return FALSE;
#else
return (num_name_collisions > 0 ? TRUE : FALSE);
#endif
}
static void add_pin_name(char *name)
{
if (strncmp(name, "$d_", 3) != 0) {
if (use_btrees) {
if (!pin_names_btree) {
pin_names_btree = tinsert(name, pin_names_btree);
} else {
(void) tinsert(name, pin_names_btree);
}
}
if (use_lists) {
if (!pin_names_list) {
pin_names_list = add_name_entry(name, pin_names_list);
} else {
(void) add_name_entry(name, pin_names_list);
}
}
}
}
static void add_port_names(char *subckt_line)
{
char *copy_line, *tok, *pos;
if (!subckt_line) {
return;
}
#ifdef TRACE
printf("TRANS_IN %s\n", subckt_line);
#endif
copy_line = tprintf("%s", subckt_line);
pos = strstr(copy_line, "optional:");
if (pos) {
*pos = '\0';
} else {
pos = strstr(copy_line, "params:");
if (pos) {
*pos = '\0';
} else {
pos = strstr(copy_line, "text:");
if (pos) {
*pos = '\0';
}
}
}
#ifdef TRACE
printf("%s\n", copy_line);
#endif
/* skip past .subckt and its name */
tok = strtok(copy_line, " \t");
tok = strtok(NULL, " \t");
while ((tok = strtok(NULL, " \t")) != NULL) {
add_pin_name(tok);
}
tfree(copy_line);
}
/*
Compound gates have delays added to the final gate.
*/
@ -502,11 +792,17 @@ struct card *replacement_udevice_cards(void)
int count = 0;
if (!translated_p) { return NULL; }
if (there_are_name_collisions()) {
return NULL;
}
if (add_zero_delay_inverter_model) {
x = create_xlate_translated(".model d_zero_inv99 d_inverter");
translated_p = add_xlator(translated_p, x);
}
for (x = first_xlator(translated_p); x; x = next_xlator(translated_p)) {
#ifdef TRACE
printf("TRANS_OUT %s\n", x->translated);
#endif
new_str = copy(x->translated);
if (count == 0) {
count++;
@ -519,13 +815,25 @@ struct card *replacement_udevice_cards(void)
nextcard = insert_new_line(nextcard, new_str, 0, 0);
}
}
#ifdef TRACE
printf("TRANS_OUT\n");
#endif
return newcard;
}
void initialize_udevice(void)
void initialize_udevice(char *subckt_line)
{
Xlatep xdata;
new_names_btree = NULL;
pin_names_btree = NULL;
new_names_list = NULL;
pin_names_list = NULL;
num_name_collisions = 0;
if (subckt_line && strncmp(subckt_line, ".subckt", 7) == 0) {
add_port_names(subckt_line);
}
create_translated_xlator();
model_xlatorp = create_xlator();
default_models = create_xlator();
@ -555,6 +863,38 @@ void cleanup_udevice(void)
delete_xlator(default_models);
default_models = NULL;
add_zero_delay_inverter_model = FALSE;
if (pin_names_btree) {
#ifdef TRACE
printf("PIN_PORT_NAMES_BTREE\n");
print_btree(pin_names_btree);
#endif
delete_btree(pin_names_btree);
pin_names_btree = NULL;
}
if (new_names_btree) {
#ifdef TRACE
printf("NEW_NAMES_BTREE\n");
print_btree(new_names_btree);
#endif
delete_btree(new_names_btree);
new_names_btree = NULL;
}
if (pin_names_list) {
#ifdef TRACE
printf("PIN_NAMES_LIST\n");
print_name_list(pin_names_list);
#endif
clear_name_list(pin_names_list);
pin_names_list = NULL;
}
if (new_names_list) {
#ifdef TRACE
printf("NEW_NAMES_LIST\n");
print_name_list(new_names_list);
#endif
clear_name_list(new_names_list);
new_names_list = NULL;
}
}
static Xlatep create_xlate_model(char *delays,
@ -1167,6 +1507,7 @@ char *new_inverter(char *iname, char *node, Xlatorp xlp)
instance_name = tprintf("a%s_%s", iname, node);
not_node = tprintf("not_%s", instance_name);
check_name_unused(not_node);
tmp = tprintf("%s %s %s d_zero_inv99",
instance_name, node, not_node);
/* instantiate the new inverter */
@ -1242,6 +1583,7 @@ static Xlatorp gen_dff_instance(struct dff_instance *ip)
clrb = ip->clrbar;
xxp = create_xlator();
add_pin_name(preb);
if (eq(preb, "$d_hi")) {
preb = "NULL";
} else {
@ -1249,6 +1591,7 @@ static Xlatorp gen_dff_instance(struct dff_instance *ip)
preb = new_inverter(iname, preb, xxp);
}
add_pin_name(clrb);
if (eq(clrb, "$d_hi")) {
clrb = "NULL";
} else {
@ -1257,19 +1600,23 @@ static Xlatorp gen_dff_instance(struct dff_instance *ip)
}
clk = ip->clk;
add_pin_name(clk);
tmodel = ip->tmodel;
/* model name, same for each dff */
modelnm = tprintf("d_a%s_%s", iname, itype);
for (i = 0; i < num_gates; i++) {
char *instance_name = NULL;
qout = qarr[i];
add_pin_name(qout);
if (eq(qout, "$d_nc")) {
qout = "NULL";
}
qbout = qbarr[i];
add_pin_name(qbout);
if (eq(qbout, "$d_nc")) {
qbout = "NULL";
}
add_pin_name(darr[i]);
instance_name = tprintf("a%s_%d", iname, i);
s1 = tprintf( "%s %s %s %s %s %s %s %s",
instance_name, darr[i], clk, preb, clrb, qout, qbout, modelnm
@ -1315,6 +1662,7 @@ static Xlatorp gen_jkff_instance(struct jkff_instance *ip)
clrb = ip->clrbar;
xxp = create_xlator();
add_pin_name(preb);
if (eq(preb, "$d_hi")) {
preb = "NULL";
} else {
@ -1322,6 +1670,7 @@ static Xlatorp gen_jkff_instance(struct jkff_instance *ip)
preb = new_inverter(iname, preb, xxp);
}
add_pin_name(clrb);
if (eq(clrb, "$d_hi")) {
clrb = "NULL";
} else {
@ -1331,6 +1680,7 @@ static Xlatorp gen_jkff_instance(struct jkff_instance *ip)
/* require a positive edge clock */
clkb = ip->clkbar;
add_pin_name(clkb);
clkb = new_inverter(iname, clkb, xxp);
tmodel = ip->tmodel;
@ -1339,13 +1689,17 @@ static Xlatorp gen_jkff_instance(struct jkff_instance *ip)
for (i = 0; i < num_gates; i++) {
char *instance_name = NULL;
qout = qarr[i];
add_pin_name(qout);
if (eq(qout, "$d_nc")) {
qout = "NULL";
}
qbout = qbarr[i];
add_pin_name(qbout);
if (eq(qbout, "$d_nc")) {
qbout = "NULL";
}
add_pin_name(jarr[i]);
add_pin_name(karr[i]);
instance_name = tprintf("a%s_%d", iname, i);
s1 = tprintf("%s %s %s %s %s %s %s %s %s",
instance_name, jarr[i], karr[i], clkb, preb, clrb,
@ -1390,6 +1744,7 @@ static Xlatorp gen_dltch_instance(struct dltch_instance *ip)
clrb = ip->clrbar;
xxp = create_xlator();
add_pin_name(preb);
if (eq(preb, "$d_hi")) {
preb = "NULL";
} else {
@ -1397,6 +1752,7 @@ static Xlatorp gen_dltch_instance(struct dltch_instance *ip)
preb = new_inverter(iname, preb, xxp);
}
add_pin_name(clrb);
if (eq(clrb, "$d_hi")) {
clrb = "NULL";
} else {
@ -1404,25 +1760,35 @@ static Xlatorp gen_dltch_instance(struct dltch_instance *ip)
clrb = new_inverter(iname, clrb, xxp);
}
gate = ip->gate;
add_pin_name(gate);
tmodel = ip->tmodel;
/* model name, same for each latch */
modelnm = tprintf("d_a%s_%s", iname, itype);
for (i = 0; i < num_gates; i++) {
char *instance_name = NULL;
qout = qarr[i];
add_pin_name(qout);
instance_name = tprintf("a%s_%d", iname, i);
if (eq(qout, "$d_nc")) {
/* NULL not allowed??? */
s1 = tprintf("%s %s %s %s %s nco_%s_%d",
instance_name, darr[i], gate, preb, clrb, iname, i);
s3 = tprintf("nco_%s_%d", iname, i);
check_name_unused(s3);
tfree(s3);
} else {
s1 = tprintf("%s %s %s %s %s %s",
instance_name, darr[i], gate, preb, clrb, qout);
}
add_pin_name(darr[i]);
qbout = qbarr[i];
add_pin_name(qbout);
if (eq(qbout, "$d_nc")) {
/* NULL not allowed??? */
s2 = tprintf(" ncn_%s_%d %s", iname, i, modelnm);
s3 = tprintf("ncn_%s_%d", iname, i);
check_name_unused(s3);
tfree(s3);
} else {
s2 = tprintf(" %s %s", qbout, modelnm);
}
@ -1470,6 +1836,7 @@ static Xlatorp gen_srff_instance(struct srff_instance *srffp)
clrb = srffp->clrbar;
xxp = create_xlator();
add_pin_name(preb);
if (eq(preb, "$d_hi")) {
preb = "NULL";
} else {
@ -1477,6 +1844,7 @@ static Xlatorp gen_srff_instance(struct srff_instance *srffp)
preb = new_inverter(iname, preb, xxp);
}
add_pin_name(clrb);
if (eq(clrb, "$d_hi")) {
clrb = "NULL";
} else {
@ -1484,25 +1852,36 @@ static Xlatorp gen_srff_instance(struct srff_instance *srffp)
clrb = new_inverter(iname, clrb, xxp);
}
gate = srffp->gate;
add_pin_name(gate);
tmodel = srffp->tmodel;
/* model name, same for each latch */
modelnm = tprintf("d_a%s_%s", iname, itype);
for (i = 0; i < num_gates; i++) {
char *instance_name = NULL;
qout = qarr[i];
add_pin_name(qout);
instance_name = tprintf("a%s_%d", iname, i);
add_pin_name(sarr[i]);
add_pin_name(rarr[i]);
if (eq(qout, "$d_nc")) {
/* NULL not allowed??? */
s1 = tprintf("%s %s %s %s %s %s nco_%s_%d",
instance_name, sarr[i], rarr[i], gate, preb, clrb, iname, i);
s3 = tprintf("nco_%s_%d", iname, i);
check_name_unused(s3);
tfree(s3);
} else {
s1 = tprintf("%s %s %s %s %s %s %s",
instance_name, sarr[i], rarr[i], gate, preb, clrb, qout);
}
qbout = qbarr[i];
add_pin_name(qbout);
if (eq(qbout, "$d_nc")) {
/* NULL not allowed??? */
s2 = tprintf(" ncn_%s_%d %s", iname, i, modelnm);
s3 = tprintf("ncn_%s_%d", iname, i);
check_name_unused(s3);
tfree(s3);
} else {
s2 = tprintf(" %s %s", qbout, modelnm);
}
@ -1584,6 +1963,7 @@ static Xlatorp gen_compound_instance(struct compound_instance *compi)
k = 0;
for (i = 0; i < num_gates; i++) {
connector[i] = tprintf("con_%s_%d", inst, i);
check_name_unused(connector[i]);
num_ins_kept = 0;
tmp[0] = '\0';
/* $d_hi AND gate inputs are ignored */
@ -1592,6 +1972,7 @@ static Xlatorp gen_compound_instance(struct compound_instance *compi)
if (!eq(inarr[k], logic_val)) {
num_ins_kept++;
sprintf(tmp + strlen(tmp), " %s", inarr[k]);
add_pin_name(inarr[k]);
}
k++;
}
@ -1632,6 +2013,7 @@ static Xlatorp gen_compound_instance(struct compound_instance *compi)
sprintf(tmp + strlen(tmp), " %s", connector[i]);
}
/* instance statement for the final gate */
add_pin_name(output);
instance_name = tprintf("a%s_out", inst);
new_stmt = tprintf("%s [%s ] %s %s",
instance_name, tmp, output, final_model_name);
@ -1665,7 +2047,7 @@ static Xlatorp gen_gate_instance(struct gate_instance *gip)
BOOL add_tristate = FALSE;
char *modelnm = NULL, *startvec = NULL, *endvec = NULL;
char *input_buf = NULL, *instance_name = NULL;
int i, j, k, width, num_gates;
int i, j, k, width, num_gates, num_ins, num_outs;
size_t sz;
Xlatorp xxp = NULL;
Xlatep xdata = NULL;
@ -1677,9 +2059,18 @@ static Xlatorp gen_gate_instance(struct gate_instance *gip)
outarr = gip->outputs;
width = gip->width;
num_gates = gip->num_gates;
num_ins = gip->num_ins;
num_outs = gip->num_outs;
enable = gip->enable;
tmodel = gip->tmodel;
vector = has_vector_inputs(itype);
for (i = 0; i < num_ins; i++) {
add_pin_name(inarr[i]);
}
if (enable) { add_pin_name(enable); }
for (i = 0; i < num_outs; i++) {
add_pin_name(outarr[i]);
}
if (num_gates == 1) {
char *inst_begin = NULL;
@ -1772,6 +2163,7 @@ static Xlatorp gen_gate_instance(struct gate_instance *gip)
Complete the translation of the original gate adding
the connector as output + model name.
*/
check_name_unused(connector);
new_stmt = tprintf("%s %s %s", inst_begin, connector, modelnm);
xdata = create_xlate_instance(new_stmt, xspice, "", modelnm);
xxp = add_xlator(xxp, xdata);
@ -1861,6 +2253,7 @@ static Xlatorp gen_gate_instance(struct gate_instance *gip)
iname, i, startvec, input_buf, endvec);
/* connector if required for tristate */
connector = tprintf("con_a%s_%d_%s", iname, i, outarr[i]);
check_name_unused(connector);
}
} else {
s1 = tprintf("a%s_%d %s%s%s",
@ -3051,6 +3444,9 @@ BOOL u_process_instance(char *nline)
delete_instance_hdr(hdr);
return FALSE;
}
#ifdef TRACE
printf("TRANS_IN %s\n", nline);
#endif
// printf("iname %s itype %s\n", hdr->instance_name, itype);
/* Skip past instance name, type, pwr, gnd */
p1 = skip_past_words(nline, 4);
@ -3093,6 +3489,9 @@ BOOL u_process_model_line(char *line)
if (n > 0 && line[n] == '\n') line[n] = '\0';
if (strncmp(line, ".model ", strlen(".model ")) == 0) {
#ifdef TRACE
printf("TRANS_IN %s\n", line);
#endif
newline = TMALLOC(char, strlen(line) + 1);
(void) memcpy(newline, line, strlen(line) + 1);
retval = u_process_model(newline, line);

View File

@ -4,7 +4,7 @@
BOOL u_process_instance(char *line);
BOOL u_process_model_line(char *line);
BOOL u_check_instance(char *line);
void initialize_udevice(void);
void initialize_udevice(char *subckt_line);
struct card *replacement_udevice_cards(void);
void cleanup_udevice(void);