Compare commits

...
10 Commits
Author SHA1 Message Date
Tim Edwards e4a4621b96 Merge branch 'master' into netgen-1.5 2025-01-02 02:00:01 -05:00
Tim Edwards 1d286f9973 Corrected an issue with generating proxy pins that had previously
forced flattening to be done whenever any pin mismatch occurred,
which undermined the whole proxy pin method.  With the proxy pins
fixed, reinstated the method of avoiding flattening when pin
issues can be trivially corrected.  Also:  Added output to the
pin matching for one mismatch case that was being missed.
2025-01-01 13:27:39 -05:00
Tim Edwards 3ca77300ac Merge branch 'master' into netgen-1.5 2024-12-28 02:00:02 -05:00
Tim Edwards 6d2ef396ef After giving the previous code change some more thought, I
decided that it is beneficial to break symmetries by net name;
it's just that net names should not be used before all symmetries
related to pins have been broken.  So I rewrote the compare
routine to take an argument allowing or disallowing net name
matches, and make one call to break symmetries by pin name
followed by another call to break symmetries by net name.  This
still solves the original problem, but does not allow symmetries
to be broken randomly on internal nets if names have been matched
in both netlists.  Otherwise the output may report nets that
appear to be swapped, making the output confusing.
2024-12-27 16:20:00 -05:00
Tim Edwards 2483b7440f Corrected an error in "ResolveAutomorphsByPin" where the code states
to check that the nodes with matching names are pins, but never does.
This results in an attempt to resolve automorphs by matching pin
names AND net names.  However, net names can match without the nets
matching, as pointed out by Andrey Bondar (private communication).
Fixed simply by adding the specified check that the node being name-
matched is actually a pin.
2024-12-26 21:20:24 -05:00
Tim Edwards 236fba18aa Merge branch 'master' into netgen-1.5 2024-11-15 02:00:04 -05:00
Tim Edwards 49c0de0433 Corrected an error found by Sylvain Munaut and discussed on
open-source-silicon slack on Nov. 3 in which the simple verilog
expression "assign name1 = name2[a:b]";  this revealed an error
where the parsing of "name2" was being incorrectly run with
GetBusTok() which must be called when the token starts with "[".
This problem existed both for the left-hand-side parsing and
the right-hand-side parsing, and has been fixed for both (where
either side may be a subset of a bus and the other a complete
bus).
2024-11-14 21:28:51 -05:00
Tim Edwards 3b9dca0cf2 Implemented the patch from Sylvain Munaut in github PR#90 (issue
that the position in the code has shifted quite a bit and I
don't really trust that git will do a clean merge.
2024-11-14 20:39:19 -05:00
Tim Edwards 1272ed22fe Merge branch 'master' into netgen-1.5 2024-10-20 02:00:02 -04:00
Tim Edwards 7d910b616c Modified the string matching "matchnocase()" routine to compare
a verilog escaped string against an equivalent non-escaped
string (requires that the escaped string differs from the non-
escaped string by having a "\" at the front and " " at the end.
The space character is always maintained as part of the string).
2024-10-19 17:07:09 -04:00
8 changed files with 145 additions and 17 deletions
+1 -1
View File
@@ -1 +1 @@
1.5.285
1.5.290
+40
View File
@@ -1306,6 +1306,14 @@ int UniquePins(char *name, int filenum)
return 1;
}
/* Structure used below for keeping track of node numbers
* belonging to removed nodes.
*/
struct LinkedNum {
int node;
struct LinkedNum *next;
};
/*------------------------------------------------------*/
/* Callback function for CleanupPins */
/* Note that if the first pin of the instance is a */
@@ -1318,6 +1326,7 @@ struct nlist *cleanuppins(struct hashlist *p, void *clientdata)
struct nlist *ptr;
struct objlist *ob, *obt, *lob, *nob, *firstpin, *pob;
struct nlist *tc = (struct nlist *)clientdata;
struct LinkedNum *newnodenum, *removedNodes = (struct LinkedNum *)NULL;
int pinnum;
char *saveinst = NULL;
@@ -1373,6 +1382,15 @@ struct nlist *cleanuppins(struct hashlist *p, void *clientdata)
saveinst = ob->instance.name;
}
if (ob->model.class != NULL) FREE(ob->model.class);
// Record the net number of the pin being removed, to
// check at the end if the net belonged to a pin that
// got orphaned.
newnodenum = (struct LinkedNum *)MALLOC(sizeof(struct LinkedNum));
newnodenum->node = ob->node;
newnodenum->next = removedNodes;
removedNodes = newnodenum;
FREE(ob);
}
else {
@@ -1416,6 +1434,28 @@ struct nlist *cleanuppins(struct hashlist *p, void *clientdata)
}
}
while (removedNodes != NULL) {
int nodenum = removedNodes->node;
struct objlist *ob2;
/* Only concerned with nodes that are in the pin list of ptr->cell */
for (ob = ptr->cell; ob != NULL; ob = ob->next) {
if (ob->type != PORT) break;
if (ob->node == nodenum) break;
}
if (ob && (ob->type == PORT)) {
/* Check if this node number exists only in the port record */
for (nob = ob->next; nob != NULL; nob = nob->next)
if (nob->node == nodenum) break;
if (nob == NULL) {
ob->node = -1; /* This pin is now disconnected */
}
}
newnodenum = removedNodes;
removedNodes = removedNodes->next;
FREE(newnodenum);
}
if (saveinst != NULL) FREE(saveinst);
return NULL; /* Keep the search going */
}
+58 -10
View File
@@ -6567,11 +6567,16 @@ void PrintAutomorphisms(void)
* separating out those devices that are connected to matching pins
* in each circuit.
*
* If match_nets == TRUE, then also match internal nets by name. Pins
* should always be matched by name without considering nets first;
* once all symmetries related to pins have been broken, then matching
* symmetries by net can keep the output from looking confusing.
*
* Return value is the same as VerifyMatching()
*-------------------------------------------------------------------------
*/
int ResolveAutomorphsByPin()
int ResolveAutomorphsByPin(int match_nets)
{
struct NodeClass *NC;
struct Node *N;
@@ -6580,7 +6585,10 @@ int ResolveAutomorphsByPin()
int portnum;
/* Diagnostic */
Fprintf(stdout, "Resolving symmetries by pin name.\n");
if (match_nets)
Fprintf(stdout, "Resolving symmetries by net name.\n");
else
Fprintf(stdout, "Resolving symmetries by pin name.\n");
for (NC = NodeClasses; NC != NULL; NC = NC->next) {
struct Node *N1, *N2;
@@ -6604,7 +6612,9 @@ int ResolveAutomorphsByPin()
if (N1->hashval != orighash) continue;
for (N2 = N1->next; N2 != NULL; N2 = N2->next) {
if ((N2->graph != N1->graph) &&
(*matchfunc)(N2->object->name, N1->object->name)) {
(*matchfunc)(N2->object->name, N1->object->name) &&
(N1->object->type == PORT || N2->object->type == PORT)) {
if (Debug == TRUE)
Printf("Symmetry group broken by name match (pin %s)\n", N2->object->name);
Magic(newhash);
@@ -7582,6 +7592,10 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) {
if (ob2->type != PORT) break;
else haspins = 1;
/* The model.port record for pins will be used to match the pin order
* of the cells in each netlist. Make sure the value is reset on
* entering this subroutine.
*/
ob2->model.port = -1;
}
numnodes = 0;
@@ -7735,7 +7749,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if (strcmp(obn->name, "(no pins)")) {
output_string_fill(ostr);
output_string_left(ostr, "%s", obn->name);
output_string_right(ostr, "(no pin, node is %s",
output_string_right(ostr, "(no pin, node is %s)",
obp->name);
output_string_print(ostr);
}
@@ -8027,11 +8041,36 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if (ob2->type != PORT) break;
if (ob2->model.port == -1) {
/* Find this node in NodeClasses and find the corresponding
* net in the other circuit, if there is one (NOTE: Needs
* refactoring; should not be going through NodeClasses
* inside a loop.)
*/
obn = NULL;
for (NC = NodeClasses; NC != NULL; NC = NC->next) {
for (N2 = NC->nodes; N2 != NULL; N2 = N2->next) {
if (N2->graph != Circuit1->file) {
obp = N2->object;
if (IsPort(obp) && (obp->node == ob2->node)) {
for (N1 = NC->nodes; N1 != NULL; N1 = N1->next) {
if (N1->graph == Circuit1->file) {
obn = N1->object;
}
}
}
}
}
}
if (Debug == 0) {
// See above for reverse case
if (strcmp(ob2->name, "(no pins)")) {
output_string_fill(ostr);
output_string_left(ostr, "%s", "(no matching pin)");
if (obn == NULL)
output_string_left(ostr, "%s", "(no matching pin)");
else
output_string_left(ostr, "(no pin, node is %s)",
obn->name);
output_string_right(ostr, "%s", ob2->name);
output_string_print(ostr);
}
@@ -8148,12 +8187,15 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if (obn == NULL) ob1->node = -1; /* Make disconnected */
}
/* NOTE: Previously kept the port if model.port is -1; however,
* all ports are -1 here so not sure why that was in there. . .
*/
if (ob1 == NULL || ob1->type != PORT || ob1->node >= 0
|| (ob1->node < 0 && tc1->class == CLASS_MODULE)
|| (ob1->node < 0 && ob1->model.port == -1)) {
|| (ob1->node < 0 && tc1->class == CLASS_MODULE)) {
/* Add a proxy pin to tc2 */
obn = (struct objlist *)CALLOC(1, sizeof(struct objlist));
obn->node = -1;
if (ob1 == NULL) {
obn->name = (char *)MALLOC(15);
sprintf(obn->name, "proxy%d", rand() & 0x3ffffff);
@@ -8165,7 +8207,6 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
obn->type = UNKNOWN;
obn->model.port = (i - j);
obn->instance.name = NULL;
obn->node = -1;
if (ob2 == tc2->cell) {
obn->next = ob2;
@@ -8181,9 +8222,16 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
HashPtrInstall(obn->name, obn, &(tc2->objdict));
}
else if (ob1 != NULL && ob1->type == PORT) {
else if (ob1 != NULL && ob1->type == PORT && ob1->node < 0) {
/* Disconnected node was not meaningful, has no pin match in */
/* the compared circuit, and so should be discarded. */
/* the compared circuit, and so should be discarded. This */
/* case is not output above, so do it here. */
output_string_fill(ostr);
output_string_left(ostr, "%s", ob1->name);
output_string_right(ostr, "%s", "(no matching pin)");
output_string_print(ostr);
ob1->node = -2;
needclean1 = 1;
+1 -1
View File
@@ -62,7 +62,7 @@ extern void RegroupDataStructures();
extern void FormatIllegalElementClasses();
extern void FormatIllegalNodeClasses();
extern int ResolveAutomorphsByProperty();
extern int ResolveAutomorphsByPin();
extern int ResolveAutomorphsByPin(int match_nets);
extern void SummarizeElementClasses(struct ElementClass *EC);
extern int remove_group_tags(struct objlist *ob);
+16
View File
@@ -223,6 +223,7 @@ int matchnocase(char *st1, char *st2)
{
char *sp1 = st1;
char *sp2 = st2;
char v1 = FALSE, v2 = FALSE;
/* In case of a property that does not exist in one netlist, matchnocase()
* may be passed a null value, so return 0 to indicate a non-match.
@@ -231,11 +232,26 @@ int matchnocase(char *st1, char *st2)
*/
if (!sp1 || !sp2) return 0;
/* Verilog back-slash escaped names should match an equivalent non-
* back-slashed name. (NOTE: This behavior needs to be added to match().)
*/
if ((*sp1 == '\\') && (*sp2 != '\\')) {
v1 = TRUE;
sp1++;
}
if ((*sp2 == '\\') && (*sp1 != '\\')) {
v2 = TRUE;
sp2++;
}
while (*sp1 != '\0' && *sp2 != '\0') {
if (to_lower[*sp1] != to_lower[*sp2]) break;
sp1++;
sp2++;
}
if (v1 && (*sp1 == ' ')) sp1++;
if (v2 && (*sp2 == ' ')) sp2++;
if ((*sp1 != '\0') || (*sp2 != '\0')) return 0;
return 1;
}
+17 -4
View File
@@ -717,10 +717,12 @@ int GetBus(char *astr, struct bus *wb)
return 0;
}
//--------------------------------------------------------------------
// Output a Verilog Module. Note that since Verilog does not describe
// low-level devices like transistors, capacitors, etc., then this
// format is limited to black-box subcircuits. Cells containing any
// such low-level devices are ignored.
//--------------------------------------------------------------------
void VerilogModule(struct nlist *tp)
{
@@ -1833,8 +1835,9 @@ skip_endmodule:
}
else { /* "assign" */
SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
if (GetBusTok(&wb) == 0) {
char *aptr = strvchr(nexttok, '[');
char *aptr = strvchr(nexttok, '[');
if (((aptr == NULL) && (GetBusTok(&wb) == 0)) ||
((aptr != NULL) && (GetBus(aptr, &wb) == 0))) {
if (aptr != NULL) {
*aptr = '\0';
/* Find object of first net in bus */
@@ -1852,6 +1855,15 @@ skip_endmodule:
}
else {
lhs = LookupObject(nexttok, CurrentCell);
/* Handle the case in which an assignment is made
* without first declaring a wire for the signal,
* which is considered valid syntax (patch by
* Sylvain Munaut).
*/
if (lhs == NULL) {
Node(nexttok);
lhs = LookupObject(nexttok, CurrentCell);
}
strcpy(noderoot, nexttok);
}
SkipTokComments(VLOG_DELIMITERS);
@@ -1900,8 +1912,9 @@ skip_endmodule:
break;
}
else {
if (GetBusTok(&wb2) == 0) {
char *aptr = strvchr(nexttok, '[');
char *aptr = strvchr(nexttok, '[');
if (((aptr == NULL) && (GetBusTok(&wb2) == 0)) ||
((aptr != NULL) && (GetBus(aptr, &wb2) == 0))) {
j = wb2.start;
if (aptr != NULL) {
*aptr = '\0';
+5
View File
@@ -655,6 +655,11 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
}
} elseif {[netgen::print queue] == {} && $result == 0} {
set pinMismatch 1
} else {
# This assumes that proxy pins are added correctly. Previously,
# that was not trusted, and so an initial pin mismatch would
# always force subcells to be flattened.
set doFlatten 0
}
}
if {$doFlatten} {
+7 -1
View File
@@ -2512,7 +2512,13 @@ _netcmp_run(ClientData clientData,
if (automorphisms > 0) {
// Next, attempt to resolve automorphisms uniquely by
// using the pin names
automorphisms = ResolveAutomorphsByPin();
automorphisms = ResolveAutomorphsByPin(FALSE);
}
if (automorphisms > 0) {
// Next, attempt to resolve automorphisms uniquely by
// using the net names (should only be done after
// resolving by pin).
automorphisms = ResolveAutomorphsByPin(TRUE);
}
if (automorphisms > 0) {
// Anything left is truly indistinguishable