Compare commits

...
147 Commits
Author SHA1 Message Date
Tim Edwards ee92d880d7 Merge branch 'master' into netgen-1.5 2022-06-27 02:00:01 -04:00
Tim Edwards 7550ef9258 Corrected an error in reworking verilog instances to add pins that
were implicit in the first instances but made explicit in a later
one.  If more than one such implicit pin was handled for the same
cell, then the pin count would become wrong and rather unpredictable
behavior results.
2022-06-26 22:16:03 -04:00
Tim Edwards a795981eff Corrected a prematch issue that will flatten a cell on one side
even when the opposing netlist has a black-box entry for the same
cell.  The black-box entry can't be flattened, so this just
results in the cell mysteriously disappearing from one side.
2022-06-26 14:57:25 -04:00
Tim Edwards d3407b3e56 Merge branch 'master' into netgen-1.5 2022-06-15 02:00:50 -04:00
Tim Edwards 1b6e4e2b36 Corrected an error in the last commit which can cause the pin
enumeration in MatchPins() to overflow the cover() array and
cause a segmentation fault.
2022-06-14 11:36:30 -04:00
Tim Edwards 0a94bec191 Merge branch 'master' into netgen-1.5 2022-06-13 02:00:18 -04:00
Tim Edwards edbe5d6e86 Made minor changes to MatchPins() to handle multiple pins connected
to a single net (as can be done with assignments in verilog or with
zero-voltage sources or zero-value resistors in SPICE).  Corrected
an error in the SPICE netlist reader that prevented the proper use
of zero-voltage sources as net splitters.
2022-06-12 17:25:37 -04:00
Tim Edwards 4a7b6bf22a Merge branch 'master' into netgen-1.5 2022-06-09 02:00:52 -04:00
Tim Edwards f8ed4e42e2 Corrected the parsing of verilog netlists to use the right
delimiter set when parsing pin names (the correct delimiter set
was used in one place but not in another).  Extended the pin
matching to include the minor hack of ignoring the backslash
before backslash-escaped verilog names when there is otherwise
no exact match, since many tools convert verilog to SPICE by
removing the backslash and trailing space.  This avoids pin
mismatches in a known set of use cases.
2022-06-08 11:53:47 -04:00
Tim Edwards 661c9ee854 Merge branch 'master' into netgen-1.5 2022-04-16 02:00:16 -04:00
Tim Edwards 89ef83c597 Corrected an error in the verilog parser that incorrectly handles
the syntax "assign a = b" when both a and b are vectors (but no
vector delimiters appear in the assignment).
2022-04-15 14:13:11 -04:00
Tim Edwards 4e96c84ec6 Extended the method created in the last commit so that it properly
handles both operator order of precedence and parenthetical groups
including nested groups.
2022-04-15 12:19:48 -04:00
Tim Edwards 5b21c1be3a Merge branch 'master' into netgen-1.5 2022-04-15 02:00:16 -04:00
Tim Edwards 592c16706e Extended the verilog parsing to parse definitions such that nested
definitions are handled correctly.  Also:  Added code to evaluate
simple expressions for array bounds.  Previously the parser could
handle a value followed by "+" or "-" and a constant.  Now it can
handle all basic arithmetic.
2022-04-14 22:33:58 -04:00
Tim Edwards e11dbac384 Merge branch 'master' into netgen-1.5 2022-01-17 03:00:14 -05:00
Tim Edwards bfb01e032f Implemented another change discussed in netgen github issue #47
by Anton Blanchard, which prevents the double-loop in the
PropertyOptimize() routine from continuing the outer loop if
all devices in the run have already been merged.
2022-01-16 14:47:52 -05:00
Tim Edwards d0ec17e442 Implemented a change to the way that netgen generates the subcircuit
summary, so that the summary lists the total number of devices as well
as the number of devices after parallel optimization, in the form
"device_name (M->N)", where "M" is the total number of devices, and
"N" is the number of devices after parallel combination.  This makes
the output somewhat more meaningful to the end user.  Implementation
as discussed in github issue #47.
2022-01-16 14:16:30 -05:00
Tim Edwards 0535128421 Merge branch 'master' into netgen-1.5 2022-01-16 03:00:18 -05:00
Tim Edwards 6195745b45 Modified the parallel combination code so that properties of
parallel devices are prepended rather than appended, which avoids
having to search for the end of what may be a rapidly increasing
linked list of properties.  This reduces the amount of time spent
in the parallel combination code.  Thanks to Anton Blanchard for
pointing out this inefficiency.
2022-01-15 12:06:43 -05:00
Tim Edwards afe0e9f758 Merge branch 'master' into netgen-1.5 2022-01-01 03:00:43 -05:00
Tim Edwards 68ec2b2a7c Modified two print statements to change "%s(%d)" to "%s (%d)" as
is my typographic preference.
2021-12-31 13:30:13 -05:00
Tim Edwards ca49a90ed6 Merged changes from github issue #45 from Mitch Bailey. These changes
speed up the time needed to flatten an instance, and add clarity to the
output by specifying the file number for each cell name being modified
during the pre-match stage.
2021-12-31 12:13:11 -05:00
Tim Edwards e487890641 Merge branch 'master' into netgen-1.5 2021-12-31 03:00:42 -05:00
Tim Edwards e07a5b416a Removed lvs_manager.py, which is a derived file and should not have
ended up in the repository, as pointed out by Mitch Bailey in github
issue #44.  Added lvs_manager.py to .gitignore to prevent that from
happening again in the future.
2021-12-30 09:19:44 -05:00
Tim Edwards bb44d3f827 Merge branch 'master' into netgen-1.5 2021-12-30 03:00:43 -05:00
Tim Edwards 8094740048 Corrected a problem that stems from code that was deprecated and
marked as unneeded, so I simply removed the code rather than
debug the issue, which was that buses got the delimeters erased
for checking but never put back again.  Also:  Modified the verilog
reading code so that if an empty set "()" is given for a pin, then
the initial proxy, which is a single net with the name prefix
"_noconnect_", can be promoted to a bus if further processing
reveals it to be a bus and not a single-bit signal.
2021-12-29 14:31:38 -05:00
Tim Edwards c25c4e1160 Merge branch 'master' into netgen-1.5 2021-12-27 03:00:18 -05:00
Tim Edwards a026d37f11 Corrected a place in the verilog read routine where ob->next is
used when ob may be NULL.  Added a check in front for ob == NULL.
Also:  Changed the disconnected node alert so that it does not
mention nodes marked "port_mismatch_error".  These are disconnected
by definition, will show up in the pin list, and printing them as
"disconnected pins" is just confusing to the end user.
2021-12-26 10:31:48 -05:00
Tim Edwards 8ed4e3cf38 Merge branch 'master' into netgen-1.5 2021-12-20 03:00:02 -05:00
Tim Edwards ab614b63f7 Corrected the last commit (again) because FlattenUnmatched()
should not be called after CreateTwoLists().  CreateTwoLists()
was being called in one case only to print the contents of the
cells, so that part was pulled out into a separate routine.
2021-12-19 16:25:32 -05:00
Tim Edwards 83dce151d8 Made a correction to the last commit. The "FlattenUnmatched()"
routine does not have an exact equivalent in PrematchLists() and
needs to be run beforehand.  This fix keeps FlattenUnmatched()
from being run on all cells at the beginning and restricts it
to being run on the contents of individual cells during matching,
after checking if either of the cells is a black-box.  Avoiding
flattening contents of one side when the other is a black-box
(or simply doesn't contain any subcircuits or devices) prevents
unnecessary flattening of cells that will never get compared.
2021-12-17 20:31:41 -05:00
Tim Edwards 69838d79e4 Merge branch 'master' into netgen-1.5 2021-12-16 03:00:06 -05:00
Tim Edwards de18ae85a4 Removed the call to FlattenUnmatched() in CreateCompareQueue().
The FlattenUnmatched() is inefficient compared to just letting
the PrematchLists() routine handle flattening of unmatched
instances.
2021-12-15 11:05:00 -05:00
Tim Edwards fc7c9371e8 Merge branch 'master' into netgen-1.5 2021-12-08 03:00:14 -05:00
Tim Edwards 9908349fdd Modified the output of "debug on" mode to print the instance name
for each connection in the dump of incorrect nets.  This is
definitely critical to finding local swapping errors, and needs
to be incorporated into the non-debug mode, preferably as part of
the JSON file dump.  But that's for later.
2021-12-07 16:33:43 -05:00
Tim Edwards 964bb0e91a Added sorting of the output lines for items which match both name and
contents (previously wasn't done), and also added sorting for items with
non-matching names which have only one item in the group for each circuit
(so they must be matching in some sense).  This makes the output a bit
more readable without re-enabling the compute-intensive sorting method
for non-matching entries.
2021-12-07 15:34:45 -05:00
Tim Edwards 0d19868145 Merge branch 'master' into netgen-1.5 2021-11-18 03:00:10 -05:00
Tim Edwards cfdc60104b Updated version to go along with the merge of pull request #39
from Kamyar Mohajerani, with a few minor edits such as renaming
my_hash to hashcase, as a better counterpoint to "hashnocase".
2021-11-17 12:05:01 -05:00
Kamyar Mohajerani 879711def3 revert removal of superfluous 'extern'
.. for functions based on review comments
2021-11-17 11:53:04 -05:00
Kamyar Mohajerani 5def9e0ffc remove <xlocale.h> 2021-11-16 22:18:59 -05:00
Kamyar Mohajerani b5c70decbd fix wrong 'hash' being linked in + C99 compat
This fixes crash on macos due to wrong hash() being linked in.
It also makes sure that proper function defs are declared and available
(as required by C99) to make compile possible in newer compilers (e.g.
Apple clang) and to some extend prevent similar linkage issues happening
again.
2021-11-16 20:06:15 -05:00
Tim Edwards 6b4eb01ee8 Merge branch 'master' into netgen-1.5 2021-11-12 03:00:29 -05:00
Tim Edwards 20f6d76926 Corrected the "format" command, which failed to return TCL_OK
after executing the command with non-zero options.
2021-11-11 08:42:46 -05:00
Tim Edwards 737b2a73bf Merge branch 'master' into netgen-1.5 2021-10-30 03:00:02 -04:00
Tim Edwards e4a15f12fb Updated version to go along with the merge of pull request #37
from Mitch Bailey.
2021-10-29 18:11:03 -04:00
D. Mitch Bailey c6fb204f0c Cosmetic report changes.
Changed line breaks in log and stdout to better differentiate subcircuits.
Added merged series device counts and differentiated from parallel merged device counts.
Added file number to disconnected net, merged count messages.
Changed black box errors to show file numbers instead of hard coded values.
Final error cell list changed from all on one line to one per line.
Removed redundant display in black box warning.
2021-10-29 18:10:30 -04:00
Tim Edwards 6b8c6d1718 Merge branch 'master' into netgen-1.5 2021-10-29 03:00:32 -04:00
Tim Edwards c7dfff4bb9 Updated version to go along with the merge of pull request #36 from
Mitch Bailey.
2021-10-28 14:24:47 -04:00
D. Mitch Bailey 12fa080212 When comparing instance counts to determine is flattening makes a better match,
flatten cells that have no instances in common.
Display a screen message to indicate a re-compare afterr flattening.
2021-10-28 01:29:32 -07:00
Tim Edwards 610eebb758 Merge branch 'master' into netgen-1.5 2021-10-24 03:00:12 -04:00
Tim Edwards 4c4bad08f2 After reverting back to before pull request #33, updated the
version and re-applied the fixes from issue #34.
2021-10-23 14:47:30 -04:00
Tim Edwards 23ff2f00a3 Revert "Remove disconnected ports after flattening."
This reverts commit 6d6da9cf5c.

Reverting back to before pull request #33.
2021-10-23 14:42:37 -04:00
Tim Edwards d09f0dd53b Revert "Flatten unmatched cells that don't contain instances from the other file."
This reverts commit 42b1acc564.

Reverting back to before pull request #33.
2021-10-23 14:42:32 -04:00
Tim Edwards 56d4d581e7 Revert "Minor syntactical editing of pull request #33, and updated version"
This reverts commit 6ceeddf096.

Reverting back to before pull request #33.
2021-10-23 14:42:28 -04:00
Tim Edwards 1bb4866226 Revert "Made a correction to the flattening code, removed a duplicate"
This reverts commit 625e043eff.

Reverting back to before pull request #33.
2021-10-23 14:41:58 -04:00
Tim Edwards 97058c5017 Merge branch 'master' into netgen-1.5 2021-10-16 03:00:13 -04:00
Tim Edwards 625e043eff Made a correction to the flattening code, removed a duplicate
print statement, and clarified the messages about non-matching
circuits at the end, all of them suggestions made by Mitch
Bailey (see issue #34 on github).
2021-10-15 09:13:02 -04:00
Tim Edwards aa120460d0 Merge branch 'master' into netgen-1.5 2021-10-15 03:00:03 -04:00
Tim Edwards 6ceeddf096 Minor syntactical editing of pull request #33, and updated version
to go along with the merge of the pull request (from Mitch Bailey).
2021-10-14 11:22:20 -04:00
D. Mitch Bailey 42b1acc564 Flatten unmatched cells that don't contain instances from the other file. 2021-10-13 21:00:49 -07:00
D. Mitch Bailey 6d6da9cf5c Remove disconnected ports after flattening. 2021-10-13 01:15:15 -07:00
Tim Edwards ea5cbacf1c Merge branch 'master' into netgen-1.5 2021-10-06 03:00:12 -04:00
Tim Edwards bbcc79fc72 Updated version to go along with merge of pull request #32 from
Harald Pretl.
2021-10-05 09:41:24 -04:00
Harald Pretl 6d5946eaf2 Added MacOS (Big Sur) installation instructions. 2021-10-03 13:58:34 +02:00
Tim Edwards cdd768addc Merge branch 'master' into netgen-1.5 2021-09-08 03:00:04 -04:00
Tim Edwards 18dcac73bc Updated version to go along with the merge of pull request #31
from Mitch Bailey.
2021-09-07 22:27:31 -04:00
D. Mitch Bailey 1338e3beb5 Removed debugging statement. 2021-09-07 19:16:33 -07:00
D. Mitch Bailey df1c4c5153 Changed debug print increment from 100 -> 10000. 2021-09-07 10:19:27 -07:00
D. Mitch Bailey a05ede99db Added missing newlines
Print debug message every 100 lines
2021-09-06 18:31:38 -07:00
D. Mitch Bailey 2d6f1f71b5 Reduce and clarify debugging message.
Add missing new line to "Flattening non-matched subcircuits.
2021-09-02 22:29:17 -07:00
Tim Edwards 66cf2b82d9 Merge branch 'master' into netgen-1.5 2021-08-30 03:00:02 -04:00
Tim Edwards d7355cea95 Updated the vezzal docker image version for CI. 2021-08-29 19:41:14 -04:00
Tim Edwards bc4192496b Merge branch 'master' into netgen-1.5 2021-08-28 13:15:58 -04:00
Tim Edwards 32585a572c Corrected the badge link at the top of README.md to point to my
own repository instead of a fork.
2021-08-28 13:14:11 -04:00
Tim Edwards 168e5502a1 Merge branch 'master' into netgen-1.5 2021-08-06 11:38:38 -04:00
Tim Edwards e773739e7d Updated VERSION as a forced change to check continuous integration
on github.
2021-08-06 11:37:29 -04:00
Tim Edwards 8d4b621b7d Merge branch 'master' into netgen-1.5 2021-08-06 11:25:01 -04:00
Tim Edwards 583cc3a151 Updated VERSION to go along with the merge of pull request #27 from
Sai Charan.  Subsequent mirror pushes to github should trigger the
continuous integration.
2021-08-06 11:18:56 -04:00
Sai Charan Lanka bdd7d25943 Update main.yml 2021-08-06 11:18:32 -04:00
Sai Charan Lanka 903b813821 Update README.md 2021-08-06 11:18:32 -04:00
Sai Charan Lanka 1f9d4317e3 Update main.yml 2021-08-06 11:18:32 -04:00
Sai Charan Lanka 7b8086fc3a Update main.yml 2021-08-06 11:18:32 -04:00
Sai Charan Lanka e80f70e67b Update main.yml 2021-08-06 11:18:32 -04:00
Sai Charan Lanka 6cc898b34b Update README.md 2021-08-06 11:18:32 -04:00
Sai Charan Lanka 30bbc28c17 Update README.md 2021-08-06 11:18:32 -04:00
Sai Charan Lanka 5ec0db678a Update README.md 2021-08-06 11:18:32 -04:00
Sai Charan Lanka e643563d4e Update README.md 2021-08-06 11:18:32 -04:00
Sai Charan Lanka 67f2801aa1 Update README.md 2021-08-06 11:18:32 -04:00
Sai Charan Lanka f76f2e002a Update README.md 2021-08-06 11:18:32 -04:00
Sai Charan Lanka 9ec613b0cb Update README.md 2021-08-06 11:18:32 -04:00
Sai Charan Lanka 9128eeda60 Update README.md 2021-08-06 11:18:32 -04:00
Sai Charan Lanka aeedf5fae9 Update README.md 2021-08-06 11:18:32 -04:00
Sai Charan Lanka f50dfd9261 Update README.md 2021-08-06 11:18:32 -04:00
Sai Charan Lanka 409ce224ad Update README.md 2021-08-06 11:18:32 -04:00
Sai Charan Lanka f50093e6c6 Rename README to README.md 2021-08-06 11:18:32 -04:00
Sai Charan Lanka a27ac8c679 Update README 2021-08-06 11:18:32 -04:00
Sai Charan Lanka 883755eed3 Update main.yml 2021-08-06 11:18:31 -04:00
Sai Charan Lanka 484cb26eee Update main.yml 2021-08-06 11:18:31 -04:00
Sai Charan Lanka 7cc6996017 Update main.yml 2021-08-06 11:18:31 -04:00
Sai Charan Lanka 7f9acf6a1a Update main.yml 2021-08-06 11:18:31 -04:00
Sai Charan Lanka e1a3ae5619 Update main.yml 2021-08-06 11:18:31 -04:00
Sai Charan Lanka 4e75889605 Update main.yml 2021-08-06 11:18:31 -04:00
Sai Charan Lanka e017811239 Update main.yml 2021-08-06 11:18:31 -04:00
Sai Charan Lanka 4468d36462 Update main.yml 2021-08-06 11:18:31 -04:00
Sai Charan Lanka b99fb96259 Update main.yml 2021-08-06 11:18:31 -04:00
Sai Charan Lanka ec8299ea14 Update main.yml 2021-08-06 11:18:31 -04:00
Sai Charan Lanka 376296eda5 Update main.yml 2021-08-06 11:18:31 -04:00
Sai Charan Lanka 30acb8be63 Update main.yml 2021-08-06 11:18:31 -04:00
Sai Charan Lanka 7e15a26417 Create main.yml 2021-08-06 11:18:31 -04:00
Tim Edwards ba3e862552 Merge branch 'master' into netgen-1.5 2021-07-30 03:00:29 -04:00
Tim Edwards 21750da6c4 Corrected the Makefile in the python directory to set the
lvs_manager.py script to be executable, or else "netgen -gui" will
not work.
2021-07-29 10:45:44 -04:00
Tim Edwards cf6dd2a638 Merge branch 'master' into netgen-1.5 2021-07-16 03:00:11 -04:00
Tim Edwards a332c23524 Corrected an error in "series_sort" that will overwrite memory
randomly if combining series devices that do not have an "S"
property (which is the typical case).  This will normally result in
a crash.
2021-07-15 16:03:43 -04:00
Tim Edwards b6d896e73f Merge branch 'master' into netgen-1.5 2021-07-12 03:00:10 -04:00
Tim Edwards 064195ecc9 Reinstated some code that had been commented out that prints pin
information for a non-matching pin in circuit1 and generates a
proxy pin in circuit2---there is some case where this is redundant,
I think, but I need to find the example.
2021-07-11 17:04:50 -04:00
Tim Edwards 88d53fab15 Correction to the verilog parser to recognize modifiers such as
"~", "!", or "-" in front of variable names in a pin list that would
render the module behavioral verilog.
2021-07-11 12:06:16 -04:00
Tim Edwards c287b6cd28 A previous attempt (in revision 193) to make the "lvs" script stop
saying that pins were mismatched when pin matching was never run
accidentally resulted in pin matching not being applied to black-box
entries.  This has been corrected.
2021-07-11 10:58:30 -04:00
Tim Edwards 9251ce2a48 Merge branch 'master' into netgen-1.5 2021-07-11 03:00:33 -04:00
Tim Edwards 0a0a6bcf63 Modified the handling of missing pins (again) such that netgen
continues to allow missing pins to match unconnected pins, but
*only* on subcircuits below the top level.  This essentially forces
layouts to separate merged pins with metal resistors, although
there should be an option in magic's ext2spice routine that allows
"equiv" statements, when declaring equivalence of two ports, to be
replaced by a zero volt source or zero ohm ideal resistor.
2021-07-10 13:54:14 -04:00
Tim Edwards 72ef2f2637 Corrected the pin matching so that it runs the same loop on unmatched
pins on non-black-boxed circuits as it does not black-boxed circuits,
but specifically looking for pins that are disconnected on both sides,
since those do not appear in the node list and are not otherwise
handled.  Otherwise, disconnected pins will appear to have disappeared
from the first netlist.
2021-07-10 11:25:07 -04:00
Tim Edwards aa82164c08 Merge branch 'master' into netgen-1.5 2021-07-09 03:00:34 -04:00
Tim Edwards 287f5963d1 Corrected an error that crept into the netgen.tcl script that causes
the "failed pin matching" error message to appear for cells mismatching
topology (in which case pin matching is never done).
2021-07-08 08:56:52 -04:00
Tim Edwards fb7876c7a6 Merge branch 'master' into netgen-1.5 2021-07-03 03:00:13 -04:00
Tim Edwards a984ac1a4d Corrected an error in a recent update that handles the case where
a final parallel or series combination needs to be done but there
are still multiple property records.  The multiplier was being
incorrectly applied twice, causing an automatic mismatch in
parameter values.
2021-07-02 10:51:44 -04:00
Tim Edwards e31caa3500 Merge branch 'master' into netgen-1.5 2021-06-26 03:00:10 -04:00
Tim Edwards 738c1f7b37 Corrected an error probably introduced into the code with the handling
of multiple devices during flattening, that will skip over a node
record at the end of a subcircuit call being flattened and therefore
remove it from the netlist.
2021-06-25 13:16:42 -04:00
Tim Edwards c3cf6c3765 Made another correction that prevents netgen from truncating the pin
list that it prints in the side-by-side element mismatch comparison
for an element, when there is no node record associated with the pin
connection.  This makes the output clearer.
2021-06-25 12:35:11 -04:00
Tim Edwards 99dcc20c0a Corrected MatchPins so that it returns an error code of 0 when pins are
swapped, so that if pin names are swapped on the top level, netgen will
report this as a final error message.  Otherwise, the mismatch is only
reported back in the pin list where it is not obvious.
2021-06-25 10:27:24 -04:00
Tim Edwards c1355bee45 Merge branch 'master' into netgen-1.5 2021-06-25 03:00:10 -04:00
Tim Edwards 4bbc496749 Corrected an error in the "run converge" and "run resolve" methods.
The algorithm is to run without exhaustive subdivision until the
last step because this is much faster.  The final iteration must
be run with exhaustive subdivision on, or else it is possible to
have cells with swapped pins matching.  The routines that resolve
automorphisms were setting exhaustive subdivision for the final
iteration.  But simple "run converge" and "run resolve" were not.
2021-06-24 14:53:24 -04:00
Tim Edwards 4fb8b59a2f Merge branch 'master' into netgen-1.5 2021-06-19 03:00:10 -04:00
Tim Edwards c4f03eabaf Corrected an error not checking for running off the end of a list,
in code from a recent commit.
2021-06-18 21:23:21 -04:00
Tim Edwards 6a555ad6ed Added a missing method from parallel/series matching which is to
add properties across multiple property records in the last matching
step, if there are still multiple properties and the values can be
combined.  Previously, netgen had been assuming that there would only
be one property record left at this point, which is not true.  This
shows up particularly for BSIM fingered devices, since "nf" is
ignored.
2021-06-18 10:44:44 -04:00
Tim Edwards 626faf22f9 Merge branch 'master' into netgen-1.5 2021-06-17 03:00:10 -04:00
Tim Edwards 1c5457e180 Corrected a minor issue that cropped up today in which the search
for file extensions is greedy and picks the first matching extension
starting at the front of the string, such that, e.g., "file.ext.spice"
is interpreted as a ".ext" file and not a ".spice" file.
2021-06-16 15:20:39 -04:00
Tim Edwards 7d246c36a6 Corrected an issue with flattening when the instances to be flattened
run to the end of the list of circuit elements.  Also corrected
another issue caused by the flag to denote multiple no-connect pins,
which can be on an instance pin and so cannot share the data from the
instance record.
2021-06-16 14:32:14 -04:00
Tim Edwards 550234dce5 Merge branch 'master' into netgen-1.5 2021-06-15 03:00:36 -04:00
Tim Edwards 92dfa74403 Corrected an issue that was caused by introducing a type of parallel
device with one or more no-connect pins.  The flag that indicates a
no-connect pin was checked incorrectly, potentially causing obscure
and misleading property mismatch messages to be generated.
2021-06-14 14:30:10 -04:00
Tim Edwards a4c0028706 Merge branch 'master' into netgen-1.5 2021-06-13 03:00:32 -04:00
Tim Edwards d53541d1d3 Correction to previous commit (failed to link to last pointer
after processing properties during flattening).
2021-06-12 20:15:55 -04:00
Tim Edwards 57b2d21221 Modified the way flattening is done to account for multiple property
records, which were being ignored.  This really only applies to
parallel subcircuits being flattened.  To flatten correctly requires
that any circuit with N property records must be flattened into the
parent at least N times.  To do:  Must look for M > 1 records in the
properties and flatten (M - 1) additional times.
2021-06-12 17:37:50 -04:00
Tim Edwards e7ae84bbc8 Merge branch 'master' into netgen-1.5 2021-06-10 03:00:09 -04:00
Tim Edwards dfabdaa367 Modified the JSON output so that missing pins which do not match
unconnected pins in the other netlist are marked as "(no pin)"
rather than "(no matching pin)".  This allows a script parsint the
JSON file (e.g., count_lvs.py from qflow) to distinguish between a
real pin error and one that can be ignored.
2021-06-09 09:34:02 -04:00
Tim Edwards c5c1306f6a Corrected a minor error where the property mismatch check outputs
an error message while doing a non-final iteration, where all
output is supposed to be suppressed.
2021-06-09 09:20:45 -04:00
Tim Edwards 43c018f3bc Merge branch 'master' into netgen-1.5 2021-06-09 03:00:10 -04:00
Tim Edwards 0614461c84 Modified MatchPins so that pin mismatches on nets that are not
connected to anything are once again ignored (the prior commit
to prevent netgen from not reporting swapped pins as an error
overcorrected).
2021-06-08 17:25:17 -04:00
Tim Edwards 6e94886b65 Messed up basic pin comparison between black-box vs. non-black-box
subcircuit situations in the last commit.  This commit fixes it.
2021-06-08 16:52:57 -04:00
24 changed files with 1403 additions and 680 deletions
+40
View File
@@ -0,0 +1,40 @@
# This is a basic workflow to help you get started with Actions
name: CI
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the master branch
push:
branches: [ master ]
pull_request:
branches: [ master ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Runs a set of commands using the runners shell
#- name: Logging into Dockerhub
# run: docker login -u ${{ secrets.DOCKERHUB_USERNAME }} -p ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Pulling the docker image
run: docker pull vezzal/vezzal:v1
- name: Start the container with the docker image
run: docker run -id --name test_netgen vezzal/vezzal:v1 bash | exit
- name: Run the testing on the container and send the mail
run: docker exec test_netgen /vezzal/test_netgen.sh "[email protected],[email protected]" ${{ secrets.MAILING_KEY }}
+1
View File
@@ -7,6 +7,7 @@ config.log
scripts/config.log
config.status
scripts/config.status
python/lvs_manager.py
*.o
*.so
*~
+48 -1
View File
@@ -1,4 +1,8 @@
NETGEN: VERSION 1.5
![Continuous Integration](https://github.com/RTimothyEdwards/netgen/actions/workflows/main.yml/badge.svg)
# NETGEN
### VERSION 1.5
NETGEN is a general-purpose netlist management system. It can read
and write several netlist formats, including NTK (Caltech, CMU),
@@ -87,6 +91,49 @@ and IRSIM version 9.7:
Note: For FreeBSD, use 'gmake' instead.
Note: On MacOS (Big Sur) follow the following procedure. If you have installed `xschem` and `magic` already on MacOS then steps (1) and (2) can likely be skipped.
**1) Build Tcl for X11**
We are following the instructions from `xschem` (https://github.com/StefanSchippers/xschem/blob/master/README_MacOS.md).
* Download `Tcl` from https://prdownloads.sourceforge.net/tcl/tcl8.6.10-src.tar.gz
We are using not `opt` but `opt2` so that this `Tcl` does not interfere with `tcl-tk` from HomeBrew.
```
./configure --prefix=/usr/local/opt2/tcl-tk
make
make install
```
**2) Build Tk for X11**
* Download `Tk` from https://prdownloads.sourceforge.net/tcl/tk8.6.10-src.tar.gz
```
./configure --prefix=/usr/local/opt2/tcl-tk \
--with-tcl=/usr/local/opt2/tcl-tk/lib --with-x \
--x-includes=/opt/X11/include --x-libraries=/opt/X11/lib
make
make install
```
**3) Build netgen**
We need to provide this custom-built `tcl-tk` and suppress compilation errors.
```
./configure --with-tcl=/usr/local/opt2/tcl-tk/lib \
--with-tk=/usr/local/opt2/tcl-tk/lib \
--x-includes=/opt/X11/include \
--x-libraries=/opt/X11/lib \
CFLAGS=-Wno-error=implicit-function-declaration
make
make install
```
IN CASE OF FAILURE
-------------------
Please contact me (tim@opencircuitdesign.com) to report compile-time and
+1 -1
View File
@@ -1 +1 @@
1.5.183
1.5.226
+4 -3
View File
@@ -23,12 +23,13 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <stdlib.h> /* for strtod() */
#include <stdarg.h>
#include <ctype.h>
#include "netgen.h"
#include "hash.h"
#include "objlist.h"
#include "netfile.h"
#include "print.h"
#include "hash.h"
void extCell(char *name, int filenum)
{
@@ -186,7 +187,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
/* Make sure all .ext file reading is case sensitive */
matchfunc = match;
matchintfunc = matchfile;
hashfunc = hash;
hashfunc = hashcase;
if (LookupCellFile(fname, filenum) != NULL) {
Printf("Error: Duplicate cell name \"%s\"!\n", fname);
@@ -652,7 +653,7 @@ char *ReadSim(char *fname, int *fnum)
/* Make sure all .sim file reading is case sensitive */
matchfunc = match;
matchintfunc = matchfile;
hashfunc = hash;
hashfunc = hashcase;
CellDef(fname, filenum);
+319 -220
View File
@@ -254,9 +254,10 @@ void flattenCell(char *name, int file)
int flattenInstancesOf(char *name, int fnum, char *instance)
{
struct objlist *ParentParams;
struct objlist *ParentProps;
struct objlist *ParentProps, *CurrentProp;
struct objlist *NextObj, *LastObj, *prepp;
struct objlist *ChildObjList;
struct objlist *ChildObjList, *ChildListEnd;
struct objlist *ChildStart, *ChildEnd, *ParentEnd, *ParentNext;
struct nlist *ThisCell;
struct nlist *ChildCell;
struct objlist *tmp, *ob2, *ob3;
@@ -334,215 +335,257 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
ParentProps = ParentProps->next) {
if (ParentProps->type == PROPERTY) break;
}
if (ParentProps && (ParentProps->type != PROPERTY)) ParentProps = NULL;
/* not primitive, so need to flatten this instance */
notdone = 1;
/* if this is a new instance, flatten it */
/* if (ChildCell->dumped == 0) flattenCell(ParentParams->model.class, file); */
ChildObjList = CopyObjList(ChildCell->cell, 1);
numflat++;
/* update node numbers in child to unique numbers */
oldmax = 0;
for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next)
if (tmp->node > oldmax) oldmax = tmp->node;
if (nextnode <= oldmax) nextnode = oldmax + 1;
for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next)
if (tmp->node <= oldmax && tmp->node > 0) {
if (Debug) Printf("Update node %d --> %d\n", tmp->node, nextnode);
UpdateNodeNumbers(ChildObjList, tmp->node, nextnode);
nextnode++;
}
/* copy nodenumbers of ports from parent */
ob2 = ParentParams;
for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next)
if (IsPort(tmp)) {
if (tmp->node > 0) {
if (ob2->node == -1) {
// Before commiting to attaching to a unconnected node, see
// if there is another node in ParentParams with the same
// name and a valid node number. If so, connect them. In
// the broader case, it may be necessary to consider all
// nodes, not just those with node == -1, and call join()
// here to update all node numbers in the parent cell.
// In that case, a more efficient method is needed for
// tracking same-name ports.
for (ob3 = ParentParams; ob3 && ob3->type >= FIRSTPIN; ob3 = ob3->next) {
if (ob3 == ob2) continue;
if ((*matchfunc)(ob3->name, ob2->name) && ob3->node != -1) {
ob2->node = ob3->node;
break;
}
}
}
if (Debug) {
// Printf(" Sealing port: %d to node %d\n", tmp->node, ob2->node);
Printf("Update node %d --> %d\n", tmp->node, ob2->node);
}
UpdateNodeNumbers(ChildObjList, tmp->node, ob2->node);
}
/* in pathological cases, the lengths of the port lists may
* change. This is an error, but that is no reason to allow
* the code to core dump. We avoid this by placing a
* superfluous check on ob2->type
*/
if (ob2 != NULL)
ob2 = ob2->next;
if (ob2 == NULL) break;
}
/* Using name == NULL to indicate that a .ext file is being */
/* flattened on the fly. This is quick & dirty. */
if (name != NULL) {
/* delete all port elements from child */
while ((ChildObjList != NULL) && IsPort(ChildObjList)) {
/* delete all ports at beginning of list */
if (Debug) Printf("deleting leading port from child\n");
tmp = ChildObjList->next;
// FreeObjectAndHash(ChildObjList, ChildCell);
FreeObject(ChildObjList);
ChildObjList = tmp;
}
tmp = ChildObjList;
while (tmp && (tmp->next != NULL)) {
if (IsPort(tmp->next)) {
ob2 = (tmp->next)->next;
if (Debug) Printf("deleting a port from child\n");
// FreeObjectAndHash(tmp->next, ChildCell);
FreeObject(tmp->next);
tmp->next = ob2;
}
else tmp = tmp->next;
}
if (ParentProps && (ParentProps->type != PROPERTY)) {
ParentProps = NULL;
CurrentProp = NULL;
}
else
CurrentProp = ParentProps;
/* for each element in child, prepend 'prefix' */
/* Find the end record of the parent cell and save it */
for (ParentEnd = (ParentProps) ? ParentProps : ParentParams;
ParentEnd && ParentEnd->next &&
/* Stop on a node or the next instance */
((ParentEnd->next->type > FIRSTPIN) ||
(ParentEnd->next->type == PROPERTY));
ParentEnd = ParentEnd->next);
/* Not primitive, so need to flatten this instance */
notdone = 1;
/* Loop over property records. Need to flatten once per */
/* property record (or more, if property has M > 1) */
ob2 = NULL;
ChildObjList = NULL;
ChildListEnd = NULL;
while (1) {
ChildStart = CopyObjList(ChildCell->cell, 1);
numflat++;
/* Find the end record of the child cell and save it */
for (ChildEnd = ChildStart; ChildEnd && ChildEnd->next;
ChildEnd = ChildEnd->next);
if (ChildListEnd == NULL) ChildListEnd = ChildEnd;
/* update node numbers in child to unique numbers */
oldmax = 0;
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next) {
if (tmp->node > oldmax) oldmax = tmp->node;
if (tmp->node > 0) tmp->node += (nextnode - 1);
}
nextnode += oldmax;
/* copy nodenumbers of ports from parent */
ob2 = ParentParams;
for (tmp = ChildStart; tmp && IsPort(tmp); tmp = tmp->next) {
if (tmp->node > 0) {
if (ob2->node == -1) {
// Before commiting to attaching to a unconnected node, see
// if there is another node in ParentParams with the same
// name and a valid node number. If so, connect them. In
// the broader case, it may be necessary to consider all
// nodes, not just those with node == -1, and call join()
// here to update all node numbers in the parent cell.
// In that case, a more efficient method is needed for
// tracking same-name ports.
for (ob3 = ParentParams; ob3 && ob3->type >= FIRSTPIN;
ob3 = ob3->next) {
if (ob3 == ob2) continue;
if ((*matchfunc)(ob3->name, ob2->name) && ob3->node != -1) {
ob2->node = ob3->node;
break;
}
}
}
if (Debug) {
// Printf(" Sealing port: %d to node %d\n", tmp->node, ob2->node);
Printf("Update node %d --> %d\n", tmp->node, ob2->node);
}
UpdateNodeNumbers(ChildStart, tmp->node, ob2->node);
}
/* in pathological cases, the lengths of the port lists may
* change. This is an error, but that is no reason to allow
* the code to core dump. We avoid this by placing a
* superfluous check on ob2->type
*/
if (ob2 != NULL) ob2 = ob2->next;
if (ob2 == NULL) break;
}
/* Using name == NULL to indicate that a .ext file is being */
/* flattened on the fly. This is quick & dirty. */
if (name != NULL) {
/* delete all port elements from child */
while ((ChildStart != NULL) && IsPort(ChildStart)) {
/* delete all ports at beginning of list */
if (Debug) Printf("deleting leading port from child\n");
tmp = ChildStart->next;
FreeObject(ChildStart);
ChildStart = tmp;
}
tmp = ChildStart;
while (tmp && (tmp->next != NULL)) {
if (IsPort(tmp->next)) {
ob2 = (tmp->next)->next;
if (Debug) Printf("deleting a port from child\n");
FreeObject(tmp->next);
tmp->next = ob2;
}
else tmp = tmp->next;
}
if (ChildStart == NULL) {
if (ChildListEnd == ChildEnd) ChildListEnd = NULL;
ChildEnd = NULL;
}
}
/* for each element in child, prepend 'prefix' */
#if !OLDPREFIX
/* replaces all the sprintf's below */
strcpy(tmpstr,ParentParams->instance.name);
strcat(tmpstr,SEPARATOR);
prefixlength = strlen(tmpstr);
/* replaces all the sprintf's below */
strcpy(tmpstr,ParentParams->instance.name);
strcat(tmpstr,SEPARATOR);
prefixlength = strlen(tmpstr);
#endif
for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next) {
if (tmp->type == PROPERTY)
continue;
for (tmp = ChildStart; tmp != NULL; tmp = tmp->next) {
if (tmp->type == PROPERTY)
continue;
else if (IsGlobal(tmp)) {
/* Keep the name but search for node of same name in parent */
/* and replace the node number, if found. */
else if (IsGlobal(tmp)) {
/* Keep the name but search for node of same name in parent */
/* and replace the node number, if found. */
for (ob2 = ThisCell->cell; ob2 != NULL; ob2 = ob2->next) {
/* Type in parent may be a port, not a global */
if (ob2->type == tmp->type || ob2->type == PORT) {
if ((*matchfunc)(tmp->name, ob2->name)) {
if (ob2->node >= 0) {
// Replace all child objects with this node number
rnodenum = tmp->node;
for (ob3 = ChildObjList; ob3 != NULL; ob3 = ob3->next) {
if (ob3->node == rnodenum)
ob3->node = ob2->node;
}
break;
}
}
}
}
// Don't hash this if the parent had a port of this name
if (!ob2 || ob2->type != PORT)
HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict));
continue;
}
for (ob2 = ThisCell->cell; ob2 != NULL; ob2 = ob2->next) {
/* Type in parent may be a port, not a global */
if (ob2->type == tmp->type || ob2->type == PORT) {
if ((*matchfunc)(tmp->name, ob2->name)) {
if (ob2->node >= 0) {
// Replace all child objects with this node number
rnodenum = tmp->node;
for (ob3 = ChildStart; ob3 != NULL; ob3 = ob3->next) {
if (ob3->node == rnodenum)
ob3->node = ob2->node;
}
break;
}
}
}
}
// Don't hash this if the parent had a port of this name
if (!ob2 || ob2->type != PORT)
HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict));
continue;
}
#if OLDPREFIX
sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR,
tmp->name);
sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR,
tmp->name);
#else
strcpy(tmpstr+prefixlength,tmp->name);
strcpy(tmpstr+prefixlength,tmp->name);
#endif
if (Debug) Printf("Renaming %s to %s\n", tmp->name, tmpstr);
FreeString(tmp->name);
tmp->name = strsave(tmpstr);
HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict));
if ((tmp->type != NODE) && (tmp->instance.name != NULL)) {
if (Debug) Printf("Renaming %s to %s\n", tmp->name, tmpstr);
FreeString(tmp->name);
tmp->name = strsave(tmpstr);
HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict));
if ((tmp->type != NODE) && (tmp->instance.name != NULL)) {
#if OLDPREFIX
sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR,
tmp->instance.name);
sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR,
tmp->instance.name);
#else
strcpy(tmpstr+prefixlength,tmp->instance.name);
strcpy(tmpstr+prefixlength,tmp->instance.name);
#endif
FreeString(tmp->instance.name);
tmp->instance.name = strsave(tmpstr);
if (tmp->type == FIRSTPIN)
HashPtrInstall(tmp->instance.name, tmp, &(ThisCell->instdict));
}
}
/* Do property inheritance */
if (ParentProps) {
for (ob2 = ChildObjList; ob2 != NULL; ob2=ob2->next) {
/* If the parent cell has properties to declare, then */
/* pass them on to children. Use globals only if the */
/* spiceparams dictionary is active (during file reading */
/* only). */
if (ob2->type == PROPERTY)
ReduceExpressions(ob2, ParentProps, ChildCell,
(spiceparams.hashtab == NULL) ? 0 : 1);
FreeString(tmp->instance.name);
tmp->instance.name = strsave(tmpstr);
if (tmp->type == FIRSTPIN)
HashPtrInstall(tmp->instance.name, tmp, &(ThisCell->instdict));
}
}
/* Do property inheritance */
/* NOTE: Need to do: Check properties for M > 1 and decrement
* and repeat without moving CurrentProp
*/
if (CurrentProp) {
for (ob2 = ChildStart; ob2 != NULL; ob2=ob2->next) {
/* If the parent cell has properties to declare, then */
/* pass them on to children. Use globals only if the */
/* spiceparams dictionary is active (during file */
/* reading only). */
if (ob2->type == PROPERTY)
ReduceExpressions(ob2, CurrentProp, ChildCell,
(spiceparams.hashtab == NULL) ? 0 : 1);
}
/* Repeat for each property record, as each property represents a
* unique instance that must be flattened individually.
*/
CurrentProp = CurrentProp->next;
if ((CurrentProp == NULL) || (CurrentProp->type != PROPERTY)) break;
}
else break;
/* Put the child cell at the start of ChildObjList */
ChildEnd->next = ChildObjList;
ChildObjList = ChildStart;
}
/* splice instance out of parent */
if ((ParentParams == ThisCell->cell) && (ChildObjList == NULL)) {
ThisCell->cell = ob2; /* Child cell was empty */
tmp = ob2;
/* Put the child cell at the start of ChildObjList */
if (ChildEnd) {
ChildEnd->next = ChildObjList;
ChildObjList = ChildStart;
}
else {
/* Pull the instance out of the parent */
if ((ParentParams != ThisCell->cell) || (ChildObjList != NULL)) {
if (ParentParams == ThisCell->cell) {
/* ParentParams are the very first thing in the list */
ThisCell->cell = ChildObjList;
for (ob2 = ChildObjList; ob2 && ob2->next != NULL; ob2 = ob2->next) ;
/* ParentParams are the very first thing in the list */
ThisCell->cell = ChildObjList;
}
else {
/* find ParentParams in ThisCell list. In most cases, LastObj */
/* should be pointing to it. */
if (LastObj && (LastObj->next == ParentParams)) {
ob2 = LastObj;
}
else {
for (ob2 = LastObj; ob2 && ob2->next != ParentParams; ob2=ob2->next);
if (ob2 == NULL) {
/* It should not happen that LastObj is ahead of ParentParams */
/* but just in case, this long loop will find it. */
for (ob2 = ThisCell->cell; ob2 && ob2->next != ParentParams; ob2=ob2->next);
}
}
if (ob2)
for (ob2->next = ChildObjList; ob2->next != NULL; ob2 = ob2->next) ;
else if (ChildObjList) {
/* find ParentParams in ThisCell list. In most cases, LastObj */
/* should be pointing to it. */
if (LastObj && (LastObj->next == ParentParams)) {
LastObj->next = ChildObjList;
}
else {
for (ob2 = LastObj; ob2 && ob2->next != ParentParams;
ob2 = ob2->next);
if (ob2 == NULL) {
/* It should not happen that LastObj is ahead of ParentParams */
/* but just in case, this long loop will find it. */
for (ob2 = ThisCell->cell; ob2 && ob2->next != ParentParams;
ob2 = ob2->next);
}
ob2->next = ChildObjList;
}
}
/* now, ob2 is last element in child list, so skip and reclaim parent */
else {
/* The child was completely optimized out, so close list around it */
LastObj->next = ParentEnd->next;
}
tmp = ParentParams;
do {
tmp = tmp->next;
} while ((tmp != NULL) && ((tmp->type > FIRSTPIN) || (tmp->type == PROPERTY)));
if (ob2) ob2->next = tmp;
/* Link end of child list into the parent */
if (ChildListEnd && ParentEnd)
ChildListEnd->next = ParentEnd->next;
}
while (ParentParams != tmp) {
ob2 = ParentParams->next;
FreeObjectAndHash(ParentParams, ThisCell);
ParentParams = ob2;
ParentNext = (ParentEnd) ? ParentEnd->next : NULL;
while (ParentParams != ParentNext) {
ob2 = ParentParams->next;
FreeObjectAndHash(ParentParams, ThisCell);
ParentParams = ob2;
}
NextObj = ParentParams;
} /* repeat until no more instances found */
@@ -1085,12 +1128,32 @@ int UniquePins(char *name, int filenum)
firstport = (struct objlist **)CALLOC(maxnode + 1, sizeof(struct objlist *));
portcount = FIRSTPIN;
lob = NULL;
for (ob = ThisCell->cell; ob != NULL; ob = ob->next) {
if (ob->type != PORT) break;
if (ob->node > 0) {
nodecount[ob->node]++;
if (nodecount[ob->node] == 2) {
Printf("Duplicate pin %s in cell %s\n", ob->name, ThisCell->name);
if (!(*matchfunc)(firstport[ob->node]->name, ob->name)) {
Printf("Pins %s and %s are shorted in cell %s (%d)\n", ob->name,
firstport[ob->node]->name, ThisCell->name, ThisCell->file);
/* Do not count this as a duplicate pin. */
nodecount[ob->node]--;
/* Move the pin adjacent to the one it is shorted to (if it
* isn't already); this will make the work of MatchPins() easier.
*/
if (firstport[ob->node]->next != ob) {
lob->next = ob->next;
ob->next = firstport[ob->node]->next;
firstport[ob->node]->next = ob;
ob = lob;
}
lob = ob;
continue;
}
else {
Printf("Duplicate pin %s in cell %s\n", ob->name, ThisCell->name);
}
}
if (nodecount[ob->node] > 1) {
/* Remove this node; prep for removal by marking with UNKNOWN */
@@ -1105,6 +1168,7 @@ int UniquePins(char *name, int filenum)
}
}
portcount++;
lob = ob;
}
if (needscleanup)
@@ -1371,6 +1435,22 @@ typedef struct ecomplist {
ECompListPtr next;
} ECompList;
/*----------------------------------------------------------------------*/
/* Determine if a cell contains at least one device or subcircuit */
/*----------------------------------------------------------------------*/
int
HasContents(struct nlist *tc)
{
struct objlist *ob;
for (ob = tc->cell; ob; ob = ob->next)
if (ob->type == FIRSTPIN)
return TRUE;
return FALSE;
}
/*------------------------------------------------------*/
/* Survey the contents of a cell and sort into a hash */
/*------------------------------------------------------*/
@@ -1468,6 +1548,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
struct hashdict compdict;
ECompare *ecomp, *ncomp;
ECompList *list0X, *listX0;
int hascontents1, hascontents2;
int match, modified = 0;
if (file1 == -1)
@@ -1483,6 +1564,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
if (tc1 == NULL || tc2 == NULL) return 0;
InitializeHashTable(&compdict, OBJHASHSIZE);
listX0 = list0X = NULL;
// Gather information about instances of cell "name1"
SurveyCell(tc1, &compdict, file1, file2, 0);
@@ -1495,7 +1577,6 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
// in the hierarchy of each instance contain devices
// or subcircuits that have more in the compared circuit.
listX0 = list0X = NULL;
ecomp = (ECompare *)HashFirst(&compdict);
while (ecomp != NULL) {
@@ -1532,22 +1613,23 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
}
}
else {
match = 0;
// cell exists in one circuit but not the other, so flatten it.
// match = 0;
break;
}
}
}
if (match) {
if (ecomp->cell1) {
Fprintf(stdout, "Flattening instances of %s in cell %s"
if (ecomp->cell1 && (ecomp->num1 > 0)) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" makes a better match\n", ecomp->cell1->name,
name1);
name1, file1);
flattenInstancesOf(name1, file1, ecomp->cell1->name);
}
if (ecomp->cell2) {
Fprintf(stdout, "Flattening instances of %s in cell %s"
if (ecomp->cell2 && (ecomp->num2 > 0)) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" makes a better match\n", ecomp->cell2->name,
name2);
name2, file2);
flattenInstancesOf(name2, file2, ecomp->cell2->name);
}
modified++;
@@ -1599,7 +1681,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
}
/* Case 2: Cell2 class is a subcircuit, and flattening */
/* (it without regard to cell1) improves the matching. */
/* it (without regard to cell1) improves the matching. */
else if ((ecomp->num1 != ecomp->num2) && (ecomp->cell2 != NULL) &&
(ecomp->num2 != 0) && (ecomp->cell2->class == CLASS_SUBCKT)) {
@@ -1627,13 +1709,21 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
}
}
if (match) {
if (ecomp->cell2) {
Fprintf(stdout, "Flattening instances of %s in cell %s"
/* Don't flatten if cell1 is a black box, because it */
/* can't also be flattened. */
if ((ecomp->num1 == 0) || (ecomp->cell1->class !=
CLASS_MODULE)) {
if (ecomp->cell2) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" makes a better match\n", ecomp->cell2->name,
name2);
flattenInstancesOf(name2, file2, ecomp->cell2->name);
name2, file2);
flattenInstancesOf(name2, file2, ecomp->cell2->name);
}
modified++;
}
modified++;
}
/* Reset or apply the count adjustments */
@@ -1657,7 +1747,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
}
/* Case 3: Cell1 class is a subcircuit, and flattening */
/* (it without regard to cell1) improves the matching. */
/* it (without regard to cell2) improves the matching. */
else if ((ecomp->num1 != ecomp->num2) && (ecomp->cell1 != NULL) &&
(ecomp->num1 != 0) && (ecomp->cell1->class == CLASS_SUBCKT)) {
@@ -1685,13 +1775,21 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
}
}
if (match) {
if (ecomp->cell1) {
Fprintf(stdout, "Flattening instances of %s in cell %s"
/* Don't flatten if cell2 is a black box, because it */
/* can't also be flattened. */
if ((ecomp->num2 == 0) || (ecomp->cell2->class !=
CLASS_MODULE)) {
if (ecomp->cell1) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" makes a better match\n", ecomp->cell1->name,
name1);
flattenInstancesOf(name1, file1, ecomp->cell1->name);
name1, file1);
flattenInstancesOf(name1, file1, ecomp->cell1->name);
}
modified++;
}
modified++;
}
/* Reset or apply the count adjustments */
@@ -1769,9 +1867,9 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
}
if (found) {
Fprintf(stdout, "Removing zero-valued device "
"%s from cell %s makes a better match\n",
tsub1->name,
tc1->name);
"%s from cell %s (%d) makes a better "
"match\n",
tsub1->name, tc1->name, tc1->file);
/* A current source is an open, while a */
/* resistor or voltage source is a short. */
@@ -1880,9 +1978,9 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
}
if (found) {
Fprintf(stdout, "Removing zero-valued device "
"%s from cell %s makes a better match\n",
tsub2->name,
tc2->name);
"%s from cell %s (%d) makes a better "
"match\n",
tsub2->name, tc2->name, tc2->file);
/* merge node of endpoints */
if (ecomp->cell2->class != CLASS_ISOURCE) {
@@ -1973,8 +2071,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
if (dstr) *dstr = '[';
if ((ncomp == ecomp0X) && (ecomp0X->num2 <= ecompX0->num1)) {
Fprintf(stdout, "Flattening instances of %s in cell %s"
" makes a better match\n", ecompX0->cell1->name,
name1);
"(%d) makes a better match\n",
ecompX0->cell1->name, name1, file1);
flattenInstancesOf(name1, file1, ecompX0->cell1->name);
ecompX0->num1 = 0;
ecomp0X->num1 += ecompX0->num1;
@@ -1999,8 +2097,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
if (dstr) *dstr = '[';
if ((ncomp == ecompX0) && (ecompX0->num1 <= ecomp0X->num2)) {
Fprintf(stdout, "Flattening instances of %s in cell %s"
" makes a better match\n", ecomp0X->cell2->name,
name2);
" (%d) makes a better match\n",
ecomp0X->cell2->name, name2, file2);
flattenInstancesOf(name2, file2, ecomp0X->cell2->name);
ecomp0X->num2 = 0;
ecompX0->num2 += ecomp0X->num2;
@@ -2014,6 +2112,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
}
}
done:
// Free the hash table and its contents.
ecomp = (ECompare *)HashFirst(&compdict);
+8
View File
@@ -0,0 +1,8 @@
#ifndef _FLATTEN_H
#define _FLATTEN_H
extern int UniquePins(char *name, int filenum);
extern void flattenCell(char *name, int file);
extern int HasContents(struct nlist *);
#endif /* _FLATTEN_H */
+2 -2
View File
@@ -30,8 +30,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#endif
#include "netgen.h"
#include "hash.h"
#include "objlist.h"
#include "hash.h"
unsigned long (*hashfunc)(char *, int) = NULL;
int (*matchfunc)(char *, char *) = NULL;
@@ -148,7 +148,7 @@ unsigned long hashnocase(char *s, int hashsize)
return (hashsize == 0) ? hashval : (hashval % hashsize);
}
unsigned long hash(char *s, int hashsize)
unsigned long hashcase(char *s, int hashsize)
{
unsigned long hashval;
+1 -1
View File
@@ -48,7 +48,7 @@ extern void *HashFirst(struct hashdict *dict);
extern void *HashNext(struct hashdict *dict);
extern unsigned long hashnocase(char *s, int hashsize);
extern unsigned long hash(char *s, int hashsize);
extern unsigned long hashcase(char *s, int hashsize);
extern int (*matchfunc)(char *, char *);
/* matchintfunc() compares based on the name and the first */
+406 -129
View File
@@ -21,11 +21,13 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include <stdio.h>
#include <stdlib.h> /* for rand(), abs(), etc */
#include <setjmp.h>
#include <signal.h>
#include <time.h> /* for time() as a seed for random number generator */
#include <limits.h>
#include <math.h> /* for fabs() */
#include <ctype.h> /* for toupper() */
#ifdef IBMPC
#include <alloc.h>
@@ -45,11 +47,13 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "netfile.h"
#include "print.h"
#include "dbug.h"
#include "hash.h"
#ifdef TCL_NETGEN
int InterruptPending = 0;
void (*oldinthandler)() = SIG_DFL;
extern Tcl_Interp *netgeninterp;
extern int check_interrupt();
#endif
/* define the following to debug core allocation */
@@ -620,15 +624,15 @@ struct FormattedList *FormatBadElementFragment(struct Element *E)
for (elems = nodes[i]->node->elementlist; elems != NULL;
elems = elems->next)
count++;
elemlist->flist[k].count = count;
if (*ob->name != *ob->instance.name) // e.g., "port_match_error"
elemlist->flist[k].name = ob->name;
else
elemlist->flist[k].name = ob->name + strlen(ob->instance.name) + 1;
elemlist->flist[k].permute = (char)1;
k++;
}
elemlist->flist[k].count = count;
if (*ob->name != *ob->instance.name) // e.g., "port_match_error"
elemlist->flist[k].name = ob->name;
else
elemlist->flist[k].name = ob->name + strlen(ob->instance.name) + 1;
elemlist->flist[k].permute = (char)1;
k++;
}
else { /* handle multiple permutable pins */
struct objlist *ob2;
@@ -665,13 +669,16 @@ struct FormattedList *FormatBadElementFragment(struct Element *E)
struct ElementList *elems;
count = 0;
if (nodes[j]->node == NULL) continue; // ?
for (elems = nodes[j]->node->elementlist; elems != NULL;
elems = elems->next)
count++;
if (nodes[j]->node == NULL) /* Under what condition is the node NULL? */
count++;
else {
for (elems = nodes[j]->node->elementlist; elems != NULL;
elems = elems->next)
count++;
}
if (count >= maxcount) {
maxcount = count;
maxindex = j;
maxcount = count;
maxindex = j;
}
}
}
@@ -868,7 +875,11 @@ struct FormattedList *FormatBadNodeFragment(struct Node *N)
for (n = pins[i]->subelement->element->nodelist; n != NULL; n = n->next){
if (n->pin_magic == pins[i]->subelement->pin_magic) {
if ((permute == 0) && (ob->instance.name != NULL)) {
pinname = ob->name + strlen(ob->instance.name) + 1;
/* Handle "port_match_error" */
if ((ob->name[0] == 'p') && !strcmp(ob->name, "port_match_error"))
pinname = ob->name;
else
pinname = ob->name + strlen(ob->instance.name) + 1;
}
else if (ob->instance.name != NULL) {
char *pinsave = pinname;
@@ -886,9 +897,8 @@ struct FormattedList *FormatBadNodeFragment(struct Node *N)
WITH THE SAME HASH NUMBER, are on this node */
for (j = i+1; j < fanout; j++) {
if (pins[j] != NULL &&
(*matchfunc) (model,
pins[j]->subelement->element->object->model.class) &&
pins[i]->subelement->pin_magic == pins[j]->subelement->pin_magic) {
(*matchfunc)(model, pins[j]->subelement->element->object->model.class) &&
pins[i]->subelement->pin_magic == pins[j]->subelement->pin_magic) {
count++;
nodelist->fanout--;
pins[j] = NULL;
@@ -968,16 +978,36 @@ void PrintBadNodeFragment(struct Node *N)
WITH THE SAME HASH NUMBER, are on this node */
for (j = i+1; j < fanout; j++) {
if (pins[j] != NULL &&
(*matchfunc)(model,
pins[j]->subelement->element->object->model.class) &&
pins[i]->subelement->pin_magic == pins[j]->subelement->pin_magic) {
count++;
pins[j] = NULL;
}
(*matchfunc)(model, pins[j]->subelement->element->object->model.class) &&
pins[i]->subelement->pin_magic == pins[j]->subelement->pin_magic) {
count++;
/* pins[j] = NULL; */ /* Done in diagnostic output, below */
}
}
if (i != 0) Fprintf(stdout, ";");
if (i != 0) {
/* Fprintf(stdout, ";"); */
Fprintf(stdout, "\n");
Ftab(stdout, 32);
}
Fprintf(stdout, " %s:%s = %d", model, pinname, count);
/* Diagnostic */
Fprintf(stdout, "\n");
Ftab(stdout, 25);
Fprintf(stdout, ">>> %s", pins[i]->subelement->element->object->instance);
for (j = i+1; j < fanout; j++) {
if (pins[j] != NULL &&
(*matchfunc)(model, pins[j]->subelement->element->object->model.class) &&
pins[i]->subelement->pin_magic == pins[j]->subelement->pin_magic) {
/* Diagnostic */
Fprintf(stdout, "\n");
Ftab(stdout, 25);
Fprintf(stdout, ">>> %s", pins[j]->subelement->element->object->instance);
pins[j] = NULL;
}
}
pins[i] = NULL; /* not really necessary */
}
Fprintf(stdout, "\n");
@@ -1360,8 +1390,8 @@ void SortUnmatchedLists(nlists1, nlists2, n1max, n2max)
nlists2[n1] = temp;
HashPtrInstall(nlists2[n1]->name, (void *)((long)n1 + 1), &n2hash);
HashPtrInstall(nlists2[n2]->name, (void *)((long)n2 + 1), &n2hash);
SortFanoutLists(nlists1[n1], nlists2[n1]);
}
SortFanoutLists(nlists1[n1], nlists2[n1]);
}
}
@@ -1416,8 +1446,13 @@ void SortUnmatchedLists(nlists1, nlists2, n1max, n2max)
nlists1[n2] = temp;
HashPtrInstall(nlists1[n1]->name, (void *)((long)n1 + 1), &n1hash);
HashPtrInstall(nlists1[n2]->name, (void *)((long)n2 + 1), &n1hash);
SortFanoutLists(nlists2[n2], nlists1[n2]);
}
SortFanoutLists(nlists2[n2], nlists1[n2]);
}
else if ((n1max == 1) && (n2max == 1)) {
/* Names didn't match but there's only one entry on each side, */
/* so do a sort anyway. */
SortFanoutLists(nlists2[n2], nlists1[n2]);
}
}
/* For all nets that didn't match by name, match by content */
@@ -3091,6 +3126,47 @@ struct nlist *LookupPrematchedClass(struct nlist *tc1, int file2)
return tc2;
}
/*----------------------------------------------------------------------*/
/* Scan the property list of a device to find the number of devices */
/* implied by the total of M records. If the device does not have a */
/* property list, then return 1. If any property list does not have an */
/* "M" record, treat it as 1. */
/*----------------------------------------------------------------------*/
int GetNumDevices(struct objlist *ob)
{
int p, found, M = 0;
struct objlist *obs;
struct valuelist *vl;
obs = ob;
if (obs->type != PROPERTY)
for (obs = ob->next; obs && (obs->type != FIRSTPIN) &&
(obs->type != PROPERTY); obs = obs->next);
if ((obs == NULL) || (obs->type != PROPERTY)) return 1;
while (obs && (obs->type == PROPERTY)) {
found = FALSE;
for (p = 0; ; p++) {
vl = &obs->instance.props[p];
if (vl->type == PROP_ENDLIST) break;
if (vl->key == NULL) continue;
if ((*matchfunc)(vl->key, "M")) {
if (vl->type == PROP_DOUBLE)
M += (int)vl->value.dval;
else
M += vl->value.ival;
found = TRUE;
break;
}
}
if (found == FALSE) M++;
obs = obs->next;
}
return M;
}
/*----------------------------------------------------------------------*/
/* Attempt to define FirstElementPass that will generate element */
/* classes by names of pins, which will allow elements with different */
@@ -3112,7 +3188,7 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
struct Element *Esrch, *Ecorr;
struct NodeList *n;
struct nlist *tp1, *tp2, *tp;
int C1, C2, i;
int C1, C2, M1, M2, i;
char *ostr;
int needflat = 0;
#ifdef TCL_NETGEN
@@ -3122,7 +3198,7 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
ostr = CALLOC(right_col_end + 2, sizeof(char));
if (Debug == 0) {
Fprintf(stdout, "\nSubcircuit summary:\n");
Fprintf(stdout, "Subcircuit summary:\n");
*(ostr + left_col_end) = '|';
*(ostr + right_col_end) = '\n';
*(ostr + right_col_end + 1) = '\0';
@@ -3153,6 +3229,8 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
Esrch->hashval = 1;
C1 = 1;
C2 = 0;
M2 = 0;
M1 = GetNumDevices(Esrch->object);
tp1 = LookupCellFile(Esrch->object->model.class, Circuit1->file);
tp2 = LookupClassEquivalent(Esrch->object->model.class, Circuit1->file,
Circuit2->file);
@@ -3164,6 +3242,7 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
if (tp && tp2 && (tp->classhash == tp2->classhash)) {
Ecorr->hashval = 1;
C2++;
M2 += GetNumDevices(Ecorr->object);
}
}
else if (Ecorr->graph == Circuit1->file) {
@@ -3172,6 +3251,7 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
if (tp && tp1 && (tp->classhash == tp1->classhash)) {
Ecorr->hashval = 1;
C1++;
M1 += GetNumDevices(Ecorr->object);
}
}
}
@@ -3188,10 +3268,19 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
snprintf(ostr, left_col_end, "%s (%d)", Esrch->object->model.class, C1);
if (C2 > 0)
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d)%s", tp2->name, C2,
(C2 == C1) ? "" : " **Mismatch**");
if (M1 == C1)
snprintf(ostr, left_col_end, "%s (%d)", Esrch->object->model.class, C1);
else
snprintf(ostr, left_col_end, "%s (%d->%d)", Esrch->object->model.class,
M1, C1);
if (C2 > 0) {
if (M2 == C2)
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d)%s", tp2->name,
C2, (C2 == C1) ? "" : " **Mismatch**");
else
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d->%d)%s",
tp2->name, M2, C2, (C2 == C1) ? "" : " **Mismatch**");
}
else {
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching element)");
}
@@ -3230,6 +3319,7 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
if (Esrch->graph == Circuit2->file && Esrch->hashval == 0) {
Esrch->hashval = 1;
C2 = 1;
M2 = GetNumDevices(Esrch->object);
tp2 = LookupCellFile(Esrch->object->model.class, Circuit2->file);
tp1 = LookupClassEquivalent(Esrch->object->model.class, Circuit2->file,
Circuit1->file);
@@ -3241,6 +3331,7 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
if (tp->classhash == tp2->classhash) {
Ecorr->hashval = 1;
C2++;
M2 += GetNumDevices(Ecorr->object);
}
}
}
@@ -3256,7 +3347,12 @@ int FirstElementPass(struct Element *E, int noflat, int dolist)
for (i = 0; i < left_col_end; i++) *(ostr + i) = ' ';
for (i = left_col_end + 1; i < right_col_end; i++) *(ostr + i) = ' ';
snprintf(ostr, left_col_end, "(no matching element)");
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d)", Esrch->object->model.class, C2);
if (C2 == M2)
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d)",
Esrch->object->model.class, C2);
else
snprintf(ostr + left_col_end + 1, left_col_end, "%s (%d->%d)",
Esrch->object->model.class, M2, C2);
for (i = 0; i < right_col_end + 1; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' ';
Fprintf(stdout, ostr);
}
@@ -3636,12 +3732,19 @@ int CreateCompareQueue(char *name1, int file1, char *name2, int file2)
Fprintf(stdout, "Descend level %d circuit 2\n", level);
DescendCompareQueue(tc2, tc1, level, 0, 1);
/* NOTE: Preemptive flattening is inefficient and can cause
* unnecessary flattening of cells that will never be compared.
* let the prematch stage take care of this.
*/
/*--------------------------------------
if (Debug == TRUE)
Fprintf(stdout, "Flatten level %d circuit 1\n", level);
FlattenUnmatched(tc1, name1, level, 0);
if (Debug == TRUE)
Fprintf(stdout, "Flatten level %d circuit 2\n", level);
FlattenUnmatched(tc2, name2, level, 0);
---------------------------------------*/
level--;
}
@@ -3720,8 +3823,23 @@ void RemoveCompareQueue()
CompareQueue = NULL;
}
/*----------------------------------------------------------------------*/
/* Output a summary of the contents of the two circuits being compared */
/*----------------------------------------------------------------------*/
void DescribeContents(char *name1, int file1, char *name2, int file2)
{
Fprintf(stdout, "\n"); // blank line before new circuit diagnostics in log file
/* print preliminary statistics */
Printf("\nContents of circuit 1: ");
DescribeInstance(name1, file1);
Printf("Contents of circuit 2: ");
DescribeInstance(name2, file2);
Printf("\n");
}
/*----------------------------------*/
/* create an initial data structure */
/* Create an initial data structure */
/*----------------------------------*/
void CreateTwoLists(char *name1, int file1, char *name2, int file2, int dolist)
@@ -3733,13 +3851,6 @@ void CreateTwoLists(char *name1, int file1, char *name2, int file2, int dolist)
ResetState();
/* print preliminary statistics */
Printf("Contents of circuit 1: ");
DescribeInstance(name1, file1);
Printf("Contents of circuit 2: ");
DescribeInstance(name2, file2);
Printf("\n");
if (file1 == -1)
tc1 = LookupCell(name1);
else
@@ -3753,7 +3864,7 @@ void CreateTwoLists(char *name1, int file1, char *name2, int file2, int dolist)
/* determine if matching will be case sensitive or case insensitive */
matchfunc = match;
matchintfunc = matchfile;
hashfunc = hash;
hashfunc = hashcase;
if (tc1 != NULL && tc2 != NULL) {
if ((tc1->flags & CELL_NOCASE) && (tc2->flags & CELL_NOCASE)) {
matchfunc = matchnocase;
@@ -4118,6 +4229,7 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
sval = 1;
cval = slop = 0.0;
for (i = 0; i < run; i++) {
sl = NULL;
merge_type = MERGE_NONE;
for (p = 0;; p++) {
vl = &(obp->instance.props[p]);
@@ -4146,13 +4258,13 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run)
proplist[i].value = cval * (double)sval;
proplist[i].slop = slop;
proplist[i].avalue = 0;
sl->value.ival = 1;
if (sl) sl->value.ival = 1;
}
else if (merge_type == MERGE_S_PAR) {
proplist[i].value = cval / (double)sval;
proplist[i].slop = slop;
proplist[i].avalue = 0;
sl->value.ival = 1;
if (sl) sl->value.ival = 1;
}
else {
/* Components which declare no series addition method stay unsorted */
@@ -4697,7 +4809,7 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
struct objlist *ob2, *obt;
struct property *kl, *m_rec, **plist;
unsigned char **clist;
struct valuelist ***vlist, *vl, *vl2, *newvlist;
struct valuelist ***vlist, *vl, *vl2, *newvlist, critval;
proplinkptr plink, ptop;
int pcount, p, i, j, k, pmatch, ival, ctype;
double dval;
@@ -4785,12 +4897,12 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
else if (kl != NULL) {
vlist[kl->idx][i] = vl;
if (series == FALSE) {
if (kl->merge & (MERGE_P_ADD | MERGE_P_PAR))
if (kl->merge & (MERGE_P_ADD | MERGE_P_PAR | MERGE_P_CRIT))
clist[kl->idx][i] = kl->merge &
(MERGE_P_ADD | MERGE_P_PAR | MERGE_P_CRIT);
}
else if (series == TRUE) {
if (kl->merge & (MERGE_S_ADD | MERGE_S_PAR))
if (kl->merge & (MERGE_S_ADD | MERGE_S_PAR | MERGE_S_CRIT))
clist[kl->idx][i] = kl->merge &
(MERGE_S_ADD | MERGE_S_PAR | MERGE_S_CRIT);
}
@@ -4813,6 +4925,7 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
// Now combine records with same properties by summing M (S).
if (comb == FALSE) {
for (i = 0; i < run - 1; i++) {
int nr_empty = 0;
for (j = i + 1; j < run; j++) {
pmatch = 0;
for (p = 1; p < pcount; p++) {
@@ -4936,8 +5049,14 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
vlist[0][i]->value.ival += vlist[0][j]->value.ival;
vlist[0][j]->value.ival = 0;
}
else
nr_empty++;
}
}
// If everything from i to the end of the run has been matched
// and zeroed out, then nothing more can be merged.
if (nr_empty == (run - (i + 1)))
break;
}
}
@@ -4945,24 +5064,44 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
// (if any)
if (comb == TRUE) {
int mult;
int mult, cidx = -1;
struct valuelist *avl, *cvl = NULL;
critval.type = PROP_ENDLIST;
critval.value.dval = 0.0;
for (i = 0; i < run; i++) {
avl = NULL;
if (vlist[0][i] == NULL) continue;
mult = vlist[0][i]->value.ival;
if (mult > 1) {
changed = 0;
changed = 0;
/* For all properties that are not M, S, or crit, */
/* combine as specified by the merge type of the property. */
/* For all properties that are not M, S, or crit, */
/* combine as specified by the merge type of the property. */
for (p = 1; p < pcount; p++) {
vl = vlist[p][i];
ctype = clist[p][i];
for (p = 1; p < pcount; p++) {
vl = vlist[p][i];
ctype = clist[p][i];
/* critical properties never combine */
if ((series == TRUE) && (ctype & MERGE_S_CRIT)) continue;
if ((series == FALSE) && (ctype & MERGE_P_CRIT)) continue;
/* critical properties never combine, but track them */
if ((series == TRUE) && (ctype & MERGE_S_CRIT)) {
if ((vl->type != critval.type) || (vl->value.dval != critval.value.dval))
{
critval.type = vl->type;
critval.value = vl->value;
cidx = i;
}
continue;
}
if ((series == FALSE) && (ctype & MERGE_P_CRIT)) {
if ((vl->type != critval.type) || (vl->value.dval != critval.value.dval))
{
critval.type = vl->type;
critval.value = vl->value;
cidx = i;
}
continue;
}
if (mult > 1) {
if (ctype & (MERGE_S_ADD | MERGE_P_ADD)) {
if (vl->type == PROP_INTEGER)
vl->value.ival *= mult;
@@ -4982,14 +5121,68 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series,
vlist[0][i]->value.ival = 1;
changed += mult;
}
if (changed > 0) {
if (series)
Printf("Combined %d series devices.\n", changed);
else
Printf("Combined %d parallel devices.\n", changed);
}
if (ctype & (MERGE_S_ADD | MERGE_P_ADD | MERGE_S_PAR | MERGE_P_PAR))
avl = vl;
}
if (cidx == i) cvl = avl;
/* Sorting should have put all records with the same critical */
/* value together sequentially. So if there are still */
/* multiple property records, then merge them into the first */
/* record with the same critical property value. */
if ((i > 0) && (cidx >= 0) && (cidx < i)) {
for (p = 1; p < pcount; p++) {
vl = vlist[p][i];
ctype = clist[p][i];
if (ctype & (MERGE_S_ADD | MERGE_P_ADD)) {
vlist[0][i]->value.ival = 0; /* set M to 0 */
if (cvl && (cvl->type == PROP_INTEGER))
{
if (vl->type == PROP_INTEGER)
cvl->value.ival += vl->value.ival;
else {
cvl->type = PROP_DOUBLE;
cvl->value.dval = (double)cvl->value.ival + vl->value.dval;
}
}
else if ((cvl && vl->type == PROP_DOUBLE))
{
if (vl->type == PROP_INTEGER)
cvl->value.dval += (double)vl->value.ival;
else
cvl->value.dval += vl->value.dval;
}
}
else if (ctype & (MERGE_S_PAR | MERGE_P_PAR)) {
vlist[0][i]->value.ival = 0; /* set M to 0 */
/* To do parallel combination, both types need to
* be double, so recast them if they are integer.
*/
if (vl->type == PROP_INTEGER) {
vl->type = PROP_DOUBLE;
vl->value.dval = (double)(vl->value.ival);
}
if (cvl && (cvl->type == PROP_INTEGER)) {
cvl->type = PROP_DOUBLE;
cvl->value.dval = (double)cvl->value.ival;
}
if ((cvl && (vl->type == PROP_DOUBLE))) {
cvl->value.dval =
sqrt(cvl->value.dval * cvl->value.dval
+ vl->value.dval * vl->value.dval);
}
}
}
}
}
if (changed > 0) {
if (series)
Printf("Combined %d series devices.\n", changed);
else
Printf("Combined %d parallel devices.\n", changed);
}
}
}
@@ -5595,10 +5788,10 @@ PropertyMatch(struct objlist *ob1, int file1,
int do_print, int do_list, int *retval)
{
struct nlist *tc1, *tc2;
struct objlist *tp1, *tp2, *obn1, *obn2;
struct objlist *tp1, *tp2, *obn1, *obn2, *tpc;
struct property *kl1, *kl2;
struct valuelist *vl1, *vl2;
int t1type, t2type;
int t1type, t2type, run1, run2;
int i, mismatches = 0, checked_one;
int rval = 1;
char *inst1, *inst2;
@@ -5691,13 +5884,12 @@ PropertyMatch(struct objlist *ob1, int file1,
#endif
}
/* WIP---Check for no-connect pins in merged devices on both sides. */
/* Check for no-connect pins in merged devices on both sides. */
/* Both sides should either have no-connects marked, or neither. */
/* (Permutable pins may need to be handled correctly. . . */
for (tp1 = ob1, tp2 = ob2; (tp1 != NULL) && tp1->type >= FIRSTPIN &&
(tp2 != NULL) && tp2->type >= FIRSTPIN; tp1 = tp1->next, tp2 = tp2->next)
{
(tp2 != NULL) && tp2->type >= FIRSTPIN; tp1 = tp1->next, tp2 = tp2->next) {
struct objlist *node1, *node2;
if (file1 == Circuit1->file)
@@ -5710,17 +5902,20 @@ PropertyMatch(struct objlist *ob1, int file1,
else
node2 = Circuit2->nodename_cache[tp2->node];
if (node1->instance.flags != node2->instance.flags)
{
/* NOTE: A "no-connect" node (multiple no-connects represented by a
* single node) has non-zero flags. A non-node entry in the cache
* implies a node with zero flags.
*/
if (node1->flags != node1->flags) {
Fprintf(stdout, " Parallelized instances disagree on pin connections.\n");
Fprintf(stdout, " Circuit1 instance %s pin %s connections are %s (%d)\n",
tp1->instance.name, node1->name,
(node1->instance.flags == 0) ? "tied together" : "no connects",
node1->instance.flags);
(node1->flags == 0) ? "tied together" : "no connects",
node1->flags);
Fprintf(stdout, " Circuit2 instance %s pin %s connections are %s (%d)\n",
tp2->instance.name, node2->name,
(node2->instance.flags == 0) ? "tied together" : "no connects",
node2->instance.flags);
(node2->flags == 0) ? "tied together" : "no connects",
node2->flags);
mismatches++;
}
}
@@ -5746,10 +5941,12 @@ PropertyMatch(struct objlist *ob1, int file1,
if ((t1type != PROPERTY) && (checked_one == TRUE)) {
// t2 has more property records than t1, and they did not get
// merged equally by PropertySortAndCombine().
Fprintf(stdout, "Circuit 1 parallel/series network does not match"
if (do_print) {
Fprintf(stdout, "Circuit 1 parallel/series network does not match"
" Circuit 2\n");
DumpNetwork(ob1, 1);
DumpNetwork(ob2, 2);
DumpNetwork(ob1, 1);
DumpNetwork(ob2, 2);
}
mismatches++;
}
else if (t1type != PROPERTY) {
@@ -5851,13 +6048,19 @@ PropertyMatch(struct objlist *ob1, int file1,
inst2, FALSE, FALSE, &multmatch, NULL);
if (multmatch == 1) {
/* Final attempt: Reduce M to 1 on both devices */
PropertyOptimize(tp1, tc1, 1, FALSE, TRUE);
PropertyOptimize(tp2, tc2, 1, FALSE, TRUE);
run1 = run2 = 0;
for (tpc = tp1; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run1++;
for (tpc = tp2; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run2++;
PropertyOptimize(tp1, tc1, run1, FALSE, TRUE);
PropertyOptimize(tp2, tc2, run2, FALSE, TRUE);
}
else if (multmatch == 2) {
/* Final attempt: Reduce S to 1 on both devices */
PropertyOptimize(tp1, tc1, 1, TRUE, TRUE);
PropertyOptimize(tp2, tc2, 1, TRUE, TRUE);
run1 = run2 = 0;
for (tpc = tp1; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run1++;
for (tpc = tp2; tpc && (tpc->type == PROPERTY); tpc = tpc->next) run2++;
PropertyOptimize(tp1, tc1, run1, TRUE, TRUE);
PropertyOptimize(tp2, tc2, run2, TRUE, TRUE);
}
#ifdef TCL_NETGEN
mlist =
@@ -6822,6 +7025,7 @@ int reorderpins(struct hashlist *p, int file)
nodes[ob2->model.port] = ob->node;
names[ob2->model.port] = ob->name;
}
ob = ob->next;
ob2 = ob2->next;
if (i < numports - 1) {
@@ -7023,7 +7227,7 @@ struct nlist *addproxies(struct hashlist *p, void *clientdata)
int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
{
char *cover, *ctemp;
char *bangptr1, *bangptr2;
char *bangptr1, *bangptr2, *backslashptr1, *backslashptr2;
struct objlist *ob1, *ob2, *obn, *obp, *ob1s, *ob2s, *obt;
struct NodeClass *NC;
struct Node *N1, *N2;
@@ -7097,8 +7301,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if (IsPort(obn)) {
i = 0;
for (ob1 = tc1->cell; ob1 != NULL; ob1 = ob1->next, i++) {
if ((IsPort(ob1))
&& (*matchfunc)(ob1->name, obn->name)) {
if ((IsPort(ob1)) && (ob1->node == obn->node)) {
b = 0;
for (N2 = NC->nodes; N2 != NULL; N2 = N2->next) {
if (N2->graph != Circuit1->file) {
@@ -7123,16 +7326,42 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
obp = N2->object;
j = 0;
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next, j++) {
if ((IsPort(ob2))
&& (*matchfunc)(ob2->name, obp->name)) {
if ((IsPort(ob2)) && (ob2->node == obp->node)) {
if (Debug == 0) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
for (m = left_col_end + 1; m < right_col_end; m++) *(ostr + m) = ' ';
snprintf(ostr, left_col_end, "%s", obn->name);
if ((*matchfunc)(obn->name, obp->name))
snprintf(ostr + left_col_end + 1, left_col_end, "%s", obp->name);
else
snprintf(ostr + left_col_end + 1, left_col_end, "%s **Mismatch**", obp->name);
snprintf(ostr, left_col_end, "%s", ob1->name);
if ((*matchfunc)(ob1->name, ob2->name))
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
else {
/* Check remainder of ports to see if there is a name match on the
* same net number (multiple ports tied to the same net)
*/
struct objlist *ob3;
for (ob3 = ob2->next, ++j; ob3 != NULL; ob3 = ob3->next, j++) {
if ((IsPort(ob3)) && (ob3->node == ob2->node)) {
if ((*matchfunc)(ob3->name, ob1->name)) {
ob2 = ob3;
snprintf(ostr + left_col_end + 1, left_col_end, "%s", ob2->name);
break;
}
}
else {
ob3 = NULL;
break; /* All pins w/the same node should be together */
}
}
if (ob3 == NULL) {
if (ob2->model.port == -1)
snprintf(ostr + left_col_end + 1, left_col_end, "%s **Mismatch**", ob2->name);
else
snprintf(ostr + left_col_end + 1, left_col_end, "(no matching pin)");
/* Pins with different names are on different nets,
* so this should trigger an error return code.
*/
result = 0;
}
}
for (m = 0; m < right_col_end + 1; m++)
if (*(ostr + m) == '\0') *(ostr + m) = ' ';
Fprintf(stdout, ostr);
@@ -7153,7 +7382,16 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
#endif
ob2->model.port = i; /* save order */
*(cover + i) = (char)1;
break;
/* If there are multiple pins on the same net, cycle through them; */
/* otherwise, move to the next entry in the partition. */
if (ob1->next && (ob1->next->type == PORT) && (ob1->next->node == ob1->node)) {
ob1 = ob1->next;
ob2 = tc2->cell; /* Restart search for matching pin */
i++;
}
else
break;
}
}
if (ob2 == NULL) {
@@ -7244,35 +7482,54 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
/* This should not happen if unconnected pins are eliminated */
/* so apply only to black-box (CELL_PLACEHOLDER) entries. */
/* (Semi-hack: Allow "!" global flag) */
/* (Another semi-hack: Ignore the leading backslash in */
/* backslash-escaped verilog names. Removing the backslash */
/* and ending space character is a common way to convert to */
/* legal SPICE. */
if ((tc1->flags & CELL_PLACEHOLDER) && (tc2->flags & CELL_PLACEHOLDER)) {
ob1 = tc1->cell;
ob1 = tc1->cell;
for (i = 0; i < numorig; i++) {
bangptr1 = strrchr(ob1->name, '!');
if (bangptr1 && (*(bangptr1 + 1) == '\0'))
*bangptr1 = '\0';
else bangptr1 = NULL;
for (i = 0; i < numorig; i++) {
if (*(cover + i) == (char)0) {
j = 0;
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) {
char *name1, *name2;
if (!IsPort(ob2)) break;
backslashptr1 = (*(ob1->name) == '\\') ? ob1->name + 1 : ob1->name;
bangptr2 = strrchr(ob2->name, '!');
if (bangptr2 && (*(bangptr2 + 1) == '\0'))
*bangptr2 = '\0';
else bangptr2 = NULL;
if (*(cover + i) == (char)0) {
j = 0;
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) {
char *name1, *name2;
name1 = ob1->name;
name2 = ob2->name;
if (!IsPort(ob2)) break;
/* Recognize proxy pins as matching */
if (!strncmp(name1, "proxy", 5)) name1 +=5;
if (!strncmp(name2, "proxy", 5)) name2 +=5;
bangptr2 = strrchr(ob2->name, '!');
if (bangptr2 && (*(bangptr2 + 1) == '\0'))
*bangptr2 = '\0';
else bangptr2 = NULL;
backslashptr2 = (*(ob2->name) == '\\') ? ob2->name + 1 : ob2->name;
name1 = backslashptr1;
name2 = backslashptr2;
/* Recognize proxy pins as matching unconnected pins */
if (!strncmp(name1, "proxy", 5) && (ob2->node == -1)) name1 +=5;
if (!strncmp(name2, "proxy", 5) && (ob1->node == -1)) name2 +=5;
if ((*matchfunc)(name1, name2)) {
/* If both sides have unconnected nodes, then pins with */
/* matching names are an automatic match. Otherwise, if */
/* matching black-box entries, then pins are always */
/* matched by name. */
if (((ob1->node == -1) && (ob2->node == -1)) ||
(((tc1->flags & CELL_PLACEHOLDER) &&
(tc2->flags & CELL_PLACEHOLDER)) ||
(NodeClasses == NULL))) {
if ((*matchfunc)(name1, name2)) {
ob2->model.port = i; /* save order */
*(cover + i) = (char)1;
@@ -7299,13 +7556,15 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
Tcl_NewStringObj(ob2->name, -1));
}
#endif
if (bangptr2) *bangptr2 = '!';
break;
}
if (bangptr2) *bangptr2 = '!';
j++;
}
if (bangptr2) *bangptr2 = '!';
j++;
}
ob1 = ob1->next;
}
ob1 = ob1->next;
if (bangptr1) *bangptr1 = '!';
}
@@ -7341,15 +7600,6 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
Fprintf(stderr, "No netlist match for cell %s pin %s\n",
tc2->name, ob2->name);
}
#ifdef TCL_NETGEN
if (dolist) {
Tcl_ListObjAppendElement(netgeninterp, plist1,
Tcl_NewStringObj("(no matching pin)", -1));
Tcl_ListObjAppendElement(netgeninterp, plist2,
Tcl_NewStringObj(ob2->name, -1));
}
#endif
result = 0;
/* Before making a proxy pin, check to see if */
/* flattening instances has left a port with a */
@@ -7366,8 +7616,34 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if ((obt == NULL) && (notempty == 1)) {
ob2->node = -2; // Will run this through cleanuppins
needclean2 = 1;
/* On the top level, missing pins are an error, even if */
/* they appear to match unconnected pins on the other side. */
if (CompareQueue == NULL)
result = 0;
#ifdef TCL_NETGEN
if (dolist) {
Tcl_ListObjAppendElement(netgeninterp, plist1,
Tcl_NewStringObj("(no pin)", -1));
Tcl_ListObjAppendElement(netgeninterp, plist2,
Tcl_NewStringObj(ob2->name, -1));
}
#endif
continue;
}
else if (notempty == 1) {
/* Flag this as an error */
result = 0;
#ifdef TCL_NETGEN
if (dolist) {
Tcl_ListObjAppendElement(netgeninterp, plist1,
Tcl_NewStringObj("(no matching pin)", -1));
Tcl_ListObjAppendElement(netgeninterp, plist2,
Tcl_NewStringObj(ob2->name, -1));
}
#endif
}
ob2->model.port = numnodes++; // Assign a port order
/* Add a proxy pin to tc1 */
@@ -7433,7 +7709,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
}
if (ob1 == NULL || ob1->type != PORT || ob1->node >= 0
|| (ob1->node < 0 && tc1->class == CLASS_MODULE)) {
|| (ob1->node < 0 && tc1->class == CLASS_MODULE)
|| (ob1->node < 0 && ob1->model.port == -1)) {
/* Add a proxy pin to tc2 */
obn = (struct objlist *)CALLOC(1, sizeof(struct objlist));
@@ -7450,8 +7727,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
obn->instance.name = NULL;
obn->node = -1;
#if 0
/* Note: This pin has already been accounted for */
/* Note: Has this pin already been accounted for? */
if (Debug == 0) {
if (strcmp(ob1->name, "(no pins)")) {
for (m = 0; m < left_col_end; m++) *(ostr + m) = ' ';
@@ -7467,7 +7743,6 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
Fprintf(stderr, "No netlist match for cell %s pin %s\n",
tc1->name, ob1->name);
}
#endif
if (ob2 == tc2->cell) {
obn->next = ob2;
@@ -7780,6 +8055,7 @@ int Compare(char *cell1, char *cell2)
{
int automorphisms;
DescribeContents(cell1, -1, cell2, -1);
CreateTwoLists(cell1, -1, cell2, -1, 0);
Permute();
while (!Iterate());
@@ -7840,6 +8116,7 @@ void NETCOMP(void)
case 'c':
promptstring("Enter cell 1: ",name);
promptstring("Enter cell 2: ",name2);
DescribeContents(name, -1, name2, -1);
CreateTwoLists(name, -1, name2, -1, 0);
#ifdef DEBUG_ALLOC
PrintCoreStats();
+11
View File
@@ -26,6 +26,7 @@ extern void PrintCoreStats(void);
extern void ResetState(void);
extern void CreateTwoLists(char *name1, int file1, char *name2, int file2,
int dolist);
extern void DescribeContents(char *name1, int file1, char *name2, int file2);
extern int Iterate(void);
extern int VerifyMatching(void);
extern void PrintAutomorphisms(void);
@@ -46,6 +47,7 @@ extern int CreateCompareQueue(char *, int, char *, int);
extern int GetCompareQueueTop(char **, int *, char **, int *);
extern int PeekCompareQueueTop(char **, int *, char **, int *);
extern void RemoveCompareQueue();
extern int FlattenUnmatched(struct nlist *, char *, int, int);
extern void PrintIllegalClasses();
extern void PrintIllegalNodeClasses();
@@ -54,6 +56,15 @@ extern void PrintIllegalElementClasses();
extern void DumpNetwork(struct objlist *ob, int cidx);
extern void DumpNetworkAll(char *name, int file);
extern void RegroupDataStructures();
extern void FormatIllegalElementClasses();
extern void FormatIllegalNodeClasses();
extern int ResolveAutomorphsByProperty();
extern int ResolveAutomorphsByPin();
extern void SummarizeElementClasses(struct ElementClass *EC);
extern int remove_group_tags(struct objlist *ob);
#ifdef TCL_NETGEN
extern int EquivalentNode();
extern int EquivalentElement();
+76 -64
View File
@@ -331,77 +331,87 @@ int GetNextLineNoNewline(char *delimiter)
linetok = (char *)MALLOC(linesize + 1);
}
/* Check for substitutions (verilog only). Make sure linetok is */
/* large enough to hold the entire line after substitutions. */
if (definitions != NULL) {
char *s, *w, e;
struct property *kl;
int len, dlen, vlen, addin = 0;
unsigned char found = FALSE;
for (s = line; *s != '\0'; s++) {
if (*s == '`') {
w = s + 1;
while (isalnum(*w) || (*w == '_') || (*w == '$')) w++;
e = *w;
*w = '\0';
kl = (struct property *)HashLookup(s + 1, definitions);
if (kl != NULL) {
dlen = strlen(s);
if (kl->type == PROP_STRING) {
vlen = strlen(kl->pdefault.string);
}
else vlen = 12; /* Leave room for numeric conversion */
addin += vlen - dlen + 1;
found = TRUE;
}
*w = e;
}
}
if (found) {
len = strlen(line);
if (len + addin > linesize) {
while (len + addin > linesize) linesize += 500;
FREE(linetok);
linetok = (char *)MALLOC(linesize);
}
}
}
/* Make definition substitutions (verilog only) */
if (definitions != NULL) {
if (definitions == NULL)
strcpy(linetok, line);
else {
char *s, *t, *w, e;
struct property *kl;
int len, dlen, vlen, addin = 0;
int oldlinesize = linesize;
unsigned char found = TRUE;
t = linetok;
for (s = line; *s != '\0'; s++) {
if (*s == '`') {
w = s + 1;
while (isalnum(*w) || (*w == '_') || (*w == '$')) w++;
e = *w;
*w = '\0';
kl = (struct property *)HashLookup(s + 1, definitions);
if (kl != NULL) {
if (kl->type == PROP_STRING)
strcpy(t, kl->pdefault.string);
else if (kl->type == PROP_INTEGER)
sprintf(t, "%d", kl->pdefault.ival);
else if (kl->type == PROP_DOUBLE)
sprintf(t, "%g", kl->pdefault.dval);
t += strlen(t);
s = w - 1;
/* Check for substitutions (verilog only). Make sure linetok is */
/* large enough to hold the entire line after substitutions. */
while (found) { /* Do this recursively, for nested definitions */
found = FALSE;
for (s = line; *s != '\0'; s++) {
if (*s == '`') {
w = s + 1;
while (isalnum(*w) || (*w == '_') || (*w == '$')) w++;
e = *w;
*w = '\0';
kl = (struct property *)HashLookup(s + 1, definitions);
if (kl != NULL) {
dlen = strlen(s);
if (kl->type == PROP_STRING) {
vlen = strlen(kl->pdefault.string);
}
else vlen = 12; /* Leave room for numeric conversion */
addin += vlen - dlen + 1;
found = TRUE;
}
*w = e;
}
}
if (found) {
len = strlen(line);
if (len + addin > linesize) {
while (len + addin > linesize) linesize += 500;
FREE(linetok);
linetok = (char *)MALLOC(linesize);
}
}
/* Make definition substitutions (verilog only) */
t = linetok;
for (s = line; *s != '\0'; s++) {
if (*s == '`') {
w = s + 1;
while (isalnum(*w) || (*w == '_') || (*w == '$')) w++;
e = *w;
*w = '\0';
kl = (struct property *)HashLookup(s + 1, definitions);
if (kl != NULL) {
if (kl->type == PROP_STRING)
strcpy(t, kl->pdefault.string);
else if (kl->type == PROP_INTEGER)
sprintf(t, "%d", kl->pdefault.ival);
else if (kl->type == PROP_DOUBLE)
sprintf(t, "%g", kl->pdefault.dval);
t += strlen(t);
s = w - 1;
}
else *t++ = *s;
*w = e;
}
else *t++ = *s;
*w = e;
}
*t = '\0';
/* Copy substituted linetok back to line and repeat until */
/* there are no more substitutions to be made. */
if (oldlinesize != linesize) {
FREE(line);
line = (char *)MALLOC(linesize + 501);
oldlinesize = linesize;
}
else *t++ = *s;
strcpy(line, linetok);
}
*t = '\0';
}
else
strcpy(linetok, line);
TrimQuoted(linetok);
linenum++;
@@ -896,7 +906,9 @@ char *ReadNetlist(char *fname, int *fnum)
/* make first pass looking for extension */
for (index = 0; formats[index].extension != NULL; index++) {
if (strstr(fname, formats[index].extension) != NULL) {
int extlen = strlen(formats[index].extension);
int flen = strlen(fname);
if (!strcmp(fname + flen - extlen, formats[index].extension)) {
return (*(formats[index].proc))(fname, fnum);
}
}
+29 -27
View File
@@ -1352,7 +1352,8 @@ void Node(char *name)
tp->name = strsave(name);
tp->type = NODE; /* internal node type */
tp->model.class = NULL;
tp->instance.flags = 0;
tp->instance.name = NULL;
tp->flags = 0;
tp->node = -1; /* null node */
tp->next = NULL;
AddToCurrentCell (tp);
@@ -3259,7 +3260,7 @@ int CombineParallel(char *model, int file)
if ((ob2->node >= 0) && (nodecount[ob2->node] == 1))
{
nob = (tp->nodename_cache)[ob2->node];
nob->instance.flags = NO_CONNECT;
nob->flags = NO_CONNECT;
strcat(pptr, "_nc");
}
else
@@ -3336,16 +3337,13 @@ int CombineParallel(char *model, int file)
/* "sob" to it. If "ob" does not have properties, then */
/* create a property record and set property "M" to 1. */
/* Find last non-property record of sob ( = pob) */
/* Find first property record of sob ( = spropfirst) */
/* Find last property record of sob ( = sproplast) */
/* Find last non-property record of sob ( = pob) */
/* Find first property record of sob ( = spropfirst) */
spropfirst = sproplast = NULL;
spropfirst = NULL;
for (ob2 = sob; ob2->type > FIRSTPIN || ob2 == sob; ob2 = ob2->next)
pob = ob2;
if (ob2->type == PROPERTY) spropfirst = ob2;
for (; ob2->type == PROPERTY; ob2 = ob2->next)
sproplast = ob2;
if (spropfirst == NULL) {
/* Create new property instance record if one doesn't exist */
@@ -3371,8 +3369,9 @@ int CombineParallel(char *model, int file)
nob->next = pob->next;
pob->next = nob;
/* Handle case of contiguous entries */
if (lob == pob) lob = nob;
spropfirst = sproplast = nob;
spropfirst = nob;
}
if (propfirst == NULL) {
/* Create new property instance record if one doesn't exist */
@@ -3395,27 +3394,26 @@ int CombineParallel(char *model, int file)
kv->type = PROP_ENDLIST;
kv->value.ival = 0;
/* Append to sob's property list */
nob->next = sproplast->next;
sproplast->next = nob;
if (lob == sproplast) lob = nob;
/* Prepend to sob's property list */
nob->next = pob->next;
pob->next = nob;
/* Handle case of contiguous entries */
if (lob == pob) lob = nob;
}
if (propfirst != NULL) {
else {
// Series/Parallel logic:
// If propfirst has _tag in properties,
// then add an "open" tag at propfirst
add_prop_tag(propfirst, '(');
// If spropfirst has _tag in properties,
// then add an "open" tag at spropfirst
add_prop_tag(spropfirst, '(');
// if spropfirst has _tag in properties then add an "open" tag
// to spropfirst and a "close" tag to propfirst
if (add_prop_tag(spropfirst, '(')) add_prop_tag(propfirst, ')');
// if propfirst has _tag in properties then add an "open" tag
// to propfirst and a "close" tag to spropfirst
if (add_prop_tag(propfirst, '(')) add_prop_tag(spropfirst, ')');
/* Append ob's property list to sob */
proplast->next = sproplast->next;
sproplast->next = propfirst;
if (lob == sproplast) lob = proplast;
/* Prepend ob's property list to sob */
proplast->next = pob->next;
pob->next = propfirst;
}
/* Link up around object to be removed */
@@ -3428,7 +3426,6 @@ int CombineParallel(char *model, int file)
obr = nob;
}
dcnt++;
}
FREE((char *)pstr);
}
@@ -3440,7 +3437,8 @@ int CombineParallel(char *model, int file)
}
HashKill(&devdict);
if (dcnt > 0) {
Fprintf(stdout, "Class %s: Merged %d devices.\n", model, dcnt);
Fprintf(stdout, "Class %s (%d): Merged %d parallel devices.\n",
model, file, dcnt);
}
FREE(nodecount);
return dcnt;
@@ -3737,6 +3735,10 @@ int CombineSeries(char *model, int file)
}
}
FREE(instlist);
if (scnt > 0) {
Fprintf(stdout, "Class %s (%d): Merged %d series devices.\n",
model, file, scnt);
}
return scnt;
}
+7 -8
View File
@@ -22,6 +22,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <ctype.h>
#include <limits.h>
#ifdef IBMPC
#include <alloc.h>
#endif
@@ -31,13 +32,13 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#endif
#include "netgen.h"
#include "hash.h"
#include "objlist.h"
#include "regexp.h"
#include "dbug.h"
#include "print.h"
#include "netfile.h"
#include "netcmp.h"
#include "hash.h"
#ifdef TCL_NETGEN
extern Tcl_Interp *netgeninterp;
@@ -288,7 +289,7 @@ static struct hashdict cell_dict;
void InitCellHashTable(void)
{
hashfunc = hash;
hashfunc = hashcase;
matchfunc = NULL;
matchintfunc = matchfile;
InitializeHashTable(&cell_dict, CELLHASHSIZE);
@@ -975,10 +976,8 @@ struct objlist *CopyObjList(struct objlist *oldlist, unsigned char doforall)
newob->model.class = NULL;
else
newob->model.class = strsave(tmp->model.class);
if (newob->type == NODE)
newob->instance.flags = tmp->instance.flags;
else
newob->instance.name = (tmp->instance.name) ?
newob->flags = tmp->flags;
newob->instance.name = (tmp->instance.name) ?
strsave(tmp->instance.name) : NULL;
}
newob->node = tmp->node;
@@ -1098,8 +1097,8 @@ void FreeObject(struct objlist *ob)
FREE(ob->instance.props);
}
}
else if (ob->type != NODE) {
/* All other records except NODE, which uses this for flags */
else {
/* All other records */
if (ob->instance.name != NULL) FreeString(ob->instance.name);
}
if (ob->model.class != NULL) FreeString(ob->model.class);
+14 -1
View File
@@ -162,9 +162,9 @@ struct objlist {
union {
char *name; /* unique name for the instance, or */
/* (string) value of property for properties */
int flags; /* Used by NODE type to flag isolated net */
struct valuelist *props; /* Property record */
} instance;
unsigned char flags; /* Used by NODE type to flag isolated net */
int node; /* the electrical node number of the port/node/pin */
struct objlist *next;
};
@@ -312,6 +312,19 @@ extern void GarbageCollect(void);
extern void InitGarbageCollection(void);
extern void AddToGarbageList(struct objlist *head);
extern void DeleteProperties(struct keyvalue **topptr);
extern void AddProperty(struct keyvalue **topptr, char *key, char *value);
extern void AddScaledProperty(struct keyvalue **topptr, char *key, char *value, double scale);
extern void DeleteProperties(struct keyvalue **topptr);
extern struct objlist *LinkProperties(char *model, struct keyvalue *topptr);
extern void ClassDelete(char *class, int file);
extern void RemoveShorted(char *class, int file);
extern void CellRehash(char *name, char *newname, int file);
/* defined in netgen.c */
extern int ConvertStringToInteger(char *string, int *ival);
#ifdef HAVE_MALLINFO
void PrintMemoryStats(void);
#endif
+8 -5
View File
@@ -805,11 +805,14 @@ void DescribeInstance(char *name, int file)
/* All black-box modules and placeholders by definition have all */
/* disconnected pins, so don't report those. */
if (!(tp->flags & CELL_PLACEHOLDER) && (tp->class != CLASS_MODULE))
{
if (disconnectednodes == 0) Fprintf(stderr, "\n");
if ((!(tp->flags & CELL_PLACEHOLDER)) && (tp->class != CLASS_MODULE)) {
// if (disconnectednodes == 0) Fprintf(stderr, "\n");
disconnectednodes++;
Fprintf(stderr, "Cell %s disconnected node: %s\n", tp->name, ob->name);
/* Don't report on ports marked "port_match_error", which is just confusing. */
if (strcmp(ob->name, "port_match_error")) {
Fprintf(stderr, "Cell %s (%d) disconnected node: %s\n",
tp->name, tp->file, ob->name);
}
}
}
}
@@ -1033,7 +1036,7 @@ void Query(void)
break;
case 'v':
promptstring("Write Verilog: circuit name: ", repstr);
VerilogModule(repstr, filenum, "");
VerilogTop(repstr, filenum, "");
break;
case 'E':
promptstring("Write ESACAP: circuit name: ", repstr);
+26 -10
View File
@@ -26,6 +26,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#endif
#include <stdlib.h> /* for calloc(), free(), getenv() */
#include <ctype.h> /* for toupper(), isascii() */
#ifndef IBMPC
#include <sys/types.h> /* for getpwnam() tilde expansion */
#include <pwd.h>
@@ -40,6 +41,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "objlist.h"
#include "netfile.h"
#include "print.h"
#include "query.h"
#include "objlist.h"
// Global storage for parameters from .PARAM
struct hashdict spiceparams;
@@ -937,7 +940,7 @@ skip_ends:
goto baddevice;
}
snprintf(instname, 255, "%s%s", model, inst);
snprintf(instname, 255, "%s:%s", model, inst);
Cell(instname, model, collector, base, emitter);
pobj = LinkProperties(model, kvlist);
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
@@ -1010,7 +1013,7 @@ skip_ends:
goto baddevice;
}
snprintf(instname, 255, "%s%s", model, inst);
snprintf(instname, 255, "%s:%s", model, inst);
Cell(instname, model, drain, gate, source, bulk);
pobj = LinkProperties(model, kvlist);
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
@@ -1101,7 +1104,7 @@ skip_ends:
usemodel = 1;
}
snprintf(instname, 255, "%s%s", model, inst);
snprintf(instname, 255, "%s:%s", model, inst);
if (usemodel)
Cell(instname, model, ctop, cbot);
else
@@ -1194,7 +1197,7 @@ skip_ends:
else
strcpy(model, "r"); /* Use default resistor model */
snprintf(instname, 255, "%s%s", model, inst);
snprintf(instname, 255, "%s:%s", model, inst);
if (usemodel)
Cell(instname, model, rtop, rbot);
else
@@ -1252,7 +1255,7 @@ skip_ends:
Fprintf(stderr, "Device \"%s\" has wrong number of ports for a diode.\n");
goto baddevice;
}
snprintf(instname, 255, "%s%s", model, inst);
snprintf(instname, 255, "%s:%s", model, inst);
Cell(instname, model, anode, cathode);
pobj = LinkProperties(model, kvlist);
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
@@ -1331,7 +1334,7 @@ skip_ends:
else
strcpy(model, "t"); /* Use default xline model */
snprintf(instname, 255, "%s%s", model, inst);
snprintf(instname, 255, "%s:%s", model, inst);
if (usemodel)
Cell(instname, model, node1, node2, node3, node4);
@@ -1414,7 +1417,7 @@ skip_ends:
else
strcpy(model, "l"); /* Use default inductor model */
snprintf(instname, 255, "%s%s", model, inst);
snprintf(instname, 255, "%s:%s", model, inst);
if (usemodel)
Cell(instname, model, end_a, end_b);
else
@@ -1446,7 +1449,20 @@ skip_ends:
if (LookupObject(pos, CurrentCell) == NULL) Node(pos);
if (LookupObject(neg, CurrentCell) == NULL) Node(neg);
/* Any device properties? */
/* Get voltage value (if present); save as property "value" */
if (nexttok != NULL) {
if (matchnocase(nexttok, "DC")) {
SpiceTokNoNewline();
}
}
if (nexttok != NULL) {
if (StringIsValueOrExpression(nexttok)) {
AddProperty(&kvlist, "value", nexttok);
}
}
/* Any other device properties? */
while (nexttok != NULL)
{
SpiceTokNoNewline();
@@ -1474,7 +1490,7 @@ skip_ends:
else if (CountPorts(model, filenum) != 2) {
/* Modeled device: Make sure it has the right number of ports */
Fprintf(stderr, "Device \"%s\" has wrong number of ports for a "
"voltage source.\n");
"voltage source.\n", inst);
goto baddevice;
}
Cell(instname, model, pos, neg);
@@ -1726,7 +1742,7 @@ skip_ends:
/* names. */
if (strncmp(instancename, scan->name, strlen(scan->name))) {
snprintf(subcktname, 99, "%s%s", scan->name, instancename);
snprintf(subcktname, 99, "%s:%s", scan->name, instancename);
strcpy(instancename, subcktname);
}
else {
+8
View File
@@ -0,0 +1,8 @@
#ifndef _TECH_H
#define _TECH_H
extern int ActelLibPresent(void);
extern void ActelLib(void);
extern void VerilogTop(char *name, int fnum, char *filename);
#endif /* _TECH_H */
+313 -172
View File
@@ -52,14 +52,15 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#endif
#include "netgen.h"
#include "hash.h"
#include "objlist.h"
#include "netfile.h"
#include "print.h"
#include "hash.h"
// See netfile.c for explanation of delimiters. 'X'
// separates single-character delimiters from two-character delimiters.
#define VLOG_DELIMITERS "X///**/#((**)X,;:(){}[]="
#define VLOG_EQUATION_DELIMITERS "X///**/#((**)X,;:(){}[]=+-*/"
#define VLOG_PIN_NAME_DELIMITERS "X///**/(**)X()"
#define VLOG_PIN_CHECK_DELIMITERS "X///**/(**)X,;(){}"
@@ -71,6 +72,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
struct hashdict verilogparams;
// Global storage for verilog definitions
struct hashdict verilogdefs;
// Record file pointer that is associated with the hash tables
int hashfile = -1;
// Global storage for wire buses
struct hashdict buses;
@@ -127,6 +130,187 @@ char *strvchr(char *string, char c)
return NULL;
}
/* Linked list, much like tokstack in netgen.c, but much simpler. */
/* contents are either a value, if oper = 0, or an operator. */
struct expr_stack {
int value;
char oper;
struct expr_stack *next;
struct expr_stack *last;
};
//-------------------------------------------------------------------------
// Evaluate an expression for an array bound. This is much like
// ReduceOneExpression() in netgen.c, but only handles basic integer
// arithmetic (+,-,*,/) and grouping by parentheses.
//
// Returns 1 if successful, 0 on error.
// Evaluated result is placed in the integer pointed to by "valptr".
//-------------------------------------------------------------------------
int EvalExpr(struct expr_stack **stackptr, int *valptr)
{
struct expr_stack *texp, *start, *tmp, *stack;
int modified, value;
stack = *stackptr;
/* Most expressions are going to be just one number, so treat
* that as a special case.
*/
if ((stack->oper == '\0') && (stack->last == NULL)) {
*valptr = stack->value;
FREE(stack);
*stackptr = NULL;
return 1;
}
/* Move to the end of the stack, which is the beginning of the
* expression.
*/
for (start = stack; start->last; start = start->last);
/* Run passes until no more modifications can be made */
modified = TRUE;
while (modified == TRUE) {
modified = FALSE;
/* Find any + or - that is used as a sign of a value */
for (texp = start; texp; texp = texp->next) {
if ((texp->oper == '+') || (texp->oper == '-') || (texp->oper == '*') ||
(texp->oper == '/') || (texp->oper == '(')) {
if ((texp->next != NULL) && (texp->next->next != NULL) &&
(texp->next->next->oper == '\0')) {
if (texp->next->oper == '+') {
/* Remove the unnecessary sign */
tmp = texp->next;
texp->next = tmp->next;
tmp->next->last = texp;
FREE(tmp);
modified = TRUE;
}
else if (texp->next->oper == '-') {
/* Remove the sign and negate the value */
tmp = texp->next;
texp->next->next->value = -texp->next->next->value;
texp->next = tmp->next;
tmp->next->last = texp;
FREE(tmp);
modified = TRUE;
}
}
}
}
/* Reduce (a * b) and (a / b) */
for (texp = start; texp; texp = texp->next) {
if ((texp->last != NULL) && (texp->next != NULL) && (texp->oper != '\0')) {
if ((texp->last->oper == '\0') && (texp->next->oper == '\0')) {
if (texp->oper == '*') {
/* Multiply */
texp->last->value *= texp->next->value;
/* Remove two items from the stack */
tmp = texp;
texp = texp->last;
texp->next = tmp->next->next;
if (tmp->next->next) tmp->next->next->last = texp;
FREE(tmp->next);
FREE(tmp);
modified = TRUE;
}
if (texp->oper == '/') {
/* Divide */
texp->last->value /= texp->next->value;
/* Remove two items from the stack */
tmp = texp;
texp = texp->last;
texp->next = tmp->next->next;
if (tmp->next->next) tmp->next->next->last = texp;
FREE(tmp->next);
FREE(tmp);
modified = TRUE;
}
}
}
}
/* Reduce (a + b) and (a - b) */
for (texp = start; texp; texp = texp->next) {
if ((texp->last != NULL) && (texp->next != NULL) && (texp->oper != '\0')) {
if ((texp->last->oper == '\0') && (texp->next->oper == '\0')) {
if (texp->oper == '-') {
/* Subtract */
texp->last->value -= texp->next->value;
/* Remove two items from the stack */
tmp = texp;
texp = texp->last;
texp->next = tmp->next->next;
if (tmp->next->next) tmp->next->next->last = texp;
FREE(tmp->next);
FREE(tmp);
modified = TRUE;
}
if (texp->oper == '+') {
/* Add */
texp->last->value += texp->next->value;
/* Remove two items from the stack */
tmp = texp;
texp = texp->last;
texp->next = tmp->next->next;
if (tmp->next->next) tmp->next->next->last = texp;
FREE(tmp->next);
FREE(tmp);
modified = TRUE;
}
}
}
}
/* Reduce (a) */
for (texp = start; texp; texp = texp->next) {
if ((texp->last != NULL) && (texp->next != NULL) && (texp->oper == '\0')) {
if ((texp->last->oper == '(') && (texp->next->oper == ')')) {
tmp = texp->last;
texp->last->oper = '\0';
texp->last->value = texp->value;
texp->last->next = texp->next->next;
if (texp->next->next) texp->next->next->last = texp->last;
FREE(texp->next);
FREE(texp);
texp = tmp;
modified = TRUE;
}
}
}
}
/* If only one numerical item remains, then place it in valptr and return 1 */
texp = start;
if ((texp->oper == '\0') && (texp->next == NULL)) {
*valptr = texp->value;
FREE(texp);
*stackptr = NULL;
return 1;
}
/* Clean up the stack before returning error status */
while (texp) {
tmp = texp;
texp = texp->next;
FREE(tmp);
}
*stackptr = NULL;
return 0;
}
//-------------------------------------------------------------------------
// Get bus indexes from the notation name[a:b]. If there is only "name"
// then look up the name in the bus hash list and return the index bounds.
@@ -138,147 +322,123 @@ char *strvchr(char *string, char c)
int GetBusTok(struct bus *wb)
{
int result, start, end;
int result, start, end, value;
char oper;
struct property *kl = NULL;
struct expr_stack *stack, *newexp;
if (wb == NULL) return 0;
else {
wb->start = -1;
wb->end = -1;
}
wb->start = -1;
wb->end = -1;
stack = NULL;
/* Parse a value for array bounds [a : b], including possible use */
/* of parameters, definitions, and basic arithmetic. */
if (match(nexttok, "[")) {
SkipTokComments(VLOG_DELIMITERS);
result = sscanf(nexttok, "%d", &start);
if (result != 1) {
char *aptr = NULL;
char addin;
// Check for "+/-(n)" at end of a parameter name
aptr = strrchr(nexttok, '+');
if (aptr == NULL) aptr = strrchr(nexttok, '-');
if (aptr != NULL) {
addin = *aptr;
*aptr = '\0';
}
// Is name in the parameter list?
kl = (struct property *)HashLookup(nexttok, &verilogparams);
if (kl == NULL) {
Printf("Array value %s is not a number or a parameter.\n",
nexttok);
return 1;
}
else {
if (kl->type == PROP_STRING) {
result = sscanf(kl->pdefault.string, "%d", &start);
if (result != 1) {
Printf("Parameter %s has value %s that cannot be parsed"
" as an integer.\n", nexttok, kl->pdefault.string);
return 1;
}
}
else if (kl->type == PROP_INTEGER) {
start = kl->pdefault.ival;
}
else if (kl->type == PROP_DOUBLE) {
start = (int)kl->pdefault.dval;
if ((double)start != kl->pdefault.dval) {
Printf("Parameter %s has value %g that cannot be parsed"
" as an integer.\n", nexttok, kl->pdefault.dval);
return 1;
}
}
else {
Printf("Parameter %s has unknown type; don't know how"
" to parse.\n", nexttok);
start = end = -1;
oper = '\0';
while (nexttok) {
SkipTokComments(VLOG_EQUATION_DELIMITERS);
if (match(nexttok, "]")) {
result = 1;
if (stack == NULL) {
Printf("Empty array found.\n");
return 1;
}
}
if (aptr != NULL) {
int addval;
*aptr = addin;
if (sscanf(aptr + 1, "%d", &addval) != 1) {
Printf("Unable to parse parameter increment '%s'\n", aptr);
if (EvalExpr(&stack, &end) != 1) {
Printf("Bad expression found in array.\n");
return 1;
}
start += (addin == '+') ? addval : -addval;
if (start == -1) start = end; // Single bit
break;
}
}
SkipTokComments(VLOG_DELIMITERS);
if (match(nexttok, "]")) {
result = 1;
end = start; // Single bit
}
else if (!match(nexttok, ":")) {
Printf("Badly formed array notation: Expected colon, found %s\n", nexttok);
return 1;
}
else {
SkipTokComments(VLOG_DELIMITERS);
result = sscanf(nexttok, "%d", &end);
if (result != 1) {
char *aptr = NULL;
char addin;
// Check for "+/-(n)" at end of a parameter name
aptr = strrchr(nexttok, '+');
if (aptr == NULL) aptr = strrchr(nexttok, '-');
if (aptr != NULL) {
addin = *aptr;
*aptr = '\0';
if (match(nexttok, ":")) {
if (stack == NULL) {
Printf("Empty array start found.\n");
return 1;
}
if (EvalExpr(&stack, &start) != 1) {
Printf("Bad expression found in array.\n");
return 1;
}
continue;
}
else if (match(nexttok, "+") || match(nexttok, "-")
|| match(nexttok, "*") || match(nexttok, "/")
|| match(nexttok, "(") || match(nexttok, ")")) {
newexp = (struct expr_stack *)MALLOC(sizeof(struct expr_stack));
newexp->oper = *nexttok;
newexp->value = 0;
newexp->next = NULL;
newexp->last = stack;
if (stack) stack->next = newexp;
stack = newexp;
continue;
}
if ((result = sscanf(nexttok, "%d", &value)) != 1) {
// Is name in the parameter list?
kl = (struct property *)HashLookup(nexttok, &verilogparams);
kl = (struct property *)HashLookup(nexttok, &verilogparams);
if (kl == NULL) {
Printf("Array value %s is not a number or a parameter.\n",
nexttok);
return 1;
nexttok);
value = 0;
break;
}
else {
if (kl->type == PROP_STRING) {
result = sscanf(kl->pdefault.string, "%d", &end);
result = sscanf(kl->pdefault.string, "%d", &value);
if (result != 1) {
Printf("Parameter %s has value %s that cannot be parsed"
" as an integer.\n", nexttok,
kl->pdefault.string);
return 1;
" as an integer.\n",
nexttok, kl->pdefault.string);
value = 0;
break;
}
}
else if (kl->type == PROP_INTEGER) {
end = kl->pdefault.ival;
value = kl->pdefault.ival;
}
else if (kl->type == PROP_DOUBLE) {
end = (int)kl->pdefault.dval;
if ((double)end != kl->pdefault.dval) {
Printf("Cannot parse second digit from parameter "
"%s value %g\n", nexttok, kl->pdefault.dval);
return 1;
value = (int)kl->pdefault.dval;
if ((double)value != kl->pdefault.dval) {
Printf("Parameter %s has value %g that cannot be parsed"
" as an integer.\n",
nexttok, kl->pdefault.dval);
value = 0;
break;
}
}
else {
Printf("Parameter %s has unknown type; don't know how"
" to parse.\n", nexttok);
return 1;
Printf("Parameter %s has unknown type; don't know how"
" to parse.\n", nexttok);
value = 0;
break;
}
}
if (aptr != NULL) {
int addval;
*aptr = addin;
if (sscanf(aptr + 1, "%d", &addval) != 1) {
Printf("Unable to parse parameter increment '%s'\n", aptr);
return 1;
}
end += (addin == '+') ? addval : -addval;
}
}
newexp = (struct expr_stack *)MALLOC(sizeof(struct expr_stack));
newexp->oper = '\0';
newexp->value = value;
newexp->next = NULL;
newexp->last = stack;
if (stack) stack->next = newexp;
stack = newexp;
}
wb->start = start;
wb->end = end;
/* In case of error, stack may need cleaning up */
while (stack != NULL) {
newexp = stack;
stack = stack->last;
FREE(newexp);
}
while (!match(nexttok, "]")) {
SkipTokComments(VLOG_DELIMITERS);
if (nexttok == NULL) {
@@ -1128,13 +1288,6 @@ skip_endmodule:
kl->pdefault.ival = 1;
kl->slop.ival = 0;
}
else if (nexttok[0] == '(') {
/* For now, the netgen verilog parser doesn't handle `define f(X) ... */
SkipNewLine(VLOG_DELIMITERS);
FREE(kl->key);
FREE(kl);
kl = NULL;
}
else if (ConvertStringToInteger(nexttok, &ival) == 1) {
/* Parameter parses as an integer */
kl->type = PROP_INTEGER;
@@ -1319,6 +1472,8 @@ skip_endmodule:
rhs = LookupObject(assignname, CurrentCell);
*aptr = '[';
}
else
strcpy(assignroot, nexttok);
}
else {
j = -1;
@@ -1514,7 +1669,7 @@ nextinst:
// Read the pin list
while (nexttok != NULL) {
SkipTokComments(VLOG_DELIMITERS);
SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
if (match(nexttok, ")")) break;
else if (match(nexttok, ",")) continue;
@@ -1577,6 +1732,14 @@ nextinst:
}
new_port->net = wire_bundle;
}
else if (nexttok[0] == '~' || nexttok[0] == '!' || nexttok[0] == '-') {
/* All of these imply that the signal is logically manipulated */
/* in turn implying behavioral code. */
Printf("Module '%s' is not structural verilog, "
"making black-box.\n", model);
SetClass(CLASS_MODULE);
goto skip_endmodule;
}
else
new_port->net = strsave(nexttok);
@@ -1770,54 +1933,6 @@ nextinst:
scan->width = width;
result = GetBus(scan->net, &wb);
if (result == -1) {
/* CHECK: THIS CODE SHOULD BE DELETED, IT IS NOT THE ISSUE */
/* Not bus notation, but check if signal was defined as a bus */
wb.start = wb.end = -1;
minnet = maxnet = -1;
/* Pins should be in index order start->end. Other nodes */
/* should be in order start->end by node number. */
for (bobj = CurrentCell->cell; bobj; bobj = bobj->next) {
if (bobj->type == PORT) {
if ((bptr = strvchr(bobj->name, '[')) != NULL) {
*bptr = '\0';
if (!strcmp(bobj->name, scan->net)) {
*bptr = '[';
if (wb.start == -1)
sscanf(bptr + 1, "%d", &wb.start);
else
sscanf(bptr + 1, "%d", &wb.end);
}
}
}
else if (bobj->type == NODE) {
if ((bptr = strvchr(bobj->name, '[')) != NULL) {
*bptr = '\0';
if (!strcmp(bobj->name, scan->net)) {
if (sscanf(bptr + 1, "%d", &testidx) == 1) {
if (minnet == -1) {
minnet = maxnet = bobj->node;
wb.start = wb.end = testidx;
}
else if (bobj->node < minnet) {
minnet = bobj->node;
wb.start = testidx;
}
else if (bobj->node > maxnet) {
maxnet = bobj->node;
wb.end = testidx;
}
}
}
*bptr = '[';
}
}
}
if (wb.start != -1) result = 0;
}
if (result == 0) {
int match = 0;
int wblen, arraylen;
@@ -1927,7 +2042,25 @@ nextinst:
}
}
else if (portstart != portend) {
Fprintf(stderr, "Error: Single net %s is connected to bus port %s\n",
/* If the name starts with "_noconnect_", then it was an
* auto-generated name that incorrectly assumed a single-bit
* wide signal because it did not have a module prototype.
* Rewrite the noconnect name as an array. This just means
* that the verilog had an empty list "()" and the initial
* assumption was wrong. If not all instances agree on the
* size, then this will eventually generate an error.
*/
if (!strncmp(scan->net, "_noconnect_", 11) &&
(strchr(scan->net, '\[') == NULL) && (width > 1)) {
char *savenet = scan->net;
char *newnet = MALLOC(strlen(scan->net) + 12);
sprintf(newnet, "%s[%d:0]", scan->net, scan->width - 1);
FREE(savenet);
scan->net = newnet;
continue; /* Re-process this entry */
}
else
Fprintf(stderr, "Error: Single net %s is connected to bus port %s\n",
scan->net, scan->name);
}
}
@@ -2099,6 +2232,7 @@ nextinst:
Node(scan->net);
join(scan->net, nobj->name);
scan->flags |= PORT_FOUND;
obptr = nobj;
/* Now any previous instance of the same cell must */
/* insert the same additional pin as a no-connect. */
@@ -2109,7 +2243,7 @@ nextinst:
sobj = sobj->next) {
if (sobj->type == FIRSTPIN) {
if (match(sobj->model.class, obptr->model.class)) {
while (sobj->next->type > FIRSTPIN)
while (sobj->next && (sobj->next->type > FIRSTPIN))
sobj = sobj->next;
/* Stop when reaching the current instance */
if (sobj->type == obptr->type + 1) break;
@@ -2231,11 +2365,22 @@ char *ReadVerilogTop(char *fname, int *fnum, int blackbox)
else {
matchfunc = match;
matchintfunc = matchfile;
hashfunc = hash;
hashfunc = hashcase;
}
InitializeHashTable(&verilogparams, OBJHASHSIZE);
InitializeHashTable(&verilogdefs, OBJHASHSIZE);
if ((hashfile != -1) && (hashfile != *fnum)) {
/* Started a new file, so remove all the parameters and definitions */
RecurseHashTable(&verilogparams, freeprop);
HashKill(&verilogparams);
RecurseHashTable(&verilogdefs, freeprop);
HashKill(&verilogdefs);
hashfile = -1;
}
if (hashfile == -1) {
InitializeHashTable(&verilogparams, OBJHASHSIZE);
InitializeHashTable(&verilogdefs, OBJHASHSIZE);
hashfile = *fnum;
}
definitions = &verilogdefs;
/* Add the pre-defined key "LVS" to verilogdefs */
@@ -2255,10 +2400,6 @@ char *ReadVerilogTop(char *fname, int *fnum, int blackbox)
// Cleanup
while (CellStack != NULL) PopStack(&CellStack);
RecurseHashTable(&verilogparams, freeprop);
HashKill(&verilogparams);
RecurseHashTable(&verilogdefs, freeprop);
HashKill(&verilogdefs);
definitions = (struct hashdict *)NULL;
// Record the top level file.
+7 -9
View File
@@ -23,6 +23,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
#include <time.h>
#ifdef IBMPC
#include <stdlib.h> /* for strtol on PC */
@@ -33,6 +34,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "netfile.h"
#include "hash.h"
#include "print.h"
#include "xilinx.h"
#include "flatten.h"
#define XILINXHASHSIZE 99
static long xilinxhashbase = 0xA00;
@@ -132,10 +135,8 @@ char *xilinx_class(model)
}
return(model);
}
void
Xilinx(cellname, filename)
char *cellname;
char *filename;
void Xilinx(char *cellname, char *filename)
{
char Path[500];
char FileName[500];
@@ -163,8 +164,7 @@ Xilinx(cellname, filename)
CloseFile(FileName);
}
xilinxCell(cell)
char *cell;
int xilinxCell(char *cell)
{
struct nlist *nl;
struct objlist *ob;
@@ -252,9 +252,7 @@ struct objlist *xilinx_gate(ob,nl)
return(nob);
}
xilinx_sym(nl,gob)
struct nlist *nl;
struct objlist *gob;
void xilinx_sym(struct nlist *nl, struct objlist *gob)
{
struct objlist *ob;
char *cp,*rindex();
+10
View File
@@ -0,0 +1,10 @@
#ifndef _XILINX_H
#define _XILINX_H
extern void xilinx_sym(struct nlist *nl, struct objlist *gob);
extern void Xilinx(char *cellname, char *filename);
extern int xilinxCell(char *cell);
extern int XilinxLibPresent(void);
extern void XilinxLib(void);
#endif /* _XILINX_H */
+1
View File
@@ -29,6 +29,7 @@ lvs_manager.py: lvs_manager.py.in
$(DESTDIR)${INSTALL_PYDIR}/lvs_manager.py: lvs_manager.py
${RM} $@
${CP} lvs_manager.py $@
chmod a+x $@
$(DESTDIR)${INSTALL_PYDIR}/treeviewsplit.py: treeviewsplit.py
${RM} $@
+19 -15
View File
@@ -532,7 +532,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
}
set properr {}
set matcherr {}
set pinsgood 0
set pinsgood -1
while {$endval != {}} {
if {$dolist == 1} {
netgen::run -list converge
@@ -562,12 +562,13 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
if {[netgen::print queue] != {}} {
if {([lsearch $noflat [lindex $endval 0]] == -1) &&
([lsearch $noflat [lindex $endval 1]] == -1)} {
netgen::log put " Flattening non-matched subcircuits $endval"
netgen::log put " Flattening non-matched subcircuits $endval\n"
netgen::flatten class "[lindex $endval 0] $fnum1"
netgen::flatten class "[lindex $endval 1] $fnum2"
} else {
netgen::log put " Continuing with black-boxed subcircuits $endval"
lappend matcherr [lindex $endval 0]
netgen::log put " Continuing with black-boxed subcircuits $endval\n"
lappend matcherr [lindex $endval 0]"($fnum1)"
lappend matcherr [lindex $endval 1]"($fnum2)"
# Match pins
netgen::log echo off
if {$dolist == 1} {
@@ -586,7 +587,6 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
}
}
} else {
# Match pins
netgen::log echo off
if {$dolist == 1} {
set result [equate -list pins "$fnum1 [lindex $endval 0]" \
@@ -599,23 +599,26 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
equate classes "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"
}
set pinsgood $result
# If $uresult == -1 then these are black-box entries and
# $pinsgood should not be set to the resulting value.
if {$uresult > 0} {
set pinsgood $result
}
netgen::log echo on
}
if {$uresult == 2} {lappend properr [lindex $endval 0]}
} else {
# Flatten the non-matching subcircuit (but not the top-level cells)
if {[netgen::print queue] != {}} {
if {([lsearch $noflat [lindex $endval 1]] == -1) &&
if {([lsearch $noflat [lindex $endval 0]] == -1) &&
([lsearch $noflat [lindex $endval 1]] == -1)} {
netgen::log put " Flattening non-matched subcircuits $endval"
netgen::log put " Flattening non-matched subcircuits $endval\n"
netgen::flatten class "[lindex $endval 0] $fnum1"
netgen::flatten class "[lindex $endval 1] $fnum2"
} else {
netgen::log put " Continuing with black-boxed subcircuits $endval"
lappend matcherr [lindex $endval 0]
netgen::log put " Continuing with black-boxed subcircuits $endval"
lappend matcherr [lindex $endval 0]
netgen::log put " Continuing with black-boxed subcircuits $endval\n"
lappend matcherr [lindex $endval 0]"($fnum1)"
lappend matcherr [lindex $endval 0]"($fnum2)"
# Match pins
netgen::log echo off
if {$dolist == 1} {
@@ -647,15 +650,16 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
puts stdout "Result: " nonewline
netgen::log echo on
if {$pinsgood == 0} {
netgen::log put "The top level cell failed pin matching.\n"
# NOTE: Need to disambiguate these two cases. . .
netgen::log put "Cells failed matching, or top level cell failed pin matching.\n"
} else {
verify only
}
if {$properr != {}} {
netgen::log put "The following cells had property errors: $properr\n"
netgen::log put "The following cells had property errors:\n " [regsub -all { } $properr "\n "] "\n"
}
if {$matcherr != {}} {
netgen::log put "The following subcells failed to match: $matcherr\n"
netgen::log put "The following subcells failed to match:\n " [regsub -all { } $matcherr "\n "] "\n"
}
if {$dolog} {
netgen::log end
+44 -12
View File
@@ -32,6 +32,9 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "print.h"
#include "query.h" /* for ElementNodes() */
#include "hash.h"
#include "xilinx.h"
#include "tech.h"
#include "flatten.h"
#ifndef TRUE
#define TRUE 1
@@ -976,7 +979,7 @@ _netgen_writenet(ClientData clientData,
SpiceCell(repstr, filenum, "");
break;
case VERILOG_IDX:
VerilogModule(repstr, filenum, "");
VerilogTop(repstr, filenum, "");
break;
case WOMBAT_IDX:
Wombat(repstr,NULL);
@@ -2066,6 +2069,7 @@ _netcmp_format(ClientData clientData,
Tcl_WrongNumArgs(interp, 1, objv, "[col1_width [col2_width]]");
return TCL_ERROR;
}
return TCL_OK;
}
/*------------------------------------------------------*/
@@ -2091,8 +2095,9 @@ _netcmp_compare(ClientData clientData,
int dohierarchy = FALSE;
int assignonly = FALSE;
int argstart = 1, qresult, llen, result;
int hascontents1, hascontents2;
struct Correspond *nextcomp;
struct nlist *tp;
struct nlist *tp1 = NULL, *tp2 = NULL;
Tcl_Obj *flist = NULL;
if (objc > 1) {
@@ -2135,24 +2140,24 @@ _netcmp_compare(ClientData clientData,
}
else if ((objc - argstart) == 2) {
result = CommonParseCell(interp, objv[argstart], &tp, &fnum1);
result = CommonParseCell(interp, objv[argstart], &tp1, &fnum1);
if (result != TCL_OK) return TCL_ERROR;
else if (fnum1 == -1) {
Tcl_SetResult(interp, "Cannot use wildcard with compare command.\n",
NULL);
return TCL_ERROR;
}
name1 = tp->name;
name1 = tp1->name;
argstart++;
result = CommonParseCell(interp, objv[argstart], &tp, &fnum2);
result = CommonParseCell(interp, objv[argstart], &tp2, &fnum2);
if (result != TCL_OK) return TCL_ERROR;
else if (fnum2 == -1) {
Tcl_SetResult(interp, "Cannot use wildcard with compare command.\n",
NULL);
return TCL_ERROR;
}
name2 = tp->name;
name2 = tp2->name;
if (dohierarchy) {
RemoveCompareQueue();
@@ -2191,11 +2196,34 @@ _netcmp_compare(ClientData clientData,
ConvertGlobals(name2, fnum2);
}
CreateTwoLists(name1, fnum1, name2, fnum2, dolist);
while (PrematchLists(name1, fnum1, name2, fnum2) > 0) {
Fprintf(stdout, "Making another compare attempt.\n");
CreateTwoLists(name1, fnum1, name2, fnum2, dolist);
tp1 = LookupCellFile(name1, fnum1);
tp2 = LookupCellFile(name2, fnum2);
hascontents1 = HasContents(tp1);
hascontents2 = HasContents(tp2);
if (hascontents1 && !hascontents2 && (tp2->flags & CELL_PLACEHOLDER)) {
Fprintf(stdout, "Circuit 2 cell %s is a black box; will not flatten "
"Circuit 1\n", name2);
}
else if (hascontents2 && !hascontents1 && (tp1->flags & CELL_PLACEHOLDER)) {
Fprintf(stdout, "Circuit 1 cell %s is a black box; will not flatten "
"Circuit 2\n", name1);
}
else if (hascontents1 || hascontents2) {
FlattenUnmatched(tp1, name1, 1, 0);
FlattenUnmatched(tp2, name2, 1, 0);
DescribeContents(name1, fnum1, name2, fnum2);
while (PrematchLists(name1, fnum1, name2, fnum2) > 0) {
Fprintf(stdout, "Making another compare attempt.\n");
Printf("Flattened mismatched instances and attempting compare again.\n");
FlattenUnmatched(tp1, name1, 1, 0);
FlattenUnmatched(tp2, name2, 1, 0);
DescribeContents(name1, fnum1, name2, fnum2);
}
}
CreateTwoLists(name1, fnum1, name2, fnum2, dolist);
// Return the names of the two cells being compared, if doing "compare
// hierarchical". If "-list" was specified, then append the output
@@ -2428,6 +2456,8 @@ _netcmp_run(ClientData clientData,
else {
enable_interrupt();
while (!Iterate() && !InterruptPending);
ExhaustiveSubdivision = 1;
while (!Iterate() && !InterruptPending);
if (dolist) {
result = _netcmp_verify(clientData, interp, 2, objv - 1);
}
@@ -2446,6 +2476,8 @@ _netcmp_run(ClientData clientData,
else {
enable_interrupt();
while (!Iterate() && !InterruptPending);
ExhaustiveSubdivision = 1;
while (!Iterate() && !InterruptPending);
automorphisms = VerifyMatching();
if (automorphisms == -1)
Fprintf(stdout, "Netlists do not match.\n");
@@ -3023,11 +3055,11 @@ _netcmp_equate(ClientData clientData,
(tp2->flags & CELL_PLACEHOLDER)) {
if (tp1->flags & CELL_PLACEHOLDER) {
Fprintf(stdout, "Warning: Equate pins: cell %s "
"has no definition, treated as a black box.\n", name1);
"is a placeholder, treated as a black box.\n", name1);
}
if (tp2->flags & CELL_PLACEHOLDER) {
Fprintf(stdout, "Warning: Equate pins: cell %s "
"has no definition, treated as a black box.\n", name2);
"is a placeholder, treated as a black box.\n", name2);
}
// If a cell in either circuit is marked as a black box, then
// the cells in both circuits should be marked as a black box.