Compare commits

...

116 Commits

Author SHA1 Message Date
R. Timothy Edwards e1528a797c Corrected the parsing for assignment left-hand-side to allow for
whitespace inside the array declaration, as was (correctly) done
for pin connections.  Previously, "assign x[ 0] = 1'b1" would
fail due to "x[" being parsed as a token by itself.  Now, upon
reading an array opening bracket delimiter, the verilog parser
will continue to read tokens until it finds the closing bracket,
as it does for pin connections.
2026-07-06 10:22:02 -04:00
R. Timothy Edwards 2c94087510 Corrected an error in delimiter parsing, which is due to the lack of
any standard array delimiter character in SPICE.  Often brackets are
used, but just as often angle brackets are used instead, and do not
match the bracket syntax of verilog.  The "matchnocase" function
automatically casts common delimiter characters to a single type to
facilitate matching between names using different delimiters.
However, some code in MatchPins() was assuming square brackets and
breaking this allowance, causing pins to be marked mismatch in spite
of the handling in "matchnocase".  The code has been corrected to
make the same allowance for different delimiter characters everywhere.
2026-06-28 11:44:42 -04:00
R. Timothy Edwards 3eadc8b0dc Corrected some issues in the SPICE parser where a subcircuit name
was checked using "subcktname" before its initialization.  Added
a check for a subcircuit called inside itself, which causes an
immediate failure (see issue tracker issue #106).  If allowed to
continue, netgen will either crash or produce inscrutable output
that doesn't pinpoint the issue.
2026-06-08 14:11:07 -04:00
R. Timothy Edwards 9630670071 The example cited in the last commit is not completely solved by
the code changes in the last commit.  There is still an issue in
which pins should match between name X on one side and X[Y] on
the other side, if there is no X[Z] where Z != Y, specifically if
one or both cells is a black box, since the equivalence cannot
be determined by net matching.

The pin matching has gotten out of hand and really should be
completely redone. . .
2026-05-21 15:35:57 -04:00
R. Timothy Edwards f29452e550 An example found by Leo Moser showed that netgen makes an incorrect
pin assignment when a verilog input file declares a signal "bundle"
with only one signal in it.  The solution is to detect bundles which
have only one component in them, and remove the bundle delimiters
("{...}") so that the pin connection is treated as a simple signal
or vector.
2026-05-21 14:19:24 -04:00
R. Timothy Edwards 8a2bbe0723 Updated version to go along with PR #105 from user jalcim on github. 2026-04-27 09:50:37 -04:00
jalcim a0c49a026a
fix(netcmp): correct signal handler type for K&R declaration
netcmp.c:55 declares oldinthandler with empty parameter list:
    void (*oldinthandler)() = SIG_DFL;

In K&R / pre-C23, this means 'function with unspecified parameters'.
GCC 14+ infers void(*)(void), which is incompatible with signal(2)'s
expected void(*)(int) handler. The signal(SIGINT, oldinthandler) calls
at lines 8777 and 8784 then fail with -Wincompatible-pointer-types
(now a default error in GCC 14+).

This 1-line fix matches the actual usage as a SIGINT handler with int
signum parameter, and restores tclnetgen.so build on Fedora 41+ /
Debian 13+ / Ubuntu 24.04+ (any system with GCC 14+).

Tested: tclnetgen.so now builds successfully and 'netgen -batch lvs'
mode works again.
2026-04-26 22:06:07 +02:00
R. Timothy Edwards 665203bba1 Corrected genhash() after Mitch Bailey pointed out that the function
was no longer hashing on both values passed to the function, as it
is supposed to.
2026-04-03 08:48:34 -04:00
R. Timothy Edwards 0192558d4b Updated version corresponding to the last commit. 2026-04-02 21:30:01 -04:00
R. Timothy Edwards 21d329b22d Modified the hash algorithm used by netgen after a discussion with
ChatGPT about hash implementations.  Switched from SDBM to FNV-1a,
which should be a better/stronger hash algorithm.  Could do
something more sophisticated, but this change can be done in a few
minutes.
2026-04-02 21:29:04 -04:00
R. Timothy Edwards 37b1a2a07d Cleaned up some errors (most minor, some not so minor) in the
code that were surfaced by Stefan Thiede running clang on Mac
OS.  Function prototype warnings have not been fixed yet, as
that is a more involved fix, although it needs to be done.
2026-02-02 20:53:13 -05:00
R. Timothy Edwards 777f7ef095 Found a counting issue with netcmp output that will overrun the
output string buffer if the size of the copied string is just
the wrong amount, due to the use of strcpy() instead of
strncpy() in at least one place.  Just hacked a solution by
allocating more space for the string, but this should be fixed
properly.  Also:  Discovered that the "zero valued resistor"
routine looks for shorted ports in the wrong place, and if it
finds shorted ports it wrongly decides that the device it's
looking at is a zero-valued resistor whether or not it really
is zero-valued.
2026-01-15 16:39:18 -05:00
R. Timothy Edwards 9b4185fe62 Reverted a change from a long time ago regarding removal of zero
valued resistors connecting two ports.  I do not recall exactly
why I put that in but it appears to cause incorrect behavior.
2025-12-28 14:54:07 -05:00
R. Timothy Edwards ddd95c4fe6 Added a few lines to the setup file parser so that if there is a
missing brace in the file (a common error), then the fact that
there is an unevaluated command when the file has finished being
read will trigger an evaluation of the unfinished code and emit
an error.  Previously, the command and anything after the
unterminated brace would just silently get ignored, which was not
helpful for debugging setup syntax errors.
2025-12-11 12:08:31 -05:00
R. Timothy Edwards c0c9993980 Corrected a major error with the verilog parser. The verilog
parser was not assigning the correct file number for the first
input file, which resulted in the effect that if the first
file read sets definitions for the netlist, then those definitions
are wiped out on the following file read.  There has been a workaround
to read from /dev/null on the first file read so that the file number
is set on all subsequent reads.  This fix avoids the need for the
workaround.
2025-12-08 16:45:27 -05:00
R. Timothy Edwards 8a20b90074 Corrected an issue that can cause a segfault in an incorrect run
setup when a cell has no pins.  Didn't really analyze the error
condition, just caught and handled the condition to avoid the
segfault.
2025-12-08 13:09:50 -05:00
R. Timothy Edwards 3392159243 Added some extra code to the verilog parser. It now handles some
additional syntax for wire bundles specified as a pin connection
on an array of instances, and a few other things.  These are not
exhaustive but are solving an immediate problem.  I will go back
and clean up the code to make it work for more general cases
later.
2025-11-29 11:55:26 -05:00
R. Timothy Edwards 24c6eb4cb9 Updated the version to go along with the merge of pull request 2025-11-24 12:26:57 -05:00
Mitch Bailey 9048191486 Allow processing of cellnames with $.
When loading a file, also print cellname on errors

Signed-off-by: Mitch Bailey <d.mitch.bailey@gmail.com>
2025-11-24 12:26:30 -05:00
R. Timothy Edwards 72d7d55bbe Corrected an issue with the "-noflatten" switch to "lvs", which is
also a problem with the underlying "flatten prohibit" command
option;  in one place, the cell's subcircuits were being prohibited
from being flattened, causing issues including a potential infinite
loop.
2025-11-21 15:52:14 -05:00
R. Timothy Edwards 04163aedcc One hopefully final modification to ensure that Tcl_InitStubs()
uses the Tcl version that the program has been compiled to.  This
should work with both Tcl 8.X and Tcl 9.X.
2025-11-12 11:32:18 -05:00
R. Timothy Edwards f7d35f9cca Accidentally changed a file in the last commit which gets
overwritten by "configure".  Moved the modification to the source
file that doesn't get overwritten.
2025-11-12 09:55:29 -05:00
R. Timothy Edwards 601277e539 Updated the revision number for the last set of changes. 2025-11-12 09:19:52 -05:00
R. Timothy Edwards 73344329f8 Made some updates for Tcl 9 compatibility; also changed the
Makefile to pass EXTRA_CFLAGS for testing with "-std=c99" and
"-std=gnu99".  Made some additional corrections to ensure a
clean compile using -std=gnu99.
2025-11-12 09:17:46 -05:00
R. Timothy Edwards 08485d28a7 Changed CONST and CONST84 everywhere in tclnetgen.c to "const".
The capitalized version of this got removed from the Tcl headers
as some point and is no longer valid.  Added an include of
"strings.h" to base/actel.c, which was missing it (uses
strcasecmp() in the code, and needs the function declaration).
2025-11-11 09:59:14 -05:00
R. Timothy Edwards 2ee286efb4 Corrected the pin permutation check for pin matching; previously,
this was not doing the correct cross-check, instead looking in the
same netlist for the permutable pin and checking its node number,
which is useless since the node number is the same by definition
for permutable pins.  This error would result in occasional false
negative results during pin matching, showing matching where pins
are actually not matched.
2025-11-07 14:06:22 -05:00
R. Timothy Edwards dae6919d4f Updating the version to go along with the merge of pull request 2025-10-23 09:54:36 -04:00
D. Mitch Bailey 017bdc6e48 Changed nested to static variable. Otherwise gets reset with each line.
Signed-off-by: D. Mitch Bailey <d.mitch.bailey@gmail.com>
2025-10-23 08:30:08 +00:00
R. Timothy Edwards b371af9235 Corrected an error that was assumed to have been fixed three years
ago (and may have been, but only under limited circumstances).  Do
to several errors, using "-noflatten" on the command line and using
"flatten prohibit" in a script would not prevent cells from being
flattened;  the "-noflatten" list needed to be used to call "flatten
prohibit", and "flatten prohibit" needed to be fixed to flag the
specified cell instead of the top level cell where it exists.
2025-10-22 10:43:00 -04:00
R. Timothy Edwards b5432d139b Corrected a corner-case where a module with no ports in verilog
was creating an implicit net for the stand-in "(no pins)" port.
2025-10-09 10:36:41 -04:00
R. Timothy Edwards 0e958bd45c Corrected an issue in which black-box entries (such as low-level
subcircuit devices) do not output information about mismatched
pins.  This can end up being treated as a non-error but the
mismatch should be noted in the output regardless.
2025-10-08 10:03:35 -04:00
R. Timothy Edwards b59196fa81 Modified the SPICE file read routine to accept the CDL syntax
"*.GLOBAL" as equivalent to ".GLOBAL".  Corrected the property
matching to handle property combination when no "critical"
property is given.  Critical properties exist when one property
must remain constant and equal for other properties to combine,
such as transistor length.  But, for example, capacitors can
combine area without any restriction based on another property.
Also, corrected the property matching code to allow more than
one property to be additive (example:  capacitor area and
perimeter).  Corrected the equation for adding properties in
parallel combination.
2025-10-02 12:33:28 -04:00
R. Timothy Edwards 6e6e9fb73f Added code to catch and print an error in connectivity between a
port and an internal node which can be missed when pin permutations
are present.  Previously, that could produce a situation where
netgen would report a "port error" but otherwise list all ports
as matching.  Because the permutation handling makes this hard to
detect while generating pin correspondence output, the non-matching
pins are listed separately at the end, and only if no mismatch was
detected during output.
2025-09-09 13:45:29 -04:00
R. Timothy Edwards e84700a607 Added a NULL check at one point in the SPICE read routine that
prevents a segfault under some condition (not fully investigated)
involving .include files.  Appears to resolve the problem without
any unintended consequences.
2025-08-31 16:52:35 -04:00
R. Timothy Edwards 0bee21ccc8 Corrected an issue in which a property error in a subcell would not
be reported at the end if there was a port error.  This is important
because port errors often resolve themselves, but the cell should not
be reported clean if the port errors resolved but it had property
errors.  Also:  Added a method to derive area and/or perimeter
properties from length and width, so that capacitors can be combined
in parallel without regard to which dimension is width and which is
length.  This feature has only been lightly tested.
2025-08-26 17:47:46 -04:00
R. Timothy Edwards c269f1de89 Corrected an unexpected corner-case error in which if a newline in
a spice netlist falls exactly on the last non-null position of the
input buffer after the buffer has been expanded to accept more
input data, then the next line gets read in automatically, and
the newline gets treated as whitespace and not a newline.
2025-08-25 10:31:19 -04:00
R. Timothy Edwards 4443826f9e Corrected a place in netcmp.c where a new instance net connection
is created without setting the cell name or instance name.  That
can cause a crash condition when attempting to locate the instance
from the net record.
2025-08-18 10:37:36 -04:00
R. Timothy Edwards a60dac6124 Modified the primary SPICE token reading routine so that the call
to strdtok() can differentiate between reading verilog and reading
SPICE.  Otherwise, SPICE containing the (dubious) syntax of using
backslashes in names will get treated as a verilog name with
verilog backslash notation, with generally undesirable results.
When called from the SPICE reading routine, backslashes are
treated as-is and not as verilog notation.
2025-05-17 20:29:38 -04:00
R. Timothy Edwards bbe645f0ab Corrected an error in which netgen was trying to reduce an
expression in a property that was not necessarily a parameter,
and if it wasn't, then netgen would crash.  Surfaced by an
example using complicated parameters that netgen was apparently
unable to handle (an issue for another day;  the main goal here
was to avoid a segmentation violation).
2025-03-25 17:00:58 -04:00
Tim Edwards 4f315d33d6 Fixed a corner case found by Sylvain Munaut (see github issue
tracker #96) in which a subcircuit with only one port (in this
case, a pad) but which has properties (in this case, "M") will
fail to set the pointer position ahead of the property because
the loop starts after the first pin, so it has already missed
the position that needs to be saved.  Fixed by initializing
the value to the first pin position before starting the loop.
2025-03-09 11:07:58 -04:00
Tim Edwards 4457248ecd Corrected a long-standing issue with permutation, which turned out
to be caused by failing to have a systematic way of determining
which pin's hash value would be used for the hash value of all the
pins.  Because equivalent cells in the two netlists may have pins in
different order, it was possible that they might end up with
different hashes.  This was solved simply by always taking the
larger hash value of the two pins belonging to the permutable pair.
Now permutation works correctly for arbitrary subcircuits.
(Previously it worked for low-level components like MOSFETs because
the pin order is always the same.)
2025-02-09 21:26:54 -05:00
Tim Edwards 021dfa6e8a Made changes to tkcon.tcl to ensure compatibility with Tcl version 9. 2025-01-04 14:18:21 -05:00
Tim Edwards 1d286f9973 Corrected an issue with generating proxy pins that had previously
forced flattening to be done whenever any pin mismatch occurred,
which undermined the whole proxy pin method.  With the proxy pins
fixed, reinstated the method of avoiding flattening when pin
issues can be trivially corrected.  Also:  Added output to the
pin matching for one mismatch case that was being missed.
2025-01-01 13:27:39 -05:00
Tim Edwards 6d2ef396ef After giving the previous code change some more thought, I
decided that it is beneficial to break symmetries by net name;
it's just that net names should not be used before all symmetries
related to pins have been broken.  So I rewrote the compare
routine to take an argument allowing or disallowing net name
matches, and make one call to break symmetries by pin name
followed by another call to break symmetries by net name.  This
still solves the original problem, but does not allow symmetries
to be broken randomly on internal nets if names have been matched
in both netlists.  Otherwise the output may report nets that
appear to be swapped, making the output confusing.
2024-12-27 16:20:00 -05:00
Tim Edwards 2483b7440f Corrected an error in "ResolveAutomorphsByPin" where the code states
to check that the nodes with matching names are pins, but never does.
This results in an attempt to resolve automorphs by matching pin
names AND net names.  However, net names can match without the nets
matching, as pointed out by Andrey Bondar (private communication).
Fixed simply by adding the specified check that the node being name-
matched is actually a pin.
2024-12-26 21:20:24 -05:00
Tim Edwards 49c0de0433 Corrected an error found by Sylvain Munaut and discussed on
open-source-silicon slack on Nov. 3 in which the simple verilog
expression "assign name1 = name2[a:b]";  this revealed an error
where the parsing of "name2" was being incorrectly run with
GetBusTok() which must be called when the token starts with "[".
This problem existed both for the left-hand-side parsing and
the right-hand-side parsing, and has been fixed for both (where
either side may be a subset of a bus and the other a complete
bus).
2024-11-14 21:28:51 -05:00
Tim Edwards 3b9dca0cf2 Implemented the patch from Sylvain Munaut in github PR#90 (issue
that the position in the code has shifted quite a bit and I
don't really trust that git will do a clean merge.
2024-11-14 20:39:19 -05:00
Tim Edwards 7d910b616c Modified the string matching "matchnocase()" routine to compare
a verilog escaped string against an equivalent non-escaped
string (requires that the escaped string differs from the non-
escaped string by having a "\" at the front and " " at the end.
The space character is always maintained as part of the string).
2024-10-19 17:07:09 -04:00
Tim Edwards b1032f846b Refactored code in netcmp.c involved in printing side-by-side
formatted output to make it much cleaner and easier to read.  This
is in preparation of correcting the circuit1<-->circuit2 asymmetry
in the MatchPins() routine.
2024-10-16 20:38:44 -04:00
Tim Edwards 4c546d1472 Corrected an error that prevents property errors from being
printed in detail if a port error is also found.
2024-10-16 09:44:48 -04:00
Tim Edwards e1aa231db1 Corrected another error discovered by Andrei Bondar in which
the critical property (e.g., L for transistors) is required to
match exactly between devices in order to allow the additive
property (e.g., W for transistors) to be summed.  The critical
property should match if all values are within the slop value,
for floating-point values.  Note:  The implementation is still
not rigorous, as the saved critical value may shift from
device to device;  so comparing, e.g., 1.00 to 1.01 to 1.02 to
1.03, etc., can find that all individual comparisons are within
the slop value even though the slop is exceeded across all values.
2024-10-15 20:52:23 -04:00
Tim Edwards df8fa29b2f Fixed an issue with property matching that was preventing the last-
ditch effort of matching based on combining devices with the same
critical property (e.g., adding gate widths together for transistors
of the same gate length, if the property records remain stubbornly
mismatched to the end).  Thanks to Bondar Andrey Renatovich for
surfacing this issue and providing a reproducible example.
2024-10-14 13:24:35 -04:00
Tim Edwards d14bf70f1c Working to get some MatchPins improvements from Mitch Bailey from
a long time ago into the code.  The improvements collided with
intervening changes to the same routines and would not merge
cleanly, which is why they were never merged.  Step 1:  Show the
net name of a matching net that is missing a pin.  Remove output
of missing pins that is redundant (pin names being output twice).
2024-10-07 11:10:33 -04:00
Tim Edwards 5c21000a8b Made a modification to accommodate the situation where a SPICE
instance is matched to a verilog module definition, and the SPICE
instance is read before the verilog definition, forcing a
placeholder cell to be created.  Netgen will now make the
assumption that the verilog ports are in the same order as the
SPICE instance port order.  At the same time, it will output a
warning message that it is making this not-necessarily-warranted
assumption.  If the number of ports don't match or the placeholder
did not come from a SPICE instance, then the placeholder pins are
left alone.
2024-10-03 14:52:42 -04:00
Tim Edwards 05872ca918 Corrected an apparently long-standing error that is responsible for
some errors failing to list in the output while also being responsible
for a number of non-errors showing up in the output.  This fix may
substantially clean up netgen output.  Also:  Added text to the
output noting that pin matching may be incorrect with respect to
symmetries if the nets have failed to match.
2024-10-02 21:20:27 -04:00
Tim Edwards e821381900 Corrected a rather obscure error in which an otherwise unconnected
port-to-port short (formed by "assign" in verilog or zero-valued
resistors in SPICE) does not get checked when counting nodes
before adding a proxy pin to a subcircuit in that cell, causing
the proxy pin to be assigned the same node number and forming an
unintended connection to the port-to-port connecting net.
2024-09-30 22:11:53 -04:00
Tim Edwards 8022e1370f Added a few lines to rebuild the node cache after removing devices
such a zero-ohm resistors or zero-volt sources during the pre-match
phase, since the list of nodes gets changed by merging nets across
the removed devices.  Otherwise, the node-name cache gets
corrupted and random LVS errors occur.
2024-09-27 10:08:37 -04:00
Tim Edwards 2b88d79adc Corrected a rare case where a NULL value propagates in the flattening
routine and is not caught until it causes a segfault.
2024-08-16 19:48:36 -04:00
Tim Edwards bf4112db07 Corrected two statements that can cause a segfault because a
structure variable is not checked for the condition of being NULL
before attempting to read a component of the structure.  These
conditions imply that something is badly wrong in the netlist but
should not be causing a segfault.
2024-05-16 11:49:56 -04:00
Tim Edwards fcee934580 Corrected the parsing of the "model" command, which was failing to
pass the right cell name to the routine which counts the number of
pins.  Using this in a setup file will prevent netgen from spending
time matching low-level devices.
2024-05-14 15:12:41 -04:00
Tim Edwards 2d427aef3c Corrected the bad placement of #ifdef TCL_NETGEN . . . #endif around
critical parts of the netcmp.c code, causing issues with the non-Tcl
build (not that anyone should be doing a non-Tcl build).
2024-05-09 14:11:26 -04:00
Tim Edwards fd0c8c87ea Corrected another error in which, for device sorting, "M" was set
to 1 before the loop over devices in "run", resulting in "M"
taking the value of the previous property record if the following
record did not have an "M" value, instead of setting it to 1.
2024-04-03 21:05:08 -04:00
Tim Edwards 3d180f778d Corrected an error that had previously been corrected in
PropertyMatch() but not corrected symmetrically between circuit1
and circuit2;  this left the possibility that "M=1" in one
circuit vs. no "M" entry in the other would still pop up as a
property error, depending on which circuit (layout or schematic)
was listed first.
2024-04-03 11:01:58 -04:00
Tim Edwards 035fef5c72 Corrected an issue that prevents "cells list <file>" from reporting
empty cells (this does not solve the problem at hand, but is a part
of it).
2024-03-04 21:26:09 -05:00
Tim Edwards 202ea0431f Also updated configure (in addition to configure.in) with the
change to remove the "m4" dependency.
2024-02-19 12:46:20 -05:00
Tim Edwards 94754dbc4e Removed the requirement for package "m4" that is in the configuration
script.  It is not needed and doesn't exist in many OS distributions.
2024-02-19 12:41:08 -05:00
Tim Edwards bf67d3c275 Having been given an example by Kareem Farid where the order of
verilog netlists makes a difference to the matching (or failure
thereof), I applied the same in-circuit pin matching as previously
applied to mixtures of SPICE and verilog netlists.  This is clearly
a more robust way to handle pin order differences between parent
and child than was implemented previously.
2024-02-18 15:22:40 -05:00
Tim Edwards 62feed812e Corrected an issue that arose due to a change made earlier: A
while back, shorted pins were moved into contiguous positions.
When that method was discovered to cause matching issues, it was
abandoned with a note that doing so might have unintended
consequences because other code might depend on the shorted pins
being contiguous.  Such a case was just found, and corrected.
However, it was also found that shorted pins were still not
completely handled correctly in MatchPins();  a solution was
found that adds such pins to the "permutes" list (which needs to
be done if the shorted pins are to be correctly handled in any
higher level of the hierarchy, if there is one), and the
"permutes" list is then checked by MatchPins() to determine if
pins match because they belong to the same group of shorted
pins.
2024-02-09 21:23:28 -05:00
Tim Edwards d1c2848e4b Corrected another error in which some simple expressions are
incorrectly evaluated;  "(w+l)" for example treats "w+l" as
a single string instead of three tokens.  Corrected the code
to watch for a failure of strtod() when parsing the expression
at the "+" sign (also for "-").
2024-02-06 16:27:32 -05:00
Tim Edwards 6b0bd4d97b Found an error with the property sorting in which float values
were not compared for sorting in the same way they are compared
for property matching.  The "slop" value was treated as absolute,
not a percentage, so for example a slop of 0.01 on a dimension
of microns would cause all dimensions to be treated as round-off
error, and no sorting would occur.
2024-02-06 15:02:50 -05:00
Tim Edwards d69fbc23bb Added code to handle the problem in which a verilog netlist is read
before its component cells, and the component cells are read in as
SPICE netlists.  Then the original verilog cell and its instances
need to have pins reordered to match the subcircuit definition in
the SPICE netlist.  Otherwise, when verilog and SPICE netlists are
mixed, the order in which the files are read is critical, and
failures due to reading out-of-order are very obscure and nearly
impossible to debug.
2024-02-03 21:21:09 -05:00
Tim Edwards c7fa0324d9 Added a piece of code that handles implicit pins in verilog by doing
the following:  (1) Checking that the parent cell is verilog,
(2) only running after the two cells themselves have been compared
and matched, then (3) added the missing pin or pins while reordering
pins on instances (note: this may not work if the verilog netlist is
the first passed to netgen;  that case needs to be checked).
2024-02-02 14:51:10 -05:00
Tim Edwards eb27a18ae3 Corrected two different errors:
(1) When a comment line follows a ".subckt" line, and the comment
    line is empty or all whitespace, then the following line would
    be ignored.  This condition appears to be very specific and
    was solved simply by detecting it and handling it.
(2) Occasionally the "M" parameter of a subcircuit will be recorded
    as type double, and this was not being anticipated by the code
    that checks if "M=1" matches a corresponding entry with no "M"
    parameter.  Simple fix to check the condition where the "M"
    parameter is type double.
2024-01-03 21:21:03 -05:00
Tim Edwards 1817f4dd6a Corrected the LDDL_FLAGS setting for Mac OS, which is to replace
"-flat_namespace -undefined suppress -noprebind" to "-undefined
dynamic_lookup" which is what was done in magic, which has a
similar structure to netgen.
2023-12-03 20:32:05 -05:00
Tim Edwards a7e859fcde Corrected an error in parallel_sort and series_sort that does not
move to the start index before relinking the sorted entries.  That
will cause properties to be lost whenever the start index is greater
than zero.  Not sure why this hasn't been caught previously, or
whether other errors are involved here.
2023-11-20 10:38:41 -05:00
Tim Edwards 6d23844483 Corrected an error in the flattening routine that will cause the
"flatten" command to crash if there are black-box subcircuits in
the netlist.
2023-10-27 10:35:27 -04:00
Tim Edwards cc84364263 Added code to the netgen Tcl startup script to grab the PDK_ROOT
variable used with open_pdks, so that PDK references can be made
independent of the local filesystem.
2023-10-27 09:54:21 -04:00
Tim Edwards 00b906c109 Corrected an error in the previous commit which made primitive
devices from a .prm file into class "subckt" when they should be
class "module" (because they are primitives).  Otherwise, netgen
will crash when attempting to flatten them.
2023-10-27 09:38:14 -04:00
Tim Edwards 25a0e12428 One correction to the last commit, to ensure that subcircuits
which are MOSFETs are output into the .sim file in correct
G-D-S-B order.
2023-10-26 20:50:43 -04:00
Tim Edwards eabb898578 Added support for converting a SPICE file to a SIM file simulatable
with IRSIM including recent changes made to support multiple device
types using the subcircuit "x" component type.  This requires
reading in a .prm file, which incidentally can be used with any
SPICE file to inform netgen of the specific component type of any
model defined as a subcircuit.
2023-10-26 15:08:20 -04:00
Tim Edwards ec0e097fcf Corrected the code from version 258 which was supposed to handle
the removal of zero-valued devices between ports on the top level
(from version 254 they are ignored for levels under the top to
prevent port order from getting scrambled).  An invalid check was
being made to determine if the cells being compared were the top
of the compare queue.  This has been fixed.
2023-10-22 10:36:54 -04:00
Tim Edwards f59c9ebcb7 Corrected an issue where a mismatch in property type (e.g.,
string vs. integer) will cause a segfault.  Not sure if
type promotion is needed at that point because the failing case
was a syntax error that caused a double value to be interpreted
as a string because it could not be cast into a numeric form.
2023-10-03 19:39:01 -04:00
Tim Edwards ce097d5d76 One minor change to the previous commit: The check for shorting
devices between two ports is ignored for top-level cells, because
the scrambled ports won't affect anything in that case, and the
error will be reported as a port error, as it should.
2023-09-04 14:47:23 -04:00
Tim Edwards 619409556c Modified the handling of zero-valued resistors and voltage sources
so that they are *not* removed to make a better match if they are
shorting across two ports.  If removed, then the port lists will
get screwed up.  It is better to let the subcircuits fail matching.
Then, after the mismatched subcircuits are flattened, if the zero-
valued resistor or voltage source no longer connects two ports, it
can be safely removed to make a better match.
2023-09-04 14:40:30 -04:00
Tim Edwards b1374e2bc8 Made two changes to the verilog token parsing in netfile.c in
response to Mitch Bailey's github issue #82:

(1) When skipping comments, skip the contents of "(* ... *)"
    delimiters as well as "/* ... */" delimiters.

(2) When checking for qflow's "\abcd\" names (final space
    replaced with a backslash for SPICE compatibility of
    names), make sure that the last "\" is followed by end-
    of-string.  Otherwise names like "\a\bcd " will fail to
    parse correctly.
