Compare commits

..
220 Commits
Author SHA1 Message Date
Tim Edwards bcbc736b51 Merge branch 'master' into netgen-1.5 2023-08-28 02:00:03 -04:00
Tim Edwards 615c55cbe2 Updated the config.guess and config.sub files; the newer ones
support, among other things, RISC-V.
2023-08-27 11:53:16 -04:00
Tim Edwards f5f1240073 Merge branch 'master' into netgen-1.5 2023-07-12 02:00:03 -04:00
Tim Edwards 87d8759a69 Corrected part of the MatchPins() routine so that the JSON output
tracks the output printed to stdout when matching pins.  One section
of this subroutine used the wrong pointers when writing to the Tcl
list (for eventual JSON output) which was the fundamental error.
Beyond that, the "debug" case (if used) would fail to run some of
the matching code, and the "no matching pin" case needed to be
handled for the Tcl list output.  Now the terminal output, terminal
debug output, and Tcl list output should all be in agreement on the
pin lists.
2023-07-11 15:40:00 -04:00
Tim Edwards 02d7a1bd01 Merge branch 'master' into netgen-1.5 2023-06-13 02:00:02 -04:00
Tim Edwards 1efa054ac1 Corrected an issue with shorted ports. When shorted ports are
connected only to ports and not to any devices, then they do not
show up in NodeClasses() and so pass through most of the checks
in MatchPins().  A separate correspondence check is needed to make
sure that the same shorted ports appear in both netlists.
2023-06-12 17:16:49 -04:00
Tim Edwards 7878b3cfbc Merge branch 'master' into netgen-1.5 2023-04-15 02:00:01 -04:00
Tim Edwards 609d1de250 Corrected a problem in the flattening routine, which was a missing
method for flattening a subcircuit with property M != 1.
2023-04-14 20:09:36 -04:00
Tim Edwards 7f727e6674 Merge branch 'master' into netgen-1.5 2023-04-14 02:00:01 -04:00
Tim Edwards 47c3b34612 Corrected the node merging around zero-volt voltage sources and
zero-ohm resistors so that if one of the nodes being merged is a
port, it is preferred over the other.
2023-04-13 15:41:12 -04:00
Tim Edwards d111fa0a3b Merge branch 'master' into netgen-1.5 2023-03-30 02:00:02 -04:00
Tim Edwards 66317c9848 Corrected an error in order-of-precedence of arithmetic operators,
ensuring that, e.g., in (a)*b+c, (a)*b gets evaluated before b+c.
2023-03-29 19:45:39 -04:00
Tim Edwards eeb3c0e5c6 Added support for simple forms of for() loops in generate blocks.
This is done by treating the loop variable as a temporary parameter
that is valid only inside the loop, and changing the parameter
value on each loop iteration.  The file stream position is used
to iterate the loop with calls to fseek() and ftell(), so that the
input tokenizer continues to work within loops.
2023-03-29 16:17:37 -04:00
Tim Edwards 490f9f7dbc Added a missing check for using a verilog macro definition as an
array delimeter for an instance array in verilog.
2023-03-29 09:54:45 -04:00
Tim Edwards 178b172c06 Merge branch 'master' into netgen-1.5 2023-03-08 02:00:03 -05:00
Tim Edwards 40cf82c2cb Slightly modified the fix from the last commit to allow an empty
string for the setup file to be the "trivial default" previously
used in case of the setup file not being found.  Put a newline
around the setup file messages so that they stand out from the
rest of the initial output information.
2023-03-07 09:00:39 -05:00
Tim Edwards 1ac2b592fb Changed what was a not-very-well thought out behavior: On being
passed an invalid setup file, the netgen "lvs" script uses a
trivial default setup and issues no error or warning.  Replaced
this behavior with an error message and a hard stop.
2023-03-07 08:53:06 -05:00
Tim Edwards 7870538ec9 Merge branch 'master' into netgen-1.5 2023-03-07 02:00:02 -05:00
Tim Edwards e12883037c Modified code from EquivalenceClasses() that forces the two cells
to have unique class hashes.  This has the problem that it prevents
comparing N-to-1 cells because declaring X->X1 as equivalent breaks
the original name equivalence of X->X.  The new implementation adds
the switch "-unique" to preserve the original behavior.  Otherwise,
the class hashes are made the same as the 2nd cell passed to the
command, and it is the responsibility of the person running LVS to
ensure that this is done in the correct direction.
2023-03-06 09:36:35 -05:00
Tim Edwards ee4e1e087f Merge branch 'master' into netgen-1.5 2023-03-05 02:00:01 -05:00
Tim Edwards 2d63fd63c1 Corrected the wrong order of arguments in an strncpy() command
that was introduced in a recent pull request, as pointed out by
Mitch Bailey in github issue #72.
2023-03-04 10:05:57 -05:00
Tim Edwards 7a8b5e835b Merge branch 'master' into netgen-1.5 2023-03-01 02:00:03 -05:00
Tim Edwards e557e61a02 Updated version and fixed a redundant include statement after
merging pull request #71 from Donn.
2023-02-28 09:04:45 -05:00
Donn 67da250615 Patches for Clang 2023-02-28 09:02:41 -05:00
Tim Edwards 77f7a773e3 Merge branch 'master' into netgen-1.5 2023-02-28 02:00:03 -05:00
Tim Edwards cd013621a7 Relaxed the prohibition on ((S != 1) && (M != 1)) in device
network parallel/series networks.  Instead, added a global option
with command "property tolerance strict|relaxed" to reinstate the
original (strict) behavior on demand, while relaxing it by default.
This allows certain series/parallel networks to match numerically
even though the schematic netlist may have combined individual
devices.
2023-02-27 15:26:18 -05:00
Tim Edwards 9a48a59f68 Merge branch 'master' into netgen-1.5 2023-02-25 02:00:03 -05:00
Tim Edwards 45712a04f1 Removed X11 definitions from the configuration when compiling
with Tcl, since Tk is launched independently through the console
script and nothing inside of netgen itself involves graphics.
This prevents netgenexec from linking to Tk and X11 libraries.
2023-02-24 10:42:59 -05:00
Tim Edwards 535b8285e9 Merge branch 'master' into netgen-1.5 2022-12-20 02:00:03 -05:00
Tim Edwards 28a2950439 Modified netgen output to not print information about combining
individual components in parallel and series as it reduces the
networks.  This information is available in total in the cell
summary.
2022-12-19 14:37:11 -05:00
Tim Edwards 1e1d506697 Merge branch 'master' into netgen-1.5 2022-12-16 02:00:03 -05:00
Tim Edwards 013fff9f37 (1) Fixed the series sorting, which needed to be modified to match
the parallel sorting routine.  This fixes occasional property
errors with series-connected devices such as resistors.  (2) Added
a method to associate properties with specific pins when pins are
permutable.  This allows netgen to properly check a value like
source/drain area when the definition of source and drain has
changed due to permutation of the device.  (3) Added a "property"
command extension "associate" to associate a property with a pin,
for use with the method described in (2).
2022-12-15 21:34:56 -05:00
Tim Edwards 4edaf0813d Merge branch 'master' into netgen-1.5 2022-11-17 02:00:01 -05:00
Tim Edwards 2292ab813b Corrected a badly implemented routine that can cause very long
run-times on large projects where a lot of cells need to be
deleted.
2022-11-16 12:37:05 -05:00
Tim Edwards a4ae5ed989 Merge branch 'master' into netgen-1.5 2022-11-05 02:00:01 -04:00
Tim Edwards 7e8508db53 Additional correction to the property match subroutine to better
check instances with permutable pins when checking parallelized
instances with disconnected pins vs. mutually connected pins.
2022-11-04 20:40:37 -04:00
Tim Edwards c9f7b24e0f Found an error in property matching causing weird errors in the
LVS result.  The property matching was failing to match (M=1) to
(M!=1) if M was not registered as a property name (which it often
isn't).  This would allow devices with different numbers of
instances in parallel to be put in the same matching group,
which then could later identify as a mismatch if the instances
were checked in a different order.
2022-11-04 12:07:21 -04:00
Tim Edwards d850586a14 Merge branch 'master' into netgen-1.5 2022-11-03 02:00:03 -04:00
Tim Edwards 95605ebbd4 Prevented checks from automatically treating two empty cells as
black boxes.  The check was supposed to check that both empty
cells really are black box entries.
2022-11-02 09:48:39 -04:00
Tim Edwards 4b5b117100 Merge branch 'master' into netgen-1.5 2022-11-02 02:00:02 -04:00
Tim Edwards 98e6a4bd8f Implemented the change from pull request #65 from Mitch Bailey
(slightly altered to put the inexpensive flag checks before the
more expensive string match).
2022-11-01 13:21:35 -04:00
Tim Edwards c73d9ec4ff Updated version to go along with pull request #67 from Mitch
Bailey.
2022-11-01 11:44:36 -04:00
D. Mitch Bailey a5375177c5 parameterized string length and increased to 256
Rebasing over latest commit.
2022-11-01 11:43:43 -04:00
Tim Edwards 935e54abe6 Merge branch 'master' into netgen-1.5 2022-11-01 02:00:02 -04:00
Tim Edwards 27b095754e Fixed an error that prints bogus property mismatch errors when
netgen is supposed to be checking properties for symmetry sorting,
but not reporting anything.  This causes mysterious property
mismatch errors that don't actually exist to show up in the
output.
2022-10-31 17:32:15 -04:00
Tim Edwards 49ccf1949a Merge branch 'master' into netgen-1.5 2022-10-30 02:00:03 -04:00
Tim Edwards db457c562b Corrected a problem that is very similar to the last issue, which
is that when the "class ignore" command is used, then ports of a
parent cell need to be checked for being disconnected if they
connect only to ports of an ignored/deleted child cell.
2022-10-29 11:43:01 -04:00
Tim Edwards 9b84776374 Merge branch 'master' into netgen-1.5 2022-10-26 02:00:01 -04:00
Tim Edwards 06386bee1b Corrected an issue with "flatten": If a cell has disconnected ports,
then flattening instances of that cell can cause a port of the parent
cell connected to the disconnected port of the child cell to itself
become disconnected.  If the parent port is not changed to show the
disconnected state, then pin mismatch can occur if the netlist being
matched didn't have the same flattened subcell.  This condition is
now detected and handled correctly.
2022-10-25 20:14:44 -04:00
Tim Edwards 2af3f2a3f7 Merge branch 'master' into netgen-1.5 2022-10-25 02:00:01 -04:00
Tim Edwards 7cd8d82964 Fix for an error causing a segfault. This does not fix the
underlying issue (which needs to be investigated), but it does
prevent netgen from crashing when it encounters it (netgen will
generate an erro message instead).
2022-10-24 21:45:14 -04:00
Tim Edwards 738abbdad9 Merge branch 'master' into netgen-1.5 2022-10-01 02:00:01 -04:00
Tim Edwards 3aeea9d164 Re-applied the modifications of revisions 231 and 232, and updated
the version to revision 234.
2022-09-30 11:47:36 -04:00
Tim Edwards 12e1ff295f Revert "Part 2 of folding in Mitch Bailey's code. This part is a"
This reverts commit 4fa4d046c8.

Reverting back to before the major change to MatchPins(), which is
breaking existing LVS scripts.
2022-09-30 11:36:09 -04:00
Tim Edwards 8d7569e9a3 Merge branch 'master' into netgen-1.5 2022-09-24 02:00:02 -04:00
Tim Edwards 2f9e898ec6 Version updated along with the merge of pull request #62 from
Mitch Bailey.
2022-09-23 16:04:49 -04:00
D. Mitch Bailey 9663579dd0 Restore matching circuits if one is empty (but only if pins match). 2022-09-21 08:05:39 -07:00
Tim Edwards d9425163e1 Merge branch 'master' into netgen-1.5 2022-09-18 02:00:02 -04:00
Tim Edwards f02e2b1ee0 Handled backslash-escapes (convert "\" to "\\") when writing pins
to the JSON format file (since JSON does not allow single backslash
characters.  Previously nets had been handled correctly, but not
pins.  Resolves github issue tracker Issue #60 from Proppy.
2022-09-17 14:33:27 -04:00
Tim Edwards 9ba1dfe814 Merge branch 'master' into netgen-1.5 2022-09-17 02:00:02 -04:00
Tim Edwards cc5f6d929f Added a missing block of code from Mitch Bailey's version that
fails to handle a topology match with a pin mismatch situation.
2022-09-16 13:55:23 -04:00
Tim Edwards fadd0ae2fc Merge branch 'master' into netgen-1.5 2022-09-16 02:00:02 -04:00
Tim Edwards 4fa4d046c8 Part 2 of folding in Mitch Bailey's code. This part is a
significant overhaul of the MatchPins() code, and better handles
issues with pins disconnected from nets and removes cases in
which proxy pins are incorrectly generated.
2022-09-15 10:50:52 -04:00
Tim Edwards 153ce0e2b3 Merge branch 'master' into netgen-1.5 2022-09-14 02:00:02 -04:00
Tim Edwards 9297090dc1 Start of merging Mitch Bailey's code changes from github pull
request #59 ("Pin match").  Because the pull request has rather
sweeping modifications, I am doing this in two steps.  The change
that most breaks with existing comparison methods is in the
PinMatch() routine in netcmp.c, where the method of generating
proxy pins has been removed.  There are specific cases for which
the proxy pin method exists, although these were coping with
issues arising from extraction in magic which have been dealt
with to some extend.  Possibly the proxy pin method is no longer
needed.  So the PinMatch() changes will be done in a second
commit where it's easier to revert or modify the changes without
affecting the modifications from this commit.
2022-09-13 10:55:00 -04:00
Tim Edwards bfdacab28c Merge branch 'master' into netgen-1.5 2022-09-13 02:00:02 -04:00
Tim Edwards 79e193e0c9 Modified behavior for the "-noflatten" option on LVS: Added a
command option "flatten prohibit" (or "flatten deny") to prevent
a subcell from being flattened at any time during the compare
process.  Previously, the "-noflatten" option for the "lvs"
script had been used to prevent flattening during initial
pre-match, but if the circuit passed the prematch phase and
subcells were mismatched, they would be flattened regardless of
whether or not they were listed by the "-noflatten" option.  This
also codifies a way to prevent subcells from being flattened in
the setup file rather than in the "lvs" command line.  Also:
Found and fixed a bug that prevents the use of "-noflatten=" with
a cell name or list of cell names instead of a filename.
2022-09-12 11:26:21 -04:00
Tim Edwards 7e9bd9f2a0 Merge branch 'master' into netgen-1.5 2022-06-28 02:00:02 -04:00
Tim Edwards 2056b37c95 Yesterday's commit surfaced two errors in series; this fixes the
second one of them, which is a failure to change CurrentTail when
an extra (implicit) pin was added to the last component in the
current cell, resulting in the failure of Node() to add the new
no-connect node, which instead overwrites the pin just created.
2022-06-27 20:35:30 -04:00
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
Tim Edwards ca119edc0a Merge branch 'master' into netgen-1.5 2021-06-04 03:00:10 -04:00
Tim Edwards 0556abf3c1 Finally corrected the issue with pins being able to be swapped
without netgen noticing---this behavior got broken by an
exception for "black box" circuits, but failed to check if the
circuit really was marked as a "black box" or not.  Fixing that
revealed another issue with verilog implicit pins.  Both issues
have now been corrected.
2021-06-03 17:42:54 -04:00
Tim Edwards 84348d2fe1 Merge branch 'master' into netgen-1.5 2021-05-31 03:00:10 -04:00
Tim Edwards 3356dd784e Made a number of usability corrections to the python GUI for
netgen.  More work will be done later.  Also:  Removed the
derived file lvs_manager.py from the repository, and modified
the Makefile to remove it as part of "make clean".
2021-05-30 20:39:47 -04:00
46 changed files with 6754 additions and 3881 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.181
1.5.256
+1 -1
View File
@@ -131,7 +131,7 @@ if format = 1, use the actel .pin file format
struct nlist *tp;
struct objlist *ob, *ob2;
char *ptr;
char physicalpin[200];
char physicalpin[MAX_STR_LEN];
tp = LookupCell(name);
if (tp == NULL) return;
+2
View File
@@ -176,4 +176,6 @@ extern int open(char *path, int oflag, ...); /* HPUX has it in <sys/fcntl.h> */
#define FALSE 0
#endif
#define MAX_STR_LEN 256
#endif /* _CONFIG_H */
+3 -3
View File
@@ -629,7 +629,7 @@ struct embed *FlattenEmbeddingTree(struct embed *E)
int LenEmbed(char *prefix, struct nlist *np, struct embed *E, int flatten)
/* return the number of characters required to print element E */
{
char longstr[200];
char longstr[MAX_STR_LEN];
if (E == NULL) return(0);
if (E->left == NULL && E->right == NULL) {
@@ -668,7 +668,7 @@ void PrintEmb(FILE *outfile, char *prefix, struct nlist *np,
struct objlist *ob;
char *instancename;
struct nlist *np2;
char name[200];
char name[MAX_STR_LEN];
ob = InstanceNumber(np,E->instancenumber);
instancename = ob->instance.name;
@@ -706,7 +706,7 @@ void PrintEmbed(FILE *outfile, char *prefix, struct nlist *np,
struct objlist *ob;
char *instancename;
struct nlist *np2;
char name[200];
char name[MAX_STR_LEN];
ob = InstanceNumber(np,E->instancenumber);
instancename = ob->instance.name;
+27 -26
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)
{
@@ -166,7 +167,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
int filenum;
if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
char name[100];
char name[MAX_STR_LEN];
SetExtension(name, fname, EXT_EXTENSION);
if ((filenum = OpenParseFile(name, *fnum)) < 0) {
@@ -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);
@@ -207,7 +208,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
else if (match(nexttok, "style")) SkipNewLine(NULL);
else if (match(nexttok, "resistclasses")) SkipNewLine(NULL);
else if (match(nexttok, "node")) {
char name[200];
char name[MAX_STR_LEN];
/* No cell is generated until at least one valid "node" or "use" */
/* has been read in the file. */
@@ -222,8 +223,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
SkipNewLine(NULL);
}
else if (match(nexttok, "equiv")) {
char name[200];
char name2[200];
char name[MAX_STR_LEN];
char name2[MAX_STR_LEN];
SkipTok(NULL);
GetExtName(name, nexttok);
if (LookupObject(name,CurrentCell) == NULL) Node(name);
@@ -234,8 +235,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
SkipNewLine(NULL);
}
else if (match(nexttok, "device")) {
char dev_name[100], dev_class[100];
char gate[200], drain[200], source[200], subs[200];
char dev_name[MAX_STR_LEN], dev_class[MAX_STR_LEN];
char gate[MAX_STR_LEN], drain[MAX_STR_LEN], source[MAX_STR_LEN], subs[MAX_STR_LEN];
char inststr[64];
SkipTok(NULL);
strcpy(dev_class, nexttok);
@@ -305,8 +306,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
SkipNewLine(NULL);
}
else if (match(nexttok, "fet")) { /* old-style FET record */
char fet_class[100];
char gate[200], drain[200], source[200], subs[200];
char fet_class[MAX_STR_LEN];
char gate[MAX_STR_LEN], drain[MAX_STR_LEN], source[MAX_STR_LEN], subs[MAX_STR_LEN];
char inststr[64];
SkipTok(NULL);
strcpy(fet_class, nexttok);
@@ -364,7 +365,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
SkipNewLine(NULL);
}
else {
char ctop[200], cbot[200], cdummy[200];
char ctop[MAX_STR_LEN], cbot[MAX_STR_LEN], cdummy[MAX_STR_LEN];
SkipTok(NULL);
GetExtName(ctop, nexttok);
SkipTok(NULL);
@@ -374,8 +375,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
}
}
else if (match(nexttok, "use")) {
char name[200];
char instancename[200];
char name[MAX_STR_LEN];
char instancename[MAX_STR_LEN];
char *basename;
/* No cell is generated until at least one valid "node" or "use" */
@@ -389,7 +390,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
SkipTok(NULL);
GetExtName(name, nexttok);
if ((basename = strrchr(name,'/')) != NULL) {
char tmp[200];
char tmp[MAX_STR_LEN];
strcpy(tmp, basename+1);
strcpy(name, tmp);
}
@@ -404,8 +405,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
SkipNewLine(NULL);
}
else if (match(nexttok, "merge")) {
char name[200];
char name2[200];
char name[MAX_STR_LEN];
char name2[MAX_STR_LEN];
SkipTok(NULL);
GetExtName(name, nexttok);
SkipTok(NULL);
@@ -639,7 +640,7 @@ char *ReadSim(char *fname, int *fnum)
double simscale = 1.0;
if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
char name[100];
char name[MAX_STR_LEN];
SetExtension(name, fname, SIM_EXTENSION);
if (OpenParseFile(name, *fnum) < 0) {
@@ -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);
@@ -669,7 +670,7 @@ char *ReadSim(char *fname, int *fnum)
SkipNewLine(NULL);
}
else if (match(nexttok, "n")) {
char gate[200], drain[200], source[200];
char gate[MAX_STR_LEN], drain[MAX_STR_LEN], source[MAX_STR_LEN];
char inststr[25], *instptr = NULL;
SkipTok(NULL);
@@ -713,7 +714,7 @@ char *ReadSim(char *fname, int *fnum)
LinkProperties("n", kvlist);
}
else if (match(nexttok, "p")) {
char gate[200], drain[200], source[200];
char gate[MAX_STR_LEN], drain[MAX_STR_LEN], source[MAX_STR_LEN];
char inststr[25], *instptr = NULL;
SkipTok(NULL);
GetExtName(gate, nexttok);
@@ -753,7 +754,7 @@ char *ReadSim(char *fname, int *fnum)
LinkProperties("p", kvlist);
}
else if (match(nexttok, "e")) { /* 3-port capacitors (poly/poly2) */
char gate[200], drain[200], source[200];
char gate[MAX_STR_LEN], drain[MAX_STR_LEN], source[MAX_STR_LEN];
char inststr[25], *instptr = NULL;
SkipTok(NULL);
GetExtName(gate, nexttok);
@@ -787,7 +788,7 @@ char *ReadSim(char *fname, int *fnum)
E(fname, instptr, gate, drain, source);
}
else if (match(nexttok, "b")) { /* bipolars added by Tim 7/16/96 */
char base[200], emitter[200], collector[200];
char base[MAX_STR_LEN], emitter[MAX_STR_LEN], collector[MAX_STR_LEN];
char inststr[25], *instptr = NULL;
SkipTok(NULL);
GetExtName(base, nexttok);
@@ -825,7 +826,7 @@ char *ReadSim(char *fname, int *fnum)
SkipNewLine(NULL);
}
else {
char ctop[200], cbot[200], cdummy[200];
char ctop[MAX_STR_LEN], cbot[MAX_STR_LEN], cdummy[MAX_STR_LEN];
SkipTok(NULL);
GetExtName(ctop, nexttok);
if (LookupObject(ctop, CurrentCell) == NULL)
@@ -850,7 +851,7 @@ char *ReadSim(char *fname, int *fnum)
SkipNewLine(NULL);
}
else {
char rtop[200], rbot[200];
char rtop[MAX_STR_LEN], rbot[MAX_STR_LEN];
SkipTok(NULL);
GetExtName(rtop, nexttok);
if (LookupObject(rtop, CurrentCell) == NULL)
@@ -874,7 +875,7 @@ char *ReadSim(char *fname, int *fnum)
SkipNewLine(NULL);
}
else {
char rtop[200], rbot[200], rdummy[200];
char rtop[MAX_STR_LEN], rbot[MAX_STR_LEN], rdummy[MAX_STR_LEN];
char inststr[25], *instptr = NULL;
SkipTok(NULL);
GetExtName(rdummy, nexttok);
@@ -916,7 +917,7 @@ char *ReadSim(char *fname, int *fnum)
SkipNewLine(NULL);
}
else if (match(nexttok, "=")) {
char node1[200], node2[200];
char node1[MAX_STR_LEN], node2[MAX_STR_LEN];
SkipTok(NULL);
GetExtName(node1, nexttok);
SkipTok(NULL);
+437 -227
View File
@@ -53,7 +53,7 @@ void flattenCell(char *name, int file)
struct nlist *ChildCell;
struct objlist *tmp, *ob2, *ob3;
int notdone, rnodenum;
char tmpstr[200];
char tmpstr[MAX_STR_LEN];
int nextnode, oldmax;
#if !OLDPREFIX
int prefixlength;
@@ -66,9 +66,13 @@ void flattenCell(char *name, int file)
else
ThisCell = LookupCellFile(name, file);
if (ThisCell == NULL) {
Printf("No cell %s found.\n", name);
Printf("No cell %s (%d) found.\n", name, file);
return;
}
/* Placeholder cells must not be flattened */
if (ThisCell->flags & CELL_PLACEHOLDER) return;
FreeNodeNames(ThisCell);
ParentParams = ThisCell->cell;
@@ -239,6 +243,13 @@ void flattenCell(char *name, int file)
ThisCell->dumped = 1; /* indicate cell has been flattened */
}
/* Structure used to keep track of nodes needing checking */
struct linkednode {
int node;
struct linkednode *next;
};
/*--------------------------------------------------------------*/
/* flattenInstancesOf -- */
/* */
@@ -254,12 +265,14 @@ 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;
struct linkednode *checknodes = NULL, *newlnode, *chknode;
int notdone, rnodenum;
char tmpstr[1024];
int nextnode, oldmax, numflat = 0;
@@ -277,16 +290,20 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
}
else {
if (Debug)
Printf("Flattening instances of %s within cell: %s\n", instance, name);
Printf("Flattening instances of %s within cell: %s (%d)\n", instance,
name, fnum);
if (fnum == -1)
ThisCell = LookupCell(name);
else
ThisCell = LookupCellFile(name, fnum);
if (ThisCell == NULL) {
Printf("No cell %s found.\n", name);
Printf("No cell %s (%d) found.\n", name, fnum);
return 0;
}
}
/* Placeholder cells must not be flattened */
if (ThisCell->flags & CELL_PLACEHOLDER) return 0;
FreeNodeNames(ThisCell);
ParentParams = ThisCell->cell;
@@ -334,219 +351,332 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
ParentProps = ParentProps->next) {
if (ParentProps->type == PROPERTY) break;
}
if (ParentProps && (ParentProps->type != PROPERTY)) ParentProps = NULL;
if (ParentProps && (ParentProps->type != PROPERTY)) {
ParentProps = NULL;
CurrentProp = NULL;
}
else
CurrentProp = ParentProps;
/* not primitive, so need to flatten this instance */
/* 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;
/* if this is a new instance, flatten it */
/* if (ChildCell->dumped == 0) flattenCell(ParentParams->model.class, file); */
ChildObjList = CopyObjList(ChildCell->cell, 1);
numflat++;
/* Loop over property records. Need to flatten once per */
/* property record (or more, if property has M > 1) */
/* 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;
ob2 = NULL;
ChildObjList = NULL;
ChildListEnd = NULL;
while (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++;
}
ChildStart = CopyObjList(ChildCell->cell, 1);
numflat++;
/* 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) {
/* Find the end record of the child cell and save it */
for (ChildEnd = ChildStart; ChildEnd && ChildEnd->next;
ChildEnd = ChildEnd->next);
// 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.
if (ChildListEnd == NULL) ChildListEnd = ChildEnd;
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;
/* 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);
}
else if (tmp->node == -1) {
/* Opposite case: If child port is an unconnected node, then */
/* removing the instance may make the parent node become */
/* unconnected. For now, just record the node number. At the */
/* end we'll check if these nodes are actually disconnected. */
newlnode = (struct linkednode *)MALLOC(sizeof(struct linkednode));
newlnode->node = ob2->node;
newlnode->next = checknodes;
checknodes = newlnode;
}
/* 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);
#endif
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. */
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);
#else
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 OLDPREFIX
sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR,
tmp->instance.name);
#else
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 (CurrentProp) {
int i, mval;
struct valuelist *kv;
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);
}
}
/* Check for property M. If it exists and is greater than */
/* one, reduce it and repeat; i.e., generate multiple */
/* child instances to match the M value. Probably this */
/* could be done quicker by just creating a new property */
/* M for a single child. */
mval = 0;
for (i = 0; ; i++) {
kv = &(CurrentProp->instance.props[i]);
if (kv->type == PROP_ENDLIST) break;
if ((*matchfunc)(kv->key, "M")) {
if (kv->type == PROP_INTEGER) {
mval = kv->value.ival;
kv->value.ival = mval - 1;
break;
}
else if (kv->type == PROP_DOUBLE) {
mval = (int)kv->value.dval;
kv->value.dval = (double)mval - 1;
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);
if (mval > 1) {
/* Put the child cell at the start of ChildObjList */
if (ChildEnd) {
ChildEnd->next = ChildObjList;
ChildObjList = ChildStart;
/* Continue without moving CurrentProp */
/* Note that if ChildEnd is NULL then the child cell
* is optimized out and there is no need to do it
* M times.
*/
continue;
}
}
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
*/
/* Repeat for each property record, as each property represents a
* unique instance that must be flattened individually.
*/
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;
}
}
/* 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);
#endif
for (tmp = ChildObjList; 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. */
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;
}
#if OLDPREFIX
sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR,
tmp->name);
#else
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 OLDPREFIX
sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR,
tmp->instance.name);
#else
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);
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 */
}
/* Check nodes that may have become disconnected after child flattening */
while (checknodes != NULL) {
struct objlist *portnode = NULL;
chknode = checknodes;
checknodes = checknodes->next;
for (ob3 = ThisCell->cell; ob3; ob3 = ob3->next) {
if ((ob3->type != PORT) && (portnode == NULL))
break;
else if ((ob3->type == PORT) && (ob3->node == chknode->node))
portnode = ob3;
else if ((ob3->type >= FIRSTPIN) && (ob3->node == chknode->node))
break;
}
if ((ob3 == NULL) && (portnode != NULL)) {
/* Port became disconnected when child was flattened */
portnode->node = -1;
}
FREE(chknode);
}
CacheNodeNames(ThisCell);
ThisCell->dumped = 1; /* indicate cell has been flattened */
return numflat;
@@ -638,7 +768,7 @@ void convertGlobalsOf(char *name, int fnum, char *instance)
else
ThisCell = LookupCellFile(name, fnum);
if (ThisCell == NULL) {
Printf("No cell %s found.\n", name);
Printf("No cell %s (%d) found.\n", name, fnum);
return;
}
}
@@ -1068,7 +1198,7 @@ int UniquePins(char *name, int filenum)
ThisCell = LookupCellFile(name, filenum);
if (ThisCell == NULL) {
Printf("No cell %s found.\n", name);
Printf("No cell %s (%d) found.\n", name, filenum);
return 0;
}
@@ -1085,12 +1215,33 @@ 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 (%d)\n", ob->name,
ThisCell->name, filenum);
}
}
if (nodecount[ob->node] > 1) {
/* Remove this node; prep for removal by marking with UNKNOWN */
@@ -1105,6 +1256,7 @@ int UniquePins(char *name, int filenum)
}
}
portcount++;
lob = ob;
}
if (needscleanup)
@@ -1289,7 +1441,7 @@ int CleanupPins(char *name, int filenum)
ThisCell = LookupCellFile(name, filenum);
if (ThisCell == NULL) {
Printf("No cell %s found.\n", name);
Printf("No cell %s (%d) found.\n", name, filenum);
return 0;
}
@@ -1371,6 +1523,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 +1636,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 +1652,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 +1665,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,25 +1701,29 @@ 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) &&
(!(ecomp->cell1->flags & CELL_PLACEHOLDER))) {
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);
modified++;
}
if (ecomp->cell2) {
Fprintf(stdout, "Flattening instances of %s in cell %s"
if (ecomp->cell2 && (ecomp->num2 > 0) &&
(!(ecomp->cell2->flags & CELL_PLACEHOLDER))) {
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++;
}
modified++;
}
/* Reset or apply the count adjustments */
@@ -1599,7 +1772,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 +1800,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 && !(ecomp->cell2->flags & CELL_PLACEHOLDER)) {
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 +1838,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 +1866,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 && !(ecomp->cell1->flags & CELL_PLACEHOLDER)) {
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,15 +1958,25 @@ 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. */
if (ecomp->cell1->class != CLASS_ISOURCE) {
/* merge node of endpoints */
/* Prefer a port node over a non-port node */
for (ob2 = tc1->cell; ob2; ob2 = ob2->next) {
if (!IsPort(ob2)) break;
else if (ob2->node == node1) break;
else if (ob2->node == node2) {
int ntemp = node1;
node1 = node2;
node2 = ntemp;
}
}
for (ob2 = tc1->cell; ob2; ob2 = ob2->next) {
if (ob2->node == node2)
ob2->node = node1;
@@ -1880,12 +2079,22 @@ 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) {
/* Prefer a port node over a non-port node */
for (ob1 = tc2->cell; ob1; ob1 = ob1->next) {
if (!IsPort(ob1)) break;
else if (ob1->node == node1) break;
else if (ob1->node == node2) {
int ntemp = node1;
node1 = node2;
node2 = ntemp;
}
}
for (ob1 = tc2->cell; ob1; ob1 = ob1->next) {
if (ob1->node == node2)
ob1->node = node1;
@@ -1973,8 +2182,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 +2208,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 +2223,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 */
+2 -1
View File
@@ -17,6 +17,7 @@ along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* inetcomp.c -- a simple wrapper to the NETCOMP() function */
#include "config.h"
#include <stdio.h>
#include "netgen.h"
@@ -33,7 +34,7 @@ void STRCPY(char *dest, char *source)
int main(int argc, char *argv[])
{
char cell1[200], cell2[200];
char cell1[MAX_STR_LEN], cell2[MAX_STR_LEN];
Debug = 0;
if (argc != 1) {
+849 -282
View File
File diff suppressed because it is too large Load Diff
+14 -1
View File
@@ -7,6 +7,7 @@ extern struct nlist *Circuit1;
extern struct nlist *Circuit2;
extern int ExhaustiveSubdivision;
extern int ExactTopology;
extern int left_col_end;
extern int right_col_end;
@@ -26,6 +27,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);
@@ -36,7 +38,8 @@ extern int PermuteSetup(char *model, int filenum, char *pin1, char *pin2);
extern int PermuteForget(char *model, int filenum, char *pin1, char *pin2);
extern int EquivalenceElements(char *name1, int file1, char *name2, int file2);
extern int EquivalenceNodes(char *name1, int file1, char *name2, int file2);
extern int EquivalenceClasses(char *name1, int file1, char *name2, int file2);
extern int EquivalenceClasses(char *name1, int file1, char *name2, int file2,
int dounique);
extern int IgnoreClass(char *name, int file, unsigned char type);
extern int MatchPins(struct nlist *tp1, struct nlist *tp2, int dolist);
extern int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run,
@@ -46,6 +49,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 +58,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();
+94 -68
View File
@@ -183,7 +183,6 @@ void CloseFile(char *filename)
fclose(outfile);
}
/* STUFF TO READ INPUT FILES */
static char *line = NULL; /* actual line read in */
@@ -207,6 +206,21 @@ struct hashdict *definitions = (struct hashdict *)NULL;
#define WHITESPACE_DELIMITER " \t\n\r"
/*----------------------------------------------------------------------*/
/* Seek and Tell on infile stream, for use with handling generate */
/* loops in verilog. */
/*----------------------------------------------------------------------*/
void SeekFile(long offset)
{
fseek(infile, offset, SEEK_SET);
}
long TellFile()
{
return ftell(infile);
}
/*----------------------------------------------------------------------*/
/* TrimQuoted() --- */
/* Remove spaces from inside single- or double-quoted strings. */
@@ -331,77 +345,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,13 +920,15 @@ 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);
}
}
/* try appending extensions in sequence, and testing for file existance */
for (index = 0; formats[index].extension != NULL; index++) {
char testname[200];
char testname[MAX_STR_LEN];
strcpy(testname, fname);
strcat(testname, formats[index].extension);
if (OpenParseFile(testname, *fnum) >= 0) {
@@ -1007,7 +1033,7 @@ void WriteNetgenFile(char *name, char *filename)
char *ReadNetgenFile (char *fname, int *fnum)
{
char name[100];
char name[MAX_STR_LEN];
char *LastCellRead = NULL;
int filenum;
@@ -1243,7 +1269,7 @@ int READ(void *buf, int bytes)
char *ReadNetgenFile (char *fname, int *fnum)
{
char name[100];
char name[MAX_STR_LEN];
int len, chars;
char *LastCellRead = NULL;
+2
View File
@@ -47,5 +47,7 @@ extern void InputParseError(FILE *f);
extern int OpenParseFile(char *name, int fnum);
extern int EndParseFile(void);
extern int CloseParseFile(void);
extern void SeekFile(long offset); /* handles verilog 'for' loops */
extern long TellFile(); /* handles verilog 'for' loops */
#endif /* _NETFILE_H */
+75 -28
View File
@@ -57,7 +57,7 @@ int AddToExistingDefinition = 0; /* default: overwrite cell when reopened */
extern int errno; /* Defined in stdlib.h */
#define MAX_STATIC_STRINGS 5
static char staticstrings[MAX_STATIC_STRINGS][200];
static char staticstrings[MAX_STATIC_STRINGS][MAX_STR_LEN];
static int laststring;
extern struct hashdict spiceparams; /* From spice.c */
@@ -984,6 +984,51 @@ PropertyDelete(char *name, int fnum, char *key)
return 0;
}
/*----------------------------------------------------------------------*/
/* Associate a property with a specific pin */
/*----------------------------------------------------------------------*/
int
PropertyAssociatePin(char *name, int fnum, char *key, char *pin)
{
struct property *kl = NULL;
struct nlist *tc;
struct objlist *ob;
int result;
if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
result = PropertyAssociatePin(name, Circuit1->file, key, pin);
result = PropertyAssociatePin(name, Circuit2->file, key, pin);
return result;
}
tc = LookupCellFile(name, fnum);
if (tc == NULL) {
Printf("No device %s found for PropertyAssociatePin()\n", name);
return -1;
}
kl = (struct property *)HashLookup(key, &(tc->propdict));
if (kl == NULL) {
Printf("No property %s found for device %s\n", key, name);
return -1;
}
else {
for (ob = tc->cell; ob != NULL; ob = ob->next) {
if (ob->type != PORT) break;
else if ((*matchfunc)(ob->name, pin)) {
kl->pin = ob->name;
break;
}
}
if (ob == NULL) {
Printf("No pin %s found for device %s\n", pin, name);
return -1;
}
}
return 0;
}
/*----------------------------------------------------------------------*/
/* Set the tolerance of a property in the master cell record. */
/*----------------------------------------------------------------------*/
@@ -1352,7 +1397,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 +3305,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 +3382,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 +3414,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 +3439,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 +3471,6 @@ int CombineParallel(char *model, int file)
obr = nob;
}
dcnt++;
}
FREE((char *)pstr);
}
@@ -3440,7 +3482,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 +3780,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;
}
+1
View File
@@ -39,6 +39,7 @@ extern void SetParallelCombine(int value);
extern void SetSeriesCombine(int value);
extern int PropertyTolerance(char *name, int fnum, char *key, int ival,
double dval);
extern int PropertyAssociatePin(char *name, int fnum, char *key, char *pin);
extern int PropertyMerge(char *name, int fnum, char *key, int merge_type,
int merge_mask);
extern void ResolveProperties(char *name1, int file1, char *name2, int file2);
+2 -2
View File
@@ -181,7 +181,7 @@ void Ntk(char *name, char *filename)
char *ReadNtk (char *fname, int *fnum)
{
char model[100], instancename[100], name[100];
char model[MAX_STR_LEN], instancename[MAX_STR_LEN], name[MAX_STR_LEN];
struct objlist *ob;
int CellDefInProgress = 0;
int filenum;
@@ -218,7 +218,7 @@ char *ReadNtk (char *fname, int *fnum)
}
}
else if (match(nexttok, "s")) {
char last[100];
char last[MAX_STR_LEN];
*last = '\0';
if (!CellDefInProgress) {
/* fake cell declaration for top-level call */
+49 -11
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;
@@ -129,6 +130,7 @@ struct property *NewProperty(void)
kl = (struct property *)CALLOC(1,sizeof(struct property));
if (kl == NULL) Fprintf(stderr,"NewProperty: Core allocation error\n");
kl->pin = (char *)NULL;
return (kl);
}
@@ -288,7 +290,7 @@ static struct hashdict cell_dict;
void InitCellHashTable(void)
{
hashfunc = hash;
hashfunc = hashcase;
matchfunc = NULL;
matchintfunc = matchfile;
InitializeHashTable(&cell_dict, CELLHASHSIZE);
@@ -439,15 +441,32 @@ void RemoveShorted(char *class, int file)
RecurseCellFileHashTable(removeshorted, file);
}
/* Remove instances of a deleted class from the database. */
/* NOTE: This treats deleted classes as not existing, so it */
/* needs to take care of disconnected ports in the same manner */
/* as flattenInstancesOf() in disconnecting the port of a */
/* parent cell if it connected to nothing other than the */
/* deleted instance. */
int deleteclass(struct hashlist *p, int file)
{
struct nlist *ptr;
struct objlist *ob, *lob, *nob;
struct objlist *ob, *lob, *nob, *portnode;
unsigned char *checknodes;
int i;
ptr = (struct nlist *)(p->ptr);
if ((file != -1) && (ptr->file != file)) return 0;
/* Note: This could be made faster by enumerating all times each
* node is used during the full pass, then subtracting each time
* the node is deleted in a child, then disconnecting all nodes
* that ended up with a zero count.
*/
checknodes = (unsigned char *)CALLOC(ptr->nodename_cache_maxnodenum + 1,
sizeof(unsigned char));
lob = NULL;
for (ob = ptr->cell; ob != NULL;) {
nob = ob->next;
@@ -455,6 +474,8 @@ int deleteclass(struct hashlist *p, int file)
if ((*matchfunc)(ob->model.class, OldCell->name)) {
HashDelete(ob->instance.name, &(ptr->instdict));
while (1) {
if (ob->type >= FIRSTPIN)
checknodes[ob->node] = (unsigned char)1;
FreeObjectAndHash(ob, ptr);
ob = nob;
if (ob == NULL) break;
@@ -476,6 +497,25 @@ int deleteclass(struct hashlist *p, int file)
ob = nob;
}
}
for (i = 0; i <= ptr->nodename_cache_maxnodenum; i++) {
if (checknodes[i] != 0) {
portnode = NULL;
for (ob = ptr->cell; ob != NULL; ob = ob->next) {
if ((ob->type != PORT) && (portnode == NULL))
break;
else if ((ob->type == PORT) && (ob->node == i))
portnode = ob;
else if ((ob->type >= FIRSTPIN) && (ob->node == i))
break;
}
if ((ob == NULL) && (portnode != NULL)) {
/* Port became disconnected when child was deleted */
portnode->node = -1;
}
}
}
FREE(checknodes);
}
/* Remove all instances of class "class" from the database */
@@ -696,7 +736,7 @@ struct nlist *RecurseCellHashTable2(struct nlist *(*foo)(struct hashlist *,
char *FixTemplate(char *t)
{
char buffer[200];
char buffer[MAX_STR_LEN];
char *rstr;
int i,j;
int InsideBrace;
@@ -975,10 +1015,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 +1136,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);
@@ -1209,7 +1247,7 @@ static char *OldNodeName(struct nlist *tp, int node)
struct objlist *firstuniqueglobal;
struct objlist *firstglobal;
struct objlist *firstpin;
static char StrBuffer[100];
static char StrBuffer[MAX_STR_LEN];
#if 0
/* make second pass, looking for ports */
+25 -10
View File
@@ -135,6 +135,7 @@ struct property {
unsigned char idx; /* index into valuelist */
unsigned char type; /* string, integer, double, value, expression */
unsigned char merge; /* how property changes when devices are merged */
char *pin; /* associated pin (or NULL if not associated) */
union {
char *string;
double dval;
@@ -162,9 +163,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;
};
@@ -206,7 +207,7 @@ struct nlist {
char *name;
int number; /* number of instances defined */
int dumped; /* instance count, and general-purpose marker */
unsigned char flags;
unsigned short flags;
unsigned char class;
unsigned long classhash; /* randomized hash value for cell class */
struct Permutation *permutes; /* list of permuting pins */
@@ -222,17 +223,18 @@ struct nlist {
/* Defined nlist structure flags */
#define CELL_MATCHED 0x01 /* cell matched to another */
#define CELL_NOCASE 0x02 /* cell is case-insensitive (e.g., SPICE) */
#define CELL_TOP 0x04 /* cell is a top-level cell */
#define CELL_PLACEHOLDER 0x08 /* cell is a placeholder cell */
#define CELL_PROPSMATCHED 0x10 /* properties matched to matching cell */
#define CELL_DUPLICATE 0x20 /* cell has a duplicate */
#define CELL_MATCHED 0x001 /* cell matched to another */
#define CELL_NOCASE 0x002 /* cell is case-insensitive (e.g., SPICE) */
#define CELL_TOP 0x004 /* cell is a top-level cell */
#define CELL_PLACEHOLDER 0x008 /* cell is a placeholder cell */
#define CELL_PROPSMATCHED 0x010 /* properties matched to matching cell */
#define CELL_DUPLICATE 0x020 /* cell has a duplicate */
#define CELL_VERILOG 0x040 /* cell is verilog module */
/* Flags for combination allowances and prohibitions */
#define COMB_SERIES 0x40
#define COMB_NO_PARALLEL 0x80
#define COMB_SERIES 0x100
#define COMB_NO_PARALLEL 0x200
extern struct nlist *CurrentCell;
extern struct objlist *CurrentTail;
@@ -312,6 +314,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
+9 -9
View File
@@ -511,8 +511,8 @@ int OpenEmbeddingFile(char *cellname, char *filename)
/* returns 1 if OK */
{
struct nlist *tp;
char outfilename[200];
char logfilename[200];
char outfilename[MAX_STR_LEN];
char logfilename[MAX_STR_LEN];
tp = LookupCell(cellname);
if (tp == NULL) {
@@ -783,7 +783,7 @@ void SetupArray(char *prompt1, char *prompt2, char *prompt3, int *data,
void (*proc)(void))
{
int i, oldfanout;
char name[100];
char name[MAX_STR_LEN];
Printf(prompt1);
for (i = 1; i <= MAX_TREE_DEPTH; i++)
@@ -792,7 +792,7 @@ void SetupArray(char *prompt1, char *prompt2, char *prompt3, int *data,
oldfanout = 1;
for (i = 1; i <= MAX_TREE_DEPTH; i++) {
char prompt[100];
char prompt[MAX_STR_LEN];
int newfanout;
sprintf(prompt, prompt2, i);
promptstring(prompt, name);
@@ -822,7 +822,7 @@ void SetupArrayFromString(char *prompt1, char *prompt3, int *data,
void (*proc)(void), char *text)
{
int i, oldfanout, newfanout;
char string[100];
char string[MAX_STR_LEN];
char *ch;
char *endch;
@@ -962,7 +962,7 @@ void ProtoPrintParameters(void)
void PROTOCHIP(void)
/* a simple command interpreter to manage embedding/routing */
{
char name[100];
char name[MAX_STR_LEN];
char ch;
InitializeFanout();
@@ -1136,7 +1136,7 @@ void PROTOCHIP(void)
oldfanout = 1;
for (i = 1; i <= MAX_TREE_DEPTH; i++) {
char prompt[100];
char prompt[MAX_STR_LEN];
int newfanout;
sprintf(prompt,"Fanout for level %d (0 to quit): ",i);
promptstring(prompt, name);
@@ -1168,7 +1168,7 @@ void PROTOCHIP(void)
oldfanout = 1;
for (i = 1; i <= MAX_TREE_DEPTH; i++) {
char prompt[100];
char prompt[MAX_STR_LEN];
int newfanout;
sprintf(prompt,"Common nodes for level %d (0 to quit): ",i);
promptstring(prompt, name);
@@ -1200,7 +1200,7 @@ void PROTOCHIP(void)
oldfanout = 1;
for (i = 1; i <= MAX_TREE_DEPTH; i++) {
char prompt[100];
char prompt[MAX_STR_LEN];
int newfanout;
sprintf(prompt,"Used leaves for level %d (0 to quit): ",i);
promptstring(prompt, name);
+3 -3
View File
@@ -37,7 +37,7 @@ extern int ColumnBase;
struct filestr {
FILE *f;
char buffer[200];
char buffer[MAX_STR_LEN];
int wrap; /* column to wrap around in, or 0 if no wrap */
} file_buffers[MAXFILES];
@@ -107,7 +107,7 @@ void Fprintf(FILE *f, char *format, ...)
{
va_list ap;
int FileIndex;
char tmpstr[200];
char tmpstr[MAX_STR_LEN];
int bufferlongenough;
int linewrapexceeded;
@@ -203,7 +203,7 @@ void Printf(char *format, ...)
void Printf(char *format, ...)
{
va_list ap;
char tmpstr[200];
char tmpstr[MAX_STR_LEN];
va_start(ap, format);
vsprintf(tmpstr, format, ap);
+12 -9
View File
@@ -52,7 +52,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/*************************************************************************/
static int SuppressPrompts = 0;
static char InputLine[200];
static char InputLine[MAX_STR_LEN];
void typeahead(char *str)
{
@@ -73,7 +73,7 @@ but reads from 'promptstring_infile' if nec. */
/* If interactive, puts out 'prompt' */
{
char *nexttok;
char tmpstr[200];
char tmpstr[MAX_STR_LEN];
int echo;
if (promptstring_infile == NULL)
@@ -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);
}
}
}
}
@@ -956,8 +959,8 @@ void Query(void)
{
/* little interactive debugger */
char reply;
char repstr[100];
char repstr2[100];
char repstr[MAX_STR_LEN];
char repstr2[MAX_STR_LEN];
float StartTime; /* for elapsed CPU times */
int Timing; /* if true, print times of each command */
int filenum = -1;
@@ -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);
+135 -107
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;
@@ -515,13 +518,13 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
int warnings = 0, update = 0, hasports = 0;
char *eqptr, devtype, in_subckt;
struct keyvalue *kvlist = NULL;
char inst[256], model[256], instname[256];
char inst[MAX_STR_LEN], model[MAX_STR_LEN], instname[MAX_STR_LEN];
struct nlist *tp;
struct objlist *parent, *sobj, *nobj, *lobj, *pobj;
inst[255] = '\0';
model[255] = '\0';
instname[255] = '\0';
inst[MAX_STR_LEN-1] = '\0';
model[MAX_STR_LEN-1] = '\0';
instname[MAX_STR_LEN-1] = '\0';
in_subckt = (char)0;
while (!EndParseFile()) {
@@ -552,7 +555,7 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
/* Check for existence of the cell. We may need to rename it. */
snprintf(model, 99, "%s", nexttok);
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
tp = LookupCellFile(nexttok, filenum);
/* Check for name conflict with duplicate cell names */
@@ -700,7 +703,7 @@ skip_ends:
SpiceTokNoNewline();
if (nexttok == NULL) continue; /* Ignore if no model name */
snprintf(model, 99, "%s", nexttok);
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
@@ -884,29 +887,29 @@ skip_ends:
}
else if (toupper(nexttok[0]) == 'Q') {
char emitter[100], base[100], collector[100];
emitter[99] = '\0';
base[99] = '\0';
collector[99] = '\0';
char emitter[MAX_STR_LEN], base[MAX_STR_LEN], collector[MAX_STR_LEN];
emitter[MAX_STR_LEN-1] = '\0';
base[MAX_STR_LEN-1] = '\0';
collector[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) {
CellDef(fname, filenum);
PushStack(fname, CellStackPtr);
}
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(collector, nexttok, 99); SpiceTokNoNewline();
strncpy(collector, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(base, nexttok, 99); SpiceTokNoNewline();
strncpy(base, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(emitter, nexttok, 99); SpiceTokNoNewline();
strncpy(emitter, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
/* make sure all the nodes exist */
if (LookupObject(collector, CurrentCell) == NULL) Node(collector);
if (LookupObject(base, CurrentCell) == NULL) Node(base);
if (LookupObject(emitter, CurrentCell) == NULL) Node(emitter);
/* Read the device model */
snprintf(model, 99, "%s", nexttok);
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
while (nexttok != NULL)
{
@@ -937,30 +940,30 @@ skip_ends:
goto baddevice;
}
snprintf(instname, 255, "%s%s", model, inst);
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
Cell(instname, model, collector, base, emitter);
pobj = LinkProperties(model, kvlist);
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
DeleteProperties(&kvlist);
}
else if (toupper(nexttok[0]) == 'M') {
char drain[100], gate[100], source[100], bulk[100];
drain[99] = '\0';
gate[99] = '\0';
source[99] = '\0';
bulk[99] = '\0';
char drain[MAX_STR_LEN], gate[MAX_STR_LEN], source[MAX_STR_LEN], bulk[MAX_STR_LEN];
drain[MAX_STR_LEN-1] = '\0';
gate[MAX_STR_LEN-1] = '\0';
source[MAX_STR_LEN-1] = '\0';
bulk[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) {
CellDef(fname, filenum);
PushStack(fname, CellStackPtr);
}
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(drain, nexttok, 99); SpiceTokNoNewline();
strncpy(drain, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(gate, nexttok, 99); SpiceTokNoNewline();
strncpy(gate, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(source, nexttok, 99); SpiceTokNoNewline();
strncpy(source, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
/* make sure all the nodes exist */
if (LookupObject(drain, CurrentCell) == NULL) Node(drain);
@@ -968,11 +971,11 @@ skip_ends:
if (LookupObject(source, CurrentCell) == NULL) Node(source);
/* handle the substrate node */
strncpy(bulk, nexttok, 99); SpiceTokNoNewline();
strncpy(bulk, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (LookupObject(bulk, CurrentCell) == NULL) Node(bulk);
/* Read the device model */
snprintf(model, 99, "%s", nexttok);
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
while (nexttok != NULL)
{
@@ -1010,7 +1013,7 @@ skip_ends:
goto baddevice;
}
snprintf(instname, 255, "%s%s", model, inst);
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
Cell(instname, model, drain, gate, source, bulk);
pobj = LinkProperties(model, kvlist);
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
@@ -1024,19 +1027,19 @@ skip_ends:
SpiceSkipNewLine();
}
else {
char ctop[100], cbot[100];
ctop[99] = '\0';
cbot[99] = '\0';
char ctop[MAX_STR_LEN], cbot[MAX_STR_LEN];
ctop[MAX_STR_LEN-1] = '\0';
cbot[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) {
CellDef(fname, filenum);
PushStack(fname, CellStackPtr);
}
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(ctop, nexttok, 99); SpiceTokNoNewline();
strncpy(ctop, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(cbot, nexttok, 99); SpiceTokNoNewline();
strncpy(cbot, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
/* make sure all the nodes exist */
if (LookupObject(ctop, CurrentCell) == NULL) Node(ctop);
@@ -1055,7 +1058,7 @@ skip_ends:
model[0] = '\0';
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
snprintf(model, 99, "%s", nexttok);
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
/* Any other device properties? */
while (nexttok != NULL)
@@ -1068,7 +1071,7 @@ skip_ends:
}
else if (!strncmp(nexttok, "$[", 2)) {
// Support for CDL modeled capacitor format
snprintf(model, 99, "%s", nexttok + 2);
snprintf(model, MAX_STR_LEN-1, "%s", nexttok + 2);
if ((eqptr = strchr(model, ']')) != NULL)
*eqptr = '\0';
}
@@ -1101,7 +1104,7 @@ skip_ends:
usemodel = 1;
}
snprintf(instname, 255, "%s%s", model, inst);
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
if (usemodel)
Cell(instname, model, ctop, cbot);
else
@@ -1118,19 +1121,19 @@ skip_ends:
SpiceSkipNewLine();
}
else {
char rtop[100], rbot[100];
rtop[99] = '\0';
rbot[99] = '\0';
char rtop[MAX_STR_LEN], rbot[MAX_STR_LEN];
rtop[MAX_STR_LEN-1] = '\0';
rbot[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) {
CellDef(fname, filenum);
PushStack(fname, CellStackPtr);
}
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(rtop, nexttok, 99); SpiceTokNoNewline();
strncpy(rtop, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(rbot, nexttok, 99); SpiceTokNoNewline();
strncpy(rbot, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
/* make sure all the nodes exist */
if (LookupObject(rtop, CurrentCell) == NULL) Node(rtop);
if (LookupObject(rbot, CurrentCell) == NULL) Node(rbot);
@@ -1149,7 +1152,7 @@ skip_ends:
model[0] = '\0';
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
snprintf(model, 99, "%s", nexttok);
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
/* Any other device properties? */
while (nexttok != NULL) {
@@ -1161,7 +1164,7 @@ skip_ends:
}
else if (!strncmp(nexttok, "$[", 2)) {
// Support for CDL modeled resistor format
snprintf(model, 99, "%s", nexttok + 2);
snprintf(model, MAX_STR_LEN-1, "%s", nexttok + 2);
if ((eqptr = strchr(model, ']')) != NULL)
*eqptr = '\0';
}
@@ -1194,7 +1197,7 @@ skip_ends:
else
strcpy(model, "r"); /* Use default resistor model */
snprintf(instname, 255, "%s%s", model, inst);
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
if (usemodel)
Cell(instname, model, rtop, rbot);
else
@@ -1205,25 +1208,25 @@ skip_ends:
}
}
else if (toupper(nexttok[0]) == 'D') { /* diode */
char cathode[100], anode[100];
cathode[99] = '\0';
anode[99] = '\0';
char cathode[MAX_STR_LEN], anode[MAX_STR_LEN];
cathode[MAX_STR_LEN-1] = '\0';
anode[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) {
CellDef(fname, filenum);
PushStack(fname, CellStackPtr);
}
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(anode, nexttok, 99); SpiceTokNoNewline();
strncpy(anode, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(cathode, nexttok, 99); SpiceTokNoNewline();
strncpy(cathode, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
/* make sure all the nodes exist */
if (LookupObject(anode, CurrentCell) == NULL) Node(anode);
if (LookupObject(cathode, CurrentCell) == NULL) Node(cathode);
/* Read the device model */
snprintf(model, 99, "%s", nexttok);
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
while (nexttok != NULL)
{
@@ -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, MAX_STR_LEN-1, "%s:%s", model, inst);
Cell(instname, model, anode, cathode);
pobj = LinkProperties(model, kvlist);
ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
@@ -1265,25 +1268,25 @@ skip_ends:
SpiceSkipNewLine();
}
else {
char node1[100], node2[100], node3[100], node4[100];
node1[99] = '\0';
node2[99] = '\0';
node3[99] = '\0';
node4[99] = '\0';
char node1[MAX_STR_LEN], node2[MAX_STR_LEN], node3[MAX_STR_LEN], node4[MAX_STR_LEN];
node1[MAX_STR_LEN-1] = '\0';
node2[MAX_STR_LEN-1] = '\0';
node3[MAX_STR_LEN-1] = '\0';
node4[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) {
CellDef(fname, filenum);
PushStack(fname, CellStackPtr);
}
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(node1, nexttok, 99); SpiceTokNoNewline();
strncpy(node1, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(node2, nexttok, 99); SpiceTokNoNewline();
strncpy(node2, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(node3, nexttok, 99); SpiceTokNoNewline();
strncpy(node3, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(node4, nexttok, 99); SpiceTokNoNewline();
strncpy(node4, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
/* make sure all the nodes exist */
if (LookupObject(node1, CurrentCell) == NULL) Node(node1);
if (LookupObject(node2, CurrentCell) == NULL) Node(node2);
@@ -1295,7 +1298,7 @@ skip_ends:
model[0] = '\0';
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
snprintf(model, 99, "%s", nexttok);
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
/* Any other device properties? */
while (nexttok != NULL) {
@@ -1331,7 +1334,7 @@ skip_ends:
else
strcpy(model, "t"); /* Use default xline model */
snprintf(instname, 255, "%s%s", model, inst);
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
if (usemodel)
Cell(instname, model, node1, node2, node3, node4);
@@ -1344,20 +1347,20 @@ skip_ends:
}
}
else if (toupper(nexttok[0]) == 'L') { /* inductor */
char end_a[100], end_b[100];
char end_a[MAX_STR_LEN], end_b[MAX_STR_LEN];
int usemodel = 0;
end_a[99] = '\0';
end_b[99] = '\0';
end_a[MAX_STR_LEN-1] = '\0';
end_b[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) {
CellDef(fname, filenum);
PushStack(fname, CellStackPtr);
}
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(end_a, nexttok, 99); SpiceTokNoNewline();
strncpy(end_a, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(end_b, nexttok, 99); SpiceTokNoNewline();
strncpy(end_b, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
/* make sure all the nodes exist */
if (LookupObject(end_a, CurrentCell) == NULL) Node(end_a);
if (LookupObject(end_b, CurrentCell) == NULL) Node(end_b);
@@ -1376,7 +1379,7 @@ skip_ends:
model[0] = '\0';
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
snprintf(model, 99, "%s", nexttok);
snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
/* Any other device properties? */
while (nexttok != NULL)
@@ -1414,7 +1417,7 @@ skip_ends:
else
strcpy(model, "l"); /* Use default inductor model */
snprintf(instname, 255, "%s%s", model, inst);
snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
if (usemodel)
Cell(instname, model, end_a, end_b);
else
@@ -1428,25 +1431,38 @@ skip_ends:
/* black-box subcircuits (class MODULE): V, I, E */
else if (toupper(nexttok[0]) == 'V') { /* voltage source */
char pos[100], neg[100];
pos[99] = '\0';
neg[99] = '\0';
char pos[MAX_STR_LEN], neg[MAX_STR_LEN];
pos[MAX_STR_LEN-1] = '\0';
neg[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) {
CellDef(fname, filenum);
PushStack(fname, CellStackPtr);
}
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(pos, nexttok, 99); SpiceTokNoNewline();
strncpy(pos, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(neg, nexttok, 99); SpiceTokNoNewline();
strncpy(neg, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
/* make sure all the nodes exist */
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);
@@ -1483,19 +1499,19 @@ skip_ends:
DeleteProperties(&kvlist);
}
else if (toupper(nexttok[0]) == 'I') { /* current source */
char pos[100], neg[100];
pos[99] = '\0';
neg[99] = '\0';
char pos[MAX_STR_LEN], neg[MAX_STR_LEN];
pos[MAX_STR_LEN-1] = '\0';
neg[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) {
CellDef(fname, filenum);
PushStack(fname, CellStackPtr);
}
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(pos, nexttok, 99); SpiceTokNoNewline();
strncpy(pos, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(neg, nexttok, 99); SpiceTokNoNewline();
strncpy(neg, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
/* make sure all the nodes exist */
if (LookupObject(pos, CurrentCell) == NULL) Node(pos);
if (LookupObject(neg, CurrentCell) == NULL) Node(neg);
@@ -1537,25 +1553,25 @@ skip_ends:
DeleteProperties(&kvlist);
}
else if (toupper(nexttok[0]) == 'E') { /* controlled voltage source */
char pos[100], neg[100], ctrlp[100], ctrln[100];
pos[99] = '\0';
neg[99] = '\0';
ctrlp[99] = '\0';
ctrln[99] = '\0';
char pos[MAX_STR_LEN], neg[MAX_STR_LEN], ctrlp[MAX_STR_LEN], ctrln[MAX_STR_LEN];
pos[MAX_STR_LEN-1] = '\0';
neg[MAX_STR_LEN-1] = '\0';
ctrlp[MAX_STR_LEN-1] = '\0';
ctrln[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) {
CellDef(fname, filenum);
PushStack(fname, CellStackPtr);
}
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline();
strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(pos, nexttok, 99); SpiceTokNoNewline();
strncpy(pos, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(neg, nexttok, 99); SpiceTokNoNewline();
strncpy(neg, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(ctrlp, nexttok, 99); SpiceTokNoNewline();
strncpy(ctrlp, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice;
strncpy(ctrln, nexttok, 99); SpiceTokNoNewline();
strncpy(ctrln, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
/* make sure all the nodes exist */
if (LookupObject(pos, CurrentCell) == NULL) Node(pos);
@@ -1603,11 +1619,11 @@ skip_ends:
}
else if (toupper(nexttok[0]) == 'X') { /* subcircuit instances */
char instancename[100], subcktname[100];
char instancename[MAX_STR_LEN], subcktname[MAX_STR_LEN];
int itype, in_props;
instancename[99] = '\0';
subcktname[99] = '\0';
instancename[MAX_STR_LEN-1] = '\0';
subcktname[MAX_STR_LEN-1] = '\0';
struct portelement {
char *name;
@@ -1617,8 +1633,8 @@ skip_ends:
struct portelement *head, *tail, *scan, *scannext;
struct objlist *obptr;
snprintf(instancename, 99, "%s", nexttok + 1);
strncpy(instancename, nexttok + 1, 99);
snprintf(instancename, MAX_STR_LEN-1, "%s", nexttok + 1);
strncpy(instancename, nexttok + 1, MAX_STR_LEN-1);
if (!(*CellStackPtr)) {
CellDef(fname, filenum);
PushStack(fname, CellStackPtr);
@@ -1726,14 +1742,14 @@ skip_ends:
/* names. */
if (strncmp(instancename, scan->name, strlen(scan->name))) {
snprintf(subcktname, 99, "%s%s", scan->name, instancename);
snprintf(subcktname, MAX_STR_LEN-1, "%s:%s", scan->name, instancename);
strcpy(instancename, subcktname);
}
else {
snprintf(subcktname, 99, "/%s", instancename);
snprintf(subcktname, MAX_STR_LEN-1, "/%s", instancename);
strcpy(instancename, subcktname);
}
snprintf(subcktname, 99, "%s", scan->name);
snprintf(subcktname, MAX_STR_LEN-1, "%s", scan->name);
if (scan == head) {
head = NULL;
@@ -1767,6 +1783,18 @@ skip_ends:
ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */
update = 1;
}
else if (tp->flags & CELL_VERILOG) {
if (tp->flags & CELL_PLACEHOLDER) {
/* Flag this as an error. To do: Rearrange the verilog instance pins to */
/* match the SPICE subcircuit pin order. */
Fprintf(stderr, "Error: SPICE subcircuit %s should be read before verilog "
"module using it, or pins may not match!\n", subcktname);
}
else {
Fprintf(stderr, "Error: SPICE subcircuit %s redefines a verilog module!\n",
subcktname);
}
}
/* nexttok is now NULL, scan->name points to class */
@@ -1969,7 +1997,7 @@ void IncludeSpice(char *fname, int parent, struct cellstack **CellStackPtr,
int blackbox)
{
int filenum = -1;
char name[256];
char name[MAX_STR_LEN];
/* If fname does not begin with "/", then assume that it is */
/* in the same relative path as its parent. */
+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 */
+2
View File
@@ -34,6 +34,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "print.h"
#endif
extern void Finsert(FILE *f);
void test_entry(void)
{
+869 -217
View File
File diff suppressed because it is too large Load Diff
+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 */
+5 -5
View File
@@ -65,10 +65,10 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
Widget toplevel = NULL;
char GlobalFileName[100],
GlobalCellName[100],
GlobalOtherName[100],
GlobalDataName[100];
char GlobalFileName[MAX_STR_LEN],
GlobalCellName[MAX_STR_LEN],
GlobalOtherName[MAX_STR_LEN],
GlobalDataName[MAX_STR_LEN];
/*********************************************************
* Menu structure: attaches label string to a function,
@@ -1708,7 +1708,7 @@ void X_main_loop(int argc, char *argv[])
XmStringCharSet cs = "ISOLatin1";
static char prompt_response[100];
static char prompt_response[MAX_STR_LEN];
int prompt_done;
int calling_editor; /* which string are we trying to get ? */
#define FILE_NAME 1
+2 -1
View File
@@ -17,6 +17,7 @@ along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* inetcomp.c -- a simple wrapper to the NETCOMP() function */
#include "config.h"
#include <stdio.h>
#include "netgen.h"
@@ -33,7 +34,7 @@ void STRCPY(char *dest, char *source)
int main(int argc, char *argv[])
{
char cell1[200], cell2[200];
char cell1[MAX_STR_LEN], cell2[MAX_STR_LEN];
Debug = 0;
if (argc != 1) {
+3 -2
View File
@@ -17,6 +17,7 @@ along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* netcomp.c -- a simple wrapper to provide netlist comparison functionality */
#include "config.h"
#include <stdio.h>
#include "netgen.h"
@@ -51,7 +52,7 @@ void STRCPY(char *dest, char *source)
int main(int argc, char *argv[])
{
#ifndef HAVE_GETOPT
char cell1[200], cell2[200];
char cell1[MAX_STR_LEN], cell2[MAX_STR_LEN];
int filenum = -1;
Debug = 0;
@@ -67,7 +68,7 @@ int main(int argc, char *argv[])
STRCPY(cell2, ReadNetlist(argv[2], &filenum));
if (argc == 5) STRCPY(cell2, argv[4]); /* if explicit cell name specified */
#else
char cell1[200], cell2[200];
char cell1[MAX_STR_LEN], cell2[MAX_STR_LEN];
int usage = 0;
int args;
int c;
+1
View File
@@ -23,6 +23,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdlib.h> /* for getenv */
#endif
#include "netgen.h"
#include "print.h"
int main(int argc, char **argv)
{
+3 -1
View File
@@ -20,9 +20,11 @@ along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ntk2xnf.c -- a simple wrapper to translate .ntk to Xilinx XNF format */
#include "config.h"
#include <stdio.h>
#include "netgen.h"
#include "xilinx.h"
#ifdef HAVE_X11
/* the following two X procedures are to permit linking
@@ -47,7 +49,7 @@ void STRCPY(char *dest, char *source)
int main(int argc, char *argv[])
{
char cellname[200];
char cellname[MAX_STR_LEN];
int filenum = -1;
Debug = 0;
+3
View File
@@ -8,6 +8,8 @@ SCRIPTINSTALL = $(DESTDIR)${INSTALL_PYDIR}
include ${NETGENDIR}/defs.mak
CLEANS += lvs_manager.py
main: lvs_manager.py
tcl-main: lvs_manager.py
@@ -27,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} $@
-819
View File
@@ -1,819 +0,0 @@
#!/bin/env python3
#
#--------------------------------------------------------
# LVS Manager GUI.
#
# This is a Python tkinter script that handles the
# process of running LVS and interpreting results.
#
#--------------------------------------------------------
# Written by Tim Edwards
# efabless, inc.
# Version 1. November 30, 2016
# Version 2. March 6, 2017. Reads JSON format output
# Version 3. April 25, 2018. Handles layout vs. verilog
#--------------------------------------------------------
import io
import os
import re
import sys
import json
import shutil
import signal
import socket
import select
import datetime
import contextlib
import subprocess
import tkinter
from tkinter import ttk
from tkinter import filedialog
import tksimpledialog
import tooltip
from consoletext import ConsoleText
from helpwindow import HelpWindow
from treeviewsplit import TreeViewSplit
# User preferences file (if it exists)
prefsfile = '~/.profile/prefs.json'
netgen_script_dir = '/usr/local/lib/netgen/python'
#------------------------------------------------------
# Simple dialog for confirming quit
#------------------------------------------------------
class ConfirmDialog(tksimpledialog.Dialog):
def body(self, master, warning, seed):
if warning:
ttk.Label(master, text=warning, wraplength=500).grid(row = 0, columnspan = 2, sticky = 'wns')
return self
def apply(self):
return 'okay'
#------------------------------------------------------
# Main class for this application
#------------------------------------------------------
class LVSManager(ttk.Frame):
"""LVS Manager GUI."""
def __init__(self, parent, *args, **kwargs):
ttk.Frame.__init__(self, parent, *args, **kwargs)
self.root = parent
self.init_gui()
parent.protocol("WM_DELETE_WINDOW", self.on_quit)
def on_quit(self):
"""Exits program."""
if self.msock:
self.msock.close()
quit()
def init_gui(self):
"""Builds GUI."""
global prefsfile
message = []
fontsize = 11
# Read user preferences file, get default font size from it.
prefspath = os.path.expanduser(prefsfile)
if os.path.exists(prefspath):
with open(prefspath, 'r') as f:
self.prefs = json.load(f)
if 'fontsize' in self.prefs:
fontsize = self.prefs['fontsize']
else:
self.prefs = {}
s = ttk.Style()
available_themes = s.theme_names()
s.theme_use(available_themes[0])
s.configure('bg.TFrame', background='gray40')
s.configure('italic.TLabel', font=('Helvetica', fontsize, 'italic'))
s.configure('title.TLabel', font=('Helvetica', fontsize, 'bold italic'),
foreground = 'brown', anchor = 'center')
s.configure('normal.TLabel', font=('Helvetica', fontsize))
s.configure('red.TLabel', font=('Helvetica', fontsize), foreground = 'red')
s.configure('green.TLabel', font=('Helvetica', fontsize), foreground = 'green3')
s.configure('blue.TLabel', font=('Helvetica', fontsize), foreground = 'blue')
s.configure('normal.TButton', font=('Helvetica', fontsize),
border = 3, relief = 'raised')
s.configure('red.TButton', font=('Helvetica', fontsize), foreground = 'red',
border = 3, relief = 'raised')
s.configure('green.TButton', font=('Helvetica', fontsize), foreground = 'green3',
border = 3, relief = 'raised')
s.configure('blue.TButton', font=('Helvetica', fontsize), foreground = 'blue',
border = 3, relief = 'raised')
s.configure('redtitle.TButton', font=('Helvetica', fontsize, 'bold italic'),
foreground = 'red', border = 3, relief = 'raised')
s.configure('bluetitle.TButton', font=('Helvetica', fontsize, 'bold italic'),
foreground = 'blue', border = 3, relief = 'raised')
# These values to be overridden from arguments
self.rootpath = None
self.project = None
self.logfile = None
self.msock = None
self.help = None
# Create the help window
if os.path.exists(netgen_script_dir + '/netgen_help.txt'):
self.help = HelpWindow(self, fontsize = fontsize)
with io.StringIO() as buf, contextlib.redirect_stdout(buf):
self.help.add_pages_from_file('lvs_help.txt')
message = buf.getvalue()
# Set the help display to the first page
self.help.page(0)
# Variables used by option menus and other stuff
self.project = "(no selection)"
self.layout = "(default)"
self.schematic = "(default)"
self.tech = "(none)"
self.lvs_setup = ''
self.lvsdata = {}
# Root window title
self.root.title('LVS Manager')
self.root.option_add('*tearOff', 'FALSE')
self.pack(side = 'top', fill = 'both', expand = 'true')
pane = tkinter.PanedWindow(self, orient = 'vertical', sashrelief='groove', sashwidth=6)
pane.pack(side = 'top', fill = 'both', expand = 'true')
self.toppane = ttk.Frame(pane)
self.botpane = ttk.Frame(pane)
# Get username
if 'username' in self.prefs:
username = self.prefs['username']
else:
username = os.environ['USER']
# Label with the user
self.toppane.title_frame = ttk.Frame(self.toppane)
self.toppane.title_frame.pack(side = 'top', fill = 'x')
self.toppane.title_frame.title = ttk.Label(self.toppane.title_frame, text='User:', style = 'red.TLabel')
self.toppane.title_frame.user = ttk.Label(self.toppane.title_frame, text=username, style = 'blue.TLabel')
self.toppane.title_frame.title.grid(column=0, row=0, ipadx = 5)
self.toppane.title_frame.user.grid(column=1, row=0, ipadx = 5)
self.toppane.title2_frame = ttk.Frame(self.toppane)
self.toppane.title2_frame.pack(side = 'top', fill = 'x')
self.toppane.title2_frame.project_label = ttk.Label(self.toppane.title2_frame, text="Project:",
style = 'title.TLabel')
self.toppane.title2_frame.project_label.grid(column=0, row=0, ipadx = 5)
# New project select button
self.toppane.title2_frame.project_select = ttk.Button(self.toppane.title2_frame,
text=self.project, style='normal.TButton', command=self.choose_project)
self.toppane.title2_frame.project_select.grid(column=1, row=0, ipadx = 5)
tooltip.ToolTip(self.toppane.title2_frame.project_select,
text = "Select new project")
# Show path to project
self.toppane.title2_frame.path_label = ttk.Label(self.toppane.title2_frame, text=self.project,
style = 'normal.TLabel')
self.toppane.title2_frame.path_label.grid(column=2, row=0, ipadx = 5, padx = 10)
# Show top-level layout cellname with select button. Initial cell name is the top-level cell.
self.toppane.title2_frame.tech_label = ttk.Label(self.toppane.title2_frame, text="Technology setup:",
style = 'title.TLabel')
self.toppane.title2_frame.tech_label.grid(column=3, row=0, ipadx = 5)
self.toppane.title2_frame.tech_select = ttk.Button(self.toppane.title2_frame,
text=self.tech, style='normal.TButton', command=self.choose_tech)
self.toppane.title2_frame.tech_select.grid(column=4, row=0, ipadx = 3, padx = 3)
self.toppane.title2_frame.layout_label = ttk.Label(self.toppane.title2_frame, text="Layout:",
style = 'title.TLabel')
self.toppane.title2_frame.layout_label.grid(column=0, row=1, ipadx = 5)
self.toppane.title2_frame.layout_select = ttk.Button(self.toppane.title2_frame,
text=self.layout, style='normal.TButton', command=self.choose_layout)
self.toppane.title2_frame.layout_select.grid(column=1, row=1, ipadx = 3, padx = 3)
# Show top-level schematic cellname with select button. Initial cell name is the top-level cell.
self.toppane.title2_frame.schem_label = ttk.Label(self.toppane.title2_frame, text="Schematic:",
style = 'title.TLabel')
self.toppane.title2_frame.schem_label.grid(column=3, row=1, ipadx = 5)
self.toppane.title2_frame.schem_select = ttk.Button(self.toppane.title2_frame,
text=self.schematic, style='normal.TButton', command=self.choose_netlist)
self.toppane.title2_frame.schem_select.grid(column=4, row=1, ipadx = 3, padx = 3)
tooltip.ToolTip(self.toppane.title2_frame.project_select,
text = "Select new project")
tooltip.ToolTip(self.toppane.title2_frame.layout_select,
text = "Select a layout subcirucit to compare")
tooltip.ToolTip(self.toppane.title2_frame.schem_select,
text = "Select a schematic subcirucit to compare")
#---------------------------------------------
ttk.Separator(self.toppane, orient='horizontal').pack(side = 'top', fill = 'x')
#---------------------------------------------
# Create listbox of Circuit1 vs. Circuit2 results
height = 10
self.toppane.lvsreport = TreeViewSplit(self.toppane, fontsize = fontsize)
self.toppane.lvsreport.populate("Layout:", [], "Schematic:", [],
[["Run", True, self.run_lvs],
# ["Find", True, self.findrecord]
], height = height)
self.toppane.lvsreport.set_title("Line")
self.toppane.lvsreport.pack(side = 'top', fill = 'both', expand = 'true')
tooltip.ToolTip(self.toppane.lvsreport.get_button(0), text="Run LVS")
#---------------------------------------------
# ttk.Separator(self, orient='horizontal').grid(column=0, row=3, sticky='ew')
#---------------------------------------------
# Add a text window below the project name to capture output. Redirect
# print statements to it.
self.botpane.console = ttk.Frame(self.botpane)
self.botpane.console.pack(side = 'top', fill = 'both', expand = 'true')
self.text_box = ConsoleText(self.botpane.console, wrap='word', height = 4)
self.text_box.pack(side='left', fill='both', expand='true')
console_scrollbar = ttk.Scrollbar(self.botpane.console)
console_scrollbar.pack(side='right', fill='y')
# attach console to scrollbar
self.text_box.config(yscrollcommand = console_scrollbar.set)
console_scrollbar.config(command = self.text_box.yview)
# Add button bar at the bottom of the window
self.botpane.bbar = ttk.Frame(self.botpane)
self.botpane.bbar.pack(side = 'top', fill = 'x')
# Define the "quit" button and action
self.botpane.bbar.quit_button = ttk.Button(self.botpane.bbar, text='Quit', command=self.on_quit,
style = 'normal.TButton')
self.botpane.bbar.quit_button.grid(column=0, row=0, padx = 5)
# Define help button
if self.help:
self.botpane.bbar.help_button = ttk.Button(self.botpane.bbar, text='Help',
command=self.help.open, style = 'normal.TButton')
self.botpane.bbar.help_button.grid(column = 2, row = 0, padx = 5)
tooltip.ToolTip(self.botpane.bbar.help_button, text = "Show help window")
# Add the panes once the internal geometry is known.
pane.add(self.toppane)
pane.add(self.botpane)
pane.paneconfig(self.toppane, stretch='first')
# Redirect stdout and stderr to the console as the last thing to do. . .
# Otherwise errors in the GUI get sucked into the void.
self.stdout = sys.stdout
self.stderr = sys.stderr
sys.stdout = ConsoleText.StdoutRedirector(self.text_box)
sys.stderr = ConsoleText.StderrRedirector(self.text_box)
if message:
print(message)
def logprint(self, message, doflush=False):
if self.logfile:
self.logfile.buffer.write(message.encode('utf-8'))
self.logfile.buffer.write('\n'.encode('utf-8'))
if doflush:
self.logfile.flush()
def printout(self, output):
# Generate output
if not output:
return
outlines = output.splitlines()
for line in outlines:
try:
print(line)
except TypeError:
line = line.decode('utf-8')
pritn(line)
def printwarn(self, output):
# Check output for warning or error
if not output:
return 0
warnrex = re.compile('.*warning', re.IGNORECASE)
errrex = re.compile('.*error', re.IGNORECASE)
errors = 0
outlines = output.splitlines()
for line in outlines:
try:
wmatch = warnrex.match(line)
except TypeError:
line = line.decode('utf-8')
wmatch = warnrex.match(line)
ematch = errrex.match(line)
if ematch:
errors += 1
if ematch or wmatch:
print(line)
return errors
def choose_tech(self):
try:
project_path = self.rootpath
initdirname = self.rootpath + '/tech',
except:
print('Must choose a project first.')
return
techname = filedialog.askopenfilename(multiple=False,
initialdir = initdirname,
filetypes = (("Tcl script", "*.tcl"),("All Files","*.*")),
title = "Choose a netgen technology setup script.")
if techname != '':
print("Selected technology setup script " + techname)
techbase = os.path.split(techname)[1]
self.tech = os.path.splitext(techbase)[0]
self.lvs_setup = techname
self.toppane.title2_frame.layout_select.config(text = self.tech)
def choose_layout(self):
try:
project_path = self.rootpath
initdirname = self.rootpath + '/layout',
except:
print('Must choose a project first.')
return
cellname = filedialog.askopenfilename(multiple=False,
initialdir = initdirname,
filetypes = (("Magic layout", "*.mag"),("All Files","*.*")),
title = "Choose a layout cell to compare.")
if cellname != '':
print("Selected compare cell " + cellname)
cellbase = os.path.split(cellname)[1]
self.layout = os.path.splitext(cellbase)[0]
self.toppane.title2_frame.layout_select.config(text = self.layout)
def choose_netlist(self):
try:
project_path = self.rootpath
initdirname = self.rootpath + '/netlist/' + self.project + '.spi'
except:
print('Must choose a project first.')
return
cellname = filedialog.askopenfilename(multiple=False,
initialdir = initdirname,
filetypes = (("Spice netlist", "*.spi"),("Verilog netlist", "*.v")),
title = "Choose a netlist to compare.")
if cellname != '':
print("Selected compare cell " + cellname)
cellbase = os.path.split(cellname)[1]
self.schematic = os.path.splitext(cellbase)[0]
self.toppane.title2_frame.schem_select.config(text = self.schematic)
fileext = os.path.splitext(cellbase)[1]
if fileext == '.v':
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
elif fileext == '.sp' or fileext == '.spi' or fileext == '.spice' or fileext == '.spc' or fileext == '.ckt':
self.toppane.title2_frame.schem_label.config(text = 'SPICE netlist:')
elif fileext == '.cdl':
self.toppane.title2_frame.schem_label.config(text = 'CDL netlist:')
else:
self.toppane.title2_frame.schem_label.config(text = 'Unknown netlist:')
def choose_project(self):
project = filedialog.askdirectory(initialdir = os.getcwd(),
title = "Find a project.")
if project != '':
print("Selected project " + str(project))
result = self.set_project(project)
def set_project(self, rootpath, project_name=None):
# Check if rootpath is valid. For LVS, there should be subdirectories
# "layout/" and "netlist/" or "verilog/".
haslay = os.path.isdir(rootpath + '/layout')
hasvlog = os.path.isdir(rootpath + '/verilog')
hasnet = os.path.isdir(rootpath + '/netlist')
if not haslay or not (hasvlog or hasnet):
if not haslay:
print("Project path has no layout (/layout) subdirectory.")
if not (hasvlog or hasnet):
print("Project path has no verilog (/verilog), or netlist (/netlist) subdirectory.")
# Continue anyway; assume that netlists will be selected manually
if self.logfile:
self.logfile.close()
self.logfile = None
if not project_name:
project = os.path.split(rootpath)[1]
else:
project = project_name
if self.project != project:
self.rootpath = rootpath
self.project = project
# Clear out old project data
self.toppane.lvsreport.repopulate([], [])
# Close any open logfile.
if self.logfile:
self.logfile.close()
self.logfile = None
# Put new log file called 'lvs.log' in the mag/ subdirectory
self.logfile = open(rootpath + '/layout/lvs.log', 'w')
# Print some initial information to the logfile.
self.logprint('Starting new log file ' + datetime.datetime.now().strftime('%c'),
doflush=True)
# Update project button
self.toppane.title2_frame.project_select.config(text = self.project)
self.toppane.title2_frame.path_label.config(text = self.rootpath)
# Cell name is the same as project name initially
self.layout = self.project
self.schematic = self.project
self.toppane.title2_frame.layout_select.config(text = self.layout)
self.toppane.title2_frame.schem_select.config(text = self.schematic)
# Update schematic button
if os.path.isfile(rootpath + '/verilog/' + self.schematic + '.v'):
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
else:
self.toppane.title2_frame.schem_label.config(text = 'Schematic netlist:')
# If there is a comparison file that post-dates both netlists, load it.
self.check_lvs()
return True
def check_layout_out_of_date(self, spipath, layoutpath):
# Check if a netlist (spipath) is out-of-date relative to the layouts
# (layoutpath). Need to read the netlist and check all of the subcells.
need_capture = False
if not os.path.isfile(spipath):
return True
if os.path.isfile(layoutpath):
spi_statbuf = os.stat(spipath)
lay_statbuf = os.stat(layoutpath)
if spi_statbuf.st_mtime < lay_statbuf.st_mtime:
# netlist exists but is out-of-date
need_capture = True
else:
# only found that the top-level-layout is older than the
# netlist. Now need to read the netlist, find all subcircuits,
# and check those dates, too.
layoutdir = os.path.split(layoutpath)[0]
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
with open(spipath, 'r') as ifile:
duttext = ifile.read()
dutlines = duttext.replace('\n+', ' ').splitlines()
for line in dutlines:
lmatch = subrex.match(line)
if lmatch:
subname = lmatch.group(1)
sublayout = layoutdir + '/' + subname + '.mag'
# subcircuits that cannot be found in the current directory are
# assumed to be library components and therefore never out-of-date.
if os.path.exists(sublayout):
sub_statbuf = os.stat(sublayout)
if spi_statbuf.st_mtime < lay_statbuf.st_mtime:
# netlist exists but is out-of-date
need_capture = True
break
return need_capture
def check_schematic_out_of_date(self, spipath, schempath):
# Check if a netlist (spipath) is out-of-date relative to the schematics
# (schempath). Need to read the netlist and check all of the subcells.
need_capture = False
if not os.path.isfile(spipath):
return True
if os.path.isfile(schempath):
spi_statbuf = os.stat(spipath)
sch_statbuf = os.stat(schempath)
if spi_statbuf.st_mtime < sch_statbuf.st_mtime:
# netlist exists but is out-of-date
need_capture = True
else:
# only found that the top-level-schematic is older than the
# netlist. Now need to read the netlist, find all subcircuits,
# and check those dates, too.
schemdir = os.path.split(schempath)[0]
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
with open(spipath, 'r') as ifile:
duttext = ifile.read()
dutlines = duttext.replace('\n+', ' ').splitlines()
for line in dutlines:
lmatch = subrex.match(line)
if lmatch:
subname = lmatch.group(1)
# NOTE: Electric uses library:cell internally to track libraries,
# and maps the ":" to "__" in the netlist. Not entirely certain that
# the double-underscore uniquely identifies the library:cell. . .
librex = re.compile('(.*)__(.*)', re.IGNORECASE)
lmatch = librex.match(subname)
if lmatch:
elecpath = os.path.split(os.path.split(schempath)[0])[0]
libname = lmatch.group(1)
subschem = elecpath + '/' + libname + '.delib/' + lmatch.group(2) + '.sch'
else:
libname = {}
subschem = schemdir + '/' + subname + '.sch'
# subcircuits that cannot be found in the current directory are
# assumed to be library components and therefore never out-of-date.
if os.path.exists(subschem):
sub_statbuf = os.stat(subschem)
if spi_statbuf.st_mtime < sub_statbuf.st_mtime:
# netlist exists but is out-of-date
need_capture = True
break
# mapping of characters to what's allowed in SPICE makes finding
# the associated schematic file a bit difficult. Requires wild-card
# searching.
elif libname:
restr = lmatch.group(2) + '.sch'
restr = restr.replace('.', '\.')
restr = restr.replace('_', '.')
schrex = re.compile(restr, re.IGNORECASE)
libpath = elecpath + '/' + libname + '.delib'
if os.path.exists(libpath):
liblist = os.listdir(libpath)
for file in liblist:
lmatch = schrex.match(file)
if lmatch:
subschem = libpath + '/' + file
sub_statbuf = os.stat(subschem)
if spi_statbuf.st_mtime < sch_statbuf.st_mtime:
# netlist exists but is out-of-date
need_capture = True
break
return need_capture
def check_lvs(self):
# If both netlists exist, and comp.json is more recent than both, then
# load LVS results from comp.json
project_path = self.rootpath
project_name = self.project
layout_path = project_path + '/layout/' + project_name + '.spc'
net_path = project_path + '/netlist/' + project_name + '.spi'
comp_path = project_path + '/layout/comp.json'
if os.path.exists(layout_path) and os.path.exists(net_path) and os.path.exists(comp_path):
magtime = os.stat(layout_path).st_mtime
schemtime = os.stat(net_path).st_mtime
comptime = os.stat(comp_path).st_mtime
if comptime > magtime and comptime > schemtime:
print("Loading LVS results from file.")
self.generate(comp_path)
def generate_layout_netlist(self, layout_path, layout_src, project_path):
# Does layout netlist exist and is it current?
if self.check_layout_out_of_date(layout_path, layout_src):
print('Generating layout netlist.')
self.update_idletasks()
mproc = subprocess.Popen(['magic', '-dnull', '-noconsole',
self.layout], stdin = subprocess.PIPE, stdout = subprocess.PIPE,
stderr = subprocess.PIPE, cwd = project_path + '/layout',
universal_newlines = True)
mproc.stdin.write("select top cell\n")
mproc.stdin.write("expand\n")
mproc.stdin.write("extract all\n")
mproc.stdin.write("ext2spice hierarchy on\n")
mproc.stdin.write("ext2spice format ngspice\n")
mproc.stdin.write("ext2spice scale off\n")
mproc.stdin.write("ext2spice renumber off\n")
mproc.stdin.write("ext2spice subcircuit top auto\n")
mproc.stdin.write("ext2spice cthresh infinite\n")
mproc.stdin.write("ext2spice rthresh infinite\n")
mproc.stdin.write("ext2spice blackbox on\n")
mproc.stdin.write("ext2spice -o " + self.layout + ".spi\n")
mproc.stdin.write("quit -noprompt\n")
magicout = mproc.communicate()[0]
self.printwarn(magicout)
if mproc.returncode != 0:
print('Failure to generate new layout netlist.')
return False
# Move .spi netlist to project_dir/netlist/lvs/
shutil.move(project_path + '/layout/' + self.layout + '.spi', layout_path)
# Remove extraction files
for file in os.listdir(project_path + '/layout'):
if os.path.splitext(file)[1] == '.ext':
os.remove(project_path + '/layout/' + file)
else:
print('Layout netlist is up-to-date, not regenerating.')
return True
def run_lvs(self, value):
# "value" is ignored (?)
# Check if netlists exist and are current; otherwise create them.
# Then run LVS.
project_path = self.rootpath
project_name = self.project
comp_path = project_path + '/layout/comp.json'
has_vlog = False
vlog_path = project_path + '/verilog/' + project_name + '.v'
layout_path = project_path + '/netlist/lvs/' + self.layout + '.spi'
net_path = project_path + '/netlist/schem/' + self.schematic + '.spi'
layout_src = project_path + '/layout/' + self.layout + '.mag'
# Does the setup file exist (this is optional)?
if self.lvs_setup != '' and not os.path.isfile('setup.tcl'):
print('No technology setup file selected.')
# Does schematic netlist exist?
if not os.path.isfile(vlog_path) and not os.path.isfile(net_path):
print('Error: No schematic netlist or verilog netlist.')
return
# Does LVS netlist subdirectory exist?
if not os.path.exists(project_path + '/netlist/lvs'):
os.makedirs(project_path + '/netlist/lvs')
# Does layout netlist exist and is it current?
if not self.generate_layout_netlist(layout_path, layout_src, project_path):
return False
# Final check
if not os.path.isfile(layout_path):
print('Error: No netlist generated from magic.')
return
else:
# Read in netlist and convert commas from [X,Y] arrays to vertical bars
# as something that can be converted back as necessary. ngspice treats
# commas as special characters for some reason.
with open(layout_path) as ifile:
spitext = ifile.read()
# spilines = spitext.replace(',', '|')
# with open(layout_path, 'w') as ofile:
# ofile.write(spilines)
# Check the netlist to see if the cell to match is a subcircuit. If
# not, then assume it is the top level.
is_subckt = False
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
dutlines = spitext.replace('\n+', ' ').splitlines()
for line in dutlines:
lmatch = subrex.match(line)
if lmatch:
subname = lmatch.group(1)
if subname == self.layout:
is_subckt = True
break
if is_subckt:
layout_arg = layout_path + ' ' + self.layout
layout_text = '"' + layout_arg + '"'
else:
layout_arg = layout_path
layout_text = layout_arg
if has_vlog:
schem_arg = vlog_path + ' ' + self.schematic
else:
schem_arg = net_path + ' ' + self.schematic
schem_text = '"' + schem_arg + '"'
# Remove any previous comparison output file
comp_out_path = os.path.splitext(comp_path)[0] + '.out'
if os.path.exists(comp_out_path):
os.remove(comp_out_path)
# Run netgen as subprocess
print('Running: netgen -batch lvs ' + layout_text +
' ' + schem_text + ' ' + self.lvs_setup + ' ' + comp_out_path +
' -json -blackbox')
# Note: Because arguments to subprocess are list items, the {filename cell}
# pair does *not* have to be quoted or braced. Doing so causes a parse
# error.
self.lvsproc = subprocess.Popen(['netgen', '-batch', 'lvs',
layout_arg, schem_arg,
self.lvs_setup, comp_out_path, '-json', '-blackbox'],
cwd=project_path + '/layout',
stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0)
# This is largely unnecessary as netgen usually runs to completion very quickly.
self.watchclock(comp_path)
def watchclock(self, filename):
if self.lvsproc == None:
return
lvs_status = self.lvsproc.poll()
sresult = select.select([self.lvsproc.stdout, self.lvsproc.stderr], [], [], 0)[0]
if self.lvsproc.stdout in sresult:
outstring = self.lvsproc.stdout.readline().decode().strip()
self.logprint(outstring, doflush=True)
print(outstring)
elif self.lvsproc.stderr in sresult:
errstring = self.lvsproc.stderr.readline().decode().strip()
self.logprint(errstring, doflush = True)
print(errstring, file=sys.stderr)
if lvs_status != None:
print("netgen LVS exited with status " + str(lvs_status))
self.lvsproc = None
if lvs_status != 0:
print('Errors encountered in LVS.')
self.logprint('Errors in LVS, lvs status = ' + str(lvs_status), doflush=True)
# Done; now read comp.json and fill the treeview listbox.
self.generate(filename)
else:
self.after(500, lambda: self.watchclock(filename))
# Generate display from "comp.out" file (json file now preferred)
def generate_orig(self, lvspath):
lefttext = []
righttext = []
print("Reading LVS output file " + lvspath)
if os.path.exists(lvspath):
with open(lvspath, 'r') as ifile:
lvslines = ifile.read().splitlines()
for line in lvslines:
if '|' in line:
# parts = line.split('|')
# lefttext.append(parts[0])
# righttext.append(parts[1])
lefttext.append(line[0:42].strip())
righttext.append(line[44:].strip())
else:
lefttext.append(line)
righttext.append('')
# Populate treeview with text
self.toppane.lvsreport.repopulate(lefttext, righttext)
else:
print("Error: No output file generated from LVS.")
# Generate output from LVS report JSON file comp.json
def generate(self, lvspath):
lefttext = []
righttext = []
print("Reading LVS output file " + lvspath)
if os.path.exists(lvspath):
with open(lvspath, 'r') as ifile:
self.lvsdata = json.load(ifile)
# Populate treeview with text
self.toppane.lvsreport.json_repopulate(self.lvsdata)
else:
print("Error: No output file generated from LVS.")
def findrecord(self, value):
print("Unimplemented function")
def findrecord_test(self, value):
# Check if socket is defined; if not, attempt to open one
if not self.msock:
try:
self.msock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
print("No response from layout tool.")
if self.msock:
self.msock.connect(("0.0.0.0", 12946))
self.msock.setblocking(False)
if self.msock:
# Pull name of net or device from 'value'
# This is a test:
self.msock.sendall(b'box 0 0 100 100\r\n')
if __name__ == '__main__':
options = []
arguments = []
for item in sys.argv[1:]:
if item.find('-', 0) == 0:
options.append(item)
else:
arguments.append(item)
root = tkinter.Tk()
app = LVSManager(root)
if arguments:
if len(arguments) >= 2:
app.set_project(arguments[0], project_name=arguments[1])
else:
app.set_project(arguments[0])
root.mainloop()
+108 -36
View File
@@ -343,7 +343,7 @@ class LVSManager(ttk.Frame):
techbase = os.path.split(techname)[1]
self.tech = os.path.splitext(techbase)[0]
self.lvs_setup = techname
self.toppane.title2_frame.layout_select.config(text = self.tech)
self.toppane.title2_frame.tech_select.config(text = self.tech)
def choose_layout(self):
try:
@@ -358,30 +358,37 @@ class LVSManager(ttk.Frame):
title = "Choose a layout cell to compare.")
if cellname != '':
print("Selected compare cell " + cellname)
self.layout = cellname
cellbase = os.path.split(cellname)[1]
self.layout = os.path.splitext(cellbase)[0]
self.toppane.title2_frame.layout_select.config(text = self.layout)
layoutname = os.path.splitext(cellbase)[0]
self.toppane.title2_frame.layout_select.config(text = layoutname)
fileext = os.path.splitext(cellbase)[1]
if fileext == '.mag':
self.toppane.title2_frame.layout_label.config(text = 'Layout:')
else:
self.toppane.title2_frame.layout_label.config(text = 'Layout netlist:')
def choose_netlist(self):
try:
project_path = self.rootpath
initdirname = self.rootpath + '/netlist/' + self.project + '.spi'
initdirname = self.rootpath + '/netlist/' + self.project + '.spice'
except:
print('Must choose a project first.')
return
cellname = filedialog.askopenfilename(multiple=False,
initialdir = initdirname,
filetypes = (("Spice netlist", "*.spi"),("Verilog netlist", "*.v")),
filetypes = (("Spice netlist", "*.spice"),("Verilog netlist", "*.v"),("All Files","*.*")),
title = "Choose a netlist to compare.")
if cellname != '':
print("Selected compare cell " + cellname)
self.schematic = cellname
cellbase = os.path.split(cellname)[1]
self.schematic = os.path.splitext(cellbase)[0]
self.toppane.title2_frame.schem_select.config(text = self.schematic)
schematic_name = os.path.splitext(cellbase)[0]
self.toppane.title2_frame.schem_select.config(text = schematic_name)
fileext = os.path.splitext(cellbase)[1]
if fileext == '.v':
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
elif fileext == '.sp' or fileext == '.spi' or fileext == '.spice' or fileext == '.spc' or fileext == '.ckt':
elif fileext == '.sp' or fileext == '.spice' or fileext == '.spi' or fileext == '.spc' or fileext == '.ckt':
self.toppane.title2_frame.schem_label.config(text = 'SPICE netlist:')
elif fileext == '.cdl':
self.toppane.title2_frame.schem_label.config(text = 'CDL netlist:')
@@ -433,7 +440,10 @@ class LVSManager(ttk.Frame):
self.logfile = None
# Put new log file called 'lvs.log' in the mag/ subdirectory
self.logfile = open(rootpath + '/layout/lvs.log', 'w')
if os.path.exists(rootpath + '/layout'):
self.logfile = open(rootpath + '/layout/lvs.log', 'w')
else:
self.logfile = open(rootpath + '/lvs.log', 'w')
# Print some initial information to the logfile.
self.logprint('Starting new log file ' + datetime.datetime.now().strftime('%c'),
doflush=True)
@@ -444,15 +454,23 @@ class LVSManager(ttk.Frame):
# Cell name is the same as project name initially
self.layout = self.project
self.schematic = self.project
self.toppane.title2_frame.layout_select.config(text = self.layout)
self.toppane.title2_frame.schem_select.config(text = self.schematic)
layname = os.path.splitext(os.path.split(self.layout)[1])[0]
self.toppane.title2_frame.layout_select.config(text = layname)
schemname = os.path.splitext(os.path.split(self.schematic)[1])[0]
self.toppane.title2_frame.schem_select.config(text = schemname)
# Update schematic button
if os.path.isfile(rootpath + '/verilog/' + self.schematic + '.v'):
if os.path.splitext(self.schematic)[1] == '.v':
self.toppane.title2_frame.schem_label.config(text = 'Verilog netlist:')
else:
self.toppane.title2_frame.schem_label.config(text = 'Schematic netlist:')
# Update layout button
if os.path.splitext(self.layout)[1] == '.mag':
self.toppane.title2_frame.schem_label.config(text = 'Layout:')
else:
self.toppane.title2_frame.schem_label.config(text = 'Layout netlist:')
# If there is a comparison file that post-dates both netlists, load it.
self.check_lvs()
return True
@@ -567,8 +585,8 @@ class LVSManager(ttk.Frame):
# load LVS results from comp.json
project_path = self.rootpath
project_name = self.project
layout_path = project_path + '/layout/' + project_name + '.spc'
net_path = project_path + '/netlist/' + project_name + '.spi'
layout_path = project_path + '/layout/' + project_name + '.spice'
net_path = project_path + '/netlist/' + project_name + '.spice'
comp_path = project_path + '/layout/comp.json'
if os.path.exists(layout_path) and os.path.exists(net_path) and os.path.exists(comp_path):
@@ -599,7 +617,7 @@ class LVSManager(ttk.Frame):
mproc.stdin.write("ext2spice cthresh infinite\n")
mproc.stdin.write("ext2spice rthresh infinite\n")
mproc.stdin.write("ext2spice blackbox on\n")
mproc.stdin.write("ext2spice -o " + self.layout + ".spi\n")
mproc.stdin.write("ext2spice -o " + self.layout + ".spice\n")
mproc.stdin.write("quit -noprompt\n")
magicout = mproc.communicate()[0]
self.printwarn(magicout)
@@ -607,8 +625,8 @@ class LVSManager(ttk.Frame):
print('Failure to generate new layout netlist.')
return False
# Move .spi netlist to project_dir/netlist/lvs/
shutil.move(project_path + '/layout/' + self.layout + '.spi', layout_path)
# Move .spice netlist to project_dir/netlist/lvs/
shutil.move(project_path + '/layout/' + self.layout + '.spice', layout_path)
# Remove extraction files
for file in os.listdir(project_path + '/layout'):
if os.path.splitext(file)[1] == '.ext':
@@ -625,17 +643,37 @@ class LVSManager(ttk.Frame):
project_path = self.rootpath
project_name = self.project
comp_path = project_path + '/layout/comp.json'
# Diagnostic:
print('project_name is ' + project_name)
print('project_path is ' + project_path)
print('self.layout is ' + self.layout)
print('self.schematic is ' + self.schematic)
print('self.lvs_setup is ' + self.lvs_setup)
has_vlog = False
vlog_path = project_path + '/verilog/' + project_name + '.v'
layout_path = project_path + '/netlist/lvs/' + self.layout + '.spi'
net_path = project_path + '/netlist/schem/' + self.schematic + '.spi'
layout_src = project_path + '/layout/' + self.layout + '.mag'
if os.path.isfile(self.layout):
layout_path = self.layout
layout_src = None
else:
layout_path = project_path + '/netlist/lvs/' + self.layout + '.spice'
layout_src = project_path + '/layout/' + self.layout + '.mag'
comp_dir = os.path.split(layout_path)[0]
comp_path = comp_dir + '/comp.json'
if os.path.isfile(self.schematic):
net_path = self.schematic
else:
net_path = project_path + '/netlist/schem/' + self.schematic + '.spice'
# Does the setup file exist (this is optional)?
if self.lvs_setup != '' and not os.path.isfile('setup.tcl'):
if self.lvs_setup == '' and not os.path.isfile('setup.tcl'):
print('No technology setup file selected.')
elif not os.path.isfile(self.lvs_setup):
print("Can't find technology setup file " + self.lvs_setup)
# Does schematic netlist exist?
if not os.path.isfile(vlog_path) and not os.path.isfile(net_path):
@@ -643,14 +681,16 @@ class LVSManager(ttk.Frame):
return
# Does LVS netlist subdirectory exist?
if not os.path.exists(project_path + '/netlist/lvs'):
os.makedirs(project_path + '/netlist/lvs')
if os.path.exists(project_path + '/netlist'):
if not os.path.exists(project_path + '/netlist/lvs'):
os.makedirs(project_path + '/netlist/lvs')
# Does layout netlist exist and is it current?
if not self.generate_layout_netlist(layout_path, layout_src, project_path):
return False
if layout_src:
if not self.generate_layout_netlist(layout_path, layout_src, project_path):
return False
# Final check
# Final checks
if not os.path.isfile(layout_path):
print('Error: No netlist generated from magic.')
return
@@ -662,26 +702,27 @@ class LVSManager(ttk.Frame):
with open(layout_path) as ifile:
spitext = ifile.read()
# spilines = spitext.replace(',', '|')
# with open(layout_path, 'w') as ofile:
# ofile.write(spilines)
# Check the netlist to see if the cell to match is a subcircuit. If
# not, then assume it is the top level.
layoutcell = os.path.splitext(os.path.split(self.layout)[1])[0]
is_subckt = False
subname = None
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
dutlines = spitext.replace('\n+', ' ').splitlines()
for line in dutlines:
lmatch = subrex.match(line)
if lmatch:
subname = lmatch.group(1)
if subname == self.layout:
if subname == layoutcell:
is_subckt = True
break
if is_subckt:
layout_arg = layout_path + ' ' + self.layout
layout_arg = self.layout + ' ' + layoutcell
layout_text = '"' + layout_arg + '"'
elif subname:
layout_arg = self.layout + ' ' + subname
layout_text = '"' + layout_arg + '"'
else:
layout_arg = layout_path
@@ -690,8 +731,39 @@ class LVSManager(ttk.Frame):
if has_vlog:
schem_arg = vlog_path + ' ' + self.schematic
else:
schem_arg = net_path + ' ' + self.schematic
schem_text = '"' + schem_arg + '"'
# Final checks
if not os.path.isfile(net_path):
print('Error: No netlist from schematic.')
return
with open(net_path) as ifile:
spitext = ifile.read()
# Check the netlist to see if the cell to match is a subcircuit. If
# not, then assume it is the top level.
schemcell = os.path.splitext(os.path.split(self.schematic)[1])[0]
subname = None
is_subckt = False
subrex = re.compile('^[^\*]*[ \t]*.subckt[ \t]+([^ \t]+).*$', re.IGNORECASE)
dutlines = spitext.replace('\n+', ' ').splitlines()
for line in dutlines:
lmatch = subrex.match(line)
if lmatch:
subname = lmatch.group(1)
if subname == schemcell:
is_subckt = True
break
if is_subckt:
schem_arg = self.schematic + ' ' + schemcell
schem_text = '"' + schem_arg + '"'
elif subname:
schem_arg = self.schematic + ' ' + subname
schem_text = '"' + schem_arg + '"'
else:
schem_arg = net_path
schem_text = schem_arg
# Remove any previous comparison output file
comp_out_path = os.path.splitext(comp_path)[0] + '.out'
@@ -708,7 +780,7 @@ class LVSManager(ttk.Frame):
self.lvsproc = subprocess.Popen(['netgen', '-batch', 'lvs',
layout_arg, schem_arg,
self.lvs_setup, comp_out_path, '-json', '-blackbox'],
cwd=project_path + '/layout',
cwd=comp_dir,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0)
# This is largely unnecessary as netgen usually runs to completion very quickly.
self.watchclock(comp_path)
+699 -418
View File
File diff suppressed because it is too large Load Diff
+1487 -1430
View File
File diff suppressed because it is too large Load Diff
+20 -3
View File
@@ -712,6 +712,7 @@ infodir
docdir
oldincludedir
includedir
runstatedir
localstatedir
sharedstatedir
sysconfdir
@@ -794,6 +795,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1046,6 +1048,15 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
-runstatedir | --runstatedir | --runstatedi | --runstated \
| --runstate | --runstat | --runsta | --runst | --runs \
| --run | --ru | --r)
ac_prev=runstatedir ;;
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
| --run=* | --ru=* | --r=*)
runstatedir=$ac_optarg ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1183,7 +1194,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir
libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@@ -1336,6 +1347,7 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@@ -6065,7 +6077,6 @@ fi
if test $usingTcl ; then
usingX11=1
cadinstall="$cadinstall tcltk"
modules="$modules tcltk"
programs="$programs tcltk"
@@ -6075,7 +6086,11 @@ if test $usingTcl ; then
extra_libs="$extra_libs \${NETGENDIR}/tcltk/libtcltk.o"
extra_defs="$extra_defs -DTCL_DIR=\\\"\${TCLDIR}\\\""
stub_defs="$stub_defs -DUSE_TCL_STUBS -DUSE_TK_STUBS"
if test $usingX11 ; then
stub_defs="$stub_defs -DUSE_TCL_STUBS"
else
stub_defs="$stub_defs -DUSE_TCL_STUBS -DUSE_TK_STUBS"
fi
else
programs="$programs netgen"
unused="$unused tcltk"
@@ -6160,6 +6175,7 @@ if test $usingTcl ; then
# Tk libraries and header files
#
# -----------------------------------------------------------------------
if test $usingX11 ; then
if test "${TK_INC_DIR}" != "/usr/include" ; then
INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}"
fi
@@ -6176,6 +6192,7 @@ if test $usingTcl ; then
loader_run_path="${TK_LIB_DIR}:${loader_run_path}"
fi
fi
fi
# -----------------------------------------------------------------------
#
+7 -2
View File
@@ -807,7 +807,6 @@ dnl "make" instead of requiring "make tcl"
dnl ----------------------------------------------------------------
if test $usingTcl ; then
usingX11=1
cadinstall="$cadinstall tcltk"
modules="$modules tcltk"
programs="$programs tcltk"
@@ -816,7 +815,11 @@ if test $usingTcl ; then
AC_DEFINE(TCL_NETGEN)
extra_libs="$extra_libs \${NETGENDIR}/tcltk/libtcltk.o"
extra_defs="$extra_defs -DTCL_DIR=\\\"\${TCLDIR}\\\""
stub_defs="$stub_defs -DUSE_TCL_STUBS -DUSE_TK_STUBS"
if test $usingX11 ; then
stub_defs="$stub_defs -DUSE_TCL_STUBS"
else
stub_defs="$stub_defs -DUSE_TCL_STUBS -DUSE_TK_STUBS"
fi
else
programs="$programs netgen"
unused="$unused tcltk"
@@ -903,6 +906,7 @@ if test $usingTcl ; then
# Tk libraries and header files
#
# -----------------------------------------------------------------------
if test $usingX11 ; then
if test "${TK_INC_DIR}" != "/usr/include" ; then
INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}"
fi
@@ -919,6 +923,7 @@ if test $usingTcl ; then
loader_run_path="${TK_LIB_DIR}:${loader_run_path}"
fi
fi
fi
# -----------------------------------------------------------------------
#
File diff suppressed because it is too large Load Diff
+123 -89
View File
@@ -62,16 +62,18 @@ proc netgen::convert_to_json {filename lvs_final} {
puts $fjson " \["
set cktval [lindex $value 0]
foreach pin [lrange $cktval 0 end-1] {
puts $fjson " \"$pin\","
set pinstr [string map {"\\" "\\\\"} $pin]
puts $fjson " \"$pinstr\","
}
set pin [lindex $cktval end]
set pin [string map {"\\" "\\\\"} [lindex $cktval end]]
puts $fjson " \"$pin\""
puts $fjson " \], \["
set cktval [lindex $value 1]
foreach pin [lrange $cktval 0 end-1] {
puts $fjson " \"$pin\","
set pinstr [string map {"\\" "\\\\"} $pin]
puts $fjson " \"$pinstr\","
}
set pin [lindex $cktval end]
set pin [string map {"\\" "\\\\"} [lindex $cktval end]]
puts $fjson " \"$pin\""
puts $fjson " \]"
if {$kidx == $nkeys} {
@@ -393,7 +395,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
# If argument is a filename then read the list of cells from it;
# otherwise, argument is the list of files itself in quotes or
# braces.
if {![catch {file exists $value}]} {
if {[file exists $value]} {
if {![catch {open $value r} fnf]} {
while {[gets $fnf line] >= 0} {
if {[lindex $line 0] != "#"} {
@@ -477,8 +479,12 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
netgen::compare assign "$fnum1 $cell1" "$fnum2 $cell2"
if {[file exists $setupfile]} {
puts stdout "Reading setup file $setupfile"
if {$setupfile == ""} {
puts stdout "\nNo setup file specified. Using trivial default setup.\n"
netgen::permute default ;# transistors and resistors
netgen::property default
} elseif {[file exists $setupfile]} {
puts stdout "\nReading setup file $setupfile\n"
# Instead of sourcing the setup file, run each line so we can
# catch individual errors and not let them halt the LVS process
set perrors 0
@@ -506,8 +512,10 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
puts stdout "Warning: There were errors reading the setup file"
}
} elseif {[string first nosetup $setupfile] < 0} {
netgen::permute default ;# transistors and resistors
netgen::property default
puts stderr "\nError: Setup file $setupfile does not exist.\n"
return
} else {
puts stderr "\nNo setup file specified. Continuing without a setup.\n"
}
if {[string first nolog $logfile] < 0} {
@@ -532,14 +540,24 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
}
set properr {}
set matcherr {}
set pinsgood 0
set childMismatch 0 ;# 1 indicates black-box child subcircuit mismatch
while {$endval != {}} {
if {$dolist == 1} {
netgen::run -list converge
} else {
netgen::run converge
}
netgen::log echo on
set pinMismatch 0 ;# indicates pin mismatch in top cell
set doCheckFlatten 0
set doFlatten 0
if {[netgen::print queue] == {}} {
set doEquatePins 1 ;# run equate pins on top cell
} else {
set doEquatePins 0 ;# don't run equate pins unless unique match
}
set forceMatch 0 ;# for pin matching
netgen::log echo off
if {[verify equivalent]} {
# Resolve automorphisms by pin and property
if {$dolist == 1} {
@@ -548,93 +566,105 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
netgen::run resolve
}
set uresult [verify unique]
# uresult: -3 : unique with property error
# -2 : equivalent with port errors
# -1 : black box
# 0 : equivalent but not unique
# 1 : unique
if {$uresult == 0} {
netgen::log echo on
netgen::log put " Networks match locally but not globally.\n"
netgen::log put " Probably connections are swapped.\n"
netgen::log put " Check the end of logfile ${logfile} for implicated nodes.\n"
netgen::log echo off
if {$dolist == 1} {
verify -list nodes
} else {
verify nodes
}
# Flatten the non-matching subcircuit (but not the top-level cells)
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::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]
# Match pins
netgen::log echo off
if {$dolist == 1} {
set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
} else {
set result [equate -force pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
}
if {$result != 0} {
equate classes "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"
}
set pinsgood $result
netgen::log echo on
}
}
set doCheckFlatten 1
} else {
# Match pins
netgen::log echo off
if {$dolist == 1} {
set result [equate -list pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
} else {
set result [equate pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
}
if {$result != 0} {
equate classes "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"
}
set pinsgood $result
netgen::log echo on
# Equate pins for black boxes, unique matches (possibly with property
# errors), and unique with port errors
set doEquatePins 1
}
if {$uresult == -1} { ;# black box
set forceMatch 1
} elseif {$uresult == -3} { ;# property error
lappend properr [lindex $endval 0]
} elseif {$uresult == -2} { ;# unmatched pins
set doCheckFlatten 1
}
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) &&
([lsearch $noflat [lindex $endval 1]] == -1)} {
netgen::log put " Flattening non-matched subcircuits $endval"
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]
# Match pins
netgen::log echo off
if {$dolist == 1} {
set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
} else {
set result [equate -force pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
}
if {$result != 0} {
equate classes "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"
}
set pinsgood $result
netgen::log echo on
# not equivalent
netgen::log echo on
# netgen::log put " DEBUG: not equivalent $endval\n"
netgen::log echo off
set doCheckFlatten 1
}
if {$doCheckFlatten} {
# Flatten the non-matching subcircuit (but not the top-level cell,
# or cells explicitly prohibited from flattening)
if {[netgen::print queue] != {}} {
if {([lsearch $noflat [lindex $endval 0]] == -1) &&
([lsearch $noflat [lindex $endval 1]] == -1)} {
set doFlatten 1
} else {
netgen::log echo on
netgen::log put " Continuing with black-boxed subcircuits $endval\n"
netgen::log echo off
lappend matcherr [lindex $endval 0]"($fnum1)"
lappend matcherr [lindex $endval 1]"($fnum2)"
netgen::flatten prohibit "[lindex $endval 0] $fnum1"
netgen::flatten prohibit "[lindex $endval 1] $fnum2"
set doEquatePins 1
set childMismatch 1
set forceMatch 1
}
}
}
netgen::log echo off
if {$doEquatePins} {
# Match pins
if {$dolist == 1} {
if {$forceMatch} {
set result [equate -list -force pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
} else {
set result [equate -list pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
}
} else {
if {$forceMatch} {
set result [equate -force pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
} else {
set result [equate pins "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"]
}
}
if {$result >= 0} {
equate classes "$fnum1 [lindex $endval 0]" \
"$fnum2 [lindex $endval 1]"
}
# Do not set pinMismatch for black boxes
if {$result < 0} {
if {$result == -1 && [netgen::print queue] != {} && $forceMatch != 1} {
# flatten pin mismatch, but not empty cells (-2) or top cell or
# cells prohibited from flattening.
set doFlatten 1
}
} elseif {[netgen::print queue] == {} && $result == 0} {
set pinMismatch 1
}
}
if {$doFlatten} {
netgen::log echo on
netgen::log put " Flattening non-matched subcircuits $endval\n"
netgen::log echo off
netgen::flatten class "[lindex $endval 0] $fnum1"
netgen::flatten class "[lindex $endval 1] $fnum2"
}
if {$dolist == 1} {
catch {lappend lvs_final $lvs_out}
set lvs_out {}
@@ -643,19 +673,23 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
set endval [netgen::compare hierarchical]
}
}
netgen::log echo off
puts stdout "Result: " nonewline
netgen::log echo on
if {$pinsgood == 0} {
netgen::log put "The top level cell failed pin matching.\n"
netgen::log put "\nFinal result: "
if {$pinMismatch || $childMismatch} {
if {$childMismatch} {
netgen::log put "Subcell(s) failed matching.\n"
}
if {$pinMismatch} {
netgen::log put "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 "\nThe 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 "\nThe following subcells failed to match:\n " [regsub -all { } $matcherr "\n "] "\n"
}
if {$dolog} {
netgen::log end
+192 -56
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);
@@ -1053,6 +1056,12 @@ _netgen_flatten(ClientData clientData,
FlattenInstancesOf(repstr, filenum);
}
}
else if (!strcmp(argv, "prohibit") || !strcmp(argv, "deny")) {
tp = GetTopCell(filenum);
Printf("Will not flatten instances of %s in file %s\n", repstr, tp->name);
/* Mark cell as placeholder so it will not be flattened */
tp->flags |= CELL_PLACEHOLDER;
}
else {
Tcl_WrongNumArgs(interp, 1, objv, "class valid_cellname");
return TCL_ERROR;
@@ -1928,9 +1937,17 @@ _netgen_log(ClientData clientData,
switch(index) {
case START_IDX:
LoggingFile = fopen(LogFileName, "w");
if (!LoggingFile) {
Tcl_SetResult(interp, "Could not open log file.", NULL);
return TCL_ERROR;
}
break;
case RESUME_IDX:
LoggingFile = fopen(LogFileName, "a");
if (!LoggingFile) {
Tcl_SetResult(interp, "Could not open log file.", NULL);
return TCL_ERROR;
}
break;
case END_IDX:
fclose(LoggingFile);
@@ -1939,6 +1956,10 @@ _netgen_log(ClientData clientData,
case RESET_IDX:
fclose(LoggingFile);
LoggingFile = fopen(LogFileName, "w");
if (!LoggingFile) {
Tcl_SetResult(interp, "Could not open log file.", NULL);
return TCL_ERROR;
}
break;
case SUSPEND_IDX:
fclose(LoggingFile);
@@ -2066,6 +2087,7 @@ _netcmp_format(ClientData clientData,
Tcl_WrongNumArgs(interp, 1, objv, "[col1_width [col2_width]]");
return TCL_ERROR;
}
return TCL_OK;
}
/*------------------------------------------------------*/
@@ -2091,8 +2113,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 +2158,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 +2214,40 @@ _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, "\nCircuit 2 cell %s is a black box; will not flatten "
"Circuit 1\n", name2);
}
else if (hascontents2 && !hascontents1 && (tp1->flags & CELL_PLACEHOLDER)) {
Fprintf(stdout, "\nCircuit 1 cell %s is a black box; will not flatten "
"Circuit 2\n", name1);
}
else if (!hascontents1 && !hascontents2 && (tp1->flags & CELL_PLACEHOLDER)
&& (tp2->flags & CELL_PLACEHOLDER)) {
/* Two empty subcircuits, don't flatten anything */
Fprintf(stdout, "\nCircuit 1 cell %s and Circuit 2 cell %s are black"
" boxes.\n", name1, name2);
}
else {
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 +2480,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,40 +2500,40 @@ _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");
else if (automorphisms == 0)
Fprintf(stdout, "Netlists match uniquely.\n");
else {
if (automorphisms > 0) {
// First try to resolve automorphisms uniquely using
// property matching
automorphisms = ResolveAutomorphsByProperty();
if (automorphisms == 0)
Fprintf(stdout, "Netlists match uniquely.\n");
else if (automorphisms > 0) {
if (automorphisms > 0) {
// Next, attempt to resolve automorphisms uniquely by
// using the pin names
automorphisms = ResolveAutomorphsByPin();
}
if (automorphisms == 0)
Fprintf(stdout, "Netlists match uniquely.\n");
else if (automorphisms > 0) {
if (automorphisms > 0) {
// Anything left is truly indistinguishable
Fprintf(stdout, "Netlists match with %d symmetr%s.\n",
automorphisms, (automorphisms == 1) ? "y" : "ies");
while ((automorphisms = ResolveAutomorphisms()) > 0);
while (ResolveAutomorphisms() > 0);
}
if (automorphisms == -1)
Fprintf(stdout, "Netlists do not match.\n");
else
Fprintf(stdout, "Circuits match correctly.\n");
}
if (PropertyErrorDetected) {
Fprintf(stdout, "There were property errors.\n");
PrintPropertyResults(dolist);
if (automorphisms == -1)
Fprintf(stdout, "Netlists do not match.\n");
else if (automorphisms == -2)
Fprintf(stdout, "Netlists match uniquely with port errors.\n");
else {
if (automorphisms == 0)
Fprintf(stdout, "Netlists match uniquely");
else
Fprintf(stdout, "Netlists match with %d symmetr%s",
automorphisms, (automorphisms == 1) ? "y" : "ies");
if (PropertyErrorDetected) {
Fprintf(stdout, " with property errors.\n");
PrintPropertyResults(dolist);
}
else
Fprintf(stdout, ".\n");
}
disable_interrupt();
}
@@ -2497,8 +2551,14 @@ _netcmp_run(ClientData clientData,
/* all, or no option. */
/* Formerly: v */
/* Results: */
/* For only, equivalent, unique: Return 1 if */
/* verified, zero if not. */
/* For only, equivalent, unique: Return */
/* 1: verified */
/* 0: not verified */
/* -1: no elements or nodes */
/* -3: verified with property error */
/* equiv option */
/* -2: pin mismatch */
/* */
/* Side Effects: */
/* For options elements, nodes, and all without */
/* option -list: Write output to log file. */
@@ -2592,13 +2652,21 @@ _netcmp_verify(ClientData clientData,
else
Fprintf(stdout, "Netlists do not match.\n");
}
else if (automorphisms == -2) {
if (index == EQUIV_IDX)
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
else if (index == UNIQUE_IDX)
Tcl_SetObjResult(interp, Tcl_NewIntObj(-2));
else if (index > 0)
Fprintf(stdout, "Circuits match uniquely with port errors.\n");
}
else {
if (automorphisms) {
if (index == EQUIV_IDX)
Tcl_SetObjResult(interp, Tcl_NewIntObj((int)automorphisms));
else if (index == UNIQUE_IDX)
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
else
else if (index > 0)
Printf("Circuits match with %d symmetr%s.\n",
automorphisms, (automorphisms == 1) ? "y" : "ies");
}
@@ -2607,11 +2675,13 @@ _netcmp_verify(ClientData clientData,
if (PropertyErrorDetected == 0)
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
else
Tcl_SetObjResult(interp, Tcl_NewIntObj(2));
Tcl_SetObjResult(interp, Tcl_NewIntObj(-3));
}
else {
else if (index > 0) {
Fprintf(stdout, "Circuits match uniquely.\n");
if (PropertyErrorDetected != 0)
if (PropertyErrorDetected == 0)
Fprintf(stdout, ".\n");
else
Fprintf(stdout, "Property errors were found.\n");
}
}
@@ -2832,7 +2902,7 @@ _netcmp_equate(ClientData clientData,
struct ElementClass *saveEclass = NULL;
struct NodeClass *saveNclass = NULL;
int file1, file2;
int i, l1, l2, ltest, lent, dolist = 0, doforce = 0;
int i, l1, l2, ltest, lent, dolist = 0, doforce = 0, dounique = 0;
Tcl_Obj *tobj1, *tobj2, *tobj3;
while (objc > 1) {
@@ -2848,6 +2918,11 @@ _netcmp_equate(ClientData clientData,
objv++;
objc--;
}
else if (!strcmp(optstart, "unique")) {
dounique = 1;
objv++;
objc--;
}
else
break;
}
@@ -3023,18 +3098,22 @@ _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.
tp1->flags |= CELL_PLACEHOLDER;
tp2->flags |= CELL_PLACEHOLDER;
}
else {
else if (doforce != TRUE) {
/* When doforce is TRUE, ElementClass has been set to NULL
* even though circuits contain elements, so this message
* is not correct.
*/
Fprintf(stdout, "Equate pins: cell %s and/or %s "
"has no elements.\n", name1, name2);
/* This is not necessarily an error, so go ahead and match pins. */
@@ -3066,6 +3145,13 @@ _netcmp_equate(ClientData clientData,
else if (result > 0) {
Fprintf(stdout, "Cell pin lists are equivalent.\n");
}
else if (result == -1) {
Fprintf(stdout, "Cell pin lists for %s and %s do not match.\n",
name1, name2);
}
else if (result == -2) {
Fprintf(stdout, "Attempt to match empty cell to non-empty cell.\n");
}
else {
Fprintf(stdout, "Cell pin lists for %s and %s altered to match.\n",
name1, name2);
@@ -3261,19 +3347,9 @@ _netcmp_equate(ClientData clientData,
return TCL_ERROR;
}
}
/* Now that all pins are assigned by name, reorder */
/* the pin lists of the 2nd cell to match the */
/* order of the 1st. */
/* Reorder the pin lists of instances of the 2nd */
/* cell to match the order of the 1st. */
// pindata.cell2 = tp2;
// RecurseCellHashTable2(pinorder, (void *)(&pindata));
}
if (EquivalenceClasses(tp1->name, file1, tp2->name, file2)) {
if (EquivalenceClasses(tp1->name, file1, tp2->name, file2, dounique)) {
Fprintf(stdout, "Device classes %s and %s are equivalent.\n",
tp1->name, tp2->name);
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
@@ -3296,6 +3372,8 @@ _netcmp_equate(ClientData clientData,
/* add --- add new property */
/* remove --- delete existing property */
/* tolerance --- set property tolerance */
/* associate --- associate property with a pin */
/* topology --- set exact/relaxed matching */
/* merge --- (deprecated) */
/* or */
/* netgen::property default */
@@ -3334,11 +3412,11 @@ _netcmp_property(ClientData clientData,
char *options[] = {
"add", "create", "remove", "delete", "tolerance", "merge", "serial",
"series", "parallel", NULL
"series", "parallel", "associate", "topology", NULL
};
enum OptionIdx {
ADD_IDX, CREATE_IDX, REMOVE_IDX, DELETE_IDX, TOLERANCE_IDX, MERGE_IDX,
SERIAL_IDX, SERIES_IDX, PARALLEL_IDX
SERIAL_IDX, SERIES_IDX, PARALLEL_IDX, ASSOCIATE_IDX, TOPOLOGY_IDX
};
int result, index, idx2;
@@ -3383,6 +3461,10 @@ _netcmp_property(ClientData clientData,
return TCL_ERROR;
}
char *topo[] = {
"strict", "relaxed", NULL
};
/* Check for special command "property default" */
if ((objc == 2) && (!strcmp(Tcl_GetString(objv[1]), "default"))) {
@@ -3468,6 +3550,36 @@ _netcmp_property(ClientData clientData,
}
return TCL_OK;
}
else if ((objc > 1) && (!strcmp(Tcl_GetString(objv[1]), "topology"))) {
if (objc == 2) {
if (ExactTopology)
Tcl_SetResult(interp, "Strict topology property matching.",
NULL);
else
Tcl_SetResult(interp, "Relaxed topology property matching.",
NULL);
}
else if (objc == 3) {
if (Tcl_GetIndexFromObj(interp, objv[2],
(CONST84 char **)topo,
"topology", 0, &idx2) == TCL_OK) {
if (idx2 == 0)
ExactTopology = TRUE;
else if (idx2 == 1)
ExactTopology = FALSE;
else {
Tcl_SetResult(interp, "Topology matching type must be "
"'strict' or 'relaxed'.", NULL);
return TCL_ERROR;
}
}
}
else {
Tcl_WrongNumArgs(interp, 1, objv, "strict|relaxed");
return TCL_ERROR;
}
return TCL_OK;
}
result = CommonParseCell(interp, objv[1], &tp, &fnum);
if (result != TCL_OK) return result;
@@ -3761,6 +3873,29 @@ _netcmp_property(ClientData clientData,
}
break;
case ASSOCIATE_IDX:
if (objc == 3) {
Tcl_WrongNumArgs(interp, 1, objv, "{property_key pin_name} ...");
return TCL_ERROR;
}
for (i = 3; i < objc; i++) {
// Each value must be a duplet
result = Tcl_ListObjLength(interp, objv[i], &llen);
if ((result != TCL_OK) || (llen != 2)) {
Tcl_SetResult(interp, "Not a {key pin} pair list.",
NULL);
}
else {
result = Tcl_ListObjIndex(interp, objv[i], 0, &tobj1);
if (result != TCL_OK) return result;
result = Tcl_ListObjIndex(interp, objv[i], 1, &tobj2);
if (result != TCL_OK) return result;
PropertyAssociatePin(tp->name, fnum, Tcl_GetString(tobj1),
Tcl_GetString(tobj2));
}
}
break;
case TOLERANCE_IDX:
if (objc == 3) {
Tcl_WrongNumArgs(interp, 1, objv, "{property_key tolerance} ...");
@@ -3860,6 +3995,7 @@ _netcmp_property(ClientData clientData,
}
}
break;
}
}
return TCL_OK;