2023-09-04 10:50:59 -04:00
Tim Edwards cff954f36a Removed a block of ill-considered code that moves pins together
when they are shorted, because doing so is scrambling the pin
order of cells with respect to the instance calls to the cell.
Not sure if there is any code that relies on shorted pins being
adjacent, though.
2023-09-01 16:04:41 -04:00
Tim Edwards c27d933adc Modified some of the verilog read-in code to avoid a segmentation
fault that would happen if the verilog had illegal syntax of a
misspelled net name (although normally netgen is expected not to
have to check the verilog for syntax, and there are probably many
such cases of netgen failing to handle incorrect verilog and then
crashing as a result).
2023-09-01 09:04:44 -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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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
37 changed files with 7255 additions and 3027 deletions

View File

@ -1 +1 @@
1.5.234 1.5.323

View File

@ -22,6 +22,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <strings.h>
#include <ctype.h> #include <ctype.h>
#ifdef IBMPC #ifdef IBMPC
#include <stdlib.h> /* for strtol on PC */ #include <stdlib.h> /* for strtol on PC */
@ -90,7 +91,7 @@ char *ActelName(char *Name)
/* strip physical-pin information, if it exists */ /* strip physical-pin information, if it exists */
if ((nm = strrchr(name,PHYSICALPIN[0])) != NULL) *nm = '\0'; if ((nm = strrchr(name,PHYSICALPIN[0])) != NULL) *nm = '\0';
if (strlen(name) > 13) { if (strlen(name) > 13) {
ActelIndex = (++ActelIndex) % ACTELNAMESIZE; ActelIndex = (ActelIndex + 1) % ACTELNAMESIZE;
/* format the value of the hashed value of the string */ /* format the value of the hashed value of the string */
sprintf(ActelNames[ActelIndex], "$%lX", ActelNameHash(name)); sprintf(ActelNames[ActelIndex], "$%lX", ActelNameHash(name));
if (Debug) if (Debug)
@ -101,7 +102,7 @@ Printf("ActelNameHash returns %s on name %s\n",ActelNames[ActelIndex], name);
NeedsQuoting = 0; NeedsQuoting = 0;
if (NULL != strpbrk(name, ".,:; \t\"'\n\r")) NeedsQuoting = 1; if (NULL != strpbrk(name, ".,:; \t\"'\n\r")) NeedsQuoting = 1;
ActelIndex = (++ActelIndex) % ACTELNAMESIZE; ActelIndex = (ActelIndex + 1) % ACTELNAMESIZE;
if (!NeedsQuoting) { if (!NeedsQuoting) {
strcpy(ActelNames[ActelIndex], name); strcpy(ActelNames[ActelIndex], name);
return(ActelNames[ActelIndex]); return(ActelNames[ActelIndex]);
@ -131,7 +132,7 @@ if format = 1, use the actel .pin file format
struct nlist *tp; struct nlist *tp;
struct objlist *ob, *ob2; struct objlist *ob, *ob2;
char *ptr; char *ptr;
char physicalpin[200]; char physicalpin[MAX_STR_LEN];
tp = LookupCell(name); tp = LookupCell(name);
if (tp == NULL) return; if (tp == NULL) return;

View File

@ -176,4 +176,6 @@ extern int open(char *path, int oflag, ...); /* HPUX has it in <sys/fcntl.h> */
#define FALSE 0 #define FALSE 0
#endif #endif
#define MAX_STR_LEN 256
#endif /* _CONFIG_H */ #endif /* _CONFIG_H */

View File

@ -629,7 +629,7 @@ struct embed *FlattenEmbeddingTree(struct embed *E)
int LenEmbed(char *prefix, struct nlist *np, struct embed *E, int flatten) int LenEmbed(char *prefix, struct nlist *np, struct embed *E, int flatten)
/* return the number of characters required to print element E */ /* 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 == NULL) return(0);
if (E->left == NULL && E->right == NULL) { if (E->left == NULL && E->right == NULL) {
@ -668,7 +668,7 @@ void PrintEmb(FILE *outfile, char *prefix, struct nlist *np,
struct objlist *ob; struct objlist *ob;
char *instancename; char *instancename;
struct nlist *np2; struct nlist *np2;
char name[200]; char name[MAX_STR_LEN];
ob = InstanceNumber(np,E->instancenumber); ob = InstanceNumber(np,E->instancenumber);
instancename = ob->instance.name; instancename = ob->instance.name;
@ -706,7 +706,7 @@ void PrintEmbed(FILE *outfile, char *prefix, struct nlist *np,
struct objlist *ob; struct objlist *ob;
char *instancename; char *instancename;
struct nlist *np2; struct nlist *np2;
char name[200]; char name[MAX_STR_LEN];
ob = InstanceNumber(np,E->instancenumber); ob = InstanceNumber(np,E->instancenumber);
instancename = ob->instance.name; instancename = ob->instance.name;

View File

@ -31,6 +31,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "print.h" #include "print.h"
#include "hash.h" #include "hash.h"
static int invlambda = 100; /* Used in sim and prm files */
void extCell(char *name, int filenum) void extCell(char *name, int filenum)
{ {
struct nlist *tp, *tp2; struct nlist *tp, *tp2;
@ -167,7 +169,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
int filenum; int filenum;
if ((filenum = OpenParseFile(fname, *fnum)) < 0) { if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
char name[100]; char name[MAX_STR_LEN];
SetExtension(name, fname, EXT_EXTENSION); SetExtension(name, fname, EXT_EXTENSION);
if ((filenum = OpenParseFile(name, *fnum)) < 0) { if ((filenum = OpenParseFile(name, *fnum)) < 0) {
@ -208,7 +210,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
else if (match(nexttok, "style")) SkipNewLine(NULL); else if (match(nexttok, "style")) SkipNewLine(NULL);
else if (match(nexttok, "resistclasses")) SkipNewLine(NULL); else if (match(nexttok, "resistclasses")) SkipNewLine(NULL);
else if (match(nexttok, "node")) { 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" */ /* No cell is generated until at least one valid "node" or "use" */
/* has been read in the file. */ /* has been read in the file. */
@ -223,8 +225,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
SkipNewLine(NULL); SkipNewLine(NULL);
} }
else if (match(nexttok, "equiv")) { else if (match(nexttok, "equiv")) {
char name[200]; char name[MAX_STR_LEN];
char name2[200]; char name2[MAX_STR_LEN];
SkipTok(NULL); SkipTok(NULL);
GetExtName(name, nexttok); GetExtName(name, nexttok);
if (LookupObject(name,CurrentCell) == NULL) Node(name); if (LookupObject(name,CurrentCell) == NULL) Node(name);
@ -235,8 +237,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
SkipNewLine(NULL); SkipNewLine(NULL);
} }
else if (match(nexttok, "device")) { else if (match(nexttok, "device")) {
char dev_name[100], dev_class[100]; char dev_name[MAX_STR_LEN], dev_class[MAX_STR_LEN];
char gate[200], drain[200], source[200], subs[200]; char gate[MAX_STR_LEN], drain[MAX_STR_LEN], source[MAX_STR_LEN], subs[MAX_STR_LEN];
char inststr[64]; char inststr[64];
SkipTok(NULL); SkipTok(NULL);
strcpy(dev_class, nexttok); strcpy(dev_class, nexttok);
@ -306,8 +308,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
SkipNewLine(NULL); SkipNewLine(NULL);
} }
else if (match(nexttok, "fet")) { /* old-style FET record */ else if (match(nexttok, "fet")) { /* old-style FET record */
char fet_class[100]; char fet_class[MAX_STR_LEN];
char gate[200], drain[200], source[200], subs[200]; char gate[MAX_STR_LEN], drain[MAX_STR_LEN], source[MAX_STR_LEN], subs[MAX_STR_LEN];
char inststr[64]; char inststr[64];
SkipTok(NULL); SkipTok(NULL);
strcpy(fet_class, nexttok); strcpy(fet_class, nexttok);
@ -365,7 +367,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
SkipNewLine(NULL); SkipNewLine(NULL);
} }
else { else {
char ctop[200], cbot[200], cdummy[200]; char ctop[MAX_STR_LEN], cbot[MAX_STR_LEN], cdummy[MAX_STR_LEN];
SkipTok(NULL); SkipTok(NULL);
GetExtName(ctop, nexttok); GetExtName(ctop, nexttok);
SkipTok(NULL); SkipTok(NULL);
@ -375,8 +377,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
} }
} }
else if (match(nexttok, "use")) { else if (match(nexttok, "use")) {
char name[200]; char name[MAX_STR_LEN];
char instancename[200]; char instancename[MAX_STR_LEN];
char *basename; char *basename;
/* No cell is generated until at least one valid "node" or "use" */ /* No cell is generated until at least one valid "node" or "use" */
@ -390,7 +392,7 @@ char *ReadExt(char *fname, int doflat, int *fnum)
SkipTok(NULL); SkipTok(NULL);
GetExtName(name, nexttok); GetExtName(name, nexttok);
if ((basename = strrchr(name,'/')) != NULL) { if ((basename = strrchr(name,'/')) != NULL) {
char tmp[200]; char tmp[MAX_STR_LEN];
strcpy(tmp, basename+1); strcpy(tmp, basename+1);
strcpy(name, tmp); strcpy(name, tmp);
} }
@ -405,8 +407,8 @@ char *ReadExt(char *fname, int doflat, int *fnum)
SkipNewLine(NULL); SkipNewLine(NULL);
} }
else if (match(nexttok, "merge")) { else if (match(nexttok, "merge")) {
char name[200]; char name[MAX_STR_LEN];
char name2[200]; char name2[MAX_STR_LEN];
SkipTok(NULL); SkipTok(NULL);
GetExtName(name, nexttok); GetExtName(name, nexttok);
SkipTok(NULL); SkipTok(NULL);
@ -450,7 +452,8 @@ void simCell(char *name, int filenum)
struct nlist *tp, *tp2; struct nlist *tp, *tp2;
struct objlist *ob, *ob2; struct objlist *ob, *ob2;
char FileName[500], simclass; char FileName[500], simclass;
short i; char writeLine[1024], paramString[128];
short i, p, mult;
double l, w, v; double l, w, v;
tp = LookupCellFile(name, filenum); tp = LookupCellFile(name, filenum);
@ -478,9 +481,9 @@ void simCell(char *name, int filenum)
} }
/* print out header list */ /* print out header list */
/* distance units are multiplied by 100 (distances are in um) */ /* distance units are multiplied by invlambda */
FlushString("| units: 100 tech: scmos\n"); FlushString("| units: %d tech: scmos\n", 100 * invlambda);
/* now run through cell's contents, print instances */ /* now run through cell's contents, print instances */
for (ob = tp->cell; ob != NULL; ob = ob->next) { for (ob = tp->cell; ob != NULL; ob = ob->next) {
@ -516,13 +519,17 @@ void simCell(char *name, int filenum)
case CLASS_NPN: case CLASS_NPN:
simclass = 'b'; simclass = 'b';
break; break;
default: case CLASS_SUBCKT:
case CLASS_MODULE:
simclass = 'x'; simclass = 'x';
break; break;
default:
simclass = '|';
break;
} }
if (simclass != 'x') if (simclass != 'x')
FlushString("%c", simclass); FlushString("%c", simclass);
switch (tp2->class) { switch (tp2->class) {
case CLASS_NMOS: case CLASS_NMOS4: case CLASS_NMOS: case CLASS_NMOS4:
@ -590,6 +597,115 @@ void simCell(char *name, int filenum)
FlushString(" %g\n", v); FlushString(" %g\n", v);
break; break;
case CLASS_MODULE:
*writeLine = 'x';
*(writeLine + 1) = '\0';
mult = 1;
/* Important---Need to look up the cell definition; if
* the first pin is "drain" then it is a FET, and pins
* get swapped from D-G-S-B to G-S-D-B. Source and drain
* are treated here as equivalent because the .sim format
* has no concept of an asymmetric source and drain.
*/
ob2 = tp2->cell;
if ((*matchfunc)(ob2->next->name, "gate"))
{
strcat(writeLine, " ");
strcat(writeLine, NodeAlias(tp, ob->next));
strcat(writeLine, " ");
strcat(writeLine, NodeAlias(tp, ob));
ob2 = ob->next->next;
}
else
ob2 = ob;
while (ob2 != NULL) {
strcat(writeLine, " ");
strcat(writeLine, NodeAlias(tp, ob2));
ob2 = ob2->next;
if ((ob2 == NULL) || (ob2->type <= FIRSTPIN)) break;
}
if (ob2 && ob2->type == PROPERTY) {
struct valuelist *vl;
/* Only known parameters are L, W, X, and Y */
for (p = 0;; p++) {
vl = (struct valuelist *)(&(ob2->instance.props[p]));
if (vl->type == PROP_ENDLIST) {
strcat(writeLine, " l=1");
break;
}
else if ((*matchfunc)(vl->key, "L")) {
v = vl->value.dval;
sprintf(paramString, " l=%d", (int)(0.5 + (v * invlambda)));
strcat(writeLine, paramString);
break;
}
}
for (p = 0;; p++) {
vl = (struct valuelist *)(&(ob2->instance.props[p]));
if (vl->type == PROP_ENDLIST) {
strcat(writeLine, " w=1");
break;
}
else if ((*matchfunc)(vl->key, "W")) {
v = vl->value.dval;
sprintf(paramString, " w=%d", (int)(0.5 + (v * invlambda)));
strcat(writeLine, paramString);
break;
}
}
for (p = 0;; p++) {
vl = (struct valuelist *)(&(ob2->instance.props[p]));
if (vl->type == PROP_ENDLIST) {
strcat(writeLine, " x=0");
break;
}
else if ((*matchfunc)(vl->key, "X")) {
i = vl->value.ival;
sprintf(paramString, " x=%d", i);
strcat(writeLine, paramString);
break;
}
}
for (p = 0;; p++) {
vl = (struct valuelist *)(&(ob2->instance.props[p]));
if (vl->type == PROP_ENDLIST) {
strcat(writeLine, " y=0");
break;
}
else if ((*matchfunc)(vl->key, "Y")) {
i = vl->value.ival;
sprintf(paramString, " y=%d", i);
strcat(writeLine, paramString);
}
}
for (p = 0;; p++) {
vl = (struct valuelist *)(&(ob2->instance.props[p]));
if (vl->type == PROP_ENDLIST) {
break;
}
else if ((*matchfunc)(vl->key, "M")) {
if (vl->type == PROP_INTEGER)
mult = vl->value.ival;
else
mult = vl->value.dval;
}
}
}
strcat(writeLine, " ");
strcat(writeLine, tp2->name);
strcat(writeLine, "\n");
/* Multiple instances (M != 1) are written multiple times.
* NF is ignored in favor of having a single device with
* the total width.
*/
for (i = 0; i < mult; i++)
FlushString(writeLine);
break;
default: default:
FlushString("| unhandled component %s\n", tp2->name); FlushString("| unhandled component %s\n", tp2->name);
break; break;
@ -626,6 +742,181 @@ int StrIsInt(char *s)
return (1); return (1);
} }
/*------------------------------------------------------*/
/* Read a .prm format file. This is specifically to */
/* get the "device" lines that indicate how a SPICE */
/* subcircuit model or a .sim "x" record needs to be */
/* translated into a specific component type like a */
/* FET, diode, resistor, etc. */
/*------------------------------------------------------*/
char *ReadPrm(char *fname, int *fnum)
{
int filenum;
struct keyvalue *kvlist = NULL;
struct nlist *tp;
if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
char name[MAX_STR_LEN];
SetExtension(name, fname, PRM_EXTENSION);
if (OpenParseFile(name, *fnum) < 0) {
Printf("Error in prm file read: No file %s\n",name);
*fnum = filenum;
return NULL;
}
}
/* Make sure all .prm file reading is case INsensitive */
/* This is because the only reason to read a PRM file */
/* is to find all the subcircuit device types so that */
/* a SPICE file can be read and a SIM file written. */
matchfunc = matchnocase;
matchintfunc = matchfile;
hashfunc = hashnocase;
CellDef(fname, filenum);
while (!EndParseFile()) {
char devicename[MAX_STR_LEN];
SkipTok(NULL);
if (EndParseFile()) break;
if (nexttok[0] == ';') continue; /* Comment line */
else if (nexttok[0] == '\0') continue; /* Blank line */
else if (match(nexttok, "lambda")) {
SkipTok(NULL);
invlambda = (int)(0.5 + (1.0 / atof(nexttok)));
SkipNewLine(NULL); /* skip any attributes */
}
else if (match(nexttok, "device")) {
SkipTok(NULL);
if (match(nexttok, "nfet")) {
SkipTok(NULL);
strcpy(devicename, nexttok);
/* Create 4-terminal nfet subcircuit device record */
if (LookupCellFile(devicename, filenum) == NULL) {
CellDef(devicename, filenum);
Port("drain");
Port("gate");
Port("source");
Port("bulk");
PropertyDouble(devicename, filenum, "l", 0.01, 0.0);
PropertyDouble(devicename, filenum, "w", 0.01, 0.0);
PropertyInteger(devicename, filenum, "nf", 0, 1);
PropertyInteger(devicename, filenum, "m", 0, 1);
SetClass(CLASS_MODULE);
EndCell();
ReopenCellDef(fname, filenum);
}
LinkProperties(devicename, kvlist);
SkipNewLine(NULL); /* skip any attributes */
}
else if (match(nexttok, "pfet")) {
SkipTok(NULL);
strcpy(devicename, nexttok);
/* Create 4-terminal pfet subcircuit device record */
if (LookupCellFile(devicename, filenum) == NULL) {
CellDef(devicename, filenum);
Port("drain");
Port("gate");
Port("source");
Port("well");
PropertyDouble(devicename, filenum, "l", 0.01, 0.0);
PropertyDouble(devicename, filenum, "w", 0.01, 0.0);
PropertyInteger(devicename, filenum, "nf", 0, 1);
PropertyInteger(devicename, filenum, "m", 0, 1);
SetClass(CLASS_MODULE);
EndCell();
ReopenCellDef(fname, filenum);
}
LinkProperties(devicename, kvlist);
SkipNewLine(NULL); /* skip various attributes */
}
else if (match(nexttok, "resistor")) {
SkipTok(NULL);
strcpy(devicename, nexttok);
/* Resistor device has additional record for the value */
/* (Need to do something with this. . . ?) */
SkipTok(NULL);
/* Create resistor subcircuit device record */
if (LookupCellFile(devicename, filenum) == NULL) {
CellDef(devicename, filenum);
Port("end_a");
Port("end_b");
PropertyDouble(devicename, filenum, "value", 0.01, 0.0);
PropertyDouble(devicename, filenum, "l", 0.01, 0.0);
PropertyDouble(devicename, filenum, "w", 0.01, 0.0);
PropertyInteger(devicename, filenum, "m", 0, 1);
SetClass(CLASS_MODULE);
EndCell();
ReopenCellDef(fname, filenum);
}
LinkProperties(devicename, kvlist);
SkipNewLine(NULL); /* skip various attributes */
}
else if (match(nexttok, "capacitor")) {
SkipTok(NULL);
strcpy(devicename, nexttok);
/* Capacitor device has additional record for the value */
/* (Need to do something with this. . . ?) */
SkipTok(NULL);
/* Create capacitor subcircuit device record */
if (LookupCellFile(devicename, filenum) == NULL) {
CellDef(devicename, filenum);
Port("top");
Port("bottom");
PropertyDouble(devicename, filenum, "value", 0.01, 0.0);
PropertyDouble(devicename, filenum, "l", 0.01, 0.0);
PropertyDouble(devicename, filenum, "w", 0.01, 0.0);
PropertyInteger(devicename, filenum, "m", 0, 1);
SetClass(CLASS_MODULE);
EndCell();
ReopenCellDef(fname, filenum); /* Reopen */
}
LinkProperties(devicename, kvlist);
SkipNewLine(NULL);
}
else if (match(nexttok, "diode")) {
SkipTok(NULL);
strcpy(devicename, nexttok);
/* Create diode subcircuit device record */
if (LookupCellFile(devicename, filenum) == NULL) {
CellDef(devicename, filenum);
Port("anode");
Port("cathode");
PropertyInteger(devicename, filenum, "m", 0, 1);
SetClass(CLASS_MODULE);
EndCell();
ReopenCellDef(fname, filenum); /* Reopen */
}
LinkProperties(devicename, kvlist);
SkipNewLine(NULL);
}
else {
Printf("Unknown device type in .prm: '%s'\n", nexttok);
InputParseError(stderr);
SkipNewLine(NULL);
}
}
else {
/* Could spell out all the keywords used in .prm files */
/* but probably not worth the effort. */
SkipNewLine(NULL);
}
DeleteProperties(&kvlist);
}
EndCell();
CloseParseFile();
tp = LookupCellFile(fname, filenum);
if (tp) tp->flags |= CELL_TOP;
*fnum = filenum;
return fname;
}
/*-------------------------*/ /*-------------------------*/
/* Read a .sim format file */ /* Read a .sim format file */
/*-------------------------*/ /*-------------------------*/
@ -640,11 +931,11 @@ char *ReadSim(char *fname, int *fnum)
double simscale = 1.0; double simscale = 1.0;
if ((filenum = OpenParseFile(fname, *fnum)) < 0) { if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
char name[100]; char name[MAX_STR_LEN];
SetExtension(name, fname, SIM_EXTENSION); SetExtension(name, fname, SIM_EXTENSION);
if (OpenParseFile(name, *fnum) < 0) { if (OpenParseFile(name, *fnum) < 0) {
Printf("Error in ext file read: No file %s\n",name); Printf("Error in sim file read: No file %s\n",name);
*fnum = filenum; *fnum = filenum;
return NULL; return NULL;
} }
@ -670,7 +961,7 @@ char *ReadSim(char *fname, int *fnum)
SkipNewLine(NULL); SkipNewLine(NULL);
} }
else if (match(nexttok, "n")) { 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; char inststr[25], *instptr = NULL;
SkipTok(NULL); SkipTok(NULL);
@ -714,7 +1005,7 @@ char *ReadSim(char *fname, int *fnum)
LinkProperties("n", kvlist); LinkProperties("n", kvlist);
} }
else if (match(nexttok, "p")) { 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; char inststr[25], *instptr = NULL;
SkipTok(NULL); SkipTok(NULL);
GetExtName(gate, nexttok); GetExtName(gate, nexttok);
@ -754,7 +1045,7 @@ char *ReadSim(char *fname, int *fnum)
LinkProperties("p", kvlist); LinkProperties("p", kvlist);
} }
else if (match(nexttok, "e")) { /* 3-port capacitors (poly/poly2) */ 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; char inststr[25], *instptr = NULL;
SkipTok(NULL); SkipTok(NULL);
GetExtName(gate, nexttok); GetExtName(gate, nexttok);
@ -788,7 +1079,7 @@ char *ReadSim(char *fname, int *fnum)
E(fname, instptr, gate, drain, source); E(fname, instptr, gate, drain, source);
} }
else if (match(nexttok, "b")) { /* bipolars added by Tim 7/16/96 */ 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; char inststr[25], *instptr = NULL;
SkipTok(NULL); SkipTok(NULL);
GetExtName(base, nexttok); GetExtName(base, nexttok);
@ -826,7 +1117,7 @@ char *ReadSim(char *fname, int *fnum)
SkipNewLine(NULL); SkipNewLine(NULL);
} }
else { else {
char ctop[200], cbot[200], cdummy[200]; char ctop[MAX_STR_LEN], cbot[MAX_STR_LEN], cdummy[MAX_STR_LEN];
SkipTok(NULL); SkipTok(NULL);
GetExtName(ctop, nexttok); GetExtName(ctop, nexttok);
if (LookupObject(ctop, CurrentCell) == NULL) if (LookupObject(ctop, CurrentCell) == NULL)
@ -847,11 +1138,11 @@ char *ReadSim(char *fname, int *fnum)
} }
else if (match(nexttok, "r")) { /* 2-port resistors */ else if (match(nexttok, "r")) { /* 2-port resistors */
if (IgnoreRC) { if (IgnoreRC) {
/* ignore all capacitances */ /* ignore all resistances */
SkipNewLine(NULL); SkipNewLine(NULL);
} }
else { else {
char rtop[200], rbot[200]; char rtop[MAX_STR_LEN], rbot[MAX_STR_LEN];
SkipTok(NULL); SkipTok(NULL);
GetExtName(rtop, nexttok); GetExtName(rtop, nexttok);
if (LookupObject(rtop, CurrentCell) == NULL) if (LookupObject(rtop, CurrentCell) == NULL)
@ -875,7 +1166,7 @@ char *ReadSim(char *fname, int *fnum)
SkipNewLine(NULL); SkipNewLine(NULL);
} }
else { 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; char inststr[25], *instptr = NULL;
SkipTok(NULL); SkipTok(NULL);
GetExtName(rdummy, nexttok); GetExtName(rdummy, nexttok);
@ -917,7 +1208,7 @@ char *ReadSim(char *fname, int *fnum)
SkipNewLine(NULL); SkipNewLine(NULL);
} }
else if (match(nexttok, "=")) { else if (match(nexttok, "=")) {
char node1[200], node2[200]; char node1[MAX_STR_LEN], node2[MAX_STR_LEN];
SkipTok(NULL); SkipTok(NULL);
GetExtName(node1, nexttok); GetExtName(node1, nexttok);
SkipTok(NULL); SkipTok(NULL);

View File

@ -53,7 +53,7 @@ void flattenCell(char *name, int file)
struct nlist *ChildCell; struct nlist *ChildCell;
struct objlist *tmp, *ob2, *ob3; struct objlist *tmp, *ob2, *ob3;
int notdone, rnodenum; int notdone, rnodenum;
char tmpstr[200]; char tmpstr[MAX_STR_LEN];
int nextnode, oldmax; int nextnode, oldmax;
#if !OLDPREFIX #if !OLDPREFIX
int prefixlength; int prefixlength;
@ -136,17 +136,16 @@ void flattenCell(char *name, int file)
ob2 = ob2->next; ob2 = ob2->next;
} }
/* delete all port elements from child */ /* delete all port elements from child */
while (IsPort(ChildObjList)) { while (IsPort(ChildObjList)) {
/* delete all ports at beginning of list */ /* delete all ports at beginning of list */
if (Debug) Printf("deleting leading port from child\n"); if (Debug) Printf("deleting leading port from child\n");
tmp = ChildObjList->next; tmp = ChildObjList->next;
FreeObjectAndHash(ChildObjList, ChildCell); FreeObjectAndHash(ChildObjList, ChildCell);
ChildObjList = tmp; if ((ChildObjList = tmp) == NULL) break;
} }
tmp = ChildObjList; tmp = ChildObjList;
while (tmp->next != NULL) { while (tmp && (tmp->next != NULL)) {
if (IsPort(tmp->next)) { if (IsPort(tmp->next)) {
ob2 = (tmp->next)->next; ob2 = (tmp->next)->next;
if (Debug) Printf("deleting a port from child\n"); if (Debug) Printf("deleting a port from child\n");
@ -243,6 +242,13 @@ void flattenCell(char *name, int file)
ThisCell->dumped = 1; /* indicate cell has been flattened */ 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 -- */ /* flattenInstancesOf -- */
/* */ /* */
@ -265,6 +271,7 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
struct nlist *ThisCell; struct nlist *ThisCell;
struct nlist *ChildCell; struct nlist *ChildCell;
struct objlist *tmp, *ob2, *ob3; struct objlist *tmp, *ob2, *ob3;
struct linkednode *checknodes = NULL, *newlnode, *chknode;
int notdone, rnodenum; int notdone, rnodenum;
char tmpstr[1024]; char tmpstr[1024];
int nextnode, oldmax, numflat = 0; int nextnode, oldmax, numflat = 0;
@ -293,8 +300,6 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
return 0; return 0;
} }
} }
/* Placeholder cells must not be flattened */
if (ThisCell->flags & CELL_PLACEHOLDER) return 0;
FreeNodeNames(ThisCell); FreeNodeNames(ThisCell);
@ -332,6 +337,10 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
LastObj = ParentParams; LastObj = ParentParams;
continue; continue;
} }
if (ChildCell->flags & CELL_PLACEHOLDER) {
LastObj = ParentParams;
continue; // Placeholder cells must not be flattened
}
if (ChildCell == ThisCell) { if (ChildCell == ThisCell) {
LastObj = ParentParams; LastObj = ParentParams;
continue; // Avoid infinite loop continue; // Avoid infinite loop
@ -416,6 +425,16 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
} }
UpdateNodeNumbers(ChildStart, 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 /* in pathological cases, the lengths of the port lists may
* change. This is an error, but that is no reason to allow * change. This is an error, but that is no reason to allow
@ -518,11 +537,10 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
/* Do property inheritance */ /* Do property inheritance */
/* NOTE: Need to do: Check properties for M > 1 and decrement
* and repeat without moving CurrentProp
*/
if (CurrentProp) { if (CurrentProp) {
int i, mval;
struct valuelist *kv;
for (ob2 = ChildStart; ob2 != NULL; ob2=ob2->next) { for (ob2 = ChildStart; ob2 != NULL; ob2=ob2->next) {
/* If the parent cell has properties to declare, then */ /* If the parent cell has properties to declare, then */
@ -530,10 +548,49 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
/* spiceparams dictionary is active (during file */ /* spiceparams dictionary is active (during file */
/* reading only). */ /* reading only). */
if (ob2->type == PROPERTY) if (ob2->type == PROPERTY) {
ReduceExpressions(ob2, CurrentProp, ChildCell, ReduceExpressions(ob2, CurrentProp, ChildCell,
(spiceparams.hashtab == NULL) ? 0 : 1); (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 (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;
}
}
/* Repeat for each property record, as each property represents a /* Repeat for each property record, as each property represents a
* unique instance that must be flattened individually. * unique instance that must be flattened individually.
@ -545,8 +602,10 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
else break; else break;
/* Put the child cell at the start of ChildObjList */ /* Put the child cell at the start of ChildObjList */
ChildEnd->next = ChildObjList; if (ChildEnd) {
ChildObjList = ChildStart; ChildEnd->next = ChildObjList;
ChildObjList = ChildStart;
}
} }
/* Put the child cell at the start of ChildObjList */ /* Put the child cell at the start of ChildObjList */
@ -598,6 +657,29 @@ int flattenInstancesOf(char *name, int fnum, char *instance)
NextObj = ParentParams; NextObj = ParentParams;
} /* repeat until no more instances found */ } /* 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); CacheNodeNames(ThisCell);
ThisCell->dumped = 1; /* indicate cell has been flattened */ ThisCell->dumped = 1; /* indicate cell has been flattened */
return numflat; return numflat;
@ -1136,7 +1218,6 @@ int UniquePins(char *name, int filenum)
firstport = (struct objlist **)CALLOC(maxnode + 1, sizeof(struct objlist *)); firstport = (struct objlist **)CALLOC(maxnode + 1, sizeof(struct objlist *));
portcount = FIRSTPIN; portcount = FIRSTPIN;
lob = NULL;
for (ob = ThisCell->cell; ob != NULL; ob = ob->next) { for (ob = ThisCell->cell; ob != NULL; ob = ob->next) {
if (ob->type != PORT) break; if (ob->type != PORT) break;
if (ob->node > 0) { if (ob->node > 0) {
@ -1147,16 +1228,16 @@ int UniquePins(char *name, int filenum)
firstport[ob->node]->name, ThisCell->name, ThisCell->file); firstport[ob->node]->name, ThisCell->name, ThisCell->file);
/* Do not count this as a duplicate pin. */ /* Do not count this as a duplicate pin. */
nodecount[ob->node]--; nodecount[ob->node]--;
/* Move the pin adjacent to the one it is shorted to (if it /* Note: Previously there was code here to move the shorted port
* isn't already); this will make the work of MatchPins() easier. * next to the pin it is shorted to. This causes the cell def pins
* to become scrambled with respect to the pin order of its instances.
* Removed the code 9/1/2023. But---Not sure if any code depends
* on shorted pins being adjacent.
*/ */
if (firstport[ob->node]->next != ob) { /* When two pins are shorted, they are by definition permutable */
lob->next = ob->next; PermuteSetup(ThisCell->name, ThisCell->file, ob->name,
ob->next = firstport[ob->node]->next; firstport[ob->node]->name);
firstport[ob->node]->next = ob;
ob = lob;
}
lob = ob;
continue; continue;
} }
else { else {
@ -1177,7 +1258,6 @@ int UniquePins(char *name, int filenum)
} }
} }
portcount++; portcount++;
lob = ob;
} }
if (needscleanup) if (needscleanup)
@ -1228,6 +1308,14 @@ int UniquePins(char *name, int filenum)
return 1; return 1;
} }
/* Structure used below for keeping track of node numbers
* belonging to removed nodes.
*/
struct LinkedNum {
int node;
struct LinkedNum *next;
};
/*------------------------------------------------------*/ /*------------------------------------------------------*/
/* Callback function for CleanupPins */ /* Callback function for CleanupPins */
/* Note that if the first pin of the instance is a */ /* Note that if the first pin of the instance is a */
@ -1240,6 +1328,7 @@ struct nlist *cleanuppins(struct hashlist *p, void *clientdata)
struct nlist *ptr; struct nlist *ptr;
struct objlist *ob, *obt, *lob, *nob, *firstpin, *pob; struct objlist *ob, *obt, *lob, *nob, *firstpin, *pob;
struct nlist *tc = (struct nlist *)clientdata; struct nlist *tc = (struct nlist *)clientdata;
struct LinkedNum *newnodenum, *removedNodes = (struct LinkedNum *)NULL;
int pinnum; int pinnum;
char *saveinst = NULL; char *saveinst = NULL;
@ -1295,6 +1384,15 @@ struct nlist *cleanuppins(struct hashlist *p, void *clientdata)
saveinst = ob->instance.name; saveinst = ob->instance.name;
} }
if (ob->model.class != NULL) FREE(ob->model.class); if (ob->model.class != NULL) FREE(ob->model.class);
// Record the net number of the pin being removed, to
// check at the end if the net belonged to a pin that
// got orphaned.
newnodenum = (struct LinkedNum *)MALLOC(sizeof(struct LinkedNum));
newnodenum->node = ob->node;
newnodenum->next = removedNodes;
removedNodes = newnodenum;
FREE(ob); FREE(ob);
} }
else { else {
@ -1338,6 +1436,28 @@ struct nlist *cleanuppins(struct hashlist *p, void *clientdata)
} }
} }
while (removedNodes != NULL) {
int nodenum = removedNodes->node;
struct objlist *ob2;
/* Only concerned with nodes that are in the pin list of ptr->cell */
for (ob = ptr->cell; ob != NULL; ob = ob->next) {
if (ob->type != PORT) break;
if (ob->node == nodenum) break;
}
if (ob && (ob->type == PORT)) {
/* Check if this node number exists only in the port record */
for (nob = ob->next; nob != NULL; nob = nob->next)
if (nob->node == nodenum) break;
if (nob == NULL) {
ob->node = -1; /* This pin is now disconnected */
}
}
newnodenum = removedNodes;
removedNodes = removedNodes->next;
FREE(newnodenum);
}
if (saveinst != NULL) FREE(saveinst); if (saveinst != NULL) FREE(saveinst);
return NULL; /* Keep the search going */ return NULL; /* Keep the search going */
} }
@ -1558,7 +1678,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
ECompare *ecomp, *ncomp; ECompare *ecomp, *ncomp;
ECompList *list0X, *listX0; ECompList *list0X, *listX0;
int hascontents1, hascontents2; int hascontents1, hascontents2;
int match, modified = 0; int match, modified1 = 0, modified2 = 0;
int not_top;
if (file1 == -1) if (file1 == -1)
tc1 = LookupCell(name1); tc1 = LookupCell(name1);
@ -1634,16 +1755,26 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)" Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" makes a better match\n", ecomp->cell1->name, " makes a better match\n", ecomp->cell1->name,
name1, file1); name1, file1);
flattenInstancesOf(name1, file1, ecomp->cell1->name); if (flattenInstancesOf(name1, file1, ecomp->cell1->name) > 0)
modified++; modified1++;
}
else if (ecomp->cell1 && (ecomp->num1 > 0)) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" would make a better match but is prohibited.\n",
ecomp->cell1->name, name1, file1);
} }
if (ecomp->cell2 && (ecomp->num2 > 0) && if (ecomp->cell2 && (ecomp->num2 > 0) &&
(!(ecomp->cell2->flags & CELL_PLACEHOLDER))) { (!(ecomp->cell2->flags & CELL_PLACEHOLDER))) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)" Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" makes a better match\n", ecomp->cell2->name, " makes a better match\n", ecomp->cell2->name,
name2, file2); name2, file2);
flattenInstancesOf(name2, file2, ecomp->cell2->name); if (flattenInstancesOf(name2, file2, ecomp->cell2->name) > 0)
modified++; modified2++;
}
else if (ecomp->cell2 && (ecomp->num2 > 0)) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" would make a better match but is prohibited.\n",
ecomp->cell2->name, name2, file2);
} }
} }
@ -1732,8 +1863,13 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)" Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" makes a better match\n", ecomp->cell2->name, " makes a better match\n", ecomp->cell2->name,
name2, file2); name2, file2);
flattenInstancesOf(name2, file2, ecomp->cell2->name); if (flattenInstancesOf(name2, file2, ecomp->cell2->name) > 0)
modified++; modified2++;
}
else if (ecomp->cell2) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" would make a better match but is prohibited.\n",
ecomp->cell2->name, name2, file2);
} }
} }
} }
@ -1798,8 +1934,13 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)" Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" makes a better match\n", ecomp->cell1->name, " makes a better match\n", ecomp->cell1->name,
name1, file1); name1, file1);
flattenInstancesOf(name1, file1, ecomp->cell1->name); if (flattenInstancesOf(name1, file1, ecomp->cell1->name) > 0)
modified++; modified1++;
}
else if (ecomp->cell1) {
Fprintf(stdout, "Flattening instances of %s in cell %s (%d)"
" would make a better match but is prohibited.\n",
ecomp->cell1->name, name1, file1);
} }
} }
} }
@ -1829,6 +1970,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
// Remove non-matching zero-value devices. This can // Remove non-matching zero-value devices. This can
// be done on a per-instance basis. // be done on a per-instance basis.
not_top = (PeekCompareQueueTop(NULL, NULL, NULL, NULL) == -1) ? FALSE : TRUE;
ecomp = (ECompare *)HashFirst(&compdict); ecomp = (ECompare *)HashFirst(&compdict);
while (ecomp != NULL) { while (ecomp != NULL) {
if ((ecomp->num1 != ecomp->num2) && (ecomp->cell1 != NULL) && if ((ecomp->num1 != ecomp->num2) && (ecomp->cell1 != NULL) &&
@ -1877,6 +2020,44 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
} }
if (found) break; if (found) break;
} }
if (found) {
/* Beware remove shorting devices that */
/* connect two ports. Otherwise the */
/* port lists get screwed up. It is */
/* better in that case to force the */
/* cells to be declared mismatched. */
/* This is ignored for a top-level cell */
/* because it will just show up as a */
/* port mismatch error as it should. */
/* (12/12/2025---disabling this worked; */
/* may need to go back to a failing */
/* example and determine how pin */
/* matching gets scrambled.) */
if ((not_top == TRUE) &&
(ecomp->cell1->class != CLASS_ISOURCE)) {
int found1 = FALSE;
int found2 = FALSE;
for (ob2 = tc1->cell; ob2; ob2 = ob2->next) {
if (!IsPort(ob2)) break;
else if (ob2->node == node1)
found1 = TRUE;
else if (ob2->node == node2)
found2 = TRUE;
if (found1 && found2) {
Fprintf(stdout, "Warning: "
"zero-valued device connects "
"port %s to another port; pin "
"matching may be affected.\n",
ob2->name);
// found = FALSE;
break;
}
}
}
}
if (found) { if (found) {
Fprintf(stdout, "Removing zero-valued device " Fprintf(stdout, "Removing zero-valued device "
"%s from cell %s (%d) makes a better " "%s from cell %s (%d) makes a better "
@ -1888,6 +2069,16 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
if (ecomp->cell1->class != CLASS_ISOURCE) { if (ecomp->cell1->class != CLASS_ISOURCE) {
/* merge node of endpoints */ /* 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) { for (ob2 = tc1->cell; ob2; ob2 = ob2->next) {
if (ob2->node == node2) if (ob2->node == node2)
ob2->node = node1; ob2->node = node1;
@ -1914,7 +2105,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
/* Remove from list */ /* Remove from list */
ecomp->num1--; ecomp->num1--;
modified++; modified1++;
ob1 = lob; ob1 = lob;
} }
@ -1986,6 +2177,27 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
break; break;
} }
} }
/* (See comments above about removing shorts */
/* between two ports.) */
if ((not_top == TRUE) &&
(ecomp->cell2->class != CLASS_ISOURCE)) {
int found1 = FALSE;
int found2 = FALSE;
for (ob1 = tc2->cell; ob1; ob1 = ob1->next) {
if (!IsPort(ob1)) break;
else if (ob1->node == node1)
found1 = TRUE;
else if (ob1->node == node2)
found2 = TRUE;
if (found1 && found2) {
found = FALSE;
break;
}
}
}
if (found) break; if (found) break;
} }
if (found) { if (found) {
@ -1996,6 +2208,16 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
/* merge node of endpoints */ /* merge node of endpoints */
if (ecomp->cell2->class != CLASS_ISOURCE) { 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) { for (ob1 = tc2->cell; ob1; ob1 = ob1->next) {
if (ob1->node == node2) if (ob1->node == node2)
ob1->node = node1; ob1->node = node1;
@ -2021,8 +2243,8 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
} }
/* Remove from list */ /* Remove from list */
ecomp->num1--; ecomp->num2--;
modified++; modified2++;
ob2 = lob; ob2 = lob;
} }
@ -2056,7 +2278,7 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
// are no other modifications, as this rule is relaxed compared to other // are no other modifications, as this rule is relaxed compared to other
// rules, and the other rules should be exhaustively applied first. // rules, and the other rules should be exhaustively applied first.
if ((listX0 != NULL) && (list0X != NULL) && (modified == 0)) { if ((listX0 != NULL) && (list0X != NULL) && ((modified1 + modified2) == 0)) {
ECompare *ecomp0X, *ecompX0; ECompare *ecomp0X, *ecompX0;
ECompList *elist0X, *elistX0; ECompList *elist0X, *elistX0;
for (elistX0 = listX0; elistX0; elistX0 = elistX0->next) { for (elistX0 = listX0; elistX0; elistX0 = elistX0->next) {
@ -2082,13 +2304,24 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
ecompX0->cell1->file, &compdict); ecompX0->cell1->file, &compdict);
if (dstr) *dstr = '['; if (dstr) *dstr = '[';
if ((ncomp == ecomp0X) && (ecomp0X->num2 <= ecompX0->num1)) { if ((ncomp == ecomp0X) && (ecomp0X->num2 <= ecompX0->num1)) {
Fprintf(stdout, "Flattening instances of %s in cell %s" if (!(ecompX0->cell1->flags & CELL_PLACEHOLDER)) {
"(%d) makes a better match\n", Fprintf(stdout, "Flattening instances of %s in cell"
ecompX0->cell1->name, name1, file1); " %s (%d) makes a better match\n",
flattenInstancesOf(name1, file1, ecompX0->cell1->name); ecompX0->cell1->name, name1, file1);
ecompX0->num1 = 0; if (flattenInstancesOf(name1, file1,
ecomp0X->num1 += ecompX0->num1; ecompX0->cell1->name) > 0) {
modified++; ecompX0->num1 = 0;
ecomp0X->num1 += ecompX0->num1;
modified1++;
}
}
else
{
Fprintf(stdout, "Flattening instances of %s in "
"cell %s (%d) would make a better "
"match but is prohibited.\n",
ecompX0->cell1->name, name1, file1);
}
break; break;
} }
} }
@ -2108,13 +2341,23 @@ PrematchLists(char *name1, int file1, char *name2, int file2)
ecomp0X->cell2->file, &compdict); ecomp0X->cell2->file, &compdict);
if (dstr) *dstr = '['; if (dstr) *dstr = '[';
if ((ncomp == ecompX0) && (ecompX0->num1 <= ecomp0X->num2)) { if ((ncomp == ecompX0) && (ecompX0->num1 <= ecomp0X->num2)) {
Fprintf(stdout, "Flattening instances of %s in cell %s" if (!(ecomp0X->cell2->flags & CELL_PLACEHOLDER)) {
" (%d) makes a better match\n", Fprintf(stdout, "Flattening instances of %s in cell"
ecomp0X->cell2->name, name2, file2); " %s (%d) makes a better match\n",
flattenInstancesOf(name2, file2, ecomp0X->cell2->name); ecomp0X->cell2->name, name2, file2);
ecomp0X->num2 = 0; if (flattenInstancesOf(name2, file2,
ecompX0->num2 += ecomp0X->num2; ecomp0X->cell2->name) > 0) {
modified++; ecomp0X->num2 = 0;
ecompX0->num2 += ecomp0X->num2;
modified2++;
}
}
else {
Fprintf(stdout, "Flattening instances of %s in "
"cell %s (%d) would make a better "
"match but is prohibited.\n",
ecompX0->cell2->name, name2, file2);
}
break; break;
} }
} }
@ -2145,5 +2388,17 @@ done:
FREE(list0X); FREE(list0X);
list0X = nextptr; list0X = nextptr;
} }
return modified;
// If either netlist was modified, rebuild its node cache
if (modified1 > 0) {
FreeNodeNames(tc1);
CacheNodeNames(tc1);
}
if (modified2 > 0) {
FreeNodeNames(tc2);
CacheNodeNames(tc2);
}
return modified1 + modified2;
} }

View File

@ -137,32 +137,39 @@ static unsigned char uppercase[] = {
// horrible things can happen, as, for example, names AOI12 and OAI12 // horrible things can happen, as, for example, names AOI12 and OAI12
// have exactly the same hash result. Lousy for binning and even // have exactly the same hash result. Lousy for binning and even
// lousier for generating class magic numbers. // lousier for generating class magic numbers.
//
// Updated again 4/2/2026 to the FNV-1a hash, which is better than
// SDBM for this application, according to ChatGPT.
unsigned long hashnocase(char *s, int hashsize) unsigned long hashnocase(char *s, int hashsize)
{ {
unsigned long hashval; unsigned long hashval = 2166136261ul;
for (; *s != '\0'; s++) {
for (hashval = 0; *s != '\0'; ) hashval ^= uppercase[*s];
hashval = uppercase[*s++] hashval *= 16777619ul;
+ (hashval << 6) + (hashval << 16) - hashval; }
return (hashsize == 0) ? hashval : (hashval % hashsize); return (hashsize == 0) ? hashval : (hashval % hashsize);
} }
unsigned long hashcase(char *s, int hashsize) unsigned long hashcase(char *s, int hashsize)
{ {
unsigned long hashval; unsigned long hashval = 2166136261ul;
for (; *s != '\0'; s++) {
for (hashval = 0; *s != '\0'; ) hashval ^= (unsigned char)(*s);
hashval = (*s++) + (hashval << 6) + (hashval << 16) - hashval; hashval *= 16777619ul;
}
return (hashsize == 0) ? hashval : (hashval % hashsize); return (hashsize == 0) ? hashval : (hashval % hashsize);
} }
unsigned long genhash(char *s, int c, int hashsize) unsigned long genhash(char *s, int c, int hashsize)
{ {
unsigned long hashval; unsigned long hashval = 2166136261ul;
hashval ^= (unsigned long)c;
for (hashval = (unsigned long)c; *s != '\0'; ) hashval *= 16777619ul;
hashval = (*s++) + (hashval << 6) + (hashval << 16) - hashval; for (; *s != '\0'; s++) {
hashval ^= (unsigned char)(*s);
hashval *= 16777619ul;
}
return (hashsize == 0) ? hashval : (hashval % hashsize); return (hashsize == 0) ? hashval : (hashval % hashsize);
} }

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. */ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* inetcomp.c -- a simple wrapper to the NETCOMP() function */ /* inetcomp.c -- a simple wrapper to the NETCOMP() function */
#include "config.h"
#include <stdio.h> #include <stdio.h>
#include "netgen.h" #include "netgen.h"
@ -33,7 +34,7 @@ void STRCPY(char *dest, char *source)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
char cell1[200], cell2[200]; char cell1[MAX_STR_LEN], cell2[MAX_STR_LEN];
Debug = 0; Debug = 0;
if (argc != 1) { if (argc != 1) {

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,7 @@ extern struct nlist *Circuit1;
extern struct nlist *Circuit2; extern struct nlist *Circuit2;
extern int ExhaustiveSubdivision; extern int ExhaustiveSubdivision;
extern int ExactTopology;
extern int left_col_end; extern int left_col_end;
extern int right_col_end; extern int right_col_end;
@ -37,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 PermuteForget(char *model, int filenum, char *pin1, char *pin2);
extern int EquivalenceElements(char *name1, int file1, char *name2, int file2); extern int EquivalenceElements(char *name1, int file1, char *name2, int file2);
extern int EquivalenceNodes(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 IgnoreClass(char *name, int file, unsigned char type);
extern int MatchPins(struct nlist *tp1, struct nlist *tp2, int dolist); extern int MatchPins(struct nlist *tp1, struct nlist *tp2, int dolist);
extern int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, extern int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run,
@ -60,7 +62,7 @@ extern void RegroupDataStructures();
extern void FormatIllegalElementClasses(); extern void FormatIllegalElementClasses();
extern void FormatIllegalNodeClasses(); extern void FormatIllegalNodeClasses();
extern int ResolveAutomorphsByProperty(); extern int ResolveAutomorphsByProperty();
extern int ResolveAutomorphsByPin(); extern int ResolveAutomorphsByPin(int match_nets);
extern void SummarizeElementClasses(struct ElementClass *EC); extern void SummarizeElementClasses(struct ElementClass *EC);
extern int remove_group_tags(struct objlist *ob); extern int remove_group_tags(struct objlist *ob);
@ -68,6 +70,8 @@ extern int remove_group_tags(struct objlist *ob);
#ifdef TCL_NETGEN #ifdef TCL_NETGEN
extern int EquivalentNode(); extern int EquivalentNode();
extern int EquivalentElement(); extern int EquivalentElement();
extern void DeriveAreaProperty();
extern void DerivePerimeterProperty();
extern void enable_interrupt(); extern void enable_interrupt();
extern void disable_interrupt(); extern void disable_interrupt();

View File

@ -183,7 +183,6 @@ void CloseFile(char *filename)
fclose(outfile); fclose(outfile);
} }
/* STUFF TO READ INPUT FILES */ /* STUFF TO READ INPUT FILES */
static char *line = NULL; /* actual line read in */ static char *line = NULL; /* actual line read in */
@ -207,6 +206,21 @@ struct hashdict *definitions = (struct hashdict *)NULL;
#define WHITESPACE_DELIMITER " \t\n\r" #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() --- */ /* TrimQuoted() --- */
/* Remove spaces from inside single- or double-quoted strings. */ /* Remove spaces from inside single- or double-quoted strings. */
@ -288,7 +302,7 @@ int GetNextLineNoNewline(char *delimiter)
{ {
char *newbuf; char *newbuf;
int testc; int testc;
int nested = 0; static int nested = 0;
int llen; int llen;
if (feof(infile)) return -1; if (feof(infile)) return -1;
@ -315,6 +329,11 @@ int GetNextLineNoNewline(char *delimiter)
llen = strlen(line); llen = strlen(line);
} }
while (llen == linesize - 1) { while (llen == linesize - 1) {
/* Note that in the rare case where a newline is in the last buffer
* position, we're done.
*/
if (*(line + llen - 1) == '\n') break;
newbuf = (char *)MALLOC(linesize + 501); newbuf = (char *)MALLOC(linesize + 501);
strcpy(newbuf, line); strcpy(newbuf, line);
FREE(line); FREE(line);
@ -573,19 +592,31 @@ void SkipTokNoNewline(char *delimiter)
/* */ /* */
/* Modified 3/30/2015 to include the condition where a comment line is */ /* Modified 3/30/2015 to include the condition where a comment line is */
/* in the middle of a series of continuation lines. */ /* in the middle of a series of continuation lines. */
/* */
/* Modified 1/3/2024 to avoid skipping two lines if a line has only the */
/* comment character '*' followed by a newline. It seems that '\n' is */
/* being ignored in WHITESPACE_DELIMITER, but it's easier to write the */
/* code to find the exception rather than track down the problem in */
/* GetNextLine(). */
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
void SpiceTokNoNewline(void) void SpiceTokNoNewline(void)
{ {
int contline; int contline;
if ((nexttok = strdtok(NULL, WHITESPACE_DELIMITER, NULL)) != NULL) return; if ((nexttok = strdtok0(NULL, WHITESPACE_DELIMITER, NULL, FALSE)) != NULL) return;
while (nexttok == NULL) { while (nexttok == NULL) {
contline = getc(infile); contline = getc(infile);
if (contline == '*') { if (contline == '*') {
GetNextLine(WHITESPACE_DELIMITER); char testline = ' ';
SkipNewLine(NULL); while ((testline == ' ') || (testline == '\t'))
testline = getc(infile);
if (testline != '\n') {
ungetc(testline, infile);
GetNextLine(WHITESPACE_DELIMITER);
SkipNewLine(NULL);
}
continue; continue;
} }
else if (contline != '+') { else if (contline != '+') {
@ -597,7 +628,8 @@ void SpiceTokNoNewline(void)
} }
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
/* Skip to the next token, ignoring any C-style comments. */ /* Skip to the next token, ignoring any C-style comments and verilog */
/* "(* ... *)"-style comments. */
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
void SkipTokComments(char *delimiter) void SkipTokComments(char *delimiter)
@ -613,6 +645,11 @@ void SkipTokComments(char *delimiter)
SkipTok(delimiter); SkipTok(delimiter);
if (nexttok) SkipTok(delimiter); if (nexttok) SkipTok(delimiter);
} }
else if (match(nexttok, "(*")) {
while (nexttok && !match(nexttok, "*)"))
SkipTok(delimiter);
if (nexttok) SkipTok(delimiter);
}
else break; else break;
} }
} }
@ -648,6 +685,7 @@ void SpiceSkipNewLine(void)
ungetc(contline, infile); ungetc(contline, infile);
} }
#if 0 /* Commented with "#if 0" due to comment characters in the comment */
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
/* Function similar to strtok() for token parsing. The difference is */ /* Function similar to strtok() for token parsing. The difference is */
/* that it takes two sets of delimiters. The first is whitespace */ /* that it takes two sets of delimiters. The first is whitespace */
@ -668,8 +706,9 @@ void SpiceSkipNewLine(void)
/* the first character of the delimiter string in addition to marking */ /* the first character of the delimiter string in addition to marking */
/* the boundary between two-character and one-character delimiters. */ /* the boundary between two-character and one-character delimiters. */
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
#endif
char *strdtok(char *pstring, char *delim1, char *delim2) char *strdtok0(char *pstring, char *delim1, char *delim2, char isverilog)
{ {
static char *stoken = NULL; static char *stoken = NULL;
static char *sstring = NULL; static char *sstring = NULL;
@ -714,10 +753,10 @@ char *strdtok(char *pstring, char *delim1, char *delim2)
/* should know whether it is parsing SPICE or verilog and handle the syntax */ /* should know whether it is parsing SPICE or verilog and handle the syntax */
/* accordingly (needs to be done). */ /* accordingly (needs to be done). */
if (*s == '\\') { if (isverilog && (*s == '\\')) {
s++; s++;
while (*s != '\0') { while (*s != '\0') {
if ((*s == ' ') || (*s == '\\')) { if ((*s == ' ') || ((*s == '\\') && (*(s + 1) == '\0'))) {
s++; s++;
break; break;
} }
@ -785,6 +824,17 @@ char *strdtok(char *pstring, char *delim1, char *delim2)
return sstring; return sstring;
} }
/*----------------------------------------------------------------------*/
/* strdtok() is the original string tokenizer. It calls strdtok0() */
/* with isverilog=TRUE, so that tokens are parsed as (potentially) */
/* verilog names, which includes verilog backslash notation. */
/*----------------------------------------------------------------------*/
char *strdtok(char *pstring, char *delim1, char *delim2)
{
return strdtok0(pstring, delim1, delim2, TRUE);
}
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
void InputParseError(FILE *f) void InputParseError(FILE *f)
@ -866,7 +916,7 @@ char *ReadNetlist(char *fname, int *fnum)
}; };
#ifdef mips #ifdef mips
struct filetype formats[7]; struct filetype formats[8];
formats[0].extension = NTK_EXTENSION; formats[0].extension = NTK_EXTENSION;
formats[0].proc = ReadNtk; formats[0].proc = ReadNtk;
@ -874,14 +924,16 @@ char *ReadNetlist(char *fname, int *fnum)
formats[1].proc = ReadExtHier; formats[1].proc = ReadExtHier;
formats[2].extension = SIM_EXTENSION; formats[2].extension = SIM_EXTENSION;
formats[2].proc = ReadSim; formats[2].proc = ReadSim;
formats[3].extension = SPICE_EXTENSION; formats[3].extension = PRM_EXTENSION;
formats[3].proc = ReadSpice; formats[3].proc = ReadPrm;
formats[4].extension = NETGEN_EXTENSION; formats[4].extension = SPICE_EXTENSION;
formats[4].proc = ReadNetgenFile; formats[4].proc = ReadSpice;
formats[5].extension = VERILOG_EXTENSION; formats[5].extension = NETGEN_EXTENSION;
formats[5].proc = ReadVerilogFile; formats[5].proc = ReadNetgenFile;
formats[6].extension = NULL; formats[6].extension = VERILOG_EXTENSION;
formats[6].proc = NULL; formats[6].proc = ReadVerilogFile;
formats[7].extension = NULL;
formats[7].proc = NULL;
#else /* not mips (i.e. compiler with reasonable initializers) */ #else /* not mips (i.e. compiler with reasonable initializers) */
@ -890,6 +942,7 @@ char *ReadNetlist(char *fname, int *fnum)
{NTK_EXTENSION, ReadNtk}, {NTK_EXTENSION, ReadNtk},
{EXT_EXTENSION, ReadExtHier}, {EXT_EXTENSION, ReadExtHier},
{SIM_EXTENSION, ReadSim}, {SIM_EXTENSION, ReadSim},
{PRM_EXTENSION, ReadPrm},
{SPICE_EXTENSION, ReadSpice}, {SPICE_EXTENSION, ReadSpice},
{SPICE_EXT2, ReadSpice}, {SPICE_EXT2, ReadSpice},
{SPICE_EXT3, ReadSpice}, {SPICE_EXT3, ReadSpice},
@ -914,7 +967,7 @@ char *ReadNetlist(char *fname, int *fnum)
} }
/* try appending extensions in sequence, and testing for file existance */ /* try appending extensions in sequence, and testing for file existance */
for (index = 0; formats[index].extension != NULL; index++) { for (index = 0; formats[index].extension != NULL; index++) {
char testname[200]; char testname[MAX_STR_LEN];
strcpy(testname, fname); strcpy(testname, fname);
strcat(testname, formats[index].extension); strcat(testname, formats[index].extension);
if (OpenParseFile(testname, *fnum) >= 0) { if (OpenParseFile(testname, *fnum) >= 0) {
@ -1019,7 +1072,7 @@ void WriteNetgenFile(char *name, char *filename)
char *ReadNetgenFile (char *fname, int *fnum) char *ReadNetgenFile (char *fname, int *fnum)
{ {
char name[100]; char name[MAX_STR_LEN];
char *LastCellRead = NULL; char *LastCellRead = NULL;
int filenum; int filenum;
@ -1255,7 +1308,7 @@ int READ(void *buf, int bytes)
char *ReadNetgenFile (char *fname, int *fnum) char *ReadNetgenFile (char *fname, int *fnum)
{ {
char name[100]; char name[MAX_STR_LEN];
int len, chars; int len, chars;
char *LastCellRead = NULL; char *LastCellRead = NULL;

View File

@ -7,6 +7,7 @@
#define WOMBAT_EXTENSION ".wom" #define WOMBAT_EXTENSION ".wom"
#define EXT_EXTENSION ".ext" #define EXT_EXTENSION ".ext"
#define SIM_EXTENSION ".sim" #define SIM_EXTENSION ".sim"
#define PRM_EXTENSION ".prm"
#define SPICE_EXTENSION ".spice" #define SPICE_EXTENSION ".spice"
#define SPICE_EXT2 ".spc" #define SPICE_EXT2 ".spc"
#define SPICE_EXT3 ".sp" #define SPICE_EXT3 ".sp"
@ -35,6 +36,7 @@ extern struct hashdict *definitions;
extern char *nexttok; extern char *nexttok;
#define SKIPTO(a) do {SkipTok(NULL);} while (!match(nexttok,a)) #define SKIPTO(a) do {SkipTok(NULL);} while (!match(nexttok,a))
extern char *strdtok0(char *pstring, char *delim1, char *delim2, char isverilog);
extern char *strdtok(char *pstring, char *delim1, char *delim2); extern char *strdtok(char *pstring, char *delim1, char *delim2);
extern char *GetLineAtTok(); extern char *GetLineAtTok();
extern void SkipTok(char *delimiter); extern void SkipTok(char *delimiter);
@ -47,5 +49,7 @@ extern void InputParseError(FILE *f);
extern int OpenParseFile(char *name, int fnum); extern int OpenParseFile(char *name, int fnum);
extern int EndParseFile(void); extern int EndParseFile(void);
extern int CloseParseFile(void); extern int CloseParseFile(void);
extern void SeekFile(long offset); /* handles verilog 'for' loops */
extern long TellFile(); /* handles verilog 'for' loops */
#endif /* _NETFILE_H */ #endif /* _NETFILE_H */

View File

@ -25,6 +25,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> /* for strtof() */ #include <stdlib.h> /* for strtof() */
#include <stdarg.h> #include <stdarg.h>
#include <string.h>
#include <strings.h>
#include <ctype.h> /* toupper() */ #include <ctype.h> /* toupper() */
#ifdef IBMPC #ifdef IBMPC
#include <alloc.h> #include <alloc.h>
@ -57,7 +59,7 @@ int AddToExistingDefinition = 0; /* default: overwrite cell when reopened */
extern int errno; /* Defined in stdlib.h */ extern int errno; /* Defined in stdlib.h */
#define MAX_STATIC_STRINGS 5 #define MAX_STATIC_STRINGS 5
static char staticstrings[MAX_STATIC_STRINGS][200]; static char staticstrings[MAX_STATIC_STRINGS][MAX_STR_LEN];
static int laststring; static int laststring;
extern struct hashdict spiceparams; /* From spice.c */ extern struct hashdict spiceparams; /* From spice.c */
@ -300,7 +302,9 @@ int ReduceOneExpression(struct valuelist *kv, struct objlist *parprops,
tstr = sstr - 1; tstr = sstr - 1;
numlast = 1; numlast = 1;
} }
break; /* But might not be. . . */
if ((dval != 0) || (sstr > estr))
break;
} }
/* Not a number, so must be arithmetic */ /* Not a number, so must be arithmetic */
*tstr = '\0'; *tstr = '\0';
@ -320,7 +324,9 @@ int ReduceOneExpression(struct valuelist *kv, struct objlist *parprops,
tstr = sstr - 1; tstr = sstr - 1;
numlast = 1; numlast = 1;
} }
break; /* But might not be. . . */
if ((dval != 0) || (sstr > estr))
break;
} }
/* Not a number, so must be arithmetic */ /* Not a number, so must be arithmetic */
*tstr = '\0'; *tstr = '\0';
@ -984,6 +990,51 @@ PropertyDelete(char *name, int fnum, char *key)
return 0; 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. */ /* Set the tolerance of a property in the master cell record. */
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
@ -2199,7 +2250,10 @@ int PromoteProperty(struct property *prop, struct valuelist *vl,
if (prop == NULL || vl == NULL) return -1; if (prop == NULL || vl == NULL) return -1;
if (prop->type == vl->type) return 1; /* Nothing to do */ if (prop->type == vl->type) return 1; /* Nothing to do */
result = 0; result = 0;
if (prop->type == PROP_EXPRESSION) { /* If vl is an expression but prop is not, then try to reduce
* the expression in vl.
*/
if (vl->type == PROP_EXPRESSION) {
ReduceOneExpression(vl, ob, tc, FALSE); ReduceOneExpression(vl, ob, tc, FALSE);
} }
switch (prop->type) { switch (prop->type) {
@ -3045,7 +3099,7 @@ void add_balancing_close(struct objlist *ob1, struct objlist *ob2)
for (nob = ob1->next; nob && nob->type != FIRSTPIN; nob = nob->next) for (nob = ob1->next; nob && nob->type != FIRSTPIN; nob = nob->next)
if (nob->type == PROPERTY) if (nob->type == PROPERTY)
break; break;
if (nob->type != PROPERTY) return; // shouldn't happen if (nob == NULL || nob->type != PROPERTY) return; // shouldn't happen
opentags = 0; opentags = 0;
for (; nob->next && nob->next->type == PROPERTY; nob = nob->next) { for (; nob->next && nob->next->type == PROPERTY; nob = nob->next) {
@ -3595,7 +3649,7 @@ int CombineSeries(char *model, int file)
nob->type = PROPERTY; nob->type = PROPERTY;
nob->name = strsave("properties"); nob->name = strsave("properties");
nob->node = -2; /* Don't report as disconnected node */ nob->node = -2; /* Don't report as disconnected node */
nob->model.class = (obp->model.class == NULL) ? NULL : nob->model.class = (obp == NULL || obp->model.class == NULL) ? NULL :
strsave(obp->model.class); strsave(obp->model.class);
nob->instance.props = NewPropValue(2); nob->instance.props = NewPropValue(2);

View File

@ -39,6 +39,7 @@ extern void SetParallelCombine(int value);
extern void SetSeriesCombine(int value); extern void SetSeriesCombine(int value);
extern int PropertyTolerance(char *name, int fnum, char *key, int ival, extern int PropertyTolerance(char *name, int fnum, char *key, int ival,
double dval); 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, extern int PropertyMerge(char *name, int fnum, char *key, int merge_type,
int merge_mask); int merge_mask);
extern void ResolveProperties(char *name1, int file1, char *name2, int file2); extern void ResolveProperties(char *name1, int file1, char *name2, int file2);
@ -190,6 +191,7 @@ extern char *ReadNtk (char *fname, int *fnum);
extern char *ReadExtHier(char *fname, int *fnum); extern char *ReadExtHier(char *fname, int *fnum);
extern char *ReadExtFlat(char *fname, int *fnum); extern char *ReadExtFlat(char *fname, int *fnum);
extern char *ReadSim(char *fname, int *fnum); extern char *ReadSim(char *fname, int *fnum);
extern char *ReadPrm(char *fname, int *fnum);
extern char *ReadSpice(char *fname, int *fnum); extern char *ReadSpice(char *fname, int *fnum);
extern char *ReadSpiceLib(char *fname, int *fnum); extern char *ReadSpiceLib(char *fname, int *fnum);
extern char *ReadNetgenFile (char *fname, int *fnum); extern char *ReadNetgenFile (char *fname, int *fnum);

View File

@ -181,7 +181,7 @@ void Ntk(char *name, char *filename)
char *ReadNtk (char *fname, int *fnum) 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; struct objlist *ob;
int CellDefInProgress = 0; int CellDefInProgress = 0;
int filenum; int filenum;
@ -218,7 +218,7 @@ char *ReadNtk (char *fname, int *fnum)
} }
} }
else if (match(nexttok, "s")) { else if (match(nexttok, "s")) {
char last[100]; char last[MAX_STR_LEN];
*last = '\0'; *last = '\0';
if (!CellDefInProgress) { if (!CellDefInProgress) {
/* fake cell declaration for top-level call */ /* fake cell declaration for top-level call */

View File

@ -130,6 +130,7 @@ struct property *NewProperty(void)
kl = (struct property *)CALLOC(1,sizeof(struct property)); kl = (struct property *)CALLOC(1,sizeof(struct property));
if (kl == NULL) Fprintf(stderr,"NewProperty: Core allocation error\n"); if (kl == NULL) Fprintf(stderr,"NewProperty: Core allocation error\n");
kl->pin = (char *)NULL;
return (kl); return (kl);
} }
@ -222,12 +223,35 @@ int matchnocase(char *st1, char *st2)
{ {
char *sp1 = st1; char *sp1 = st1;
char *sp2 = st2; char *sp2 = st2;
char v1 = FALSE, v2 = FALSE;
/* In case of a property that does not exist in one netlist, matchnocase()
* may be passed a null value, so return 0 to indicate a non-match.
* *Both* values null will also be treated as a mismatch (debatable
* behavior).
*/
if (!sp1 || !sp2) return 0;
/* Verilog back-slash escaped names should match an equivalent non-
* back-slashed name. (NOTE: This behavior needs to be added to match().)
*/
if ((*sp1 == '\\') && (*sp2 != '\\')) {
v1 = TRUE;
sp1++;
}
if ((*sp2 == '\\') && (*sp1 != '\\')) {
v2 = TRUE;
sp2++;
}
while (*sp1 != '\0' && *sp2 != '\0') { while (*sp1 != '\0' && *sp2 != '\0') {
if (to_lower[*sp1] != to_lower[*sp2]) break; if (to_lower[*sp1] != to_lower[*sp2]) break;
sp1++; sp1++;
sp2++; sp2++;
} }
if (v1 && (*sp1 == ' ')) sp1++;
if (v2 && (*sp2 == ' ')) sp2++;
if ((*sp1 != '\0') || (*sp2 != '\0')) return 0; if ((*sp1 != '\0') || (*sp2 != '\0')) return 0;
return 1; return 1;
} }
@ -258,6 +282,33 @@ int matchfilenocase(char *st1, char *st2, int f1, int f2)
return 1; return 1;
} }
/* Delimiter matching---Find an opening delimiter in a string. */
/* Return the position of the first opening delimeter in the string, */
/* like strchr(). Place the actual delimeter character in *delim. */
char *get_array_delimiter(char *name, char *delim)
{
char *stest = name;
while (*stest != '\0')
{
if (to_lower[*stest] == '<') {
*delim = *stest;
return stest;
}
stest++;
}
return NULL;
}
/* Delimiter parsing---Check if a character is an opening array delimiter. */
/* Return TRUE if the character is an opening delimiter, FALSE if not. */
int is_delimiter(char testc)
{
return (to_lower[testc] == '<') ? TRUE : FALSE;
}
#ifdef HAVE_MALLINFO #ifdef HAVE_MALLINFO
void PrintMemoryStats(void) void PrintMemoryStats(void)
{ {
@ -425,6 +476,7 @@ int removeshorted(struct hashlist *p, int file)
ob = nob; ob = nob;
} }
} }
return 1;
} }
/* Remove shorted instances of class "class" from the database */ /* Remove shorted instances of class "class" from the database */
@ -440,15 +492,32 @@ void RemoveShorted(char *class, int file)
RecurseCellFileHashTable(removeshorted, 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) int deleteclass(struct hashlist *p, int file)
{ {
struct nlist *ptr; struct nlist *ptr;
struct objlist *ob, *lob, *nob; struct objlist *ob, *lob, *nob, *portnode;
unsigned char *checknodes;
int i;
ptr = (struct nlist *)(p->ptr); ptr = (struct nlist *)(p->ptr);
if ((file != -1) && (ptr->file != file)) return 0; 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; lob = NULL;
for (ob = ptr->cell; ob != NULL;) { for (ob = ptr->cell; ob != NULL;) {
nob = ob->next; nob = ob->next;
@ -456,6 +525,8 @@ int deleteclass(struct hashlist *p, int file)
if ((*matchfunc)(ob->model.class, OldCell->name)) { if ((*matchfunc)(ob->model.class, OldCell->name)) {
HashDelete(ob->instance.name, &(ptr->instdict)); HashDelete(ob->instance.name, &(ptr->instdict));
while (1) { while (1) {
if (ob->type >= FIRSTPIN)
checknodes[ob->node] = (unsigned char)1;
FreeObjectAndHash(ob, ptr); FreeObjectAndHash(ob, ptr);
ob = nob; ob = nob;
if (ob == NULL) break; if (ob == NULL) break;
@ -477,6 +548,26 @@ int deleteclass(struct hashlist *p, int file)
ob = nob; 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);
return 1;
} }
/* Remove all instances of class "class" from the database */ /* Remove all instances of class "class" from the database */
@ -514,6 +605,7 @@ int renameinstances(struct hashlist *p, int file)
} }
} }
} }
return 1;
} }
void InstanceRename(char *from, char *to, int file) void InstanceRename(char *from, char *to, int file)
@ -536,9 +628,10 @@ int freeprop(struct hashlist *p)
struct property *prop; struct property *prop;
prop = (struct property *)(p->ptr); prop = (struct property *)(p->ptr);
if (prop->type == PROP_STRING) if (prop->type == PROP_STRING) {
if (prop->pdefault.string != NULL) if (prop->pdefault.string != NULL)
FREE(prop->pdefault.string); FREE(prop->pdefault.string);
}
else if (prop->type == PROP_EXPRESSION) { else if (prop->type == PROP_EXPRESSION) {
struct tokstack *stackptr, *nptr; struct tokstack *stackptr, *nptr;
stackptr = prop->pdefault.stack; stackptr = prop->pdefault.stack;
@ -557,65 +650,65 @@ int freeprop(struct hashlist *p)
void CellDelete(char *name, int fnum) void CellDelete(char *name, int fnum)
{ {
/* delete all the contents of cell 'name', and remove 'name' from /* delete all the contents of cell 'name', and remove 'name' from
the cell hash table. NOTE: this procedure does not care or check the cell hash table. NOTE: this procedure does not care or check
if 'name' has been instanced anywhere. It is assumed that if this if 'name' has been instanced anywhere. It is assumed that if this
is the case, the user will (quickly) define a new cell of that name. is the case, the user will (quickly) define a new cell of that name.
*/ */
struct objlist *ob, *obnext; struct objlist *ob, *obnext;
struct nlist *tp; struct nlist *tp;
tp = LookupCellFile(name, fnum); tp = LookupCellFile(name, fnum);
if (tp == NULL) { if (tp == NULL) {
Printf ("No cell '%s' found.\n", name); Printf ("No cell '%s' found.\n", name);
return; return;
} }
HashIntDelete(name, fnum, &cell_dict); HashIntDelete(name, fnum, &cell_dict);
/* now make sure that we free all the fields of the nlist struct */ /* now make sure that we free all the fields of the nlist struct */
if (tp->name != NULL) FREE(tp->name); if (tp->name != NULL) FREE(tp->name);
HashKill(&(tp->objdict)); HashKill(&(tp->objdict));
HashKill(&(tp->instdict)); HashKill(&(tp->instdict));
RecurseHashTable(&(tp->propdict), freeprop); RecurseHashTable(&(tp->propdict), freeprop);
HashKill(&(tp->propdict)); HashKill(&(tp->propdict));
FreeNodeNames(tp); FreeNodeNames(tp);
ob = tp->cell; ob = tp->cell;
while (ob != NULL) { while (ob != NULL) {
obnext = ob->next; obnext = ob->next;
FreeObject (ob); FreeObject (ob);
ob = obnext; ob = obnext;
} }
} }
static int PrintCellHashTableElement(struct hashlist *p) static int PrintCellHashTableElement(struct hashlist *p)
{ {
struct nlist *ptr; struct nlist *ptr;
ptr = (struct nlist *)(p->ptr); ptr = (struct nlist *)(p->ptr);
if ((TopFile >= 0) && (ptr->file != TopFile)) return 1; if ((TopFile >= 0) && (ptr->file != TopFile)) return 1;
if (ptr->class != CLASS_SUBCKT) { if ((ptr->class != CLASS_SUBCKT) && (ptr->class != CLASS_MODULE)) {
/* only print primitive cells if Debug is enabled */ /* only print primitive cells if Debug is enabled */
if (Debug == 1) Printf("Cell: %s (instanced %d times); Primitive\n", if (Debug == 1) Printf("Cell: %s (instanced %d times); Primitive\n",
ptr->name, ptr->number); ptr->name, ptr->number);
else if (Debug == 3) { /* list */ else if (Debug == 3) { /* list */
#ifdef TCL_NETGEN #ifdef TCL_NETGEN
Tcl_AppendElement(netgeninterp, ptr->name); Tcl_AppendElement(netgeninterp, ptr->name);
#else #else
Printf("%s ", ptr->name); Printf("%s ", ptr->name);
#endif #endif
} }
} }
else if ((Debug == 2) || (Debug == 3)) { /* list only */ else if ((Debug == 2) || (Debug == 3)) { /* list only */
#ifdef TCL_NETGEN #ifdef TCL_NETGEN
Tcl_AppendElement(netgeninterp, ptr->name); Tcl_AppendElement(netgeninterp, ptr->name);
#else #else
Printf("%s ", ptr->name); Printf("%s ", ptr->name);
#endif #endif
} }
else else
Printf("Cell: %s (instanced %d times)\n",ptr->name,ptr->number); Printf("Cell: %s (instanced %d times)\n", ptr->name, ptr->number);
return(1); return(1);
} }
/* Print the contents of the cell hash table. */ /* Print the contents of the cell hash table. */
@ -624,65 +717,65 @@ static int PrintCellHashTableElement(struct hashlist *p)
void PrintCellHashTable(int full, int filenum) void PrintCellHashTable(int full, int filenum)
{ {
int total, bins; int total, bins;
int OldDebug; int OldDebug;
if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) {
PrintCellHashTable(full, Circuit1->file); PrintCellHashTable(full, Circuit1->file);
PrintCellHashTable(full, Circuit2->file); PrintCellHashTable(full, Circuit2->file);
return; return;
} }
TopFile = filenum; TopFile = filenum;
bins = RecurseHashTable(&cell_dict, CountHashTableBinsUsed); bins = RecurseHashTable(&cell_dict, CountHashTableBinsUsed);
total = RecurseHashTable(&cell_dict, CountHashTableEntries); total = RecurseHashTable(&cell_dict, CountHashTableEntries);
if (full < 2) if (full < 2)
Printf("Hash table: %d of %d bins used; %d cells total (%.2f per bin)\n", Printf("Hash table: %d of %d bins used; %d cells total (%.2f per bin)\n",
bins, CELLHASHSIZE, total, (bins == 0) ? 0 : bins, CELLHASHSIZE, total, (bins == 0) ? 0 :
(float)((float)total / (float)bins)); (float)((float)total / (float)bins));
OldDebug = Debug; OldDebug = Debug;
Debug = full; Debug = full;
RecurseHashTable(&cell_dict, PrintCellHashTableElement); RecurseHashTable(&cell_dict, PrintCellHashTableElement);
Debug = OldDebug; Debug = OldDebug;
#ifndef TCL_NETGEN #ifndef TCL_NETGEN
if (full >= 2) Printf("\n"); if (full >= 2) Printf("\n");
#endif #endif
} }
struct nlist *FirstCell(void) struct nlist *FirstCell(void)
{ {
return((struct nlist *)HashFirst(&cell_dict)); return((struct nlist *)HashFirst(&cell_dict));
} }
struct nlist *NextCell(void) struct nlist *NextCell(void)
{ {
return((struct nlist *)HashNext(&cell_dict)); return((struct nlist *)HashNext(&cell_dict));
} }
static int ClearDumpedElement(struct hashlist *np) static int ClearDumpedElement(struct hashlist *np)
{ {
struct nlist *p; struct nlist *p;
p = (struct nlist *)(np->ptr); p = (struct nlist *)(np->ptr);
p->dumped = 0; p->dumped = 0;
return(1); return(1);
} }
void ClearDumpedList(void) void ClearDumpedList(void)
{ {
RecurseHashTable(&cell_dict, ClearDumpedElement); RecurseHashTable(&cell_dict, ClearDumpedElement);
} }
int RecurseCellHashTable(int (*foo)(struct hashlist *np)) int RecurseCellHashTable(int (*foo)(struct hashlist *np))
{ {
return RecurseHashTable(&cell_dict, foo); return RecurseHashTable(&cell_dict, foo);
} }
int RecurseCellFileHashTable(int (*foo)(struct hashlist *, int), int value) int RecurseCellFileHashTable(int (*foo)(struct hashlist *, int), int value)
{ {
return RecurseHashTableValue(&cell_dict, foo, value); return RecurseHashTableValue(&cell_dict, foo, value);
} }
/* Yet another version, passing one parameter that is a pointer */ /* Yet another version, passing one parameter that is a pointer */
@ -690,14 +783,14 @@ int RecurseCellFileHashTable(int (*foo)(struct hashlist *, int), int value)
struct nlist *RecurseCellHashTable2(struct nlist *(*foo)(struct hashlist *, struct nlist *RecurseCellHashTable2(struct nlist *(*foo)(struct hashlist *,
void *), void *pointer) void *), void *pointer)
{ {
return RecurseHashTablePointer(&cell_dict, foo, pointer); return RecurseHashTablePointer(&cell_dict, foo, pointer);
} }
/************************** WILD-CARD STUFF *******************************/ /************************** WILD-CARD STUFF *******************************/
char *FixTemplate(char *t) char *FixTemplate(char *t)
{ {
char buffer[200]; char buffer[MAX_STR_LEN];
char *rstr; char *rstr;
int i,j; int i,j;
int InsideBrace; int InsideBrace;
@ -1208,7 +1301,7 @@ static char *OldNodeName(struct nlist *tp, int node)
struct objlist *firstuniqueglobal; struct objlist *firstuniqueglobal;
struct objlist *firstglobal; struct objlist *firstglobal;
struct objlist *firstpin; struct objlist *firstpin;
static char StrBuffer[100]; static char StrBuffer[MAX_STR_LEN];
#if 0 #if 0
/* make second pass, looking for ports */ /* make second pass, looking for ports */

View File

@ -135,6 +135,7 @@ struct property {
unsigned char idx; /* index into valuelist */ unsigned char idx; /* index into valuelist */
unsigned char type; /* string, integer, double, value, expression */ unsigned char type; /* string, integer, double, value, expression */
unsigned char merge; /* how property changes when devices are merged */ unsigned char merge; /* how property changes when devices are merged */
char *pin; /* associated pin (or NULL if not associated) */
union { union {
char *string; char *string;
double dval; double dval;
@ -206,7 +207,7 @@ struct nlist {
char *name; char *name;
int number; /* number of instances defined */ int number; /* number of instances defined */
int dumped; /* instance count, and general-purpose marker */ int dumped; /* instance count, and general-purpose marker */
unsigned char flags; unsigned short flags;
unsigned char class; unsigned char class;
unsigned long classhash; /* randomized hash value for cell class */ unsigned long classhash; /* randomized hash value for cell class */
struct Permutation *permutes; /* list of permuting pins */ struct Permutation *permutes; /* list of permuting pins */
@ -222,17 +223,18 @@ struct nlist {
/* Defined nlist structure flags */ /* Defined nlist structure flags */
#define CELL_MATCHED 0x01 /* cell matched to another */ #define CELL_MATCHED 0x001 /* cell matched to another */
#define CELL_NOCASE 0x02 /* cell is case-insensitive (e.g., SPICE) */ #define CELL_NOCASE 0x002 /* cell is case-insensitive (e.g., SPICE) */
#define CELL_TOP 0x04 /* cell is a top-level cell */ #define CELL_TOP 0x004 /* cell is a top-level cell */
#define CELL_PLACEHOLDER 0x08 /* cell is a placeholder cell */ #define CELL_PLACEHOLDER 0x008 /* cell is a placeholder cell */
#define CELL_PROPSMATCHED 0x10 /* properties matched to matching cell */ #define CELL_PROPSMATCHED 0x010 /* properties matched to matching cell */
#define CELL_DUPLICATE 0x20 /* cell has a duplicate */ #define CELL_DUPLICATE 0x020 /* cell has a duplicate */
#define CELL_VERILOG 0x040 /* cell is verilog module */
/* Flags for combination allowances and prohibitions */ /* Flags for combination allowances and prohibitions */
#define COMB_SERIES 0x40 #define COMB_SERIES 0x100
#define COMB_NO_PARALLEL 0x80 #define COMB_NO_PARALLEL 0x200
extern struct nlist *CurrentCell; extern struct nlist *CurrentCell;
extern struct objlist *CurrentTail; extern struct objlist *CurrentTail;
@ -307,6 +309,8 @@ extern int match(char *, char *);
extern int matchnocase(char *, char *); extern int matchnocase(char *, char *);
extern int matchfile(char *, char *, int, int); extern int matchfile(char *, char *, int, int);
extern int matchfilenocase(char *, char *, int, int); extern int matchfilenocase(char *, char *, int, int);
extern int is_delimiter(char);
extern char *get_array_delimiter(char *, char *);
extern void GarbageCollect(void); extern void GarbageCollect(void);
extern void InitGarbageCollection(void); extern void InitGarbageCollection(void);

View File

@ -511,8 +511,8 @@ int OpenEmbeddingFile(char *cellname, char *filename)
/* returns 1 if OK */ /* returns 1 if OK */
{ {
struct nlist *tp; struct nlist *tp;
char outfilename[200]; char outfilename[MAX_STR_LEN];
char logfilename[200]; char logfilename[MAX_STR_LEN];
tp = LookupCell(cellname); tp = LookupCell(cellname);
if (tp == NULL) { if (tp == NULL) {
@ -783,7 +783,7 @@ void SetupArray(char *prompt1, char *prompt2, char *prompt3, int *data,
void (*proc)(void)) void (*proc)(void))
{ {
int i, oldfanout; int i, oldfanout;
char name[100]; char name[MAX_STR_LEN];
Printf(prompt1); Printf(prompt1);
for (i = 1; i <= MAX_TREE_DEPTH; i++) for (i = 1; i <= MAX_TREE_DEPTH; i++)
@ -792,7 +792,7 @@ void SetupArray(char *prompt1, char *prompt2, char *prompt3, int *data,
oldfanout = 1; oldfanout = 1;
for (i = 1; i <= MAX_TREE_DEPTH; i++) { for (i = 1; i <= MAX_TREE_DEPTH; i++) {
char prompt[100]; char prompt[MAX_STR_LEN];
int newfanout; int newfanout;
sprintf(prompt, prompt2, i); sprintf(prompt, prompt2, i);
promptstring(prompt, name); promptstring(prompt, name);
@ -822,7 +822,7 @@ void SetupArrayFromString(char *prompt1, char *prompt3, int *data,
void (*proc)(void), char *text) void (*proc)(void), char *text)
{ {
int i, oldfanout, newfanout; int i, oldfanout, newfanout;
char string[100]; char string[MAX_STR_LEN];
char *ch; char *ch;
char *endch; char *endch;
@ -962,7 +962,7 @@ void ProtoPrintParameters(void)
void PROTOCHIP(void) void PROTOCHIP(void)
/* a simple command interpreter to manage embedding/routing */ /* a simple command interpreter to manage embedding/routing */
{ {
char name[100]; char name[MAX_STR_LEN];
char ch; char ch;
InitializeFanout(); InitializeFanout();
@ -1136,7 +1136,7 @@ void PROTOCHIP(void)
oldfanout = 1; oldfanout = 1;
for (i = 1; i <= MAX_TREE_DEPTH; i++) { for (i = 1; i <= MAX_TREE_DEPTH; i++) {
char prompt[100]; char prompt[MAX_STR_LEN];
int newfanout; int newfanout;
sprintf(prompt,"Fanout for level %d (0 to quit): ",i); sprintf(prompt,"Fanout for level %d (0 to quit): ",i);
promptstring(prompt, name); promptstring(prompt, name);
@ -1168,7 +1168,7 @@ void PROTOCHIP(void)
oldfanout = 1; oldfanout = 1;
for (i = 1; i <= MAX_TREE_DEPTH; i++) { for (i = 1; i <= MAX_TREE_DEPTH; i++) {
char prompt[100]; char prompt[MAX_STR_LEN];
int newfanout; int newfanout;
sprintf(prompt,"Common nodes for level %d (0 to quit): ",i); sprintf(prompt,"Common nodes for level %d (0 to quit): ",i);
promptstring(prompt, name); promptstring(prompt, name);
@ -1200,7 +1200,7 @@ void PROTOCHIP(void)
oldfanout = 1; oldfanout = 1;
for (i = 1; i <= MAX_TREE_DEPTH; i++) { for (i = 1; i <= MAX_TREE_DEPTH; i++) {
char prompt[100]; char prompt[MAX_STR_LEN];
int newfanout; int newfanout;
sprintf(prompt,"Used leaves for level %d (0 to quit): ",i); sprintf(prompt,"Used leaves for level %d (0 to quit): ",i);
promptstring(prompt, name); promptstring(prompt, name);

View File

@ -37,7 +37,7 @@ extern int ColumnBase;
struct filestr { struct filestr {
FILE *f; FILE *f;
char buffer[200]; char buffer[MAX_STR_LEN];
int wrap; /* column to wrap around in, or 0 if no wrap */ int wrap; /* column to wrap around in, or 0 if no wrap */
} file_buffers[MAXFILES]; } file_buffers[MAXFILES];
@ -107,7 +107,7 @@ void Fprintf(FILE *f, char *format, ...)
{ {
va_list ap; va_list ap;
int FileIndex; int FileIndex;
char tmpstr[200]; char tmpstr[MAX_STR_LEN];
int bufferlongenough; int bufferlongenough;
int linewrapexceeded; int linewrapexceeded;
@ -203,7 +203,7 @@ void Printf(char *format, ...)
void Printf(char *format, ...) void Printf(char *format, ...)
{ {
va_list ap; va_list ap;
char tmpstr[200]; char tmpstr[MAX_STR_LEN];
va_start(ap, format); va_start(ap, format);
vsprintf(tmpstr, format, ap); vsprintf(tmpstr, format, ap);

View File

@ -52,7 +52,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/*************************************************************************/ /*************************************************************************/
static int SuppressPrompts = 0; static int SuppressPrompts = 0;
static char InputLine[200]; static char InputLine[MAX_STR_LEN];
void typeahead(char *str) void typeahead(char *str)
{ {
@ -73,7 +73,7 @@ but reads from 'promptstring_infile' if nec. */
/* If interactive, puts out 'prompt' */ /* If interactive, puts out 'prompt' */
{ {
char *nexttok; char *nexttok;
char tmpstr[200]; char tmpstr[MAX_STR_LEN];
int echo; int echo;
if (promptstring_infile == NULL) if (promptstring_infile == NULL)
@ -319,7 +319,7 @@ void Fanout(char *cell, char *node, int filter)
while (ob != NULL) { while (ob != NULL) {
char *obname = ob->name; char *obname = ob->name;
if (*obname == '/') obname++; if (*obname == '/') obname++;
if (ob->node == nodenum) if (ob->node == nodenum) {
if (filter == ALLOBJECTS) { if (filter == ALLOBJECTS) {
Printf(" %s (", obname); Printf(" %s (", obname);
PrintObjectType(ob->type); PrintObjectType(ob->type);
@ -331,6 +331,7 @@ void Fanout(char *cell, char *node, int filter)
else if (ob->type == filter) { else if (ob->type == filter) {
Printf(" %s\n", obname); Printf(" %s\n", obname);
} }
}
ob = ob->next; ob = ob->next;
} }
} }
@ -933,7 +934,7 @@ static int PrintLeavesInCellHash(struct hashlist *p)
struct nlist *ptr; struct nlist *ptr;
ptr = (struct nlist *)(p->ptr); ptr = (struct nlist *)(p->ptr);
if ((ptr->class == CLASS_SUBCKT)) PrintLeavesInCell(ptr->name, ptr->file); if (ptr->class == CLASS_SUBCKT) PrintLeavesInCell(ptr->name, ptr->file);
return(0); return(0);
} }
@ -959,8 +960,8 @@ void Query(void)
{ {
/* little interactive debugger */ /* little interactive debugger */
char reply; char reply;
char repstr[100]; char repstr[MAX_STR_LEN];
char repstr2[100]; char repstr2[MAX_STR_LEN];
float StartTime; /* for elapsed CPU times */ float StartTime; /* for elapsed CPU times */
int Timing; /* if true, print times of each command */ int Timing; /* if true, print times of each command */
int filenum = -1; int filenum = -1;

View File

@ -21,6 +21,9 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h" #include "config.h"
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#if 0 #if 0
#include <stdarg.h> /* what about varargs, like in pdutils.c ??? */ #include <stdarg.h> /* what about varargs, like in pdutils.c ??? */
#endif #endif
@ -43,6 +46,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "print.h" #include "print.h"
#include "query.h" #include "query.h"
#include "objlist.h" #include "objlist.h"
#include "netcmp.h"
// Global storage for parameters from .PARAM // Global storage for parameters from .PARAM
struct hashdict spiceparams; struct hashdict spiceparams;
@ -192,7 +196,7 @@ void SpiceSubCell(struct nlist *tp, int IsSubCell)
if (ob->type == PROPERTY) { if (ob->type == PROPERTY) {
struct valuelist *vl; struct valuelist *vl;
int i; int i;
for (i == 0;; i++) { for (i = 0;; i++) {
vl = &(ob->instance.props[i]); vl = &(ob->instance.props[i]);
if (vl->type == PROP_ENDLIST) break; if (vl->type == PROP_ENDLIST) break;
else if (vl->type == PROP_VALUE) { else if (vl->type == PROP_VALUE) {
@ -212,7 +216,7 @@ void SpiceSubCell(struct nlist *tp, int IsSubCell)
if (ob->type == PROPERTY) { if (ob->type == PROPERTY) {
struct valuelist *vl; struct valuelist *vl;
int i; int i;
for (i == 0;; i++) { for (i = 0;; i++) {
vl = &(ob->instance.props[i]); vl = &(ob->instance.props[i]);
if (vl->type == PROP_ENDLIST) break; if (vl->type == PROP_ENDLIST) break;
else if (vl->type == PROP_VALUE) { else if (vl->type == PROP_VALUE) {
@ -232,7 +236,7 @@ void SpiceSubCell(struct nlist *tp, int IsSubCell)
if (ob->type == PROPERTY) { if (ob->type == PROPERTY) {
struct valuelist *vl; struct valuelist *vl;
int i; int i;
for (i == 0;; i++) { for (i = 0;; i++) {
vl = &(ob->instance.props[i]); vl = &(ob->instance.props[i]);
if (vl->type == PROP_ENDLIST) break; if (vl->type == PROP_ENDLIST) break;
else if (vl->type == PROP_VALUE) { else if (vl->type == PROP_VALUE) {
@ -395,7 +399,7 @@ int renamepins(struct hashlist *p, int file)
ptr = (struct nlist *)(p->ptr); ptr = (struct nlist *)(p->ptr);
if (ptr->file != file) if (ptr->file != file)
return 1; return 0;
for (ob = ptr->cell; ob != NULL; ob = ob->next) { for (ob = ptr->cell; ob != NULL; ob = ob->next) {
if (ob->type == FIRSTPIN) { if (ob->type == FIRSTPIN) {
@ -422,6 +426,7 @@ int renamepins(struct hashlist *p, int file)
} }
} }
} }
return 1;
} }
/* If any pins are marked unconnected, see if there are */ /* If any pins are marked unconnected, see if there are */
@ -518,21 +523,27 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
int warnings = 0, update = 0, hasports = 0; int warnings = 0, update = 0, hasports = 0;
char *eqptr, devtype, in_subckt; char *eqptr, devtype, in_subckt;
struct keyvalue *kvlist = NULL; 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 nlist *tp, *tpsave;
struct objlist *parent, *sobj, *nobj, *lobj, *pobj; struct objlist *parent, *sobj, *nobj, *lobj, *pobj;
inst[255] = '\0'; inst[MAX_STR_LEN-1] = '\0';
model[255] = '\0'; model[MAX_STR_LEN-1] = '\0';
instname[255] = '\0'; instname[MAX_STR_LEN-1] = '\0';
in_subckt = (char)0; in_subckt = (char)0;
while (!EndParseFile()) { while (!EndParseFile()) {
SkipTok(NULL); /* get the next token */ SkipTok(NULL); /* get the next token */
if ((EndParseFile()) && (nexttok == NULL)) break; if ((EndParseFile()) && (nexttok == NULL)) break;
if (nexttok == NULL) break;
if (nexttok[0] == '*') SkipNewLine(NULL); /* Handle comment lines. Note that some variants of CDL format
* use "*." for information that is transparent to SPICE simulators.
* Handle "*.GLOBAL" entries. All others are ignored.
*/
if ((nexttok[0] == '*') && (!matchnocase(nexttok, "*.GLOBAL")))
SkipNewLine(NULL);
else if (matchnocase(nexttok, ".SUBCKT")) { else if (matchnocase(nexttok, ".SUBCKT")) {
SpiceTokNoNewline(); SpiceTokNoNewline();
@ -555,8 +566,9 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
/* Check for existence of the cell. We may need to rename it. */ /* 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); tp = LookupCellFile(nexttok, filenum);
tpsave = NULL;
/* Check for name conflict with duplicate cell names */ /* Check for name conflict with duplicate cell names */
/* This may mean that the cell was used before it was */ /* This may mean that the cell was used before it was */
@ -595,11 +607,46 @@ void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr,
tp = LookupCellFile(nexttok, filenum); tp = LookupCellFile(nexttok, filenum);
} }
else if (tp != NULL) { /* Make a new definition for an empty cell */ else if (tp != NULL) { /* Make a new definition for an empty cell */
FreePorts(nexttok); /* Handle issue with SPICE read after verilog, where a placeholder
CellDelete(nexttok, filenum); /* This removes any PLACEHOLDER flag */ * was created from the verilog. (1) If the pin names are "1", "2",
CellDef(model, filenum); * "3", then this is a SPICE placeholder, and just remove the CellDef
tp = LookupCellFile(model, filenum); * and re-create it. Otherwise, create new cell "_PLACEHOLDER_".
update = 1; /* Will need to update existing instances */ * (2) After encountering .ends, run MatchPins between the two cells.
* (3) delete the original cell and rename the new cell.
*/
int i = 1;
char pname[10];
for (pobj = tp->cell; pobj && pobj->type == PORT; pobj = pobj->next) {
sprintf(pname, "%d", i);
if (!matchnocase(pobj->name, pname)) break;
i++;
}
if ((pobj == NULL) || (pobj->type != PORT)) {
/* This is a SPICE placeholder created because the cell was instanced
* before it was defined. However, the pins can be assumed to be in
* the correct order, and pin reordering does not need to be done.
*/
FreePorts(nexttok);
CellDelete(nexttok, filenum); /* This removes any PLACEHOLDER flag */
CellDef(model, filenum);
tp = LookupCellFile(model, filenum);
update = 1; /* Will need to update existing instances */
}
else {
/* This is (probably) a verilog placeholder created because the
* verilog was read before the (SPICE) definitions. The verilog
* netlist should have named the pins of the parent cell. However,
* there is no guarantee the order of pins is correct. The MatchPins()
* routine from netcmp.c can be used here to match the cell against
* the placeholder, and reorder the pins in all instances to match.
* Note that we cannot just reorder the SPICE pins to match the
* verilog order, because there may be other SPICE netlists which
* instance the cell with the correct SPICE port order.
*/
tpsave = tp;
CellDef("_PLACEHOLDER_", filenum);
tp = LookupCellFile("_PLACEHOLDER_", filenum);
}
} }
else if (tp == NULL) { /* Completely new cell, no name conflict */ else if (tp == NULL) { /* Completely new cell, no name conflict */
CellDef(model, filenum); CellDef(model, filenum);
@ -691,6 +738,38 @@ skip_ends:
if (*CellStackPtr) PopStack(CellStackPtr); if (*CellStackPtr) PopStack(CellStackPtr);
if (*CellStackPtr) ReopenCellDef((*CellStackPtr)->cellname, filenum); if (*CellStackPtr) ReopenCellDef((*CellStackPtr)->cellname, filenum);
SkipNewLine(NULL); SkipNewLine(NULL);
if (tpsave != NULL) {
struct nlist *tpplace;
char *savename;
/* Handle a placeholder from a verilog file that has been replaced
* by a netlist with pins in a different order. The pins need to
* be matched, corrected in the original cell and all instances,
* and the new cell deleted.
*/
Printf("Verilog placeholder %s replaced by SPICE definition\n",
tpsave->name);
tpplace = LookupCellFile("_PLACEHOLDER_", filenum);
/* MatchPins is part of netcmp and normally Circuit2 is the
* circuit being matched, so set Circuit2 to the original
* verilog black-box cell, and MatchPins() will force its
* pins to be rearranged to match the SPICE definition just
* read.
*/
Circuit2 = tpsave;
MatchPins(tpplace, tpsave, 0);
savename = strsave(tpsave->name);
/* Now the original verilog black-box cell can be removed */
FreePorts(savename);
CellDelete(savename, filenum);
/* And _PLACEHOLDER_ is renamed to the original name of the cell. */
CellRehash("_PLACEHOLDER_", savename, filenum);
tpsave = NULL;
Circuit2 = NULL;
FREE(savename);
}
} }
else if (matchnocase(nexttok, ".MODEL")) { else if (matchnocase(nexttok, ".MODEL")) {
unsigned char class = CLASS_SUBCKT; unsigned char class = CLASS_SUBCKT;
@ -703,7 +782,7 @@ skip_ends:
SpiceTokNoNewline(); SpiceTokNoNewline();
if (nexttok == NULL) continue; /* Ignore if no model name */ if (nexttok == NULL) continue; /* Ignore if no model name */
snprintf(model, 99, "%s", nexttok); snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
SpiceTokNoNewline(); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
@ -752,7 +831,10 @@ skip_ends:
// Handle some commonly-used cards // Handle some commonly-used cards
else if (matchnocase(nexttok, ".GLOBAL")) { /* .GLOBAL and *.GLOBAL. Note that *.GLOBAL is excepted from comment-line
* handling, above, so any line starting with '*' is "*.GLOBAL".
*/
else if (matchnocase(nexttok, ".GLOBAL") || (nexttok[0] == '*')) {
while (nexttok != NULL) { while (nexttok != NULL) {
int numnodes = 0; int numnodes = 0;
SpiceTokNoNewline(); SpiceTokNoNewline();
@ -887,29 +969,29 @@ skip_ends:
} }
else if (toupper(nexttok[0]) == 'Q') { else if (toupper(nexttok[0]) == 'Q') {
char emitter[100], base[100], collector[100]; char emitter[MAX_STR_LEN], base[MAX_STR_LEN], collector[MAX_STR_LEN];
emitter[99] = '\0'; emitter[MAX_STR_LEN-1] = '\0';
base[99] = '\0'; base[MAX_STR_LEN-1] = '\0';
collector[99] = '\0'; collector[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) { if (!(*CellStackPtr)) {
CellDef(fname, filenum); CellDef(fname, filenum);
PushStack(fname, CellStackPtr); PushStack(fname, CellStackPtr);
} }
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(collector, nexttok, 99); SpiceTokNoNewline(); strncpy(collector, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(base, nexttok, 99); SpiceTokNoNewline(); strncpy(base, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(emitter, nexttok, 99); SpiceTokNoNewline(); strncpy(emitter, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
/* make sure all the nodes exist */ /* make sure all the nodes exist */
if (LookupObject(collector, CurrentCell) == NULL) Node(collector); if (LookupObject(collector, CurrentCell) == NULL) Node(collector);
if (LookupObject(base, CurrentCell) == NULL) Node(base); if (LookupObject(base, CurrentCell) == NULL) Node(base);
if (LookupObject(emitter, CurrentCell) == NULL) Node(emitter); if (LookupObject(emitter, CurrentCell) == NULL) Node(emitter);
/* Read the device model */ /* Read the device model */
snprintf(model, 99, "%s", nexttok); snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
while (nexttok != NULL) while (nexttok != NULL)
{ {
@ -940,30 +1022,30 @@ skip_ends:
goto baddevice; 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); Cell(instname, model, collector, base, emitter);
pobj = LinkProperties(model, kvlist); pobj = LinkProperties(model, kvlist);
ReduceExpressions(pobj, NULL, CurrentCell, TRUE); ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
DeleteProperties(&kvlist); DeleteProperties(&kvlist);
} }
else if (toupper(nexttok[0]) == 'M') { else if (toupper(nexttok[0]) == 'M') {
char drain[100], gate[100], source[100], bulk[100]; char drain[MAX_STR_LEN], gate[MAX_STR_LEN], source[MAX_STR_LEN], bulk[MAX_STR_LEN];
drain[99] = '\0'; drain[MAX_STR_LEN-1] = '\0';
gate[99] = '\0'; gate[MAX_STR_LEN-1] = '\0';
source[99] = '\0'; source[MAX_STR_LEN-1] = '\0';
bulk[99] = '\0'; bulk[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) { if (!(*CellStackPtr)) {
CellDef(fname, filenum); CellDef(fname, filenum);
PushStack(fname, CellStackPtr); PushStack(fname, CellStackPtr);
} }
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(drain, nexttok, 99); SpiceTokNoNewline(); strncpy(drain, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(gate, nexttok, 99); SpiceTokNoNewline(); strncpy(gate, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(source, nexttok, 99); SpiceTokNoNewline(); strncpy(source, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
/* make sure all the nodes exist */ /* make sure all the nodes exist */
if (LookupObject(drain, CurrentCell) == NULL) Node(drain); if (LookupObject(drain, CurrentCell) == NULL) Node(drain);
@ -971,11 +1053,11 @@ skip_ends:
if (LookupObject(source, CurrentCell) == NULL) Node(source); if (LookupObject(source, CurrentCell) == NULL) Node(source);
/* handle the substrate node */ /* handle the substrate node */
strncpy(bulk, nexttok, 99); SpiceTokNoNewline(); strncpy(bulk, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (LookupObject(bulk, CurrentCell) == NULL) Node(bulk); if (LookupObject(bulk, CurrentCell) == NULL) Node(bulk);
/* Read the device model */ /* Read the device model */
snprintf(model, 99, "%s", nexttok); snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
while (nexttok != NULL) while (nexttok != NULL)
{ {
@ -1013,7 +1095,7 @@ skip_ends:
goto baddevice; 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); Cell(instname, model, drain, gate, source, bulk);
pobj = LinkProperties(model, kvlist); pobj = LinkProperties(model, kvlist);
ReduceExpressions(pobj, NULL, CurrentCell, TRUE); ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
@ -1027,19 +1109,19 @@ skip_ends:
SpiceSkipNewLine(); SpiceSkipNewLine();
} }
else { else {
char ctop[100], cbot[100]; char ctop[MAX_STR_LEN], cbot[MAX_STR_LEN];
ctop[99] = '\0'; ctop[MAX_STR_LEN-1] = '\0';
cbot[99] = '\0'; cbot[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) { if (!(*CellStackPtr)) {
CellDef(fname, filenum); CellDef(fname, filenum);
PushStack(fname, CellStackPtr); PushStack(fname, CellStackPtr);
} }
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(ctop, nexttok, 99); SpiceTokNoNewline(); strncpy(ctop, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(cbot, nexttok, 99); SpiceTokNoNewline(); strncpy(cbot, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
/* make sure all the nodes exist */ /* make sure all the nodes exist */
if (LookupObject(ctop, CurrentCell) == NULL) Node(ctop); if (LookupObject(ctop, CurrentCell) == NULL) Node(ctop);
@ -1058,7 +1140,7 @@ skip_ends:
model[0] = '\0'; model[0] = '\0';
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL)) if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
snprintf(model, 99, "%s", nexttok); snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
/* Any other device properties? */ /* Any other device properties? */
while (nexttok != NULL) while (nexttok != NULL)
@ -1071,7 +1153,7 @@ skip_ends:
} }
else if (!strncmp(nexttok, "$[", 2)) { else if (!strncmp(nexttok, "$[", 2)) {
// Support for CDL modeled capacitor format // 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) if ((eqptr = strchr(model, ']')) != NULL)
*eqptr = '\0'; *eqptr = '\0';
} }
@ -1104,7 +1186,7 @@ skip_ends:
usemodel = 1; usemodel = 1;
} }
snprintf(instname, 255, "%s:%s", model, inst); snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
if (usemodel) if (usemodel)
Cell(instname, model, ctop, cbot); Cell(instname, model, ctop, cbot);
else else
@ -1121,19 +1203,19 @@ skip_ends:
SpiceSkipNewLine(); SpiceSkipNewLine();
} }
else { else {
char rtop[100], rbot[100]; char rtop[MAX_STR_LEN], rbot[MAX_STR_LEN];
rtop[99] = '\0'; rtop[MAX_STR_LEN-1] = '\0';
rbot[99] = '\0'; rbot[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) { if (!(*CellStackPtr)) {
CellDef(fname, filenum); CellDef(fname, filenum);
PushStack(fname, CellStackPtr); PushStack(fname, CellStackPtr);
} }
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(rtop, nexttok, 99); SpiceTokNoNewline(); strncpy(rtop, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(rbot, nexttok, 99); SpiceTokNoNewline(); strncpy(rbot, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
/* make sure all the nodes exist */ /* make sure all the nodes exist */
if (LookupObject(rtop, CurrentCell) == NULL) Node(rtop); if (LookupObject(rtop, CurrentCell) == NULL) Node(rtop);
if (LookupObject(rbot, CurrentCell) == NULL) Node(rbot); if (LookupObject(rbot, CurrentCell) == NULL) Node(rbot);
@ -1152,7 +1234,7 @@ skip_ends:
model[0] = '\0'; model[0] = '\0';
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL)) if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
snprintf(model, 99, "%s", nexttok); snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
/* Any other device properties? */ /* Any other device properties? */
while (nexttok != NULL) { while (nexttok != NULL) {
@ -1164,7 +1246,7 @@ skip_ends:
} }
else if (!strncmp(nexttok, "$[", 2)) { else if (!strncmp(nexttok, "$[", 2)) {
// Support for CDL modeled resistor format // 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) if ((eqptr = strchr(model, ']')) != NULL)
*eqptr = '\0'; *eqptr = '\0';
} }
@ -1197,7 +1279,7 @@ skip_ends:
else else
strcpy(model, "r"); /* Use default resistor model */ 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) if (usemodel)
Cell(instname, model, rtop, rbot); Cell(instname, model, rtop, rbot);
else else
@ -1208,25 +1290,25 @@ skip_ends:
} }
} }
else if (toupper(nexttok[0]) == 'D') { /* diode */ else if (toupper(nexttok[0]) == 'D') { /* diode */
char cathode[100], anode[100]; char cathode[MAX_STR_LEN], anode[MAX_STR_LEN];
cathode[99] = '\0'; cathode[MAX_STR_LEN-1] = '\0';
anode[99] = '\0'; anode[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) { if (!(*CellStackPtr)) {
CellDef(fname, filenum); CellDef(fname, filenum);
PushStack(fname, CellStackPtr); PushStack(fname, CellStackPtr);
} }
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(anode, nexttok, 99); SpiceTokNoNewline(); strncpy(anode, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(cathode, nexttok, 99); SpiceTokNoNewline(); strncpy(cathode, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
/* make sure all the nodes exist */ /* make sure all the nodes exist */
if (LookupObject(anode, CurrentCell) == NULL) Node(anode); if (LookupObject(anode, CurrentCell) == NULL) Node(anode);
if (LookupObject(cathode, CurrentCell) == NULL) Node(cathode); if (LookupObject(cathode, CurrentCell) == NULL) Node(cathode);
/* Read the device model */ /* Read the device model */
snprintf(model, 99, "%s", nexttok); snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
while (nexttok != NULL) while (nexttok != NULL)
{ {
@ -1255,7 +1337,7 @@ skip_ends:
Fprintf(stderr, "Device \"%s\" has wrong number of ports for a diode.\n"); Fprintf(stderr, "Device \"%s\" has wrong number of ports for a diode.\n");
goto baddevice; goto baddevice;
} }
snprintf(instname, 255, "%s:%s", model, inst); snprintf(instname, MAX_STR_LEN-1, "%s:%s", model, inst);
Cell(instname, model, anode, cathode); Cell(instname, model, anode, cathode);
pobj = LinkProperties(model, kvlist); pobj = LinkProperties(model, kvlist);
ReduceExpressions(pobj, NULL, CurrentCell, TRUE); ReduceExpressions(pobj, NULL, CurrentCell, TRUE);
@ -1268,25 +1350,25 @@ skip_ends:
SpiceSkipNewLine(); SpiceSkipNewLine();
} }
else { else {
char node1[100], node2[100], node3[100], node4[100]; char node1[MAX_STR_LEN], node2[MAX_STR_LEN], node3[MAX_STR_LEN], node4[MAX_STR_LEN];
node1[99] = '\0'; node1[MAX_STR_LEN-1] = '\0';
node2[99] = '\0'; node2[MAX_STR_LEN-1] = '\0';
node3[99] = '\0'; node3[MAX_STR_LEN-1] = '\0';
node4[99] = '\0'; node4[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) { if (!(*CellStackPtr)) {
CellDef(fname, filenum); CellDef(fname, filenum);
PushStack(fname, CellStackPtr); PushStack(fname, CellStackPtr);
} }
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(node1, nexttok, 99); SpiceTokNoNewline(); strncpy(node1, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(node2, nexttok, 99); SpiceTokNoNewline(); strncpy(node2, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(node3, nexttok, 99); SpiceTokNoNewline(); strncpy(node3, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(node4, nexttok, 99); SpiceTokNoNewline(); strncpy(node4, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
/* make sure all the nodes exist */ /* make sure all the nodes exist */
if (LookupObject(node1, CurrentCell) == NULL) Node(node1); if (LookupObject(node1, CurrentCell) == NULL) Node(node1);
if (LookupObject(node2, CurrentCell) == NULL) Node(node2); if (LookupObject(node2, CurrentCell) == NULL) Node(node2);
@ -1298,7 +1380,7 @@ skip_ends:
model[0] = '\0'; model[0] = '\0';
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL)) if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
snprintf(model, 99, "%s", nexttok); snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
/* Any other device properties? */ /* Any other device properties? */
while (nexttok != NULL) { while (nexttok != NULL) {
@ -1334,7 +1416,7 @@ skip_ends:
else else
strcpy(model, "t"); /* Use default xline model */ 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) if (usemodel)
Cell(instname, model, node1, node2, node3, node4); Cell(instname, model, node1, node2, node3, node4);
@ -1347,20 +1429,20 @@ skip_ends:
} }
} }
else if (toupper(nexttok[0]) == 'L') { /* inductor */ 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; int usemodel = 0;
end_a[99] = '\0'; end_a[MAX_STR_LEN-1] = '\0';
end_b[99] = '\0'; end_b[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) { if (!(*CellStackPtr)) {
CellDef(fname, filenum); CellDef(fname, filenum);
PushStack(fname, CellStackPtr); PushStack(fname, CellStackPtr);
} }
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; 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; 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 */ /* make sure all the nodes exist */
if (LookupObject(end_a, CurrentCell) == NULL) Node(end_a); if (LookupObject(end_a, CurrentCell) == NULL) Node(end_a);
if (LookupObject(end_b, CurrentCell) == NULL) Node(end_b); if (LookupObject(end_b, CurrentCell) == NULL) Node(end_b);
@ -1379,7 +1461,7 @@ skip_ends:
model[0] = '\0'; model[0] = '\0';
if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL)) if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL))
snprintf(model, 99, "%s", nexttok); snprintf(model, MAX_STR_LEN-1, "%s", nexttok);
/* Any other device properties? */ /* Any other device properties? */
while (nexttok != NULL) while (nexttok != NULL)
@ -1417,7 +1499,7 @@ skip_ends:
else else
strcpy(model, "l"); /* Use default inductor model */ 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) if (usemodel)
Cell(instname, model, end_a, end_b); Cell(instname, model, end_a, end_b);
else else
@ -1431,19 +1513,19 @@ skip_ends:
/* black-box subcircuits (class MODULE): V, I, E */ /* black-box subcircuits (class MODULE): V, I, E */
else if (toupper(nexttok[0]) == 'V') { /* voltage source */ else if (toupper(nexttok[0]) == 'V') { /* voltage source */
char pos[100], neg[100]; char pos[MAX_STR_LEN], neg[MAX_STR_LEN];
pos[99] = '\0'; pos[MAX_STR_LEN-1] = '\0';
neg[99] = '\0'; neg[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) { if (!(*CellStackPtr)) {
CellDef(fname, filenum); CellDef(fname, filenum);
PushStack(fname, CellStackPtr); PushStack(fname, CellStackPtr);
} }
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(pos, nexttok, 99); SpiceTokNoNewline(); strncpy(pos, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(neg, nexttok, 99); SpiceTokNoNewline(); strncpy(neg, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
/* make sure all the nodes exist */ /* make sure all the nodes exist */
if (LookupObject(pos, CurrentCell) == NULL) Node(pos); if (LookupObject(pos, CurrentCell) == NULL) Node(pos);
@ -1499,19 +1581,19 @@ skip_ends:
DeleteProperties(&kvlist); DeleteProperties(&kvlist);
} }
else if (toupper(nexttok[0]) == 'I') { /* current source */ else if (toupper(nexttok[0]) == 'I') { /* current source */
char pos[100], neg[100]; char pos[MAX_STR_LEN], neg[MAX_STR_LEN];
pos[99] = '\0'; pos[MAX_STR_LEN-1] = '\0';
neg[99] = '\0'; neg[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) { if (!(*CellStackPtr)) {
CellDef(fname, filenum); CellDef(fname, filenum);
PushStack(fname, CellStackPtr); PushStack(fname, CellStackPtr);
} }
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(pos, nexttok, 99); SpiceTokNoNewline(); strncpy(pos, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(neg, nexttok, 99); SpiceTokNoNewline(); strncpy(neg, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
/* make sure all the nodes exist */ /* make sure all the nodes exist */
if (LookupObject(pos, CurrentCell) == NULL) Node(pos); if (LookupObject(pos, CurrentCell) == NULL) Node(pos);
if (LookupObject(neg, CurrentCell) == NULL) Node(neg); if (LookupObject(neg, CurrentCell) == NULL) Node(neg);
@ -1553,25 +1635,25 @@ skip_ends:
DeleteProperties(&kvlist); DeleteProperties(&kvlist);
} }
else if (toupper(nexttok[0]) == 'E') { /* controlled voltage source */ else if (toupper(nexttok[0]) == 'E') { /* controlled voltage source */
char pos[100], neg[100], ctrlp[100], ctrln[100]; char pos[MAX_STR_LEN], neg[MAX_STR_LEN], ctrlp[MAX_STR_LEN], ctrln[MAX_STR_LEN];
pos[99] = '\0'; pos[MAX_STR_LEN-1] = '\0';
neg[99] = '\0'; neg[MAX_STR_LEN-1] = '\0';
ctrlp[99] = '\0'; ctrlp[MAX_STR_LEN-1] = '\0';
ctrln[99] = '\0'; ctrln[MAX_STR_LEN-1] = '\0';
if (!(*CellStackPtr)) { if (!(*CellStackPtr)) {
CellDef(fname, filenum); CellDef(fname, filenum);
PushStack(fname, CellStackPtr); PushStack(fname, CellStackPtr);
} }
strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); strncpy(inst, nexttok + 1, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(pos, nexttok, 99); SpiceTokNoNewline(); strncpy(pos, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(neg, nexttok, 99); SpiceTokNoNewline(); strncpy(neg, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(ctrlp, nexttok, 99); SpiceTokNoNewline(); strncpy(ctrlp, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
if (nexttok == NULL) goto baddevice; if (nexttok == NULL) goto baddevice;
strncpy(ctrln, nexttok, 99); SpiceTokNoNewline(); strncpy(ctrln, nexttok, MAX_STR_LEN-1); SpiceTokNoNewline();
/* make sure all the nodes exist */ /* make sure all the nodes exist */
if (LookupObject(pos, CurrentCell) == NULL) Node(pos); if (LookupObject(pos, CurrentCell) == NULL) Node(pos);
@ -1619,11 +1701,11 @@ skip_ends:
} }
else if (toupper(nexttok[0]) == 'X') { /* subcircuit instances */ 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; int itype, in_props;
instancename[99] = '\0'; instancename[MAX_STR_LEN-1] = '\0';
subcktname[99] = '\0'; subcktname[MAX_STR_LEN-1] = '\0';
struct portelement { struct portelement {
char *name; char *name;
@ -1633,8 +1715,8 @@ skip_ends:
struct portelement *head, *tail, *scan, *scannext; struct portelement *head, *tail, *scan, *scannext;
struct objlist *obptr; struct objlist *obptr;
snprintf(instancename, 99, "%s", nexttok + 1); snprintf(instancename, MAX_STR_LEN-1, "%s", nexttok + 1);
strncpy(instancename, nexttok + 1, 99); strncpy(instancename, nexttok + 1, MAX_STR_LEN-1);
if (!(*CellStackPtr)) { if (!(*CellStackPtr)) {
CellDef(fname, filenum); CellDef(fname, filenum);
PushStack(fname, CellStackPtr); PushStack(fname, CellStackPtr);
@ -1701,10 +1783,19 @@ skip_ends:
if (scan->next != NULL) scan = scan->next; if (scan->next != NULL) scan = scan->next;
tail->next = NULL; tail->next = NULL;
/* Check for class defined inside itself (self-referential loop) */
if (!strcasecmp(model, scan->name)) {
Fprintf(stderr, "Fatal: Class \"%s\" is instanced inside of itself!\n",
scan->name);
InputParseError(stderr);
return;
}
/* Check for ignored class */ /* Check for ignored class */
if ((itype = IsIgnored(subcktname, filenum)) == IGNORE_CLASS) { if ((itype = IsIgnored(scan->name, filenum)) == IGNORE_CLASS) {
Printf("Class '%s' instanced in input but is being ignored.\n", model); Printf("Class '%s' instanced in input but is being ignored.\n", scan->name);
return; return;
} }
@ -1719,7 +1810,7 @@ skip_ends:
break; break;
} }
if (shorted == (unsigned char)1) { if (shorted == (unsigned char)1) {
Printf("Instance of '%s' is shorted, ignoring.\n", subcktname); Printf("Instance of '%s' is shorted, ignoring.\n", scan->name);
while (head) { while (head) {
p = head->next; p = head->next;
FREE(head); FREE(head);
@ -1742,14 +1833,14 @@ skip_ends:
/* names. */ /* names. */
if (strncmp(instancename, scan->name, strlen(scan->name))) { 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); strcpy(instancename, subcktname);
} }
else { else {
snprintf(subcktname, 99, "/%s", instancename); snprintf(subcktname, MAX_STR_LEN-1, "/%s", instancename);
strcpy(instancename, subcktname); strcpy(instancename, subcktname);
} }
snprintf(subcktname, 99, "%s", scan->name); snprintf(subcktname, MAX_STR_LEN-1, "%s", scan->name);
if (scan == head) { if (scan == head) {
head = NULL; head = NULL;
@ -1783,6 +1874,18 @@ skip_ends:
ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */ ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */
update = 1; 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 */ /* nexttok is now NULL, scan->name points to class */
@ -1985,7 +2088,7 @@ void IncludeSpice(char *fname, int parent, struct cellstack **CellStackPtr,
int blackbox) int blackbox)
{ {
int filenum = -1; int filenum = -1;
char name[256]; char name[MAX_STR_LEN];
/* If fname does not begin with "/", then assume that it is */ /* If fname does not begin with "/", then assume that it is */
/* in the same relative path as its parent. */ /* in the same relative path as its parent. */

View File

@ -34,6 +34,8 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "print.h" #include "print.h"
#endif #endif
extern void Finsert(FILE *f);
void test_entry(void) void test_entry(void)
{ {

File diff suppressed because it is too large Load Diff

View File

@ -65,10 +65,10 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
Widget toplevel = NULL; Widget toplevel = NULL;
char GlobalFileName[100], char GlobalFileName[MAX_STR_LEN],
GlobalCellName[100], GlobalCellName[MAX_STR_LEN],
GlobalOtherName[100], GlobalOtherName[MAX_STR_LEN],
GlobalDataName[100]; GlobalDataName[MAX_STR_LEN];
/********************************************************* /*********************************************************
* Menu structure: attaches label string to a function, * Menu structure: attaches label string to a function,
@ -1708,7 +1708,7 @@ void X_main_loop(int argc, char *argv[])
XmStringCharSet cs = "ISOLatin1"; XmStringCharSet cs = "ISOLatin1";
static char prompt_response[100]; static char prompt_response[MAX_STR_LEN];
int prompt_done; int prompt_done;
int calling_editor; /* which string are we trying to get ? */ int calling_editor; /* which string are we trying to get ? */
#define FILE_NAME 1 #define FILE_NAME 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. */ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* inetcomp.c -- a simple wrapper to the NETCOMP() function */ /* inetcomp.c -- a simple wrapper to the NETCOMP() function */
#include "config.h"
#include <stdio.h> #include <stdio.h>
#include "netgen.h" #include "netgen.h"
@ -33,7 +34,7 @@ void STRCPY(char *dest, char *source)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
char cell1[200], cell2[200]; char cell1[MAX_STR_LEN], cell2[MAX_STR_LEN];
Debug = 0; Debug = 0;
if (argc != 1) { if (argc != 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. */ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* netcomp.c -- a simple wrapper to provide netlist comparison functionality */ /* netcomp.c -- a simple wrapper to provide netlist comparison functionality */
#include "config.h"
#include <stdio.h> #include <stdio.h>
#include "netgen.h" #include "netgen.h"
@ -51,7 +52,7 @@ void STRCPY(char *dest, char *source)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
#ifndef HAVE_GETOPT #ifndef HAVE_GETOPT
char cell1[200], cell2[200]; char cell1[MAX_STR_LEN], cell2[MAX_STR_LEN];
int filenum = -1; int filenum = -1;
Debug = 0; Debug = 0;
@ -67,7 +68,7 @@ int main(int argc, char *argv[])
STRCPY(cell2, ReadNetlist(argv[2], &filenum)); STRCPY(cell2, ReadNetlist(argv[2], &filenum));
if (argc == 5) STRCPY(cell2, argv[4]); /* if explicit cell name specified */ if (argc == 5) STRCPY(cell2, argv[4]); /* if explicit cell name specified */
#else #else
char cell1[200], cell2[200]; char cell1[MAX_STR_LEN], cell2[MAX_STR_LEN];
int usage = 0; int usage = 0;
int args; int args;
int c; int c;

View File

@ -23,6 +23,7 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdlib.h> /* for getenv */ #include <stdlib.h> /* for getenv */
#endif #endif
#include "netgen.h" #include "netgen.h"
#include "print.h"
int main(int argc, char **argv) int main(int argc, char **argv)
{ {

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. */ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ntk2xnf.c -- a simple wrapper to translate .ntk to Xilinx XNF format */ /* ntk2xnf.c -- a simple wrapper to translate .ntk to Xilinx XNF format */
#include "config.h"
#include <stdio.h> #include <stdio.h>
#include "netgen.h" #include "netgen.h"
#include "xilinx.h"
#ifdef HAVE_X11 #ifdef HAVE_X11
/* the following two X procedures are to permit linking /* 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[]) int main(int argc, char *argv[])
{ {
char cellname[200]; char cellname[MAX_STR_LEN];
int filenum = -1; int filenum = -1;
Debug = 0; Debug = 0;

1117
scripts/config.guess vendored

File diff suppressed because it is too large Load Diff

2917
scripts/config.sub vendored

File diff suppressed because it is too large Load Diff

76
scripts/configure vendored
View File

@ -668,7 +668,6 @@ XMKMF
HAVE_PYTHON3 HAVE_PYTHON3
EGREP EGREP
GREP GREP
M4
RANLIB RANLIB
INSTALL_DATA INSTALL_DATA
INSTALL_SCRIPT INSTALL_SCRIPT
@ -712,6 +711,7 @@ infodir
docdir docdir
oldincludedir oldincludedir
includedir includedir
runstatedir
localstatedir localstatedir
sharedstatedir sharedstatedir
sysconfdir sysconfdir
@ -794,6 +794,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc' sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com' sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var' localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include' includedir='${prefix}/include'
oldincludedir='/usr/include' oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@ -1046,6 +1047,15 @@ do
| -silent | --silent | --silen | --sile | --sil) | -silent | --silent | --silen | --sile | --sil)
silent=yes ;; 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) -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;; ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@ -1183,7 +1193,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \ datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir libdir localedir mandir runstatedir
do do
eval ac_val=\$$ac_var eval ac_val=\$$ac_var
# Remove trailing slashes. # Remove trailing slashes.
@ -1336,6 +1346,7 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var] --localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib] --libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include] --includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include] --oldincludedir=DIR C header files for non-gcc [/usr/include]
@ -3690,56 +3701,6 @@ else
fi fi
for ac_prog in gm4 gnum4 m4
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_M4+:} false; then :
$as_echo_n "(cached) " >&6
else
case $M4 in
[\\/]* | ?:[\\/]*)
ac_cv_path_M4="$M4" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_M4="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac
fi
M4=$ac_cv_path_M4
if test -n "$M4"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $M4" >&5
$as_echo "$M4" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
test -n "$M4" && break
done
test -n "$M4" || M4="no"
if test x$M4 = xno; then
as_fn_error $? "M4 is required" "$LINENO" 5
fi
if test "$CPP" = "$CC -E" ; then if test "$CPP" = "$CC -E" ; then
CPP="$CPP -x c" CPP="$CPP -x c"
@ -6065,7 +6026,6 @@ fi
if test $usingTcl ; then if test $usingTcl ; then
usingX11=1
cadinstall="$cadinstall tcltk" cadinstall="$cadinstall tcltk"
modules="$modules tcltk" modules="$modules tcltk"
programs="$programs tcltk" programs="$programs tcltk"
@ -6075,7 +6035,11 @@ if test $usingTcl ; then
extra_libs="$extra_libs \${NETGENDIR}/tcltk/libtcltk.o" extra_libs="$extra_libs \${NETGENDIR}/tcltk/libtcltk.o"
extra_defs="$extra_defs -DTCL_DIR=\\\"\${TCLDIR}\\\"" 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 else
programs="$programs netgen" programs="$programs netgen"
unused="$unused tcltk" unused="$unused tcltk"
@ -6160,6 +6124,7 @@ if test $usingTcl ; then
# Tk libraries and header files # Tk libraries and header files
# #
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
if test $usingX11 ; then
if test "${TK_INC_DIR}" != "/usr/include" ; then if test "${TK_INC_DIR}" != "/usr/include" ; then
INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}" INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}"
fi fi
@ -6176,6 +6141,7 @@ if test $usingTcl ; then
loader_run_path="${TK_LIB_DIR}:${loader_run_path}" loader_run_path="${TK_LIB_DIR}:${loader_run_path}"
fi fi
fi fi
fi
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# #
@ -6285,7 +6251,7 @@ if test $usingTcl ; then
*darwin*) *darwin*)
SHDLIB_EXT=".dylib" SHDLIB_EXT=".dylib"
LDDL_FLAGS="-dynamiclib -flat_namespace -undefined suppress -noprebind" LDDL_FLAGS="-dynamiclib -undefined dynamic_lookup"
LDFLAGS="${LDFLAGS} ${LIB_SPECS}" LDFLAGS="${LDFLAGS} ${LIB_SPECS}"
CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common" CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common"
;; ;;

View File

@ -26,12 +26,6 @@ AC_ISC_POSIX
AC_PROG_INSTALL AC_PROG_INSTALL
AC_PROG_RANLIB AC_PROG_RANLIB
dnl GNU M4 is preferred due to some of the option switches.
AC_PATH_PROGS([M4], [gm4 gnum4 m4], [no])
if test x$M4 = xno; then
AC_MSG_ERROR([M4 is required])
fi
dnl check size of pointer for correct behavior on 64-bit systems dnl check size of pointer for correct behavior on 64-bit systems
dnl If the C preprocessor is GCC, we need to force the flag to dnl If the C preprocessor is GCC, we need to force the flag to
dnl assert that input files are of type C, or else the preprocessing dnl assert that input files are of type C, or else the preprocessing
@ -807,7 +801,6 @@ dnl "make" instead of requiring "make tcl"
dnl ---------------------------------------------------------------- dnl ----------------------------------------------------------------
if test $usingTcl ; then if test $usingTcl ; then
usingX11=1
cadinstall="$cadinstall tcltk" cadinstall="$cadinstall tcltk"
modules="$modules tcltk" modules="$modules tcltk"
programs="$programs tcltk" programs="$programs tcltk"
@ -816,7 +809,11 @@ if test $usingTcl ; then
AC_DEFINE(TCL_NETGEN) AC_DEFINE(TCL_NETGEN)
extra_libs="$extra_libs \${NETGENDIR}/tcltk/libtcltk.o" extra_libs="$extra_libs \${NETGENDIR}/tcltk/libtcltk.o"
extra_defs="$extra_defs -DTCL_DIR=\\\"\${TCLDIR}\\\"" 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 else
programs="$programs netgen" programs="$programs netgen"
unused="$unused tcltk" unused="$unused tcltk"
@ -903,6 +900,7 @@ if test $usingTcl ; then
# Tk libraries and header files # Tk libraries and header files
# #
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
if test $usingX11 ; then
if test "${TK_INC_DIR}" != "/usr/include" ; then if test "${TK_INC_DIR}" != "/usr/include" ; then
INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}" INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}"
fi fi
@ -919,6 +917,7 @@ if test $usingTcl ; then
loader_run_path="${TK_LIB_DIR}:${loader_run_path}" loader_run_path="${TK_LIB_DIR}:${loader_run_path}"
fi fi
fi fi
fi
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# #
@ -1028,7 +1027,7 @@ if test $usingTcl ; then
*darwin*) *darwin*)
SHDLIB_EXT=".dylib" SHDLIB_EXT=".dylib"
LDDL_FLAGS="-dynamiclib -flat_namespace -undefined suppress -noprebind" LDDL_FLAGS="-dynamiclib -undefined dynamic_lookup"
LDFLAGS="${LDFLAGS} ${LIB_SPECS}" LDFLAGS="${LDFLAGS} ${LIB_SPECS}"
CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common" CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common"
;; ;;

1362
scripts/configure.in.bak Normal file

File diff suppressed because it is too large Load Diff

View File

@ -68,6 +68,7 @@ LIB_SPECS = @LIB_SPECS@
LIB_SPECS_NOSTUB = @LIB_SPECS_NOSTUB@ LIB_SPECS_NOSTUB = @LIB_SPECS_NOSTUB@
WISH_EXE = @WISH_EXE@ WISH_EXE = @WISH_EXE@
TCL_LIB_DIR = @TCL_LIB_DIR@ TCL_LIB_DIR = @TCL_LIB_DIR@
EXTRA_CFLAGS =
CC = @CC@ CC = @CC@
CPP = @CPP@ CPP = @CPP@
@ -76,7 +77,7 @@ CXX = @CXX@
CPPFLAGS = -I. -I${NETGENDIR} @CPPFLAGS@ CPPFLAGS = -I. -I${NETGENDIR} @CPPFLAGS@
DFLAGS = @extra_defs@ @stub_defs@ @DEFS@ -DSHDLIB_EXT=\"@SHDLIB_EXT@\" -DNDEBUG DFLAGS = @extra_defs@ @stub_defs@ @DEFS@ -DSHDLIB_EXT=\"@SHDLIB_EXT@\" -DNDEBUG
DFLAGS_NOSTUB = @extra_defs@ @DEFS@ -DSHDLIB_EXT=\"@SHDLIB_EXT@\" -DNDEBUG DFLAGS_NOSTUB = @extra_defs@ @DEFS@ -DSHDLIB_EXT=\"@SHDLIB_EXT@\" -DNDEBUG
CFLAGS = @CFLAGS@ @SHLIB_CFLAGS@ @INC_SPECS@ CFLAGS = @CFLAGS@ @SHLIB_CFLAGS@ @INC_SPECS@ ${EXTRA_CFLAGS}
DEPEND_FILE = Depend DEPEND_FILE = Depend
DEPEND_FLAG = @DEPEND_FLAG@ DEPEND_FLAG = @DEPEND_FLAG@

View File

@ -429,7 +429,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
set file1 $name1 set file1 $name1
set cell1 $name1 set cell1 $name1
} }
puts stdout "Reading netlist file $file1" puts stdout "Reading netlist file $file1 for $name1"
set fnum1 [netgen::readnet $file1] set fnum1 [netgen::readnet $file1]
} else { } else {
set cell1 [lindex $flist1 0] set cell1 [lindex $flist1 0]
@ -446,7 +446,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
set file2 $name2 set file2 $name2
set cell2 $name2 set cell2 $name2
} }
puts stdout "Reading netlist file $file2" puts stdout "Reading netlist file $file2 for $name2"
set fnum2 [netgen::readnet $file2] set fnum2 [netgen::readnet $file2]
} else { } else {
set cell2 [lindex $flist2 0] set cell2 [lindex $flist2 0]
@ -461,7 +461,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
} }
set clist1 [cells list $fnum1] set clist1 [cells list $fnum1]
set cidx [lsearch -regexp $clist1 ^$cell1$] set cidx [lsearch -exact $clist1 $cell1]
if {$cidx < 0} { if {$cidx < 0} {
puts stderr "Cannot find cell $cell1 in file $file1" puts stderr "Cannot find cell $cell1 in file $file1"
return return
@ -469,7 +469,7 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
set cell1 [lindex $clist1 $cidx] set cell1 [lindex $clist1 $cidx]
} }
set clist2 [cells list $fnum2] set clist2 [cells list $fnum2]
set cidx [lsearch -regexp $clist2 ^$cell2$] set cidx [lsearch -exact $clist2 $cell2]
if {$cidx < 0} { if {$cidx < 0} {
puts stderr "Cannot find cell $cell2 in file $file2" puts stderr "Cannot find cell $cell2 in file $file2"
return return
@ -477,10 +477,26 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
set cell2 [lindex $clist2 $cidx] set cell2 [lindex $clist2 $cidx]
} }
# The "noflat" list is non-file-specific, so run on each file.
foreach cell $noflat {
set cidx [lsearch -regexp $clist1 ^$cell$]
if {$cidx >= 0} {
netgen::flatten prohibit "$fnum1 $cell"
}
set cidx [lsearch -regexp $clist2 ^$cell$]
if {$cidx >= 0} {
netgen::flatten prohibit "$fnum2 $cell"
}
}
netgen::compare assign "$fnum1 $cell1" "$fnum2 $cell2" netgen::compare assign "$fnum1 $cell1" "$fnum2 $cell2"
if {[file exists $setupfile]} { if {$setupfile == ""} {
puts stdout "Reading setup file $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 # Instead of sourcing the setup file, run each line so we can
# catch individual errors and not let them halt the LVS process # catch individual errors and not let them halt the LVS process
set perrors 0 set perrors 0
@ -500,6 +516,14 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
} }
} }
close $fsetup close $fsetup
if {$command != {}} {
# Incomplete command. Evaluate it to get a meaningful error message
if {[catch {uplevel 1 [list namespace eval netgen $command]} msg]} {
set msg [string trimright $msg "\n"]
puts stderr "Error $setupfile:$sline (ignoring), $msg"
incr perrors
}
}
} else { } else {
puts stdout "Error: Cannot read the setup file $setupfile" puts stdout "Error: Cannot read the setup file $setupfile"
} }
@ -508,8 +532,10 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
puts stdout "Warning: There were errors reading the setup file" puts stdout "Warning: There were errors reading the setup file"
} }
} elseif {[string first nosetup $setupfile] < 0} { } elseif {[string first nosetup $setupfile] < 0} {
netgen::permute default ;# transistors and resistors puts stderr "\nError: Setup file $setupfile does not exist.\n"
netgen::property default return
} else {
puts stderr "\nNo setup file specified. Continuing without a setup.\n"
} }
if {[string first nolog $logfile] < 0} { if {[string first nolog $logfile] < 0} {
@ -588,6 +614,9 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
lappend properr [lindex $endval 0] lappend properr [lindex $endval 0]
} elseif {$uresult == -2} { ;# unmatched pins } elseif {$uresult == -2} { ;# unmatched pins
set doCheckFlatten 1 set doCheckFlatten 1
} elseif {$uresult == -4} { ;# unmatched pins and properties
lappend properr [lindex $endval 0]
set doCheckFlatten 1
} }
} else { } else {
# not equivalent # not equivalent
@ -649,6 +678,11 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
} }
} elseif {[netgen::print queue] == {} && $result == 0} { } elseif {[netgen::print queue] == {} && $result == 0} {
set pinMismatch 1 set pinMismatch 1
} else {
# This assumes that proxy pins are added correctly. Previously,
# that was not trusted, and so an initial pin mismatch would
# always force subcells to be flattened.
set doFlatten 0
} }
} }
if {$doFlatten} { if {$doFlatten} {
@ -735,6 +769,19 @@ set auto_noexec 1 ;# don't EVER call UNIX commands w/o "shell" in front
# Cross-Application section # Cross-Application section
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# For use with open_pdks, set PDK_ROOT from the environment. If no
# such environment variable exists, check some common locations.
if {[catch {set PDK_ROOT $::env(PDK_ROOT)}]} {
if {[file isdir /usr/local/share/pdk] == 1} {
set PDK_ROOT /usr/local/share/pdk
} elseif {[file isdir /usr/share/pdk] == 1} {
set PDK_ROOT /usr/share/pdk
} elseif {[file isdir /foss/pdk] == 1} {
set PDK_ROOT /foss/pdk
}
}
# Setup IRSIM assuming that the Tcl version is installed. # Setup IRSIM assuming that the Tcl version is installed.
# We do not need to rename procedure irsim to NULL because it is # We do not need to rename procedure irsim to NULL because it is
# redefined in a script, which simply overwrites the original. # redefined in a script, which simply overwrites the original.

File diff suppressed because it is too large Load Diff

View File

@ -44,6 +44,8 @@ exec ${NETGEN_WISH:=wish} "$0" ${1+"$@"}
if {$tcl_version < 8.0} { if {$tcl_version < 8.0} {
return -code error "tkcon requires at least Tcl/Tk8" return -code error "tkcon requires at least Tcl/Tk8"
} else { } else {
# Prevent breaking on version 8.5.2
# package require -exact Tk $tcl_version
package require Tk $tcl_version package require Tk $tcl_version
} }
@ -59,18 +61,6 @@ foreach pkg [info loaded {}] {
} }
catch {unset pkg file name version} catch {unset pkg file name version}
# Tk 8.4 makes previously exposed stuff private.
# FIX: Update tkcon to not rely on the private Tk code.
#
if {![llength [info globals tkPriv]]} {
::tk::unsupported::ExposePrivateVariable tkPriv
}
foreach cmd {SetCursor UpDownLine Transpose ScrollPages} {
if {![llength [info commands tkText$cmd]]} {
::tk::unsupported::ExposePrivateCommand tkText$cmd
}
}
# Initialize the ::tkcon namespace # Initialize the ::tkcon namespace
# #
namespace eval ::tkcon { namespace eval ::tkcon {
@ -196,7 +186,7 @@ proc ::tkcon::Init {} {
tkcon_puts tkcon_gets observe observe_var unalias which what tkcon_puts tkcon_gets observe observe_var unalias which what
} }
version 2.3 version 2.3
RCS {RCS: @(#) $Id: tkcon.tcl,v 1.2 2008/05/23 00:20:17 tim Exp $} RCS {RCS: @(#) $Id: tkcon.tcl,v 1.2 2008/04/18 16:28:13 tim Exp $}
HEADURL {http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/tkcon/tkcon/tkcon.tcl?rev=HEAD} HEADURL {http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/tkcon/tkcon/tkcon.tcl?rev=HEAD}
docs "http://tkcon.sourceforge.net/" docs "http://tkcon.sourceforge.net/"
email {jeff@hobbs.org} email {jeff@hobbs.org}
@ -745,7 +735,7 @@ proc ::tkcon::EvalCmd {w cmd} {
$w tag bind $tag <Leave> \ $w tag bind $tag <Leave> \
[list $w tag configure $tag -underline 0] [list $w tag configure $tag -underline 0]
$w tag bind $tag <ButtonRelease-1> \ $w tag bind $tag <ButtonRelease-1> \
"if {!\[info exists tkPriv(mouseMoved)\] || !\$tkPriv(mouseMoved)} \ "if {!\[info exists ::tk::Priv(mouseMoved)\] || !\$::tk::Priv(mouseMoved)} \
{[list edit -attach [Attach] -type error -- $PRIV(errorInfo)]}" {[list edit -attach [Attach] -type error -- $PRIV(errorInfo)]}"
} else { } else {
$w insert output $res\n stderr $w insert output $res\n stderr
@ -2474,7 +2464,7 @@ proc ::tkcon::ErrorHighlight w {
$w tag configure $tag -foreground $COLOR(stdout) $w tag configure $tag -foreground $COLOR(stdout)
$w tag bind $tag <Enter> [list $w tag configure $tag -underline 1] $w tag bind $tag <Enter> [list $w tag configure $tag -underline 1]
$w tag bind $tag <Leave> [list $w tag configure $tag -underline 0] $w tag bind $tag <Leave> [list $w tag configure $tag -underline 0]
$w tag bind $tag <ButtonRelease-1> "if {!\$tkPriv(mouseMoved)} \ $w tag bind $tag <ButtonRelease-1> "if {!\$::tk::Priv(mouseMoved)} \
{[list edit -attach $app -type proc -find $what -- $cmd]}" {[list edit -attach $app -type proc -find $what -- $cmd]}"
} }
set info [string range $info $c1 end] set info [string range $info $c1 end]
@ -2503,7 +2493,7 @@ proc ::tkcon::ErrorHighlight w {
$w tag configure $tag -foreground $COLOR(proc) $w tag configure $tag -foreground $COLOR(proc)
$w tag bind $tag <Enter> [list $w tag configure $tag -underline 1] $w tag bind $tag <Enter> [list $w tag configure $tag -underline 1]
$w tag bind $tag <Leave> [list $w tag configure $tag -underline 0] $w tag bind $tag <Leave> [list $w tag configure $tag -underline 0]
$w tag bind $tag <ButtonRelease-1> "if {!\$tkPriv(mouseMoved)} \ $w tag bind $tag <ButtonRelease-1> "if {!\$::tk::Priv(mouseMoved)} \
{[list edit -attach $app -type proc -- $cmd]}" {[list edit -attach $app -type proc -- $cmd]}"
} }
} }
@ -2552,8 +2542,8 @@ proc tkcon {cmd args} {
## 'congets' a replacement for [gets stdin] ## 'congets' a replacement for [gets stdin]
# Use the 'gets' alias of 'tkcon_gets' command instead of # Use the 'gets' alias of 'tkcon_gets' command instead of
# calling the *get* methods directly for best compatability # calling the *get* methods directly for best compatability
if {[llength $args]} { if {[llength $args] > 1} {
return -code error "wrong # args: must be \"tkcon congets\"" return -code error "wrong # args: must be \"tkcon congets [pfix]\""
} }
tkcon show tkcon show
set old [bind TkConsole <<TkCon_Eval>>] set old [bind TkConsole <<TkCon_Eval>>]
@ -2561,7 +2551,12 @@ proc tkcon {cmd args} {
set w $::tkcon::PRIV(console) set w $::tkcon::PRIV(console)
# Make sure to move the limit to get the right data # Make sure to move the limit to get the right data
$w mark set insert end $w mark set insert end
$w mark set limit insert if {[llength $args]} {
$w mark set limit insert
$w insert end $args
} else {
$w mark set limit insert
}
$w see end $w see end
vwait ::tkcon::PRIV(wait) vwait ::tkcon::PRIV(wait)
set line [::tkcon::CmdGet $w] set line [::tkcon::CmdGet $w]
@ -2798,13 +2793,19 @@ proc tkcon_puts args {
foreach {arg1 arg2 arg3} $args { break } foreach {arg1 arg2 arg3} $args { break }
if {$len == 1} { if {$len == 1} {
tkcon console insert output "$arg1\n" stdout set sarg $arg1
set nl 1
set farg stdout
} elseif {$len == 2} { } elseif {$len == 2} {
if {![string compare $arg1 -nonewline]} { if {![string compare $arg1 -nonewline]} {
tkcon console insert output $arg2 stdout set sarg $arg2
set farg stdout
set nl 0
} elseif {![string compare $arg1 stdout] \ } elseif {![string compare $arg1 stdout] \
|| ![string compare $arg1 stderr]} { || ![string compare $arg1 stderr]} {
tkcon console insert output "$arg2\n" $arg1 set sarg $arg2
set farg $arg1
set nl 1
} else { } else {
set len 0 set len 0
} }
@ -2812,11 +2813,15 @@ proc tkcon_puts args {
if {![string compare $arg1 -nonewline] \ if {![string compare $arg1 -nonewline] \
&& (![string compare $arg2 stdout] \ && (![string compare $arg2 stdout] \
|| ![string compare $arg2 stderr])} { || ![string compare $arg2 stderr])} {
tkcon console insert output $arg3 $arg2 set sarg $arg3
set farg $arg2
set nl 0
} elseif {(![string compare $arg1 stdout] \ } elseif {(![string compare $arg1 stdout] \
|| ![string compare $arg1 stderr]) \ || ![string compare $arg1 stderr]) \
&& ![string compare $arg3 nonewline]} { && ![string compare $arg3 nonewline]} {
tkcon console insert output $arg2 $arg1 set sarg $arg2
set farg $arg1
set nl 0
} else { } else {
set len 0 set len 0
} }
@ -2826,7 +2831,42 @@ proc tkcon_puts args {
## $len == 0 means it wasn't handled by tkcon above. ## $len == 0 means it wasn't handled by tkcon above.
## ##
if {$len == 0} {
if {$len != 0} {
## "poor man's" \r substitution---erase everything on the output
## line and print from character after the \r
set rpt [string last \r $sarg]
if {$rpt >= 0} {
tkcon console delete "insert linestart" "insert lineend"
set sarg [string range $sarg [expr {$rpt + 1}] end]
}
set bpt [string first \b $sarg]
if {$bpt >= 0} {
set narg [string range $sarg [expr {$bpt + 1}] end]
set sarg [string range $sarg 0 [expr {$bpt - 1}]]
set nl 0
}
if {$nl == 0} {
tkcon console insert output $sarg $farg
} else {
tkcon console insert output "$sarg\n" $farg
}
if {$bpt >= 0} {
tkcon console delete "insert -1 char" insert
if {$nl == 0} {
tkcon_puts $farg $narg nonewline
} else {
tkcon_puts $farg $narg
}
}
} else {
global errorCode errorInfo global errorCode errorInfo
if {[catch "tkcon_tcl_puts $args" msg]} { if {[catch "tkcon_tcl_puts $args" msg]} {
regsub tkcon_tcl_puts $msg puts msg regsub tkcon_tcl_puts $msg puts msg
@ -4106,7 +4146,7 @@ proc ::tkcon::Bindings {} {
global tcl_platform tk_version global tcl_platform tk_version
#----------------------------------------------------------------------- #-----------------------------------------------------------------------
# Elements of tkPriv that are used in this file: # Elements of ::tk::Priv that are used in this file:
# #
# char - Character position on the line; kept in order # char - Character position on the line; kept in order
# to allow moving up or down past short lines while # to allow moving up or down past short lines while
@ -4134,6 +4174,9 @@ proc ::tkcon::Bindings {} {
foreach ev [bind Text] { bind TkConsole $ev [bind Text $ev] } foreach ev [bind Text] { bind TkConsole $ev [bind Text $ev] }
## We really didn't want the newline insertion ## We really didn't want the newline insertion
bind TkConsole <Control-Key-o> {} bind TkConsole <Control-Key-o> {}
## in 8.6b3, the virtual events <<NextLine>> and <<PrevLine>>
# mess up our history feature
bind TkConsole <<NextLine>> {} bind TkConsole <<NextLine>> {}
bind TkConsole <<PrevLine>> {} bind TkConsole <<PrevLine>> {}
@ -4342,9 +4385,9 @@ proc ::tkcon::Bindings {} {
bind TkConsole <Control-a> { bind TkConsole <Control-a> {
if {[%W compare {limit linestart} == {insert linestart}]} { if {[%W compare {limit linestart} == {insert linestart}]} {
tkTextSetCursor %W limit ::tk::TextSetCursor %W limit
} else { } else {
tkTextSetCursor %W {insert linestart} ::tk::TextSetCursor %W {insert linestart}
} }
} }
bind TkConsole <Key-Home> [bind TkConsole <Control-a>] bind TkConsole <Key-Home> [bind TkConsole <Control-a>]
@ -4368,14 +4411,14 @@ proc ::tkcon::Bindings {} {
} }
bind TkConsole <<TkCon_Previous>> { bind TkConsole <<TkCon_Previous>> {
if {[%W compare {insert linestart} != {limit linestart}]} { if {[%W compare {insert linestart} != {limit linestart}]} {
tkTextSetCursor %W [tkTextUpDownLine %W -1] ::tk::TextSetCursor %W [::tk::TextUpDownLine %W -1]
} else { } else {
::tkcon::Event -1 ::tkcon::Event -1
} }
} }
bind TkConsole <<TkCon_Next>> { bind TkConsole <<TkCon_Next>> {
if {[%W compare {insert linestart} != {end-1c linestart}]} { if {[%W compare {insert linestart} != {end-1c linestart}]} {
tkTextSetCursor %W [tkTextUpDownLine %W 1] ::tk::TextSetCursor %W [::tk::TextUpDownLine %W 1]
} else { } else {
::tkcon::Event 1 ::tkcon::Event 1
} }
@ -4390,7 +4433,7 @@ proc ::tkcon::Bindings {} {
} }
bind TkConsole <<TkCon_Transpose>> { bind TkConsole <<TkCon_Transpose>> {
## Transpose current and previous chars ## Transpose current and previous chars
if {[%W compare insert > "limit+1c"]} { tkTextTranspose %W } if {[%W compare insert > "limit+1c"]} { ::tk::TextTranspose %W }
} }
bind TkConsole <<TkCon_ClearLine>> { bind TkConsole <<TkCon_ClearLine>> {
## Clear command line (Unix shell staple) ## Clear command line (Unix shell staple)
@ -4408,10 +4451,10 @@ proc ::tkcon::Bindings {} {
::tkcon::Insert %W $::tkcon::PRIV(tmp) ::tkcon::Insert %W $::tkcon::PRIV(tmp)
%W see end %W see end
} }
catch {bind TkConsole <Key-Page_Up> { tkTextScrollPages %W -1 }} catch {bind TkConsole <Key-Page_Up> { ::tk::TextScrollPages %W -1 }}
catch {bind TkConsole <Key-Prior> { tkTextScrollPages %W -1 }} catch {bind TkConsole <Key-Prior> { ::tk::TextScrollPages %W -1 }}
catch {bind TkConsole <Key-Page_Down> { tkTextScrollPages %W 1 }} catch {bind TkConsole <Key-Page_Down> { ::tk::TextScrollPages %W 1 }}
catch {bind TkConsole <Key-Next> { tkTextScrollPages %W 1 }} catch {bind TkConsole <Key-Next> { ::tk::TextScrollPages %W 1 }}
bind TkConsole <$PRIV(meta)-d> { bind TkConsole <$PRIV(meta)-d> {
if {[%W compare insert >= limit]} { if {[%W compare insert >= limit]} {
%W delete insert {insert wordend} %W delete insert {insert wordend}
@ -4429,7 +4472,7 @@ proc ::tkcon::Bindings {} {
} }
bind TkConsole <ButtonRelease-2> { bind TkConsole <ButtonRelease-2> {
if { if {
(!$tkPriv(mouseMoved) || $tk_strictMotif) && (!$::tk::Priv(mouseMoved) || $tk_strictMotif) &&
![catch {::tkcon::GetSelection %W} ::tkcon::PRIV(tmp)] ![catch {::tkcon::GetSelection %W} ::tkcon::PRIV(tmp)]
} { } {
if {[%W compare @%x,%y < limit]} { if {[%W compare @%x,%y < limit]} {