Compare commits

...

73 Commits

Author SHA1 Message Date
R. Timothy Edwards 66faf1d907 Added documentation for the attribute labels in the "label" command
description, because otherwise it only appears in the tech file
reference, where it doesn't really belong since the labels are a
user-level feature, even if they do affect extraction.  The new
feature of using gate attributes for parameters was added to the
command description.  I noticed that the tech file reference made
mention of a gate label in the form of ":ext <name>=<value>", but
this seems not to be implemented anywhere.  At any rate, the method
just committed supercedes that.
2026-03-18 19:28:23 -04:00
R. Timothy Edwards 37db9e453b Extended the use of attribute labels to allow gate attributes to
specify additional parameters for a device.  Any gate attribute
(label ending with "^") that has an "=" in it is considered a
parameter, and is output with the device in the .ext file.  This
gives a way to add specific parameters to a device, which otherwise
have no meaning to the layout editor.  Note that prior to this
extension, the gate attribute was used only to set the device
index.  If a gate attribute is made for a device index, it cannot
have "=" in the name, so it remains backwardly compatible.  Only
non-parameter attributes are passed on to ext2spice.
2026-03-18 16:41:42 -04:00
R. Timothy Edwards 2d5c4be6dd Added a few lines of code to the toolkit management to work around
the issue of a device name in a netlist having different case than
the procedures defined for the device in the PDK.  The difference
in case is transparent to SPICE, so it should also be transparent
to the PDK.
2026-03-18 12:18:42 -04:00
R. Timothy Edwards a9673e45ae Added inductors to the list of devices for which the toolkit can
call a device generator for an ideal component in a netlist.
2026-03-17 11:42:16 -04:00
R. Timothy Edwards 8f95efc257 Added a feature to the toolkit scripts for generated devices to
allow ideal devices in an input netlist to be mapped to
automatically generated cells.  This works if the PDK toolkit
defines a device called either "capacitor" or "resistor".  The
device must be defined such that it can determine sane parameters
for the drawn device from only a value given in the netlist
(capacitance in farads, or resistance in ohms).
2026-03-17 11:32:53 -04:00
R. Timothy Edwards fd12c39c37 Modified the toolkit scripts so that the "add_dependency" procedure
actually works, and also can be called multiple times.  The chaining
of commands and bindings had earlier been done for one of the widget
types (selection) but not the others (entry or checkbox).
2026-03-16 20:02:09 -04:00
R. Timothy Edwards 7d9167257a Corrected an error caused by a recent commit that was attempting
to avoid bogus values for array pitch in the direction in which
a cell is not arrayed:  If the array declares an ANGLE of 90 or
270, then rows and columns are effectively swapped for the
purpose of figuring out which coordinate direction should be
ignored in the input.  The original example did not use ANGLE
and so the exception was not handled.
2026-03-16 12:50:17 -04:00
R. Timothy Edwards 058b320c3f Also applied the same correction as the previous commit, to
hierarchical extraction (as opposed to flat extraction, which is
what the previous commit fixed).
2026-03-15 15:55:48 -04:00
R. Timothy Edwards fee4b887c0 Corrected an issue in ext2spice in which devices extracted as
ideal, unmodeled capacitors or resistors are missing a space
between the 2nd terminal and the device value in the output
netlist.  This affects the ability to produce correct output
for, for example, a metal fingered capacitor using the
"device" property to generate an ideal capacitor in the
netlist.
2026-03-15 15:40:10 -04:00
R. Timothy Edwards 04e91d640d Corrected a problem in which if a label exists that is only connected
to material in a child cell, and the label is a point or line label,
and the parent cell has no material other than the label in the
immediate area, then the "interaction area" will have zero area,
which will cause problems as area checks on a zero-sized area don't
do anything useful.  The solution is to ensure that interaction areas
do not have zero area, but will expand around point labels.  This
should not have any other implications, because the interaction area
is just a way to limit the amount of processing;  larger interaction
areas do not affect the extraction result (except in this case, where
it fixes the error).
2026-03-12 11:50:21 -04:00
R. Timothy Edwards 7d9210a3f1 Updated the HTML reference for the "property" command, which did
not describe the "list" option (which was just as well, since the
option didn't work).
2026-03-11 16:43:29 -04:00
R. Timothy Edwards 03bbc544b2 Fixed a long-standing error that had gone unnoticed that prevents
the use of "property list <key>" to return NULL if <key> is
undefined, instead of printing an error message that cannot be
suppressed.  Scripts which wish to test whether or not a bounding
box exists will of course want the "quiet" version of the command.
2026-03-11 16:35:52 -04:00
R. Timothy Edwards ee79bba5e4 Decided to change the name of the new cifinput/cifoutput operator
from "labeled" to "tagged", since there is already an operator
called "labels", which is confusing.
2026-03-11 15:52:42 -04:00
R. Timothy Edwards 15943d0cb1 Implemented new cifinput/cifoutput operator "labeled" which operates
like "bloat-all" except starting with a label and expanding into a
type rather than starting with a layer.  This is equivalent to what
many tools refer to as "stamping".
2026-03-11 15:06:24 -04:00
R. Timothy Edwards 7bdd9e1d4f Reworked the method from the previous set of commits, which creates
yet another property type "plane".  This allows mask hints to be
handled like tile planes.  That is, after all, what they represent.
Although this change is transparent to the end user (apart from a
slight performance improvement that is probably not noticeable), it
allows for a number of useful future extensions, including the
ability to handle non-Manhattan geometry in mask hints, and the
ability to view and edit mask hints like any other layout.
2026-03-10 14:25:02 -04:00
R. Timothy Edwards 725c8e9235 Made a few corrections to yesterday's code. Most are minor, but
one can potentially cause a crash condition.
2026-03-09 14:40:53 -04:00
R. Timothy Edwards 73ffad3802 Implemented the new feature discussed in the github discussion #492.
This features allows two new instructions in the tech file "drc"
section:  "exception <name>|none" and "exemption <name>|none".  The
purpose of these rules is to allow DRC rule exceptions for certain
areas which are marked, usually by a GDS identifier layer.  Because
GDS identifier layers can be cast as "mask-hint" properties, the
DRC rule exceptions make use of that (recent) feature.  So rules
can be specified as "exceptions" (rule applies for layout inside
the marked area) or "exemptions" (rule is ignored for layout inside
the marked area).  Rules following the statements will have the
exception or exemption applied until another exception or exemption
statement is given.  Either "exception none" or "exemption none" will
stop applying any rule exception or exemption.  This is especially
useful for applications like SRAM where there may be a number of
rule exceptions on different layers.  The previous way to handle
that was to create new layers in magic for any layer that needed a
rule exception.  That mainly resulted in very messy tech files,
and a large number of defined layers.  This implementation is both
simpler and cleaner.
2026-03-08 20:12:58 -04:00
R. Timothy Edwards 037daf1121 Found an issue with coupling capacitance where contact types not
surrounded by metal are not checked for perimeter coupling parasitic
capacitance to other layers.
2026-03-05 18:04:53 -05:00
R. Timothy Edwards d0ef32de0f Tracked down a DRC issue found recently where spurious errors get
drawn outside the area being worked on.  Tracked it down to a
missing check for an invalid rectangle.  Fixed now.
2026-03-05 10:17:29 -05:00
R. Timothy Edwards 0d9b862c0e Corrected a minor error in ext2hier.c where views with no devices
and no ports are still supposed to be output as instances if they
have been marked as abstract views.  Such views were getting output
as cell definitions but not instanced, which although is irrelevant
for simulation, would potentially cause LVS errors.
2026-03-05 09:35:28 -05:00
R. Timothy Edwards 71dc472797 Modified the toolkit code to make use of the "units" command;
otherwise, the existing code would produce results that vary
by units, with potentially incorrect label sizes and spacing
between instances when generating layout devices and subcells
from a netlist.
2026-03-04 13:34:31 -05:00
R. Timothy Edwards 2929ef583e Minor correction to the new "repeat <steps> ... endrepeat" function for
tech files, as the first implementation was repeating one too many
times.  Also:  The wrong type was being read for the number of steps,
although the resulting value was correct.
2026-03-02 12:24:46 -05:00
R. Timothy Edwards ecd6ec56ae Modified the routine for the cif-output "bloat-all <dist>" operator
to make it slightly more efficient.  Noting, however, that it is
still highly inefficient relative to the stepped "grow" + "and"
(or "and-not") operators that it was supposed to replace, I also
implemented a convenience function "repeat <steps>" ... "endrepeat"
to the tech file syntax.  This allows the "grow" + "and" series to
be defined with a few lines, whereas if the steps have to be
spelled out, the series can be scores or hundreds of lines long.
2026-03-01 21:35:00 -05:00
R. Timothy Edwards f3478cba7b Fixed a few issues related to the "save <file>.tcl":
(1) Dimension properties were not output correctly.
(2) Magic insisted that the output file was <cell>.tcl, not <file>.tcl,
    although the error was only in the messaging
(3) Magic was incorrectly renaming the cell to <cell>.tcl after writing
    the file.
2026-03-01 11:29:25 -05:00
R. Timothy Edwards ba5154698d Thought better of the recent change to make "snap" no longer change
units;  although that is a more proper usage, it also happens to
break a lot of existing scripts.  Since virtually all of these
scripts start out with "snap internal" to force units, I have kept
this single usage, when "units" is still set to "default".  That
keeps the older scripts from breaking, while hopefully scripts get
updated over time to use "units" instead of "snap".  Note that there
are still ways to make this behavior break, such as running
"units microns" to set units and then sourcing a script that assumes
that "snap internal" will change the units, which will then not
happen.  But batch scripts should be handled property with backwards-
compatibility mode.
2026-02-28 20:07:00 -05:00
R. Timothy Edwards 1023461ca5 Minor change to the "save <file>.tcl" method to only paint from
TECHDEPBASE, as the layers below that cannot be directly painted;
this avoids putting things like "paint checkpaint" into the
output, which are harmless but useless.
2026-02-27 12:08:35 -05:00
R. Timothy Edwards 197763e46e Modified the output of "save <cell>.tcl" so that (1) it strips the
".tcl" off of the name, so that the cell name remains the same, and
(2) it uses "units" instead of "snap", as the latter is no longer
used for setting the unit type.
2026-02-27 11:18:27 -05:00
R. Timothy Edwards cb7855235a Added a new cifinput operator "not-square" that is useful for
differentiating between bar and square contacts on input.  Also:
added handling of the "mask-hints" operator for GDS input as
well as GDS output.  This is a bit more realistic now that the
mask hint properties are handled as scalable integers and not as
character strings.
2026-02-26 12:48:00 -05:00
R. Timothy Edwards 8f684ad5be Found and fixed the actual error underlying the problem with
grid rescaling while reading a GDS AREF record.  The previous
commit is still valid and prevents excessive warnings and
unnecessary rescaling when a bogus value is given for an array
pitch when the array has only one row or one column.  But the
scaling was still incorrect and would potentially cause an
error if an array pitch was at a finer scale than any data read
before it, forcing a valid grid rescaling.  This now works
correctly.
2026-02-25 09:59:28 -05:00
R. Timothy Edwards f3404f67b7 Came across a weird error today in which some tool inserted bogus
data into an array reference in GDS;  This may be ignored by most
tools (which are not trying to keep track of grid scaling) which
read the bogus value which then gets discarded because it is
unused (X pitch is irrelevant when there is only one column, and
Y pitch is irrelevant when there is only one row).  But since
magic will try to interpret all input relative to the grid, a
bogus value can cause serious problems, and magic needs to actively
ignore the appropriate input in the case of rows = 1 or columns = 1.
2026-02-24 20:56:27 -05:00
R. Timothy Edwards cedd64adcb Quick fix to the script use of "units", which needs to expand the
list argument if the units were saved as a variable.
2026-02-24 16:40:07 -05:00
R. Timothy Edwards afca58f162 Fixed a number of places in the Tcl code where "snap" had been used
to force internal units to be used;  this usage is now deprecated
and needed to be changed to the "units" command.  Also:  Fixed a
separate issue with getting both "view bbox" and "view get" to
return values in the currently selected units.  Also:  Fixed an
issue with "property" when setting a property to a list passed as
a single value (e.g., "property FIXED_BBOX [box values]"), which
needed to null the string after each value.
2026-02-24 15:59:21 -05:00
R. Timothy Edwards 95baea1c22 Corrected another place where the property handling had not been
converted to the new PropertyRecord type.  Since this was in the
CIFPropRecordPath() subroutine, which has always been problematic
and generally useless, I took the opportunity to make that function
dependent on an option set by "gds savepaths true", with the option
set to "false" by default, so "path" properties will no longer be
created from GDS input unless the option is manually set to "true".
Also:  Found that the returned boolean from "box exists" is
sometimes getting overwritten with a NULL result, causing a spurious
Tcl error messages to pop up.  I could not find where this
overwriting happens (probably in a tag callback), so I just took the
hack approach of converting a NULL result to "false", which is always
safe to do.
2026-02-19 11:40:46 -05:00
R. Timothy Edwards 751757a02c Another correction to one function call that was not updated for
the new property structure, causing the "instance abutment"
command to potentially generate an incorrect set of values.
2026-02-19 10:27:03 -05:00
R. Timothy Edwards c32bae1a24 Corrected a minor error from yesterday's commit that will cause
magic to complain about reading GDS_START and GDS_END properties
from a .mag file, although its fallback method handles the properties
correctly, anyway, so there is no actual impact other than the
error message.
2026-02-19 09:42:41 -05:00
R. Timothy Edwards 0c913eca59 Another correction to a code error from a commit earlier today.
Fixes an infinite loop when querying properties during CIF read.
2026-02-18 20:27:33 -05:00
R. Timothy Edwards 2f00f6d8f1 Corrected an error in the output of string properties when writing
.mag files caused by the last commit---Failure to put a space between
the key and the value.  Fixed.
2026-02-18 19:15:14 -05:00
R. Timothy Edwards 9ab7b77dc4 Thought better about suddenly changing the .mag file format with
new properties, so created a "property compat" setting and made
it TRUE by default.  This makes magic print all properties as
type "string" on output into a .mag file.  Which is fine, since
it converts all values to the right type on input anyway.  The
only thing that backwards-compatibility mode prevents is user-
defined properties that are not strings.  That is a very rare case
and can be done by turning off comptability mode.  Some time in
the future compatibility mode can be changed to be default false,
but there's probably no real need to do so.
2026-02-18 16:17:03 -05:00
R. Timothy Edwards 00c0208f18 Corrected an error in which the "global substrate node" flag does
not get transferred to a new node during a node merge;  consequently,
the identity of the default substrate node gets lost, and node
capacitance to substrate ends up being placed on node "0"---
Probably okay for simulation, but not the expected result.
2026-02-18 12:28:48 -05:00
R. Timothy Edwards cb30ac369b Extended the "property" command and modified the way that properties
are handled.  Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy.  The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double".  All types except "string" can consist of multiple
values.  Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted.  In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
2026-02-18 10:48:47 -05:00
R. Timothy Edwards 7e9b6fb61e Fixed the logic for determining which of two node names is "best".
The code was not enforcing an order of precedence, which meant
that the lexigraphical order of EFHNBest() was able to override
the simpler case of one of the node names being a top level port.
2026-02-16 12:02:32 -05:00
R. Timothy Edwards 3b1de8ff40 Corrected an egregious error made when converting "extresist" from
reading the .sim file format to reading the .ext file format, which
is that .sim files use capacitance values of fF while .ext files
use capacitance values of (nominally) aF.  So there was a conversion
factor of 1000 left over from the .sim file reading code that needed
to be removed, or else parasitic values come out to be 1000 times too
high.
2026-02-06 10:50:29 -05:00
R. Timothy Edwards 10a6c8635f Corrected an error with the new "extresist" code which fails to set
the location of a node which was previously read as a port.  But
the port location was not set when reading the port, only the
drivepoint, so the location is undefined and can cause a program
crash.
2026-02-05 17:57:43 -05:00
R. Timothy Edwards e2292f5d70 Modified additional code in ext2spice in the subcircuit instance
output which matches the code for the subcircuit definition output,
so that the pin order matches between the two.  The previous fix
prevented pins from going missing in the subcircuit definition,
but didn't match that change in the instances.  This should
resolve github issue #488.
2026-02-05 17:17:25 -05:00
R. Timothy Edwards 736c507fe8 Preparing to merge another round of development work on extresist;
this work is incomplete but cleans up the code a lot and removes
unused code and improves misleading variable and subroutine names,
as well as correcting an issue with "extresist" not recognizing
the "extract path" setting.  There are no known impacts to the
operation of extresist itself.
2026-02-04 07:54:43 -05:00
R. Timothy Edwards c20a267a2b Updates to the README file for development work in progress. 2026-02-03 21:12:27 -05:00
R. Timothy Edwards bad0b67ce8 Additional work to clean up the code and make some things less
confusing.  Saving work here while rebasing to changes in master.
2026-02-03 21:12:27 -05:00
R. Timothy Edwards 727649b308 Saving work so I can rebase on changes made to the magic extract
code which are relevant and need to be included.  Current state
is that hierarchical extresist "basically works" but entry and
exit points through the hierarchy are not being examined, so
results are currently based on port positions and not actual
connections.  Also, proper distribution of coupling caps has not
yet been worked on.

Rebased, fixing merge conflict.
2026-02-03 21:11:45 -05:00
R. Timothy Edwards 4dde62b206 Start of project. Only some comments in a README file so far. 2026-02-03 21:09:40 -05:00
R. Timothy Edwards 94edc2a23d Corrected an issue where "extresist" crashes magic if the .ext file
it needs to read doesn't exist.
2026-02-03 20:59:28 -05:00
R. Timothy Edwards b248f186ec Identified a potential issue where the terminal area and perimeter
calculation could result in the wrong count of shared terminals
if the device consists of more than one tile, and corrected it.
2026-02-03 17:27:57 -05:00
R. Timothy Edwards 1656866f41 Accidentally reduced by one the count of devices sharing a terminal
area in a recent commit;  fixed this.
2026-02-03 16:14:08 -05:00
R. Timothy Edwards 99297e33ec Modified the way that ext2spice determines which nodes are port
nodes; this should fix issues with ports not appearing in a
subcircuit's port list.
2026-02-03 11:45:20 -05:00
R. Timothy Edwards 727833fcd3 Made another update to go along with the previous commit, that
changes the EFHNIsGlob() function to treat only names listed in
the Tcl array variable "globals" as global, and ignore names
that simply end in "!".
2026-01-31 13:02:35 -05:00
R. Timothy Edwards feb5d61294 Removed two lines of code in the EFHNBest() routine that prefer a
name with a trailing exclamation point over any other name.  The
handling of global names might be properly implementable, but this
is not it, as it will favor a non-port default name or a subcircuit
name over a port.
2026-01-31 10:40:29 -05:00
R. Timothy Edwards 4b120eb417 Corrected two errors related to extraction:
(1) All parasitic extraction:  The "defaultperimeter" and the
"defaultsideoverlap" commands were failing to exempt types other
than space from the list of edges from which fringing capacitance
is evaluated.  This led to incorrectly considering the boundary
between types such as poly and nfet, or between metal1 and rm1,
to be sidewall areas.  The "default" statements are supposed to
consider the most common usage, so the code has been changed to
make sure that only edges from material to space are considered.
In the rare case that a material-to-material edge in the same
plane should be considered a sidewall, the non-default statements
can be used instead.
(2) Hierarchical parasitic extraction:  Magic was incorrectly
adding capacitances for subcells which had been output already
when handling subcircuit connections during "ext2spice".  This
duplicate counting has been eliminated.
2026-01-30 16:47:36 -05:00
R. Timothy Edwards 55eadcfb90 Updated some of the HTML command reference documentation to reflect
changes just made in the "extract" and "extresist" commands.
2026-01-28 17:05:00 -05:00
R. Timothy Edwards b4f62abb40 Removing my file of notes during development of the extresist
code;  the file exists in git history but shouldn't be kept in
the current master branch.
2026-01-28 15:59:08 -05:00
R. Timothy Edwards deefe0e3a3 Updated the version after merging the new extresist code changes. 2026-01-28 14:35:45 -05:00
R. Timothy Edwards 57c33c48c7 Final work on the first stage of the extresist overhaul. The
"extresist" command continues to work as before.  However, the
method now reads from .ext files instead of .sim files, so
generating ".sim" and ".nodes" files is no longer necessary.
In addition, the core code of "extresist" was put directly into
ExtCell.c so that full R-C extraction can be run using
"extract do resistance" followed by "extract all", without
needing to run "extresist" at all other than to set parameters
(e.g., "extresist tolerance 10").
2026-01-28 14:31:38 -05:00
R. Timothy Edwards 76f97c90e5 Slowly working through things needed for removing the ".sim"
file dependency of "extresist".  Stopping and committing work
in order to rebase from the master branch.
2026-01-27 11:58:15 -05:00
R. Timothy Edwards 297a05c4ed More notes in the README file. 2026-01-27 11:58:15 -05:00
R. Timothy Edwards b768fcc3f9 Beginning to tear apart the extresist code; work in progress
and a lot of construction mess.

Resolved conflicts after rebasing on master, since both were
modifying the list of options to "extract".
2026-01-27 11:58:15 -05:00
R. Timothy Edwards 4943da5ce4 Starting new project; only a README so far. 2026-01-27 11:58:15 -05:00
R. Timothy Edwards 512400e39f Added a feature to the wiring tool so that "Control_Button1"
(Ctrl key + left mouse button) will start a wire at the current
cursor position with the wire values set by "wire type" and
reported by "wire values".  So "wire type metal1 0.28um" will
always start a 0.28um wide wire of metal1 regardless of what is
present at the cursor location.
2026-01-27 11:49:33 -05:00
R. Timothy Edwards 0cbed6078a 2nd part of last commit's work: Implement a simple math solving
parser that allows simple expressions to be entered for dimensions,
such as "2um + 2um" or even mixtures of units like "3um + 200i".
This feature is currently experimental.
2026-01-24 21:02:00 -05:00
R. Timothy Edwards 9760ef6d1d Made some changes to the "snap" HTML document to reflect the way
that "units" now affects its behavior.
2026-01-24 16:55:14 -05:00
R. Timothy Edwards bd13febb72 Added HTML documentation for the new "units" command. 2026-01-24 16:50:16 -05:00
R. Timothy Edwards 81436b75ed Reworked the way that magic displays measurement values (both linear
and area) so that they are consistent across commands.  The default
behavior remains the same, for backwards compatibility.  However, a
new "units" command has been added, so that "units microns" results
in measurements always being displayed in microns, with choice of
that or "internal", "lambda", or "grid".  The units themselves may
be printed (for interactive use) or not (for scripted use).  The
use of "units" is independent of "snap", after overriding the
default behavior, so that units parsed on the command line are
interpreted according to "units", not to "snap".
2026-01-24 16:19:12 -05:00
R. Timothy Edwards 8822f8dce2 Added additional code to make the last pull request merge work,
which is to not force a setting for the command entry window
when creating a new window if the option variable already exists.
2026-01-22 11:55:36 -05:00
R. Timothy Edwards f03003b79f Just added a comment to the command entry enablement in the
wrapper.tcl script.
2026-01-22 11:42:45 -05:00
Daniel Hwang 802c31d16a wrapper.tcl: allow cmdentry to be enabled (by default) 2026-01-22 11:31:33 -05:00
R. Timothy Edwards 308224109f Multiple fixes and updates:
(1) Fixed an error that was introduced in version 8.3.590 with
    a patch that should have been applied only for the case of
    BJT devices, and not for MOSFETs.  The patch will cause
    devices generated by "device mosfet" or "device asymmetric"
    to be read incorrectly from a .ext file during "ext2spice".
(2) Fixed an error in the tech file reading, where using CDL
    parameters on a capacitor device would cause the tech file
    loader to print an error message.  The parsing was correct
    and only the message should not have been printed.
(3) Added a new feature with the new command option "extract
    do unique".  This replaces the "extract unique" command by
    running the same code within the extraction, but has the
    additional effect of reverting the label changes afterward.
    This prevents the user from inadvertently writing the
    altered labels back to the database file.
2026-01-22 11:20:20 -05:00
101 changed files with 7026 additions and 4092 deletions

View File

@ -1 +1 @@
8.3.593
8.3.625

View File

@ -53,6 +53,7 @@ int calmaNonManhattan;
int CalmaFlattenLimit = 10;
int NameConvertErrors = 0;
bool CalmaRewound = FALSE;
bool CalmaRecordPaths = FALSE;
TileTypeBitMask *CalmaMaskHints = NULL;
extern HashTable calmaDefInitHash;
@ -505,28 +506,33 @@ calmaParseStructure(
if (CalmaReadOnly || predefined)
{
PropertyRecord *proprec;
char cstring[1024];
/* Writing the file position into a string is slow, but */
/* it prevents requiring special handling when printing */
/* out the properties. */
char *fpcopy = (char *)mallocMagic(20);
char *fncopy;
/* Substitute variable for PDK path or ~ for home directory */
/* the same way that cell references are handled in .mag files. */
DBPathSubstitute(filename, cstring, cifReadCellDef);
fncopy = StrDup(NULL, cstring);
sprintf(fpcopy, "%"DLONG_PREFIX"d", (dlong) filepos);
DBPropPut(cifReadCellDef, "GDS_START", (ClientData)fpcopy);
fpcopy = (char *)mallocMagic(20);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
proprec->prop_type = PROPERTY_TYPE_DOUBLE;
proprec->prop_len = 1;
proprec->prop_value.prop_double[0] = filepos;
DBPropPut(cifReadCellDef, "GDS_START", (ClientData)proprec);
filepos = FTELL(calmaInputFile);
sprintf(fpcopy, "%"DLONG_PREFIX"d", (dlong) filepos);
DBPropPut(cifReadCellDef, "GDS_END", (ClientData)fpcopy);
DBPropPut(cifReadCellDef, "GDS_FILE", (ClientData)fncopy);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
proprec->prop_type = PROPERTY_TYPE_DOUBLE;
proprec->prop_len = 1;
proprec->prop_value.prop_double[0] = filepos;
DBPropPut(cifReadCellDef, "GDS_END", (ClientData)proprec);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) - 7 +
strlen(cstring));
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = 1;
strcpy(proprec->prop_value.prop_string, cstring);
DBPropPut(cifReadCellDef, "GDS_FILE", (ClientData)proprec);
if (predefined)
{
@ -783,8 +789,8 @@ calmaElementSref(
char *filename)
{
int nbytes, rtype, cols, rows, nref, n, i, savescale;
int xlo, ylo, xhi, yhi, xsep, ysep;
bool madeinst = FALSE;
int xlo, ylo, xhi, yhi, xsep, ysep, angle;
bool madeinst = FALSE, rotated = FALSE;
char *sname = NULL;
bool isArray = FALSE;
bool dolookahead = FALSE;
@ -984,17 +990,73 @@ calmaElementSref(
refarray[2].p_x = refarray[2].p_y = 0;
}
/* If the array is given an angle, then the meaning of rows and
* columns needs to be swapped for the purpose of ignoring
* X or Y values in the case of a 1-row or 1-column entry.
*/
angle = GeoTransAngle(&trans, 0);
if ((angle == 90) || (angle == 270) || (angle == -90) || (angle == -270))
rotated = TRUE;
/* If this is a cell reference, then we scale to magic coordinates
* and place the cell in the magic database. However, if this is
* a cell to be flattened a la "gds flatten", then we keep the GDS
* coordinates, and don't scale to the magic database.
*
* NOTE: Scaling everything in the middle or reading array data
* and then retroactively adjusting the array data read earlier
* is problematic, and probably incorrect.
*/
for (n = 0; n < nref; n++)
{
savescale = calmaReadScale1;
/* If there is only one column, then X data in the 2nd or 3rd
* entry is irrelevant. If there is only one row, then Y data
* in the 2nd or 3rd entry is irrelevant. Prevent issues caused
* by incorrect/uninitialized data in these positions by ignoring
* them as needed.
*/
if ((n > 0) && ((!rotated && (rows == 1)) || (rotated && (cols == 1))))
{
calmaReadX(&refarray[n], 1);
calmaSkipBytes(4);
refarray[n].p_y = refarray[0].p_y;
}
else if ((n > 0) && ((!rotated && (cols == 1)) || (rotated && (rows == 1))))
{
calmaSkipBytes(4);
calmaReadY(&refarray[n], 1);
refarray[n].p_x = refarray[0].p_x;
}
else
calmaReadPoint(&refarray[n], 1);
if (savescale != calmaReadScale1)
{
/* Scale changed, so update previous points read */
int newscale = calmaReadScale1 / savescale;
for (i = 0; i < n; i++)
{
refarray[i].p_x *= newscale;
refarray[i].p_y *= newscale;
}
}
if (FEOF(calmaInputFile))
return -1;
}
for (n = 0; n < nref; n++)
refunscaled[n] = refarray[n]; // Save for CDFLATGDS cells
for (n = 0; n < nref; n++)
{
savescale = cifCurReadStyle->crs_scaleFactor;
calmaReadPoint(&refarray[n], 1);
refunscaled[n] = refarray[n]; // Save for CDFLATGDS cells
refarray[n].p_x = CIFScaleCoord(refarray[n].p_x, COORD_EXACT);
if (savescale != cifCurReadStyle->crs_scaleFactor)
{
@ -1015,9 +1077,6 @@ calmaElementSref(
}
refarray[n].p_x *= (savescale / cifCurReadStyle->crs_scaleFactor);
}
if (FEOF(calmaInputFile))
return -1;
}
/* Skip remainder */

View File

@ -114,6 +114,8 @@ calmaInputRescale(
/*
* ----------------------------------------------------------------------------
*
* calmaReadX ---
* calmaReadY ---
* calmaReadPoint ---
*
* Read a point from the input.
@ -132,11 +134,17 @@ calmaInputRescale(
* encountered, then everything in the GDS planes is rescaled
* to match.
*
* Notes:
* This routine has been split into individual X and Y reads so that
* array data can be read while ignoring offset information when there
* is only one row or column; otherwise, bad or uninitialized data
* in the record can cause unnecessary and incorrect scaling.
*
* ----------------------------------------------------------------------------
*/
void
calmaReadPoint(
calmaReadX(
Point *p,
int iscale)
{
@ -163,6 +171,15 @@ calmaReadPoint(
}
}
p->p_x /= calmaReadScale2;
}
void
calmaReadY(
Point *p,
int iscale)
{
int rescale;
READI4((p)->p_y);
p->p_y *= (calmaReadScale1 * iscale);
@ -188,6 +205,15 @@ calmaReadPoint(
p->p_y /= calmaReadScale2;
}
void
calmaReadPoint(
Point *p,
int iscale)
{
calmaReadX(p, iscale);
calmaReadY(p, iscale);
}
/*
* ----------------------------------------------------------------------------
@ -692,7 +718,12 @@ calmaElementPath(void)
}
}
CIFPropRecordPath(cifReadCellDef, pathheadp, TRUE, "path");
/* If requested by command option, record the path centerline as a
* property of the cell def.
*/
if (CalmaRecordPaths)
CIFPropRecordPath(cifReadCellDef, pathheadp, TRUE, "path");
CIFPaintWirePath(pathheadp, width,
(pathtype == CALMAPATH_SQUAREFLUSH || pathtype == CALMAPATH_CUSTOM) ?
FALSE : TRUE, plane, CIFPaintTable, (PaintUndoInfo *)NULL);

View File

@ -528,7 +528,7 @@ calmaDumpStructure(
/* Is view abstract? */
DBPropGet(edef, "LEFview", &isAbstract);
chklibname = (char *)DBPropGet(edef, "GDS_FILE", &isReadOnly);
chklibname = DBPropGetString(edef, "GDS_FILE", &isReadOnly);
if (isAbstract && isReadOnly)
{
@ -738,7 +738,7 @@ calmaFullDump(
* names in the GDS file do not shadow any names in the database.
*/
viewopts = (char *)DBPropGet(def, "LEFview", &isAbstract);
viewopts = DBPropGetString(def, "LEFview", &isAbstract);
if ((!isAbstract) || (strcasecmp(viewopts, "no_prefix")))
{
/* Generate a SHORT name for this cell (else it is easy to run into the
@ -918,7 +918,7 @@ calmaProcessDef(
DBPropGet(def, "GDS_END", &hasGDSEnd);
DBPropGet(def, "CIFhier", &needHier);
filename = (char *)DBPropGet(def, "GDS_FILE", &isReadOnly);
filename = DBPropGetString(def, "GDS_FILE", &isReadOnly);
/* When used with "calma addendum true", don't output the read-only */
/* cells. This makes the library incomplete and dependent on the */
@ -1033,13 +1033,12 @@ calmaProcessDef(
}
else
{
offptr = (char *)DBPropGet(def, "GDS_END", NULL);
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
cval = DBPropGetDouble(def, "GDS_END", NULL);
cellend = (off_t)cval;
offptr = (char *)DBPropGet(def, "GDS_BEGIN", &oldStyle);
cval = DBPropGetDouble(def, "GDS_BEGIN", &oldStyle);
if (!oldStyle)
{
offptr = (char *)DBPropGet(def, "GDS_START", NULL);
cval = DBPropGetDouble(def, "GDS_START", NULL);
/* Write our own header and string name, to ensure */
/* that the magic cell name and GDS name match. */
@ -1056,7 +1055,6 @@ calmaProcessDef(
calmaOutStructName(CALMA_STRNAME, def, outf);
}
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
cellstart = (off_t)cval;
/* GDS_START has been defined as the start of data after the cell */
@ -1263,7 +1261,7 @@ calmaOutFunc(
int dbunits;
calmaOutputStruct cos;
bool propfound;
char *propvalue;
PropertyRecord *proprec;
cos.f = f;
cos.area = (cliprect == &TiPlaneRect) ? NULL : cliprect;
@ -1323,14 +1321,20 @@ calmaOutFunc(
/* Include any fixed bounding box as part of the area to process, */
/* in case the fixed bounding box is larger than the geometry. */
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &propfound);
proprec = DBPropGet(def, "FIXED_BBOX", &propfound);
if (propfound)
{
Rect bbox;
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) == 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
GeoInclude(&bbox, &bigArea);
}
}
CIFErrorDef = def;

View File

@ -508,7 +508,7 @@ calmaDumpStructureZ(
/* Is view abstract? */
DBPropGet(edef, "LEFview", &isAbstract);
chklibname = (char *)DBPropGet(edef, "GDS_FILE", &isReadOnly);
chklibname = DBPropGetString(edef, "GDS_FILE", &isReadOnly);
if (isAbstract && isReadOnly)
{
@ -716,7 +716,7 @@ calmaFullDumpZ(
* names in the GDS file do not shadow any names in the database.
*/
viewopts = (char *)DBPropGet(def, "LEFview", &isAbstract);
viewopts = DBPropGetString(def, "LEFview", &isAbstract);
if ((!isAbstract) || (strcasecmp(viewopts, "no_prefix")))
{
/* Generate a SHORT name for this cell (else it is easy to run into the
@ -870,7 +870,7 @@ calmaProcessDefZ(
DBPropGet(def, "GDS_START", &hasContent);
DBPropGet(def, "GDS_END", &hasGDSEnd);
DBPropGet(def, "CIFhier", &needHier);
filename = (char *)DBPropGet(def, "GDS_FILE", &isReadOnly);
filename = DBPropGetString(def, "GDS_FILE", &isReadOnly);
/* When used with "calma addendum true", don't output the read-only */
/* cells. This makes the library incomplete and dependent on the */
@ -985,13 +985,12 @@ calmaProcessDefZ(
}
else
{
offptr = (char *)DBPropGet(def, "GDS_END", NULL);
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
cval = DBPropGetDouble(def, "GDS_END", NULL);
cellend = (z_off_t)cval;
offptr = (char *)DBPropGet(def, "GDS_BEGIN", &oldStyle);
cval = DBPropGetDouble(def, "GDS_BEGIN", &oldStyle);
if (!oldStyle)
{
offptr = (char *)DBPropGet(def, "GDS_START", NULL);
cval = DBPropGetDouble(def, "GDS_START", NULL);
/* Write our own header and string name, to ensure */
/* that the magic cell name and GDS name match. */
@ -1008,7 +1007,6 @@ calmaProcessDefZ(
calmaOutStructNameZ(CALMA_STRNAME, def, outf);
}
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
cellstart = (z_off_t)cval;
/* GDS_START has been defined as the start of data after the cell */
@ -1186,6 +1184,7 @@ calmaOutFuncZ(
int dbunits;
calmaOutputStructZ cos;
bool propfound;
PropertyRecord *proprec;
char *propvalue;
extern int compport(const void *one, const void *two); /* Forward declaration */
@ -1247,14 +1246,20 @@ calmaOutFuncZ(
/* Include any fixed bounding box as part of the area to process, */
/* in case the fixed bounding box is larger than the geometry. */
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &propfound);
proprec = DBPropGet(def, "FIXED_BBOX", &propfound);
if (propfound)
{
Rect bbox;
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) == 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
GeoInclude(&bbox, &bigArea);
}
}
CIFErrorDef = def;

View File

@ -38,6 +38,7 @@ extern TileTypeBitMask *CalmaMaskHints;
extern bool CalmaMergeTiles;
extern bool CalmaFlattenArrays;
extern bool CalmaNoDRCCheck;
extern bool CalmaRecordPaths;
extern bool CalmaFlattenUses;
extern int CalmaFlattenLimit;
extern float CalmaMagScale;
@ -81,6 +82,8 @@ extern int calmaProcessDefZ(CellDef *def, gzFile outf, bool do_library);
#endif
extern bool calmaReadI2Record(int type, int *pvalue);
extern bool calmaReadI4Record(int type, int *pvalue);
extern void calmaReadX(Point *p, int iscale);
extern void calmaReadY(Point *p, int iscale);
extern void calmaReadPoint(Point *p, int iscale);
extern bool calmaReadR8(double *pd);
extern bool calmaReadStampRecord(int type, int *stampptr);

View File

@ -25,6 +25,7 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
#include <stdlib.h> /* for abs() */
#include <math.h> /* for ceil() and sqrt() */
#include <ctype.h>
#include <string.h> /* for strcmp() */
#include "utils/magic.h"
#include "utils/geometry.h"
@ -1500,6 +1501,7 @@ cifBloatAllFunc(
while (!StackEmpty(BloatStack))
{
Rect cifarea;
TileType tt;
POPTILE(t, dinfo, BloatStack);
@ -1516,8 +1518,6 @@ cifBloatAllFunc(
if (op->co_distance > 0)
{
Rect cifarea;
cifarea.r_xbot = area.r_xbot;
cifarea.r_ybot = area.r_ybot;
cifarea.r_xtop = area.r_xtop;
@ -1555,40 +1555,42 @@ cifBloatAllFunc(
{
tt = TiGetTypeExact(t);
if (op->co_distance > 0)
GeoClip(&area, &clipArea);
DBNMPaintPlane(cifPlane, TiGetTypeExact(t), &area,
DBNMPaintPlane(cifPlane, TiGetTypeExact(t), &cifarea,
CIFPaintTable, (PaintUndoInfo *) NULL);
else
DBNMPaintPlane(cifPlane, TiGetTypeExact(t), &area,
CIFPaintTable, (PaintUndoInfo *) NULL);
}
/* Top */
for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
if (TTMaskHasType(connect, TiGetBottomType(tp)))
PUSHTILE(tp,
(SplitDirection(tp) == ((tt & TT_DIRECTION) ? 1 : 0)) ?
(TileType)0 : (TileType)TT_SIDE,
BloatStack);
if ((op->co_distance == 0) || (area.r_ytop < clipArea.r_ytop))
for (tp = RT(t); RIGHT(tp) > LEFT(t); tp = BL(tp))
if (TTMaskHasType(connect, TiGetBottomType(tp)))
PUSHTILE(tp, (SplitDirection(tp) == ((tt & TT_DIRECTION) ? 1 : 0)) ?
(TileType)0 : (TileType)TT_SIDE, BloatStack);
/* Left */
for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
if (TTMaskHasType(connect, TiGetRightType(tp)))
PUSHTILE(tp, (TileType)TT_SIDE, BloatStack);
if ((op->co_distance == 0) || (area.r_xbot > clipArea.r_xbot))
for (tp = BL(t); BOTTOM(tp) < TOP(t); tp = RT(tp))
if (TTMaskHasType(connect, TiGetRightType(tp)))
PUSHTILE(tp, (TileType)TT_SIDE, BloatStack);
/* Bottom */
for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
if (TTMaskHasType(connect, TiGetTopType(tp)))
PUSHTILE(tp,
(SplitDirection(tp) == ((tt & TT_DIRECTION) ? 1 : 0)) ?
(TileType)TT_SIDE : (TileType)0,
BloatStack);
if ((op->co_distance == 0) || (area.r_ybot > clipArea.r_ybot))
for (tp = LB(t); LEFT(tp) < RIGHT(t); tp = TR(tp))
if (TTMaskHasType(connect, TiGetTopType(tp)))
PUSHTILE(tp, (SplitDirection(tp) == ((tt & TT_DIRECTION) ? 1 : 0)) ?
(TileType)TT_SIDE : (TileType)0, BloatStack);
/* Right */
for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
if (TTMaskHasType(connect, TiGetLeftType(tp)))
PUSHTILE(tp, (TileType)0, BloatStack);
if ((op->co_distance == 0) || (area.r_xtop < clipArea.r_xtop))
for (tp = TR(t); TOP(tp) > BOTTOM(t); tp = LB(tp))
if (TTMaskHasType(connect, TiGetLeftType(tp)))
PUSHTILE(tp, (TileType)0, BloatStack);
}
/* Clear self */
TiSetClient(tile, CIF_UNPROCESSED);
// TiSetClient(tile, CIF_UNPROCESSED);
/* NOTE: Tiles must be cleared after the bloat-all function has
* completed. However, for bloat-all with a limiting distance,
@ -4458,14 +4460,16 @@ bridgeErase(
maskBits = DBPlaneTypes[i];
TTMaskAndMask(&maskBits, &brlims->co_paintMask);
if (!TTMaskEqual(&maskBits, &DBZeroTypeBits))
if (DBSrPaintArea((Tile *) NULL, brlims->def->cd_planes[i], area, &brlims->co_paintMask, cifPaintFunc, CIFEraseTable))
if (DBSrPaintArea((Tile *) NULL, brlims->def->cd_planes[i],
area, &brlims->co_paintMask, cifPaintFunc, CIFEraseTable))
return 0;
}
for (t = 0; t < TT_MAXTYPES; t++, temps++)
{
if (TTMaskHasType(&brlims->co_cifMask, t))
if (DBSrPaintArea((Tile *) NULL, *temps, area, &CIFSolidBits, cifPaintFunc, CIFEraseTable))
if (DBSrPaintArea((Tile *) NULL, *temps, area, &CIFSolidBits,
cifPaintFunc, CIFEraseTable))
return 0;
}
@ -4766,6 +4770,106 @@ cifBridgeLimFunc2(
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* cifNotSquareFunc --
*
* Process each tile and remove those which are square and not
* connected to any other tile of the same type. This operator aids
* in the detection of bar contacts to distinguish them from regular
* (square) contact cuts. Because of the special nature of the
* operator, only the negative-sense operator "not-square" is
* implemented, as the positive-sense operator is not especially
* useful (and can be implemented if needed with "not-square" and
* "and-not").
*
* Results:
* None.
*
* Side effects:
* Modifies the CIF planes.
*
* ----------------------------------------------------------------------------
*/
int
cifNotSquareFunc(
Tile *tile,
TileType dinfo,
ClientData clientData) /* (unused) */
{
Tile *tp;
TileType ttype;
Rect area;
int width, height;
bool isolated = TRUE;
if (IsSplit(tile)) return 0; /* Non-Manhattan tiles are never square */
ttype = TiGetType(tile);
if (ttype == TT_SPACE) return 0; /* Don't handle space tiles */
/* Search all four sides of the tile. Tiles are only considered square
* for the purposes of this operator if they are also unconnected to any
* other tile.
*/
/* Top */
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
if (TiGetBottomType(tp) == ttype)
{
isolated = FALSE;
break;
}
/* Left */
if (isolated)
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
if (TiGetBottomType(tp) == ttype)
{
isolated = FALSE;
break;
}
/* Bottom */
if (isolated)
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
if (TiGetBottomType(tp) == ttype)
{
isolated = FALSE;
break;
}
/* Right */
if (isolated)
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
if (TiGetBottomType(tp) == ttype)
{
isolated = FALSE;
break;
}
TiToRect(tile, &area);
if (isolated)
{
width = area.r_xtop - area.r_xbot;
height = area.r_ytop - area.r_ybot;
if (width == height) return 0; /* Square and isolated */
}
area.r_xbot *= cifScale;
area.r_ybot *= cifScale;
area.r_xtop *= cifScale;
area.r_ytop *= cifScale;
DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *)NULL);
CIFTileOps += 1;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
@ -4779,6 +4883,7 @@ cifBridgeLimFunc2(
* None.
*
* Side effects:
* Modifies the CIF planes.
*
* ----------------------------------------------------------------------------
*/
@ -4940,6 +5045,47 @@ cifInteractingRegions(
}
}
/*
* ----------------------------------------------------------------------------
*
* cifCopyPropPlaneFunc --
*
* Copy the contents of a plane saved as a plane-type property into the
* current CIF plane. The property plane is in magic internal
* coordinates, so each tile needs to be scaled and redrawn into the
* current CIF plane.
*
* Results:
* Zero to keep the search going
*
* Side effects:
* Copies translated geometry into the target plane.
*
* ----------------------------------------------------------------------------
*/
int
cifCopyPropPlaneFunc(Tile *tile,
TileType dinfo,
Plane *curPlane)
{
Rect bbox;
TiToRect(tile, &bbox);
cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
bbox.r_xbot *= cifScale;
bbox.r_ybot *= cifScale;
bbox.r_xtop *= cifScale;
bbox.r_ytop *= cifScale;
cifScale = 1;
DBNMPaintPlane(curPlane, CIF_SOLIDTYPE, &bbox,
CIFPaintTable, (PaintUndoInfo *)NULL);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
@ -4991,13 +5137,15 @@ CIFGenLayer(
CIFSquaresInfo csi;
SearchContext scx;
TileType ttype;
char *netname;
char *netname, *text;
Label *label;
BloatStruct bls;
BridgeStruct brs;
BridgeLimStruct brlims;
BridgeData *bridge;
BloatData *bloats;
BloatData *bloats, locbloat;
bool hstop = FALSE;
PropertyRecord *proprec;
char *propvalue;
bool found;
@ -5395,7 +5543,6 @@ CIFGenLayer(
nextPlane = temp;
break;
case CIFOP_MAXRECT:
cifPlane = curPlane;
@ -5418,6 +5565,19 @@ CIFGenLayer(
nextPlane = temp;
break;
case CIFOP_NOTSQUARE:
DBClearPaintPlane(nextPlane);
cifPlane = nextPlane;
cifScale = 1;
DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect,
&CIFSolidBits, cifNotSquareFunc,
(ClientData)NULL);
temp = curPlane;
curPlane = nextPlane;
nextPlane = temp;
break;
case CIFOP_NET:
if (hier)
{
@ -5443,6 +5603,105 @@ CIFGenLayer(
}
break;
case CIFOP_TAGGED:
if (hier)
{
hstop = TRUE; /* Stop hierarchical processing */
break;
}
/*
* Find all relevant labels by text matching and then continue
* like CIFOP_BLOATALL. CIFOP_BLOATALL uses a BloatData record
* which is not part of CIFOP_TAGGED. Create a BloatData record
* on the fly for each tagged area based on type, and swap it for
* the text, so that cifBloatAllFunc believes this is actually a
* CIFOP_BLOATALL operation. Note that we don't actually care
* what layer the label is attached to (lab_type). We are looking
* for labels whose lab_rect values overlap the types that are given
* in the rule.
*/
cifPlane = curPlane;
bls.op = op;
bls.def = cellDef;
bls.temps = temps;
text = (char *)op->co_client;
bloats = &locbloat;
if (!TTMaskIsZero(&op->co_cifMask))
{
bloats->bl_plane = -1;
for (ttype = 0; ttype < TT_MAXTYPES; ttype++)
{
if (TTMaskHasType(&op->co_cifMask, ttype))
bloats->bl_distance[ttype] = 1;
else
bloats->bl_distance[ttype] = 0;
}
}
else if (!TTMaskIsZero(&op->co_paintMask))
{
int plane, pmask;
pmask = DBTechTypesToPlanes(&op->co_paintMask);
for (plane = PL_TECHDEPBASE; plane < DBNumPlanes; plane++)
if (PlaneMaskHasPlane(pmask, plane))
break;
bloats->bl_plane = plane;
for (ttype = 0; ttype < TT_MAXTYPES; ttype++)
{
if (TTMaskHasType(&op->co_paintMask, ttype))
bloats->bl_distance[ttype] = 1;
else
bloats->bl_distance[ttype] = 0;
}
}
/* Replace the client data with the bloat record */
op->co_client = (ClientData)bloats;
if (bloats->bl_plane < 0)
{
/* bl_plane == -1 indicates bloating into a CIF templayer, */
/* so the only connecting type should be CIF_SOLIDTYPE. */
TTMaskSetOnlyType(&bls.connect, CIF_SOLIDTYPE);
}
else
{
int i;
TTMaskZero(&bls.connect);
for (i = 0; i < TT_MAXTYPES; i++)
if (bloats->bl_distance[i] != 0)
TTMaskSetType(&bls.connect, i);
}
for (label = cellDef->cd_labels; label; label = label->lab_next)
if (!strcmp(label->lab_text, text))
cifSrTiles(op, &label->lab_rect, cellDef, temps,
cifBloatAllFunc, (ClientData)&bls);
/* Reset marked tiles */
if (bloats->bl_plane < 0) /* Bloat types are CIF types */
{
bls.temps = temps;
for (ttype = 0; ttype < TT_MAXTYPES; ttype++, bls.temps++)
if (bloats->bl_distance[ttype] > 0)
(void) DBSrPaintArea((Tile *)NULL, *bls.temps, &TiPlaneRect,
&CIFSolidBits, cifProcessResetFunc,
(ClientData)NULL);
}
else
DBSrPaintArea((Tile *)NULL, cellDef->cd_planes[bloats->bl_plane],
&TiPlaneRect, &bls.connect, cifProcessResetFunc,
(ClientData)NULL);
/* Replace the client data */
op->co_client = (ClientData)text;
break;
case CIFOP_BOUNDARY:
if (hier)
{
@ -5454,10 +5713,17 @@ CIFGenLayer(
if (origDef && (origDef->cd_flags & CDFIXEDBBOX))
{
propvalue = (char *)DBPropGet(origDef, "FIXED_BBOX", &found);
proprec = DBPropGet(origDef, "FIXED_BBOX", &found);
if (!found) break;
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) != 4) break;
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
}
cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
bbox.r_xbot *= cifScale;
@ -5519,46 +5785,22 @@ CIFGenLayer(
case CIFOP_MASKHINTS:
{
int j, numfound;
int n;
char propname[512];
char *propptr;
char *layername = (char *)op->co_client;
Tile *t;
sprintf(propname, "MASKHINTS_%s", layername);
snprintf(propname, 512, "MASKHINTS_%s", layername);
propvalue = (char *)DBPropGet(cellDef, propname, &found);
if (cellDef == (CellDef *)NULL) break;
proprec = DBPropGet(cellDef, propname, &found);
if (!found) break; /* No mask hints available */
propptr = propvalue;
while (*propptr)
{
numfound = sscanf(propptr, "%d %d %d %d",
&bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop);
if (numfound != 4)
{
/* To do: Allow keyword "rect", "tri", or "poly"
* at the start of the list and parse accordingly.
* For now, this only flags an error.
*/
TxError("%s: Cannot read rectangle values.\n", propname);
break;
}
cifPlane = curPlane;
cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
bbox.r_xbot *= cifScale;
bbox.r_xtop *= cifScale;
bbox.r_ybot *= cifScale;
bbox.r_ytop *= cifScale;
cifScale = 1;
DBNMPaintPlane(curPlane, CIF_SOLIDTYPE, &bbox,
CIFPaintTable, (PaintUndoInfo *)NULL);
for (j = 0; j < 4; j++)
{
while (*propptr && isspace(*propptr)) propptr++;
while (*propptr && !isspace(*propptr)) propptr++;
}
}
ASSERT (proprec->prop_type == PROPERTY_TYPE_PLANE, "CIFGenLayer");
t = PlaneGetHint(proprec->prop_value.prop_plane);
DBSrPaintArea(t, proprec->prop_value.prop_plane,
&TiPlaneRect, &CIFSolidBits,
cifCopyPropPlaneFunc, (ClientData)curPlane);
}
break;

View File

@ -209,52 +209,41 @@ typedef struct _maskHintsData
{
Transform *mh_trans;
CellDef *mh_def;
Plane *mh_plane;
} MaskHintsData;
/*
* ----------------------------------------------------------------------------
*
* cifMaskHints --
* cifCopyMaskHintFunc --
*
* Copy a mask hint into a target cell by adding it to the
* property list of the target cell. If the target cell already
* has the same mask hint key, then the mask hint value is
* appended to the property in the target cell def.
* Callback function used by cifFlatMaskHints. Transforms a tile
* from the original plane and paints it into the target plane,
* both of which are properties.
*
* Returns:
* 0 to keep the search going.
* Results:
* Zero to keep the search going.
*
* Side effects:
* Modifies properties of the target cell def.
* Paints geometry into the target plane.
*
* ----------------------------------------------------------------------------
*/
/* DEPRECATED */
int
cifMaskHints(
char *name,
char *value,
CellDef *targetDef)
cifCopyMaskHintFunc(Tile *tile,
TileType dinfo,
ClientData cdata)
{
char *propvalue, *newval;
bool propfound;
MaskHintsData *mhd = (MaskHintsData *)cdata;
Rect r, newr;
if (!strncmp(name, "MASKHINTS_", 10))
{
/* Check if name exists already in the flattened cell */
propvalue = (char *)DBPropGet(targetDef, name, &propfound);
if (propfound)
{
/* Append value to the property */
newval = mallocMagic(strlen(value) + strlen(propvalue) + 2);
sprintf(newval, "%s %s", propvalue, value);
}
else
newval = StrDup((char **)NULL, value);
TiToRect(tile, &r);
/* Transform tile area to coordinates of mhd->mh_plane and paint */
GeoTransRect(mhd->mh_trans, &r, &newr);
DBPaintPlane(mhd->mh_plane, &newr, CIFPaintTable, (PaintUndoInfo *)NULL);
DBPropPut(targetDef, name, newval);
}
return 0;
}
@ -264,8 +253,8 @@ cifMaskHints(
* cifFlatMaskHints --
*
* Copy a mask hint into a flattened cell by transforming it into the
* coordinate system of the flattened cell, and adding it to the
* property list of the flattened cell.
* coordinate system of the flattened cell, and painting it into the
* property plane of the flattened cell.
*
* Returns:
* 0 to keep the search going.
@ -279,67 +268,40 @@ cifMaskHints(
int
cifFlatMaskHints(
char *name,
char *value,
PropertyRecord *proprec,
MaskHintsData *mhd)
{
Rect r, newr;
char *vptr, *newval, *lastval, *propvalue;
bool propfound;
int lastlen, numvals;
int i, lastlen, numvals;
PropertyRecord *newproprec, *oldproprec;
Plane *plane;
if (!strncmp(name, "MASKHINTS_", 10))
{
newval = (char *)NULL;
vptr = value;
while (*vptr != '\0')
{
numvals = sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
&r.r_xtop, &r.r_ytop);
if (numvals == 4)
{
/* Transform rectangle to top level coordinates */
GeoTransRect(mhd->mh_trans, &r, &newr);
lastval = newval;
lastlen = (lastval) ? strlen(lastval) : 0;
newval = mallocMagic(40 + lastlen);
if (lastval)
strcpy(newval, lastval);
else
*newval = '\0';
sprintf(newval + lastlen, "%s%d %d %d %d", (lastval) ? " " : "",
newr.r_xbot, newr.r_ybot, newr.r_xtop, newr.r_ytop);
if (lastval) freeMagic(lastval);
/* Parse through the four values and check if there's more */
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
}
else
{
TxError("MASKHINTS_%s: Expected 4 values, found only %d\n",
name + 10, numvals);
break;
}
}
/* Check if name exists already in the flattened cell */
propvalue = (char *)DBPropGet(mhd->mh_def, name, &propfound);
oldproprec = (PropertyRecord *)DBPropGet(mhd->mh_def, name, &propfound);
if (propfound)
{
/* Append newval to the property */
lastval = newval;
newval = mallocMagic(strlen(lastval) + strlen(propvalue) + 2);
sprintf(newval, "%s %s", propvalue, lastval);
freeMagic(lastval);
ASSERT(oldproprec->prop_value.prop_type == PROPERTY_TYPE_PLANE,
"cifFlatMaskHints");
plane = oldproprec->prop_value.prop_plane;
}
DBPropPut(mhd->mh_def, name, newval);
else
{
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
newproprec->prop_len = 0; /* (unused) */
newproprec->prop_type = PROPERTY_TYPE_PLANE;
plane = DBNewPlane((ClientData)TT_SPACE);
newproprec->prop_value.prop_plane = plane;
DBPropPut(mhd->mh_def, name, newproprec);
}
mhd->mh_plane = plane;
DBSrPaintArea((Tile *)NULL, proprec->prop_value.prop_plane,
&TiPlaneRect, &CIFSolidBits,
cifCopyMaskHintFunc, (ClientData)mhd);
}
return 0;
}
@ -350,9 +312,10 @@ cifFlatMaskHints(
* CIFCopyMaskHints --
*
* Callback function to copy mask hints from one cell into another.
* (Occasionally called as a standalone function, not as a callback.)
*
* Results:
* None.
* Return 0 to keep the search going.
*
* Side effects:
* May modify properties in the target cell.
@ -360,7 +323,7 @@ cifFlatMaskHints(
* ----------------------------------------------------------------------------
*/
void
int
CIFCopyMaskHints(
SearchContext *scx,
CellDef *targetDef)
@ -370,38 +333,9 @@ CIFCopyMaskHints(
CellDef *sourceDef = scx->scx_use->cu_def;
mhd.mh_trans = &scx->scx_trans;
mhd.mh_def = targetDef;
mhd.mh_plane = (Plane *)NULL;
DBPropEnum(sourceDef, cifFlatMaskHints, &mhd);
}
/*
* ----------------------------------------------------------------------------
*
* cifHierCopyMaskHints --
*
* Callback function to copy mask hints from a subcell into a flattened
* cell, which is passed in the clientData record.
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* May modify properties in the flattened cell.
*
* ----------------------------------------------------------------------------
*/
int
cifHierCopyMaskHints(
SearchContext *scx,
ClientData clientData)
{
MaskHintsData mhd;
mhd.mh_trans = &scx->scx_trans;
mhd.mh_def = (CellDef *)clientData;
DBPropEnum(scx->scx_use->cu_def, cifFlatMaskHints, &mhd);
return 0;
}
@ -526,7 +460,7 @@ cifHierCellFunc(
/* Flatten mask hints in the area of interest */
CIFCopyMaskHints(scx, CIFComponentDef);
DBTreeSrCells(&newscx, 0, cifHierCopyMaskHints,
DBTreeSrCells(&newscx, 0, CIFCopyMaskHints,
(ClientData)CIFComponentDef);
/* Set CIFErrorDef to NULL to ignore errors here... these will
@ -854,7 +788,7 @@ CIFGenSubcells(
cifHierCopyFunc, (ClientData) CIFTotalDef);
/* Flatten mask hints in the area of interest */
CIFCopyMaskHints(&scx, CIFTotalDef);
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFTotalDef);
CIFErrorDef = def;
@ -1032,14 +966,14 @@ cifHierElementFunc(
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
cifHierCopyFunc, (ClientData) CIFTotalDef);
CIFCopyMaskHints(&scx, CIFTotalDef);
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFTotalDef);
DBCellClearDef(CIFComponentDef);
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef);
CIFCopyMaskHints(&scx, CIFComponentDef);
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFComponentDef);
CIFErrorDef = (CellDef *) NULL;

View File

@ -145,6 +145,8 @@ typedef struct cifop
* CIFOP_BRIDGE - Added 6/11/20---Bridge across catecorner gaps
* CIFOP_BRIDGELIM - Added 27/07/20---Bridge across catecorner gaps, but with limiting layers
* CIFOP_MASKHINTS - Added 12/14/20---Add geometry from cell properties, if any.
* CIFOP_NOTSQUARE - Added 2/26/26---Keep only geometry which is not square.
* CIFOP_TAGGED - Added 3/11/26---Find geometry attached to the given text label
*/
#define CIFOP_AND 1
@ -172,6 +174,8 @@ typedef struct cifop
#define CIFOP_BRIDGE 23
#define CIFOP_BRIDGELIM 24
#define CIFOP_MASKHINTS 25
#define CIFOP_NOTSQUARE 26
#define CIFOP_TAGGED 27
/* Definitions of bit fields used in the value of co_client for CIFOP_INTERACT */
#define CIFOP_INT_NOT 0x1 /* Inverted sense (not interacting) */
@ -336,9 +340,8 @@ extern Plane *CIFGenLayer(CIFOp *op, const Rect *area, CellDef *cellDef, CellDef
bool hier, ClientData clientdata);
extern void CIFInitCells(void);
extern int cifHierCopyFunc(Tile *tile, TileType dinfo, TreeContext *cxp);
extern int cifHierCopyMaskHints(SearchContext *scx, ClientData clientData);
extern void CIFLoadStyle(char *stylename);
extern void CIFCopyMaskHints(SearchContext *scx, CellDef *targetDef);
extern int CIFCopyMaskHints(SearchContext *scx, CellDef *targetDef);
/* C99 compat */
extern void CIFCoverageLayer(CellDef *rootDef, Rect *area, char *layer, bool dolist);

View File

@ -613,7 +613,7 @@ CIFPaintCurrent(
CIFOp *op;
plane = CIFGenLayer(cifCurReadStyle->crs_layers[i]->crl_ops,
&TiPlaneRect, (CellDef *)NULL, (CellDef *)NULL,
&TiPlaneRect, cifReadCellDef, cifReadCellDef,
cifCurReadPlanes, FALSE, (ClientData)NULL);
/* Generate a paint/erase table, then paint from the CIF
@ -688,6 +688,8 @@ CIFPaintCurrent(
}
else if (op == NULL)
{
LinkedRect *lrec = NULL, *lsrch;
/* Handle boundary layer */
op = cifCurReadStyle->crs_layers[i]->crl_ops;
@ -702,6 +704,102 @@ CIFPaintCurrent(
(ClientData)NULL) == 1))
DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect,
&CIFSolidBits, cifMakeBoundaryFunc, INT2CD(filetype));
/* Handle mask-hints input operator */
op = cifCurReadStyle->crs_layers[i]->crl_ops;
while (op)
{
if (op->co_opcode == CIFOP_MASKHINTS) break;
op = op->co_next;
}
if (op && (DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect,
&DBAllButSpaceBits, cifCheckPaintFunc,
(ClientData)NULL) == 1))
{
/* (To do: remove the linked Rects and paint directly
* into the plane in cifMaskHintFunc())
*/
DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect,
&CIFSolidBits, cifMaskHintFunc,
(ClientData)&lrec);
if (lrec != NULL)
{
PropertyRecord *proprec, *proporig;
char *propname, *layername;
int proplen, i, savescale;
bool origfound = FALSE;
Plane *plane;
layername = (char *)op->co_client;
propname = (char *)mallocMagic(11 + strlen(layername));
sprintf(propname, "MASKHINTS_%s", layername);
/* If there is already a mask hint plane for this layer,
* then add to it; otherwise, create a new plane.
*/
proprec = DBPropGet(cifReadCellDef, layername, &origfound);
if (origfound)
plane = proprec->prop_value.prop_plane;
else
{
proprec = (PropertyRecord *)mallocMagic(
sizeof(PropertyRecord));
proprec->prop_type = PROPERTY_TYPE_PLANE;
proprec->prop_len = 0; /* (unused) */
plane = DBNewPlane((ClientData)TT_SPACE);
proprec->prop_value.prop_plane = plane;
DBPropPut(cifReadCellDef, propname, proprec);
}
while (lrec != NULL)
{
lrec->r_r.r_xtop =
CIFScaleCoord(lrec->r_r.r_xtop, COORD_EXACT);
savescale = cifCurReadStyle->crs_scaleFactor;
lrec->r_r.r_ytop =
CIFScaleCoord(lrec->r_r.r_ytop, COORD_EXACT);
if (savescale != cifCurReadStyle->crs_scaleFactor)
{
lrec->r_r.r_xtop *=
(savescale / cifCurReadStyle->crs_scaleFactor);
savescale = cifCurReadStyle->crs_scaleFactor;
}
lrec->r_r.r_xbot =
CIFScaleCoord(lrec->r_r.r_xbot, COORD_EXACT);
if (savescale != cifCurReadStyle->crs_scaleFactor)
{
lrec->r_r.r_xtop *=
(savescale / cifCurReadStyle->crs_scaleFactor);
lrec->r_r.r_ytop *=
(savescale / cifCurReadStyle->crs_scaleFactor);
savescale = cifCurReadStyle->crs_scaleFactor;
}
lrec->r_r.r_ybot =
CIFScaleCoord(lrec->r_r.r_ybot, COORD_EXACT);
if (savescale != cifCurReadStyle->crs_scaleFactor)
{
lrec->r_r.r_xtop *=
(savescale / cifCurReadStyle->crs_scaleFactor);
lrec->r_r.r_ytop *=
(savescale / cifCurReadStyle->crs_scaleFactor);
lrec->r_r.r_xbot *=
(savescale / cifCurReadStyle->crs_scaleFactor);
}
DBPaintPlane(plane, &lrec->r_r, CIFPaintTable,
(PaintUndoInfo *)NULL);
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, lrec);
lrec = lrec->r_next;
freeMagic1_end(&mm1);
}
freeMagic(propname);
}
}
}
/* Swap planes */
@ -790,9 +888,7 @@ CIFPaintCurrent(
for (i = 0; i < cifNReadLayers; i++)
{
LinkedRect *lrec = NULL;
char *propstr = NULL;
char locstr[512];
LinkedRect *lrec = NULL, *lsrch;
Plane *tempp;
if (!TTMaskHasType(CalmaMaskHints, i)) continue;
@ -817,53 +913,55 @@ CIFPaintCurrent(
(CellDef *)NULL, CIFPlanes, FALSE, (ClientData)NULL);
/* Scan the resulting plane and generate linked Rect structures for
* each shape found.
* each shape found. (To do: Remove the linked Rects and paint
* directly into the plane in cifMaskHintFunc(), which is more
* efficient but not hugely so.)
*/
DBSrPaintArea((Tile *)NULL, presult, &TiPlaneRect, &CIFSolidBits,
cifMaskHintFunc, (ClientData)&lrec);
if (lrec != NULL)
{
PropertyRecord *proprec;
bool propfound;
char *propname;
Plane *plane;
propname = (char *)mallocMagic(11 + strlen(cifReadLayers[i]));
sprintf(propname, "MASKHINTS_%s", cifReadLayers[i]);
propstr = (char *)NULL;
/* Turn all linked Rects into a mask-hints property in the
* target cell.
/* Paint all linked Rects into a mask-hints property plane
* in the target cell.
*/
proprec = DBPropGet(cifReadCellDef, propname, &propfound);
if (!propfound)
{
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
proprec->prop_type = PROPERTY_TYPE_PLANE;
proprec->prop_len = 0; /* (unused) */
plane = DBNewPlane((ClientData)TT_SPACE);
proprec->prop_value.prop_plane = plane;
DBPropPut(cifReadCellDef, propname, proprec);
}
else
plane = proprec->prop_value.prop_plane;
while (lrec != NULL)
{
char *newstr;
sprintf(locstr, "%d %d %d %d",
lrec->r_r.r_xbot / CIFCurStyle->cs_scaleFactor,
lrec->r_r.r_ybot / CIFCurStyle->cs_scaleFactor,
lrec->r_r.r_xtop / CIFCurStyle->cs_scaleFactor,
lrec->r_r.r_ytop / CIFCurStyle->cs_scaleFactor);
if (propstr == NULL)
{
newstr = (char *)mallocMagic(strlen(locstr) + 1);
sprintf(newstr, "%s", locstr);
}
else
{
newstr = (char *)mallocMagic(strlen(locstr)
+ strlen(propstr) + 2);
sprintf(newstr, "%s %s", propstr, locstr);
freeMagic(propstr);
}
propstr = newstr;
lrec->r_r.r_xbot /= CIFCurStyle->cs_scaleFactor;
lrec->r_r.r_ybot /= CIFCurStyle->cs_scaleFactor;
lrec->r_r.r_xtop /= CIFCurStyle->cs_scaleFactor;
lrec->r_r.r_ytop /= CIFCurStyle->cs_scaleFactor;
DBPaintPlane(plane, &lrec->r_r, CIFPaintTable,
(PaintUndoInfo *)NULL);
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, lrec);
lrec = lrec->r_next;
freeMagic1_end(&mm1);
}
/* NOTE: propstr is transferred to the CellDef and should
* not be free'd here.
*/
DBPropPut(cifReadCellDef, propname, propstr);
freeMagic(propname);
}
@ -902,6 +1000,7 @@ cifMakeBoundaryFunc(
/* If there are multiple rectangles defined with the boundary */
/* layer, then the last one defines the FIXED_BBOX property. */
PropertyRecord *proprec;
Rect area;
char propertyvalue[128], *storedvalue;
int savescale;
@ -933,19 +1032,24 @@ cifMakeBoundaryFunc(
if (cifReadCellDef->cd_flags & CDFIXEDBBOX)
{
char *propvalue;
PropertyRecord *proprec;
bool found;
/* Only flag a warning if the redefined boundary was */
/* different from the original. */
propvalue = (char *)DBPropGet(cifReadCellDef, "FIXED_BBOX", &found);
proprec = DBPropGet(cifReadCellDef, "FIXED_BBOX", &found);
if (found)
{
Rect bbox;
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) == 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
if ((bbox.r_xbot != area.r_xbot) ||
(bbox.r_ybot != area.r_ybot) ||
(bbox.r_xtop != area.r_xtop) ||
@ -962,10 +1066,15 @@ cifMakeBoundaryFunc(
}
}
sprintf(propertyvalue, "%d %d %d %d",
area.r_xbot, area.r_ybot, area.r_xtop, area.r_ytop);
storedvalue = StrDup((char **)NULL, propertyvalue);
DBPropPut(cifReadCellDef, "FIXED_BBOX", storedvalue);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) + 2 * sizeof(int));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = 4;
proprec->prop_value.prop_integer[0] = area.r_xbot;
proprec->prop_value.prop_integer[1] = area.r_ybot;
proprec->prop_value.prop_integer[2] = area.r_xtop;
proprec->prop_value.prop_integer[3] = area.r_ytop;
DBPropPut(cifReadCellDef, "FIXED_BBOX", proprec);
cifReadCellDef->cd_flags |= CDFIXEDBBOX;
return 0;
}

View File

@ -244,40 +244,61 @@ CIFPropRecordPath(
{
extern float CIFGetOutputScale(int convert);
CIFPath *pathp;
char *pathstr, *sptr;
int components;
float x, y, oscale, mult;
char *namestr = NULL;
int components, i, x, y, mult, pathnum;
PropertyRecord *proprec;
bool propfound;
oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */
if (oscale == 0.0) oscale = 1.0;
mult = (iswire == TRUE) ? 0.5 : 1.0;
/* If "name" is a property, then append a suffix to it to ensure uniqueness */
DBPropGet(def, propname, &propfound);
if (propfound)
{
pathnum = 0;
namestr = mallocMagic(strlen(propname) + 10);
while (propfound)
{
sprintf(namestr, "%s_%d", propname, pathnum);
DBPropGet(def, namestr, &propfound);
pathnum++;
}
}
pathp = pathheadp;
components = 0;
mult = (iswire == TRUE) ? 1 : 0;
/* Count the number of components in the path */
pathp = pathheadp;
components = 0;
while (pathp != NULL)
{
pathp = pathp->cifp_next;
components++;
pathp = pathp->cifp_next;
}
/* Allocate enough space to hold 2 * N points at "infinity" */
pathstr = (char *)mallocMagic(components * 40);
/* Allocate enough space to hold 2 * N points. */
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
((components - 1) * 2) * sizeof(int));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = components * 2;
pathp = pathheadp;
sptr = pathstr;
i = 0;
while (pathp != NULL)
{
x = (float)pathp->cifp_x * oscale * mult;
y = (float)pathp->cifp_y * oscale * mult;
sprintf(sptr, "%.3f %.3f ", x, y);
sptr = sptr + strlen(sptr);
x = pathp->cifp_x >> mult;
y = pathp->cifp_y >> mult;
proprec->prop_value.prop_integer[i] = x;
proprec->prop_value.prop_integer[i + 1] = y;
i += 2;
pathp = pathp->cifp_next;
}
/* Reallocate pathstr to be no larger than needed to hold the path contents */
StrDup(&pathstr, pathstr);
DBPropPut(def, propname, (ClientData)pathstr);
if (namestr)
{
DBPropPut(def, namestr, proprec);
freeMagic(namestr);
}
else
DBPropPut(def, propname, proprec);
}
/*

View File

@ -324,14 +324,19 @@ cifNewReadStyle(void)
{
/* Destroy old style and free all memory allocated to it */
for (i=0; i<MAXCIFRLAYERS; i+=1)
for (i = 0; i < MAXCIFRLAYERS; i++)
{
layer = cifCurReadStyle->crs_layers[i];
if (layer != NULL)
{
free_magic1_t mm1 = freeMagic1_init();
for (op = layer->crl_ops; op != NULL; op = op->co_next)
{
if (op->co_opcode == CIFOP_MASKHINTS ||
op->co_opcode == CIFOP_TAGGED)
freeMagic((char *)op->co_client);
freeMagic1(&mm1, (char *)op);
}
freeMagic1_end(&mm1);
freeMagic((char *)layer);
}
@ -990,6 +995,12 @@ CIFReadTechLine(
newOp->co_opcode = CIFOP_COPYUP;
else if (strcmp(argv[0], "boundary") == 0)
newOp->co_opcode = CIFOP_BOUNDARY;
else if (strcmp(argv[0], "not-square") == 0)
newOp->co_opcode = CIFOP_NOTSQUARE;
else if (strcmp(argv[0], "mask-hints") == 0)
newOp->co_opcode = CIFOP_MASKHINTS;
else if (strcmp(argv[0], "tagged") == 0)
newOp->co_opcode = CIFOP_TAGGED;
else
{
TechError("Unknown statement \"%s\".\n", argv[0]);
@ -1016,6 +1027,15 @@ CIFReadTechLine(
goto errorReturn;
}
break;
case CIFOP_MASKHINTS:
if (argc != 2) goto wrongNumArgs;
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
break;
case CIFOP_TAGGED:
if (argc != 3) goto wrongNumArgs;
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
CIFParseReadLayers(argv[2], &newOp->co_cifMask, TRUE);
break;
}
/* Link the new CIFOp onto the list. */
@ -1099,6 +1119,7 @@ CIFReadTechFinal(void)
*
* ----------------------------------------------------------------------------
*/
void
CIFReadLoadStyle(
char *stylename)

View File

@ -166,9 +166,9 @@ CIFPaintLayer(
scx.scx_use = CIFDummyUse;
scx.scx_trans = GeoIdentityTransform;
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef);
cifHierCopyFunc, (ClientData) CIFComponentDef);
CIFCopyMaskHints(&scx, CIFComponentDef);
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFComponentDef);
oldCount = DBWFeedbackCount;
@ -287,9 +287,9 @@ CIFSeeLayer(
scx.scx_use = CIFDummyUse;
scx.scx_trans = GeoIdentityTransform;
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef);
cifHierCopyFunc, (ClientData) CIFComponentDef);
CIFCopyMaskHints(&scx, CIFComponentDef);
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFComponentDef);
oldCount = DBWFeedbackCount;
@ -459,9 +459,9 @@ CIFCoverageLayer(
scx.scx_use = CIFDummyUse;
scx.scx_trans = GeoIdentityTransform;
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef);
cifHierCopyFunc, (ClientData) CIFComponentDef);
CIFCopyMaskHints(&scx, CIFComponentDef);
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFComponentDef);
CIFGen(CIFComponentDef, rootDef, area, CIFPlanes, &depend, TRUE, TRUE,
@ -504,10 +504,10 @@ CIFCoverageLayer(
}
else
{
TxPrintf("%s Area = %lld CIF units^2\n", doBox ? "Cursor Box" :
TxPrintf("%s Area = %"DLONG_PREFIX"d CIF units^2\n", doBox ? "Cursor Box" :
"Cell", btotal);
TxPrintf("Layer Bounding Area = %lld CIF units^2\n", atotal);
TxPrintf("Layer Total Area = %lld CIF units^2\n", cstats.coverage);
TxPrintf("Layer Bounding Area = %"DLONG_PREFIX"d CIF units^2\n", atotal);
TxPrintf("Layer Total Area = %"DLONG_PREFIX"d CIF units^2\n", cstats.coverage);
TxPrintf("Coverage in %s = %1.1f%%\n", doBox ? "box" :
"cell", 100.0 * fcover);
}

View File

@ -1107,6 +1107,8 @@ CIFTechLine(
newOp->co_opcode = CIFOP_BBOX;
else if (strcmp(argv[0], "net") == 0)
newOp->co_opcode = CIFOP_NET;
else if (strcmp(argv[0], "tagged") == 0)
newOp->co_opcode = CIFOP_TAGGED;
else if (strcmp(argv[0], "maxrect") == 0)
newOp->co_opcode = CIFOP_MAXRECT;
else if (strcmp(argv[0], "boundary") == 0)
@ -1117,6 +1119,8 @@ CIFTechLine(
newOp->co_opcode = CIFOP_CLOSE;
else if (strcmp(argv[0], "orthogonal") == 0)
newOp->co_opcode = CIFOP_MANHATTAN;
else if (strcmp(argv[0], "not-square") == 0)
newOp->co_opcode = CIFOP_NOTSQUARE;
else if (strcmp(argv[0], "bridge") == 0)
newOp->co_opcode = CIFOP_BRIDGE;
else if (strcmp(argv[0], "bridge-lim") == 0)
@ -1355,6 +1359,7 @@ bloatCheck:
bloatDone: break;
case CIFOP_NET:
case CIFOP_TAGGED:
if (argc != 3) goto wrongNumArgs;
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
cifParseLayers(argv[2], CIFCurStyle, &newOp->co_paintMask,
@ -1669,12 +1674,12 @@ cifComputeRadii(
for (op = layer->cl_ops; op != NULL; op = op->co_next)
{
/* BBOX, NET, and MASKHINTS operators should never be used */
/* hierarchically so ignore any grow/shrink operators that */
/* BBOX, NET, TAGGED, and MASKHINTS operators should never be */
/* used hierarchically so ignore any grow/shrink operators that */
/* come after them. */
if (op->co_opcode == CIFOP_BBOX || op->co_opcode == CIFOP_NET ||
op->co_opcode == CIFOP_MASKHINTS)
op->co_opcode == CIFOP_TAGGED || op->co_opcode == CIFOP_MASKHINTS)
break;
/* If CIF layers are used, switch to the max of current
@ -1986,8 +1991,8 @@ CIFTechFinal(void)
/* Presence of op->co_opcode in CIFOP_OR indicates a copy */
/* of the SquaresData pointer from a following operator. */
/* CIFOP_BBOX and CIFOP_MAXRECT uses the co_client field */
/* as a flag field, while CIFOP_NET and CIFOP_MASKHINTS */
/* uses it for a string. */
/* as a flag field, while CIFOP_NET, CIFOP_MASKHINTS, and */
/* CIFOP_TAGGED use it for a string. */
else
{
switch (op->co_opcode)
@ -1999,6 +2004,7 @@ CIFTechFinal(void)
case CIFOP_MAXRECT:
case CIFOP_MANHATTAN:
case CIFOP_NET:
case CIFOP_TAGGED:
break;
case CIFOP_BRIDGELIM:
case CIFOP_BRIDGE:
@ -2534,6 +2540,7 @@ CIFTechOutputScale(
case CIFOP_MAXRECT:
case CIFOP_MANHATTAN:
case CIFOP_NET:
case CIFOP_TAGGED:
case CIFOP_INTERACT:
break;
case CIFOP_BRIDGELIM:
@ -2649,8 +2656,8 @@ CIFTechOutputScale(
default:
/* op->co_opcode in CIFOP_OR is a pointer copy, */
/* in CIFOP_BBOX and CIFOP_MAXRECT is a flag, */
/* and in CIFOP_NET and CIFOP_MASKHINTS is a */
/* string. */
/* and in CIFOP_NET, CIFOP_MASKHINTS, and */
/* CIFOP_TAGGED is a string. */
break;
}
}

View File

@ -338,14 +338,17 @@ CmdArray(
case ARRAY_WIDTH:
if (locargc == 2)
{
char *xsepvalue;
for (la = lahead; la != NULL; la = la->ar_next)
{
xsepvalue = DBWPrintValue(la->arrayInfo.ar_xsep,
w, TRUE);
#ifdef MAGIC_WRAPPER
if (doList)
{
tobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewIntObj(la->arrayInfo.ar_xsep));
Tcl_NewStringObj(xsepvalue, -1));
Tcl_SetObjResult(magicinterp, tobj);
}
else
@ -355,7 +358,7 @@ CmdArray(
TxPrintf("Cell use \"%s\":", la->cellUse->cu_id);
else
TxPrintf("Cell \"%s\":", la->cellUse->cu_def->cd_name);
TxPrintf("x separation %d\n", la->arrayInfo.ar_xsep);
TxPrintf("x separation %s\n", xsepvalue);
#ifdef MAGIC_WRAPPER
}
#endif
@ -374,14 +377,17 @@ CmdArray(
case ARRAY_HEIGHT:
if (locargc == 2)
{
char *ysepvalue;
for (la = lahead; la != NULL; la = la->ar_next)
{
ysepvalue = DBWPrintValue(la->arrayInfo.ar_ysep,
w, FALSE);
#ifdef MAGIC_WRAPPER
if (doList)
{
tobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewIntObj(la->arrayInfo.ar_ysep));
Tcl_NewStringObj(ysepvalue, -1));
Tcl_SetObjResult(magicinterp, tobj);
}
else
@ -391,7 +397,7 @@ CmdArray(
TxPrintf("Cell use \"%s\":", la->cellUse->cu_id);
else
TxPrintf("Cell \"%s\":", la->cellUse->cu_def->cd_name);
TxPrintf("y separation %d\n", la->arrayInfo.ar_ysep);
TxPrintf("y separation %s\n", ysepvalue);
#ifdef MAGIC_WRAPPER
}
#endif
@ -410,16 +416,21 @@ CmdArray(
case ARRAY_PITCH:
if (locargc == 2)
{
char *xpitch, *ypitch;
for (la = lahead; la != NULL; la = la->ar_next)
{
xpitch = DBWPrintValue(la->arrayInfo.ar_xsep,
w, TRUE);
ypitch = DBWPrintValue(la->arrayInfo.ar_ysep,
w, FALSE);
#ifdef MAGIC_WRAPPER
if (doList)
{
tobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewIntObj(la->arrayInfo.ar_xsep));
Tcl_NewStringObj(xpitch, -1));
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewIntObj(la->arrayInfo.ar_ysep));
Tcl_NewStringObj(ypitch, -1));
Tcl_SetObjResult(magicinterp, tobj);
}
else
@ -429,8 +440,8 @@ CmdArray(
TxPrintf("Cell use \"%s\":", la->cellUse->cu_id);
else
TxPrintf("Cell \"%s\":", la->cellUse->cu_def->cd_name);
TxPrintf("x separation %d ", la->arrayInfo.ar_xsep);
TxPrintf("y separation %d\n", la->arrayInfo.ar_ysep);
TxPrintf("x separation %s ", xpitch);
TxPrintf("y separation %s\n", ypitch);
#ifdef MAGIC_WRAPPER
}
#endif
@ -450,16 +461,21 @@ CmdArray(
case ARRAY_POSITION:
if (locargc == 2)
{
char *xpos, *ypos;
for (la = lahead; la != NULL; la = la->ar_next)
{
xpos = DBWPrintValue(la->cellUse->cu_bbox.r_xbot,
w, TRUE);
ypos = DBWPrintValue(la->cellUse->cu_bbox.r_ybot,
w, FALSE);
#ifdef MAGIC_WRAPPER
if (doList)
{
tobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewIntObj(la->cellUse->cu_bbox.r_xbot));
Tcl_NewStringObj(xpos, -1));
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewIntObj(la->cellUse->cu_bbox.r_ybot));
Tcl_NewStringObj(ypos, -1));
Tcl_SetObjResult(magicinterp, tobj);
}
else
@ -469,8 +485,8 @@ CmdArray(
TxPrintf("Cell use \"%s\":", la->cellUse->cu_id);
else
TxPrintf("Cell \"%s\":", la->cellUse->cu_def->cd_name);
TxPrintf("x=%d ", la->cellUse->cu_bbox.r_xbot);
TxPrintf("y=%d\n", la->cellUse->cu_bbox.r_ybot);
TxPrintf("x=%s ", xpos);
TxPrintf("y=%s\n", ypos);
#ifdef MAGIC_WRAPPER
}
#endif
@ -763,8 +779,8 @@ CmdBox(
break;
case BOX_EXISTS:
#ifdef MAGIC_WRAPPER
Tcl_SetResult(magicinterp, ToolGetBox(NULL, NULL) ? "1" : "0",
NULL);
Tcl_SetObjResult(magicinterp,
Tcl_NewBooleanObj(ToolGetBox(NULL, NULL) ? TRUE : FALSE));
#else
TxPrintf("%s\n", ToolGetBox(NULL, NULL) ? "True" : "False");
#endif
@ -874,13 +890,16 @@ CmdBox(
TxRebuildCommand(cmd);
return;
}
else if (DBWSnapToGrid != DBW_SNAP_USER)
else if (DBWUnits != DBW_UNITS_USER)
{
distancex = cmdParseCoord(w, cmd->tx_argv[3], TRUE, FALSE);
distancey = distancex;
}
else
{
/* For user units, the distance may be different in the X and Y
* directions for a given value.
*/
switch (direction)
{
case GEO_EAST: case GEO_WEST:
@ -908,15 +927,14 @@ CmdBox(
case BOX_WIDTH:
if (argc == 2)
{
char *boxvalues;
boxvalues = DBWPrintValue(boxptr->r_xtop - boxptr->r_xbot,
w, TRUE);
#ifdef MAGIC_WRAPPER
char *boxvalues = (char *)Tcl_Alloc(50);
sprintf(boxvalues, "%d",
boxptr->r_xtop - boxptr->r_xbot);
Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC);
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(boxvalues, -1));
#else
TxPrintf("%s box width is %d\n",
(refEdit) ? "Edit" : "Root",
boxptr->r_xtop - boxptr->r_xbot);
TxPrintf("%s box width is %s\n", (refEdit) ? "Edit" : "Root",
boxvalues);
#endif
return;
}
@ -928,15 +946,14 @@ CmdBox(
case BOX_HEIGHT:
if (argc == 2)
{
char *boxvalues;
boxvalues = DBWPrintValue(boxptr->r_ytop - boxptr->r_ybot,
w, FALSE);
#ifdef MAGIC_WRAPPER
char *boxvalues = (char *)Tcl_Alloc(50);
sprintf(boxvalues, "%d",
boxptr->r_ytop - boxptr->r_ybot);
Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC);
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(boxvalues, -1));
#else
TxPrintf("%s box height is %d\n",
(refEdit) ? "Edit" : "Root",
boxptr->r_ytop - boxptr->r_ybot);
TxPrintf("%s box height is %s\n", (refEdit) ? "Edit" : "Root",
boxvalues);
#endif
return;
}
@ -949,16 +966,24 @@ CmdBox(
if (argc == 2)
{
#ifdef MAGIC_WRAPPER
char *boxvalues = (char *)Tcl_Alloc(50);
sprintf(boxvalues, "%d %d",
boxptr->r_xtop - boxptr->r_xbot,
boxptr->r_ytop - boxptr->r_ybot);
Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC);
Tcl_Obj *tobj;
#endif
char *boxvaluex, *boxvaluey;
boxvaluex = DBWPrintValue(boxptr->r_xtop - boxptr->r_xbot,
w, TRUE);
boxvaluey = DBWPrintValue(boxptr->r_ytop - boxptr->r_ybot,
w, FALSE);
#ifdef MAGIC_WRAPPER
tobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(boxvaluex, -1));
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(boxvaluey, -1));
Tcl_SetObjResult(magicinterp, tobj);
#else
TxPrintf("%s box size is %d x %d\n",
TxPrintf("%s box size is %s x %s\n",
(refEdit) ? "Edit" : "Root",
boxptr->r_xtop - boxptr->r_xbot,
boxptr->r_ytop - boxptr->r_ybot);
boxvaluex, boxvaluey);
#endif
return;
}
@ -973,14 +998,22 @@ CmdBox(
if (argc == 2)
{
#ifdef MAGIC_WRAPPER
char *boxvalues = (char *)Tcl_Alloc(50);
sprintf(boxvalues, "%d %d",
boxptr->r_xbot, boxptr->r_ybot);
Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC);
Tcl_Obj *tobj;
#endif
char *boxvaluex, *boxvaluey;
boxvaluex = DBWPrintValue(boxptr->r_xbot, w, TRUE);
boxvaluey = DBWPrintValue(boxptr->r_ybot, w, FALSE);
#ifdef MAGIC_WRAPPER
tobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(boxvaluex, -1));
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(boxvaluey, -1));
Tcl_SetObjResult(magicinterp, tobj);
#else
TxPrintf("%s box lower-left corner at (%d, %d)\n",
TxPrintf("%s box lower-left corner at (%s, %s)\n",
(refEdit) ? "Edit" : "Root",
boxptr->r_xbot, boxptr->r_ybot);
boxvaluex, boxvaluey);
#endif
return;
}
@ -1012,16 +1045,31 @@ CmdBox(
if (argc == 2)
{
#ifdef MAGIC_WRAPPER
char *boxvalues = (char *)Tcl_Alloc(50);
sprintf(boxvalues, "%d %d %d %d",
boxptr->r_xbot, boxptr->r_ybot,
boxptr->r_xtop, boxptr->r_ytop);
Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC);
Tcl_Obj *tobj;
#endif
char *boxvaluellx, *boxvaluelly;
char *boxvalueurx, *boxvalueury;
boxvaluellx = DBWPrintValue(boxptr->r_xbot, w, TRUE);
boxvaluelly = DBWPrintValue(boxptr->r_ybot, w, FALSE);
boxvalueurx = DBWPrintValue(boxptr->r_xtop, w, TRUE);
boxvalueury = DBWPrintValue(boxptr->r_ytop, w, FALSE);
#ifdef MAGIC_WRAPPER
tobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(boxvaluellx, -1));
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(boxvaluelly, -1));
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(boxvalueurx, -1));
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(boxvalueury, -1));
Tcl_SetObjResult(magicinterp, tobj);
#else
TxPrintf("%s box coordinates (%d, %d) to (%d, %d)\n",
TxPrintf("%s box coordinates (%s, %s) to (%s, %s)\n",
(refEdit) ? "Edit" : "Root",
boxptr->r_xbot, boxptr->r_ybot,
boxptr->r_xtop, boxptr->r_ytop);
boxvaluellx, boxvaluelly, boxvalueurx, boxvalueury);
#endif
return;
}

View File

@ -117,12 +117,13 @@ bool cmdDumpParseArgs(char *cmdName, MagWindow *w, TxCommand *cmd, CellUse *dumm
#define CALMA_READ 19
#define CALMA_READONLY 20
#define CALMA_RESCALE 21
#define CALMA_WARNING 22
#define CALMA_WRITE 23
#define CALMA_POLYS 24
#define CALMA_PATHS 25
#define CALMA_UNDEFINED 26
#define CALMA_UNIQUE 27
#define CALMA_SAVEPATHS 22
#define CALMA_WARNING 23
#define CALMA_WRITE 24
#define CALMA_POLYS 25
#define CALMA_PATHS 26
#define CALMA_UNDEFINED 27
#define CALMA_UNIQUE 28
#define CALMA_WARN_HELP CIF_WARN_END /* undefined by CIF module */
@ -175,6 +176,7 @@ CmdCalma(
" into edit cell",
"readonly [yes|no] set cell as read-only and generate output from GDS file",
"rescale [yes|no] allow or disallow internal grid subdivision",
"savepaths [yes|no] save path centerlines as cell properties",
"warning [option] set warning information level",
"write file output Calma GDS-II format to \"file\"\n"
" for the window's root cell",
@ -738,6 +740,27 @@ CmdCalma(
CalmaSubcellPolygons = (unsigned char)option;
return;
case CALMA_SAVEPATHS:
if (cmd->tx_argc == 2)
{
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(CalmaRecordPaths));
#else
TxPrintf("Paths in GDS cells read from input file are%s recorded"
" as cell properties.\n",
(CalmaRecordPaths) ? " " : " not");
#endif
return;
}
else if (cmd->tx_argc != 3)
goto wrongNumArgs;
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
if (option < 0)
goto wrongNumArgs;
CalmaRecordPaths = (option < 4) ? FALSE : TRUE;
return;
case CALMA_NO_DUP:
if (cmd->tx_argc == 2)
{
@ -1300,7 +1323,7 @@ CmdCellname(
if (cellDef == (CellDef *) NULL)
TxError("Unknown cell %s\n", cellname);
else
CmdDoProperty(cellDef, cmd, 3 + ((dolist) ? 1 : 0));
CmdDoProperty(cellDef, w, cmd, 3 + ((dolist) ? 1 : 0));
break;
case IDX_DELETE:
@ -4991,15 +5014,20 @@ cmdDumpParseArgs(
bbox = def->cd_bbox;
if (def->cd_flags & CDFIXEDBBOX)
{
char *propvalue;
PropertyRecord *proprec;
bool found;
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &found);
proprec = DBPropGet(def, "FIXED_BBOX", &found);
if (found)
{
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) != 4)
bbox = def->cd_bbox;
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
}
}
}

View File

@ -925,11 +925,14 @@ cmdExpandFunc(
#define DOALL 1
#define DOCAPACITANCE 2
#define DOCOUPLING 3
#define DOLENGTH 4
#define DOLOCAL 5
#define DORESISTANCE 6
#define DOLABELCHECK 7
#define DOALIASES 8
#define DOEXTRESIST 4
#define DOLENGTH 5
#define DOLOCAL 6
#define DORESISTANCE 7
#define DOLABELCHECK 8
#define DOALIASES 9
#define DOUNIQUE 10
#define DOEXTRESIST2 11
#define LENCLEAR 0
#define LENDRIVER 1
@ -972,11 +975,14 @@ CmdExtract(
"all all options",
"capacitance extract substrate capacitance",
"coupling extract coupling capacitance",
"extresist extract resistance",
"length compute driver-receiver pathlengths",
"local put all generated files in the current directory",
"resistance estimate resistance",
"lumped estimate lumped resistance",
"labelcheck check for connections through sticky labels",
"aliases output all net name aliases",
"unique ensure unique node names during extraction",
"resistance extract resistance (same as \"do extresist\")",
NULL
};
static const char * const cmdExtLength[] =
@ -1120,12 +1126,13 @@ CmdExtract(
}
else if (argc == 2)
{
char *halodisp;
halodisp = DBWPrintValue(ExtCurStyle->exts_sideCoupleHalo,
w, TRUE);
#ifdef MAGIC_WRAPPER
Tcl_Obj *tobj;
tobj = Tcl_NewIntObj(ExtCurStyle->exts_sideCoupleHalo);
Tcl_SetObjResult(magicinterp, tobj);
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(halodisp, -1));
#else
TxPrintf("Side overlap halo is %d\n", ExtCurStyle->exts_sideCoupleHalo);
TxPrintf("Side overlap halo is %s\n", halodisp);
#endif
return;
}
@ -1150,12 +1157,12 @@ CmdExtract(
}
else if (argc == 2)
{
char *stepdisp;
stepdisp = DBWPrintValue(ExtCurStyle->exts_stepSize, w, TRUE);
#ifdef MAGIC_WRAPPER
Tcl_Obj *tobj;
tobj = Tcl_NewIntObj(ExtCurStyle->exts_stepSize);
Tcl_SetObjResult(magicinterp, tobj);
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(stepdisp, -1));
#else
TxPrintf("Extraction step size is %d\n", ExtCurStyle->exts_stepSize);
TxPrintf("Extraction step size is %s\n", stepdisp);
#endif
return;
}
@ -1277,9 +1284,11 @@ CmdExtract(
TxPrintf("%s capacitance\n", OPTSET(EXT_DOCAPACITANCE));
TxPrintf("%s coupling\n", OPTSET(EXT_DOCOUPLING));
TxPrintf("%s length\n", OPTSET(EXT_DOLENGTH));
TxPrintf("%s resistance\n", OPTSET(EXT_DORESISTANCE));
TxPrintf("%s lumped R\n", OPTSET(EXT_DORESISTANCE));
TxPrintf("%s label check\n", OPTSET(EXT_DOLABELCHECK));
TxPrintf("%s aliases\n", OPTSET(EXT_DOALIASES));
TxPrintf("%s unique\n", OPTSET(EXT_DOUNIQUE));
TxPrintf("%s resistance (extresist)\n", OPTSET(EXT_DOEXTRESIST));
return;
#undef OPTSET
}
@ -1309,6 +1318,9 @@ CmdExtract(
case DORESISTANCE: option = EXT_DORESISTANCE; break;
case DOLABELCHECK: option = EXT_DOLABELCHECK; break;
case DOALIASES: option = EXT_DOALIASES; break;
case DOUNIQUE: option = EXT_DOUNIQUE; break;
case DOEXTRESIST:
case DOEXTRESIST2: option = EXT_DOEXTRESIST; break;
case DOLOCAL:
/* "extract do local" and "extract no local" are kept for
* backwards compatibility, but now effectively implement

View File

@ -45,9 +45,8 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
#include "utils/undo.h"
#include "select/select.h"
#include "netmenu/netmenu.h"
/* C99 compat */
#include "cif/cif.h"
#include "cif/CIFint.h"
/* Forward declarations */
@ -2296,6 +2295,8 @@ parsepositions:
editDef->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
}
#define PROPERTY_TYPE_COMPAT 4 /* Last entry in cmdPropertyType */
/*
* ----------------------------------------------------------------------------
*
@ -2319,47 +2320,449 @@ parsepositions:
void
CmdDoProperty(
CellDef *def,
MagWindow *w,
TxCommand *cmd,
int argstart)
{
int printPropertiesFunc();
PropertyRecord *proprec;
char *value;
bool propfound;
bool propfound, dolist;
int proptype, proplen, propvalue, i;
dlong dvalue;
int locargc = cmd->tx_argc - argstart + 1;
#ifdef MAGIC_WRAPPER
Tcl_Obj *tobj;
#endif
/* Forward declarations */
int printPropertiesFunc();
int printPlanePropFunc();
/* These should match the property codes in database.h.in, except
* for "compat" which must come at the end.
*/
static const char * const cmdPropertyType[] = {
"string", "integer", "dimension", "double", "plane", "compat", NULL
};
/* If the first keyword is "list", then set dolist and increment
* the starting argument position.
*/
dolist = FALSE;
if (locargc > 1)
{
if (!strcmp(cmd->tx_argv[argstart], "list"))
{
dolist = TRUE;
locargc--;
argstart++;
}
}
/* If a property type is given, parse it and then strip it from
* the arguments list.
*/
if (locargc > 1)
{
proptype = Lookup(cmd->tx_argv[argstart], cmdPropertyType);
if (proptype >= 0)
{
if (proptype != PROPERTY_TYPE_COMPAT)
{
locargc--;
argstart++;
}
}
else
proptype = PROPERTY_TYPE_STRING; /* default */
}
else
proptype = PROPERTY_TYPE_STRING; /* default */
if (locargc == 1)
{
#ifdef MAGIC_WRAPPER
Tcl_Obj *tobj;
/* Create an empty list for the interpreter result; the
* printPropertiesFunc() function will append values to it.
*/
tobj = Tcl_NewListObj(0, NULL);
Tcl_SetObjResult(magicinterp, tobj);
#endif
/* print all properties and their values */
DBPropEnum(def, printPropertiesFunc, NULL);
DBPropEnum(def, printPropertiesFunc, (ClientData)w);
}
else if (locargc == 2)
{
/* print the value of the indicated property */
value = (char *)DBPropGet(def, cmd->tx_argv[argstart], &propfound);
if (propfound)
/* If the property type was "compat", then give the state of the
* compatibility flag and return.
*/
if (proptype == PROPERTY_TYPE_COMPAT)
{
#ifdef MAGIC_WRAPPER
Tcl_SetResult(magicinterp, value, NULL);
Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(DBPropCompat));
#else
TxPrintf("%s", value);
TxPrintf("%s\n", (DBPropCompat == TRUE) ? "True" : "False");
#endif
return;
}
/* Print the value of the indicated property */
proprec = (PropertyRecord *)DBPropGet(def, cmd->tx_argv[argstart], &propfound);
if (propfound)
{
proptype = proprec->prop_type;
#ifdef MAGIC_WRAPPER
switch (proptype)
{
case PROPERTY_TYPE_STRING:
Tcl_SetResult(magicinterp, proprec->prop_value.prop_string, NULL);
break;
case PROPERTY_TYPE_INTEGER:
if (proprec->prop_len == 1)
Tcl_SetObjResult(magicinterp,
Tcl_NewIntObj(proprec->prop_value.prop_integer[0]));
else
{
tobj = Tcl_NewListObj(0, NULL);
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewIntObj(
proprec->prop_value.prop_integer[i]));
Tcl_SetObjResult(magicinterp, tobj);
}
break;
case PROPERTY_TYPE_DIMENSION:
if (proprec->prop_len == 1)
Tcl_SetResult(magicinterp,
DBWPrintValue(proprec->prop_value.prop_integer[0],
w, TRUE), NULL);
else
{
tobj = Tcl_NewListObj(0, NULL);
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(DBWPrintValue(
proprec->prop_value.prop_integer[i], w,
((i % 2) == 0) ? TRUE : FALSE), -1));
Tcl_SetObjResult(magicinterp, tobj);
}
break;
case PROPERTY_TYPE_PLANE:
tobj = Tcl_NewListObj(0, NULL);
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
proprec->prop_value.prop_plane,
&TiPlaneRect, &CIFSolidBits, printPlanePropFunc,
(ClientData)tobj);
Tcl_SetObjResult(magicinterp, tobj);
break;
case PROPERTY_TYPE_DOUBLE:
if (proprec->prop_len == 1)
Tcl_SetObjResult(magicinterp,
Tcl_NewWideIntObj((Tcl_WideInt)
proprec->prop_value.prop_double[0]));
else
{
tobj = Tcl_NewListObj(0, NULL);
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewWideIntObj((Tcl_WideInt)
proprec->prop_value.prop_double[i]));
Tcl_SetObjResult(magicinterp, tobj);
}
break;
}
#else
switch (proptype)
{
case PROPERTY_TYPE_STRING:
TxPrintf("%s\n", proprec->prop_value.prop_string);
break;
case PROPERTY_TYPE_INTEGER:
for (i = 0; i < proprec->prop_len; i++)
TxPrintf("%d ", proprec->prop_value.prop_integer[i]);
TxPrintf("\n");
break;
case PROPERTY_TYPE_DIMENSION:
for (i = 0; i < proprec->prop_len; i++)
TxPrintf("%s ", DBWPrintValue(
proprec->prop_value.prop_integer[i], w,
((i % 2) == 0) ? TRUE : FALSE);
TxPrintf("\n");
break;
case PROPERTY_TYPE_PLANE:
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
proprec->prop_value.prop_plane,
&TiPlaneRect, &CIFSolidBits, printPlanePropFunc,
(ClientData)NULL);
TxPrintf("\n");
break;
case PROPERTY_TYPE_DOUBLE:
for (i = 0; i < proprec->prop_len; i++)
TxPrintf( "%"DLONG_PREFIX"d",
proprec->prop_value.prop_double[i]);
TxPrintf("\n");
break;
}
#endif
}
else {
#ifdef MAGIC_WRAPPER
/* If the command was "cellname list property ...", then */
/* just return NULL if the property was not found. */
if (strcmp(cmd->tx_argv[1], "list"))
if (!dolist)
#endif
TxError("Property name \"%s\" is not defined\n", cmd->tx_argv[1]);
TxError("Property name \"%s\" is not defined\n", cmd->tx_argv[argstart]);
}
}
else if (locargc == 3)
else if (locargc >= 3)
{
/* If the property type was "compat", then set the state of the
* compatibility flag and return.
*/
if (proptype == PROPERTY_TYPE_COMPAT)
{
int idx;
static const char * const cmdPropYesNo[] = {
"disable", "no", "false", "off", "0",
"enable", "yes", "true", "on", "1", 0 };
idx = Lookup(cmd->tx_argv[2], cmdPropYesNo);
if (idx < 0)
{
TxError("Unknown property compat option \"%s\"\n", cmd->tx_argv[2]);
return;
}
DBPropCompat = (idx <= 4) ? FALSE : TRUE;
return;
}
/* Catch the following known reserved keywords and cast them to the
* expected property type. If any property type was already given
* to the command, it is overridden. This ensures that the reserved
* keyword functions work correctly.
*
* GDS_START, GDS_END: PROPERTY_TYPE_DOUBLE
* MASKHINTS_*: PROPERTY_TYPE_PLANE
* FIXED_BBOX: PROPERTY_TYPE_DIMENSION
*/
if (!strcmp(cmd->tx_argv[argstart], "GDS_START"))
proptype = PROPERTY_TYPE_DOUBLE;
else if (!strcmp(cmd->tx_argv[argstart], "GDS_END"))
proptype = PROPERTY_TYPE_DOUBLE;
else if (!strcmp(cmd->tx_argv[argstart], "GDS_FILE"))
proptype = PROPERTY_TYPE_STRING;
else if (!strcmp(cmd->tx_argv[argstart], "FIXED_BBOX"))
proptype = PROPERTY_TYPE_DIMENSION;
else if (!strcmp(cmd->tx_argv[argstart], "OBS_BBOX"))
proptype = PROPERTY_TYPE_DIMENSION;
else if (!strncmp(cmd->tx_argv[argstart], "MASKHINTS_", 10))
proptype = PROPERTY_TYPE_PLANE;
if (strlen(cmd->tx_argv[argstart + 1]) == 0)
DBPropPut(def, cmd->tx_argv[argstart], NULL);
else
{
value = StrDup((char **)NULL, cmd->tx_argv[argstart + 1]);
DBPropPut(def, cmd->tx_argv[argstart], value);
if (proptype == PROPERTY_TYPE_STRING)
{
proplen = strlen(cmd->tx_argv[argstart + 1]);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) -
7 + proplen);
proprec->prop_type = proptype;
proprec->prop_len = proplen;
strcpy(proprec->prop_value.prop_string, cmd->tx_argv[argstart + 1]);
}
else /* All non-string properties */
{
Plane *plane;
Rect r;
/* Two choices: If locargc == 3 then all values are in one
* argument. If locargc > 3, then parse each argument as a
* separate value.
*/
if (locargc > 3)
{
proplen = locargc - 2;
if (proptype == PROPERTY_TYPE_DOUBLE)
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(proplen - 1)*sizeof(dlong));
else if (proptype == PROPERTY_TYPE_PLANE)
{
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
plane = DBNewPlane((ClientData)TT_SPACE);
proprec->prop_value.prop_plane = plane;
}
else
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(proplen - 2)*sizeof(int));
proprec->prop_type = proptype;
proprec->prop_len = proplen;
for (i = 1; i < locargc - 1; i++)
{
if (proptype == PROPERTY_TYPE_INTEGER)
{
if (sscanf(cmd->tx_argv[argstart + i], "%d",
&propvalue) == 1)
proprec->prop_value.prop_integer[i - 1] = propvalue;
else
{
TxError("Unable to parse value \"%s\" as an integer\n",
cmd->tx_argv[argstart + i]);
proprec->prop_value.prop_integer[i - 1] = 0;
}
}
else if (proptype == PROPERTY_TYPE_DOUBLE)
{
if (sscanf(cmd->tx_argv[argstart + i], "%"DLONG_PREFIX"d",
&dvalue) == 1)
proprec->prop_value.prop_double[i - 1] = dvalue;
else
{
TxError("Unable to parse value \"%s\" as an integer\n",
cmd->tx_argv[argstart + i]);
proprec->prop_value.prop_double[i - 1] = 0;
}
}
else if (proptype == PROPERTY_TYPE_PLANE)
{
propvalue = cmdParseCoord(w, cmd->tx_argv[argstart + i],
FALSE, ((i % 2) == 0) ? FALSE : TRUE);
switch ((i - 1) % 4)
{
case 0:
r.r_xbot = propvalue;
break;
case 1:
r.r_ybot = propvalue;
break;
case 2:
r.r_xtop = propvalue;
break;
case 3:
r.r_ytop = propvalue;
DBPaintPlane(plane, &r, CIFPaintTable,
(PaintUndoInfo *)NULL);
break;
}
}
else /* PROPERTY_TYPE_DIMENSION */
{
propvalue = cmdParseCoord(w, cmd->tx_argv[argstart + i],
FALSE, ((i % 2) == 0) ? FALSE : TRUE);
proprec->prop_value.prop_integer[i - 1] = propvalue;
}
}
}
else
{
/* Make two passes through the argument string, once to get
* the valid number of arguments, then again to parse the
* values, once the property record has been allocated
*/
if (proptype == PROPERTY_TYPE_PLANE)
{
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
plane = DBNewPlane((ClientData)TT_SPACE);
proprec->prop_value.prop_plane = plane;
}
else
{
value = cmd->tx_argv[argstart + 1];
for (proplen = 0; *value != '\0'; )
{
if (isspace(*value) && (*value != '\0')) value++;
if (!isspace(*value))
{
proplen++;
while (!isspace(*value) && (*value != '\0')) value++;
}
}
if (proplen > 0)
{
proprec = (PropertyRecord *)mallocMagic(
sizeof(PropertyRecord) +
(proplen - 2) * sizeof(int));
proprec->prop_type = proptype;
proprec->prop_len = proplen;
}
}
/* Second pass */
value = cmd->tx_argv[argstart + 1];
for (proplen = 0; proplen < proprec->prop_len; proplen++)
{
if (isspace(*value) && (*value != '\0')) value++;
if (!isspace(*value))
{
char *spptr, spchar;
/* cmdParseCoord() can only handle one value at a
* time, so look ahead and null out the next space
* character if there is one.
*/
spptr = value + 1;
while (!isspace(*spptr) && (*spptr != '\0')) spptr++;
spchar = *spptr;
*spptr = '\0';
if (proptype == PROPERTY_TYPE_INTEGER)
{
if (sscanf(value, "%d", &propvalue) != 1)
{
TxError("Unable to parse integer "
"value from \"%s\"\n",
value);
propvalue = 0;
}
proprec->prop_value.prop_integer[proplen] = propvalue;
}
else if (proptype == PROPERTY_TYPE_DOUBLE)
{
if (sscanf(value, "%"DLONG_PREFIX"d", &dvalue) != 1)
{
TxError("Unable to parse integer "
"value from \"%s\"\n",
value);
propvalue = 0;
}
proprec->prop_value.prop_double[proplen] = dvalue;
}
else if (proptype == PROPERTY_TYPE_PLANE)
{
propvalue = cmdParseCoord(w, value, FALSE,
((proplen % 2) == 0) ? TRUE : FALSE);
switch (proplen % 4)
{
case 0:
r.r_xbot = propvalue;
break;
case 1:
r.r_ybot = propvalue;
break;
case 2:
r.r_xtop = propvalue;
break;
case 3:
r.r_ytop = propvalue;
DBPaintPlane(plane, &r, CIFPaintTable,
(PaintUndoInfo *)NULL);
break;
}
}
else /* PROPERTY_TYPE_DIMENSION */
{
propvalue = cmdParseCoord(w, value, FALSE,
((proplen % 2) == 0) ? TRUE : FALSE);
proprec->prop_value.prop_integer[proplen] = propvalue;
}
*spptr = spchar;
while (!isspace(*value) && (*value != '\0')) value++;
}
}
}
}
DBPropPut(def, cmd->tx_argv[argstart], proprec);
}
def->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
}
@ -2380,10 +2783,14 @@ CmdDoProperty(
* defined in database/DBprop.c.
*
* Usage:
* property [name] [value]
* property [string|integer|dimension] [name] [value]
*
* "name" is a unique string tag for the property, and "value" is its
* string value.
* If the first argument is present, it must be one of the known
* keywords, and determines the form in which "value" is interpreted and
* stored. "name" is a unique string tag for the property. "value" is
* the value of the property, which is either a string, integer, or a
* list of integers. The difference between an "integer" and a "dimension"
* is that all values which are dimensions are scaled with internal units.
*
* Results:
* None.
@ -2410,9 +2817,62 @@ CmdProperty(
else
def = ((CellUse *) w->w_surfaceID)->cu_def;
CmdDoProperty(def, cmd, 1);
CmdDoProperty(def, w, cmd, 1);
}
/*
* ----------------------------------------------------------------------------
* Callback function for printing values from a Plane property
* ----------------------------------------------------------------------------
*/
#ifdef MAGIC_WRAPPER
int
printPlanePropFunc(
Tile *tile,
TileType dinfo,
Tcl_Obj *lobj)
{
Rect r;
MagWindow *w;
TiToRect(tile, &r);
windCheckOnlyWindow(&w, DBWclientID);
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(DBWPrintValue(r.r_xbot, w, TRUE), -1));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(DBWPrintValue(r.r_ybot, w, FALSE), -1));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(DBWPrintValue(r.r_xtop, w, TRUE), -1));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(DBWPrintValue(r.r_ytop, w, FALSE), -1));
return 0;
}
#else
int
printPlanePropFunc(
Tile *tile,
TileType dinfo,
ClientData cdata /* (unused) */
{
Rect r;
MagWindow *w;
TiToRect(tile, &r)
windCheckOnlyWindow(&w, DBWclientID);
TxPrintf("%s ", DBWPrintValue(r.r_xbot, w, TRUE);
TxPrintf("%s ", DBWPrintValue(r.r_ybot, w, FALSE);
TxPrintf("%s ", DBWPrintValue(r.r_xtop, w, TRUE);
TxPrintf("%s ", DBWPrintValue(r.r_ytop, w, FALSE);
return 0;
}
#endif
/*
* ----------------------------------------------------------------------------
* Callback function for printing a single property key:value pair
@ -2422,27 +2882,84 @@ CmdProperty(
int
printPropertiesFunc(
const char *name,
ClientData value,
ClientData cdata) /* not used */
PropertyRecord *proprec,
MagWindow *w)
{
#ifdef MAGIC_WRAPPER
char *keyvalue;
int i;
if (value == NULL)
#ifdef MAGIC_WRAPPER
Tcl_Obj *tobj, *lobj;
tobj = Tcl_GetObjResult(magicinterp);
lobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_NewStringObj(name, -1));
switch (proprec->prop_type)
{
keyvalue = (char *)mallocMagic(strlen(name) + 4);
sprintf(keyvalue, "%s {}", name);
case PROPERTY_TYPE_STRING:
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(proprec->prop_value.prop_string, -1));
break;
case PROPERTY_TYPE_INTEGER:
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(proprec->prop_value.prop_integer[i]));
break;
case PROPERTY_TYPE_DIMENSION:
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(
DBWPrintValue(proprec->prop_value.prop_integer[i],
w, ((i % 2) == 0) ? TRUE : FALSE), -1));
break;
case PROPERTY_TYPE_PLANE:
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
proprec->prop_value.prop_plane,
&TiPlaneRect, &CIFSolidBits, printPlanePropFunc,
(ClientData)lobj);
break;
case PROPERTY_TYPE_DOUBLE:
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewWideIntObj(proprec->prop_value.prop_double[i]));
break;
}
else
{
keyvalue = (char *)mallocMagic(strlen(name) + strlen((const char *)value) + 2);
sprintf(keyvalue, "%s %s", name, (const char *)value);
}
Tcl_AppendElement(magicinterp, keyvalue);
freeMagic(keyvalue);
Tcl_ListObjAppendElement(magicinterp, tobj, lobj);
Tcl_SetObjResult(magicinterp, tobj);
#else
TxPrintf("%s = %s\n", name, (const char *)value);
switch (proprec->prop_type)
{
case PROPERTY_TYPE_STRING:
TxPrintf("%s = %s\n", name, (const char *)proprec->prop_string);
break;
case PROPERTY_TYPE_INTEGER:
TxPrintf("%s = ", name);
for (i = 0; i < proprec->prop_len; i++)
TxPrintf("%d ", proprec->prop_integer[i]);
TxPrintf("\n");
break;
case PROPERTY_TYPE_DIMENSION:
TxPrintf("%s = ", name);
for (i = 0; i < proprec->prop_len; i++)
TxPrintf("%s ", DBWPrintValue(proprec->prop_value.prop_integer[i],
w, ((i % 2) == 0) ? TRUE : FALSE);
TxPrintf("\n");
break;
case PROPERTY_TYPE_PLANE:
TxPrintf("%s = ", name);
DBSrPaintArea((Tile *)NULL, proprec->prop_value.prop_plane,
&TiPlaneRect, &CIFSolidBits, printPlanePropFunc,
(ClientData)NULL);
TxPrintf("\n");
break;
case PROPERTY_TYPE_DOUBLE:
TxPrintf("%s = ", name);
for (i = 0; i < proprec->prop_len; i++)
TxPrintf("%"DLONG_PREFIX"d ", proprec->prop_double[i]);
TxPrintf("\n");
break;
}
#endif
return 0; /* keep the search alive */

View File

@ -1084,25 +1084,33 @@ CmdSelect(
*/
case SEL_BBOX:
{
char *selllx, *sellly, *selurx, *selury;
GeoTransRect(&SelectUse->cu_transform, &SelectDef->cd_bbox, &selarea);
selllx = DBWPrintValue(selarea.r_xbot, w, TRUE);
sellly = DBWPrintValue(selarea.r_ybot, w, FALSE);
selurx = DBWPrintValue(selarea.r_xtop, w, TRUE);
selury = DBWPrintValue(selarea.r_ytop, w, FALSE);
#ifdef MAGIC_WRAPPER
lobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(selarea.r_xbot));
Tcl_NewStringObj(selllx, -1));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(selarea.r_ybot));
Tcl_NewStringObj(sellly, -1));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(selarea.r_xtop));
Tcl_NewStringObj(selurx, -1));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(selarea.r_ytop));
Tcl_NewStringObj(selury, -1));
Tcl_SetObjResult(magicinterp, lobj);
#else
TxPrintf("Select bounding box: %d %d %d %d\n",
selarea.r_xbot, selarea.r_ybot,
selarea.r_xtop, selarea.r_ytop);
TxPrintf("Select bounding box: %s %s %s %s\n",
selllx, sellly, selurx, selury);
#endif
return;
}
/*--------------------------------------------------------------------
* Make a copy of the selection at its present loction but do not
@ -1985,23 +1993,25 @@ cmdLabelRectFunc(
if (rect == NULL)
{
char *labllx, *lablly, *laburx, *labury;
/* Note: Ideally, the MagWindow pointer should be passed to this function */
labllx = DBWPrintValue(label->lab_rect.r_xbot, (MagWindow *)NULL, TRUE);
lablly = DBWPrintValue(label->lab_rect.r_ybot, (MagWindow *)NULL, FALSE);
laburx = DBWPrintValue(label->lab_rect.r_xtop, (MagWindow *)NULL, TRUE);
labury = DBWPrintValue(label->lab_rect.r_ytop, (MagWindow *)NULL, FALSE);
#ifdef MAGIC_WRAPPER
lobj = Tcl_GetObjResult(magicinterp);
pobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
Tcl_ListObjAppendElement(magicinterp, pobj,
Tcl_NewIntObj((double)label->lab_rect.r_xbot));
Tcl_ListObjAppendElement(magicinterp, pobj,
Tcl_NewIntObj((double)label->lab_rect.r_ybot));
Tcl_ListObjAppendElement(magicinterp, pobj,
Tcl_NewIntObj((double)label->lab_rect.r_xtop));
Tcl_ListObjAppendElement(magicinterp, pobj,
Tcl_NewIntObj((double)label->lab_rect.r_ytop));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(labllx, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(lablly, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(laburx, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(labury, -1));
Tcl_SetObjResult(magicinterp, lobj);
#else
TxPrintf("%d %d %d %d\n",
label->lab_rect.r_xbot, label->lab_rect.r_ybot,
label->lab_rect.r_xtop, label->lab_rect.r_ytop);
TxPrintf("%s %s %s %s\n", labllx, lablly, laburx,labury);
#endif
}
else if (!GEO_SAMERECT(label->lab_rect, *rect))
@ -2317,11 +2327,13 @@ CmdSetLabel(
{
if (locargc == 2)
{
char *labsize;
labsize = DBWPrintValue(DefaultLabel->lab_size, w, FALSE);
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp,
Tcl_NewIntObj(DefaultLabel->lab_size));
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(labsize, -1));
#else
TxPrintf("%d\n", DefaultLabel->lab_size);
TxPrintf("%s\n", labsize);
#endif
}
else
@ -2360,16 +2372,20 @@ CmdSetLabel(
{
if (locargc == 2)
{
char *laboffx, *laboffy;
laboffx = DBWPrintValue(DefaultLabel->lab_offset.p_x, w,
TRUE);
laboffy = DBWPrintValue(DefaultLabel->lab_offset.p_y, w,
FALSE);
#ifdef MAGIC_WRAPPER
lobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(DefaultLabel->lab_offset.p_x));
Tcl_NewStringObj(laboffx, -1));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(DefaultLabel->lab_offset.p_y));
Tcl_NewStringObj(laboffy, -1));
Tcl_SetObjResult(magicinterp, lobj);
#else
TxPrintf("%d %d\n", DefaultLabel->lab_offset.p_x,
DefaultLabel->lab_offset.p_y);
TxPrintf("%s %s\n", laboffx, laboffy);
#endif
}
else
@ -2884,16 +2900,39 @@ CmdSnap(
TxPrintf("Usage: snap [internal | lambda | user]\n");
return;
}
/* Backwards compatibility: Use of "snap" to set units display and
* parsing has been deprecated as of February 2026. However, as this
* is rather disruptive to existing scripts which use "snap" to change
* the parsing of units, then the following measure is being taken
* (for now, anyway): If DBWUnits is set to DBW_UNITS_DEFAULT, then
* "snap internal" will set DBWUnits as well as DBWSnapToGrid. If
* DBWUnits is changed first (e.g., "units internal"), then "snap" will
* affect only the snap grid. The older usage will be accompanied by a
* warning message. Note that backwards compatibility is being kept
* only in the case of "snap internal", which was commonly used in
* scripts to make sure that all units were interpreted as internal
* units.
*/
if ((DBWUnits == DBW_UNITS_DEFAULT) && (n == SNAP_INTERNAL))
{
DBWUnits = DBW_UNITS_INTERNAL;
TxError("Warning: snap setting is also changing units. This usage "
"is deprecated\nand may be removed in the future. Use "
"\"units\" to change units, and\nchange units before "
"setting snap to keep this message from appearing.\n");
}
switch (n)
{
case SNAP_OFF: case SNAP_INTERNAL:
DBWSnapToGrid = DBW_SNAP_INTERNAL;
DBWSnapToGrid = DBW_UNITS_INTERNAL;
return;
case SNAP_LAMBDA:
DBWSnapToGrid = DBW_SNAP_LAMBDA;
DBWSnapToGrid = DBW_UNITS_LAMBDA;
return;
case SNAP_GRID: case SNAP_USER: case SNAP_ON:
DBWSnapToGrid = DBW_SNAP_USER;
DBWSnapToGrid = DBW_UNITS_USER;
return;
}
@ -2901,21 +2940,19 @@ printit:
if (n == SNAP_LIST) /* list */
#ifdef MAGIC_WRAPPER
Tcl_SetResult(magicinterp,
(DBWSnapToGrid == DBW_SNAP_INTERNAL) ? "internal" :
((DBWSnapToGrid == DBW_SNAP_LAMBDA) ? "lambda" : "user"),
(DBWSnapToGrid == DBW_UNITS_INTERNAL) ? "internal" :
((DBWSnapToGrid == DBW_UNITS_LAMBDA) ? "lambda" : "user"),
TCL_VOLATILE);
#else
TxPrintf("%s\n", (DBWSnapToGrid == DBW_SNAP_INTERNAL) ? "internal" :
((DBWSnapToGrid == DBW_SNAP_LAMBDA) ? "lambda" : "user"));
TxPrintf("%s\n", (DBWSnapToGrid == DBW_UNITS_INTERNAL) ? "internal" :
((DBWSnapToGrid == DBW_UNITS_LAMBDA) ? "lambda" : "user"));
#endif
else
TxPrintf("Box is aligned to %s grid\n",
(DBWSnapToGrid == DBW_SNAP_INTERNAL) ? "internal" :
((DBWSnapToGrid == DBW_SNAP_LAMBDA) ? "lambda" : "user"));
(DBWSnapToGrid == DBW_UNITS_INTERNAL) ? "internal" :
((DBWSnapToGrid == DBW_UNITS_LAMBDA) ? "lambda" : "user"));
}
/*
* ----------------------------------------------------------------------------
*

View File

@ -73,9 +73,22 @@ TileTypeBitMask CmdYMAllButSpace;
* lambda, a suffix of "g" indicates the user grid, and a suffix in metric
* notation ("nm", "um", "mm", "cm") indicates natural units. Other valid
* units are "cu" or "centimicrons" for centimicrons, or "microns" for um.
* Units without any suffix are assumed to be in lambda if "snap"
* (DBWSnapToGrid) is set to lambda, grid units if "snap" is set to the
* user grid, and internal units otherwise.
* Traditional (backwards-compatible) behavior: Units without any suffix
* are assumed to be in lambda if "snap" (DBWSnapToGrid) is set to lambda,
* grid units if "snap" is set to the user grid, and internal units otherwise.
* Current behavior: Use of the "units" command to set the units to
* any value other than "default" causes cmdScaleCoord() to parse any
* units provided without an identifying suffix as the units indicted by
* the "units" command. Once the "units" command has been issued, the
* values are dependent on DBWUnits and not on DBWSnapToGrid.
*
* Additional behavior from magic version 8.3.596: A single command
* option can use simple expressions using '+', '-', '*', and '/'. These
* can be passed as a single token, without spaces, or within a string
* token deliniated by quotes or braces, per usual Tcl syntax. Unlike
* the Tcl "expr" command, this can solve arithmetic expressions of
* suffixed values, evaluated independently such that different suffixes
* may be used (e.g., "1g + 3um" meaning 1 grid pitch plus 3 microns).
*
* MagWindow argument w is used only with grid-based snapping, to find
* the value of the grid for the given window. In this case, because the
@ -99,6 +112,13 @@ TileTypeBitMask CmdYMAllButSpace;
* ----------------------------------------------------------------------------
*/
#define PARSEOP_NONE 0
#define PARSEOP_ADD 1
#define PARSEOP_SUB 2
#define PARSEOP_MUL 3
#define PARSEOP_DIV 4
#define PARSEOP_END 5
int
cmdScaleCoord(
MagWindow *w,
@ -109,107 +129,195 @@ cmdScaleCoord(
{
char *endptr;
double dval = 0;
int mscale = 1;
int mscale = 1, curunits;
int retval, curval, parseop;
DBWclientRec *crec;
if (*arg == '{') arg++;
while (isspace(*arg)) arg++;
if (*arg == '{' || *arg == '"') arg++;
while (isspace(*arg) && (*arg != '\0')) arg++;
dval = strtod(arg, &endptr);
dval *= (double)scale;
parseop = PARSEOP_NONE;
retval = 0;
while (*arg != '\0')
{
dval = strtod(arg, &endptr);
dval *= (double)scale;
mscale = -1;
if (endptr == arg)
{
/* strtod() error condition */
TxError("Coordinate value cannot be parsed: assuming 0\n");
return 0;
}
else if ((*endptr == 'l')
|| ((*endptr == '\0') && (DBWSnapToGrid == DBW_SNAP_LAMBDA)))
{
/* lambda or default units */
dval *= (double)DBLambda[1];
dval /= (double)DBLambda[0];
return round(dval);
}
else if ((*endptr == 'i')
|| ((*endptr == '\0') && (DBWSnapToGrid == DBW_SNAP_INTERNAL)))
{
/* internal units */
return round(dval);
}
else if ((*endptr == 'g')
|| ((*endptr == '\0') && (DBWSnapToGrid == DBW_SNAP_USER)))
{
/* grid units */
if (w == (MagWindow *)NULL)
if (endptr == arg)
{
windCheckOnlyWindow(&w, DBWclientID);
if (w == (MagWindow *)NULL)
return round(dval); /* Default, if window is unknown */
}
crec = (DBWclientRec *) w->w_clientData;
if (is_x)
{
dval *= (double)(crec->dbw_gridRect.r_xtop
- crec->dbw_gridRect.r_xbot);
if (!is_relative)
dval += (double)crec->dbw_gridRect.r_xbot;
/* strtod() error condition */
TxError("Coordinate value cannot be parsed: assuming 0\n");
curval = 0;
break;
}
/* Original behavior was to accept un-suffixed values according to the
* "snap" setting. This behavior remains in effect until the "units"
* command is used, in which case units follow the selected units
* value indepedendently of the snap setting.
*
* Updated 12/24/2026 to handle space-separated values (in which
* *endptr may be a space as well as NULL).
*/
if (DBWUnits == DBW_UNITS_DEFAULT)
curunits = DBWSnapToGrid;
else
curunits = DBWUnits & DBW_UNITS_TYPE_MASK;
if ((*endptr == 'l')
|| (((*endptr == '\0') || isspace(*endptr))
&& (curunits == DBW_UNITS_LAMBDA)))
{
dval *= (double)(crec->dbw_gridRect.r_ytop
- crec->dbw_gridRect.r_ybot);
if (!is_relative)
dval += (double)crec->dbw_gridRect.r_ybot;
/* lambda or default units */
dval *= (double)DBLambda[1];
dval /= (double)DBLambda[0];
}
return round(dval);
}
else
{
/* natural units referred to the current cifoutput style */
if (*(endptr + 1) == 'm')
else if ((*endptr == 'i')
|| (((*endptr == '\0') || isspace(*endptr))
&& (curunits == DBW_UNITS_INTERNAL)))
{
/* internal units */
}
else if ((*endptr == 'g')
|| (((*endptr == '\0') || isspace(*endptr))
&& (curunits == DBW_UNITS_USER)))
{
/* grid units */
if (w == (MagWindow *)NULL)
{
windCheckOnlyWindow(&w, DBWclientID);
if (w == (MagWindow *)NULL)
{
curval = round(dval); /* Default, if window is unknown */
break;
}
}
crec = (DBWclientRec *) w->w_clientData;
if (is_x)
{
dval *= (double)(crec->dbw_gridRect.r_xtop
- crec->dbw_gridRect.r_xbot);
if (!is_relative)
dval += (double)crec->dbw_gridRect.r_xbot;
}
else
{
dval *= (double)(crec->dbw_gridRect.r_ytop
- crec->dbw_gridRect.r_ybot);
if (!is_relative)
dval += (double)crec->dbw_gridRect.r_ybot;
}
}
else if (((*endptr == '\0') || isspace(*endptr))
&& (curunits == DBW_UNITS_MICRONS))
{
mscale = 1000;
}
else if (*endptr != '\0')
{
/* natural units referred to the current cifoutput style */
if (*(endptr + 1) == 'm')
{
switch (*endptr)
{
case 'n':
mscale = 1;
break;
case 'u':
mscale = 1000;
break;
case 'm':
mscale = 1000000;
break;
case 'c':
mscale = 10000000;
break;
default:
TxError("Unknown metric prefix \"%cm\"; assuming "
"internal units\n", *endptr);
mscale = -1;
}
}
else if ((*endptr == 'u') && !isalnum(*(endptr + 1)))
/* Maybe "u" is too ambiguous but it is very commonly used as
* an abbreviation for "micron".
*/
mscale = 1000;
else if (!strncmp(endptr, "micron", 6))
mscale = 1000;
else if (!strncmp(endptr, "centimicron", 11) || !strcmp(endptr, "cu"))
mscale = 10;
else if (!isspace(*endptr) && (*endptr != '+') && (*endptr != '-') &&
(*endptr != '*') && (*endptr != '/'))
{
TxError("Unknown coordinate type at \"%s\"; assuming internal units\n",
endptr);
mscale = -1;
}
}
if (mscale != -1)
dval /= CIFGetOutputScale(mscale);
curval = round(dval);
switch (parseop)
{
case PARSEOP_NONE:
retval = curval;
break;
case PARSEOP_ADD:
retval += curval;
break;
case PARSEOP_SUB:
retval -= curval;
break;
case PARSEOP_MUL:
retval *= curval;
break;
case PARSEOP_DIV:
retval /= curval;
break;
}
parseop = PARSEOP_NONE;
while (*endptr != '\0')
{
switch (*endptr)
{
case 'n':
mscale = 1;
case '}':
case '"':
parseop = PARSEOP_END;
break;
case 'u':
mscale = 1000;
case '+':
parseop = PARSEOP_ADD;
endptr++;
break;
case 'm':
mscale = 1000000;
case '-':
parseop = PARSEOP_SUB;
endptr++;
break;
case 'c':
mscale = 10000000;
case '*':
parseop = PARSEOP_MUL;
endptr++;
break;
case '/':
parseop = PARSEOP_DIV;
endptr++;
break;
case ' ':
case '\t':
endptr++;
break;
default:
TxError("Unknown metric prefix \"%cm\"; assuming internal units\n",
*endptr);
return round(dval);
/* Should this flag an error? */
return retval;
}
if (parseop != PARSEOP_NONE) break;
}
else if (!strcmp(endptr, "u"))
/* Maybe "u" is too ambiguous but it is very commonly used as
* an abbreviation for "micron".
*/
mscale = 1000;
else if (!strncmp(endptr, "micron", 6))
mscale = 1000;
else if (!strncmp(endptr, "centimicron", 11) || !strcmp(endptr, "cu"))
mscale = 10;
else if (!isspace(*endptr))
{
TxError("Unknown coordinate type \"%s\"; assuming internal units\n",
endptr);
return round(dval);
}
arg = endptr;
while (isspace(*arg) && (*arg != '\0')) arg++;
}
if (!isspace(*endptr))
dval /= CIFGetOutputScale(mscale);
return round(dval);
return retval;
}
/*
@ -653,13 +761,16 @@ cmdSaveCell(
if (!tryRename || (fileName == NULL) || (strcmp(cellDef->cd_name, fileName) == 0))
goto cleanup;
/* Rename the cell */
if (!DBCellRenameDef(cellDef, fileName))
/* Rename the cell, unless fileName is a .tcl file (scripted output) */
if ((strlen(fileName) <= 4) || strcmp(fileName + strlen(fileName) - 4, ".tcl"))
{
/* This should never happen */
TxError("Magic error: there is already a cell named \"%s\"\n",
if (!DBCellRenameDef(cellDef, fileName))
{
/* This should never happen */
TxError("Magic error: there is already a cell named \"%s\"\n",
fileName);
goto cleanup;
goto cleanup;
}
}
if (EditCellUse && (cellDef == EditCellUse->cu_def))

View File

@ -455,15 +455,18 @@ CmdTech(
}
if (!strncmp(cmd->tx_argv[2], "width", 5))
{
char *techwidth;
tresult = DRCGetDefaultLayerWidth(t1);
techwidth = DBWPrintValue(tresult, w, TRUE);
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult));
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techwidth, -1));
#else
TxPrintf("Minimum width is %d\n", tresult);
TxPrintf("Minimum width is %s\n", techwidth);
#endif
}
else if (!strncmp(cmd->tx_argv[2], "spac", 4))
{
char *techspace;
if (cmd->tx_argc >= 5)
{
t2 = DBTechNoisyNameType(cmd->tx_argv[4]);
@ -475,14 +478,16 @@ CmdTech(
else
t2 = t1;
tresult = DRCGetDefaultLayerSpacing(t1, t2);
techspace = DBWPrintValue(tresult, w, TRUE);
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult));
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techspace, -1));
#else
TxPrintf("Minimum spacing is %d\n", tresult);
TxPrintf("Minimum spacing is %s\n", techspace);
#endif
}
else if (!strncmp(cmd->tx_argv[2], "surr", 4))
{
char *techsurround;
if (cmd->tx_argc >= 5)
{
t2 = DBTechNoisyNameType(cmd->tx_argv[4]);
@ -498,14 +503,17 @@ CmdTech(
}
tresult = DRCGetDefaultLayerSurround(t1, t2);
techsurround = DBWPrintValue(tresult, w, TRUE);
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult));
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techsurround, -1));
#else
TxPrintf("Minimum surround is %d\n", tresult);
TxPrintf("Minimum surround is %s\n", techsurround);
#endif
}
else if (!strncmp(cmd->tx_argv[2], "direc", 5))
{
char *techdirec;
if (cmd->tx_argc >= 5)
{
t2 = DBTechNoisyNameType(cmd->tx_argv[4]);
@ -521,10 +529,11 @@ CmdTech(
}
tresult = DRCGetDirectionalLayerSurround(t1, t2);
techdirec = DBWPrintValue(tresult, w, TRUE);
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult));
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techdirec, -1));
#else
TxPrintf("Minimum surround (in one orientation) is %d\n", tresult);
TxPrintf("Minimum surround (in one orientation) is %s\n", techdirec);
#endif
}
}
@ -754,6 +763,182 @@ cmdUnexpandFunc(
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* CmdUnits --
*
* Implement the "units" command.
*
* Usage:
* units [value] [print|noprint]
*
* where "value" may be one of "default", "internal", "lambda",
* "user" (equivalently "grid"), or "microns".
*
* Results:
* None.
*
* Side effects:
* The global variable DBWUnits may be changed, which changes the
* behavior of magic when interpreting un-suffixed values or
* displaying values.
*
* Notes:
* The units behavior was previously dependent on what command was
* issued, with results usually being given in internal units, and
* with un-suffixed values following the snap behavior. Backwards-
* compatible behavior is used on startup or at any time by setting
* the units to "default". Otherwise, unit display follows the
* given "units" setting.
*
* ----------------------------------------------------------------------------
*/
#define UNITS_DEFAULT 0
#define UNITS_INTERNAL 1
#define UNITS_LAMBDA 2
#define UNITS_GRID 3
#define UNITS_USER 4
#define UNITS_MICRONS 5
#define UNITS_LIST 6
#define UNITS_PRINT 7
#define UNITS_NOPRINT 8
void
CmdUnits(
MagWindow *w,
TxCommand *cmd)
{
static const char * const names[] = { "default", "internal", "lambda",
"grid", "user", "microns", "list", "print", "noprint", 0 };
int idx, n = UNITS_LIST, n2, saveflag;
DBWclientRec *crec;
if (cmd->tx_argc >= 2)
{
n = Lookup(cmd->tx_argv[1], names);
if (n < 0)
{
TxPrintf("Usage: units [default | internal | lambda | microns"
" | user] [print]\n");
return;
}
if (DBWUnits != DBW_UNITS_DEFAULT)
saveflag = DBWUnits & DBW_UNITS_PRINT_FLAG;
else
saveflag = -1;
switch (n)
{
case UNITS_DEFAULT:
DBWUnits = DBW_UNITS_DEFAULT;
break;
case UNITS_INTERNAL:
DBWUnits = DBW_UNITS_INTERNAL;
break;
case UNITS_LAMBDA:
DBWUnits = DBW_UNITS_LAMBDA;
break;
case UNITS_USER:
case UNITS_GRID:
DBWUnits = DBW_UNITS_USER;
break;
case UNITS_MICRONS:
DBWUnits = DBW_UNITS_MICRONS;
break;
case UNITS_PRINT:
saveflag = DBW_UNITS_PRINT_FLAG;
break;
case UNITS_NOPRINT:
saveflag = 0;
break;
}
if (n < 0)
{
TxError("Unrecognized units option %s\n.", cmd->tx_argv[1]);
return;
}
if (n != UNITS_LIST)
{
if ((cmd->tx_argc == 3) && (n != UNITS_DEFAULT))
{
n2 = Lookup(cmd->tx_argv[2], names);
switch (n2)
{
case UNITS_PRINT:
DBWUnits |= DBW_UNITS_PRINT_FLAG;
break;
case UNITS_NOPRINT:
DBWUnits &= DBW_UNITS_TYPE_MASK;
break;
default:
TxError("Unrecognized units option %s\n.", cmd->tx_argv[2]);
break;
}
}
else if ((n != UNITS_DEFAULT) && (saveflag != -1))
{
/* Preserve the previous value of the print/noprint flag */
DBWUnits &= DBW_UNITS_TYPE_MASK;
DBWUnits |= saveflag;
}
return;
}
}
if (DBWUnits == DBW_UNITS_DEFAULT)
idx = UNITS_DEFAULT;
else
switch (DBWUnits & DBW_UNITS_TYPE_MASK)
{
case DBW_UNITS_INTERNAL:
idx = UNITS_INTERNAL;
break;
case DBW_UNITS_LAMBDA:
idx = UNITS_LAMBDA;
break;
case DBW_UNITS_USER:
idx = UNITS_USER;
break;
case DBW_UNITS_MICRONS:
idx = UNITS_MICRONS;
break;
}
if (n == UNITS_LIST) /* list */
{
#ifdef MAGIC_WRAPPER
Tcl_Obj *tobj;
tobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj((char *)names[idx], -1));
if (idx != UNITS_DEFAULT)
{
if (DBWUnits & DBW_UNITS_PRINT_FLAG)
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj("print", 5));
else
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj("noprint", 7));
}
Tcl_SetObjResult(magicinterp, tobj);
#else
TxPrintf("%s", names[idx]);
if (idx != UNITS_DEFAULT)
if (DBWUnits & DBW_UNITS_PRINT_FLAG)
TxPrintf(" print");
TxPrintf("\n");
#endif
}
else if (idx == UNITS_DEFAULT)
TxPrintf("Reported units follow the snap setting.\n");
else if (DBWUnits & DBW_UNITS_PRINT_FLAG)
TxPrintf("Values are reported as %s, along with the units.\n", names[idx]);
else
TxPrintf("Values are reported as %s\n", names[idx]);
}
/*
* ----------------------------------------------------------------------------
*
@ -1696,18 +1881,20 @@ CmdWire(
case VALUES:
if (locargc == 2)
{
char *wdisp;
width = WireGetWidth();
type = WireGetType();
wdisp = DBWPrintValue(width, w, TRUE);
#ifdef MAGIC_WRAPPER
lobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(width));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(DBTypeLongNameTbl[type], -1));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(wdisp, -1));
Tcl_SetObjResult(magicinterp, lobj);
#else
TxPrintf("Wire layer %s, width %d\n",
DBTypeLongNameTbl[type], width);
TxPrintf("Wire layer %s, width %s\n",
DBTypeLongNameTbl[type], wdisp);
#endif
}
break;
@ -1732,12 +1919,14 @@ CmdWire(
case WIDTH:
if (locargc == 2)
{
char *wdisp;
width = WireGetWidth();
wdisp = DBWPrintValue(width, w, TRUE);
#ifdef MAGIC_WRAPPER
lobj = Tcl_NewIntObj(width);
lobj = Tcl_NewStringObj(wdisp, -1);
Tcl_SetObjResult(magicinterp, lobj);
#else
TxPrintf("Wire width is %d\n", width);
TxPrintf("Wire width is %s\n", wdisp);
#endif
}
else if (locargc != 3)

View File

@ -72,7 +72,7 @@ extern int cmdParseCoord(MagWindow *w, char *arg, bool is_relative, bool is_x);
extern void cmdSaveCell(CellDef *cellDef, char *newName, bool noninteractive, bool tryRename);
extern void CmdInit(void);
extern void CmdDoProperty(CellDef *def, TxCommand *cmd, int argstart);
extern void CmdDoProperty(CellDef *def, MagWindow *w, TxCommand *cmd, int argstart);
extern void CmdPaintEraseButton(MagWindow *w, Point *refPoint, bool isPaint, bool isScreen);
#endif /* _MAGIC__COMMANDS__COMMANDS_H */

View File

@ -37,9 +37,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "commands/commands.h"
/* C99 compat */
#include "graphics/graphics.h"
#include "cif/CIFint.h"
/*
* The following variable points to the tables currently used for
@ -357,9 +356,43 @@ DBCellCheckCopyAllPaint(scx, mask, xMask, targetUse, func)
struct propUseDefStruct {
CellDef *puds_source;
CellDef *puds_dest;
Plane *puds_plane; /* Mask hint plane in dest */
Transform *puds_trans; /* Transform from source use to dest */
Rect *puds_area; /* Clip area in source coordinates */
};
/*
*-----------------------------------------------------------------------------
*
* dbCopyMaskHintPlaneFunc --
*
* Translate tiles from a child mask-hint property plane into the
* coordinate system of the parent, and paint the mask-hint area
* into the mask-hint property plane of the parent.
*
*-----------------------------------------------------------------------------
*/
int
dbCopyMaskHintPlaneFunc(Tile *tile,
TileType dinfo,
struct propUseDefStruct *puds)
{
Transform *trans = puds->puds_trans;
Rect *clip = puds->puds_area;
Rect r, rnew;
Plane *plane = puds->puds_plane;
TiToRect(tile, &r);
GeoClip(&r, clip);
if (!GEO_RECTNULL(&r))
{
GeoTransRect(trans, &r, &rnew);
DBPaintPlane(plane, &rnew, CIFPaintTable, (PaintUndoInfo *)NULL);
}
return 0;
}
/*
*-----------------------------------------------------------------------------
*
@ -380,63 +413,52 @@ struct propUseDefStruct {
*/
int
dbCopyMaskHintsFunc(key, value, puds)
dbCopyMaskHintsFunc(key, proprec, puds)
char *key;
ClientData value;
PropertyRecord *proprec;
struct propUseDefStruct *puds;
{
CellDef *dest = puds->puds_dest;
Transform *trans = puds->puds_trans;
char *propstr = (char *)value;
Rect *clip = puds->puds_area;
PropertyRecord *parentproprec, *newproprec;
char *parentprop, *newvalue, *vptr;
Rect r, rnew;
bool propfound;
int i, j;
if (!strncmp(key, "MASKHINTS_", 10))
{
char *vptr, *lastval;
int lastlen;
Plane *plane;
/* Append to existing mask hint (if any) */
parentprop = (char *)DBPropGet(dest, key, &propfound);
newvalue = (propfound) ? StrDup((char **)NULL, parentprop) : (char *)NULL;
ASSERT(proprec->prop_type == PROPERTY_TYPE_PLANE, "dbCopyMaskHintsFunc");
vptr = propstr;
while (*vptr != '\0')
/* Get the existing mask hint plane in the parent cell, and
* create it if it does not already exist.
*/
parentproprec = (PropertyRecord *)DBPropGet(dest, key, &propfound);
if (propfound)
plane = parentproprec->prop_value.prop_plane;
else
{
if (sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
&r.r_xtop, &r.r_ytop) == 4)
{
GeoTransRect(trans, &r, &rnew);
lastval = newvalue;
lastlen = (lastval) ? strlen(lastval) : 0;
newvalue = mallocMagic(40 + lastlen);
if (lastval)
strcpy(newvalue, lastval);
else
*newvalue = '\0';
sprintf(newvalue + lastlen, "%s%d %d %d %d", (lastval) ? " " : "",
rnew.r_xbot, rnew.r_ybot, rnew.r_xtop, rnew.r_ytop);
if (lastval) freeMagic(lastval);
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
}
else break;
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
newproprec->prop_type = PROPERTY_TYPE_PLANE;
newproprec->prop_len = 0;
plane = DBNewPlane((ClientData)TT_SPACE);
newproprec->prop_value.prop_plane = plane;
DBPropPut(dest, key, newproprec);
}
if (newvalue)
DBPropPut(dest, key, newvalue);
}
puds->puds_plane = plane;
/* Copy the properties from child to parent */
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
proprec->prop_value.prop_plane,
clip, &CIFSolidBits, dbCopyMaskHintPlaneFunc,
(ClientData)puds);
}
return 0;
}
@ -468,6 +490,7 @@ DBCellCopyMaskHints(child, parent, transform)
puds.puds_source = child->cu_def;
puds.puds_dest = parent;
puds.puds_trans = transform;
puds.puds_area = (Rect *)&TiPlaneRect;
DBPropEnum(child->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
}
@ -501,6 +524,7 @@ dbFlatCopyMaskHintsFunc(scx, def)
puds.puds_source = scx->scx_use->cu_def;
puds.puds_dest = def;
puds.puds_trans = &scx->scx_trans;
puds.puds_area = &scx->scx_area;
DBPropEnum(use->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);

View File

@ -152,10 +152,9 @@ DBCellRename(cellname, newname, doforce)
if (doforce && ((celldef->cd_flags & CDVENDORGDS) == CDVENDORGDS))
{
char *chkgdsfile;
bool isReadOnly;
chkgdsfile = (char *)DBPropGet(celldef, "GDS_FILE", &isReadOnly);
DBPropGet(celldef, "GDS_FILE", &isReadOnly);
/* Note that clearing GDS_FILE will also clear CDVENDORGDS flag */
if (isReadOnly) DBPropPut(celldef, "GDS_FILE", NULL);
@ -1620,7 +1619,9 @@ dbAbutmentUseFunc(selUse, use, transform, data)
{
Rect bbox, refbox;
Transform *trans;
PropertyRecord *proprec;
char *propvalue;
char *refllx, *reflly, *refurx, *refury;
bool found;
bool *dolist = (bool *)data;
@ -1642,32 +1643,47 @@ dbAbutmentUseFunc(selUse, use, transform, data)
}
trans = &use->cu_transform;
propvalue = (char *)DBPropGet(use->cu_def, "FIXED_BBOX", &found);
proprec = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
if (!found)
bbox = use->cu_def->cd_bbox;
else
{
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) != 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
}
else
{
TxError("Unable to parse the cell's FIXED_BBOX property; using "
"the instance bounding box instead.\n");
bbox = use->cu_def->cd_bbox;
}
}
GeoTransRect(trans, &bbox, &refbox);
/* NOTE: Ideally, the MagWindow pointer should get passed to this routine */
refllx = DBWPrintValue(refbox.r_xbot, (MagWindow *)NULL, TRUE);
reflly = DBWPrintValue(refbox.r_ybot, (MagWindow *)NULL, FALSE);
refurx = DBWPrintValue(refbox.r_xtop, (MagWindow *)NULL, TRUE);
refury = DBWPrintValue(refbox.r_ytop, (MagWindow *)NULL, FALSE);
#ifdef MAGIC_WRAPPER
if (*dolist)
{
pobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_xbot));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_ybot));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_xtop));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_ytop));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(refllx, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(reflly, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(refurx, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(refury, -1));
Tcl_SetObjResult(magicinterp, pobj);
}
else
#endif
TxPrintf("Abutment box: %d %d %d %d\n", refbox.r_xbot, refbox.r_ybot,
refbox.r_xtop, refbox.r_ytop);
TxPrintf("Abutment box: %s %s %s %s\n", refllx, reflly, refurx, refury);
return 0;
}

View File

@ -1713,7 +1713,7 @@ dbTileMoveFunc(tile, dinfo, mvvals)
if (IsSplit(tile))
type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
DBNMPaintPlane(mvvals->ptarget, exact, &targetRect,
DBStdPaintTbl(type, mvvals->pnum),
(mvvals->pnum < 0) ? CIFPaintTable : DBStdPaintTbl(type, mvvals->pnum),
(PaintUndoInfo *)NULL);
return 0;
}
@ -1806,84 +1806,48 @@ typedef struct _cellpropstruct {
* ----------------------------------------------------------------------------
*/
int dbScaleProp(name, value, cps)
int dbScaleProp(name, proprec, cps)
char *name;
char *value;
PropertyRecord *proprec;
CellPropStruct *cps;
{
int scalen, scaled;
char *newvalue, *vptr;
Rect r;
int i, scalen, scaled;
Point p;
if ((strlen(name) > 5) && !strncmp(name + strlen(name) - 5, "_BBOX", 5))
/* Only "dimension" and "plane" type properties get scaled */
if (proprec->prop_type == PROPERTY_TYPE_PLANE)
{
if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
&r.r_xtop, &r.r_ytop) == 4)
{
/* Scale numerator held in point X value, */
/* scale denominator held in point Y value */
scalen = cps->cps_point.p_x;
scaled = cps->cps_point.p_y;
DBScalePoint(&r.r_ll, scalen, scaled);
DBScalePoint(&r.r_ur, scalen, scaled);
newvalue = (char *)mallocMagic(40);
sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot,
r.r_xtop, r.r_ytop);
DBPropPut(cps->cps_def, name, newvalue);
}
Plane *newplane;
newplane = DBNewPlane((ClientData)TT_SPACE);
DBClearPaintPlane(newplane);
/* Plane index is unused; arbitrarily substitute -1 */
dbScalePlane(proprec->prop_value.prop_plane, newplane, -1,
scalen, scaled, TRUE);
DBFreePaintPlane(proprec->prop_value.prop_plane);
TiFreePlane(proprec->prop_value.prop_plane);
proprec->prop_value.prop_plane = newplane;
return 0;
}
else if (!strncmp(name, "MASKHINTS_", 10))
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
/* Scale numerator held in point X value, */
/* scale denominator held in point Y value */
scalen = cps->cps_point.p_x;
scaled = cps->cps_point.p_y;
for (i = 0; i < proprec->prop_len; i += 2)
{
char *vptr, *lastval;
int lastlen;
if ((i + 1) >= proprec->prop_len) break;
newvalue = (char *)NULL;
vptr = value;
while (*vptr != '\0')
{
if (sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
&r.r_xtop, &r.r_ytop) == 4)
{
/* Scale numerator held in point X value, */
/* scale denominator held in point Y value */
scalen = cps->cps_point.p_x;
scaled = cps->cps_point.p_y;
DBScalePoint(&r.r_ll, scalen, scaled);
DBScalePoint(&r.r_ur, scalen, scaled);
lastval = newvalue;
lastlen = (lastval) ? strlen(lastval) : 0;
newvalue = mallocMagic(40 + lastlen);
if (lastval)
strcpy(newvalue, lastval);
else
*newvalue = '\0';
sprintf(newvalue + lastlen, "%s%d %d %d %d", (lastval) ? " " : "",
r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
if (lastval) freeMagic(lastval);
/* Parse through the four values and check if there's more */
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
}
else break;
}
if (newvalue)
DBPropPut(cps->cps_def, name, newvalue);
p.p_x = proprec->prop_value.prop_integer[i];
p.p_y = proprec->prop_value.prop_integer[i + 1];
DBScalePoint(&p, scalen, scaled);
proprec->prop_value.prop_integer[i] = p.p_x;
proprec->prop_value.prop_integer[i + 1] = p.p_y;
}
return 0; /* Keep enumerating through properties */
}
@ -1899,33 +1863,47 @@ int dbScaleProp(name, value, cps)
* ----------------------------------------------------------------------------
*/
int dbMoveProp(name, value, cps)
int dbMoveProp(name, proprec, cps)
char *name;
char *value;
PropertyRecord *proprec;
CellPropStruct *cps;
{
int origx, origy;
int i, origx, origy;
char *newvalue;
Rect r;
Point p;
if (((strlen(name) > 5) && !strncmp(name + strlen(name) - 5, "_BBOX", 5))
|| !strncmp(name, "MASKHINTS_", 10))
/* Only "dimension" and "plane" type properties get scaled */
if (proprec->prop_type == PROPERTY_TYPE_PLANE)
{
if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
&r.r_xtop, &r.r_ytop) == 4)
{
origx = cps->cps_point.p_x;
origy = cps->cps_point.p_y;
Plane *newplane;
DBMovePoint(&r.r_ll, origx, origy);
DBMovePoint(&r.r_ur, origx, origy);
newvalue = (char *)mallocMagic(40);
sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot,
r.r_xtop, r.r_ytop);
DBPropPut(cps->cps_def, name, newvalue);
}
newplane = DBNewPlane((ClientData) TT_SPACE);
DBClearPaintPlane(newplane);
/* Use plane index -1 to indicate use of CIFPaintTable */
dbMovePlane(proprec->prop_value.prop_plane, newplane, -1, origx, origy);
DBFreePaintPlane(proprec->prop_value.prop_plane);
TiFreePlane(proprec->prop_value.prop_plane);
proprec->prop_value.prop_plane = newplane;
return 0;
}
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
origx = cps->cps_point.p_x;
origy = cps->cps_point.p_y;
for (i = 0; i < proprec->prop_len; i += 2)
{
if ((i + 1) >= proprec->prop_len) break;
p.p_x = proprec->prop_value.prop_integer[i];
p.p_y = proprec->prop_value.prop_integer[i + 1];
DBMovePoint(&p, origx, origy);
proprec->prop_value.prop_integer[i] = p.p_x;
proprec->prop_value.prop_integer[i + 1] = p.p_y;
}
return 0; /* Keep enumerating through properties */
}

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,16 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "database/database.h"
#include "utils/malloc.h"
/* Global variable */
bool DBPropCompat = TRUE; /* If TRUE, then always save properties to
* .mag files as type "string" for backwards
* compatibility. If FALSE, then properties
* are saved to the .mag file along with their
* type. Regardless of the setting, properties
* which are reserved keywords are converted
* to the best internal representation on input.
*/
/* ----------------------------------------------------------------------------
*
@ -47,16 +57,16 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
void
DBPropPut(cellDef, name, value)
CellDef *cellDef; /* Pointer to definition of cell. */
char *name; /* The name of the property desired. */
ClientData value; /* MUST point to a malloc'ed structure, or NULL.
* This will be freed when the CellDef is freed.
*/
CellDef *cellDef; /* Pointer to definition of cell. */
char *name; /* The name of the property desired. */
PropertyRecord *value; /* MUST point to a malloc'ed structure, or NULL.
* This will be freed when the CellDef is freed.
*/
{
HashTable *htab;
HashEntry *entry;
char *oldvalue;
PropertyRecord *oldvalue;
/* Honor the NOEDIT flag. Note that the caller always assumes that */
/* the value would be saved in the hash table, so if it is not */
@ -95,12 +105,23 @@ DBPropPut(cellDef, name, value)
}
entry = HashFind(htab, name);
oldvalue = (char *)HashGetValue(entry);
if (oldvalue != NULL) freeMagic(oldvalue);
if (value == (ClientData)NULL)
oldvalue = (PropertyRecord *)HashGetValue(entry);
/* All properties are allocated as a single block and can just be freed,
* except for plane properties, which require freeing the plane.
*/
if (oldvalue != NULL)
{
if (oldvalue->prop_type == PROPERTY_TYPE_PLANE)
{
DBFreePaintPlane(oldvalue->prop_value.prop_plane);
TiFreePlane(oldvalue->prop_value.prop_plane);
}
freeMagic((char *)oldvalue);
}
if (value == (PropertyRecord *)NULL)
HashRemove(htab, name);
else
HashSetValue(entry, value);
HashSetValue(entry, PTR2CD(value));
}
/* ----------------------------------------------------------------------------
@ -110,13 +131,13 @@ DBPropPut(cellDef, name, value)
* Get a property from a celldef.
*
* Results:
* NULL if the property didn't exist, or if the property value was NULL.
* Otherwise, ClientData that represents the property.
* NULL if the property didn't exist, or if the property record was NULL.
* Otherwise, returns a pointer to the property record.
*
* ----------------------------------------------------------------------------
*/
ClientData
PropertyRecord *
DBPropGet(cellDef, name, found)
CellDef *cellDef; /* Pointer to definition of cell. */
char *name; /* The name of the property desired. */
@ -124,12 +145,12 @@ DBPropGet(cellDef, name, found)
* exists.
*/
{
ClientData result;
PropertyRecord *result;
bool haveit;
HashTable *htab;
HashEntry *entry;
result = (ClientData) NULL;
result = (PropertyRecord *)NULL;
haveit = FALSE;
htab = (HashTable *) cellDef->cd_props;
if (htab == (HashTable *) NULL) goto done;
@ -138,7 +159,7 @@ DBPropGet(cellDef, name, found)
if (entry != NULL)
{
haveit = TRUE;
result = (ClientData) HashGetValue(entry);
result = (PropertyRecord *)HashGetValue(entry);
}
done:
@ -146,6 +167,109 @@ done:
return result;
}
/* ----------------------------------------------------------------------------
*
* DBPropGetString --
*
* Get a string property from a celldef.
*
* Results:
* NULL if the property didn't exist, or if the property record was NULL.
* Otherwise, returns a pointer to the property's string record.
*
* Notes:
* This is basically the original DBPropGet(), when properties were only
* allowed to be strings.
*
* ----------------------------------------------------------------------------
*/
char *
DBPropGetString(cellDef, name, found)
CellDef *cellDef; /* Pointer to definition of cell. */
char *name; /* The name of the property desired. */
bool *found; /* If not NULL, filled in with TRUE iff the property
* exists.
*/
{
char *result = NULL;
PropertyRecord *proprec;
bool haveit;
HashTable *htab;
HashEntry *entry;
haveit = FALSE;
htab = (HashTable *) cellDef->cd_props;
if (htab == (HashTable *) NULL) goto pdone;
entry = HashLookOnly(htab, name);
if (entry != NULL)
{
proprec = (PropertyRecord *)HashGetValue(entry);
if (proprec->prop_type == PROPERTY_TYPE_STRING)
{
haveit = TRUE;
result = proprec->prop_value.prop_string;
}
}
pdone:
if (found != (bool *) NULL) *found = haveit;
return result;
}
/* ----------------------------------------------------------------------------
*
* DBPropGetDouble --
*
* Get a single double-long integer property from a celldef.
*
* Results:
* NULL if the property didn't exist, or if the property record was NULL.
* Otherwise, returns a pointer to the property's value record.
*
* ----------------------------------------------------------------------------
*/
dlong
DBPropGetDouble(cellDef, name, found)
CellDef *cellDef; /* Pointer to definition of cell. */
char *name; /* The name of the property desired. */
bool *found; /* If not NULL, filled in with TRUE iff the property
* exists.
*/
{
dlong result = 0;
PropertyRecord *proprec;
bool haveit;
HashTable *htab;
HashEntry *entry;
haveit = FALSE;
htab = (HashTable *) cellDef->cd_props;
if (htab == (HashTable *) NULL) goto ddone;
entry = HashLookOnly(htab, name);
if (entry != NULL)
{
proprec = (PropertyRecord *)HashGetValue(entry);
if (proprec->prop_type == PROPERTY_TYPE_DOUBLE)
{
haveit = TRUE;
result = proprec->prop_value.prop_double[0];
}
else if (proprec->prop_type == PROPERTY_TYPE_STRING)
{
haveit = TRUE;
sscanf(proprec->prop_value.prop_string, "%"DLONG_PREFIX"d", &result);
}
}
ddone:
if (found != (bool *) NULL) *found = haveit;
return result;
}
/* ----------------------------------------------------------------------------
*
* DBPropEnum --
@ -168,7 +292,7 @@ DBPropEnum(cellDef, func, cdata)
*
* int foo(name, value, cdata)
* char *name;
* ClientData value;
* PropertyRecord *value;
* ClientData cdata;
* {
* -- return 0 to continue,
@ -189,7 +313,7 @@ DBPropEnum(cellDef, func, cdata)
HashStartSearch(&hs);
while ((entry = HashNext(htab, &hs)) != NULL)
{
res = (*func)(entry->h_key.h_name, (ClientData) entry->h_pointer, cdata);
res = (*func)(entry->h_key.h_name, (PropertyRecord *)entry->h_pointer, cdata);
if (res != 0) return res;
}

View File

@ -303,9 +303,14 @@ typedef struct label
#define PORT_SHAPE_RING 0x1000 /* Port is a ring shape */
#define PORT_SHAPE_THRU 0x1800 /* Port is a feedthrough shape */
#define PORT_VISITED 0x2000 /* Bit for checking if a port */
#define LABEL_STICKY 0x2000 /* Label does not change layers */
#define LABEL_UNIQUE 0x4000 /* Temporary unique label */
/* The last two flags are never used at the same time and so can share
* a flag bit.
*/
#define PORT_VISITED 0x8000 /* Bit for checking if a port */
/* has been previously visited. */
#define LABEL_STICKY 0x4000 /* Label does not change layers */
#define LABEL_GENERATE 0x8000 /* Auto-generated label */
/*
@ -699,6 +704,25 @@ struct conSrArg2
#define CSA2_LIST_SIZE 65536 /* Number of entries per list */
/* ------------------------ Properties ------------------------------ */
/* Note that the property record is a single allocated block large enough
* to hold the string or integer list, and can be freed as a single block.
* The array bounds, like those of lab_text for labels, are placeholders.
*/
typedef struct
{
int prop_type; /* See codes below; e.g., PROPERTY_TYPE_STRING */
int prop_len; /* String length or number of values */
union {
char prop_string[8]; /* For PROPERTY_TYPE_STRING */
int prop_integer[2]; /* For PROPERTY_TYPE_INTEGER or _DIMENSION */
dlong prop_double[1]; /* For PROPERTY_TYPE_DOUBLE */
Plane *prop_plane; /* For PROPERTY_TYPE_PLANE */
} prop_value;
} PropertyRecord;
/* -------------- Undo information passed to DBPaintPlane ------------- */
typedef struct
@ -731,6 +755,14 @@ typedef struct
#define PAINT_MARK 1 /* Mark tiles that are painted */
#define PAINT_XOR 2 /* Use with XOR function to prevent double-painting */
/* ---------------------- Codes for properties -------------------------*/
#define PROPERTY_TYPE_STRING 0 /* ASCII string property */
#define PROPERTY_TYPE_INTEGER 1 /* Fixed integer property */
#define PROPERTY_TYPE_DIMENSION 2 /* Integer property that scales with units */
#define PROPERTY_TYPE_DOUBLE 3 /* Double-long integer (for file positions) */
#define PROPERTY_TYPE_PLANE 4 /* A tile plane structure */
/* -------------------- Exported procedure headers -------------------- */
/* Painting/erasing */
@ -916,7 +948,9 @@ extern void DBFreePaintPlane();
/* Cell properties */
extern void DBPropPut();
extern ClientData DBPropGet();
extern PropertyRecord *DBPropGet();
extern char *DBPropGetString();
extern dlong DBPropGetDouble();
extern int DBPropEnum();
extern void DBPropClearAll();
@ -1014,6 +1048,7 @@ extern int DBLambda[2];
/* -------------------- Exported magic file suffix -------------------- */
extern char *DBSuffix; /* Suffix appended to all Magic cell names */
extern bool DBPropCompat; /* Backwards-compatible properties */
/* -------------------- User Interface Stuff -------------------------- */

View File

@ -54,7 +54,7 @@ extern void CmdRandom(), CmdSave(), CmdScaleGrid(), CmdSee();
extern void CmdSelect(), CmdSetLabel(), CmdSideways();
extern void CmdShell(), CmdSnap();
extern void CmdStretch(), CmdStraighten();
extern void CmdTech(), CmdTool(), CmdUnexpand();
extern void CmdTech(), CmdTool(), CmdUnexpand(), CmdUnits();
extern void CmdUpsidedown(), CmdWhat(), CmdWire(), CmdWriteall();
extern void CmdGoto(), CmdFlatten(), CmdXload(), CmdXor();
@ -474,6 +474,9 @@ DBWInitCommands()
WindAddCommand(DBWclientID,
"unexpand unexpand subcells under box",
CmdUnexpand, FALSE);
WindAddCommand(DBWclientID,
"units [type] set type of units parsed and displayed",
CmdUnits, FALSE);
WindAddCommand(DBWclientID,
"upsidedown flip selection and box upside down",
CmdUpsidedown, FALSE);

View File

@ -25,6 +25,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include <string.h>
#include <sys/stat.h>
#include "tcltk/tclmagic.h"
#include "utils/main.h"
#include "utils/magic.h"
#include "utils/geometry.h"
@ -33,6 +34,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/hash.h"
#include "database/database.h"
#include "utils/main.h"
#include "cif/cif.h"
#include "commands/commands.h"
#include "dbwind/dbwind.h"
#include "graphics/graphics.h"
@ -653,6 +655,311 @@ DBWexit()
return (CmdWarnWrite() == 1);
}
/*
* ----------------------------------------------------------------------------
*
* dbwValueFormat ---
*
* Remove unnecessary trailing zeros and decimal from a floating-point
* value formatted with "%.Nf" where N is the expected maximum number
* of places after the decimal, matching the argument "places".
* This makes the "%f" formatting work like "%g" formatting, but
* works around the limitation of "%.Ng" that it operates on the number
* of significant digits, not the number of decimal places.
*
* Results:
* None.
*
* Side effects:
* The string "buf" may be altered with a new terminating null character.
*
* ----------------------------------------------------------------------------
*/
void
dbwValueFormat(char *buf,
int places)
{
char *p = buf + strlen(buf) - 1;
while (p > buf && *p == '0') *p-- = '\0';
if (p > buf && *p == '.') *p = '\0';
}
/*
* ----------------------------------------------------------------------------
*
* dbwPrintValue0 --
*
* Convert a value in internal database units to a string based on
* the chosen display units as defined by DBWUnits (which is set
* with the "units" command). If DBWUnits has not been changed
* since startup, then the behavior is to print the internal units
* in string form. If DBWUnits has been set, then the units type
* determines how the output is displayed.
*
* If "is_square" is TRUE, then the value is in units squared, and
* scaling is done accordingly. In the case of DBW_UNITS_USER,
* where values are in grid multiples, the units for X and Y may
* differ, and "is_x" = TRUE indicates a measurement in the X direction,
* while false indicase a measurements in the Y direction. Naturally,
* if "is_square" is TRUE then "is_x" is ignored. "is_x" is also ignored
* for any output units other than user/grid units.
*
* If "is_cif" is true, then "value" is in CIF database units
* (centimicrons, nanometers, or angstroms, according to the
* scalefactor line in the tech file), rather than internal units.
*
* This routine is generally meant to be called as one of the three
* variants defined below it: DBWPrintValue(), DBWPrintSqValue(),
* or DBWPrintCIFValue().
*
* Results:
* A pointer to a string. To facilitate printing up to four values
* (e.g., rectangle coordinates, such as from "box values"), a static
* string partitioned into four parts is created in this subroutine,
* and the result points to one position in the string, which is cycled
* through every four calls to the subroutine. The caller does not
* free the returned string.
*
* Side effects:
* None.
*
* NOTE: Prior to the introduction of the "units" command, magic had the
* inconsistent behavior that parsed input values on the command line
* would be interpreted per the "snap" setting, but output values were
* (almost) always given in internal units. This routine keeps the
* original behavior backwards-compatible, as inconsistent as it is.
*
* ----------------------------------------------------------------------------
*/
char *
dbwPrintValue0(int value, /* value to print, in internal units */
MagWindow *w, /* current window, for use with grid */
bool is_x, /* TRUE if value is an X dimension */
bool is_square, /* TRUE if value is a dimension squared */
bool is_cif) /* TRUE if value is in centimicrons */
{
char *result;
float oscale, dscale, fvalue;
DBWclientRec *crec;
int locunits;
/* This routine is called often, so avoid constant use of malloc and
* free by keeping up to four printed results in static memory.
*/
static char resultstr[128];
static unsigned char resultpos = 0;
result = &resultstr[resultpos];
resultpos += 32;
resultpos &= 127; /* At 128, cycle back to zero */
/* CIF database units are centimicrons/nanometers/angstroms as
* set by the "scalefactor" line in the tech file. When "is_cif"
* is TRUE, then "value" is in these units. Find the conversion
* factor to convert "value" to internal units, and then it can
* be subsequently converted to lambda, microns, etc.
*/
if (is_cif == TRUE)
dscale = CIFGetScale(100) / CIFGetOutputScale(1000);
else
dscale = 1.0;
/* When printing user/grid units, check for a valid window */
locunits = DBWUnits;
if (locunits != DBW_UNITS_DEFAULT) locunits &= DBW_UNITS_TYPE_MASK;
/* The MagWindow argument is only needed for user units, since the
* user grid values are found there. Setting MagWindow to NULL
* effectively disables printing values in user grid units, which
* then default to internal units.
*/
if (locunits == DBW_UNITS_USER)
{
if (w == (MagWindow *)NULL)
{
windCheckOnlyWindow(&w, DBWclientID);
if (w == (MagWindow *)NULL)
locunits = DBW_UNITS_DEFAULT;
}
}
switch (locunits)
{
case DBW_UNITS_DEFAULT:
snprintf(result, 32, "%d", value);
break;
case DBW_UNITS_INTERNAL:
if (is_cif)
{
if (is_square)
{
snprintf(result, 32, "%.6f", value * dscale * dscale);
dbwValueFormat(result, 6);
}
else
{
snprintf(result, 32, "%.3f", value * dscale);
dbwValueFormat(result, 3);
}
}
else
snprintf(result, 32, "%d", value);
if (is_square)
{
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 29))
strcat(result, "i^2");
}
else
{
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 31))
strcat(result, "i");
}
break;
case DBW_UNITS_LAMBDA:
oscale = (float)DBLambda[0];
oscale /= (float)DBLambda[1];
if (is_square)
{
fvalue = (float)value * oscale * oscale * dscale * dscale;
snprintf(result, 32, "%0.6f", (double)fvalue);
dbwValueFormat(result, 6);
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 29))
strcat(result, "l^2");
}
else
{
fvalue = (float)value * oscale * dscale;
snprintf(result, 32, "%0.3f", (double)fvalue);
dbwValueFormat(result, 3);
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 31))
strcat(result, "l");
}
break;
case DBW_UNITS_MICRONS:
oscale = CIFGetOutputScale(1000);
if (is_square)
{
fvalue = (float)value * oscale * oscale * dscale * dscale;
snprintf(result, 32, "%0.6f", (double)fvalue);
dbwValueFormat(result, 6);
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 28))
strcat(result, "um^2");
}
else
{
fvalue = (float)value * oscale * dscale;
snprintf(result, 32, "%0.3f", (double)fvalue);
dbwValueFormat(result, 3);
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 30))
strcat(result, "um");
}
break;
case DBW_UNITS_USER:
if (is_square)
{
oscale = (float)((crec->dbw_gridRect.r_xtop -
crec->dbw_gridRect.r_xbot) *
(crec->dbw_gridRect.r_ytop -
crec->dbw_gridRect.r_ybot));
}
else if (is_x)
{
oscale = (float)(crec->dbw_gridRect.r_xtop -
crec->dbw_gridRect.r_xbot);
}
else
{
oscale = (float)(crec->dbw_gridRect.r_ytop -
crec->dbw_gridRect.r_ybot);
}
fvalue = (float)value * oscale * dscale;
if (is_square)
{
fvalue *= dscale;
snprintf(result, 32, "%0.6f", (double)fvalue);
dbwValueFormat(result, 6);
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 27))
strcat(result, "gx*gy");
}
else
{
snprintf(result, 32, "%0.3f", (double)fvalue);
dbwValueFormat(result, 3);
if (is_x)
{
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 30))
strcat(result, "gx");
}
else
{
if ((DBWUnits & DBW_UNITS_PRINT_FLAG) && (strlen(result) < 30))
strcat(result, "gy");
}
}
break;
}
return result;
}
/*
* ----------------------------------------------------------------------------
*
* DBWPrintValue --
* DBWPrintSqValue --
* DBWPrintCIFValue --
* DBWPrintCIFSqValue --
*
* Convenience functions which call dbwPrintValue0() with specific
* fixed arguments, so that the calls are not full of boolean values.
* The "is_x" boolean is retained because it is used often.
*
* ----------------------------------------------------------------------------
*/
char *
DBWPrintValue(int value, /* value to print, in internal units */
MagWindow *w, /* current window, for use with grid */
bool is_x) /* TRUE if value is an X dimension */
{
/* Call dbwPrintValue0() with is_square = FALSE and is_cif = FALSE */
return dbwPrintValue0(value, w, is_x, FALSE, FALSE);
}
char *
DBWPrintSqValue(int value, /* value to print, in internal units */
MagWindow *w) /* current window, for use with grid */
{
/* Call dbwPrintValue0() with is_square = TRUE and is_cif = FALSE */
/* is_x is set to TRUE although it is unused. */
return dbwPrintValue0(value, w, TRUE, TRUE, FALSE);
}
char *
DBWPrintCIFValue(int value, /* value to print, in internal units */
MagWindow *w, /* current window, for use with grid */
bool is_x) /* TRUE if value is an X dimension */
{
/* Call dbwPrintValue0() with is_square = FALSE and is_cif = TRUE */
return dbwPrintValue0(value, w, is_x, FALSE, TRUE);
}
char *
DBWPrintCIFSqValue(int value, /* value to print, in internal units */
MagWindow *w) /* current window, for use with grid */
{
/* Call dbwPrintValue0() with is_square = TRUE and is_cif = TRUE */
/* is_x is set to TRUE although it is unused. */
return dbwPrintValue0(value, w, TRUE, TRUE, TRUE);
}
/*
* ----------------------------------------------------------------------------
*

View File

@ -65,11 +65,21 @@ typedef struct _crosshairRec {
static CrosshairRec curCrosshair; /* Crosshair position */
/*
* If the following is DBW_SNAP_USER, the box gets snapped to the user's
* If the following is DBW_UNITS_USER, the box gets snapped to the user's
* grid always, instead of snapping to the usual 1x1 grid. If the value
* is DBW_SNAP_INTERNAL, the box gets snapped to the internal grid.
* is DBW_UNITS_INTERNAL, the box gets snapped to the internal grid.
*/
int DBWSnapToGrid = DBW_SNAP_LAMBDA;
int DBWSnapToGrid = DBW_UNITS_LAMBDA;
/*
* The original behavior with respect to units was that un-suffixed
* values follow whatever the snap setting is (DBWSnapToGrid, above).
* Current behavior is that the original behavior is followed while
* DBWUnits is set to DBW_UNITS_DEFAULT. However, if the "units"
* command is given, then displayed and entered units follow that
* value independently of the snap setting.
*/
int DBWUnits = DBW_UNITS_DEFAULT;
/* Forward reference: */
@ -82,8 +92,8 @@ extern int DBWToolDraw();
* toolFindPoint --
*
* Returns the point in root coordinates.
* If DBWSnapToGrid is DBW_SNAP_USER, pick the nearest point that is
* aligned with the window's grid. If DBWSnapToGrid is DBW_SNAP_LAMBDA,
* If DBWSnapToGrid is DBW_UNITS_USER, pick the nearest point that is
* aligned with the window's grid. If DBWSnapToGrid is DBW_UNITS_LAMBDA,
* pick the nearest point that is an integer lambda value.
*
* Results:
@ -120,7 +130,7 @@ toolFindPoint(p, rootPoint, rootArea)
if (!GEO_ENCLOSE(p, &WindCurrentWindow->w_screenArea)) return NULL;
WindPointToSurface(WindCurrentWindow, p, rootPoint, rootArea);
if (DBWSnapToGrid != DBW_SNAP_INTERNAL)
if (DBWSnapToGrid != DBW_UNITS_INTERNAL)
ToolSnapToGrid(WindCurrentWindow, rootPoint, rootArea);
return WindCurrentWindow;
@ -844,8 +854,8 @@ DBWResetBox(CellDef *def)
* Repositions the box by one of its corners.
* If the point given to reposition the box is in screen coordinates,
* the box corner is snapped to the user's grid (set with the :grid
* command) if DBWSnapToGrid is DBW_SNAP_USER. If DBWSnapToGrid is
* DBW_SNAP_LAMBDA, the box corner is snapped to the nearest integer
* command) if DBWSnapToGrid is DBW_UNITS_USER. If DBWSnapToGrid is
* DBW_UNITS_LAMBDA, the box corner is snapped to the nearest integer
* lambda value.
*
* Results:
@ -948,8 +958,8 @@ ToolMoveBox(corner, point, screenCoords, rootDef)
*
* If the point given to reposition the box is in screen coordinates,
* the box corner is snapped to the user's grid (set with the :grid
* command) if DBWSnapToGrid is DBW_SNAP_USER. If DBWSnapToGrid is
* DBW_SNAP_LAMBDA, the box corner is snapped to the nearest integer
* command) if DBWSnapToGrid is DBW_UNITS_USER. If DBWSnapToGrid is
* DBW_UNITS_LAMBDA, the box corner is snapped to the nearest integer
* lambda value.
*
* Results:
@ -1092,7 +1102,7 @@ ToolSnapToGrid(w, p, rEnclose)
if (crec == NULL || p == NULL)
return;
if (DBWSnapToGrid == DBW_SNAP_LAMBDA)
if (DBWSnapToGrid == DBW_UNITS_LAMBDA)
{
lr.r_xbot = lr.r_ybot = 0;
lr.r_xtop = DBLambda[1] / DBLambda[0];

View File

@ -113,6 +113,7 @@ typedef struct DBW1 {
extern WindClient DBWclientID;
extern int DBWSnapToGrid;
extern int DBWUnits;
extern int DBWMaxTechStyles;
extern int DBWMaxTileStyles;
@ -121,13 +122,17 @@ extern int DBWNumStyles;
extern int RtrPolyWidth, RtrMetalWidth, RtrContactWidth;
/*
* Exported procedure headers for redisplay
* Exported procedure headers for redisplay and output
*/
extern int DBWWatchTiles();
extern void DBWAreaChanged();
extern void DBWLabelChanged();
extern void DBWDrawLabel();
extern char *DBWPrintValue(int value, MagWindow *w, bool is_x);
extern char *DBWPrintSqValue(int value, MagWindow *w);
extern char *DBWPrintCIFValue(int value, MagWindow *w, bool is_x);
extern char *DBWPrintCIFSqValue(int value, MagWindow *w);
/*
* Exported procedures and variables related to the technology file
@ -169,14 +174,36 @@ extern void DBWBoxHandler();
#define TOOL_ILG -1
/* The following defines are used to indicate which coordinate system
* the cursor box snaps to when moved with mouse clicks (values for
* DBWSnapToGrid).
* is used when displaying or returning values. By default this is
* set to DBW_UNITS_INTERNAL. From magic version 8.3.595, this is
* independently set from "snap". For backwards compatibility,
* the value starts as DBW_UNITS_DEFAULT which implements the original
* behavior in which the "snap" setting dictates the dispaly units.
* Only if set to a non-negative value do the display units operate
* independently of the snap setting.
*
* NOTES:
* Lambda units are fixed by the tech file.
* Internal units are scalable.
* User units are scalable; this can be used, for example, to
* set a box position according to multiples of a track
* pitch, but is most often used manually with the "g"
* (for "grid") suffix; e.g., "move box e 1g"
* Micron units are dependent on the specified cifoutput style
* and how the tech file defines the scalefactor for it.
*/
#define DBW_SNAP_INTERNAL 0 /* internal units (fine grid) */
#define DBW_SNAP_LAMBDA 1 /* lambda units (coarse grid) */
#define DBW_SNAP_USER 2 /* user grid units (user grid) */
#define DBW_SNAP_MICRONS 3 /* micron units */
#define DBW_UNITS_DEFAULT -1 /* backwards-compatible behavior */
#define DBW_UNITS_INTERNAL 0 /* internal units */
#define DBW_UNITS_LAMBDA 1 /* lambda units */
#define DBW_UNITS_USER 2 /* user grid units */
#define DBW_UNITS_MICRONS 3 /* micron units */
#define DBW_UNITS_TYPE_MASK 3 /* everything but the flag field(s) */
#define DBW_UNITS_PRINT_FLAG 4 /* flag used to indicate that
* the units should be printed
* with the value; e.g.,
* "10um" instead of "10".
*/
/* The following window mask can be used to select all database windows
* for things like the mask parameter to DBWAreaChanged.

View File

@ -334,23 +334,23 @@
</TR>
<TR>
<TD> <A HREF=undo.html> <B>undo</B></A> </TD>
<TD> <A HREF=units.html> <B>units</B></A> </TD>
<TD> <A HREF=updatedisplay.html> <B>updatedisplay</B></A> </TD>
<TD> <A HREF=version.html> <B>version</B></A> </TD>
</TR>
<TR>
<TD> <A HREF=version.html> <B>version</B></A> </TD>
<TD> <A HREF=view.html> <B>view</B></A> </TD>
<TD> <A HREF=windowborder.html> <B>windowborder</B></A> </TD>
<TD> <A HREF=windowcaption.html> <B>windowcaption</B></A> </TD>
</TR>
<TR>
<TD> <A HREF=windowcaption.html> <B>windowcaption</B></A> </TD>
<TD> <A HREF=windownames.html> <B>windownames</B></A> </TD>
<TD> <A HREF=windowscrollbars.html> <B>windowscrollbars</B></A> </TD>
<TD> <A HREF=xview.html> <B>xview</B></A> </TD>
</TR>
<TR>
<TD> <A HREF=xview.html> <B>xview</B></A> </TD>
<TD> <A HREF=zoom.html> <B>zoom</B></A> </TD>
<TD> <A HREF=tk_path_name.html> <I>tk_path_name</I></A> </TD>
<TD> </TD>
</TR>
</TBODY>
</TABLE>

View File

@ -117,6 +117,7 @@ techmanager
tool
undo
unexpand
units
updatedisplay
upsidedown
version

View File

@ -42,9 +42,11 @@ Circuit netlist extractor
<DL>
<DT> <B>capacitance</B>
<DD> Extract local parasitic capacitance values to substrate
<DT> <B>resistance</B>
<DD> Extract lumped resistance values. Note that this
is <I>not</I> the same as full parasitic resistance.
<DT> <B>coupling</B>
<DD> Extract the parasitic coupling capacitance between
nodes.
<DT> <B>lumped</B>
<DD> Extract lumped resistance values.
The values extracted are "lumped" resistance and
indicate the value for which the delay through the
net can be computed with R times C, where R is the
@ -55,9 +57,10 @@ Circuit netlist extractor
command. Lumped resistances have no meaning in
SPICE netlists and will only be used when running
<B>ext2sim</B> to generate a .sim netlist.
<DT> <B>coupling</B>
<DD> Extract the parasitic coupling capacitance between
nodes.
Prior to magic version 8.3.597, this option was
<B>resistance</B>, but as that was often confused
with full parasitic resistance extraction, it has
been changed.
<DT> <B>length</B>
<DD> Extract the length of the shortest path from a driver
to a receiver, for computing more accurate parasitic
@ -73,7 +76,7 @@ Circuit netlist extractor
array instances, is guaranteed to be strictly positive.
<DT> <B>all</B>
<DD> Apply all standard options (does not include options
"local", "labelcheck", or "aliases").
"local", "labelcheck", "aliases", or "resistance").
<DT> <B>local</B>
<DD> Write all .ext files to the current working directory.
If not specified, each .ext file will be placed in the
@ -99,6 +102,28 @@ Circuit netlist extractor
but will usually just slow down processing by commands
like "ext2spice" that use the .ext file contents, so it
is disabled by default.
<DT> <B>unique</B>
<DD> (Added in magic version 8.3.594) This setting replaces
the use of the command option "extract unique". Instead
of changing labels in the design, unique labels are
generated for the duration of the extraction, and then
reverted back to the original text. The "extract unique"
command option is maintained for backwards compatibility.
Note the difference: "extract unique" is a command that
runs immediately, and cannot be undone;
"extract do unique" is an option setting for "extract".
<DT> <B>resistance</B>
<DD> (Added in magic version 8.3.597) This setting replaces
the use of the standalone command "extresist". The
effect is the same: Magic performs full R-C extraction,
generating a <TT>.res.ext</TT> file that annotates the
existing <TT>.ext</TT> file (see the "extresist" command
documentation). The "extresist" command options can
still be used to set options such as tolerance for the
R-C extraction.
Note that prior to magic version 8.3.597, this option
name would produce the lumped resistance approximation
(see <B>lumped</B>, above).
</DL>
</BLOCKQUOTE>
These options (except for "local") determine how much
@ -213,7 +238,9 @@ Circuit netlist extractor
<I>Warning:</I> This operation immediately modifies the
existing layout in preparation for extraction. Label
modifications are permanent, and cannot be undone. All
cells in the hierarchy may potentially be modified. <BR>
cells in the hierarchy may potentially be modified. To avoid
this issue, use the "extract do unique" option instead (see
above). <BR>
<DT> <B>warn</B> [[<B>no</B>] <I>option</I>]
<DD> Enable/disable reporting of non-fatal errors, where <I>option</I>
may be one of the following:

View File

@ -92,17 +92,25 @@ information.
The <B>extresist</B> command provides a method for generating
a more detailed model of resistance, in which long network
routes and branching routes are replaced with resistor devices
and device networks. <P>
and device networks. This is known as "full R-C extraction". <P>
Using <B>extresist</B> is a multi-step process. It is first
necessary to run both <B>extract</B> and <B>ext2sim</B> to get
the initial netlist (with lumped, not detailed, resistances).
After a <TT>.sim</TT> file has been generated, the
<B>extresist all</B> command may be run. The output is
Using <B>extresist</B> as a standalone command is a multi-step
process. It is first necessary to run <B>extract</B> to get
the initial netlist.
After a <TT>.ext</TT> file has been generated, the
<B>extresist</B> command may be run. The output is
a file <TT>.res.ext</TT> for each cell in the hierarchy.
Finally, with the option <B>extresist on</B> set,
<B>ext2sim</B> or <B>ext2spice</B> will generate the final,
detailed simulation file. <P>
Finally, with the option <B>extresist on</B> set, <B>ext2spice</B>
will generate the final, detailed simulation file. <P>
Prior to magic version 8.3.597, it was also necessary to run
<B>ext2sim labels on</B> and <B>ext2sim</B> to write out a
<TT>.sim</TT> and a <TT>.node</TT> file before running
<B>extresist</B>. This is no longer necessary. There is since
magic version 8.3.597 an option <B>extract do resistance</B>
that runs the resistance extraction in sequence with the regular
extraction, producing both the <TT>.ext</TT> and <TT>.res.ext</TT>
files.
More details on using <B>extresist</B> can be found in
<B>magic</B> Tutorial number 8.
@ -117,6 +125,7 @@ information.
<BLOCKQUOTE>
<A HREF=extract.html><B>extract</B></A> <BR>
<A HREF=ext2sim.html><B>ext2sim</B></A> <BR>
<A HREF=ext2spice.html><B>ext2spice</B></A> <BR>
</BLOCKQUOTE>
<P><IMG SRC=graphics/line1.gif><P>

View File

@ -182,6 +182,13 @@ Read GDSII input or generate GDSII output.
than to subsplit the internal grid to such a fine value.
The "<B>cif limit</B>" function may also be used to limit
grid subdivision to a minimum value.
<DT> <B>savepaths</B> [<B>yes</B>|<B>no</B>]
<DD> When reading paths from a GDS file, record the centerline of
the path as a property in the cell. The default behavior is
<B>no</B>. If no argument is given, then return the status
of the <B>savepaths</B> option. The first path property is
named "<TT>path</TT>", followed by "<TT>path_0</TT>" and
increasing the suffix index for each individual path read.
<DT> <B>unique</B> [<B>yes</B>|<B>no</B>]
<DD> When reading a GDS file, this option forces magic to rename
cell definitions in the database when a cell of the same name

View File

@ -87,6 +87,50 @@ Place a label in the layout
to another layer. <P>
</BLOCKQUOTE>
<BLOCKQUOTE>
<B>Attribute labels:</B> <P>
A handful of labels are referred to as "attribute" labels. These
label types are placed on devices and affect how the device is
extracted. <P>
A label that is placed inside a device (e.g., a MOSFET gate) which
ends with the character "<B>^</B>" is a <I>gate attribute</I>. A
gate attribute in the form of "<I>name</I><B>=</B><I>value</I><B>^</B>"
specifies an extra parameter to be passed to the device in addition
to the standard parameters calculated for that device. This is used
to capture parameters which cannot easily be inferred from the layout.
For example, an RF device model might be distinguished from a non-RF
device model by a parameter such as <B>rfmode=1</B>. Whether or not
a device is intended for RF use is not easily guessed from the layout,
and so "tagging" the gate with the parameter allows the correct model
parameters to be used for the device. <P>
A gate attribute that is not in the form of a parameter will be used
as the device's instance index in the netlist; e.g., a label of
"<B>1^</B>" on a MOSFET gate extracted as a MOSFET device would be an
entry "<B>M1</B>" in the netlist. This can be used to better track
device indexes between a schematic and layout. <P>
A label that is placed on the <I>edge</I> a device, specificlly a
MOSFET gate, and which ends with the character "<B>$</B>", is a
<I>terminal attribute</I>. The only terminal attributes recognized
by magic are <B>S$</B> and <B>D$</B>, which specify which side of the
gate is to be considered the source and which is to be considered the
drain. Generally, MOSFET devices are symmetric, and their use in a
simulation does not depend on which side is in the position of the
"source" and which is in the position of the "drain". To the extent
that it matters, the terminal attributes can be used to ensure that
the source and drain connections appear in the netlist in their
intended orientation. <P>
Labels ending with "<B>@</B>" are <I>node attributes</I>. There is
currently no functional application for node attributes. When one
is applied, it will appear in the output netlist in a SPICE comment
line indicating the node and attribute. This could be used, say,
by a post-processing script, but as it is in a comment line, it has
no impact on simulation or LVS.
</BLOCKQUOTE>
<H3>Implementation Notes:</H3>
<BLOCKQUOTE>
<B>label</B> is implemented as a built-in command in <B>magic</B>.

View File

@ -25,9 +25,13 @@ Attach a "property" (string key and value pair) to the edit cell
<H3>Usage:</H3>
<BLOCKQUOTE>
<B>property</B> [<I>key</I> [<I>value</I>]] <BR><BR>
<B>property</B> [<I>list</I>] [<I>type</I>] [<I>key</I> [<I>value</I>]] <BR>
or
<B>property</B> [<B>compat</B>] [<B>true</B>|<B>false</B>] <BR><BR>
<BLOCKQUOTE>
where <I>key</I> and <I>value</I> are any text strings.
where <I>key</I> and <I>value</I> are any text strings. <BR>
<I>type</I> may be one of <B>string</B>, <B>integer</B>,
<B>dimension</B>, or <B>double</B>.
</BLOCKQUOTE>
</BLOCKQUOTE>
@ -45,11 +49,64 @@ Attach a "property" (string key and value pair) to the edit cell
with the key is returned. With both arguments, the string
<I>value</I> is associated with the string <I>key</I> as a
property of the cell. If <I>key</I> is an existing key, then
its original value will be overwritten.
its original value will be overwritten. <P>
By default, properties are interpreted as verbatim string values,
with exceptions for the reserved types (see below). To force the
values of the property to be interpreted as a specific type, use
the <I>type</I> option. <P>
The <B>property compat</B> setting determines how properties are
written out to a .mag file. The default setting is <B>true</B>
(backwards compatibility mode), which writes all properties as
type "<TT>string</TT>". Properties which are reserved names
(see below) will be converted to the best type when reading the
.mag file. However, if the user wants to create a property that
is handled differently than a string (namely, to be a dimensional
value that scales), then comptability mode should be turned off. <P>
If the argument <I>list</I> is given as the first argument, and
<I>value</I> is not present, then if the property <I>key</I>
does not exist, then the command will return a NULL object to the
interpreter instead of printing an error message. This is the
"quiet" version of the command preferred for scripts that want to
query whether or not a specific property exists.
</BLOCKQUOTE>
<BLOCKQUOTE>
Property names reserved by and used by magic:
Types are interpreted as follows:
<DL>
<DT> <B>string</B> type:
<DD> The property value is a character string. Character strings
may contain spaces, but if so, then the string should be quoted
or in braces, per Tcl syntax.
<DT> <B>integer</I> type:
<DD> The property value is an integer value or a list of integer
values. The values are not considered to be measurements and
do not scale. Multiple values may be passed on the command
line as additional arguments, or the set of values may be
given as a list.
<DT> <B>dimension</I> type:
<DD> The property value is an integer value or a list of integer
values. The values are considered to be (linear) dimensional
measurements and therefore scale with the database internal
units. They are interpreted as having the values currently
specified for <B>units</B>, and display back in the same
units. Multiple values may be passed on the command line as
additional arguments, or the set of values may be given as a
list.
<DT> <B>double</I> type:
<DD> The property value is a double-wide (64-bit) integer value or
a list of double-wide integer values. The values are not
considered to be measurements and do not scale. Multiple
values may be passed on the command line as additional arguments,
or the set of values may be given as a list.
</DL>
</BLOCKQUOTE>
<BLOCKQUOTE>
Property names reserved by and used by magic (types are <B>string</B>
unless otherwise noted):
<DL>
<DT> <B>GDS_FILE</B>
<DD> The value is the name of a GDS file which contains the mask
@ -60,12 +117,14 @@ Attach a "property" (string key and value pair) to the edit cell
<DD> If a <B>GDS_FILE</B> is defined, then this value indicates the
byte position of the start of mask data for this cell definition
in the file. If set to value <B>0</B>, then the file will be
searched for the data bounds.
searched for the data bounds. This property is always of type
<B>double</B>.
<DT> <B>GDS_END</B>
<DD> If a <B>GDS_FILE</B> is defined, then this value indicates the
byte position of the end of mask data for this cell definition
in the file. If <B>GDS_START</B> is set to <B>0</B>, then this
property may be omitted.
property may be omitted. This property is always of type
<B>double</B>.
<DT> <B>LEFview</B>
<DD> If set to <B>TRUE</B>, this cell is an abstract view such as that
obtained from a LEF macro, and should not be used for extraction
@ -97,6 +156,8 @@ Attach a "property" (string key and value pair) to the edit cell
corresponding to the abutment box of the cell, in magic's internal
units. The abutment box is automatically read from LEF files, but
may be defined for any file and can be used for placement alignment.
This property is always of type <B>dimension</B> and must contain
exactly four values.
<DT> <B>OBS_BBOX</B>
<DD> This property value is a space-sparated list of four integer values
corresponding to a bounding box to be used when generating a LEF
@ -104,7 +165,8 @@ Attach a "property" (string key and value pair) to the edit cell
will be entirely covered in obstruction layers (unless cut-outs
are required to accommodate pins). Any set-back applied by the
"lef write -hide <value>" option will be applied to this obstruction
box.
box. This property is always of type <B>dimension</B> and must
contain exactly four values.
<DT> <B>flatten</B>
<DD> This property is used in conjunction with the "flatten -doproperty"
command option and marks the cell for flattening. Cells without
@ -146,7 +208,8 @@ Attach a "property" (string key and value pair) to the edit cell
always generate mask layer <I>type</I> in the specified rectangle
area when writing GDS or CIF output. <I>type</I> may be a templayer,
such that <I>type</I> could be defined as the absence of a mask layer,
for example.
for example. This property is always of type <B>dimension</B> and
must have a multiple of four values.
</DL>
</BLOCKQUOTE>
@ -157,6 +220,11 @@ Attach a "property" (string key and value pair) to the edit cell
the cell definition structure.
</BLOCKQUOTE>
<H3>See Also:</H3>
<BLOCKQUOTE>
<A HREF=units.html><B>units</B></A> <BR>
</BLOCKQUOTE>
<P><IMG SRC=graphics/line1.gif><P>
<TABLE BORDER=0>
<TR>

View File

@ -39,21 +39,15 @@ in the selected grid.
feature size, and <B>user</B>, based on the value given by the
user to the <B>grid</B> command. <P>
In addition to changing the behavior of the box to mouse
button events, the <B>snap</B> command also changes the way
that <A HREF=distance.html>distance measurements</A> are
interpreted in commands that take distance arguments, such
as <B>move</B>, <B>copy</B>, and <B>stretch</B>. An integer
number with no other identifying units is interpreted as a
measurement in the current snap grid. All other measurements
must have an identifying unit: <B>i</B> for internal units,
<B>l</B> for lambda units, and <B>g</B> for user grid units
(as well as the usual metric units). Even when <B>snap</B>
is set to the larger lambda or user grids, it is possible to
move the cursor box to finer grid positions from the command
line. See the reference page on
<A HREF=distance.html>distance measures</A> for a complete
description of distance values. <P>
Historically, in addition to changing the behavior of the box
to mouse button events, the <B>snap</B> command also changed
the way that <A HREF=distance.html>distance measurements</A>
are interpreted in commands that take distance arguments.
This behavior remains the default for backwards compatibility.
The <B>units</B> command overrides this behavior and allows
<B>snap</B> to control only the box positioning behavior,
independently of how unsuffixed values are parsed by the
interpreter. <P>
<B>snap</B> with no arguments returns the current snap grid
type. <P>
@ -80,6 +74,7 @@ in the selected grid.
<H3>See Also:</H3>
<BLOCKQUOTE>
<A HREF=units.html><B>units</B></A> <BR>
<A HREF=grid.html><B>grid</B></A> <BR>
</BLOCKQUOTE>

102
doc/html/units.html Normal file
View File

@ -0,0 +1,102 @@
<HTML>
<HEAD>
<STYLE type="text/css">
H1 {color: black }
H2 {color: maroon }
H3 {color: #007090 }
A.head:link {color: #0060a0 }
A.head:visited {color: #3040c0 }
A.head:active {color: white }
A.head:hover {color: yellow }
A.red:link {color: red }
A.red:visited {color: maroon }
A.red:active {color: yellow }
</STYLE>
</HEAD>
<TITLE>Magic-8.3 Command Reference</TITLE>
<BODY BACKGROUND=graphics/blpaper.gif>
<H1> <IMG SRC=graphics/magic_title8_3.png ALT="Magic VLSI Layout Tool Version 8.3">
<IMG SRC=graphics/magic_OGL_sm.gif ALIGN="top" ALT="*"> </H1>
<H2>units</H2>
<HR>
Cause distance measurements to be interpreted by default (with no
suffix provied) as measurments of the selected units, and also cause
distance measurements to be printed in the selected units.
<HR>
<H3>Usage:</H3>
<BLOCKQUOTE>
<B>units</B> [<B>internal</B>|<B>lambda</B>|<B>user</B>|<B>grid</B>|<B>microns</B>|<B>default</B>] [<B>print</B>|</B>noprint</B>] <BR>
or <BR>
<B>units</B> [<B>list</B>] <BR><BR>
</BLOCKQUOTE>
<H3>Summary:</H3>
<BLOCKQUOTE>
The <B>units</B> command causes printed measurements to be
given in the selected units. The possible unit types are
<B>internal</B>, the size of the internal database units,
<B>lambda</B>, the lambda grid based on the technology minimum
feature size, <B>user</B> (or <B>grid</B>), based on the
value given by the user to the <B>grid</B> command, or
<B>microns</B>, which are physical units dependent on the
CIF or GDS output scaling as defined in the technology file. <P>
The <B>units</B> command also changes the way
that <A HREF=distance.html>distance measurements</A> are
interpreted in commands that take distance arguments, such
as <B>move</B>, <B>copy</B>, and <B>stretch</B>. An integer
number with no other identifying units is interpreted as a
measurement in the current units type. All other measurements
must have an identifying unit: <B>i</B> for internal units,
<B>l</B> for lambda units, and <B>g</B> for user grid units,
as well as the usual metric units such as <B>um</B> for
microns, <B>nm</B> for nanometers, and so forth. See the
reference page on <A HREF=distance.html>distance measures</A>
for a complete description of distance values. <P>
For printed units, the additional argument <B>print</B>
causes the units to be printed along with the value; e.g.,
"<B>1.0um</B>." This is the usual setting for interactive
use. The argument <B>noprint</B> suppresses the unit name,
which is appropriate for scripted use, when the value may
be passed to arithmetic expressions to be evaluated by the
interpreter. <P>
<B>units</B> with no arguments returns the current units type.
<B>units list</B> returns the current units type as a Tcl list
of two items; the first item is the units type, and the second
item is <B>print</B> or <B>noprint</B>, indicating whether units
suffixes are printed with the values. <P>
Historically, values parsed from the command line were interpreted
according to the <B>snap</B> setting. On startup, this behavior
remains in effect for backwards compatibility until overridden
with a <B>units</B> command. The command <B>units default</B>
reverts back to the original behavior. Once the <B>units</B>
default type is overridden, the <B>snap</B> behavior is controlled
independently of <B>units</B>. <P>
</BLOCKQUOTE>
<H3>Implementation Notes:</H3>
<BLOCKQUOTE>
<B>units</B> is implemented as a built-in command in <B>magic</B>.
</BLOCKQUOTE>
<H3>See Also:</H3>
<BLOCKQUOTE>
<A HREF=grid.html><B>grid</B></A> <BR>
<A HREF=snap.html><B>snap</B></A> <BR>
</BLOCKQUOTE>
<P><IMG SRC=graphics/line1.gif><P>
<TABLE BORDER=0>
<TR>
<TD> <A HREF=commands.html>Return to command index</A>
</TR>
</TABLE>
<P><I>Last updated:</I> March 7, 2020 at 1:06pm <P>
</BODY>
</HTML>

View File

@ -45,10 +45,12 @@ view [get|bbox|llx lly urx ury]
center and scale the screen view of the layout window to fit the layout. <P>
<B>view bbox</B> returns the bounding box dimensions of the layout,
in the coordinate system of the layout. <P>
in the coordinate system of the layout (according to the units
set by the "units" command). <P>
<B>view get</B> returns the coordinates of the screen limits in
the coordinate system of the layout (internal database units). <P>
the coordinate system of the layout (according to the units set
by the "units" command). <P>
<B>view</B> <I>llx lly urx ury</I> sets the view so that the
corners of the screen are at the indicated positions in the

View File

@ -45,7 +45,7 @@ extern int drcArrayYankFunc(), drcArrayOverlapFunc();
static DRCCookie drcArrayCookie = {
0, 0, 0, 0,
{ {0} }, { {0} },
0, 0, 0,
0, DRC_EXCEPTION_NONE, 0, 0,
DRC_ARRAY_OVERLAP_TAG,
(DRCCookie *) NULL
};

View File

@ -27,6 +27,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include <stdio.h>
#include <string.h> // for memcpy()
#include <math.h> // for sqrt() for diagonal check
#include "tcltk/tclmagic.h"
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
@ -36,7 +38,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/signals.h"
#include "utils/maxrect.h"
#include "utils/malloc.h"
#include "utils/undo.h"
#include "textio/textio.h"
#include "cif/CIFint.h"
int dbDRCDebug = 0;
@ -48,7 +52,7 @@ int dbDRCDebug = 0;
static DRCCookie drcOverlapCookie = {
0, 0, 0, 0,
{ {0} }, { {0} },
0, 0, 0,
0, DRC_EXCEPTION_NONE, 0, 0,
DRC_OVERLAP_TAG,
(DRCCookie *) NULL
};
@ -62,7 +66,33 @@ extern MaxRectsData *drcCanonicalMaxwidth();
/*
*-----------------------------------------------------------------------
*
* drcCifPointToSegment
* drcFoundOneFunc --
*
* Simple callback for a plane search on a mask-hint plane inside
* a DRC check area.
*
* Results:
* Return 1 always, indicating that a tile has been found in the
* DRC search area, and the search can end.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------
*/
int
drcFoundOneFunc(Tile *tile,
TileType dinfo,
ClientData cdata)
{
return 1;
}
/*
*-----------------------------------------------------------------------
*
* drcCifPointToSegment --
*
* Euclidean-distance point-to-segment distance (squared)
* calculation (borrowed from XCircuit)
@ -468,6 +498,13 @@ DRCBasicCheck (celldef, checkRect, clipRect, function, cdata)
DBResetTilePlane(celldef->cd_planes[planeNum], DRC_UNPROCESSED);
(void) DBSrPaintArea ((Tile *) NULL, celldef->cd_planes[planeNum],
checkRect, &DBAllTypeBits, drcTile, (ClientData) &arg);
#ifdef MAGIC_WRAPPER
/* Execute pending Tcl events, so the DRC process doesn't block. */
UndoEnable();
while (Tcl_DoOneEvent(TCL_DONT_WAIT));
UndoDisable();
#endif
}
drcCifCheck(&arg);
if (arg.dCD_rlist != NULL) freeMagic(arg.dCD_rlist);
@ -727,6 +764,43 @@ drcTile (tile, dinfo, arg)
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
cptr = cptr->drcc_next)
{
/* Handle rule exceptions and exemptions */
if (cptr->drcc_exception != (char)DRC_EXCEPTION_NONE)
{
PropertyRecord *proprec;
bool propfound, isinside = FALSE;
char *name;
char idx = cptr->drcc_exception;
if (idx < 0) idx = -idx - 1;
name = DRCCurStyle->DRCExceptionList[idx];
/* Is there any exception area defined? */
proprec = DBPropGet(arg->dCD_celldef, name, &propfound);
/* If an exception area exists, is the error edge inside? */
if (propfound)
{
Rect redge;
redge.r_xbot = redge.r_xtop = edgeX;
redge.r_ybot = edgeBot;
redge.r_ytop = edgeTop;
if (DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
proprec->prop_value.prop_plane,
&redge, &CIFSolidBits, drcFoundOneFunc,
(ClientData)NULL) == 1)
isinside = TRUE;
}
/* Exemption rules are ignored if the edge is inside
* an exception area. Exception rules are ignored if
* the edge is outside an exception area.
*/
if (!isinside && (cptr->drcc_exception >= 0)) continue;
if (isinside && (cptr->drcc_exception < 0)) continue;
}
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
/* the code above for non-Manhattan shapes and do not */
/* need to be processed again. */
@ -1136,6 +1210,49 @@ drcTile (tile, dinfo, arg)
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
cptr = cptr->drcc_next)
{
/* Handle rule exceptions and exemptions */
if (cptr->drcc_exception != (char)DRC_EXCEPTION_NONE)
{
PropertyRecord *proprec;
bool propfound, isinside = FALSE;
char *name;
char idx = cptr->drcc_exception;
if (idx < 0) idx = -idx - 1;
name = DRCCurStyle->DRCExceptionList[idx];
/* Is there any exception area defined? */
proprec = DBPropGet(arg->dCD_celldef, name, &propfound);
/* Quickest case: Rule is an exception but there are no
* exception areas.
*/
if ((!propfound) && (cptr->drcc_exception >= 0))
continue;
/* If an exception area exists, is the error edge inside? */
if (propfound)
{
Rect redge;
redge.r_ybot = redge.r_ytop = edgeY;
redge.r_xbot = edgeLeft;
redge.r_xtop = edgeRight;
if (DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
proprec->prop_value.prop_plane,
&redge, &CIFSolidBits, drcFoundOneFunc,
(ClientData)NULL) == 1)
isinside = TRUE;
}
/* Exemption rules are ignored if the edge is inside
* an exception area. Exception rules are ignored if
* the edge is outside an exception area.
*/
if (isinside && (cptr->drcc_exception < 0)) continue;
if (!isinside && (cptr->drcc_exception >= 0)) continue;
}
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
/* the code above for non-Manhattan shapes and do not */
/* need to be processed again. */

View File

@ -184,9 +184,9 @@ drcSubstitute (cptr)
DRCCookie * cptr; /* Design rule violated */
{
static char *why_out = NULL;
char *whyptr, *sptr, *wptr;
int subscnt = 0, whylen;
float oscale, value;
char *whyptr, *sptr, *wptr, *vptr;
int subscnt = 0, whylen, saveunits;
float value;
extern float CIFGetOutputScale();
whyptr = DRCCurStyle->DRCWhyList[cptr->drcc_tag];
@ -203,10 +203,14 @@ drcSubstitute (cptr)
why_out = (char *)mallocMagic(whylen * sizeof(char));
strcpy(why_out, whyptr);
if (cptr->drcc_flags & DRC_CIFRULE)
oscale = CIFGetScale(100); /* 100 = microns to centimicrons */
else
oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */
/* For backwards compatibility: If the units are set to "default",
* then print the DRC value in microns, with units, which is how
* the output was previously presented.
*/
saveunits = DBWUnits;
if (saveunits == DBW_UNITS_DEFAULT)
DBWUnits = DBW_UNITS_MICRONS | DBW_UNITS_PRINT_FLAG;
wptr = why_out;
while ((sptr = strchr(whyptr, '%')) != NULL)
@ -218,21 +222,29 @@ drcSubstitute (cptr)
switch (*(sptr + 1))
{
case 'd':
/* Replace with "dist" value in microns */
value = (float)cptr->drcc_dist * oscale;
snprintf(wptr, 20, "%01.3gum", value);
if (cptr->drcc_flags & DRC_CIFRULE)
vptr = DBWPrintCIFValue(cptr->drcc_dist, (MagWindow *)NULL, TRUE);
else
vptr = DBWPrintValue(cptr->drcc_dist, (MagWindow *)NULL, TRUE);
snprintf(wptr, 20, "%s", vptr);
wptr += strlen(wptr);
break;
case 'c':
/* Replace with "cdist" value in microns */
value = (float)cptr->drcc_cdist * oscale;
snprintf(wptr, 20, "%01.3gum", value);
if (cptr->drcc_flags & DRC_CIFRULE)
vptr = DBWPrintCIFValue(cptr->drcc_cdist, (MagWindow *)NULL, TRUE);
else
vptr = DBWPrintValue(cptr->drcc_cdist, (MagWindow *)NULL, TRUE);
snprintf(wptr, 20, "%s", vptr);
wptr += strlen(wptr);
break;
case 'a':
/* Replace with "cdist" value in microns squared */
value = (float)cptr->drcc_cdist * oscale * oscale;
snprintf(wptr, 20, "%01.4gum^2", value);
if (cptr->drcc_flags & DRC_CIFRULE)
vptr = DBWPrintCIFSqValue(cptr->drcc_cdist, (MagWindow *)NULL);
else
vptr = DBWPrintSqValue(cptr->drcc_cdist, (MagWindow *)NULL);
snprintf(wptr, 20, "%s", vptr);
wptr += strlen(wptr);
break;
default:
@ -245,6 +257,7 @@ drcSubstitute (cptr)
/* copy remainder of string (including trailing null) */
strncpy(wptr, whyptr, strlen(whyptr) + 1);
DBWUnits = saveunits;
return why_out;
}
@ -425,6 +438,8 @@ drcListallError (celldef, rect, cptr, scx)
}
if (drcsave == DRCErrorCount)
{
char *rllx, *rlly, *rurx, *rury;
DRCErrorCount += 1;
h = HashFind(&DRCErrorTable, drcSubstitute(cptr));
lobj = (Tcl_Obj *) HashGetValue(h);
@ -433,10 +448,15 @@ drcListallError (celldef, rect, cptr, scx)
pobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_xbot));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_ybot));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_xtop));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_ytop));
rllx = DBWPrintValue(r.r_xbot, (MagWindow *)NULL, TRUE);
rlly = DBWPrintValue(r.r_ybot, (MagWindow *)NULL, FALSE);
rurx = DBWPrintValue(r.r_xtop, (MagWindow *)NULL, TRUE);
rury = DBWPrintValue(r.r_ytop, (MagWindow *)NULL, FALSE);
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(rllx, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(rlly, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(rurx, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(rury, -1));
Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
HashSetValue(h, lobj);

View File

@ -52,7 +52,7 @@ static ClientData drcSubClientData; /* To be passed to error function. */
static DRCCookie drcSubcellCookie = {
0, 0, 0, 0,
{ {0} }, { {0} },
0, 0, 0,
0, DRC_EXCEPTION_NONE, 0, 0,
DRC_SUBCELL_OVERLAP_TAG,
(DRCCookie *) NULL
};
@ -65,7 +65,7 @@ static DRCCookie drcSubcellCookie = {
static DRCCookie drcInSubCookie = {
0, 0, 0, 0,
{ {0} }, { {0} },
0, 0, 0,
0, DRC_EXCEPTION_NONE, 0, 0,
DRC_IN_SUBCELL_TAG,
(DRCCookie *) NULL
};
@ -79,7 +79,7 @@ static DRCCookie drcInSubCookie = {
static DRCCookie drcOffGridCookie = {
0, 0, 0, 0,
{ {0} }, { {0} },
0, 0, 0,
0, DRC_EXCEPTION_NONE, 0, 0,
DRC_OFFGRID_TAG,
(DRCCookie *) NULL
};
@ -826,6 +826,7 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
*/
subArea = *erasebox;
GeoClip(&subArea, &cliparea);
if (GEO_RECTNULL(&subArea)) continue;
GEO_EXPAND(&subArea, DRCTechHalo, &intArea);
errorSaveType = DRCErrorType;

View File

@ -72,6 +72,12 @@ static int drcRulesOptimized = 0;
static int DRCtag = 0;
/* Keep track of what rule exemption or exception is in effect
* while reading the DRC tech file section.
*/
static char drcCurException = (char)DRC_EXCEPTION_NONE;
/*
* Forward declarations.
*/
@ -79,6 +85,7 @@ int drcWidth(), drcSpacing(), drcEdge(), drcNoOverlap();
int drcExactOverlap(), drcExtend();
int drcSurround(), drcRectOnly(), drcOverhang();
int drcStepSize(), drcOption(), drcOffGrid();
int drcException(), drcExemption();
int drcMaxwidth(), drcArea(), drcRectangle(), drcAngles();
int drcCifSetStyle(), drcCifWidth(), drcCifSpacing();
int drcCifMaxwidth(), drcCifArea();
@ -301,6 +308,12 @@ drcTechFreeStyle()
/* Clear the Why string list */
freeMagic(DRCCurStyle->DRCWhyList);
/* Clear the exception list */
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
freeMagic(DRCCurStyle->DRCExceptionList[i]);
if (DRCCurStyle->DRCExceptionList != (char **)NULL)
freeMagic(DRCCurStyle->DRCExceptionList);
freeMagic(DRCCurStyle);
DRCCurStyle = NULL;
}
@ -384,6 +397,60 @@ drcWhyCreate(whystring)
return DRCCurStyle->DRCWhySize;
}
/*
* ----------------------------------------------------------------------------
* drcExceptionCreate --
*
* Create an entry for a DRC rule exception/exemption type, if it does
* not already exist.
*
* Results:
* The index of the exception (which is a signed character).
*
* Side effects:
* Adds to the DRCExceptionList if "name" has not been used before.
* Calls StrDup() and increments DRCExceptionSize.
*
* ----------------------------------------------------------------------------
*/
char
drcExceptionCreate(name)
char *name;
{
int i;
char **newlist;
/* NOTE: DRCExceptionList has "MASKHINTS_" prepended to the names */
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
if (!strcmp(name, DRCCurStyle->DRCExceptionList[i] + 10))
return (char)i;
if (i > 127)
{
/* I would be shocked if this code ever got executed. */
TxError("Error: Too many rule exceptions! Limit is 127.\n");
return (char)DRC_EXCEPTION_NONE;
}
/* Create a new list that is one entry longer than the old list.
* This is not elegant but there will never be more than a handful
* of exceptions in a rule deck.
*/
newlist = (char **)mallocMagic((i + 1) * sizeof(char *));
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
newlist[i] = DRCCurStyle->DRCExceptionList[i];
/* The rule deck does not have the "MASKHINTS_" prefix on the name */
newlist[i] = (char *)mallocMagic(strlen(name) + 11);
sprintf(newlist[i], "MASKHINTS_%s", name);
DRCCurStyle->DRCExceptionSize++;
if (DRCCurStyle->DRCExceptionList != (char **)NULL)
freeMagic(DRCCurStyle->DRCExceptionList);
DRCCurStyle->DRCExceptionList = newlist;
return (char)i;
}
/*
* ----------------------------------------------------------------------------
*
@ -571,6 +638,8 @@ DRCTechStyleInit()
DRCCurStyle->DRCStepSize = 0;
DRCCurStyle->DRCFlags = (char)0;
DRCCurStyle->DRCWhySize = 0;
DRCCurStyle->DRCExceptionList = (char **)NULL;
DRCCurStyle->DRCExceptionSize = 0;
HashInit(&DRCWhyErrorTable, 16, HT_STRINGKEYS);
@ -663,6 +732,7 @@ DRCTechStyleInit()
}
drcCifInit();
drcCurException = (char)DRC_EXCEPTION_NONE;
}
/*
@ -955,6 +1025,7 @@ drcCifAssign(cookie, dist, next, mask, corner, tag, cdist, flags, planeto, plane
(cookie)->drcc_plane = planeto;
(cookie)->drcc_mod = 0;
(cookie)->drcc_cmod = 0;
(cookie)->drcc_exception = drcCurException;
}
// This is like drcCifAssign, but checks for bad plane numbers in planeto and
@ -1031,50 +1102,37 @@ DRCTechAddRule(sectionName, argc, argv)
int (*rk_proc)(); /* Procedure implementing this keyword */
const char *rk_err; /* Error message */
} ruleKeys[] = {
{"angles", 4, 4, drcAngles,
"layers 45|90 why"},
{"angles", 4, 4, drcAngles, "layers 45|90 why"},
{"edge", 8, 10, drcEdge,
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
{"edge4way", 8, 10, drcEdge,
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
{"exact_overlap", 2, 2, drcExactOverlap,
"layers"},
{"exact_overlap", 2, 2, drcExactOverlap, "layers"},
{"exception", 2, 2, drcException, "name"},
{"exemption", 2, 2, drcExemption, "name"},
{"extend", 5, 6, drcExtend,
"layers1 layers2 distance [option] why"},
{"no_overlap", 3, 3, drcNoOverlap,
"layers1 layers2"},
{"option", 2, 2, drcOption,
"option_name option_value"},
{"overhang", 5, 5, drcOverhang,
"layers1 layers2 distance why"},
{"rect_only", 3, 3, drcRectOnly,
"layers why"},
{"no_overlap", 3, 3, drcNoOverlap, "layers1 layers2"},
{"option", 2, 2, drcOption, "option_name option_value"},
{"overhang", 5, 5, drcOverhang, "layers1 layers2 distance why"},
{"rect_only", 3, 3, drcRectOnly, "layers why"},
{"spacing", 6, 7, drcSpacing,
"layers1 layers2 separation [layers3] adjacency why"},
{"stepsize", 2, 2, drcStepSize,
"step_size"},
{"stepsize", 2, 2, drcStepSize, "step_size"},
{"surround", 6, 7, drcSurround,
"layers1 layers2 distance presence why"},
{"width", 4, 5, drcWidth,
"layers width why"},
{"width", 4, 5, drcWidth, "layers width why"},
{"widespacing", 7, 8, drcSpacing,
"layers1 width layers2 separation adjacency why"},
{"area", 5, 5, drcArea,
"layers area horizon why"},
{"off_grid", 4, 4, drcOffGrid,
"layers pitch why"},
{"maxwidth", 4, 6, drcMaxwidth,
"layers maxwidth bends why"},
{"cifstyle", 2, 2, drcCifSetStyle,
"cif_style"},
{"cifwidth", 4, 4, drcCifWidth,
"layers width why"},
{"area", 5, 5, drcArea, "layers area horizon why"},
{"off_grid", 4, 4, drcOffGrid, "layers pitch why"},
{"maxwidth", 4, 6, drcMaxwidth, "layers maxwidth bends why"},
{"cifstyle", 2, 2, drcCifSetStyle, "cif_style"},
{"cifwidth", 4, 4, drcCifWidth, "layers width why"},
{"cifspacing", 6, 6, drcCifSpacing,
"layers1 layers2 separation adjacency why"},
{"cifarea", 5, 5, drcCifArea,
"layers area horizon why"},
{"cifmaxwidth", 5, 5, drcCifMaxwidth,
"layers maxwidth bends why"},
{"cifarea", 5, 5, drcCifArea, "layers area horizon why"},
{"cifmaxwidth", 5, 5, drcCifMaxwidth, "layers maxwidth bends why"},
{"rectangle", 5, 5, drcRectangle,
"layers maxwidth [even|odd|any] why"},
{0}
@ -1695,7 +1753,7 @@ drcMaxwidth(argc, argv)
if (PlaneMaskHasPlane(pmask2, plane2))
break;
if (plane2 == plane)
if (PlaneMaskHasPlane(pmask, plane2))
TechError("Warning: Exclude types for \"maxwidth\" are on the "
"same plane and so cannot be checked.\n");
}
@ -3634,6 +3692,83 @@ drcRectangle(argc, argv)
return maxwidth;
}
/*
* ----------------------------------------------------------------------------
*
* drcException, drcExemption --
*
* Process a DRC exception declaration
* This is of the form:
*
* exception exception_name|none
* or
* exemption exemption_name|none
*
* e.g,
*
* exception SRAM
* exemption SRAM
*
* The exception_name or exemption_name is the suffix part of a MASKHINTS_*
* property name; e.g., the name SRAM corresponds to a property called
* MASKHINTS_SRAM. This declaration is followed by a block of DRC rules
* that are subject to the exception or the exemption. An exception is the
* opposite of an exemption: If a rule is excepted, then the rule applies
* within areas delineated by bounding boxes defined by the
* MASKHINTS_<exception_name> property. If a rule is exempted, then the
* rule applies only outside of areas delineated by bounding boxes defined
* by the MASKHINTS_<exemption_name> property. The block of rules subject
* to the exemption or exception ends with another exception or exemption
* declaration. If the following rules are not to be excepted or exempted
* at all, then use "exception none" or "exemption none".
*
* Results:
* Returns 0.
*
* Side effects:
* Updates drcCurException. drcCurException is zero or positive for
* exceptions and negative for exemptions. The index can be
* recovered from a negative value by negating it and subtracting 1.
*
* ----------------------------------------------------------------------------
*/
int
drcException(argc, argv)
int argc;
char *argv[];
{
int i;
if (DRCCurStyle == NULL) return 0;
/* Assume that argc must be 2 because the parser insists upon it */
if (!strcmp(argv[1], "none"))
drcCurException = (char)DRC_EXCEPTION_NONE;
else
drcCurException = drcExceptionCreate(argv[1]);
return (0);
}
int
drcExemption(argc, argv)
int argc;
char *argv[];
{
int i;
if (DRCCurStyle == NULL) return 0;
/* Assume that argc must be 2 because the parser insists upon it */
if (!strcmp(argv[1], "none"))
drcCurException = (char)DRC_EXCEPTION_NONE;
else
drcCurException = -(drcExceptionCreate(argv[1])) - 1;
return (0);
}
/*
* ----------------------------------------------------------------------------
*
@ -4119,6 +4254,7 @@ drcTechFinalStyle(style)
if (dp->drcc_dist > next->drcc_dist) continue;
if (dp->drcc_cdist > next->drcc_cdist) continue;
if (dp->drcc_plane != next->drcc_plane) continue;
if (dp->drcc_exception != next->drcc_exception) continue;
if (dp->drcc_flags & DRC_REVERSE)
{
if (!(next->drcc_flags & DRC_REVERSE)) continue;

View File

@ -36,6 +36,7 @@ typedef struct drccookie
TileTypeBitMask drcc_mask; /* Legal types on RHS */
TileTypeBitMask drcc_corner; /* Types that trigger corner check */
unsigned short drcc_flags; /* Miscellaneous flags, see below. */
char drcc_exception; /* Index to list of exceptions */
int drcc_edgeplane; /* Plane of edge */
int drcc_plane; /* Index of plane on which to check
* legal types. */
@ -91,6 +92,9 @@ typedef struct drccookie
#define DRC_UNPROCESSED CLIENTDEFAULT
#define DRC_PROCESSED 1
/* drcc_exception defaults to -128 (0x80) meaning no exceptions/exemptions */
#define DRC_EXCEPTION_NONE (char)0x80
/*
* Background DRC (DRC Idle proc) for Tcl-based Magic
*/
@ -177,6 +181,8 @@ typedef struct drcstyle
unsigned short DRCFlags; /* Option flags */
char **DRCWhyList; /* Indexed list of "why" text strings */
int DRCWhySize; /* Length of DRCWhyList */
char **DRCExceptionList; /* Indexed list of DRC exceptions */
int DRCExceptionSize; /* Length of DRCExceptionList */
PaintResultType DRCPaintTable[NP][NT][NT];
} DRCStyle;

View File

@ -35,9 +35,9 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
#include "dbwind/dbwind.h" /* for DBWclientID */
#include "commands/commands.h" /* for module auto-load */
#include "textio/txcommands.h"
#include "extract/extract.h" /* for extDevTable */
#include "extflat/extflat.h"
#include "extflat/EFint.h"
#include "extract/extract.h" /* for extDevTable */
#include "utils/runstats.h"
#include "utils/malloc.h"

View File

@ -41,14 +41,11 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
#include "commands/commands.h" /* for module auto-load */
#include "textio/txcommands.h"
#include "extflat/extflat.h"
#include "extflat/EFint.h"
#include "extract/extract.h" /* for extDevTable */
#include "extflat/EFint.h"
#include "utils/runstats.h"
#include "ext2spice/ext2spice.h"
/* C99 compat */
#include "extflat/extflat.h"
/* These global values are defined in ext2spice.c */
extern HashTable subcktNameTable;
extern DQueue subcktNameQueue;
@ -637,7 +634,7 @@ subcktHierVisit(
if (hasports || is_top)
return subcktVisit(use, hierName, is_top);
else if (def->def_flags & DEF_NODEVICES)
else if ((def->def_flags & DEF_NODEVICES) && (!isStub))
return 0;
else
return subcktVisit(use, hierName, is_top);
@ -1091,6 +1088,7 @@ spcdevHierVisit(
if (!has_model)
{
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
}
@ -1141,6 +1139,7 @@ spcdevHierVisit(
if (!has_model)
{
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
}

View File

@ -38,9 +38,9 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
#include "dbwind/dbwind.h" /* for DBWclientID */
#include "commands/commands.h" /* for module auto-load */
#include "textio/txcommands.h"
#include "extract/extract.h" /* for extDevTable */
#include "extflat/extflat.h"
#include "extflat/EFint.h"
#include "extract/extract.h" /* for extDevTable */
#include "utils/runstats.h"
#include "ext2spice/ext2spice.h"
@ -1689,23 +1689,43 @@ subcktVisit(
HashStartSearch(&hs);
while ((he = HashNext(&def->def_nodes, &hs)))
{
bool found = FALSE;
sname = (EFNodeName *) HashGetValue(he);
if (sname == NULL) continue;
snode = sname->efnn_node;
if ((snode == NULL) || !(snode->efnode_flags & EF_PORT)) continue;
portidx = snode->efnode_name->efnn_port;
if (portidx >= 0)
{
if (nodeList[portidx] == NULL)
{
nodeList[portidx] = snode->efnode_name;
found = TRUE;
}
}
/* Normally there should be a port associated with snode, but
* if not, go looking for one in the node name aliases.
*/
for (nodeName = sname; nodeName != NULL; nodeName = nodeName->efnn_next)
{
if (found == TRUE) break;
portidx = nodeName->efnn_port;
if (portidx < 0) continue;
if (nodeList[portidx] == NULL)
{
nodeList[portidx] = nodeName;
found = TRUE;
}
else if (EFHNBest(nodeName->efnn_hier, nodeList[portidx]->efnn_hier))
{
nodeList[portidx] = nodeName;
found = TRUE;
}
}
}
@ -1932,6 +1952,7 @@ topVisit(
{
char stmp[MAX_STR_SIZE];
int portidx;
bool found = FALSE;
sname = (EFNodeName *) HashGetValue(he);
if (sname == NULL) continue; /* Should not happen */
@ -1939,33 +1960,68 @@ topVisit(
snode = sname->efnn_node;
if ((!snode) || (!(snode->efnode_flags & EF_PORT))) continue;
/* Found a node which is also a port */
portidx = snode->efnode_name->efnn_port;
if (portidx >= 0)
{
if (sorted_ports[portidx] == NULL)
{
if ((def->def_flags & DEF_ABSTRACT))
{
EFHNSprintf(stmp, sname->efnn_hier);
pname = stmp;
}
else
pname = nodeSpiceName(snode->efnode_name->efnn_hier, NULL);
hep = HashLookOnly(&portNameTable, pname);
if (hep == (HashEntry *)NULL)
{
hep = HashFind(&portNameTable, pname);
HashSetValue(hep, (ClientData)(pointertype)portidx);
sorted_ports[portidx] = StrDup((char **)NULL, pname);
}
else
{
/* Node that was unassigned has been found to be
* a repeat (see NOTE at top), so make sure its
* port number is set correctly.
*/
snode->efnode_name->efnn_port = (int)(pointertype)HashGetValue(hep);
}
found = TRUE;
}
}
if (!(def->def_flags & DEF_ABSTRACT))
heh = HashLookOnly(&efNodeHashTable, (char *)snode->efnode_name->efnn_hier);
/* Might need to check here for a port that was optimized out? */
/* If snode is flagged as a port but no port number was found, then
* check the all of the node's name entries to see if any of them has
* a port number.
*/
for (nodeName = sname; nodeName != NULL; nodeName = nodeName->efnn_next)
{
if (found == TRUE) break;
portidx = nodeName->efnn_port;
if (portidx < 0) continue;
/* Check if the same hierName is recorded in the flattened/optimized
* def's efNodeHashTable. If not, then it has been optimized out
* and should be removed from the port list.
*/
if (def->def_flags & DEF_ABSTRACT)
heh = HashLookOnly(&efNodeHashTable, (char *)nodeName->efnn_hier);
else
heh = HashLookOnly(&efNodeHashTable,
(char *)snode->efnode_name->efnn_hier);
/* If view is abstract, rely on the given port name, not
* the node. Otherwise, artifacts of the abstract view
* may cause nodes to be merged and the names lost.
*/
if (def->def_flags & DEF_ABSTRACT)
{
heh = HashLookOnly(&efNodeHashTable, (char *)nodeName->efnn_hier);
/* If view is abstract, rely on the given port name, not
* the node. Otherwise, artifacts of the abstract view
* may cause nodes to be merged and the names lost.
*/
EFHNSprintf(stmp, nodeName->efnn_hier);
pname = stmp;
}
else
// pname = nodeSpiceName(snode->efnode_name->efnn_hier, NULL);
pname = nodeSpiceName(nodeName->efnn_hier, NULL);
if (heh == (HashEntry *)NULL) /* pname now resolved for log output */
@ -1983,7 +2039,10 @@ topVisit(
hep = HashFind(&portNameTable, pname);
HashSetValue(hep, (ClientData)(pointertype)nodeName->efnn_port);
if (sorted_ports[portidx] == NULL)
{
sorted_ports[portidx] = StrDup((char **)NULL, pname);
found = TRUE;
}
}
else
{
@ -3081,6 +3140,7 @@ spcdevVisit(
if (!has_model)
{
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
}
@ -3127,6 +3187,7 @@ spcdevVisit(
if (!has_model)
{
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
}

View File

@ -34,8 +34,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header$";
#include "tiles/tile.h"
#include "database/database.h" /* for TileType definition */
#include "extflat/extflat.h"
#include "extflat/extparse.h"
#include "extflat/EFint.h"
#include "extract/extract.h" /* for device class list */
#include "extract/extract.h"
#include "extract/extractInt.h" /* for extGetDevType() */
/* C99 compat */
@ -647,8 +648,21 @@ efBuildEquiv(def, nodeName1, nodeName2, resist, isspice)
return;
}
else if (!resist)
TxError("Warning: Ports \"%s\" and \"%s\" are electrically "
{
char *uptr1, *uptr2;
/* Do not generate an error message if one or both node names
* is made by "extract unique".
*/
if ((uptr1 = strstr(nodeName1, "_uq")) != 0) *uptr1 = '\0';
if ((uptr2 = strstr(nodeName2, "_uq")) != 0) *uptr2 = '\0';
if ((uptr1 == NULL && uptr2 == NULL) ||
strcmp(nodeName1, nodeName2))
TxError("Warning: Ports \"%s\" and \"%s\" are electrically "
"shorted.\n", nodeName1, nodeName2);
if (uptr1) *uptr1 = '_';
if (uptr2) *uptr2 = '_';
}
else
/* Do not merge the nodes when folding in extresist parasitics */
return;
@ -907,6 +921,9 @@ efBuildDevice(
case DEV_FET:
case DEV_MOSFET:
case DEV_ASYMMETRIC:
/* Terminals start after L and W values, substrate, and parameters */
termstart = 3;
break;
case DEV_BJT:
/* Terminals start after L and W values, plus parameters */
termstart = 2;
@ -2099,7 +2116,7 @@ efNodeMerge(node1ptr, node2ptr)
/* Make all EFNodeNames point to "keeping" */
if (removing->efnode_name)
{
bool topportk, topportr, bestname;
bool topportk, topportr, bestname, swapnames;
for (nn = removing->efnode_name; nn; nn = nn->efnn_next)
{
@ -2110,10 +2127,31 @@ efNodeMerge(node1ptr, node2ptr)
topportk = (keeping->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
topportr = (removing->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
/* Concatenate list of EFNodeNames, taking into account precedence */
if ((!keeping->efnode_name) || (!topportk && topportr)
|| EFHNBest(removing->efnode_name->efnn_hier,
keeping->efnode_name->efnn_hier))
/* The node "keeping" is being kept, but we need to decide which
* node name of the two will be the node name of "keeping". If
* "keeping" has the best node name, then we're good; otherwise,
* we need to copy the name from "removing" to "keeping".
*
* Order of precedence:
* 1) If one node does not have a name, then use the name of the other.
* 2) If one node is a port and the other isn't, then use the port name.
* 3) Use the one with the preferred lexigraphical order according to
* EFHNBest().
*/
if ((!keeping->efnode_name) && (removing->efnode_name))
swapnames = TRUE;
else if ((keeping->efnode_name) && (!removing->efnode_name))
swapnames = FALSE;
else if (!topportk && topportr)
swapnames = TRUE;
else if (topportk && !topportr)
swapnames = FALSE;
else
swapnames = EFHNBest(removing->efnode_name->efnn_hier,
keeping->efnode_name->efnn_hier);
/* Concatenate list of EFNodeNames */
if (swapnames)
{
/*
* New official name is that of "removing".
@ -2200,6 +2238,14 @@ efNodeMerge(node1ptr, node2ptr)
if (removing->efnode_flags & EF_SUBS_NODE)
keeping->efnode_flags |= EF_SUBS_NODE;
/*
* If "removing" has the EF_GLOB_SUBS_NODE flag set, then copy the
* port record in the flags to "keeping".
*/
if (removing->efnode_flags & EF_GLOB_SUBS_NODE)
keeping->efnode_flags |= EF_GLOB_SUBS_NODE;
/* If EFSaveLocs is set, then merge any disjoint segments from
/* If EFSaveLocs is set, then merge any disjoint segments from
* removing to keeping.
*/

View File

@ -36,9 +36,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/magic.h"
#include "utils/geometry.h"
#include "textio/textio.h"
extern char *efReadFileName;
extern int efReadLineNum;
#include "extflat/extparse.h"
#ifdef MAGIC_WRAPPER
extern int Tcl_printf();

View File

@ -61,15 +61,17 @@ int efFlatGlobHash(HierName *);
bool efFlatGlobCmp(HierName *, HierName *);
char *efFlatGlobCopy(HierName *);
void efFlatGlobError(EFNodeName *nameGlob, EFNodeName *nameFlat);
int efAddNodes(HierContext *hc, bool stdcell);
int efAddConns(HierContext *hc, bool doWarn);
int efAddOneConn(HierContext *hc, char *name1, char *name2, Connection *conn, bool doWarn);
int efAddNodes(HierContext *hc, int flags);
int efAddConns(HierContext *hc, int flags);
int efAddOneConn(HierContext *hc, char *name1, char *name2, Connection *conn, int flags);
/* Flags passed to efFlatNode() */
#define FLATNODE_STDCELL 0x01
#define FLATNODE_DOWARN 0x02
#define FLATNODE_NOABSTRACT 0x04
#define FLATNODE_HIER 0x08
#define FLATNODE_CHILD 0x10
/*
@ -216,7 +218,7 @@ EFFlatBuildOneLevel(def, flags)
efFlatRootUse.use_def = efFlatRootDef;
/* Record all nodes down the hierarchy from here */
flatnodeflags = 0; /* No FLATNODE_DOWARN */
flatnodeflags = FLATNODE_HIER; /* No FLATNODE_DOWARN */
efFlatNodes(&efFlatContext, INT2CD(flatnodeflags));
/* Expand all subcells that contain connectivity information but */
@ -320,9 +322,7 @@ efFlatNodes(hc, clientData)
ClientData clientData;
{
int flags = (int)CD2INT(clientData);
bool stdcell = (flags & FLATNODE_STDCELL) ? TRUE : FALSE;
bool doWarn = (flags & FLATNODE_DOWARN) ? TRUE : FALSE;
int hierflags = 0;
if (flags & FLATNODE_NOABSTRACT)
{
@ -332,13 +332,19 @@ efFlatNodes(hc, clientData)
def->def_name);
}
(void) efHierSrUses(hc, efFlatNodes, clientData);
/* If called with FLATNODE_HIER set, then set the FLATNODE_CHILD
* flag while calling efHierSrUses(), to prevent efAddNodes() from
* duplicating the capacitance of nodes in child cells.
*/
hierflags = flags | ((flags & FLATNODE_HIER) ? FLATNODE_CHILD : 0);
(void) efHierSrUses(hc, efFlatNodes, INT2CD(hierflags));
/* Add all our own nodes to the table */
efAddNodes(hc, stdcell);
efAddNodes(hc, flags);
/* Process our own connections and adjustments */
(void) efAddConns(hc, doWarn);
(void) efAddConns(hc, flags);
return (0);
}
@ -386,11 +392,11 @@ efFlatNodesStdCell(hc)
}
/* Add all our own nodes to the table */
efAddNodes(hc, TRUE);
efAddNodes(hc, (int)FLATNODE_STDCELL);
/* Process our own connections and adjustments */
if (!(hc->hc_use->use_def->def_flags & DEF_SUBCIRCUIT))
(void) efAddConns(hc, TRUE);
(void) efAddConns(hc, (int)FLATNODE_DOWARN);
return (0);
}
@ -413,10 +419,10 @@ efFlatNodesDeviceless(hc, cdata)
if ((HashGetNumEntries(&hc->hc_use->use_def->def_devs) == 0) && (newcount == 0))
{
/* Add all our own nodes to the table */
efAddNodes(hc, TRUE);
efAddNodes(hc, (int)FLATNODE_STDCELL);
/* Process our own connections and adjustments */
efAddConns(hc, TRUE);
efAddConns(hc, (int)FLATNODE_DOWARN);
/* Mark this definition as having no devices, so it will not be visited */
hc->hc_use->use_def->def_flags |= DEF_NODEVICES;
@ -455,7 +461,7 @@ efFlatNodesDeviceless(hc, cdata)
int
efAddNodes(
HierContext *hc,
bool stdcell)
int flags)
{
Def *def = hc->hc_use->use_def;
EFNodeName *nn, *newname, *oldname;
@ -465,6 +471,8 @@ efAddNodes(
HierName *hierName;
int size, asize;
HashEntry *he;
bool stdcell = (flags & FLATNODE_STDCELL) ? TRUE : FALSE;
bool is_child = (flags & FLATNODE_CHILD) ? TRUE : FALSE;
bool is_subcircuit = (def->def_flags & DEF_SUBCIRCUIT) ? TRUE : FALSE;
size = sizeof (EFNode) + (efNumResistClasses-1) * sizeof (EFPerimArea);
@ -503,12 +511,15 @@ efAddNodes(
// If called with "hierarchy on", all local node caps and adjustments
// have been output and should be ignored.
newnode->efnode_cap = (!stdcell) ? node->efnode_cap : (EFCapValue)0.0;
if (!stdcell && !is_child)
newnode->efnode_cap = node->efnode_cap;
else
newnode->efnode_cap = (EFCapValue)0.0;
newnode->efnode_client = (ClientData) NULL;
newnode->efnode_flags = node->efnode_flags;
newnode->efnode_type = node->efnode_type;
newnode->efnode_num = 1;
if (!stdcell)
if (!stdcell && !is_child)
bcopy((char *) node->efnode_pa, (char *) newnode->efnode_pa,
efNumResistClasses * sizeof (EFPerimArea));
else
@ -601,7 +612,7 @@ efAddNodes(
int
efAddConns(
HierContext *hc,
bool doWarn)
int flags)
{
Connection *conn;
@ -614,9 +625,9 @@ efAddConns(
{
/* Special case for speed when no array info is present */
if (conn->conn_1.cn_nsubs == 0)
efAddOneConn(hc, conn->conn_name1, conn->conn_name2, conn, doWarn);
efAddOneConn(hc, conn->conn_name1, conn->conn_name2, conn, flags);
else
efHierSrArray(hc, conn, efAddOneConn, INT2CD(doWarn));
efHierSrArray(hc, conn, efAddOneConn, INT2CD(flags));
}
return (0);
@ -648,18 +659,23 @@ efAddOneConn(
char *name1, /* These are strings, not HierNames */
char *name2,
Connection *conn,
bool doWarn)
int flags)
{
HashEntry *he1, *he2;
EFNode *node, *newnode;
int n;
bool doWarn = (flags & FLATNODE_DOWARN) ? TRUE : FALSE;
bool doHier = (flags & FLATNODE_HIER) ? TRUE : FALSE;
he1 = EFHNLook(hc->hc_hierName, name1, (doWarn) ? "connect(1)" : NULL);
if (he1 == NULL)
return 0;
/* Adjust the resistance and capacitance of its corresponding node */
node = ((EFNodeName *) HashGetValue(he1))->efnn_node;
/* Adjust the resistance and capacitance of its corresponding node */
node->efnode_cap += conn->conn_cap;
for (n = 0; n < efNumResistClasses; n++)
{

View File

@ -82,6 +82,12 @@ extern void efHNRecord();
* variables cause nets named VDD and GND to become globals, which was
* not intended.
*
* Updated 1/2026: Also seems like a bad idea to treat the suffix "!"
* automatically as a global. By removing this, a global pin must be
* manually declared by putting it in the "globals" array variable.
* When not compiled with Tcl/Tk support, the original behavior is
* implemented.
*
* Results:
* TRUE if the name is a global.
*
@ -99,12 +105,10 @@ EFHNIsGlob(hierName)
char *retstr;
retstr = (char *)Tcl_GetVar2(magicinterp, "globals", hierName->hn_name,
TCL_GLOBAL_ONLY);
if (retstr != NULL) return TRUE;
// retstr = (char *)Tcl_GetVar(magicinterp, hierName->hn_name, TCL_GLOBAL_ONLY);
// if (retstr != NULL) return TRUE;
#endif
return (retstr != NULL) ? TRUE : FALSE;
#else
return hierName->hn_name[strlen(hierName->hn_name) - 1] == '!';
#endif
}
/*
@ -520,13 +524,22 @@ EFHNBest(hierName1, hierName2)
last1 = hierName1->hn_name[strlen(hierName1->hn_name) - 1];
last2 = hierName2->hn_name[strlen(hierName2->hn_name) - 1];
if (last1 != '!' || last2 != '!')
{
#if 0
/* NOTE (Jan. 31, 2026): The handling of trailing "!" as a global
* is at best incorrect; the node output should not consider the
* ancestor hierarchy, but it does. I am disabling the check here,
* and treating all names as local. It could be reinstated, but
* I think global names are just a bad idea altogether.
*/
/* Prefer global over local names */
if (last1 == '!') return TRUE;
if (last2 == '!') return FALSE;
#endif
/* Neither name is global, so chose label over generated name */
/* Neither name is global, so choose label over generated name */
if (last1 != '#' && last2 == '#') return TRUE;
if (last1 == '#' && last2 != '#') return FALSE;
}

View File

@ -37,6 +37,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "commands/commands.h"
#include "database/database.h"
#include "extflat/extflat.h"
#include "extflat/extparse.h"
#include "extflat/EFint.h"
#include "extract/extract.h"
#include "extract/extractInt.h"
@ -48,58 +49,11 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#ifndef MAGIC_WRAPPER
/* This must match the definition for extDevTable in extract/ExtBasic.c */
const char * const extDevTable[] = {"fet", "mosfet", "asymmetric", "bjt", "devres",
"devcap", "devcaprev", "vsource", "diode", "pdiode",
"ndiode", "subckt", "rsubckt", "msubckt", "csubckt",
"dsubckt", "veriloga", NULL};
"devcap", "devcaprev", "vsource", "diode", "pdiode",
"ndiode", "subckt", "rsubckt", "msubckt", "csubckt",
"dsubckt", "veriloga", NULL};
#endif
/*
* The following table describes the kinds of lines
* that may be read in a .ext file.
*/
typedef enum
{
ABSTRACT, ADJUST, ATTR, CAP, DEVICE, DIST, EQUIV, FET, KILLNODE, MERGE,
NODE, PARAMETERS, PORT, PRIMITIVE, RESISTOR, RESISTCLASS, RNODE, SCALE,
SUBCAP, SUBSTRATE, TECH, TIMESTAMP, USE, VERSION, EXT_STYLE
} Key;
static const struct
{
const char *k_name; /* Name of first token on line */
Key k_key; /* Internal name for token of this type */
int k_mintokens; /* Min total # of tokens on line of this type */
}
keyTable[] =
{
{"abstract", ABSTRACT, 0}, /* defines a LEF-like view */
{"adjust", ADJUST, 4},
{"attr", ATTR, 8},
{"cap", CAP, 4},
{"device", DEVICE, 11}, /* effectively replaces "fet" */
{"distance", DIST, 4},
{"equiv", EQUIV, 3},
{"fet", FET, 12}, /* for backwards compatibility */
{"killnode", KILLNODE, 2},
{"merge", MERGE, 3},
{"node", NODE, 7},
{"parameters", PARAMETERS, 3},
{"port", PORT, 8},
{"primitive", PRIMITIVE, 0}, /* defines a primitive device */
{"resist", RESISTOR, 4},
{"resistclasses", RESISTCLASS, 1},
{"rnode", RNODE, 5},
{"scale", SCALE, 4},
{"subcap", SUBCAP, 3},
{"substrate", SUBSTRATE, 3},
{"tech", TECH, 2},
{"timestamp", TIMESTAMP, 2},
{"use", USE, 9},
{"version", VERSION, 2},
{"style", EXT_STYLE, 2},
{0}
};
/* Data shared with EFerror.c */
char *efReadFileName; /* Name of file currently being read */
int efReadLineNum; /* Current line number in above file */
@ -109,10 +63,6 @@ bool EFSaveLocs; /* If TRUE, save location of merged top-level nodes */
/* Data local to this file */
static bool efReadDef(Def *def, bool dosubckt, bool resist, bool noscale, bool toplevel, bool isspice);
/* atoCap - convert a string to a EFCapValue */
#define atoCap(s) ((EFCapValue)atof(s))
/*
* ----------------------------------------------------------------------------
*

View File

@ -27,7 +27,6 @@
#include "extflat/EFtypes.h" /* EFCapValue, HierName, EFPerimArea, EFNode */
#include "extflat/EFint.h" /* Def, HierContext, Connection, Distance, CallArg */
extern float EFScale; /* Scale factor to multiply all coords by */
extern char *EFTech; /* Technology of extracted circuit */
extern char *EFStyle; /* Extraction style of extracted circuit */

75
extflat/extparse.h Normal file
View File

@ -0,0 +1,75 @@
/*
* extparse.h
*
* Definitions for the .ext file parser. Relocated from EFread.c.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef _MAGIC__EXTFLAT__EXTPARSE_H
#define _MAGIC__EXTFLAT__EXTPARSE_H
/*
* The following table describes the kinds of lines
* that may be read in a .ext file.
*/
typedef enum
{
ABSTRACT, ADJUST, ATTR, CAP, DEVICE, DIST, EQUIV, FET, KILLNODE, MERGE,
NODE, PARAMETERS, PORT, PRIMITIVE, RESISTOR, RESISTCLASS, RNODE, SCALE,
SUBCAP, SUBSTRATE, TECH, TIMESTAMP, USE, VERSION, EXT_STYLE
} Key;
static const struct
{
const char *k_name; /* Name of first token on line */
Key k_key; /* Internal name for token of this type */
int k_mintokens; /* Min total # of tokens on line of this type */
}
keyTable[] =
{
{"abstract", ABSTRACT, 0}, /* defines a LEF-like view */
{"adjust", ADJUST, 4},
{"attr", ATTR, 8},
{"cap", CAP, 4},
{"device", DEVICE, 11}, /* effectively replaces "fet" */
{"distance", DIST, 4},
{"equiv", EQUIV, 3},
{"fet", FET, 12}, /* for backwards compatibility */
{"killnode", KILLNODE, 2},
{"merge", MERGE, 3},
{"node", NODE, 7},
{"parameters", PARAMETERS, 3},
{"port", PORT, 8},
{"primitive", PRIMITIVE, 0}, /* defines a primitive device */
{"resist", RESISTOR, 4},
{"resistclasses", RESISTCLASS, 1},
{"rnode", RNODE, 5},
{"scale", SCALE, 4},
{"subcap", SUBCAP, 3},
{"substrate", SUBSTRATE, 3},
{"tech", TECH, 2},
{"timestamp", TIMESTAMP, 2},
{"use", USE, 9},
{"version", VERSION, 2},
{"style", EXT_STYLE, 2},
{0}
};
/* atoCap - convert a string to a EFCapValue */
#define atoCap(s) ((EFCapValue)atof(s))
extern int efReadLineNum; /* Current line number in the .ext file */
extern char *efReadFileName; /* Name of current .ext file being read */
#endif /* _MAGIC__EXTFLAT__EXTPARSE_H */

View File

@ -37,6 +37,7 @@ static char sccsid[] = "@(#)ExtBasic.c 4.13 MAGIC (Berkeley) 12/5/85";
#include "utils/malloc.h"
#include "textio/textio.h"
#include "debug/debug.h"
#include "extflat/extparse.h"
#include "extract/extract.h"
#include "extract/extractInt.h"
#include "utils/signals.h"
@ -85,6 +86,8 @@ typedef struct /* Position of each terminal (below) tile position */
{
int pnum;
Point pt;
Tile *tile; /* Any tile beloging to the terminal */
TileType type; /* Type of "tile", including split information */
} TermTilePos;
/* Field definitions for tr_devmatch */
@ -147,6 +150,7 @@ int extTransTileFunc();
int extTransPerimFunc();
int extTransFindSubs();
int extTransFindId();
void extTermAPFunc();
int extAnnularTileFunc();
int extResistorTileFunc();
@ -322,7 +326,7 @@ extBasic(def, outFile)
}
/* Check for "device", as it modifies handling of parasitics */
propptr = (char *)DBPropGet(def, "device", &propfound);
propptr = DBPropGetString(def, "device", &propfound);
if (propfound)
{
/* Remove parasitics from local nodes */
@ -798,14 +802,34 @@ extOutputNodes(nodeList, outFile)
lastname = ll->ll_label->lab_text;
}
/* Don't print a warning unless both labels are
* really ports.
* really ports. Also, don't print a warning for
* names generated by "extract unique" vs. real
* pin names or another unique name---"extract
* unique" does not observe where nets pass through
* subcircuits, so it tends to over-generated
* unique names, which "ext2spice" will filter out.
* For a net to be shorted to itself is not an error.
* NOTE: Potentially the unique name could be removed
* here and save ext2spice the trouble.
*/
if ((portname != NULL) &&
(ll->ll_attr == LL_PORTATTR) &&
(strcmp(ll->ll_label->lab_text, portname)))
TxError("Warning: Ports \"%s\" and \"%s\" are"
" electrically shorted.\n",
text, ll->ll_label->lab_text);
{
char *uptr1, *uptr2;
uptr1 = strstr(text, "_uq");
uptr2 = strstr(ll->ll_label->lab_text, "_uq");
if (uptr1) *uptr1 = '\0';
if (uptr2) *uptr2 = '\0';
if (strcmp(text, ll->ll_label->lab_text))
{
TxError("Warning: Ports \"%s\" and \"%s\" are"
" electrically shorted.\n",
text, ll->ll_label->lab_text);
}
if (uptr1) *uptr1 = '_';
if (uptr2) *uptr2 = '_';
}
if (!isPort && (ll->ll_attr == LL_PORTATTR))
portname = ll->ll_label->lab_text;
}
@ -1678,7 +1702,7 @@ extOutputParameters(def, transList, outFile)
* and device name, and if detected, add the type corresponding to the
* device name to the mask so it gets handled, too.
*/
propptr = DBPropGet(def, "device", &propfound);
propptr = DBPropGetString(def, "device", &propfound);
if (propfound)
{
char *devname;
@ -1811,6 +1835,8 @@ extOutputDevParams(reg, devptr, outFile, length, width, areavec, perimvec)
ParamList *chkParam;
HashEntry *he;
ResValue resvalue;
LabRegion *node; /* Node connected to gate terminal */
LabelList *ll; /* Gate's label list */
for (chkParam = devptr->exts_deviceParams; chkParam
!= NULL; chkParam = chkParam->pl_next)
@ -1942,6 +1968,34 @@ extOutputDevParams(reg, devptr, outFile, length, width, areavec, perimvec)
break;
}
}
/* If there are device attribute labels (labels attached to the device
* type ending with "^") with "=" in them, then treat them as extra
* parameters. Output each one and remove the gate attribute property
* from the label.
*/
node = (LabRegion *)ExtGetRegion(reg->treg_tile, reg->treg_dinfo);
for (ll = node->lreg_labels; ll; ll = ll->ll_next)
{
if (ll->ll_attr == LL_GATEATTR)
{
char cs, *ct, *cp = ll->ll_label->lab_text;
if (strchr(cp, '=') != NULL)
{
/* Since this is an attribute label, it has a special character
* at the end, which needs to be stripped off while printing
* and then put back again.
*/
ct = ll->ll_label->lab_text + strlen(ll->ll_label->lab_text) - 1;
cs = *ct;
*ct = '\0';
fprintf(outFile, " %s", ll->ll_label->lab_text);
ll->ll_attr = LL_NOATTR;
*ct = cs;
}
}
}
}
/* Structures used by extTermAPFunc() for storing area and perimeter data */
@ -2168,8 +2222,6 @@ extTransFindTermArea(tile, dinfo, eapd)
TileType dinfo;
ExtAreaPerimData *eapd;
{
void extTermAPFunc(); /* Forward declaration */
extEnumTerminal(tile, dinfo, DBConnectTbl, extTermAPFunc, (ClientData)eapd);
return 1;
}
@ -2257,6 +2309,8 @@ extOutputDevices(def, transList, outFile)
extTransRec.tr_termpos[i].pnum = 0;
extTransRec.tr_termpos[i].pt.p_x = 0;
extTransRec.tr_termpos[i].pt.p_y = 0;
extTransRec.tr_termpos[i].tile = NULL;
extTransRec.tr_termpos[i].type = TT_SPACE;
}
arg.fra_def = def;
@ -2281,6 +2335,58 @@ extOutputDevices(def, transList, outFile)
arg.fra_each = extTransTileFunc;
ntiles = ExtFindNeighbors(reg->treg_tile, reg->treg_dinfo, arg.fra_pNum, &arg);
/* Once the entire device has been marked with the device region,
* replacing the node region, search each terminal to determine
* if the terminal is shared by multiple devices. Note that this
* algorithm is not foolproof: In the rare case that three or more
* devices share the same terminal, and more than one of them have
* the same gate, then those gates will have the same node record and
* will not be seen as individual devices.
*/
for (i = 0; i < MAXSD; i++)
{
Tile *termtile = extTransRec.tr_termpos[i].tile;
if (termtile != NULL)
{
/* Find the area and perimeter of the terminal area (connected
* area outside the boundary on a single plane). Note that
* this does not consider terminal area outside of the cell
* or how area or perimeter may be shared or overlap between
* devices.
*/
int shared;
ExtAreaPerimData eapd;
TileType termtype = extTransRec.tr_termpos[i].type;
eapd.eapd_area = eapd.eapd_perim = 0;
TTMaskCom2(&eapd.eapd_mask, &DBConnectTbl[termtype & TT_LEFTMASK]);
eapd.eapd_gatemask = &ExtCurStyle->exts_deviceMask;
eapd.eapd_gatenode = (NodeRegion *)reg;
eapd.eapd_shared = NULL;
extEnumTerminal(termtile,
termtype & (TT_DIAGONAL | TT_SIDE | TT_DIRECTION),
DBConnectTbl, extTermAPFunc,
(ClientData)&eapd);
shared = 1; /* Count self since we divide by "shared" */
free_magic1_t mm1 = freeMagic1_init();
while (eapd.eapd_shared)
{
shared++;
freeMagic1(&mm1, eapd.eapd_shared);
eapd.eapd_shared = eapd.eapd_shared->nl_next;
}
freeMagic1_end(&mm1);
extTransRec.tr_termarea[i] = eapd.eapd_area;
extTransRec.tr_termperim[i] = eapd.eapd_perim;
extTransRec.tr_termshared[i] = shared;
}
}
/* Re-mark with extTransRec.tr_gatenode */
arg.fra_uninit = (ClientData) reg;
arg.fra_region = (ExtRegion *) extTransRec.tr_gatenode;
@ -3911,8 +4017,11 @@ extTransPerimFunc(bp)
extTransRec.tr_termvector[thisterm].p_y = 0;
extTransRec.tr_termpos[thisterm].pnum = DBPlane(toutside);
extTransRec.tr_termpos[thisterm].pt = bp->b_outside->ti_ll;
/* Find the total area of this terminal */
/* tile and dinfo need only be one valid terminal tile,
* and do not need to be updated.
*/
extTransRec.tr_termpos[thisterm].tile = bp->b_outside;
extTransRec.tr_termpos[thisterm].type = dinfo | toutside;
}
else if (extTransRec.tr_termnode[thisterm] == termNode)
{
@ -3944,42 +4053,6 @@ extTransPerimFunc(bp)
/* Add the length to this terminal's perimeter */
extTransRec.tr_termlen[thisterm] += len;
if (extTransRec.tr_termarea[thisterm] == 0)
{
/* Find the area and perimeter of the terminal area (connected
* area outside the boundary on a single plane). Note that
* this does not consider terminal area outside of the cell
* or how area or perimeter may be shared or overlap between
* devices.
*/
ExtAreaPerimData eapd;
int shared;
eapd.eapd_area = eapd.eapd_perim = 0;
TTMaskCom2(&eapd.eapd_mask, &DBConnectTbl[toutside]);
eapd.eapd_gatemask = &ExtCurStyle->exts_deviceMask;
eapd.eapd_gatenode = extTransRec.tr_gatenode;
eapd.eapd_shared = NULL;
extEnumTerminal(bp->b_outside, dinfo, DBConnectTbl,
extTermAPFunc, (ClientData)&eapd);
shared = 0;
free_magic1_t mm1 = freeMagic1_init();
while (eapd.eapd_shared)
{
shared++;
freeMagic1(&mm1, eapd.eapd_shared);
eapd.eapd_shared = eapd.eapd_shared->nl_next;
}
freeMagic1_end(&mm1);
extTransRec.tr_termarea[thisterm] = eapd.eapd_area;
extTransRec.tr_termperim[thisterm] = eapd.eapd_perim;
extTransRec.tr_termshared[thisterm] = shared;
}
/* Update the boundary traversal vector */
switch(bp->b_direction) {
case BD_LEFT:
@ -4994,9 +5067,12 @@ extFindNodes(def, clipArea, subonly)
/* If the default substrate type is set, it is used *only* for */
/* isolated substrate regions and does not mark the default */
/* substrate, so remove it from the list of substrate types. */
/* Note that this is not the case when doing full R-C */
/* extraction. */
if (ExtCurStyle->exts_globSubstrateDefaultType != -1)
TTMaskClearType(&subsTypesNonSpace,
if (!(ExtOptions & EXT_DOEXTRESIST))
if (ExtCurStyle->exts_globSubstrateDefaultType != -1)
TTMaskClearType(&subsTypesNonSpace,
ExtCurStyle->exts_globSubstrateDefaultType);
pNum = ExtCurStyle->exts_globSubstratePlane;

View File

@ -50,7 +50,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
/* Forward declarations */
int extOutputUsesFunc();
FILE *extFileOpen();
Plane* extCellFile();
void extHeader();
@ -96,7 +95,7 @@ ExtCell(def, outName, doLength)
if (def->cd_flags & CDNOEXTRACT)
return extPrepSubstrate(def);
f = extFileOpen(def, outName, "w", &filename);
f = ExtFileOpen(def, outName, "w", &filename);
TxPrintf("Extracting %s into %s:\n", def->cd_name, filename);
@ -132,7 +131,7 @@ ExtCell(def, outName, doLength)
/*
* ----------------------------------------------------------------------------
*
* extFileOpen --
* ExtFileOpen --
*
* Open the .ext file corresponding to a .mag file.
* If def->cd_file is non-NULL, the .ext file is just def->cd_file with
@ -150,7 +149,7 @@ ExtCell(def, outName, doLength)
*/
FILE *
extFileOpen(def, file, mode, prealfile)
ExtFileOpen(def, file, mode, prealfile)
CellDef *def; /* Cell whose .ext file is to be written */
char *file; /* If non-NULL, open 'name'.ext; otherwise,
* derive filename from 'def' as described
@ -486,8 +485,17 @@ extCellFile(def, f, doLength)
UndoDisable();
/* If "extract do unique" was specified, then make labels in the
* cell unique.
*/
if (ExtOptions & EXT_DOUNIQUE)
extUniqueCell(def, EXT_UNIQ_TEMP);
/* Prep any isolated substrate areas */
saveSub = extPrepSubstrate(def);
if (ExtOptions & EXT_DOEXTRESIST)
saveSub = extResPrepSubstrate(def);
else
saveSub = extPrepSubstrate(def);
/* Remove any label markers that were made by a previous extraction */
for (lab = def->cd_labels; lab; lab = lab->lab_next)
@ -586,7 +594,7 @@ extHeader(def, f)
/* are to be passed to instances of the cell */
/* (created by defining property "parameter") */
propvalue = (char *)DBPropGet(def, "parameter", &propfound);
propvalue = DBPropGetString(def, "parameter", &propfound);
if (propfound)
{
// Use device parameter table to store the cell def parameters,

View File

@ -1289,6 +1289,14 @@ extFindOverlap(tp, area, esws)
TileType tin = TiGetType(bp->b_inside);
TileType tout = TiGetType(bp->b_outside);
/* Get residues
* (Note: Isn't it better to include contacts in the tables?)
*/
if (DBIsContact(tin))
tin = DBPlaneToResidue(tin, esws->plane_of_boundary);
if (DBIsContact(tout))
tout = DBPlaneToResidue(tout, esws->plane_of_boundary);
pMask = ExtCurStyle->exts_sideOverlapOtherPlanes[tin][tout];
extOverlapDef = esws->def;

View File

@ -354,8 +354,8 @@ extHierConnections(ha, cumFlat, oneFlat)
if (!(lab->lab_flags & LABEL_STICKY)) continue;
r = lab->lab_rect;
if (!GEO_TOUCH(&r, &ha->ha_subArea)) continue;
GEOCLIP(&r, &ha->ha_subArea);
if (GEO_RECTNULL(&r)) continue;
cumDef = cumFlat->et_use->cu_def;
connected = &DBConnectTbl[lab->lab_type];

View File

@ -35,6 +35,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "debug/debug.h"
#include "extract/extract.h"
#include "extract/extractInt.h"
#include "resis/resis.h"
#include "utils/signals.h"
#include "utils/stack.h"
#include "utils/utils.h"
@ -43,9 +44,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/main.h"
#include "utils/undo.h"
/* Imports from elsewhere in this module */
extern FILE *extFileOpen();
/* ------------------------ Exported variables ------------------------ */
/*
@ -83,16 +81,6 @@ typedef struct _linkedDef {
struct _linkedDef *ld_next;
} LinkedDef;
/* Linked list structure to use to store the substrate plane from each */
/* extracted CellDef so that they can be returned to the original after */
/* extraction. */
struct saveList {
Plane *sl_plane;
CellDef *sl_def;
struct saveList *sl_next;
};
/* Stack of defs pending extraction */
Stack *extDefStack;
@ -606,7 +594,7 @@ extParents(use, doExtract)
extDefParentFunc(use->cu_def);
/* Now extract all the cells we just found */
extExtractStack(extDefStack, doExtract, (CellDef *) NULL);
extExtractStack(extDefStack, doExtract, (CellDef *)NULL);
StackFree(extDefStack);
/* Replace any modified substrate planes in use->cu_def's children */
@ -688,7 +676,7 @@ ExtParentArea(use, changedArea, doExtract)
extDefParentAreaFunc(use->cu_def, use->cu_def, (CellUse *) NULL, &area);
/* Now extract all the cells we just found */
extExtractStack(extDefStack, doExtract, (CellDef *) NULL);
extExtractStack(extDefStack, doExtract, (CellDef *)NULL);
StackFree(extDefStack);
}
@ -806,12 +794,30 @@ ExtractOneCell(def, outName, doLength)
savePlane = ExtCell(def, outName, doLength);
/* Restore all modified substrate planes */
/* Run full R-C extraction if specified in options */
if (ExtOptions & EXT_DOEXTRESIST)
{
ResisData *resisdata = ResInit();
UndoDisable();
ResOptionsFlags |= ResOpt_Signal;
resisdata->mainDef = def;
resisdata->savePlanes = (struct saveList *)NULL; /* unused */
ExtResisForDef(def, resisdata);
UndoEnable();
}
/* Restore all modified substrate planes and modified labels */
if (savePlane != NULL) ExtRevertSubstrate(def, savePlane);
free_magic1_t mm1 = freeMagic1_init();
for (; sl; sl = sl->sl_next)
{
if (EXT_DOUNIQUE) ExtRevertUniqueCell(sl->sl_def);
ExtRevertSubstrate(sl->sl_def, sl->sl_plane);
freeMagic1(&mm1, sl);
}
@ -944,7 +950,7 @@ extTimestampMisMatch(def)
doLocal = (ExtLocalPath == NULL) ? FALSE : TRUE;
extFile = extFileOpen(def, (char *) NULL, "r", (char **) NULL);
extFile = ExtFileOpen(def, (char *) NULL, "r", (char **) NULL);
if (extFile == NULL)
return (TRUE);
@ -990,10 +996,18 @@ extExtractStack(stack, doExtract, rootDef)
bool first = TRUE;
Plane *savePlane;
CellDef *def;
LinkedDef *savelist = NULL, *revlist = NULL, *newld;
struct saveList *newsl, *sl = (struct saveList *)NULL;
while ((def = (CellDef *) StackPop(stack)))
{
if (ExtOptions & EXT_DOEXTRESIST)
{
newld = (LinkedDef *)mallocMagic(sizeof(LinkedDef));
newld->ld_def = def;
newld->ld_next = savelist;
savelist = newld;
}
def->cd_client = (ClientData) 0;
if (!SigInterruptPending)
{
@ -1026,10 +1040,50 @@ extExtractStack(stack, doExtract, rootDef)
}
}
/* Replace any modified substrate planes */
/* Now that all cells have been processed, run full R-C extraction */
if (ExtOptions & EXT_DOEXTRESIST)
{
ResisData *resisdata = ResInit();
LinkedDef *srchld, *nextld;
UndoDisable();
/* Reverse the linked list from top-down to bottom-up */
srchld = savelist;
while (srchld != NULL)
{
nextld = srchld->ld_next;
srchld->ld_next = revlist;
revlist = srchld;
srchld = nextld;
}
/* Reprocess the list and call "extresist" for each cell def */
srchld = revlist;
while (srchld != NULL)
{
nextld = srchld->ld_next;
def = srchld->ld_def;
ResOptionsFlags |= ResOpt_Signal;
resisdata->mainDef = def;
resisdata->savePlanes = (struct saveList *)NULL; /* unused */
TxPrintf("Processing cell %s for resistance extraction.\n", def->cd_name);
ExtResisForDef(def, resisdata);
freeMagic(srchld);
srchld = nextld;
}
UndoEnable();
}
/* Replace any modified substrate planes and modified labels */
free_magic1_t mm1 = freeMagic1_init();
for (; sl; sl = sl->sl_next)
{
if (EXT_DOUNIQUE) ExtRevertUniqueCell(sl->sl_def);
ExtRevertSubstrate(sl->sl_def, sl->sl_plane);
sl->sl_def->cd_flags &= ~CDNOEXTRACT;
freeMagic1(&mm1, sl);

View File

@ -251,6 +251,17 @@ extSubtree(parentUse, reg, f)
if (result == 0) {
/* If result == FALSE then ha.ha_interArea is invalid. */
ha.ha_interArea = rlab;
/* Ensure that the interaction area is not zero */
if (ha.ha_interArea.r_xtop - ha.ha_interArea.r_xbot == 0)
{
ha.ha_interArea.r_xtop++;
ha.ha_interArea.r_xbot--;
}
if (ha.ha_interArea.r_ytop - ha.ha_interArea.r_ybot == 0)
{
ha.ha_interArea.r_ytop++;
ha.ha_interArea.r_ybot--;
}
result = 1;
}
else
@ -779,6 +790,7 @@ extSubtreeFunc(scx, ha)
*/
ha->ha_subArea = use->cu_bbox;
GEOCLIP(&ha->ha_subArea, &ha->ha_interArea);
hy.hy_area = &ha->ha_subArea;
hy.hy_target = oneFlat->et_use;
hy.hy_prefix = TRUE;

View File

@ -1368,7 +1368,7 @@ ExtTechSimplePerimCap(argc, argv)
if (ExtCurStyle->exts_planeOrderStatus != seenPlaneOrder)
{
TechError("Cannot parse area cap line without plane ordering!\n");
TechError("Cannot parse perimeter cap line without plane ordering!\n");
return;
}
@ -1376,9 +1376,14 @@ ExtTechSimplePerimCap(argc, argv)
TTMaskSetMask(allExtractTypes, &types);
plane1 = DBTechNoisyNamePlane(argv[2]);
TTMaskCom2(&nottypes, &types);
/* As part of the "simple perimeter" simplifications, "nottypes" can
* only be space. This prevents perimeter edges from being seen
* between, e.g., poly and transistor gates, or metal and metal
* resistors.
*/
TTMaskSetOnlyType(&nottypes, TT_SPACE);
TTMaskAndMask(&types, &DBPlaneTypes[plane1]);
TTMaskAndMask(&nottypes, &DBPlaneTypes[plane1]);
capVal = aToCap(argv[argc - 1]);
@ -1632,7 +1637,7 @@ ExtTechSimpleOverlapCap(argv)
if (ExtCurStyle->exts_planeOrderStatus != seenPlaneOrder)
{
TechError("Cannot parse area cap line without plane ordering!\n");
TechError("Cannot parse overlap cap line without plane ordering!\n");
return;
}
@ -1732,7 +1737,7 @@ ExtTechSimpleSideOverlapCap(argv)
if (ExtCurStyle->exts_planeOrderStatus != seenPlaneOrder)
{
TechError("Cannot parse area cap line without plane ordering!\n");
TechError("Cannot parse side overlap cap line without plane ordering!\n");
return;
}
@ -1740,9 +1745,14 @@ ExtTechSimpleSideOverlapCap(argv)
TTMaskSetMask(allExtractTypes, &types);
plane1 = DBTechNoisyNamePlane(argv[2]);
TTMaskCom2(&nottypes, &types);
/* As part of the "simple sideoverlap" simplifications, "nottypes"
* can only be space. This prevents perimeter edges from being
* seen between, e.g., poly and transistor gates, or metal and
* metal resistors.
*/
TTMaskSetOnlyType(&nottypes, TT_SPACE);
TTMaskAndMask(&types, &DBPlaneTypes[plane1]);
TTMaskAndMask(&nottypes, &DBPlaneTypes[plane1]);
DBTechNoisyNameMask(argv[3], &ov);
TTMaskSetMask(allExtractTypes, &ov);
@ -2747,24 +2757,34 @@ ExtTechLine(sectionName, argc, argv)
DBTechNoisyNameMask(argv[4], &termtypes[0]); /* bottom */
TTMaskSetMask(allExtractTypes, &termtypes[0]);
termtypes[1] = DBZeroTypeBits;
if (argc > 5)
gccap = aToCap(argv[argc - 1]); /* area cap */
if ((argc > 6) && StrIsNumeric(argv[argc - 2]))
{
gscap = aToCap(argv[argc - 2]); /* perimeter cap */
argc--;
}
nterm = 1;
if ((argc > 6) && strcmp(argv[5], "None"))
/* If argv[argc - 1] is a numerical value, then it is
* an area cap value and may be followed by another
* numerical value, the perimeter cap.
*/
if ((argc > 5) && StrIsNumeric(argv[argc - 1]))
{
DBTechNoisyNameMask(argv[5], &subsTypes); /* substrate */
gccap = aToCap(argv[argc - 1]); /* area cap */
argc--;
if ((argc > 5) && StrIsNumeric(argv[argc - 1]))
{
gscap = aToCap(argv[argc - 1]); /* perimeter cap */
argc--;
}
}
if ((argc > 5) && strcmp(argv[5], "None"))
{
/* substrate */
DBTechNoisyNameMask(argv[5], &subsTypes);
TTMaskSetMask(allExtractTypes, &subsTypes);
}
else
subsTypes = DBZeroTypeBits;
if (argc > 7) subsName = argv[6];
if (argc > 6) subsName = argv[6];
break;
case DEV_SUBCKT:

View File

@ -61,6 +61,11 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
* names that don't end in '!'.
* If option is EXT_UNIQ_NOPORTS, then generate unique names as for
* option 0 only if the label is not a port.
* If option is EXT_UNIQ_TEMP, then generate unique names as for
* EXT_UNIQ_ALL, but also set the LABEL_UNIQUE flag for the
* label. This way, the unique label form can be used by the
* extraction code but labels (and port indexes) can be reverted
* afterward, and no permanent change is made to the circuit.
*
* Results:
* Returns the number of warnings generated.
@ -219,7 +224,7 @@ extMakeUnique(def, ll, lreg, lregList, labelHash, option)
* changes a label to make it unique.
*/
text = ll->ll_label->lab_text;
if (option == EXT_UNIQ_ALL)
if (option == EXT_UNIQ_ALL || option == EXT_UNIQ_TEMP)
goto makeUnique;
else if ((option == EXT_UNIQ_NOPORTS || option == EXT_UNIQ_NOTOPPORTS)
&& !(ll->ll_label->lab_flags & PORT_DIR_MASK))
@ -320,8 +325,11 @@ makeUnique:
lab = ll2->ll_label;
saveLab = *lab;
/* Flag this label as having been modified */
if (option == EXT_UNIQ_TEMP) flags |= LABEL_UNIQUE;
DBRemoveLabel(def, lab);
(void) DBPutFontLabel(def, &saveLab.lab_rect,
DBPutFontLabel(def, &saveLab.lab_rect,
saveLab.lab_font, saveLab.lab_size, saveLab.lab_rotate,
&saveLab.lab_offset, saveLab.lab_just, name2,
saveLab.lab_type, flags, (unsigned int)portno);
@ -334,3 +342,64 @@ makeUnique:
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* extRevertUniqueCell --
*
* For the cell 'def', look for labels marked with LABEL_UNIQUE and
* remove the unique suffix. If the label is a port, then revert
* the port index back to the original port number.
*
* Results:
* None.
*
* Side effects:
* Changes the label records in the cell def.
*
* ----------------------------------------------------------------------------
*/
void
ExtRevertUniqueCell(CellDef *def)
{
Label *lab, *tlab;
char *uptr;
for (lab = def->cd_labels; lab; lab = lab->lab_next)
{
if (lab->lab_flags & LABEL_UNIQUE)
{
/* There is no need to regenerate the label. We are
* only reducing the string length, so just drop a null
* at the last underscore and leave it at that.
*/
lab->lab_flags &= ~LABEL_UNIQUE; /* Clear the flag */
/* Place a null at the last underscore */
uptr = strrchr(lab->lab_text, '_');
if (uptr != NULL) /* should always be true */
*uptr = '\0';
/* If the label is a port, then find the first unmodified
* version of the label and change the port back to its
* port number
*/
if (lab->lab_flags & PORT_DIR_MASK)
{
for (tlab = def->cd_labels; tlab; tlab = tlab->lab_next)
{
if (tlab == lab) continue;
else if (!strcmp(tlab->lab_text, lab->lab_text))
{
lab->lab_port = tlab->lab_port;
break;
}
}
}
}
}
}

View File

@ -68,12 +68,14 @@ extern const char * const extDevTable[];
#define EXT_DOADJUST 0x001 /* Extract hierarchical adjustments */
#define EXT_DOCAPACITANCE 0x002 /* Extract capacitance */
#define EXT_DOCOUPLING 0x004 /* Extract coupling capacitance */
#define EXT_DORESISTANCE 0x008 /* Extract resistance */
#define EXT_DORESISTANCE 0x008 /* Extract lumped resistance */
#define EXT_DOLENGTH 0x010 /* Extract pathlengths */
#define EXT_DOFRINGEHALO 0x020 /* Distributed fringe capacitance */
#define EXT_DOALL 0x03f /* ALL OF THE ABOVE */
#define EXT_DOLABELCHECK 0x040 /* Check for connections by label */
#define EXT_DOALIASES 0x080 /* Output all node aliases */
#define EXT_DOUNIQUE 0x100 /* Force unique nodes during extraction */
#define EXT_DOEXTRESIST 0x200 /* Do full R-C extraction */
extern int ExtOptions; /* Bitmask of above */
extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */
@ -83,6 +85,7 @@ extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */
#define EXT_UNIQ_TAGGED 1
#define EXT_UNIQ_NOPORTS 2
#define EXT_UNIQ_NOTOPPORTS 3
#define EXT_UNIQ_TEMP 4 /* Used only with "EXT_DOUNIQUE" */
extern bool ExtTechLine();
extern void ExtTechInit();
@ -110,6 +113,8 @@ extern void ExtDumpCaps();
extern int extEnumTilePerim(Tile *tpIn, TileType dinfo, const TileTypeBitMask *maskp, int pNum, int (*func)(), ClientData cdata);
extern Plane *extPrepSubstrate();
extern FILE *ExtFileOpen(CellDef *def, char *file, char *mode, char **prealfile);
/* C99 compat */
extern void ExtAll();

View File

@ -209,6 +209,7 @@ typedef struct nreg
* in X, then in Y.
*/
LabelList *nreg_labels; /* See LabRegion for description */
ClientData nreg_subnet; /* Subnet record generated by extresist */
CapValue nreg_cap; /* Capacitance to ground */
ResValue nreg_resist; /* Resistance estimate */
PerimArea nreg_pa[1]; /* Dummy; each node actually has
@ -1126,6 +1127,7 @@ extern int extMakeUnique();
extern void extEnumTerminal();
extern void extEnumTerminal(Tile *tile, TileType dinfo,
TileTypeBitMask *connect, void (*func)(), ClientData clientData);
extern void ExtRevertUniqueCell(CellDef *def);
/* ------------------ Connectivity table management ------------------- */

View File

@ -694,15 +694,22 @@ w3dCutBox(w, cmd)
{
if (crec->clipped)
{
char *cllx, *clly, *curx, *cury;
cllx = DBWPrintValue(crec->cutbox.r_xbot, w, TRUE);
clly = DBWPrintValue(crec->cutbox.r_ybot, w, TRUE);
curx = DBWPrintValue(crec->cutbox.r_xtop, w, TRUE);
cury = DBWPrintValue(crec->cutbox.r_ytop, w, TRUE);
Tcl_Obj *rlist = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, rlist,
Tcl_NewIntObj((int)(crec->cutbox.r_xbot)));
Tcl_NewStringObj(cllx, -1));
Tcl_ListObjAppendElement(magicinterp, rlist,
Tcl_NewIntObj((int)(crec->cutbox.r_ybot)));
Tcl_NewStringObj(clly, -1));
Tcl_ListObjAppendElement(magicinterp, rlist,
Tcl_NewIntObj((int)(crec->cutbox.r_xtop)));
Tcl_NewStringObj(curx, -1));
Tcl_ListObjAppendElement(magicinterp, rlist,
Tcl_NewIntObj((int)(crec->cutbox.r_ytop)));
Tcl_NewStringObj(cury, -1));
Tcl_SetObjResult(magicinterp, rlist);
}

View File

@ -1359,15 +1359,21 @@ DefReadLocation(
if (use->cu_def->cd_flags & CDFIXEDBBOX)
{
char *propval;
PropertyRecord *proprec;
bool found;
propval = (char *)DBPropGet(use->cu_def, "FIXED_BBOX", &found);
proprec = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
if (found)
{
if (sscanf(propval, "%d %d %d %d", &rect.r_xbot, &rect.r_ybot,
&rect.r_xtop, &rect.r_ytop) == 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
rect.r_xbot = proprec->prop_value.prop_integer[0];
rect.r_ybot = proprec->prop_value.prop_integer[1];
rect.r_xtop = proprec->prop_value.prop_integer[2];
rect.r_ytop = proprec->prop_value.prop_integer[3];
r = &rect;
}
}
}
}
@ -2453,7 +2459,7 @@ DefRead(
FILE *f;
char *filename;
const char *token;
char *bboxstr;
PropertyRecord *proprec;
int keyword, dscale, total;
float oscale;
Rect *dierect;
@ -2605,14 +2611,17 @@ DefRead(
break;
case DEF_DIEAREA:
dierect = LefReadRect(f, 0, oscale);
bboxstr = mallocMagic(40);
sprintf(bboxstr, "%d %d %d %d",
dierect->r_xbot,
dierect->r_ybot,
dierect->r_xtop,
dierect->r_ytop);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
2 * sizeof(int));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = 4;
proprec->prop_value.prop_integer[0] = dierect->r_xbot;
proprec->prop_value.prop_integer[1] = dierect->r_ybot;
proprec->prop_value.prop_integer[2] = dierect->r_xtop;
proprec->prop_value.prop_integer[3] = dierect->r_ytop;
if (rootDef == NULL) rootDef = DefNewCell(inName);
DBPropPut(rootDef, "FIXED_BBOX", bboxstr);
DBPropPut(rootDef, "FIXED_BBOX", proprec);
LefEndStatement(f);
break;
case DEF_PROPERTYDEFINITIONS:

View File

@ -108,7 +108,7 @@ defWriteHeader(
float oscale,
int units) /* Units for UNITS; could be derived from oscale */
{
char *propvalue;
PropertyRecord *proprec;
bool propfound;
TxPrintf("Diagnostic: Write DEF header for cell %s\n", def->cd_name);
@ -141,15 +141,20 @@ defWriteHeader(
/* For DIEAREA, use the FIXED_BBOX property if present. Otherwise, */
/* use the extents of geometry (CellDef bounding box) */
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &propfound);
proprec = DBPropGet(def, "FIXED_BBOX", &propfound);
if (propfound)
{
Rect bbox;
/* Die area, taken from the declared FIXED_BBOX. */
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) == 4)
{
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
fprintf(f, " DIEAREA ( %.10g %.10g ) ( %.10g %.10g ) ;\n",
(float)bbox.r_xbot * oscale,
(float)bbox.r_ybot * oscale,
@ -2786,15 +2791,21 @@ arrayDefFunc(
if (use->cu_def->cd_flags & CDFIXEDBBOX)
{
char *propval;
PropertyRecord *proprec;
bool found;
propval = (char *)DBPropGet(use->cu_def, "FIXED_BBOX", &found);
proprec = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
if (found)
{
if (sscanf(propval, "%d %d %d %d", &rect.r_xbot, &rect.r_ybot,
&rect.r_xtop, &rect.r_ytop) == 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
rect.r_xbot = proprec->prop_value.prop_integer[0];
rect.r_ybot = proprec->prop_value.prop_integer[1];
rect.r_xtop = proprec->prop_value.prop_integer[2];
rect.r_ytop = proprec->prop_value.prop_integer[3];
r = &rect;
}
}
}
@ -2844,15 +2855,20 @@ defComponentFunc(
xoff = yoff = 0;
if (cellUse->cu_def->cd_flags & CDFIXEDBBOX)
{
char *propval;
PropertyRecord *proprec;
bool found;
propval = (char *)DBPropGet(cellUse->cu_def, "FIXED_BBOX", &found);
proprec = DBPropGet(cellUse->cu_def, "FIXED_BBOX", &found);
if (found)
{
if (sscanf(propval, "%d %d %d %d", &rect.r_xbot, &rect.r_ybot,
&rect.r_xtop, &rect.r_ytop) == 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
rect.r_xbot = proprec->prop_value.prop_integer[0];
rect.r_ybot = proprec->prop_value.prop_integer[1];
rect.r_xtop = proprec->prop_value.prop_integer[2];
rect.r_ytop = proprec->prop_value.prop_integer[3];
r = &rect;
GeoTransRect(&cellUse->cu_transform, &rect, &bbrect);
GeoTransRect(&cellUse->cu_transform, &cellUse->cu_def->cd_bbox, &defrect);

View File

@ -2150,6 +2150,7 @@ LefReadMacro(
int keyword, pinNum, propsize, result;
float x, y;
bool has_size, is_imported = FALSE, propfound;
PropertyRecord *proprec;
Rect lefBBox;
Point gdsOffset; /* Difference between GDS and LEF coordinates */
@ -2250,7 +2251,12 @@ LefReadMacro(
sprintf(tsave + strlen(tsave), " %s", token);
token = LefNextToken(f, TRUE);
}
DBPropPut(lefMacro, "LEFclass", StrDup((char **)NULL, tsave + 1));
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
strlen(tsave + 1) - 7);
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = strlen(tsave + 1);
strcpy(proprec->prop_value.prop_string, tsave + 1);
DBPropPut(lefMacro, "LEFclass", proprec);
break;
case LEF_SIZE:
token = LefNextToken(f, TRUE);
@ -2294,7 +2300,12 @@ origin_error:
sprintf(tsave + strlen(tsave), " %s", token);
token = LefNextToken(f, TRUE);
}
DBPropPut(lefMacro, "LEFsymmetry", StrDup((char **)NULL, tsave + 1));
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
strlen(tsave + 1) - 7);
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = strlen(tsave + 1);
strcpy(proprec->prop_value.prop_string, tsave + 1);
DBPropPut(lefMacro, "LEFsymmetry", proprec);
break;
case LEF_SOURCE:
token = LefNextToken(f, TRUE);
@ -2305,12 +2316,19 @@ origin_error:
case LEF_SITE:
token = LefNextToken(f, TRUE);
if (*token != '\n')
DBPropPut(lefMacro, "LEFsite", StrDup((char **)NULL, token));
{
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
strlen(token) - 7);
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = strlen(token);
strcpy(proprec->prop_value.prop_string, token);
DBPropPut(lefMacro, "LEFsite", proprec);
}
LefEndStatement(f);
break;
case LEF_PROPERTY:
/* Append property key:value pairs to the cell property LEFproperties */
propval = (char *)DBPropGet(lefMacro, "LEFproperties", &propfound);
propval = DBPropGetString(lefMacro, "LEFproperties", &propfound);
if (propfound)
propsize = strlen(propval);
else
@ -2322,14 +2340,19 @@ origin_error:
char *propext;
sprintf(tsave, "%.127s", token);
token = LefNextToken(f, TRUE);
propext = (char *)mallocMagic(propsize + strlen(tsave) +
strlen(token) + 4);
if (propsize > 0)
sprintf(propext, "%s %s %s", propval, tsave, token);
else
sprintf(propext, "%s %s", tsave, token);
DBPropPut(lefMacro, "LEFproperties", StrDup((char **)NULL, propext));
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
propsize + strlen(tsave) + strlen(token) - 3);
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = propsize + strlen(tsave) + strlen(token) + 4;
if (propsize > 0)
sprintf(proprec->prop_value.prop_string, "%s %s %s",
propval, tsave, token);
else
sprintf(proprec->prop_value.prop_string, "%s %s", tsave, token);
DBPropPut(lefMacro, "LEFproperties", proprec);
}
LefEndStatement(f);
break;
@ -2405,11 +2428,16 @@ foreign_error:
if (has_size)
{
lefMacro->cd_flags |= CDFIXEDBBOX;
propval = (char *)mallocMagic(40);
sprintf(propval, "%d %d %d %d",
lefBBox.r_xbot, lefBBox.r_ybot,
lefBBox.r_xtop, lefBBox.r_ytop);
DBPropPut(lefMacro, "FIXED_BBOX", propval);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(2 * sizeof(int)));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = 4;
proprec->prop_value.prop_integer[0] = lefBBox.r_xbot;
proprec->prop_value.prop_integer[1] = lefBBox.r_ybot;
proprec->prop_value.prop_integer[2] = lefBBox.r_xtop;
proprec->prop_value.prop_integer[3] = lefBBox.r_ytop;
DBPropPut(lefMacro, "FIXED_BBOX", proprec);
}
}
else
@ -2419,11 +2447,16 @@ foreign_error:
if (has_size)
{
lefMacro->cd_flags |= CDFIXEDBBOX;
propval = (char *)mallocMagic(40);
sprintf(propval, "%d %d %d %d",
lefBBox.r_xbot, lefBBox.r_ybot,
lefBBox.r_xtop, lefBBox.r_ytop);
DBPropPut(lefMacro, "FIXED_BBOX", propval);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(2 * sizeof(int)));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = 4;
proprec->prop_value.prop_integer[0] = lefBBox.r_xbot;
proprec->prop_value.prop_integer[1] = lefBBox.r_ybot;
proprec->prop_value.prop_integer[2] = lefBBox.r_xtop;
proprec->prop_value.prop_integer[3] = lefBBox.r_ytop;
DBPropPut(lefMacro, "FIXED_BBOX", proprec);
}
else
{
@ -2432,13 +2465,17 @@ foreign_error:
/* Set the placement bounding box property to the current bounding box */
lefMacro->cd_flags |= CDFIXEDBBOX;
propval = (char *)mallocMagic(40);
sprintf(propval, "%d %d %d %d",
lefMacro->cd_bbox.r_xbot,
lefMacro->cd_bbox.r_ybot,
lefMacro->cd_bbox.r_xtop,
lefMacro->cd_bbox.r_ytop);
DBPropPut(lefMacro, "FIXED_BBOX", propval);
lefMacro->cd_flags |= CDFIXEDBBOX;
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(2 * sizeof(int)));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = 4;
proprec->prop_value.prop_integer[0] = lefMacro->cd_bbox.r_xbot;
proprec->prop_value.prop_integer[1] = lefMacro->cd_bbox.r_ybot;
proprec->prop_value.prop_integer[2] = lefMacro->cd_bbox.r_xtop;
proprec->prop_value.prop_integer[3] = lefMacro->cd_bbox.r_ytop;
DBPropPut(lefMacro, "FIXED_BBOX", proprec);
DRCCheckThis(lefMacro, TT_CHECKPAINT, &lefMacro->cd_bbox);
}
}
@ -2453,7 +2490,13 @@ foreign_error:
/* i.e., setting it to "FALSE" would be ineffective. */
if (!is_imported)
DBPropPut(lefMacro, "LEFview", StrDup((char **)NULL, "TRUE"));
{
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = 4;
strcpy(proprec->prop_value.prop_string, "TRUE");
DBPropPut(lefMacro, "LEFview", proprec);
}
DBWAreaChanged(lefMacro, &lefMacro->cd_bbox, DBW_ALLWINDOWS,
&DBAllButSpaceBits);

View File

@ -328,14 +328,14 @@ lefWriteHeader(
{
fprintf(f, "SITE %s\n", siteDef->cd_name);
propvalue = (char *)DBPropGet(siteDef, "LEFsymmetry", &propfound);
propvalue = DBPropGetString(siteDef, "LEFsymmetry", &propfound);
if (propfound)
fprintf(f, IN0 "SYMMETRY %s ;\n", propvalue);
else
/* Usually core cells have symmetry Y only. */
fprintf(f, IN0 "SYMMETRY Y ;\n");
propvalue = (char *)DBPropGet(siteDef, "LEFclass", &propfound);
propvalue = DBPropGetString(siteDef, "LEFclass", &propfound);
if (propfound)
fprintf(f, IN0 "CLASS %s ;\n", propvalue);
else
@ -345,10 +345,20 @@ lefWriteHeader(
boundary = siteDef->cd_bbox;
if (siteDef->cd_flags & CDFIXEDBBOX)
{
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &propfound);
PropertyRecord *proprec;
proprec = DBPropGet(def, "FIXED_BBOX", &propfound);
if (propfound)
sscanf(propvalue, "%d %d %d %d", &boundary.r_xbot,
&boundary.r_ybot, &boundary.r_xtop, &boundary.r_ytop);
{
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
boundary.r_xbot = proprec->prop_value.prop_integer[0];
boundary.r_ybot = proprec->prop_value.prop_integer[1];
boundary.r_xtop = proprec->prop_value.prop_integer[2];
boundary.r_ytop = proprec->prop_value.prop_integer[3];
}
}
}
scale = CIFGetOutputScale(1000); /* conversion to microns */
@ -1288,7 +1298,7 @@ lefWriteMacro(
/* default values are optional, so in this case we will leave those */
/* entries blank. */
propvalue = (char *)DBPropGet(def, "LEFclass", &propfound);
propvalue = DBPropGetString(def, "LEFclass", &propfound);
if (propfound)
{
fprintf(f, IN0 "CLASS %s ;\n", propvalue);
@ -1324,13 +1334,21 @@ lefWriteMacro(
if (def->cd_flags & CDFIXEDBBOX)
{
char *propvalue;
PropertyRecord *proprec;
bool found;
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &found);
proprec = DBPropGet(def, "FIXED_BBOX", &found);
if (found)
sscanf(propvalue, "%d %d %d %d", &boundary.r_xbot,
&boundary.r_ybot, &boundary.r_xtop, &boundary.r_ytop);
{
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
boundary.r_xbot = proprec->prop_value.prop_integer[0];
boundary.r_ybot = proprec->prop_value.prop_integer[1];
boundary.r_xtop = proprec->prop_value.prop_integer[2];
boundary.r_ytop = proprec->prop_value.prop_integer[3];
}
}
}
/* Check if (boundry less setback) is degenerate. If so, then */
@ -1358,11 +1376,11 @@ lefWriteMacro(
lc.origin.p_x = 0;
lc.origin.p_y = 0;
propvalue = (char *)DBPropGet(def, "LEFsymmetry", &propfound);
propvalue = DBPropGetString(def, "LEFsymmetry", &propfound);
if (propfound)
fprintf(f, IN0 "SYMMETRY %s ;\n", propvalue);
propvalue = (char *)DBPropGet(def, "LEFsite", &propfound);
propvalue = DBPropGetString(def, "LEFsite", &propfound);
if (propfound)
fprintf(f, IN0 "SITE %s ;\n", propvalue);
@ -1821,20 +1839,24 @@ lefWriteMacro(
Rect layerBound, manualBound;
labelLinkedList *thislll;
bool propfound;
char *propvalue;
PropertyRecord *proprec;
/* If there is a property OBS_BBOX, then use the value of the */
/* defined box to set the minimum hidden area. This will still */
/* get clipped to the setback. */
propvalue = (char *)DBPropGet(def, "OBS_BBOX", &propfound);
proprec = DBPropGet(def, "OBS_BBOX", &propfound);
if (propfound)
{
if (sscanf(propvalue, "%d %d %d %d",
&(manualBound.r_xbot),
&(manualBound.r_ybot),
&(manualBound.r_xtop),
&(manualBound.r_ytop)) != 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
manualBound.r_xbot = proprec->prop_value.prop_integer[0];
manualBound.r_ybot = proprec->prop_value.prop_integer[1];
manualBound.r_xtop = proprec->prop_value.prop_integer[2];
manualBound.r_ytop = proprec->prop_value.prop_integer[3];
}
else
{
TxError("Improper values for obstruction bounding box "
"OBS_BBOX property");
@ -2016,7 +2038,7 @@ lefWriteMacro(
/* If there are any properties saved in LEFproperties, write them out */
propvalue = (char *)DBPropGet(def, "LEFproperties", &propfound);
propvalue = DBPropGetString(def, "LEFproperties", &propfound);
if (propfound)
{
char *delim;
@ -2094,7 +2116,7 @@ lefGetSites(
bool propfound;
char *propvalue;
propvalue = (char *)DBPropGet(def, "LEFsite", &propfound);
propvalue = DBPropGetString(def, "LEFsite", &propfound);
if (propfound)
he = HashFind(lefSiteTbl, propvalue); /* FIXME return value not used from call to function with no side-effects (reevaluate this entire func purpose?) */
@ -2124,7 +2146,7 @@ lefGetProperties(
bool propfound;
char *propvalue;
propvalue = (char *)DBPropGet(def, "LEFproperties", &propfound);
propvalue = DBPropGetString(def, "LEFproperties", &propfound);
if (propfound)
{
char *key;

View File

@ -120,61 +120,61 @@ macro Control_XK_space "tool wiring"
# Arrow keys (X11 versions only)
macro XK_Left "scroll l .1 w"
macro Shift_XK_Left "scroll l 1 w"
macro Control_XK_Left "box grow w 1"
macro Control_Shift_XK_Left "box shrink e 1"
macro Control_XK_Left "box grow w 1i"
macro Control_Shift_XK_Left "box shrink e 1i"
macro XK_Right "scroll r .1 w"
macro Shift_XK_Right "scroll r 1 w"
macro Control_XK_Right "box grow e 1"
macro Control_Shift_XK_Right "box shrink w 1"
macro Control_XK_Right "box grow e 1i"
macro Control_Shift_XK_Right "box shrink w 1i"
macro XK_Up "scroll u .1 w"
macro Shift_XK_Up "scroll u 1 w"
macro Control_XK_Up "box grow n 1"
macro Control_Shift_XK_Up "box shrink s 1"
macro Control_XK_Up "box grow n 1i"
macro Control_Shift_XK_Up "box shrink s 1i"
macro XK_Down "scroll d .1 w"
macro Shift_XK_Down "scroll d 1 w"
macro Control_XK_Down "box grow s 1"
macro Control_Shift_XK_Down "box shrink n 1"
macro Control_XK_Down "box grow s 1i"
macro Control_Shift_XK_Down "box shrink n 1i"
# Keypad keys (X11 versions only)
# Functions duplicated for use both with Num_Lock ON and OFF
macro XK_KP_Delete "box size 0 0"
macro XK_KP_Insert "box size 4 4"
macro XK_KP_0 "box size 7 2"
macro Shift_XK_KP_0 "box size 7 2"
macro XK_0 "box size 7 2"
macro Control_XK_KP_0 "box size 2 7"
macro Control_XK_KP_Insert "box size 2 7"
macro XK_KP_End "move sw 1"
macro XK_KP_Down "move d 1"
macro XK_KP_2 "stretch d 1"
macro XK_KP_Insert "box size 4l 4l"
macro XK_KP_0 "box size 7l 2l"
macro Shift_XK_KP_0 "box size 7l 2l"
macro XK_0 "box size 7l 2l"
macro Control_XK_KP_0 "box size 2l 7l"
macro Control_XK_KP_Insert "box size 2l 7l"
macro XK_KP_End "move sw 1i"
macro XK_KP_Down "move d 1i"
macro XK_KP_2 "stretch d 1i"
macro Shift_XK_KP_2 "stretch d 1"
macro Shift_XK_KP_Down "stretch d 1"
macro Shift_XK_KP_Down "move d 1"
macro Control_XK_KP_Down "stretch d 1i"
macro XK_2 "stretch d 1"
macro XK_KP_Next "move se 1"
macro XK_KP_Left "move l 1"
macro XK_KP_4 "stretch l 1"
macro XK_2 "stretch d 1i"
macro XK_KP_Next "move se 1i"
macro XK_KP_Left "move l 1i"
macro XK_KP_4 "stretch l 1i"
macro Shift_XK_KP_4 "stretch l 1"
macro Shift_XK_KP_Left "stretch l 1"
macro Shift_XK_KP_Left "move l 1"
macro Control_XK_KP_Left "stretch l 1i"
macro XK_4 "stretch l 1"
macro XK_4 "stretch l 1i"
macro XK_KP_Begin "findbox zoom"
macro XK_KP_5 "findbox"
macro Shift_XK_KP_5 "findbox"
macro XK_5 "findbox"
macro XK_KP_Right "move r 1"
macro XK_KP_6 "stretch r 1"
macro XK_KP_Right "move r 1i"
macro XK_KP_6 "stretch r 1i"
macro Shift_XK_KP_6 "stretch r 1"
macro Shift_XK_KP_Right "stretch r 1"
macro Shift_XK_KP_Right "move r 1"
macro Control_XK_KP_Right "stretch r 1i"
macro XK_6 "stretch r 1"
macro XK_KP_Home "move nw 1"
macro XK_KP_Up "move u 1"
macro XK_KP_8 "stretch u 1"
macro XK_6 "stretch r 1i"
macro XK_KP_Home "move nw 1i"
macro XK_KP_Up "move u 1i"
macro XK_KP_8 "stretch u 1i"
macro Shift_XK_KP_8 "stretch u 1"
macro Shift_XK_KP_Up "stretch u 1"
macro Shift_XK_KP_Up "move u 1"
macro Control_XK_KP_Up "stretch u 1i"
macro XK_8 "stretch u 1"
macro XK_KP_Prior "move ne 1"
macro XK_8 "stretch u 1i"
macro XK_KP_Prior "move ne 1i"
# Scroll wheel bindings
macro XK_Pointer_Button4 "scroll u .05 w"
macro XK_Pointer_Button5 "scroll d .05 w"

View File

@ -58,6 +58,8 @@ MAGIC_8.0 {
DBPlaneTypes;
DBPrintUseId;
DBPropGet;
DBPropGetString;
DBPropGetDouble;
DBPutLabel;
DBReComputeBbox;
DBSeeTypesAll;

View File

@ -5,7 +5,7 @@
MODULE = resis
MAGICDIR = ..
SRCS = ResMain.c ResJunct.c ResMakeRes.c ResSimple.c ResPrint.c \
ResReadSim.c ResRex.c ResBasic.c ResMerge.c ResChecks.c \
ResReadExt.c ResRex.c ResBasic.c ResMerge.c ResChecks.c \
ResFract.c ResUtils.c ResDebug.c
include ${MAGICDIR}/defs.mak

View File

@ -46,22 +46,22 @@ resNodeIsPort(node, x, y, tile)
Rect *rect;
Point p;
resPort *pl, *lp;
tileJunk *junk = (tileJunk *)TiGetClientPTR(tile);
resInfo *info = (resInfo *)TiGetClientPTR(tile);
p.p_x = x;
p.p_y = y;
for (pl = junk->portList; pl; pl = pl->rp_nextPort)
for (pl = info->portList; pl; pl = pl->rp_nextPort)
{
rect = &(pl->rp_bbox);
if (GEO_ENCLOSE(&p, rect))
{
node->rn_name = pl->rp_nodename;
if (junk->portList == pl)
junk->portList = pl->rp_nextPort;
if (info->portList == pl)
info->portList = pl->rp_nextPort;
else
{
for (lp = junk->portList; lp && (lp->rp_nextPort != pl);
for (lp = info->portList; lp && (lp->rp_nextPort != pl);
lp = lp->rp_nextPort);
lp->rp_nextPort = pl->rp_nextPort;
}
@ -77,7 +77,8 @@ resNodeIsPort(node, x, y, tile)
* resAllPortNodes --
*
* Generate new nodes and breakpoints for every unused port declared
* on a tile.
* on a tile. However, if "startpoint" is inside the port position,
* then it has already been processed, so ignore it.
*
*--------------------------------------------------------------------------
*/
@ -90,15 +91,15 @@ resAllPortNodes(tile, list)
int x, y;
resNode *resptr;
resPort *pl;
tileJunk *junk = (tileJunk *)TiGetClientPTR(tile);
resInfo *info = (resInfo *)TiGetClientPTR(tile);
free_magic1_t mm1 = freeMagic1_init();
for (pl = junk->portList; pl; pl = pl->rp_nextPort)
for (pl = info->portList; pl; pl = pl->rp_nextPort)
{
x = pl->rp_loc.p_x;
y = pl->rp_loc.p_y;
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
InitializeNode(resptr, x, y, RES_NODE_ORIGIN);
InitializeResNode(resptr, x, y, RES_NODE_ORIGIN);
resptr->rn_status = TRUE;
resptr->rn_noderes = 0;
resptr->rn_name = pl->rp_nodename;
@ -225,7 +226,7 @@ ResEachTile(tile, startpoint)
int xj, yj, i;
bool merged;
tElement *tcell;
tileJunk *tstructs= (tileJunk *)TiGetClientPTR(tile);
resInfo *tstructs= (resInfo *)TiGetClientPTR(tile);
ExtDevice *devptr;
int sides;
@ -262,7 +263,7 @@ ResEachTile(tile, startpoint)
int x = startpoint->p_x;
int y = startpoint->p_y;
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
InitializeNode(resptr, x, y, RES_NODE_ORIGIN);
InitializeResNode(resptr, x, y, RES_NODE_ORIGIN);
resptr->rn_status = TRUE;
resptr->rn_noderes = 0;
ResAddToQueue(resptr, &ResNodeQueue);
@ -278,7 +279,7 @@ ResEachTile(tile, startpoint)
* for single tile device, but not as good for multiple ones.
*/
if (tstructs->tj_status & RES_TILE_DEV)
if (tstructs->ri_status & RES_TILE_DEV)
{
if (tstructs->deviceList->rd_fet_gate == NULL)
{
@ -291,7 +292,7 @@ ResEachTile(tile, startpoint)
tcell->te_thist = tstructs->deviceList;
tcell->te_nextt = NULL;
InitializeNode(resptr, x, y, RES_NODE_JUNCTION);
InitializeResNode(resptr, x, y, RES_NODE_JUNCTION);
resptr->rn_te = tcell;
ResAddToQueue(resptr, &ResNodeQueue);
resNodeIsPort(resptr, x, y, tile);
@ -516,7 +517,7 @@ ResEachTile(tile, startpoint)
}
}
tstructs->tj_status |= RES_TILE_DONE;
tstructs->ri_status |= RES_TILE_DONE;
resAllPortNodes(tile, &ResNodeQueue);

View File

@ -64,7 +64,7 @@ ResSanityChecks(nodename, resistorList, nodeList, devlist)
for (node = nodeList; node != NULL; node=node->rn_more)
{
node->rn_status &= ~RES_REACHED_NODE;
if (node->rn_why == RES_NODE_ORIGIN)
if (node->rn_why & RES_NODE_ORIGIN)
STACKPUSH((ClientData) node, resSanityStack);
}
for (resistor = resistorList; resistor != NULL; resistor = resistor->rr_nextResistor)
@ -112,7 +112,6 @@ ResSanityChecks(nodename, resistorList, nodeList, devlist)
{
int i;
if (dev->rd_status & RES_DEV_PLUG) continue;
reached = FALSE;
for (i = 0; i != dev->rd_nterms; i++)
{

View File

@ -120,7 +120,6 @@ ResPrintDeviceList(fp, list)
int i;
for (; list != NULL; list = list->rd_nextDev)
{
if (list->rd_status & RES_DEV_PLUG) continue;
if (fp == stdout)
TxPrintf("t w %d l %d ", list->rd_width, list->rd_length);
else

View File

@ -52,7 +52,7 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
resDevice *resDev;
tElement *tcell;
int newnode;
tileJunk *j;
resInfo *ri;
newnode = FALSE;
@ -62,9 +62,9 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
*/
if (TiGetClient(tp) == CLIENTDEFAULT) return;
j = (tileJunk *) TiGetClientPTR(tp);
resDev = j->deviceList;
if ((j->sourceEdge & direction) != 0)
ri = (resInfo *) TiGetClientPTR(tp);
resDev = ri->deviceList;
if ((ri->sourceEdge & direction) != 0)
{
if (resDev->rd_fet_source == (resNode *) NULL)
{
@ -94,8 +94,8 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
{
tcell = (tElement *) mallocMagic((unsigned)(sizeof(tElement)));
tcell->te_nextt = NULL;
tcell->te_thist = j->deviceList;
InitializeNode(resptr, xj, yj, RES_NODE_DEVICE);
tcell->te_thist = ri->deviceList;
InitializeResNode(resptr, xj, yj, RES_NODE_DEVICE);
resptr->rn_te = tcell;
ResAddToQueue(resptr, PendingList);
}
@ -125,11 +125,11 @@ ResNewSubDevice(tile, tp, xj, yj, direction, PendingList)
resDevice *resDev;
tElement *tcell;
int newnode;
tileJunk *j;
resInfo *ri;
newnode = FALSE;
j = (tileJunk *) TiGetClientPTR(tp);
resDev = j->deviceList;
ri = (resInfo *) TiGetClientPTR(tp);
resDev = ri->deviceList;
/* Arrived at a device that has a terminal connected to substrate */
/* that is not a FET bulk terminal (e.g., varactor, diode). */
@ -150,8 +150,8 @@ ResNewSubDevice(tile, tp, xj, yj, direction, PendingList)
{
tcell = (tElement *) mallocMagic((unsigned)(sizeof(tElement)));
tcell->te_nextt = NULL;
tcell->te_thist = j->deviceList;
InitializeNode(resptr, xj, yj, RES_NODE_DEVICE);
tcell->te_thist = ri->deviceList;
InitializeResNode(resptr, xj, yj, RES_NODE_DEVICE);
resptr->rn_te = tcell;
ResAddToQueue(resptr, PendingList);
}
@ -181,8 +181,8 @@ ResProcessJunction(tile, tp, xj, yj, NodeList)
ResJunction *junction;
resNode *resptr;
jElement *jcell;
tileJunk *j0 = (tileJunk *)TiGetClientPTR(tile);
tileJunk *j2 = (tileJunk *)TiGetClientPTR(tp);
resInfo *ri0 = (resInfo *)TiGetClientPTR(tile);
resInfo *ri2 = (resInfo *)TiGetClientPTR(tp);
#ifdef PARANOID
if (tile == tp)
@ -191,12 +191,12 @@ ResProcessJunction(tile, tp, xj, yj, NodeList)
return;
}
#endif
if (j2->tj_status & RES_TILE_DONE) return;
if (ri2->ri_status & RES_TILE_DONE) return;
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
resptr->rn_te = (tElement *) NULL;
junction = (ResJunction *) mallocMagic((unsigned)(sizeof(ResJunction)));
jcell = (jElement *) mallocMagic((unsigned)(sizeof(jElement)));
InitializeNode(resptr, xj, yj, RES_NODE_JUNCTION);
InitializeResNode(resptr, xj, yj, RES_NODE_JUNCTION);
resptr->rn_je = jcell;
ResAddToQueue(resptr, NodeList);
@ -208,10 +208,10 @@ ResProcessJunction(tile, tp, xj, yj, NodeList)
junction->rj_Tile[1] = tp;
junction->rj_loc.p_x =xj;
junction->rj_loc.p_y =yj;
junction->rj_nextjunction[0] = j0->junctionList;
j0->junctionList = junction;
junction->rj_nextjunction[1] = j2->junctionList;
j2->junctionList = junction;
junction->rj_nextjunction[0] = ri0->junctionList;
ri0->junctionList = junction;
junction->rj_nextjunction[1] = ri2->junctionList;
ri2->junctionList = junction;
NEWBREAK(junction->rj_jnode,tile, junction->rj_loc.p_x,
junction->rj_loc.p_y, NULL);

View File

@ -35,13 +35,12 @@ resNode *ResNodeList = NULL; /* Processed Nodes */
resDevice *ResDevList = NULL; /* Devices */
ResContactPoint *ResContactList = NULL; /* Contacts */
resNode *ResNodeQueue = NULL; /* Pending nodes */
resNode *ResOriginNode = NULL; /* node where R=0 */
resNode *ResNodeAtOrigin = NULL; /* node where R=0 */
resNode *resCurrentNode;
int ResTileCount = 0; /* Number of tiles rn_status */
extern ExtRegion *ResFirst();
extern Tile *FindStartTile();
extern int ResEachTile();
extern ResSimNode *ResInitializeNode();
TileTypeBitMask ResSDTypesBitMask;
TileTypeBitMask ResSubTypesBitMask;
@ -184,7 +183,7 @@ ResDissolveContacts(contacts)
* ResMakePortBreakpoints --
*
* Search for nodes which are ports, and force them to be breakpoints
* in the "tileJunk" field of their respective tiles in ResUse. This
* in the "resInfo" field of their respective tiles in ResUse. This
* ensures that connected nodes that stretch between two ports will
* not be assumed to be "hanging" nodes.
*
@ -201,13 +200,13 @@ ResMakePortBreakpoints(def)
TileTypeBitMask mask;
HashSearch hs;
HashEntry *entry;
ResSimNode *node;
ResExtNode *node;
int ResAddBreakpointFunc(); /* Forward Declaration */
HashStartSearch(&hs);
while((entry = HashNext(&ResNodeTable,&hs)) != NULL)
while((entry = HashNext(&ResNodeTable, &hs)) != NULL)
{
node = (ResSimNode *)HashGetValue(entry);
node = (ResExtNode *)HashGetValue(entry);
if (node->status & PORTNODE)
{
if (node->rs_ttype <= 0)
@ -266,22 +265,22 @@ ResMakePortBreakpoints(def)
* ResMakeLabelBreakpoints --
*
* Search for labels that are part of a node, and force them to be
* breakpoints in the "tileJunk" field of their respective tiles in
* breakpoints in the "resInfo" field of their respective tiles in
* ResUse. This ensures (among other things) that pins of a top level
* cell will be retained and become the endpoint of a net.
*
*----------------------------------------------------------------------------
*/
void
ResMakeLabelBreakpoints(def, goodies)
CellDef *def;
ResGlobalParams *goodies;
ResMakeLabelBreakpoints(def, resisdata)
CellDef *def;
ResisData *resisdata;
{
Plane *plane;
Rect *rect;
TileTypeBitMask mask;
HashEntry *entry;
ResSimNode *node;
ResExtNode *node;
Label *slab;
int ResAddBreakpointFunc(); /* Forward Declaration */
@ -292,14 +291,14 @@ ResMakeLabelBreakpoints(def, goodies)
if (*(slab->lab_text) == '\0') continue;
entry = HashFind(&ResNodeTable, slab->lab_text);
node = ResInitializeNode(entry);
node = ResExtInitNode(entry);
/* If the drivepoint position changes and the drivepoint is */
/* in the "goodies" record, then make sure the tile type in */
/* "goodies" gets changed to match. */
/* If the drivepoint position changes and the drivepoint is */
/* in the "resisdata" record, then make sure the tile type */
/* in "resisdata" gets changed to match. */
if (goodies->rg_devloc == &node->drivepoint)
goodies->rg_ttype = slab->lab_type;
if (resisdata->rg_devloc == &node->drivepoint)
resisdata->rg_ttype = slab->lab_type;
node->drivepoint = slab->lab_rect.r_ll;
node->rs_bbox = slab->lab_rect;
@ -344,7 +343,7 @@ ResMakeLabelBreakpoints(def, goodies)
*
* ResAddBreakpointFunc --
*
* Add a breakpoint to the "tileJunk" structure of the tile
* Add a breakpoint to the "resInfo" structure of the tile
*
*----------------------------------------------------------------------------
*/
@ -353,9 +352,9 @@ int
ResAddBreakpointFunc(tile, dinfo, node)
Tile *tile;
TileType dinfo; /* (unused) */
ResSimNode *node;
ResExtNode *node;
{
tileJunk *junk;
resInfo *info;
if (TiGetClient(tile) == CLIENTDEFAULT)
return 0;
@ -430,15 +429,15 @@ ResFindNewContactTiles(contacts)
if ((IsSplit(tile) && TTMaskHasType(&mask, TiGetRightType(tile)))
|| TTMaskHasType(&mask, TiGetLeftType(tile)))
{
tileJunk *j = (tileJunk *)TiGetClientPTR(tile);
resInfo *ri = (resInfo *)TiGetClientPTR(tile);
cElement *ce;
ce = (cElement *) mallocMagic((unsigned) (sizeof(cElement)));
contacts->cp_tile[contacts->cp_currentcontact] = tile;
ce->ce_thisc = contacts;
ce->ce_nextc = j->contactList;
ce->ce_nextc = ri->contactList;
(contacts->cp_currentcontact) += 1;
j->contactList = ce;
ri->contactList = ce;
}
else if (!IsSplit(tile))
{
@ -452,15 +451,15 @@ ResFindNewContactTiles(contacts)
*/
if (TTMaskIntersect(DBResidueMask(ttype), &mask))
{
tileJunk *j = (tileJunk *)TiGetClientPTR(tile);
resInfo *ri = (resInfo *)TiGetClientPTR(tile);
cElement *ce;
ce = (cElement *) mallocMagic((unsigned) (sizeof(cElement)));
contacts->cp_tile[contacts->cp_currentcontact] = tile;
ce->ce_thisc = contacts;
ce->ce_nextc = j->contactList;
ce->ce_nextc = ri->contactList;
(contacts->cp_currentcontact) += 1;
j->contactList = ce;
ri->contactList = ce;
}
}
}
@ -490,9 +489,9 @@ ResFindNewContactTiles(contacts)
*/
int
ResProcessTiles(goodies, origin)
Point *origin;
ResGlobalParams *goodies;
ResProcessTiles(resisdata, origin)
Point *origin;
ResisData *resisdata;
{
Tile *startTile;
@ -506,57 +505,12 @@ ResProcessTiles(goodies, origin)
if (ResOptionsFlags & ResOpt_Signal)
{
startTile = FindStartTile(goodies, origin);
startTile = FindStartTile(resisdata, origin);
if (startTile == NULL)
return 1;
resCurrentNode = NULL;
(void) ResEachTile(startTile, origin);
}
#ifdef ARIEL
else if (ResOptionsFlags & ResOpt_Power)
{
for (fix = ResFixList; fix != NULL; fix = fix->fp_next)
{
Tile *tile = fix->fp_tile;
if (tile == NULL)
{
tile = PlaneGetHint(ResDef->cd_planes[DBPlane(fix->fp_ttype)]);
GOTOPOINT(tile, &(fix->fp_loc));
if (TiGetTypeExact(tile) != TT_SPACE)
{
fix->fp_tile = tile;
}
else
{
tile = NULL;
}
}
if (tile != NULL)
{
int x = fix->fp_loc.p_x;
int y = fix->fp_loc.p_y;
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
InitializeNode(resptr, x, y, RES_NODE_ORIGIN);
resptr->rn_status = TRUE;
resptr->rn_noderes = 0;
ResAddToQueue(resptr, &ResNodeQueue);
fix->fp_node = resptr;
NEWBREAK(resptr, tile, x, y, NULL);
}
}
for (fix = ResFixList; fix != NULL; fix = fix->fp_next)
{
Tile *tile = fix->fp_tile;
if (tile != NULL && (((tileJunk *)TiGetClientPTR(tile)->tj_status &
RES_TILE_DONE) == 0)
{
resCurrentNode = fix->fp_node;
(void) ResEachTile(startile, (Point *)NULL);
}
}
}
#endif
#ifdef PARANOID
else
{
@ -569,7 +523,7 @@ ResProcessTiles(goodies, origin)
while (ResNodeQueue != NULL)
{
/*
* merged keeps track of whether another node gets merged into
* "merged" keeps track of whether another node gets merged into
* the current one. If it does, then the node must be processed
* because additional junctions or contacts were added
*/
@ -587,16 +541,14 @@ ResProcessTiles(goodies, origin)
for (tilenum = 0; tilenum < TILES_PER_JUNCTION; tilenum++)
{
Tile *tile = rj->rj_Tile[tilenum];
tileJunk *j = (tileJunk *)TiGetClientPTR(tile);
resInfo *ri = (resInfo *)TiGetClientPTR(tile);
if ((j->tj_status & RES_TILE_DONE) == 0)
if ((ri->ri_status & RES_TILE_DONE) == 0)
{
resCurrentNode = resptr2;
merged |= ResEachTile(tile, (Point *)NULL);
}
if (merged & ORIGIN) break;
}
if (merged & ORIGIN) break;
rj->rj_status = TRUE;
}
}
@ -607,16 +559,15 @@ ResProcessTiles(goodies, origin)
{
ResContactPoint *cp = workingc->ce_thisc;
if (merged & ORIGIN) break;
if (cp->cp_status == FALSE)
{
int newstatus = TRUE;
for (tilenum = 0; tilenum < cp->cp_currentcontact; tilenum++)
{
Tile *tile = cp->cp_tile[tilenum];
tileJunk *j = (tileJunk *) TiGetClientPTR(tile);
resInfo *ri = (resInfo *) TiGetClientPTR(tile);
if ((j->tj_status & RES_TILE_DONE) == 0)
if ((ri->ri_status & RES_TILE_DONE) == 0)
{
if (cp->cp_cnode[tilenum] == resptr2)
{
@ -628,9 +579,7 @@ ResProcessTiles(goodies, origin)
newstatus = FALSE;
}
}
if (merged & ORIGIN) break;
}
if (merged & ORIGIN) break;
cp->cp_status = newstatus;
}
}
@ -646,15 +595,15 @@ ResProcessTiles(goodies, origin)
ResRemoveFromQueue(resptr2, &ResNodeQueue);
resptr2->rn_more = ResNodeList;
resptr2->rn_less = NULL;
resptr2->rn_status &= ~PENDING;
resptr2->rn_status |= FINISHED | MARKED;
resptr2->rn_status &= ~RES_PENDING;
resptr2->rn_status |= RES_FINISHED | RES_MARKED;
if (ResNodeList != NULL)
{
ResNodeList->rn_less = resptr2;
}
if (resptr2->rn_noderes == 0)
{
ResOriginNode=resptr2;
ResNodeAtOrigin = resptr2;
}
ResNodeList = resptr2;
ResCleanNode(resptr2, FALSE, &ResNodeList, &ResNodeQueue);
@ -733,7 +682,7 @@ ResCalcPerimOverlap(tile, dev)
* resMakeDevFunc --
*
* Callback function from ResExtractNet. For each device in a node's
* device list pulled from the .sim file, find the tile(s) corresponding
* device list pulled from the .ext file, find the tile(s) corresponding
* to the device in the source tree, and fill out the complete device
* record (namely the full device area).
*
@ -771,7 +720,7 @@ resMakeDevFunc(tile, dinfo, cx)
/* If more than one tile type extracts to the same device, then */
/* the device type may be different from what was recorded when */
/* the sim file was read. Restricted to the plane of the */
/* the .ext file was read. Restricted to the plane of the */
/* original type to avoid conflict with completely different */
/* devices (like transistors vs. MiM caps). */
@ -1035,9 +984,9 @@ ResShaveContacts(tile, dinfo, def)
*/
bool
ResExtractNet(node, goodies, cellname)
ResSimNode *node;
ResGlobalParams *goodies;
ResExtractNet(node, resisdata, cellname)
ResExtNode *node;
ResisData *resisdata;
char *cellname;
{
SearchContext scx;
@ -1059,12 +1008,12 @@ ResExtractNet(node, goodies, cellname)
ResDevList = NULL;
ResNodeQueue = NULL;
ResContactList = NULL;
ResOriginNode = NULL;
ResNodeAtOrigin = NULL;
/* Pass back network pointers */
goodies->rg_maxres = 0;
goodies->rg_tilecount = 0;
resisdata->rg_maxres = 0;
resisdata->rg_tilecount = 0;
/* Set up internal stuff if this is the first time through */
@ -1103,11 +1052,6 @@ ResExtractNet(node, goodies, cellname)
DBCellClearDef(ResUse->cu_def);
#ifdef ARIEL
if ((ResOptionsFlags & ResOpt_Power) &&
strcmp(node->name, goodies->rg_name) != 0) continue;
#endif
/* Copy Paint */
scx.scx_area.r_ll.p_x = node->location.p_x - 2;
@ -1152,10 +1096,10 @@ ResExtractNet(node, goodies, cellname)
resMakeDevFunc, (ClientData)thisDev);
if (result == 0)
{
TxError("No device of type %s found at location %d,%d\n",
TxError("No device of type %s found at location %s, %s\n",
DBTypeLongNameTbl[thisDev->type],
tptr->thisDev->location.p_x,
tptr->thisDev->location.p_y);
DBWPrintValue(tptr->thisDev->location.p_x, (MagWindow*)NULL, TRUE),
DBWPrintValue(tptr->thisDev->location.p_y, (MagWindow*)NULL, FALSE));
freeMagic(thisDev);
continue;
}
@ -1219,7 +1163,7 @@ ResExtractNet(node, goodies, cellname)
ResDissolveContacts(ResContactList);
/* Add "junk" fields to tiles */
/* Add "resInfo" fields to tiles */
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
@ -1232,39 +1176,22 @@ ResExtractNet(node, goodies, cellname)
(ClientData) &ResDevList);
}
/* Finish preprocessing. */
/* If this is a top-level cell, then determine where connections
* are made into the cell from ports. Otherwise, determine points
* of entry by looking at how all parent cells connect to this
* cell.
*/
ResMakePortBreakpoints(ResUse->cu_def);
ResMakeLabelBreakpoints(ResUse->cu_def, goodies);
ResMakeLabelBreakpoints(ResUse->cu_def, resisdata);
/* Finish preprocessing. */
ResFindNewContactTiles(ResContactList);
ResPreProcessDevices(DevTiles, ResDevList, ResUse->cu_def);
#ifdef LAPLACE
if (ResOptionsFlags & ResOpt_DoLaplace)
{
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
Plane *plane = ResUse->cu_def->cd_planes[pNum];
Rect *rect = &ResUse->cu_def->cd_bbox;
Res1d(plane, rect);
}
}
#endif
#ifdef ARIEL
if (ResOptionsFlags & ResOpt_Power)
{
for (fix = startlist; fix != NULL; fix = fix->fp_next)
{
fix->fp_tile = PlaneGetHint(ResUse->cu_def->cd_planes[DBPlane(fix->fp_ttype)]);
GOTOPOINT(fix->fp_tile, &fix->fp_loc);
if (TiGetTypeExact(fix->fp_tile) == TT_SPACE) fix->fp_tile = NULL;
}
}
#endif
/* do extraction */
if (ResProcessTiles(goodies, &startpoint) != 0) return TRUE;
if (ResProcessTiles(resisdata, &startpoint) != 0) return TRUE;
return FALSE;
}
@ -1383,7 +1310,7 @@ ResGetTileFunc(tile, dinfo, tpptr)
*-------------------------------------------------------------------------
*
* FindStartTile-- To start the extraction, we need to find the first driver.
* The sim file gives us the location of a point in or near (within 1
* The .ext file gives us the location of a point in or near (within 1
* unit) of the device. FindStartTile looks for the device, then
* for adjoining diffusion. The diffusion tile is returned.
*
@ -1397,10 +1324,9 @@ ResGetTileFunc(tile, dinfo, tpptr)
*/
Tile *
FindStartTile(goodies, SourcePoint)
FindStartTile(resisdata, SourcePoint)
ResisData *resisdata;
Point *SourcePoint;
ResGlobalParams *goodies;
{
Point workingPoint;
Tile *tile, *tp;
@ -1413,39 +1339,39 @@ FindStartTile(goodies, SourcePoint)
/* If the drive point is on a contact, check for the contact residues */
/* first, then the contact type itself. */
if (DBIsContact(goodies->rg_ttype))
if (DBIsContact(resisdata->rg_ttype))
{
TileTypeBitMask *rmask = DBResidueMask(goodies->rg_ttype);
TileType savtype = goodies->rg_ttype;
TileTypeBitMask *rmask = DBResidueMask(resisdata->rg_ttype);
TileType savtype = resisdata->rg_ttype;
TileType rtype;
for (rtype = TT_TECHDEPBASE; rtype < DBNumUserLayers; rtype++)
if (TTMaskHasType(rmask, rtype))
{
goodies->rg_ttype = rtype;
if ((tile = FindStartTile(goodies, SourcePoint)) != NULL)
resisdata->rg_ttype = rtype;
if ((tile = FindStartTile(resisdata, SourcePoint)) != NULL)
{
goodies->rg_ttype = savtype;
resisdata->rg_ttype = savtype;
return tile;
}
}
goodies->rg_ttype = savtype;
resisdata->rg_ttype = savtype;
}
workingPoint.p_x = goodies->rg_devloc->p_x;
workingPoint.p_y = goodies->rg_devloc->p_y;
workingPoint.p_x = resisdata->rg_devloc->p_x;
workingPoint.p_y = resisdata->rg_devloc->p_y;
pnum = DBPlane(goodies->rg_ttype);
pnum = DBPlane(resisdata->rg_ttype);
/* for drivepoints, we don't have to find a device */
if (goodies->rg_status & DRIVEONLY)
if (resisdata->rg_status & DRIVEONLY)
{
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
GOTOPOINT(tile, &workingPoint);
SourcePoint->p_x = workingPoint.p_x;
SourcePoint->p_y = workingPoint.p_y;
if (TiGetTypeExact(tile) == goodies->rg_ttype)
if (TiGetTypeExact(tile) == resisdata->rg_ttype)
return tile;
else
{
@ -1457,18 +1383,19 @@ FindStartTile(goodies, SourcePoint)
if (workingPoint.p_x == LEFT(tile))
{
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp))
if (TiGetRightType(tp) == goodies->rg_ttype)
if (TiGetRightType(tp) == resisdata->rg_ttype)
return(tp);
}
else if (workingPoint.p_y == BOTTOM(tile))
{
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
if (TiGetTopType(tp) == goodies->rg_ttype)
if (TiGetTopType(tp) == resisdata->rg_ttype)
return(tp);
}
}
TxError("Couldn't find wire at %d %d\n",
goodies->rg_devloc->p_x, goodies->rg_devloc->p_y);
TxError("Couldn't find wire at %s %s\n",
DBWPrintValue(resisdata->rg_devloc->p_x, (MagWindow *)NULL, TRUE),
DBWPrintValue(resisdata->rg_devloc->p_y, (MagWindow *)NULL, FALSE));
return NULL;
}
@ -1483,15 +1410,17 @@ FindStartTile(goodies, SourcePoint)
t1 = TiGetRightType(tile);
else
{
TxError("Couldn't find device at %d %d\n",
goodies->rg_devloc->p_x, goodies->rg_devloc->p_y);
TxError("Couldn't find device at %s %s\n",
DBWPrintValue(resisdata->rg_devloc->p_x, (MagWindow *)NULL, TRUE),
DBWPrintValue(resisdata->rg_devloc->p_y, (MagWindow *)NULL, FALSE));
return(NULL);
}
}
else if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetType(tile)) == 0)
{
TxError("Couldn't find device at %d %d\n",
goodies->rg_devloc->p_x, goodies->rg_devloc->p_y);
TxError("Couldn't find device at %s %s\n",
DBWPrintValue(resisdata->rg_devloc->p_x, (MagWindow *)NULL, TRUE),
DBWPrintValue(resisdata->rg_devloc->p_y, (MagWindow *)NULL, FALSE));
return(NULL);
}
else
@ -1522,8 +1451,9 @@ FindStartTile(goodies, SourcePoint)
else
{
const ClientData ticlient = TiGetClient(tp);
const tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
if (ticlient != CLIENTDEFAULT && tj->tj_status & RES_TILE_DEV)
const resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
if (ticlient != CLIENTDEFAULT && rinfo->ri_status & RES_TILE_DEV)
complex = TRUE;
}
}
@ -1543,8 +1473,8 @@ FindStartTile(goodies, SourcePoint)
else
{
const ClientData ticlient = TiGetClient(tp);
const tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
if (ticlient != CLIENTDEFAULT && tj->tj_status & RES_TILE_DEV)
const resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
if (ticlient != CLIENTDEFAULT && rinfo->ri_status & RES_TILE_DEV)
complex = TRUE;
}
}
@ -1564,8 +1494,8 @@ FindStartTile(goodies, SourcePoint)
else
{
const ClientData ticlient = TiGetClient(tp);
const tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
if (ticlient != CLIENTDEFAULT && tj->tj_status & RES_TILE_DEV)
const resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
if (ticlient != CLIENTDEFAULT && rinfo->ri_status & RES_TILE_DEV)
complex = TRUE;
}
}
@ -1585,8 +1515,8 @@ FindStartTile(goodies, SourcePoint)
else
{
const ClientData ticlient = TiGetClient(tp);
const tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
if (ticlient != CLIENTDEFAULT && tj->tj_status & RES_TILE_DEV)
const resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
if (ticlient != CLIENTDEFAULT && rinfo->ri_status & RES_TILE_DEV)
complex = TRUE;
}
}
@ -1599,7 +1529,7 @@ FindStartTile(goodies, SourcePoint)
if (devStack == NULL) devStack = StackNew(8);
((tileJunk *)TiGetClientPTR(tile))->tj_status |= RES_TILE_PUSHED;
((resInfo *)TiGetClientPTR(tile))->ri_status |= RES_TILE_PUSHED;
STACKPUSH((ClientData)tile, devStack);
while (!StackEmpty(devStack))
{
@ -1626,12 +1556,12 @@ FindStartTile(goodies, SourcePoint)
const ClientData ticlient = TiGetClient(tp);
if (ticlient != CLIENTDEFAULT)
{
tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
if (tj->tj_status & RES_TILE_DEV)
resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
if (rinfo->ri_status & RES_TILE_DEV)
{
if (!(tj->tj_status & RES_TILE_PUSHED))
if (!(rinfo->ri_status & RES_TILE_PUSHED))
{
tj->tj_status |= RES_TILE_PUSHED;
rinfo->ri_status |= RES_TILE_PUSHED;
STACKPUSH((ClientData)tp, devStack);
}
}
@ -1660,12 +1590,12 @@ FindStartTile(goodies, SourcePoint)
const ClientData ticlient = TiGetClient(tp);
if (ticlient != CLIENTDEFAULT)
{
tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
if (tj->tj_status & RES_TILE_DEV)
resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
if (rinfo->ri_status & RES_TILE_DEV)
{
if (!(tj->tj_status & RES_TILE_PUSHED))
if (!(rinfo->ri_status & RES_TILE_PUSHED))
{
tj->tj_status |= RES_TILE_PUSHED;
rinfo->ri_status |= RES_TILE_PUSHED;
STACKPUSH((ClientData)tp, devStack);
}
}
@ -1694,12 +1624,12 @@ FindStartTile(goodies, SourcePoint)
const ClientData ticlient = TiGetClient(tp);
if (ticlient != CLIENTDEFAULT)
{
tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
if (tj->tj_status & RES_TILE_DEV)
resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
if (rinfo->ri_status & RES_TILE_DEV)
{
if (!(tj->tj_status & RES_TILE_PUSHED))
if (!(rinfo->ri_status & RES_TILE_PUSHED))
{
tj->tj_status |= RES_TILE_PUSHED;
rinfo->ri_status |= RES_TILE_PUSHED;
STACKPUSH((ClientData)tp, devStack);
}
}
@ -1728,12 +1658,12 @@ FindStartTile(goodies, SourcePoint)
const ClientData ticlient = TiGetClient(tp);
if (ticlient != CLIENTDEFAULT)
{
tileJunk *tj = (tileJunk *)CD2PTR(ticlient);
if (tj->tj_status & RES_TILE_DEV)
resInfo *rinfo = (resInfo *)CD2PTR(ticlient);
if (rinfo->ri_status & RES_TILE_DEV)
{
if (!(tj->tj_status & RES_TILE_PUSHED))
if (!(rinfo->ri_status & RES_TILE_PUSHED))
{
tj->tj_status |= RES_TILE_PUSHED;
rinfo->ri_status |= RES_TILE_PUSHED;
STACKPUSH((ClientData)tp, devStack);
}
}
@ -1782,8 +1712,9 @@ FindStartTile(goodies, SourcePoint)
/* Didn't find a terminal (S/D or substrate) type tile anywhere. Flag an error. */
if (devptr == NULL)
TxError("Couldn't find a terminal of the device at %d %d\n",
goodies->rg_devloc->p_x, goodies->rg_devloc->p_y);
TxError("Couldn't find a terminal of the device at %s %s\n",
DBWPrintValue(resisdata->rg_devloc->p_x, (MagWindow*)NULL, TRUE),
DBWPrintValue(resisdata->rg_devloc->p_y, (MagWindow*)NULL, FALSE));
return((Tile *) NULL);
}
@ -1791,7 +1722,7 @@ FindStartTile(goodies, SourcePoint)
*-------------------------------------------------------------------------
*
* ResGetDevice -- Once the net is extracted, we still have to equate
* the sim file devices with the layout devices. ResGetDevice
* the .ext file devices with the layout devices. ResGetDevice
* looks for a device at the given location. "type" is also
* specified to that the right plane will be searched.
*
@ -1827,7 +1758,7 @@ ResGetDevice(pt, type)
{
if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetLeftType(tile))
|| TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetRightType(tile)))
return (((tileJunk *)CD2PTR(ticlient))->deviceList);
return (((resInfo *)CD2PTR(ticlient))->deviceList);
}
else if (TTMaskHasType(&ExtCurStyle->exts_deviceMask, TiGetType(tile)))
{
@ -1835,7 +1766,7 @@ ResGetDevice(pt, type)
* error and indicates a problem that needs debugging.
*/
if (ticlient != CLIENTDEFAULT)
return (((tileJunk *)CD2PTR(ticlient))->deviceList);
return (((resInfo *)CD2PTR(ticlient))->deviceList);
}
return NULL;
}

View File

@ -52,9 +52,9 @@ bool ResCalcEastWest();
*/
bool
ResCalcTileResistance(tile, junk, pendingList, doneList)
ResCalcTileResistance(tile, info, pendingList, doneList)
Tile *tile;
tileJunk *junk;
resInfo *info;
resNode **pendingList, **doneList;
{
@ -67,7 +67,7 @@ ResCalcTileResistance(tile, junk, pendingList, doneList)
merged = FALSE;
device = FALSE;
if ((p1 = junk->breakList) == NULL) return FALSE;
if ((p1 = info->breakList) == NULL) return FALSE;
for (; p1; p1 = p1->br_next)
{
int x = p1->br_loc.p_x;
@ -133,7 +133,7 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
resElement *element;
resNode *currNode;
float rArea;
tileJunk *junk = (tileJunk *)TiGetClientPTR(tile);
resInfo *info = (resInfo *)TiGetClientPTR(tile);
merged = FALSE;
height = TOP(tile) - BOTTOM(tile);
@ -143,12 +143,12 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
* breakpoint, then return.
*/
p1 = junk->breakList;
p1 = info->breakList;
if (p1->br_next == NULL)
{
p1->br_this->rn_float.rn_area += height * (LEFT(tile) - RIGHT(tile));
freeMagic((char *)p1);
junk->breakList = NULL;
info->breakList = NULL;
return(merged);
}
@ -164,14 +164,14 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
/* Re-sort nodes left to right. */
ResSortBreaks(&junk->breakList, TRUE);
ResSortBreaks(&info->breakList, TRUE);
/*
* Eliminate breakpoints with the same X coordinate and merge
* their nodes.
*/
p2= junk->breakList;
p2= info->breakList;
/* Add extra left area to leftmost node */
@ -213,7 +213,7 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
}
/*
* Was the node used in another junk or breakpoint?
* Was the node used in another info or breakpoint?
* If so, replace the old node with the new one.
*/
@ -263,10 +263,6 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
{
resistor->rr_status = RES_EW;
}
#ifdef ARIEL
resistor->rr_csArea = height *
ExtCurStyle->exts_thick[resistor->rr_tt];
#endif
resistor->rr_value =
(float)ExtCurStyle->exts_sheetResist[resistor->rr_tt]
* (float)(p2->br_loc.p_x - p1->br_loc.p_x)
@ -282,7 +278,7 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
p2->br_this->rn_float.rn_area += height * (RIGHT(tile) - p2->br_loc.p_x);
freeMagic((char *)p2);
junk->breakList = NULL;
info->breakList = NULL;
return merged;
}
@ -313,7 +309,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
resElement *element;
resNode *currNode;
float rArea;
tileJunk *junk = (tileJunk *)TiGetClientPTR(tile);
resInfo *info = (resInfo *)TiGetClientPTR(tile);
merged = FALSE;
width = RIGHT(tile) - LEFT(tile);
@ -323,17 +319,17 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
* breakpoint, then return.
*/
p1 = junk->breakList;
p1 = info->breakList;
if (p1->br_next == NULL)
{
p1->br_this->rn_float.rn_area += width * (TOP(tile) - BOTTOM(tile));
freeMagic((char *)p1);
junk->breakList = NULL;
info->breakList = NULL;
return(merged);
}
/* Re-sort nodes south to north. */
ResSortBreaks(&junk->breakList, FALSE);
ResSortBreaks(&info->breakList, FALSE);
/* Simplified split tile handling */
if (IsSplit(tile))
@ -350,7 +346,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
* their nodes.
*/
p2 = junk->breakList;
p2 = info->breakList;
/* Add extra left area to leftmost node */
@ -392,7 +388,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
}
/*
* Was the node used in another junk or breakpoint?
* Was the node used in another info or breakpoint?
* If so, replace the old node with the new one.
*/
p3 = p2->br_next;
@ -440,10 +436,6 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
{
resistor->rr_status = RES_NS;
}
#ifdef ARIEL
resistor->rr_csArea = width
* ExtCurStyle->exts_thick[resistor->rr_tt];
#endif
resistor->rr_value =
(float)ExtCurStyle->exts_sheetResist[resistor->rr_tt]
* (float)(p2->br_loc.p_y - p1->br_loc.p_y)
@ -457,7 +449,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
}
p2->br_this->rn_float.rn_area += width * (TOP(tile) - p2->br_loc.p_y);
freeMagic((char *)p2);
junk->breakList = NULL;
info->breakList = NULL;
return(merged);
}
@ -490,7 +482,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
bool merged;
int devcount, devedge, deltax, deltay;
Breakpoint *p1, *p2, *p3;
tileJunk *junk = (tileJunk *)TiGetClientPTR(tile);
resInfo *info = (resInfo *)TiGetClientPTR(tile);
merged = FALSE;
@ -499,10 +491,10 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
* breakpoint, then return.
*/
if (junk->breakList->br_next == NULL)
if (info->breakList->br_next == NULL)
{
freeMagic((char *)junk->breakList);
junk->breakList = NULL;
freeMagic((char *)info->breakList);
info->breakList = NULL;
return(merged);
}
@ -511,7 +503,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
devcount = 0;
devedge = 0;
for (p1 = junk->breakList; p1 != NULL; p1 = p1->br_next)
for (p1 = info->breakList; p1 != NULL; p1 = p1->br_next)
{
if (p1->br_this->rn_why == RES_NODE_DEVICE)
{
@ -533,9 +525,9 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
(devedge & TOPEDGE) == devedge ||
(devedge & BOTTOMEDGE) == devedge)
{
ResSortBreaks(&junk->breakList,TRUE);
ResSortBreaks(&info->breakList,TRUE);
p2 = NULL;
for (p1 = junk->breakList; p1 != NULL; p1 = p1->br_next)
for (p1 = info->breakList; p1 != NULL; p1 = p1->br_next)
{
if (p1->br_this->rn_why == RES_NODE_DEVICE)
break;
@ -595,9 +587,9 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
}
/* Re-sort nodes south to north. */
ResSortBreaks(&junk->breakList, FALSE);
ResSortBreaks(&info->breakList, FALSE);
p2 = NULL;
for (p1 = junk->breakList; p1 != NULL; p1 = p1->br_next)
for (p1 = info->breakList; p1 != NULL; p1 = p1->br_next)
{
if (p1->br_this->rn_why == RES_NODE_DEVICE)
{
@ -692,17 +684,17 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
(RIGHT(tile) - LEFT(tile)) > (TOP(tile) - BOTTOM(tile))))
{
/* re-sort nodes south to north. */
ResSortBreaks(&junk->breakList, FALSE);
ResSortBreaks(&info->breakList, FALSE);
/* eliminate duplicate S/D pointers */
for (p1 = junk->breakList; p1 != NULL; p1 = p1->br_next)
for (p1 = info->breakList; p1 != NULL; p1 = p1->br_next)
{
if (p1->br_this->rn_why == RES_NODE_DEVICE &&
(p1->br_loc.p_y == BOTTOM(tile) ||
p1->br_loc.p_y == TOP(tile)))
{
p3 = NULL;
p2 = junk->breakList;
p2 = info->breakList;
while (p2 != NULL)
{
if (p2->br_this == p1->br_this && p2 != p1 &&
@ -711,9 +703,9 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
{
if (p3 == NULL)
{
junk->breakList = p2->br_next;
info->breakList = p2->br_next;
freeMagic((char *) p2);
p2 = junk->breakList;
p2 = info->breakList;
}
else
{
@ -735,14 +727,14 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
else
{
/* Eliminate duplicate S/D pointers */
for (p1 = junk->breakList; p1 != NULL; p1 = p1->br_next)
for (p1 = info->breakList; p1 != NULL; p1 = p1->br_next)
{
if (p1->br_this->rn_why == RES_NODE_DEVICE &&
(p1->br_loc.p_x == LEFT(tile) ||
p1->br_loc.p_x == RIGHT(tile)))
{
p3 = NULL;
p2 = junk->breakList;
p2 = info->breakList;
while (p2 != NULL)
{
if (p2->br_this == p1->br_this && p2 != p1 &&
@ -751,9 +743,9 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
{
if (p3 == NULL)
{
junk->breakList = p2->br_next;
info->breakList = p2->br_next;
freeMagic((char *) p2);
p2 = junk->breakList;
p2 = info->breakList;
}
else
{
@ -813,7 +805,7 @@ ResDoContacts(contact, nodes, resList)
int y = contact->cp_center.p_y;
resptr = (resNode *) mallocMagic((unsigned) (sizeof(resNode)));
InitializeNode(resptr, x, y, RES_NODE_CONTACT);
InitializeResNode(resptr, x, y, RES_NODE_CONTACT);
ResAddToQueue(resptr, nodes);
ccell = (cElement *) mallocMagic((unsigned) (sizeof(cElement)));
@ -866,7 +858,7 @@ ResDoContacts(contact, nodes, resList)
Tile *tile = contact->cp_tile[tilenum];
resptr = (resNode *) mallocMagic((unsigned) (sizeof(resNode)));
InitializeNode(resptr, x, y, RES_NODE_CONTACT);
InitializeResNode(resptr, x, y, RES_NODE_CONTACT);
ResAddToQueue(resptr, nodes);
/* Add contact pointer to node */
@ -916,11 +908,6 @@ ResDoContacts(contact, nodes, resList)
resistor->rr_value =
(float)ExtCurStyle->exts_viaResist[contact->cp_type] /
(float)(squaresx * squaresy);
#ifdef ARIEL
resistor->rr_csArea =
(float)ExtCurStyle->exts_thick[contact->cp_type] /
(float)(squaresx * squaresy);
#endif
resistor->rr_tt = contact->cp_type;
resistor->rr_float.rr_area = 0;
resistor->rr_status = 0;

View File

@ -53,7 +53,7 @@ ResDoneWithNode(resptr)
resResistor *rr1;
resptr2 = NULL;
resptr->rn_status |= RESTRUE;
resptr->rn_status |= RES_TRUE;
status = UNTOUCHED;
/* are there any resistors? */
@ -93,9 +93,9 @@ ResDoneWithNode(resptr)
ResMergeNodes(resptr2, resptr, &ResNodeQueue, &ResNodeList);
resptr2->rn_float.rn_area += rr1->rr_float.rr_area;
ResEliminateResistor(rr1, &ResResList);
if ((resptr2->rn_status & RESTRUE) == RESTRUE)
if ((resptr2->rn_status & RES_TRUE) == RES_TRUE)
{
resptr2->rn_status &= ~RESTRUE;
resptr2->rn_status &= ~RES_TRUE;
ResDoneWithNode(resptr2);
}
resptr2 = NULL;
@ -108,14 +108,16 @@ ResDoneWithNode(resptr)
/* Eliminations that can be only if there are no devices connected */
/* to node. Series and dangling connections fall in this group. */
if ((resptr->rn_te == NULL) && (resptr->rn_why != RES_NODE_ORIGIN)
&& (status == UNTOUCHED))
if ((status == UNTOUCHED) && (resptr->rn_te == NULL) &&
!(resptr->rn_why & (RES_NODE_ORIGIN | RES_NODE_SINK)))
status = ResSeriesCheck(resptr);
if ((status == UNTOUCHED) && (resptr->rn_why != RES_NODE_ORIGIN))
if ((status == UNTOUCHED) &&
!(resptr->rn_why & (RES_NODE_ORIGIN | RES_NODE_SINK)))
status = ResParallelCheck(resptr);
if ((status == UNTOUCHED) && (resptr->rn_why != RES_NODE_ORIGIN))
if ((status == UNTOUCHED) &&
!(resptr->rn_why & (RES_NODE_ORIGIN | RES_NODE_SINK)))
status = ResTriangleCheck(resptr);
}
@ -150,14 +152,6 @@ ResFixRes(resptr, resptr2, resptr3, elimResis, newResis)
ASSERT(newResis->rr_value > 0, "series");
newResis->rr_float.rr_area += elimResis->rr_float.rr_area;
#ifdef ARIEL
if (elimResis->rr_csArea && elimResis->rr_csArea < newResis->rr_csArea
|| newResis->rr_csArea == 0)
{
newResis->rr_csArea = elimResis->rr_csArea;
newResis->rr_tt = elimResis->rr_tt;
}
#endif
for (thisREl = resptr3->rn_re; (thisREl != NULL); thisREl = thisREl->re_nextEl)
{
if (thisREl->re_thisEl == elimResis)
@ -206,9 +200,6 @@ ResFixParallel(elimResis, newResis)
newResis->rr_value = 0;
}
newResis->rr_float.rr_area += elimResis->rr_float.rr_area;
#ifdef ARIEL
newResis->rr_csArea += elimResis->rr_csArea;
#endif
ResDeleteResPointer(elimResis->rr_connection1, elimResis);
ResDeleteResPointer(elimResis->rr_connection2, elimResis);
ResEliminateResistor(elimResis, &ResResList);
@ -253,9 +244,9 @@ ResSeriesCheck(resptr)
ResEliminateResistor(rr1, &ResResList);
ResCleanNode(resptr, TRUE, &ResNodeList, &ResNodeQueue);
status = SINGLE;
if (resptr2->rn_status & RESTRUE)
if (resptr2->rn_status & RES_TRUE)
{
resptr2->rn_status &= ~RESTRUE;
resptr2->rn_status &= ~RES_TRUE;
ResDoneWithNode(resptr2);
}
resptr2 = NULL;
@ -291,9 +282,9 @@ ResSeriesCheck(resptr)
rr1->rr_connection1 = rr2->rr_connection2;
ResFixRes(resptr, resptr2, resptr3, rr2, rr1);
}
if ((resptr2->rn_status & RESTRUE) == RESTRUE)
if ((resptr2->rn_status & RES_TRUE) == RES_TRUE)
{
resptr2->rn_status &= ~RESTRUE;
resptr2->rn_status &= ~RES_TRUE;
ResDoneWithNode(resptr2);
}
resptr2 = NULL;
@ -322,9 +313,9 @@ ResSeriesCheck(resptr)
rr1->rr_connection1 = rr2->rr_connection1;
ResFixRes(resptr, resptr2, resptr3, rr2, rr1);
}
if ((resptr2->rn_status & RESTRUE) == RESTRUE)
if ((resptr2->rn_status & RES_TRUE) == RES_TRUE)
{
resptr2->rn_status &= ~RESTRUE;
resptr2->rn_status &= ~RES_TRUE;
ResDoneWithNode(resptr2);
}
resptr2 = NULL;
@ -356,9 +347,9 @@ ResSeriesCheck(resptr)
rr1->rr_connection2 = rr2->rr_connection2;
ResFixRes(resptr, resptr2, resptr3, rr2, rr1);
}
if ((resptr2->rn_status & RESTRUE) == RESTRUE)
if ((resptr2->rn_status & RES_TRUE) == RES_TRUE)
{
resptr2->rn_status &= ~RESTRUE;
resptr2->rn_status &= ~RES_TRUE;
ResDoneWithNode(resptr2);
}
resptr2 = NULL;
@ -387,9 +378,9 @@ ResSeriesCheck(resptr)
rr1->rr_connection2 = rr2->rr_connection1;
ResFixRes(resptr, resptr2, resptr3, rr2, rr1);
}
if ((resptr2->rn_status & RESTRUE) == RESTRUE)
if ((resptr2->rn_status & RES_TRUE) == RES_TRUE)
{
resptr2->rn_status &= ~RESTRUE;
resptr2->rn_status &= ~RES_TRUE;
ResDoneWithNode(resptr2);
}
resptr2 = NULL;
@ -444,10 +435,10 @@ ResParallelCheck(resptr)
ResFixParallel(r1, r2);
status = PARALLEL;
resptr2 = NULL;
if (resptr3->rn_status & RESTRUE)
if (resptr3->rn_status & RES_TRUE)
{
resptr2 = resptr3;
resptr2->rn_status &= ~RESTRUE;
resptr2->rn_status &= ~RES_TRUE;
}
ResDoneWithNode(resptr);
if (resptr2 != NULL) ResDoneWithNode(resptr2);
@ -542,8 +533,8 @@ ResTriangleCheck(resptr)
/* is arbitrarily assigned to the location */
/* occupied by the first node. */
InitializeNode(n3, resptr->rn_loc.p_x, resptr->rn_loc.p_y, TRIANGLE);
n3->rn_status = FINISHED | RESTRUE | MARKED;
InitializeResNode(n3, resptr->rn_loc.p_x, resptr->rn_loc.p_y, TRIANGLE);
n3->rn_status = RES_FINISHED | RES_TRUE | RES_MARKED;
n3->rn_less = NULL;
n3->rn_more = ResNodeList;
@ -591,13 +582,13 @@ ResTriangleCheck(resptr)
element->re_nextEl = n3->rn_re;
element->re_thisEl = rr3;
n3->rn_re = element;
if ((n1->rn_status & RESTRUE) == RESTRUE)
n1->rn_status &= ~RESTRUE;
if ((n1->rn_status & RES_TRUE) == RES_TRUE)
n1->rn_status &= ~RES_TRUE;
else
n1 = NULL;
if ((n2->rn_status & RESTRUE) == RESTRUE)
n2->rn_status &= ~RESTRUE;
if ((n2->rn_status & RES_TRUE) == RES_TRUE)
n2->rn_status &= ~RES_TRUE;
else
n2 = NULL;
@ -648,15 +639,18 @@ ResMergeNodes(node1, node2, pendingList, doneList)
return;
}
/* don't want to merge away startpoint */
/* don't want to merge away start or end points */
if (node2->rn_why & RES_NODE_ORIGIN)
node1->rn_why = RES_NODE_ORIGIN;
if (node2->rn_why & RES_NODE_SINK)
node1->rn_why = RES_NODE_SINK;
/* set node resistance */
if (node1->rn_noderes > node2->rn_noderes)
{
node1->rn_noderes = node2->rn_noderes;
if ((node1->rn_status & FINISHED) != FINISHED)
if ((node1->rn_status & RES_FINISHED) != RES_FINISHED)
{
ResRemoveFromQueue(node1, pendingList);
ResAddToQueue(node1, pendingList);
@ -665,37 +659,22 @@ ResMergeNodes(node1, node2, pendingList, doneList)
node1->rn_float.rn_area += node2->rn_float.rn_area;
/* combine relevant flags */
node1->rn_status |= (node2->rn_status & RN_MAXTDI);
node1->rn_status |= (node2->rn_status & RES_MAXTDI);
/* merge device lists */
workingDev = node2->rn_te;
while (workingDev != NULL)
{
if (workingDev->te_thist->rd_status & RES_DEV_PLUG)
{
ResPlug *plug = (ResPlug *) workingDev->te_thist;
if (plug->rpl_node == node2)
plug->rpl_node = node1;
else
{
TxError("Bad plug node: is (%d %d), should be (%d %d)\n",
plug->rpl_node->rn_loc.p_x, plug->rpl_node->rn_loc.p_y,
node2->rn_loc.p_x, node2->rn_loc.p_y);
plug->rpl_node = NULL;
}
}
else
{
int j;
int j;
for (j = 0; j != workingDev->te_thist->rd_nterms; j++)
if (workingDev->te_thist->rd_terminals[j] == node2)
workingDev->te_thist->rd_terminals[j] = node1;
}
tDev = workingDev;
workingDev = workingDev->te_nextt;
tDev->te_nextt = node1->rn_te;
node1->rn_te = tDev;
for (j = 0; j != workingDev->te_thist->rd_nterms; j++)
if (workingDev->te_thist->rd_terminals[j] == node2)
workingDev->te_thist->rd_terminals[j] = node1;
tDev = workingDev;
workingDev = workingDev->te_nextt;
tDev->te_nextt = node1->rn_te;
node1->rn_te = tDev;
}
/* append junction lists */
@ -706,13 +685,13 @@ ResMergeNodes(node1, node2, pendingList, doneList)
tJunc = workingJunc;
for (i = 0; i < TILES_PER_JUNCTION; i++)
{
tileJunk *junk;
resInfo *info;
tile = tJunc->je_thisj->rj_Tile[i];
junk = (tileJunk *) TiGetClientPTR(tile);
info = (resInfo *) TiGetClientPTR(tile);
if ((junk->tj_status & RES_TILE_DONE) == FALSE)
ResFixBreakPoint(&junk->breakList, node2, node1);
if ((info->ri_status & RES_TILE_DONE) == FALSE)
ResFixBreakPoint(&info->breakList, node2, node1);
}
tJunc->je_thisj->rj_jnode = node1;
workingJunc = workingJunc->je_nextj;
@ -729,13 +708,13 @@ ResMergeNodes(node1, node2, pendingList, doneList)
{
if (workingCon->ce_thisc->cp_cnode[i] == node2)
{
tileJunk *junk;
resInfo *info;
workingCon->ce_thisc->cp_cnode[i] = node1;
tile =tCon->ce_thisc->cp_tile[i];
junk = (tileJunk *) TiGetClientPTR(tile);
if ((junk->tj_status & RES_TILE_DONE) == FALSE)
ResFixBreakPoint(&junk->breakList, node2, node1);
info = (resInfo *) TiGetClientPTR(tile);
if ((info->ri_status & RES_TILE_DONE) == FALSE)
ResFixBreakPoint(&info->breakList, node2, node1);
}
}
workingCon = workingCon->ce_nextc;
@ -749,11 +728,11 @@ ResMergeNodes(node1, node2, pendingList, doneList)
else if ((node2->rn_name != NULL) && (node2->rn_name != node1->rn_name))
{
HashEntry *entry;
ResSimNode *node;
ResExtNode *node;
/* Check if node2 is a port */
entry = HashFind(&ResNodeTable, node2->rn_name);
node = (ResSimNode *)HashGetValue(entry);
node = (ResExtNode *)HashGetValue(entry);
if (node && (node->status & PORTNODE))
node1->rn_name = node2->rn_name;
}
@ -775,7 +754,7 @@ ResMergeNodes(node1, node2, pendingList, doneList)
tRes->re_nextEl = node1->rn_re;
node1->rn_re = tRes;
}
if ((node2->rn_status & FINISHED) == FINISHED)
if ((node2->rn_status & RES_FINISHED) == RES_FINISHED)
ResRemoveFromQueue(node2, doneList);
else
ResRemoveFromQueue(node2, pendingList);
@ -885,7 +864,7 @@ ResEliminateResistor(resistor, homelist)
*-------------------------------------------------------------------------
*
* ResCleanNode--removes the linked lists of junctions and contacts after
* they are no longer needed. If the 'junk' option is used,
* they are no longer needed. If the 'info' option is used,
* the node is eradicated.
*
* Results:
@ -897,9 +876,9 @@ ResEliminateResistor(resistor, homelist)
*/
void
ResCleanNode(resptr, junk, homelist1, homelist2)
ResCleanNode(resptr, info, homelist1, homelist2)
resNode *resptr;
int junk;
int info;
resNode **homelist1;
resNode **homelist2;
{
@ -922,7 +901,7 @@ ResCleanNode(resptr, junk, homelist1, homelist2)
freeMagic((char *)jcell->je_thisj);
freeMagic((char *)jcell);
}
if (junk == TRUE)
if (info == TRUE)
{
if (resptr->rn_client != (ClientData)NULL)
{

View File

@ -17,6 +17,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "database/database.h"
#include "utils/malloc.h"
#include "textio/textio.h"
#include "extflat/extparse.h"
#include "extract/extract.h"
#include "extract/extractInt.h"
#include "windows/windows.h"
@ -32,9 +33,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#define MAXNAME 1000
#define KV_TO_mV 1000000
extern ResSimNode *ResInitializeNode();
/*
*-------------------------------------------------------------------------
*
@ -57,7 +55,7 @@ ResPrintExtRes(outextfile, resistors, nodename)
int nodenum=0;
char newname[MAXNAME];
HashEntry *entry;
ResSimNode *node, *ResInitializeNode();
ResExtNode *node;
for (; resistors != NULL; resistors = resistors->rr_nextResistor)
{
@ -72,7 +70,7 @@ ResPrintExtRes(outextfile, resistors, nodename)
{
(void)sprintf(newname, "%s%s%d", nodename, ".r", nodenum++);
entry = HashFind(&ResNodeTable, newname);
node = ResInitializeNode(entry);
node = ResExtInitNode(entry);
resistors->rr_connection1->rn_name = node->name;
node->oldname = nodename;
}
@ -80,7 +78,7 @@ ResPrintExtRes(outextfile, resistors, nodename)
{
(void)sprintf(newname, "%s%s%d", nodename, ".r", nodenum++);
entry = HashFind(&ResNodeTable, newname);
node = ResInitializeNode(entry);
node = ResExtInitNode(entry);
resistors->rr_connection2->rn_name = node->name;
node->oldname = nodename;
}
@ -175,13 +173,13 @@ ResPrintExtDev(outextfile, devices)
fprintf(outextfile, " \"%s\" %d %s",
devices->gate->name,
devices->layout->rd_length * 2,
devices->rs_gattr);
(*devices->rs_gattr == '\0') ? "0" : devices->rs_gattr);
if (devices->source != NULL)
fprintf(outextfile, " \"%s\" %d %s",
devices->source->name,
devices->layout->rd_width,
devices->rs_sattr);
(*devices->rs_sattr == '\0') ? "0" : devices->rs_sattr);
/* Don't write drain values for 2-terminal devices */
if (devptr->exts_deviceSDCount > 1)
@ -189,7 +187,7 @@ ResPrintExtDev(outextfile, devices)
fprintf(outextfile, " \"%s\" %d %s",
devices->drain->name,
devices->layout->rd_width,
devices->rs_dattr);
(*devices->rs_dattr == '\0') ? "0" : devices->rs_dattr);
fprintf(outextfile, "\n");
}
@ -215,13 +213,13 @@ void
ResPrintExtNode(outextfile, nodelist, node)
FILE *outextfile;
resNode *nodelist;
ResSimNode *node;
ResExtNode *node;
{
char *nodename = node->name;
int nodenum = 0;
char newname[MAXNAME+32], tmpname[MAXNAME], *cp;
HashEntry *entry;
ResSimNode *newnode, *ResInitializeNode();
ResExtNode *newnode;
bool DoKillNode = TRUE;
bool NeedFix = FALSE;
resNode *snode;
@ -270,7 +268,7 @@ ResPrintExtNode(outextfile, nodelist, node)
(void)sprintf(newname, "%s%s%d", tmpname, ".n", nodenum++);
entry = HashFind(&ResNodeTable, newname);
newnode = ResInitializeNode(entry);
newnode = ResExtInitNode(entry);
snode->rn_name = newnode->name;
newnode->oldname = nodename;
}
@ -290,6 +288,13 @@ ResPrintExtNode(outextfile, nodelist, node)
if (NeedFix)
{
if (nodelist == NULL)
{
TxError("Error: Orphaned node \"%s\" not output.\n",
node->name);
return;
}
/* Patch up the output netlist for an orphaned node by
* creating a zero-valued resistance between it and the
* first subnode (arbitrary connection). Flag a warning.
@ -316,16 +321,16 @@ ResPrintExtNode(outextfile, nodelist, node)
*/
void
ResPrintStats(goodies, name)
ResGlobalParams *goodies;
char *name;
ResPrintStats(resisdata, name)
ResisData *resisdata;
char *name;
{
static int totalnets = 0, totalnodes = 0, totalresistors = 0;
int nodes, resistors;
resNode *node;
resResistor *res;
if (goodies == NULL)
if (resisdata == NULL)
{
TxError("nets:%d nodes:%d resistors:%d\n",
totalnets, totalnodes, totalresistors);
@ -411,16 +416,16 @@ ResPrintFHNodes(fp, nodelist, nodename, nidx, celldef)
else
{
HashEntry *entry;
ResSimNode *simnode;
ResExtNode *extnode;
/* If we process another sim file node while doing this */
/* one, mark it as status "REDUNDANT" so we don't duplicate */
/* the entry. */
entry = HashFind(&ResNodeTable, nodeptr->rn_name);
simnode = (ResSimNode *)HashGetValue(entry);
if (simnode != NULL)
simnode->status |= REDUNDANT;
extnode = (ResExtNode *)HashGetValue(entry);
if (extnode != NULL)
extnode->status |= REDUNDANT;
}
resWriteNodeName(fp, nodeptr);

684
resis/ResReadExt.c Normal file
View File

@ -0,0 +1,684 @@
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResReadExt.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
/*
*-------------------------------------------------------------------------
*
* ResReadExt.c -- Routines to parse .ext files for information needed
* by extresist.
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "utils/magic.h"
#include "utils/main.h"
#include "utils/geometry.h"
#include "utils/geofast.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "utils/malloc.h"
#include "textio/textio.h"
#include "extract/extract.h"
#include "extract/extractInt.h"
#include "extflat/extflat.h"
#include "extflat/extparse.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "utils/utils.h"
#include "utils/tech.h"
#include "textio/txcommands.h"
#include "resis/resis.h"
/* constants defining where various fields can be found in .ext files. */
/* The value corresponds to the argument number on the list after */
/* parsing by efReadLine(). */
#define FET_NAME 1
#define FET_X 2
#define FET_Y 3
#define FET_AREA 4
#define FET_PERIM 5
#define FET_SUBS 6
#define FET_GATE 7
#define FET_GATE_ATTR 9
#define FET_SOURCE 10
#define FET_SOURCE_ATTR 12
#define FET_DRAIN 13
#define FET_DRAIN_ATTR 15
#define DEV_NAME 2
#define DEV_X 3
#define DEV_Y 4
#define DEV_PARAM_START 7
#define NODES_NODENAME 1
#define NODES_NODEX 4
#define NODES_NODEY 5
#define NODES_NODETYPE 6
#define COUPLETERMINAL1 1
#define COUPLETERMINAL2 2
#define COUPLEVALUE 3
#define RES_EXT_ATTR_NAME 1
#define RES_EXT_ATTR_X 2
#define RES_EXT_ATTR_Y 3
#define RES_EXT_ATTR_TYPE 6
#define RES_EXT_ATTR_TEXT 7
#define PORT_NAME 1
#define PORT_LLX 3
#define PORT_LLY 4
#define PORT_URX 5
#define PORT_URY 6
#define PORT_TYPE 7
#define MAXDIGIT 20
ResExtNode *ResOriginalNodes; /*Linked List of Nodes */
char RDEV_NOATTR[1] = {'0'};
ResFixPoint *ResFixList;
/*
*-------------------------------------------------------------------------
*
* ResReadExt--
*
* Results: returns 0 if ext file is correct, 1 if not.
*
* Side Effects:Reads in ExtTable and makes a hash table of nodes.
*
*-------------------------------------------------------------------------
*/
int
ResReadExt(CellDef *def)
{
char *line = NULL, *argv[128];
int result, locresult;
int argc, n, size = 0;
FILE *fp;
CellDef *dbdef;
ResExtNode *curnode;
/* Search for the .ext file in the same way that efReadDef() does. */
fp = ExtFileOpen(def, (char *)NULL, "r", (char **)NULL);
if (fp == NULL)
{
TxError("Cannot open file %s%s\n", def->cd_name, ".ext");
return 1;
}
/* Read in the file. Makes use of various functions
* from extflat, mostly in EFread.c.
*/
EFSaveLocs = FALSE;
efReadLineNum = 0;
result = 0;
while ((argc = efReadLine(&line, &size, fp, argv)) >= 0)
{
n = LookupStruct(argv[0], (const LookupTable *)keyTable, sizeof keyTable[0]);
if (n < 0)
{
efReadError("Unrecognized token \"%s\" (ignored)\n", argv[0]);
continue;
}
if (argc < keyTable[n].k_mintokens)
{
efReadError("Not enough tokens for %s line\n", argv[0]);
continue;
}
/* We don't care about most tokens, only DEVICE, NODE, PORT,
* and SUBSTRATE; and MERGE is used to locate drive points.
*/
switch (keyTable[n].k_key)
{
case SCALE:
/* NOTE: Currently the code assumes that the .ext
* file is read back immediately and has the same
* scale values currently in the extraction style.
* However, this should be style-independent and
* scale values should be read back and used.
* (to be completed).
*/
break;
case DEVICE:
locresult = ResReadDevice(argc, argv);
break;
case FET:
locresult = ResReadFET(argc, argv);
break;
case MERGE:
/* To be completed */
/* ResReadDrivePoint(argc, argv); */
break;
case NODE:
case SUBSTRATE:
curnode = ResReadNode(argc, argv);
break;
case PORT:
locresult = ResReadPort(argc, argv);
break;
case ATTR:
locresult = ResReadAttribute(curnode, argc, argv);
break;
case CAP:
locresult = ResReadCapacitor(argc, argv);
break;
default:
break;
}
if (locresult == 1) result = 1;
}
fclose(fp);
return(result);
}
/*
*-------------------------------------------------------------------------
*
* ResReadNode-- Reads in a node statement, puts location and type of
* node into a node structure.
*
* Results: Pointer to the node record if the node was read correctly,
* NULL otherwise.
*
* Side Effects: see above
*
*-------------------------------------------------------------------------
*/
ResExtNode *
ResReadNode(int argc, char *argv[])
{
HashEntry *entry;
ResExtNode *node;
entry = HashFind(&ResNodeTable, argv[NODES_NODENAME]);
node = ResExtInitNode(entry);
node->location.p_x = atoi(argv[NODES_NODEX]);
node->location.p_y = atoi(argv[NODES_NODEY]);
/* If this node was previously read as a port, then don't change the
* node type, which is tracking the type at the drivepoint.
*/
if (!(node->status & PORTNODE))
{
node->type = DBTechNameType(argv[NODES_NODETYPE]);
}
if (node->type == -1)
{
TxError("Bad tile type name in .ext file for node %s\n", node->name);
return NULL;
}
return node;
}
/*
*-------------------------------------------------------------------------
*
* ResReadPort-- Reads in a port statement from the .ext file and sets
* node records accordingly to mark the node as a drivepoint.
*
* Results: 0 if successful and 1 otherwise.
*
* Side Effects: see above
*
*-------------------------------------------------------------------------
*/
int
ResReadPort(int argc,
char *argv[])
{
HashEntry *entry;
ResExtNode *node;
entry = HashFind(&ResNodeTable, argv[PORT_NAME]);
node = ResExtInitNode(entry);
node->drivepoint.p_x = atoi(argv[PORT_LLX]);
node->drivepoint.p_y = atoi(argv[PORT_LLY]);
node->status |= FORCE;
/* To do: Check for multiple ports on a net; each port needs its
* own drivepoint.
*/
node->status |= DRIVELOC | PORTNODE;
node->rs_bbox.r_ll = node->drivepoint;
node->rs_bbox.r_ur.p_x = atoi(argv[PORT_URX]);
node->rs_bbox.r_ur.p_y = atoi(argv[PORT_URY]);
node->rs_ttype = DBTechNoisyNameType(argv[PORT_TYPE]);
node->type = node->rs_ttype;
if (node->type == -1)
{
TxError("Bad tile type name in .ext file for node %s\n", node->name);
return 1;
}
return 0;
}
/*
*-------------------------------------------------------------------------
*
* ResNodeAddDevice --
*
* Given a device and a node which connects to one of its terminals,
* add the device to the node's device list. Device type is one
* of the indexes defined by GATE, SOURCE, or DRAIN (to do: generalize
* this).
*
* Results:
* None.
*
* Side effects:
* Allocates memory for a devPtr, adds to the node's firstDev linked
* list.
*
*-------------------------------------------------------------------------
*/
void
ResNodeAddDevice(ResExtNode *node,
RDev *device,
int termtype)
{
devPtr *tptr;
tptr = (devPtr *)mallocMagic((unsigned)(sizeof(devPtr)));
tptr->thisDev = device;
tptr->nextDev = node->firstDev;
node->firstDev = tptr;
tptr->terminal = termtype;
}
/*
*-------------------------------------------------------------------------
*
* ResReadDevice--
*
* Process a "device" line from a ext file.
*
* Results: returns 0 if line was added correctly.
*
* Side Effects: Allocates devicesl
*
*-------------------------------------------------------------------------
*/
int
ResReadDevice(int argc,
char *argv[])
{
RDev *device;
int rvalue, i, j, k;
ExtDevice *devptr;
TileType ttype;
HashEntry *entry;
ResExtNode *node;
ResValue rpersquare;
float wval;
device = (RDev *)mallocMagic((unsigned)(sizeof(RDev)));
device->status = FALSE;
device->nextDev = ResRDevList;
/* Find the device definition record corresponding to the device name */
devptr = (ExtDevice *)NULL;
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
{
for (devptr = ExtCurStyle->exts_device[ttype]; devptr;
devptr = devptr->exts_next)
if (!strcmp(devptr->exts_deviceName, argv[DEV_NAME])) break;
if (devptr != NULL) break;
}
device->location.p_x = atoi(argv[DEV_X]);
device->location.p_y = atoi(argv[DEV_Y]);
device->rs_gattr = RDEV_NOATTR;
device->rs_sattr = RDEV_NOATTR;
device->rs_dattr = RDEV_NOATTR;
device->rs_devptr = devptr;
device->source = (ResExtNode *)NULL;
device->drain = (ResExtNode *)NULL;
device->subs = (ResExtNode *)NULL;
entry = HashLookOnly(&devptr->exts_deviceResist, "linear");
if (entry != NULL)
rpersquare = (ResValue)(spointertype)HashGetValue(entry);
else
rpersquare = (ResValue)10000.0; /* Default to a sane value */
/* For devices, the device width is in the parameter list */
wval = 0.0;
for (i = DEV_Y; i < argc; i++)
{
char *eptr;
if ((eptr = strchr(argv[i], '=')) != NULL)
{
if (*argv[i] == 'w')
sscanf(eptr + 1, "%f", &wval);
}
else if (!StrIsInt(argv[i]))
break;
}
if (i == argc)
{
TxError("Bad device %s: Too few arguments in .ext file\n",
argv[DEV_NAME]);
return 1;
}
else
device->resistance = wval * rpersquare; /* Channel resistance */
/* Find and record the device terminal nodes */
/* Note that this only records up to two terminals matching FET
* source and drain; it needs to be expanded to include an
* arbitrary number of terminals.
*/
if (strcmp(argv[i], "None"))
{
entry = HashFind(&ResNodeTable, argv[i]);
device->subs = (ResExtNode *)HashGetValue(entry);
ResNodeAddDevice(device->subs, device, SUBS);
}
i++;
entry = HashFind(&ResNodeTable, argv[i]);
device->gate = (ResExtNode *)HashGetValue(entry);
device->rs_gattr = StrDup((char **)NULL, argv[i + 2]);
ResNodeAddDevice(device->gate, device, GATE);
i += 3;
if (i < argc - 2)
{
entry = HashFind(&ResNodeTable, argv[i]);
device->source = (ResExtNode *)HashGetValue(entry);
device->rs_sattr = StrDup((char **)NULL, argv[i + 2]);
ResNodeAddDevice(device->source, device, SOURCE);
i += 3;
}
if (i < argc - 2)
{
entry = HashFind(&ResNodeTable, argv[i]);
device->drain = (ResExtNode *)HashGetValue(entry);
device->rs_dattr = StrDup((char **)NULL, argv[i + 2]);
ResNodeAddDevice(device->drain, device, DRAIN);
i += 3;
}
if (i < argc - 2)
{
TxError("Warning: Device %s has more than 4 ports (not handled).\n",
argv[DEV_NAME]);
}
device->rs_ttype = extGetDevType(devptr->exts_deviceName);
ResRDevList = device;
device->layout = NULL;
return 0;
}
/*
*-------------------------------------------------------------------------
*
* ResReadFET-- Processes a "fet" line from a ext file.
*
* Results: returns 0 if line was added correctly.
*
* Side Effects: Allocates devices.
*
*-------------------------------------------------------------------------
*/
int
ResReadFET(int argc,
char *argv[])
{
RDev *device;
int rvalue, i, j, k;
ExtDevice *devptr;
TileType ttype;
HashEntry *entry;
ResExtNode *node;
ResValue rpersquare;
float area, perim, wval, lval;
device = (RDev *)mallocMagic((unsigned)(sizeof(RDev)));
device->status = FALSE;
device->nextDev = ResRDevList;
/* Find the device definition record corresponding to the device name */
devptr = (ExtDevice *)NULL;
for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++)
{
for (devptr = ExtCurStyle->exts_device[ttype]; devptr;
devptr = devptr->exts_next)
if (!strcmp(devptr->exts_deviceName, argv[FET_NAME])) break;
if (devptr != NULL) break;
}
device->location.p_x = atoi(argv[FET_X]);
device->location.p_y = atoi(argv[FET_Y]);
device->rs_gattr = RDEV_NOATTR;
device->rs_sattr = RDEV_NOATTR;
device->rs_dattr = RDEV_NOATTR;
device->rs_devptr = devptr;
entry = HashLookOnly(&devptr->exts_deviceResist, "linear");
if (entry != NULL)
rpersquare = (ResValue)(spointertype)HashGetValue(entry);
else
rpersquare = (ResValue)10000.0; /* Default to a sane value */
/* For old-style FETs, the width is determined from area and perimeter */
area = MagAtof(argv[FET_AREA]);
perim = MagAtof(argv[FET_PERIM]);
lval = 0.5 * (perim + sqrt(perim * perim - 4 * area));
wval = area / lval;
device->resistance = wval * rpersquare; /* Channel resistance */
/* Find and record the FET terminal nodes */
entry = HashFind(&ResNodeTable, argv[FET_GATE]);
device->gate = (ResExtNode *)HashGetValue(entry);
entry = HashFind(&ResNodeTable, argv[FET_SOURCE]);
device->source = (ResExtNode *)HashGetValue(entry);
entry = HashFind(&ResNodeTable, argv[FET_DRAIN]);
device->drain = (ResExtNode *)HashGetValue(entry);
entry = HashFind(&ResNodeTable, argv[FET_SUBS]);
device->subs = (ResExtNode *)HashGetValue(entry);
device->rs_ttype = extGetDevType(devptr->exts_deviceName);
/* Copy attributes verbatim */
device->rs_gattr = StrDup((char **)NULL, argv[FET_GATE_ATTR]);
device->rs_sattr = StrDup((char **)NULL, argv[FET_SOURCE_ATTR]);
device->rs_dattr = StrDup((char **)NULL, argv[FET_DRAIN_ATTR]);
ResRDevList = device;
device->layout = NULL;
return 0;
}
/*
*-------------------------------------------------------------------------
*
* ResReadCapacitor-- Adds the capacitance from a C line to the appropriate
* node. Coupling capacitors are added twice, moving the capacitance
* to the substrate.
*
* Results:
* Always return 0
*
* Side Effects: modifies capacitance field of ResExtNode.
*
*-------------------------------------------------------------------------
*/
int
ResReadCapacitor(int argc,
char *argv[])
{
HashEntry *entry1, *entry2;
ResExtNode *node1, *node2;
entry1 = HashFind(&ResNodeTable, argv[COUPLETERMINAL1]);
node1 = ResExtInitNode(entry1);
if (ResOptionsFlags & ResOpt_Signal)
{
node1->capacitance += MagAtof(argv[COUPLEVALUE]);
entry2 = HashFind(&ResNodeTable, argv[COUPLETERMINAL2]);
node2 = ResExtInitNode(entry2);
node2->capacitance += MagAtof(argv[COUPLEVALUE]);
return 0;
}
entry2 = HashFind(&ResNodeTable, argv[COUPLETERMINAL2]);
node2 = ResExtInitNode(entry2);
node1->cap_couple += MagAtof(argv[COUPLEVALUE]);
node2->cap_couple += MagAtof(argv[COUPLEVALUE]);
return 0;
}
/*
*-------------------------------------------------------------------------
*
* ResReadAttribute--checks to see if a node attribute is a resistance
* attribute. If it is, add it to the correct node's status flag.
* Only works with 5.0 1/line attributes
*
* Results:
* Return 0 to keep search going, 1 to abort
*
* Side Effects: modifies resistance field of ResExtNode
*
*-------------------------------------------------------------------------
*/
int
ResReadAttribute(ResExtNode *node,
int argc,
char *argv[])
{
char *aname, *avalue;
char digit[MAXDIGIT];
int i;
static int notwarned = TRUE;
aname = argv[RES_EXT_ATTR_NAME];
avalue = argv[RES_EXT_ATTR_TEXT];
if (strncmp(avalue, "res:skip", 8) == 0)
{
if (node->status & FORCE)
{
TxError("Warning: Node %s is both forced and skipped\n", aname);
}
else
{
node->status |= SKIP;
}
}
else if (strncmp(avalue, "res:force", 9) == 0)
{
if (node->status & SKIP)
TxError("Warning: Node %s is both skipped and forced \n", aname);
else
node->status |= FORCE;
}
else if (strncmp(avalue, "res:min=", 8) == 0)
{
node->status |= MINSIZE;
for (i = 0, avalue += 8; *avalue != '\0'; avalue++)
{
digit[i++] = *avalue;
}
digit[i++] = '\0';
node->minsizeres = MagAtof(digit);
}
else if (strncmp(avalue, "res:drive", 9) == 0 &&
(ResOptionsFlags & ResOpt_Signal))
{
node->drivepoint.p_x = atoi(argv[RES_EXT_ATTR_X]);
node->drivepoint.p_y = atoi(argv[RES_EXT_ATTR_Y]);
node->rs_ttype = DBTechNoisyNameType(argv[RES_EXT_ATTR_TYPE]);
node->status |= DRIVELOC;
}
return 0;
}
/*
*-------------------------------------------------------------------------
*
* ResExtInitNode --
* Gets the node corresponding to a given hash table entry. If no
* such node exists, one is created.
*
* Results: Returns ResExtNode corresponding to entry.
*
* Side Effects: May allocate a new ResExtNode.
*
*-------------------------------------------------------------------------
*/
ResExtNode *
ResExtInitNode(entry)
HashEntry *entry;
{
ResExtNode *node;
if ((node = (ResExtNode *) HashGetValue(entry)) == NULL)
{
node = (ResExtNode *)mallocMagic((unsigned)(sizeof(ResExtNode)));
HashSetValue(entry, (char *) node);
node->nextnode = ResOriginalNodes;
ResOriginalNodes = node;
node->status = FALSE;
node->forward = (ResExtNode *) NULL;
node->capacitance = 0;
node->cap_couple = 0;
node->resistance = 0;
node->type = 0;
node->firstDev = NULL;
node->name = entry->h_key.h_name;
node->oldname = NULL;
node->drivepoint.p_x = INFINITY;
node->drivepoint.p_y = INFINITY;
node->location.p_x = INFINITY;
node->location.p_y = INFINITY;
}
while (node->status & FORWARD)
{
node = node->forward;
}
return node;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -32,7 +32,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/stack.h"
#include "utils/tech.h"
#include "textio/txcommands.h"
#include "resis/resis.h"
#include "resis/resis.h"
#define MILLIOHMSPEROHM 1000
@ -77,7 +77,7 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
if (*nodelist == NULL) return;
node = *nodelist;
node->rn_status |= MARKED | FINISHED;
node->rn_status |= RES_MARKED | RES_FINISHED;
*nodelist = node->rn_more;
if (node->rn_more != NULL)
node->rn_more->rn_less = (resNode *) NULL;
@ -138,7 +138,8 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
* more than 1, delete the current resistor to break the deadlock.
*/
if (numreceive == 0 && numdrive == 1 && node->rn_why != RES_NODE_ORIGIN)
if (numreceive == 0 && numdrive == 1 &&
!(node->rn_why & (RES_NODE_ORIGIN | RES_NODE_SINK)))
{
resistor1->rr_status |= RES_DEADEND;
if (resistor1->rr_value < tolerance)
@ -155,8 +156,8 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
{
if (resisptr->re_thisEl->rr_connection1 == otherNode)
{
if ((resisptr->re_thisEl->rr_connection2->rn_status & MARKED)
!= MARKED)
if ((resisptr->re_thisEl->rr_connection2->rn_status & RES_MARKED)
!= RES_MARKED)
{
PendingReceivers++;
}
@ -180,9 +181,9 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
(UnMarkedReceivers == 0 && MarkedReceivers > 1 &&
resistor2 == resistor1 && PendingReceivers == 0))
{
if (otherNode->rn_status & MARKED)
if (otherNode->rn_status & RES_MARKED)
{
otherNode->rn_status &= ~MARKED;
otherNode->rn_status &= ~RES_MARKED;
ResRemoveFromQueue(otherNode, biglist);
otherNode->rn_less = NULL;
otherNode->rn_more = *nodelist;
@ -208,9 +209,9 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
ResDeleteResPointer(resistor1->rr_connection2, resistor1);
ResEliminateResistor(resistor1, reslist);
ResMergeNodes(otherNode, node, nodelist, biglist);
if (otherNode->rn_status & MARKED)
if (otherNode->rn_status & RES_MARKED)
{
otherNode->rn_status &= ~MARKED;
otherNode->rn_status &= ~RES_MARKED;
ResRemoveFromQueue(otherNode, biglist);
otherNode->rn_less= NULL;
otherNode->rn_more = *nodelist;
@ -287,12 +288,12 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
resisptr->re_nextEl = node2->rn_re;
node2->rn_re = resisptr;
ResEliminateResistor(resistor2, reslist);
otherNode->rn_status |= (node->rn_status & RN_MAXTDI);
otherNode->rn_status |= (node->rn_status & RES_MAXTDI);
ResCleanNode(node, TRUE, biglist, nodelist);
node1->rn_status &= ~RES_DONE_ONCE;
if (node1->rn_status & MARKED)
if (node1->rn_status & RES_MARKED)
{
node1->rn_status &= ~MARKED;
node1->rn_status &= ~RES_MARKED;
ResRemoveFromQueue(node1, biglist);
node1->rn_less = NULL;
node1->rn_more = *nodelist;
@ -301,9 +302,9 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
*nodelist = node1;
}
node2->rn_status &= ~RES_DONE_ONCE;
if (node2->rn_status & MARKED)
if (node2->rn_status & RES_MARKED)
{
node2->rn_status &= ~MARKED;
node2->rn_status &= ~RES_MARKED;
ResRemoveFromQueue(node2, biglist);
node2->rn_less = NULL;
node2->rn_more = *nodelist;
@ -334,7 +335,7 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
if (resisptr->re_thisEl->rr_status & RES_DONE_ONCE)
continue;
if (resisptr->re_thisEl->rr_connection2->rn_status & MARKED)
if (resisptr->re_thisEl->rr_connection2->rn_status & RES_MARKED)
{
/*
* Mark big resistors so we only process them
@ -343,7 +344,7 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
if (resisptr->re_thisEl->rr_value > tolerance)
resisptr->re_thisEl->rr_status |= RES_DONE_ONCE;
resisptr->re_thisEl->rr_connection2->rn_status &= ~MARKED;
resisptr->re_thisEl->rr_connection2->rn_status &= ~RES_MARKED;
ResRemoveFromQueue(resisptr->re_thisEl->rr_connection2, biglist);
resisptr->re_thisEl->rr_connection2->rn_less= NULL;
resisptr->re_thisEl->rr_connection2->rn_more = *nodelist;
@ -383,27 +384,17 @@ ResMoveDevices(node1, node2)
device = devptr->te_thist;
oldptr = devptr;
devptr = devptr->te_nextt;
if (device->rd_status & RES_DEV_PLUG)
{
if (((ResPlug *)(device))->rpl_node == node1)
((ResPlug *)(device))->rpl_node = node2;
else
TxError("Bad node connection in plug\n");
}
if (device->rd_fet_gate == node1)
device->rd_fet_gate = node2;
else if (device->rd_fet_subs == node1)
device->rd_fet_subs = node2;
else if (device->rd_fet_source == node1)
device->rd_fet_source = node2;
else if (device->rd_fet_drain == node1)
device->rd_fet_drain = node2;
else
{
if (device->rd_fet_gate == node1)
device->rd_fet_gate = node2;
else if (device->rd_fet_subs == node1)
device->rd_fet_subs = node2;
else if (device->rd_fet_source == node1)
device->rd_fet_source = node2;
else if (device->rd_fet_drain == node1)
device->rd_fet_drain = node2;
else
TxError("Missing Device connection in squish routines"
TxError("Missing Device connection in squish routines"
" at %d, %d\n", node1->rn_loc.p_x, node1->rn_loc.p_y);
}
oldptr->te_nextt = node2->rn_te;
node2->rn_te = oldptr;
}
@ -537,7 +528,7 @@ ResScrunchNet(reslist, pendingList, biglist, tolerance)
ResEliminateResistor(current, reslist);
ResAddResistorToList(working, reslist);
if (node2->rn_why & RES_NODE_ORIGIN)
if (node2->rn_why & (RES_NODE_ORIGIN | RES_NODE_SINK))
{
ResMergeNodes(node2, node1, pendingList, biglist);
node1 = node2;
@ -551,7 +542,7 @@ ResScrunchNet(reslist, pendingList, biglist, tolerance)
*/
ResRemoveFromQueue(node1, biglist);
ResAddToQueue(node1, pendingList);
node1->rn_status &= ~(RES_DONE_ONCE | FINISHED);
node1->rn_status &= ~(RES_DONE_ONCE | RES_FINISHED);
ResDoneWithNode(node1);
while (*pendingList != NULL)
ResSimplifyNet(pendingList, biglist, reslist, tolerance);
@ -650,7 +641,7 @@ ResDistributeCapacitance(nodelist, totalcap)
TxError("Error: Node with no area.\n");
return;
}
capperarea = FEMTOTOATTO * totalcap / totalarea;
capperarea = totalcap / totalarea;
for (workingNode = nodelist; workingNode != NULL; workingNode = workingNode->rn_more)
workingNode->rn_float.rn_area *= capperarea;
@ -852,24 +843,26 @@ ResPruneTree(node, minTdi, nodelist1, nodelist2, resistorlist)
*/
int
ResDoSimplify(tolerance, rctol, goodies)
float tolerance;
float rctol;
ResGlobalParams *goodies;
ResDoSimplify(tolerance,resisdata)
float tolerance;
ResisData *resisdata;
{
resNode *node, *slownode;
float bigres = 0;
float millitolerance;
float totalcap;
float rctol;
resResistor *res;
ResSetPathRes();
rctol = resisdata->tdiTolerance;
ResSetPathRes(resisdata);
for (node = ResNodeList; node != NULL; node = node->rn_more)
bigres = MAX(bigres, node->rn_noderes);
bigres /= OHMSTOMILLIOHMS; /* convert from milliohms to ohms */
goodies->rg_maxres = bigres;
resisdata->rg_maxres = bigres;
#ifdef PARANOID
ResSanityChecks("ExtractSingleNet", ResResList, ResNodeList, ResDevList);
@ -880,7 +873,7 @@ ResDoSimplify(tolerance, rctol, goodies)
/* we're calculating lumped values so that the capacitance */
/* values get calculated correctly. */
(void) ResDistributeCapacitance(ResNodeList, goodies->rg_nodecap);
(void) ResDistributeCapacitance(ResNodeList, resisdata->rg_nodecap);
if (((tolerance > bigres) || ((ResOptionsFlags & ResOpt_Simplify) == 0)) &&
((ResOptionsFlags & ResOpt_DoLumpFile) == 0))
@ -905,43 +898,48 @@ ResDoSimplify(tolerance, rctol, goodies)
------*/
}
if (ResOptionsFlags & ResOpt_Tdi)
if (ResNodeAtOrigin == NULL)
{
if (goodies->rg_nodecap != -1 &&
(totalcap = ResCalculateChildCapacitance(ResOriginNode)) != -1)
TxError("Error: Network simplification: Failed to to get origin node.\n");
resisdata->rg_Tdi = 0;
}
else if (ResOptionsFlags & ResOpt_Tdi)
{
if ((resisdata->rg_nodecap != -1) &&
(totalcap = ResCalculateChildCapacitance(ResNodeAtOrigin)) != -1)
{
RCDelayStuff *rc = (RCDelayStuff *) ResNodeList->rn_client;
RCDelayStuff *rc = (RCDelayStuff *) ResNodeList->rn_client;
goodies->rg_nodecap = totalcap;
ResCalculateTDi(ResOriginNode, (resResistor *)NULL,
goodies->rg_bigdevres);
resisdata->rg_nodecap = totalcap;
ResCalculateTDi(ResNodeAtOrigin, (resResistor *)NULL,
resisdata->rg_bigdevres);
if (rc != (RCDelayStuff *)NULL)
goodies->rg_Tdi = rc->rc_Tdi;
resisdata->rg_Tdi = rc->rc_Tdi;
else
goodies->rg_Tdi = 0;
resisdata->rg_Tdi = 0;
slownode = ResNodeList;
for (node = ResNodeList; node != NULL; node = node->rn_more)
{
rc = (RCDelayStuff *)node->rn_client;
if ((rc != NULL) && (goodies->rg_Tdi < rc->rc_Tdi))
if ((rc != NULL) && (resisdata->rg_Tdi < rc->rc_Tdi))
{
slownode = node;
goodies->rg_Tdi = rc->rc_Tdi;
resisdata->rg_Tdi = rc->rc_Tdi;
}
}
slownode->rn_status |= RN_MAXTDI;
slownode->rn_status |= RES_MAXTDI;
}
else
goodies->rg_Tdi = -1;
resisdata->rg_Tdi = -1;
}
else
goodies->rg_Tdi = 0;
resisdata->rg_Tdi = 0;
if ((rctol+1) * goodies->rg_bigdevres * goodies->rg_nodecap >
rctol * goodies->rg_Tdi &&
if ((rctol+1) * resisdata->rg_bigdevres * resisdata->rg_nodecap >
rctol * resisdata->rg_Tdi &&
(ResOptionsFlags & ResOpt_Tdi) &&
goodies->rg_Tdi != -1)
resisdata->rg_Tdi != -1)
return 0;
/* Simplify network; resistors are still in milliohms, so use
@ -960,35 +958,35 @@ ResDoSimplify(tolerance, rctol, goodies)
for (node = ResNodeList; node != NULL; node = node->rn_more)
{
if (node->rn_noderes == 0)
ResOriginNode = node;
ResNodeAtOrigin = node;
node->rn_status |= FINISHED;
node->rn_status |= RES_FINISHED;
}
if (ResOriginNode != NULL)
if (ResNodeAtOrigin != NULL)
{
/* if Tdi is enabled, prune all branches whose end nodes */
/* have time constants less than the tolerance. */
if ((ResOptionsFlags & ResOpt_Tdi) &&
goodies->rg_Tdi != -1 &&
resisdata->rg_Tdi != -1 &&
rctol != 0)
{
ResPruneTree(ResOriginNode, (rctol + 1) *
goodies->rg_bigdevres * goodies->rg_nodecap / rctol,
ResPruneTree(ResNodeAtOrigin, (rctol + 1) *
resisdata->rg_bigdevres * resisdata->rg_nodecap / rctol,
&ResNodeList, &ResNodeQueue, &ResResList);
}
ResOriginNode->rn_status &= ~MARKED;
if (ResOriginNode->rn_less == NULL)
ResNodeList = ResOriginNode->rn_more;
ResNodeAtOrigin->rn_status &= ~RES_MARKED;
if (ResNodeAtOrigin->rn_less == NULL)
ResNodeList = ResNodeAtOrigin->rn_more;
else
ResOriginNode->rn_less->rn_more = ResOriginNode->rn_more;
ResNodeAtOrigin->rn_less->rn_more = ResNodeAtOrigin->rn_more;
if (ResOriginNode->rn_more != NULL)
ResOriginNode->rn_more->rn_less = ResOriginNode->rn_less;
if (ResNodeAtOrigin->rn_more != NULL)
ResNodeAtOrigin->rn_more->rn_less = ResNodeAtOrigin->rn_less;
ResOriginNode->rn_more = NULL;
ResOriginNode->rn_less = NULL;
ResNodeQueue = ResOriginNode;
ResNodeAtOrigin->rn_more = NULL;
ResNodeAtOrigin->rn_less = NULL;
ResNodeQueue = ResNodeAtOrigin;
while (ResNodeQueue != NULL)
ResSimplifyNet(&ResNodeQueue, &ResNodeList, &ResResList, millitolerance);
@ -1009,7 +1007,7 @@ ResDoSimplify(tolerance, rctol, goodies)
*/
void
ResSetPathRes()
ResSetPathRes(ResisData *resisdata)
{
HeapEntry he;
resNode *node;
@ -1025,24 +1023,32 @@ ResSetPathRes()
{
if (node->rn_noderes == 0)
{
ResOriginNode = node;
node->rn_status |= FINISHED;
ResNodeAtOrigin = node;
node->rn_status |= RES_FINISHED;
}
else
{
node->rn_noderes = RES_INFINITY;
node->rn_status &= ~FINISHED;
node->rn_status &= ~RES_FINISHED;
}
}
if (ResOriginNode == NULL)
if (ResNodeAtOrigin == NULL)
{
resDevice *res = ResGetDevice(gparams.rg_devloc, gparams.rg_ttype);
ResOriginNode = res->rd_fet_source;
ResOriginNode->rn_why = RES_NODE_ORIGIN;
ResOriginNode->rn_noderes = 0;
resDevice *res = ResGetDevice(resisdata->rg_devloc, resisdata->rg_ttype);
if (res == (resDevice *)NULL)
{
TxError("Error: No device type %s found at location %s %s\n",
DBTypeLongNameTbl[resisdata->rg_ttype],
DBWPrintValue(resisdata->rg_devloc->p_x, (MagWindow *)NULL, TRUE),
DBWPrintValue(resisdata->rg_devloc->p_y, (MagWindow *)NULL, FALSE));
return;
}
ResNodeAtOrigin = res->rd_fet_source;
ResNodeAtOrigin->rn_why = RES_NODE_ORIGIN;
ResNodeAtOrigin->rn_noderes = 0;
}
ASSERT(ResOriginNode != NULL, "ResDoSimplify");
resPathNode(ResOriginNode);
ASSERT(ResNodeAtOrigin != NULL, "ResDoSimplify");
resPathNode(ResNodeAtOrigin);
while (HeapRemoveTop(&ResistorHeap,&he))
resPathRes((resResistor *)he.he_id);
}
@ -1053,7 +1059,7 @@ ResSetPathRes()
*
* Given node "node", add every resistor connected to the node, and
* for which the node on the other side has not been processed, to
* the heap. Node is marked with FINISHED to prevent going 'round
* the heap. Node is marked with RES_FINISHED to prevent going 'round
* and 'round loops.
*-------------------------------------------------------------------------
*/
@ -1065,7 +1071,7 @@ resPathNode(node)
{
resElement *re;
node->rn_status |= FINISHED;
node->rn_status |= RES_FINISHED;
for (re = node->rn_re; re; re = re->re_nextEl)
{
resResistor *res = re->re_thisEl;
@ -1073,7 +1079,7 @@ resPathNode(node)
if (res->rr_status & RES_HEAP) continue;
if ((node2 = res->rr_node[0]) == node) node2 = res->rr_node[1];
if ((node2->rn_status & FINISHED) == 0)
if ((node2->rn_status & RES_FINISHED) == 0)
HeapAddInt(&ResistorHeap, node->rn_noderes + res->rr_value,
(char *)res);
}
@ -1109,8 +1115,8 @@ resPathRes(res)
res->rr_status &= ~RES_MARKED;
node0 = res->rr_node[0];
node1 = res->rr_node[1];
flag0 = node0->rn_status & FINISHED;
flag1 = node1->rn_status & FINISHED;
flag0 = node0->rn_status & RES_FINISHED;
flag1 = node1->rn_status & RES_FINISHED;
if (flag0 && flag1)
{
res->rr_status |= RES_TDI_IGNORE;

View File

@ -93,7 +93,7 @@ ResFirst(tile, dinfo, arg)
*
* resMultiPlaneTerm --
*
* Callback function to set a junk field
* Callback function to set a resInfo field
*
*--------------------------------------------------------------------------
*/
@ -102,13 +102,13 @@ int
resMultiPlaneTerm(
Tile *tile,
TileType dinfo, // Unused (but should be handled)
tileJunk *junk2)
resInfo *rinfo2)
{
tileJunk *Junk;
resInfo *Info;
Junk = resAddField(tile);
Junk->tj_status |= RES_TILE_SD;
junk2->sourceEdge |= OTHERPLANE;
Info = resAddField(tile);
Info->ri_status |= RES_TILE_SD;
rinfo2->sourceEdge |= OTHERPLANE;
return 0;
}
@ -117,7 +117,7 @@ resMultiPlaneTerm(
*
* resSubstrateTerm --
*
* Callback function to set a junk field
* Callback function to set a resInfo field
*
*--------------------------------------------------------------------------
*/
@ -128,10 +128,10 @@ resSubstrateTerm(
TileType dinfo,
ClientData clientdata) /* (unused) */
{
tileJunk *Junk;
resInfo *Info;
Junk = resAddField(tile);
Junk->tj_status |= RES_TILE_SUBS;
Info = resAddField(tile);
Info->ri_status |= RES_TILE_SUBS;
return 0;
}
@ -168,7 +168,7 @@ ResEach(tile, dinfo, pNum, arg)
/*
*-------------------------------------------------------------------------
*
* ResAddPlumbing-- Each tile is a tileJunk structure associated with it
* ResAddPlumbing-- Each tile has a resInfo structure associated with it
* to keep track of various things used by the extractor. ResAddPlumbing
* adds this structure and sets the tile's ClientData field to point to it.
* If the tile is a device, then a device structure is also added;
@ -188,7 +188,7 @@ ResAddPlumbing(tile, dinfo, arg)
TileType dinfo;
ClientData *arg;
{
tileJunk *Junk, *junk2;
resInfo *Info, *rinfo2;
static Stack *resDevStack = NULL;
TileType loctype, t1;
Tile *tp1, *tp2, *source;
@ -208,7 +208,7 @@ ResAddPlumbing(tile, dinfo, arg)
loctype = TiGetTypeExact(tile);
devptr = ExtCurStyle->exts_device[loctype];
junk2 = resAddField(tile);
rinfo2 = resAddField(tile);
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), loctype))
{
int i, nterms, pNum;
@ -249,8 +249,8 @@ ResAddPlumbing(tile, dinfo, arg)
resDev->rd_status = 0;
resDev->rd_nextDev = (resDevice *)*arg;
*arg = (ClientData)resDev;
junk2->deviceList = resDev;
junk2->tj_status |= RES_TILE_DEV;
rinfo2->deviceList = resDev;
rinfo2->ri_status |= RES_TILE_DEV;
for (i = 0; i < nterms - 2; i++)
{
@ -263,10 +263,10 @@ ResAddPlumbing(tile, dinfo, arg)
if TTMaskHasType(&(devptr->exts_deviceSDTypes[i]),
TiGetBottomType(tp2))
{
junk2->sourceEdge |= TOPEDGE;
rinfo2->sourceEdge |= TOPEDGE;
source = tp2;
Junk = resAddField(source);
Junk->tj_status |= RES_TILE_SD;
Info = resAddField(source);
Info->ri_status |= RES_TILE_SD;
break;
}
}
@ -278,10 +278,10 @@ ResAddPlumbing(tile, dinfo, arg)
if TTMaskHasType(&(devptr->exts_deviceSDTypes[i]),
TiGetTopType(tp2))
{
junk2->sourceEdge |= BOTTOMEDGE;
rinfo2->sourceEdge |= BOTTOMEDGE;
source = tp2;
Junk = resAddField(source);
Junk->tj_status |= RES_TILE_SD;
Info = resAddField(source);
Info->ri_status |= RES_TILE_SD;
break;
}
}
@ -293,10 +293,10 @@ ResAddPlumbing(tile, dinfo, arg)
if TTMaskHasType(&(devptr->exts_deviceSDTypes[i]),
TiGetLeftType(tp2))
{
junk2->sourceEdge |= RIGHTEDGE;
rinfo2->sourceEdge |= RIGHTEDGE;
source = tp2;
Junk = resAddField(source);
Junk->tj_status |= RES_TILE_SD;
Info = resAddField(source);
Info->ri_status |= RES_TILE_SD;
break;
}
}
@ -309,9 +309,9 @@ ResAddPlumbing(tile, dinfo, arg)
TiGetRightType(tp2))
{
source = tp2;
Junk = resAddField(source);
Junk->tj_status |= RES_TILE_SD;
junk2->sourceEdge |= LEFTEDGE;
Info = resAddField(source);
Info->ri_status |= RES_TILE_SD;
rinfo2->sourceEdge |= LEFTEDGE;
break;
}
}
@ -327,7 +327,7 @@ ResAddPlumbing(tile, dinfo, arg)
DBSrPaintArea((Tile *)NULL,
ResUse->cu_def->cd_planes[pNum],
&r, &(devptr->exts_deviceSDTypes[i]),
resMultiPlaneTerm, (ClientData)junk2);
resMultiPlaneTerm, (ClientData)rinfo2);
}
}
@ -360,10 +360,10 @@ ResAddPlumbing(tile, dinfo, arg)
{
if (TiGetBottomType(tp2) == t1)
{
tileJunk *j = resAddField(tp2);
if ((j->tj_status & RES_TILE_SD) == 0)
resInfo *re = resAddField(tp2);
if ((re->ri_status & RES_TILE_SD) == 0)
{
j->tj_status |= RES_TILE_SD;
re->ri_status |= RES_TILE_SD;
STACKPUSH((ClientData)tp2, resDevStack);
}
}
@ -373,10 +373,10 @@ ResAddPlumbing(tile, dinfo, arg)
{
if (TiGetTopType(tp2) == t1)
{
tileJunk *j = resAddField(tp2);
if ((j->tj_status & RES_TILE_SD) == 0)
resInfo *re = resAddField(tp2);
if ((re->ri_status & RES_TILE_SD) == 0)
{
j->tj_status |= RES_TILE_SD;
re->ri_status |= RES_TILE_SD;
STACKPUSH((ClientData)tp2, resDevStack);
}
}
@ -386,10 +386,10 @@ ResAddPlumbing(tile, dinfo, arg)
{
if (TiGetLeftType(tp2) == t1)
{
tileJunk *j = resAddField(tp2);
if ((j->tj_status & RES_TILE_SD) == 0)
resInfo *re = resAddField(tp2);
if ((re->ri_status & RES_TILE_SD) == 0)
{
j->tj_status |= RES_TILE_SD;
re->ri_status |= RES_TILE_SD;
STACKPUSH((ClientData)tp2, resDevStack);
}
}
@ -399,10 +399,10 @@ ResAddPlumbing(tile, dinfo, arg)
{
if (TiGetRightType(tp2) == t1)
{
tileJunk *j = resAddField(tp2);
if ((j->tj_status & RES_TILE_SD) == 0)
resInfo *re = resAddField(tp2);
if ((re->ri_status & RES_TILE_SD) == 0)
{
j->tj_status |= RES_TILE_SD;
re->ri_status |= RES_TILE_SD;
STACKPUSH((ClientData)tp2, resDevStack);
}
}
@ -430,7 +430,7 @@ ResAddPlumbing(tile, dinfo, arg)
STACKPUSH((ClientData)tile, resDevStack);
while (!StackEmpty(resDevStack))
{
tileJunk *j0;
resInfo *re0;
tp1 = (Tile *) STACKPOP(resDevStack);
if (IsSplit(tp1))
@ -446,17 +446,17 @@ ResAddPlumbing(tile, dinfo, arg)
t1 = TiGetTypeExact(tp1);
devptr = ExtCurStyle->exts_device[t1];
j0 = (tileJunk *) TiGetClientPTR(tp1);
re0 = (resInfo *) TiGetClientPTR(tp1);
/* top */
for (tp2 = RT(tp1); RIGHT(tp2) > LEFT(tp1); tp2 = BL(tp2))
{
if ((TiGetBottomType(tp2) == t1) &&
(TiGetClient(tp2) == CLIENTDEFAULT))
{
Junk = resAddField(tp2);
Info = resAddField(tp2);
STACKPUSH((ClientData)tp2, resDevStack);
Junk->deviceList = resDev;
Junk->tj_status |= RES_TILE_DEV;
Info->deviceList = resDev;
Info->ri_status |= RES_TILE_DEV;
/* Update device position to point to the lower-leftmost tile */
if ((tp2->ti_ll.p_x < resDev->rd_inside.r_ll.p_x) ||
@ -472,9 +472,9 @@ ResAddPlumbing(tile, dinfo, arg)
else if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),
TiGetBottomType(tp2))
{
Junk = resAddField(tp2);
if (Junk->tj_status & RES_TILE_SD)
j0->sourceEdge |= TOPEDGE;
Info = resAddField(tp2);
if (Info->ri_status & RES_TILE_SD)
re0->sourceEdge |= TOPEDGE;
}
}
/* bottom */
@ -483,10 +483,10 @@ ResAddPlumbing(tile, dinfo, arg)
if ((TiGetTopType(tp2) == t1) &&
(TiGetClient(tp2) == CLIENTDEFAULT))
{
Junk = resAddField(tp2);
Info = resAddField(tp2);
STACKPUSH((ClientData)tp2, resDevStack);
Junk->deviceList = resDev;
Junk->tj_status |= RES_TILE_DEV;
Info->deviceList = resDev;
Info->ri_status |= RES_TILE_DEV;
/* Update device position to point to the lower-leftmost tile */
if ((tp2->ti_ll.p_x < resDev->rd_inside.r_ll.p_x) ||
@ -502,9 +502,9 @@ ResAddPlumbing(tile, dinfo, arg)
else if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),
TiGetTopType(tp2))
{
Junk = resAddField(tp2);
if (Junk->tj_status & RES_TILE_SD)
j0->sourceEdge |= BOTTOMEDGE;
Info = resAddField(tp2);
if (Info->ri_status & RES_TILE_SD)
re0->sourceEdge |= BOTTOMEDGE;
}
}
/* right */
@ -513,10 +513,10 @@ ResAddPlumbing(tile, dinfo, arg)
if ((TiGetLeftType(tp2) == t1) &&
(TiGetClient(tp2) == CLIENTDEFAULT))
{
Junk = resAddField(tp2);
Info = resAddField(tp2);
STACKPUSH((ClientData)tp2, resDevStack);
Junk->deviceList = resDev;
Junk->tj_status |= RES_TILE_DEV;
Info->deviceList = resDev;
Info->ri_status |= RES_TILE_DEV;
/* Update device position to point to the lower-leftmost tile */
if ((tp2->ti_ll.p_x < resDev->rd_inside.r_ll.p_x) ||
@ -532,9 +532,9 @@ ResAddPlumbing(tile, dinfo, arg)
else if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),
TiGetLeftType(tp2))
{
Junk = resAddField(tp2);
if (Junk->tj_status & RES_TILE_SD)
j0->sourceEdge |= RIGHTEDGE;
Info = resAddField(tp2);
if (Info->ri_status & RES_TILE_SD)
re0->sourceEdge |= RIGHTEDGE;
}
}
/* left */
@ -543,10 +543,10 @@ ResAddPlumbing(tile, dinfo, arg)
if ((TiGetRightType(tp2) == t1) &&
(TiGetClient(tp2) == CLIENTDEFAULT))
{
Junk = resAddField(tp2);
Info = resAddField(tp2);
STACKPUSH((ClientData)tp2, resDevStack);
Junk->deviceList = resDev;
Junk->tj_status |= RES_TILE_DEV;
Info->deviceList = resDev;
Info->ri_status |= RES_TILE_DEV;
/* Update device position to point to the lower-leftmost tile */
if ((tp2->ti_ll.p_x < resDev->rd_inside.r_ll.p_x) ||
@ -562,9 +562,9 @@ ResAddPlumbing(tile, dinfo, arg)
else if TTMaskHasType(&(devptr->exts_deviceSDTypes[0]),
TiGetRightType(tp2))
{
Junk = resAddField(tp2);
if (Junk->tj_status & RES_TILE_SD)
j0->sourceEdge |= LEFTEDGE;
Info = resAddField(tp2);
if (Info->ri_status & RES_TILE_SD)
re0->sourceEdge |= LEFTEDGE;
}
}
}
@ -573,10 +573,10 @@ ResAddPlumbing(tile, dinfo, arg)
if (source != (Tile *) NULL)
{
tileJunk *j = (tileJunk *) TiGetClientPTR(source);
resInfo *re = (resInfo *) TiGetClientPTR(source);
STACKPUSH((ClientData)source, resDevStack);
j->tj_status &= ~RES_TILE_SD;
re->ri_status &= ~RES_TILE_SD;
}
while (!StackEmpty(resDevStack))
{
@ -592,12 +592,12 @@ ResAddPlumbing(tile, dinfo, arg)
/* top */
for (tp2 = RT(tp1); RIGHT(tp2) > LEFT(tp1); tp2 = BL(tp2))
{
tileJunk *j2 = (tileJunk *) TiGetClientPTR(tp2);
resInfo *re2 = (resInfo *) TiGetClientPTR(tp2);
if (TiGetBottomType(tp2) == t1)
{
if (j2->tj_status & RES_TILE_SD)
if (re2->ri_status & RES_TILE_SD)
{
j2->tj_status &= ~RES_TILE_SD;
re2->ri_status &= ~RES_TILE_SD;
STACKPUSH((ClientData)tp2, resDevStack);
}
}
@ -605,12 +605,12 @@ ResAddPlumbing(tile, dinfo, arg)
/* bottom */
for(tp2 = LB(tp1); LEFT(tp2) < RIGHT(tp1); tp2 = TR(tp2))
{
tileJunk *j2 = (tileJunk *) TiGetClientPTR(tp2);
resInfo *re2 = (resInfo *) TiGetClientPTR(tp2);
if (TiGetTopType(tp2) == t1)
{
if (j2->tj_status & RES_TILE_SD)
if (re2->ri_status & RES_TILE_SD)
{
j2->tj_status &= ~RES_TILE_SD;
re2->ri_status &= ~RES_TILE_SD;
STACKPUSH((ClientData)tp2, resDevStack);
}
}
@ -618,12 +618,12 @@ ResAddPlumbing(tile, dinfo, arg)
/* right */
for (tp2 = TR(tp1); TOP(tp2) > BOTTOM(tp1); tp2 = LB(tp2))
{
tileJunk *j2 = (tileJunk *) TiGetClientPTR(tp2);
resInfo *re2 = (resInfo *) TiGetClientPTR(tp2);
if (TiGetLeftType(tp2) == t1)
{
if (j2->tj_status & RES_TILE_SD)
if (re2->ri_status & RES_TILE_SD)
{
j2->tj_status &= ~RES_TILE_SD;
re2->ri_status &= ~RES_TILE_SD;
STACKPUSH((ClientData)tp2, resDevStack);
}
}
@ -631,12 +631,12 @@ ResAddPlumbing(tile, dinfo, arg)
/* left */
for (tp2 = BL(tp1); BOTTOM(tp2) < TOP(tp1); tp2 = RT(tp2))
{
tileJunk *j2 = (tileJunk *) TiGetClientPTR(tp2);
resInfo *re2 = (resInfo *) TiGetClientPTR(tp2);
if (TiGetRightType(tp2) == t1)
{
if (j2->tj_status & RES_TILE_SD)
if (re2->ri_status & RES_TILE_SD)
{
j2->tj_status &= ~RES_TILE_SD;
re2->ri_status &= ~RES_TILE_SD;
STACKPUSH((ClientData)tp2, resDevStack);
}
}
@ -650,7 +650,7 @@ ResAddPlumbing(tile, dinfo, arg)
/*
*-------------------------------------------------------------------------
*
* ResRemovePlumbing-- Removes and deallocates all the tileJunk fields.
* ResRemovePlumbing-- Removes and deallocates all the resInfo fields.
*
* Results: returns 0
*
@ -702,7 +702,7 @@ ResPreProcessDevices(TileList, DeviceList, Def)
{
Tile *tile;
ResDevTile *oldTile;
tileJunk *tstruct;
resInfo *tstruct;
TileType tt, residue;
int pNum;
@ -735,9 +735,9 @@ ResPreProcessDevices(TileList, DeviceList, Def)
GOTOPOINT(tile, &(TileList->area.r_ll));
tt = TiGetType(tile);
tstruct = (tileJunk *) TiGetClientPTR(tile);
tstruct = (resInfo *) TiGetClientPTR(tile);
if ((tstruct == (tileJunk *)CLIENTDEFAULT) ||
if ((tstruct == (resInfo *)CLIENTDEFAULT) ||
(tstruct->deviceList == NULL) ||
!TTMaskHasType(&ExtCurStyle->exts_deviceMask, tt))
{
@ -745,11 +745,11 @@ ResPreProcessDevices(TileList, DeviceList, Def)
TileList->area.r_ll.p_x,
TileList->area.r_ll.p_y);
}
else if ((tstruct->tj_status & RES_TILE_MARK) == 0)
else if ((tstruct->ri_status & RES_TILE_MARK) == 0)
{
resDevice *rd = tstruct->deviceList;
tstruct->tj_status |= RES_TILE_MARK;
tstruct->ri_status |= RES_TILE_MARK;
rd->rd_perim += TileList->perim;
rd->rd_length += TileList->overlap;
rd->rd_area += (TileList->area.r_xtop - TileList->area.r_xbot)
@ -851,17 +851,17 @@ ResRemoveFromQueue(node, list)
node->rn_less = NULL;
}
tileJunk *
resInfo *
resAddField(tile)
Tile *tile;
{
ClientData ticlient = TiGetClient(tile);
tileJunk *Junk = (tileJunk *)CD2PTR(ticlient);
resInfo *Info = (resInfo *)CD2PTR(ticlient);
if (ticlient == CLIENTDEFAULT)
{
Junk = (tileJunk *) mallocMagic((unsigned) (sizeof(tileJunk)));
ResJunkInit(Junk);
TiSetClientPTR(tile, Junk);
Info = (resInfo *) mallocMagic((unsigned) (sizeof(resInfo)));
ResInfoInit(Info);
TiSetClientPTR(tile, Info);
}
return Junk;
return Info;
}

View File

@ -140,9 +140,8 @@ resCurrentPrintFunc(node, resistor, filename)
for (workingDev = node->rn_te; workingDev != NULL;
workingDev = workingDev->te_nextt)
{
if ((workingDev->te_thist->rd_status & RES_DEV_PLUG) ||
workingDev->te_thist->rd_gate != node)
i_sum += workingDev->te_thist->rd_i;
if (workingDev->te_thist->rd_gate != node)
i_sum += workingDev->te_thist->rd_i;
}
if (i_sum != 0.0)
{

View File

@ -1,49 +1,38 @@
/* Header files for resistance extraction */
/* Type declarations */
/* contact points: keeps track where contacts are and what tiles they
refer to both before and after processing.
*/
/* Header files for resistance extraction */
#ifndef _MAGIC__RESIS__RESIS_H
#define _MAGIC__RESIS__RESIS_H
/*
* Contact points: keeps track where contacts are and what tiles they refer to both
* before and after processing.
*/
#define LAYERS_PER_CONTACT 4
#define TILES_PER_JUNCTION 2
typedef struct contactpoint
{
struct contactpoint *cp_nextcontact;/* Next contact in linked */
/* list. */
Point cp_center; /*Center of contact */
Rect cp_rect; /* Tile rectangle */
Tile *cp_contactTile;
/*
The following two keep
track of the tiles where
the contact was before
preprocessing, and the
next contact in that tile's
area.
*/
Tile *cp_tile[LAYERS_PER_CONTACT];
int cp_currentcontact; /* keeps track of tile
being processed
*/
TileType cp_type; /* Type of contact */
int cp_width; /* Width (in x) of contact region */
int cp_height; /* Height (in y) of contact region */
struct resnode *cp_cnode[LAYERS_PER_CONTACT];/* this contact's nodes */
int cp_status; /* status of processing on
this contact
*/
struct contactpoint *cp_nextcontact; /* Next contact in linked list. */
Point cp_center; /* Center of contact */
Rect cp_rect; /* Tile rectangle */
Tile *cp_contactTile; /* The following two keep track of
* the tiles where the contact was
* before preprocessing, and the
* next contact in that tile's area.
*/
Tile *cp_tile[LAYERS_PER_CONTACT];
int cp_currentcontact; /* keeps track of tile being processed */
TileType cp_type; /* Type of contact */
int cp_width; /* Width (in x) of contact region */
int cp_height; /* Height (in y) of contact region */
struct resnode *cp_cnode[LAYERS_PER_CONTACT]; /* this contact's nodes */
int cp_status; /* status of processing on this contact */
} ResContactPoint;
typedef struct resistor
{
struct resistor *rr_nextResistor; /* Doubly linked list pointers */
struct resistor *rr_nextResistor; /* Doubly linked list pointers */
struct resistor *rr_lastResistor;
struct resnode *rr_node[2];
float rr_value; /* Resistor's value in milliohms */
@ -57,10 +46,6 @@ typedef struct resistor
int rr_cl; /* resistor centerline for geometry */
int rr_width; /* resistor width for geometry */
TileType rr_tt; /* type that composes this */
/* resistor. */
#ifdef ARIEL
int rr_csArea; /* crosssectional area in lamba**2*/
#endif
} resResistor;
#define rr_connection1 rr_node[0]
@ -85,22 +70,18 @@ typedef struct device
struct resnode **rd_terminals;
int rd_nterms; /* number of terminals in rt_terminals */
int rd_perim; /* info about device */
int rd_area; /* used in .ext and .sim file */
int rd_area; /* used in .ext file */
int rd_length; /* patches. */
int rd_width;
int rd_tiles; /* number of tiles in device */
int rd_devtype; /* tiletype of device. */
Rect rd_inside; /* 1x1 rectangle inside device */
Tile *rd_tile; /* pointer to a tile in device */
#ifdef ARIEL
float rd_i; /* Current injected from this device */
/* in milliamps */
#endif
} resDevice;
/*
a junction is formed when two tiles that connect are next to one another.
*/
* A junction is formed when two tiles that connect are next to one another.
*/
typedef struct junction
{
@ -112,8 +93,8 @@ typedef struct junction
} ResJunction;
/*
* A port is declared for subcircuits; its name overrides any locally-
* generated node name.
* A port is declared for subcircuits; its name overrides any locally-generated
* node name.
*/
typedef struct resport
@ -125,9 +106,9 @@ typedef struct resport
} resPort;
/*
?element are 'cons' cells used to make linked lists of their referential
structures.
*/
* *element are 'cons' (in the LISP sense) cells used to make linked lists of
* their referential structures.
*/
typedef struct reselement
{
@ -161,15 +142,16 @@ typedef struct celement
} cElement;
/*
Nodes formed from network. These are linked both forwards and backwords
to other nodes. Lists of devices, resistors, junctions, and contacts
corresponding to this node are kept.
*/
* Nodes formed from network. These are linked both forwards and backwards
* to other nodes. Lists of devices, resistors, junctions, and contacts
* corresponding to this node are kept.
*/
typedef struct resnode
{
struct resnode *rn_more; /* doubly linked list pointers */
struct resnode *rn_less;
tElement *rn_te; /* widgets connected to this node */
tElement *rn_te; /* widgets connected to this node */
resElement *rn_re;
jElement *rn_je;
cElement *rn_ce;
@ -202,10 +184,10 @@ typedef struct nelement
} nElement;
/*
Breakpoints are places on a tile which may serve as sources/sinks of
current. When resistance is calculated for a tile. this is calculated
between these points.
*/
* Breakpoints are places on a tile which may serve as sources/sinks of
* current. When resistance is calculated for a tile. this is calculated
* between these points.
*/
typedef struct breakpoint
{
@ -216,31 +198,31 @@ typedef struct breakpoint
} Breakpoint;
/*
Each tile needs to keep track of the following things associated with it.
Since there are too many things to fit in the single ti_client field,
this 1 to 6 adaptor is used.
*/
* Each tile needs to keep track of the following things associated with it.
* Since there are too many things to fit in the single ti_client field,
* this 1 to 7 adaptor is used.
*/
typedef struct tilejunk
typedef struct resinfo
{
cElement *contactList; /*widgets connected to this tile */
resDevice *deviceList;
resPort *portList;
ResJunction *junctionList;
Breakpoint *breakList;
cElement *contactList; /* widgets connected to this tile */
resDevice *deviceList; /* devices this tile is part of */
resPort *portList; /* ports connected to this tile */
ResJunction *junctionList; /* junctions inside the tile */
Breakpoint *breakList; /* breakpoints inside the tile */
int sourceEdge; /* used in device tiles to keep
* of which diffusion edges are
* a transistor's source
* track of which diffusion edges
* are a transistor's source
*/
int tj_status; /* status of tile processing */
} tileJunk;
int ri_status; /* status of tile processing */
} resInfo;
/* ResDevTile keeps track of the location and type of devices.
These areas are painted into our copied def after the tree is totally
flattened. (They can't be painted right away becasue the copy routine
uses the new def to keep track of where it is in the design. It is also
used when devices are preproceesed.
*/
* These areas are painted into our copied def after the tree is totally
* flattened. (They can't be painted right away becasue the copy routine
* uses the new def to keep track of where it is in the design. It is also
* used when devices are preproceesed.
*/
typedef struct resdevtile
{
@ -253,25 +235,47 @@ typedef struct resdevtile
} ResDevTile;
/*
Goodies contains random stuff passed between the node extractor
and ResCheckSimNodes. The location of a start tile and the resistive
tolerance are passed down, while the derived network is passed back.
*/
* Linked list structure to use to store the substrate plane from each
* extracted CellDef so that they can be returned to the original after
* extraction.
*/
typedef struct goodstuff
struct saveList {
Plane *sl_plane;
CellDef *sl_def;
struct saveList *sl_next;
};
/* Structure stores information required to be sent to ExtResisForDef() */
typedef struct resoptions
{
TileType rg_ttype;
float rg_maxres;
float rg_nodecap;
float rg_Tdi;
int rg_bigdevres;
int rg_tilecount;
int rg_status;
Point *rg_devloc;
char *rg_name;
} ResGlobalParams;
/* Global options for extresist */
/* Used in RC delay calculations for Tdi filter */
float tdiTolerance;
float frequency;
float rthresh;
struct saveList *savePlanes;
CellDef *mainDef;
/*
* Various information passed between the node extractor and
* ResCheckExtNodes. The location of a start tile and the resistive
* tolerance are passed down, while the derived network is passed back.
*/
TileType rg_ttype;
float rg_maxres;
float rg_nodecap;
float rg_Tdi;
int rg_bigdevres;
int rg_tilecount;
int rg_status;
Point *rg_devloc;
char *rg_name;
} ResisData;
/* Structure used in RC delay calculations for Tdi filter. */
/* Attaches to rn_client field of resNode */
typedef struct rcdelaystuff
@ -280,8 +284,7 @@ typedef struct rcdelaystuff
float rc_Tdi; /* Tdi for node */
} RCDelayStuff;
/* ResSim.c type declarations */
/* More type declarations */
typedef struct rdev
{
@ -291,10 +294,10 @@ typedef struct rdev
resDevice *layout; /* pointer to resDevice that */
/* corresponds to RDev */
int status;
struct ressimnode *gate; /* Terminals of transistor. */
struct ressimnode *source;
struct ressimnode *drain;
struct ressimnode *subs; /* Used with subcircuit type only */
struct resextnode *gate; /* Terminals of transistor. */
struct resextnode *source;
struct resextnode *drain;
struct resextnode *subs; /* Used with subcircuit type only */
Point location; /* Location of lower left point of */
/* device. */
float resistance; /* "Resistance" of device. */
@ -305,47 +308,40 @@ typedef struct rdev
char *rs_dattr;
} RDev;
typedef struct ressimnode
typedef struct resextnode
{
struct ressimnode *nextnode; /* next node in OriginalNodes */
struct resextnode *nextnode; /* next node in OriginalNodes */
/* linked list. */
int status;
struct ressimnode *forward; /* If node has been merged, this */
int status;
struct resextnode *forward; /* If node has been merged, this */
/* points to the merged node. */
float capacitance; /* capacitance between node and */
/* GND for power connections */
/* and all capacitance for every */
/* thing else. */
float cap_vdd; /* capacitance to VDD (used for */
/* power calculations only */
float cap_couple; /* coupling capacitance */
float resistance; /* lumped resistance */
float minsizeres; /* Minimum size resistor allowed */
Point drivepoint; /* optional, user specified drive */
float capacitance; /* Capacitance between node and */
/* substrate */
float cap_couple; /* Coupling capacitance */
float resistance; /* Lumped resistance */
float minsizeres; /* Minimum size resistor allowed */
Point drivepoint; /* optional, user specified drive */
/* point for network. */
TileType rs_ttype; /* tiletype of drivepoint */
Point location; /* location of bottom of leftmost */
TileType rs_ttype; /* Tiletype of drivepoint */
Point location; /* Location of bottom of leftmost */
/* tile in the lowest numbered */
/* plane contained in the node . */
Rect rs_bbox; /* location of bottom of leftmost */
/* plane contained in the node. */
Rect rs_bbox; /* Location of bottom of leftmost */
/* tile in the lowest numbered */
/* plane contained in the node . */
TileType type; /* Tile type of tile at location */
struct devptr *firstDev; /* linked list of devices */
/* plane contained in the node. */
TileType type; /* Tile type of tile at location */
struct devptr *firstDev; /* Linked list of devices */
/* connected to node. */
char *name; /* Pointer to name of node stored */
char *name; /* Pointer to name of node stored */
/* in hash table. */
char *oldname; /* Pointer to previous name of */
char *oldname; /* Pointer to previous name of */
/* node, if it exists */
tElement *rs_sublist[2]; /* pointers to Gnd and Vdd sub */
/* strate connections,
if they exist */
} ResSimNode;
} ResExtNode;
#define RES_SUB_GND 0
#define RES_SUB_VDD 1
/* `cons' cell for linked list of devices connected to node */
/* `cons' cell for linked list of devices connected to node */
typedef struct devptr
{
@ -355,40 +351,6 @@ typedef struct devptr
/* is connected to node. */
} devPtr;
/* ResTime.c type declarations */
typedef struct resevent /* Raw event list read in from rsim/tv */
{
int rv_node; /* node number */
int rv_final; /* final value; (0,1, or X) */
int rv_tmin; /* minimum event time in units of 100ps */
int rv_tmax; /* maximum event time in units of 100ps */
float rv_i; /* event current in milliamps */
resDevice *rv_dev; /* device where charge drains */
} ResEvent;
typedef struct reseventcell
{
ResEvent *rl_this;
struct reseventcell *rl_next;
} REcell;
typedef struct rescurrentevent /* processed event used to feed relaxer */
{
struct rescurrentevent *ri_next;
float ri_i;
resDevice *ri_dev;
} ResCurrentEvent;
typedef struct restimebin /* Holds one timestep's worth of Events */
{
struct restimebin *rb_next;
struct restimebin *rb_last;
int rb_start;
int rb_end;
ResCurrentEvent *rb_first;
} ResTimeBin;
typedef struct resfixpoint /* Keeps track of where voltage sources are */
{
struct resfixpoint *fp_next;
@ -400,197 +362,136 @@ typedef struct resfixpoint /* Keeps track of where voltage sources are */
char fp_name[1];
} ResFixPoint;
typedef struct clump
{
unsigned rp_status;
rElement *rp_grouplist;
nElement *rp_nodelist;
rElement *rp_downlist;
rElement *rp_singlelist;
} ResClump;
/* the first two fields of this plug must be the the same as for
resDevice
*/
typedef struct plug
{
float rpl_i; /* current injected through
this plug
*/
int rpl_status; /* status bits for this plug */
struct plug *rpl_next; /* next plug in this bin */
Point rpl_loc; /*location of plug */
int rpl_type; /*type of plug */
resNode *rpl_node; /* this point's node */
} ResPlug;
/*
* Multipliers telling what portion of capacitance is to Vdd and what part is
* to ground. Right now, coupling capacitance is counted twice, so
* cap[0] + cap[1] = (c_vdd + c_gnd + 2 * c_couple) / (c_vdd + c_gnd + c_couple);
*/
typedef struct capval
{
float cap[1][2]; /* multipliers telling what portion of capacitance is
to Vdd and what part is to ground. Right now,
coupling capacitance is counted twice, so
cap[0]+cap[1] = (c_vdd+c_gnd+2*c_couple)/
(c_vdd+c_gnd+c_couple);
*/
float cap[1][2];
} ResCapVal;
/* node flags */
#define RES_REACHED_NODE 0x00200000
#define RES_NODE_XADJ 0x00400000
#define RES_NODE_YADJ 0x00800000
/* Node flags ("rn_status" field) */
/* type of node flags */
#define RES_NODE_JUNCTION 0x00000001
#define RES_NODE_DEVICE 0x00000002
#define RES_NODE_CONTACT 0x00000004
#define RES_NODE_ORIGIN 0x00000008
#define RES_TRUE 0x00000001
#define RES_PENDING 0x00000002
#define RES_FINISHED 0x00000004
#define RES_MARKED 0x00000100
#define RES_MAXTDI 0x00001000
#define RES_DONE_ONCE 0x00002000
#define RES_REACHED_NODE 0x00200000
#define RES_NODE_XADJ 0x00400000
#define RES_NODE_YADJ 0x00800000
/* resistor flags */
#define RES_DEADEND 0x00001000
#define RES_DONE_ONCE 0x00002000
#define RES_MARKED 0x00000100
#define RES_EW 0x00000200
#define RES_NS 0x00000400
#define RES_DIAGONAL 0x00000800
#define RES_TDI_IGNORE 0x00010000
#define RES_REACHED_RESISTOR 0x00100000
#define RES_HEAP 0x00200000
/* Resistor flags ("rr_status" field) */
/* device flags */
#define RES_DEV_SAVE 0x00000001
#define RES_DEV_PLUG 0x00000002
#define RES_EW 0x00000200
#define RES_NS 0x00000400
#define RES_DIAGONAL 0x00000800
#define RES_DEADEND 0x00001000
#define RES_TDI_IGNORE 0x00010000
#define RES_REACHED_RESISTOR 0x00100000
#define RES_HEAP 0x00200000
/* Note that RES_DONE_ONCE and RES_MARKED are used both for rn_status and
* rr_status, and these bit values must not collide with any other field
* values.
*/
/* Device flags ("rd_status" field) */
#define RES_DEV_SAVE 0x00000001
/* Type of node flags ("why" field) */
#define RES_NODE_JUNCTION 0x00000001
#define RES_NODE_DEVICE 0x00000002
#define RES_NODE_CONTACT 0x00000004
#define RES_NODE_ORIGIN 0x00000008
#define RES_NODE_SINK 0x00000010
/* Flags for tiles ("ri_status" field) */
#define RES_TILE_SUBS 0x01 /* A tile which is part of a substrate region. */
#define RES_TILE_SD 0x02 /* A tile which is part of a source/drain region. */
#define RES_TILE_DEV 0x04 /* A tile which is actually a device */
#define RES_TILE_DONE 0x08 /* Indicates whether tile has been processed */
#define RES_TILE_MARK 0x10 /* A temporary marking flag */
#define RES_TILE_PUSHED 0x20 /* Another temporary marking flag */
/* Tree walking flags */
/* flags for tiles */
/* A tile which is part of a substrate region. */
#define RES_TILE_SUBS 0x01
/* A tile which is part of a source/drain region. */
#define RES_TILE_SD 0x02
/* A tile which is actually a device */
#define RES_TILE_DEV 0x04
/* Indicates whether the tile has been processed or not */
#define RES_TILE_DONE 0x08
/*a temporary marking flag */
#define RES_TILE_MARK 0x10
/*another temporary marking flag */
#define RES_TILE_PUSHED 0x20
/* indicates that tile has unidirectional current flow */
#ifdef LAPLACE
#define RES_TILE_1D 0x40
#define RES_TILE_GDONE 0x80
#endif
/* tree walking flags */
#define RES_LOOP_OK 1
#define RES_NO_LOOP 1
#define RES_DO_LAST 0
#define RES_DO_FIRST 1
#define RES_NO_FLAGS 0
/* Constants (ResExtNode "status" field) */
/* ResSim Constants */
#define FORWARD 0x0000010
#define SKIP 0x0000020
#define FORCE 0x0000040
#define MINSIZE 0x0000080
#define DRIVELOC 0x0000100
#define PORTNODE 0x0000200
#define REDUNDANT 0x0000400
#define DONTKILL 0x0000800
#define FORWARD 0x0000010
#define SKIP 0x0000020
#define FORCE 0x0000040
#define MINSIZE 0x0000080
#define DRIVELOC 0x0000100
#define PORTNODE 0x0000200
#define REDUNDANT 0x0000400
#define DONTKILL 0x0000800
/* Capacitance table constants */
#define RES_CAP_GND 0
#define RES_CAP_VDD 1
#define RES_CAP_COUPLE 2
#define OHMSTOMILLIOHMS 1000
#define FEMTOTOATTO 1000
#define ATTOTOFEMTO 0.001
#define UNTOUCHED 0
#define SERIES 1
#define PARALLEL 2
#define LOOP 4
#define SINGLE 8
#define TRIANGLE 32
#define UNTOUCHED 0
#define SERIES 1
#define PARALLEL 2
#define LOOP 4
#define SINGLE 8
#define TRIANGLE 32
#define RESTRUE 1
#define PENDING 2
#define FINISHED 4
#define LEFTEDGE 1
#define RIGHTEDGE 4
#define TOPEDGE 8
#define BOTTOMEDGE 16
#define OTHERPLANE 32
#define LEFTEDGE 1
#define RIGHTEDGE 4
#define TOPEDGE 8
#define BOTTOMEDGE 16
#define OTHERPLANE 32
#define GATE 1
#define SOURCE 2
#define DRAIN 3
#define SUBS 4
#define RN_MAXTDI 0x00001000
/* "rg_status" flag */
#define MARKED 0x00000100
#define DRIVEONLY 0x00001000
#define GATE 1
#define SOURCE 2
#define DRAIN 3
#define SUBS 4
/* Magic's normal value of infinity is too small---67108863 is only 67K ohms. */
#define DRIVEONLY 0x00001000
#define ORIGIN 0x00000008
/* magic's normal value of infinity is too small- */
/* 67108863 is only 67K ohms. */
#define RES_INFINITY 0x3FFFFFFF
#define ResCheckIntegrity
#define RES_INFINITY 0x3FFFFFFF
/* The following turns on and off various options */
#define ResOpt_ExtractAll 0x00000002
#define ResOpt_Simplify 0x00000004
#define ResOpt_DoExtFile 0x00000008
#define ResOpt_DoRsmFile 0x00000010
#define ResOpt_DoLumpFile 0x00000020
#define ResOpt_RunSilent 0x00000040
#define ResOpt_ExplicitRtol 0x00000080
#define ResOpt_ExplicitTditol 0x00000100
#define ResOpt_Tdi 0x00000200
#define ResOpt_Stat 0x00000400
#define ResOpt_Power 0x00000800
#define ResOpt_Signal 0x00001000
#define ResOpt_Pname 0x00002000
#define ResOpt_Geometry 0x00004000
#define ResOpt_FastHenry 0x00008000
#define ResOpt_Blackbox 0x00010000
#define ResOpt_Dump 0x00020000
#define ResOpt_DoSubstrate 0x00040000
#define ResOpt_GndPlugs 0x00200000
#define ResOpt_VddPlugs 0x00400000
#define ResOpt_CMOS 0x00800000
#define ResOpt_Bipolar 0x01000000
#define ResOpt_Box 0x02000000
#ifdef LAPLACE
#define ResOpt_DoLaplace 0x04000000
#define ResOpt_CacheLaplace 0x08000000
#define ResOpt_Checkpoint 0x80000000
#endif
#define ResOpt_VDisplay 0x10000000
#define ResOpt_IDisplay 0x20000000
#define ResOpt_PDisplay 0x40000000
#define ResOpt_ExtractAll 0x0001
#define ResOpt_Simplify 0x0002
#define ResOpt_DoExtFile 0x0004
#define ResOpt_DoLumpFile 0x0008
#define ResOpt_RunSilent 0x0010
#define ResOpt_Stats 0x0020
#define ResOpt_Tdi 0x0040
#define ResOpt_Signal 0x0080
#define ResOpt_Geometry 0x0100
#define ResOpt_FastHenry 0x0200
#define ResOpt_Blackbox 0x0300
#define ResOpt_DoSubstrate 0x0800
#define ResOpt_Box 0x1000
/* Assorted Variables */
extern RDev *ResRDevList;
extern REcell *ResBigEventList;
extern int ResOptionsFlags;
extern char *ResCurrentNode;
extern ResSimNode *ResOriginalNodes;
#ifdef ARIEL
extern int ResMinEventTime;
extern int ResMaxEventTime;
typedef float ResCapElement[2];
extern ResCapElement *ResCapTableMax;
extern ResCapElement *ResCapTableMin;
extern HashTable ResPlugTable;
#endif
extern ResExtNode *ResOriginalNodes;
extern CellUse *ResUse;
extern CellDef *ResDef;
@ -601,39 +502,44 @@ extern resNode *ResNodeList;
extern resDevice *ResDevList;
extern ResContactPoint *ResContactList;
extern resNode *ResNodeQueue;
extern resNode *ResOriginNode;
extern resNode *ResNodeAtOrigin;
extern resNode *resCurrentNode;
extern HashTable ResNodeTable;
extern HashTable ResSimDevTable;
extern HashTable ResExtDevTable;
extern ResFixPoint *ResFixList;
extern int ResTileCount;
extern ResSimNode **ResNodeArray;
extern ResExtNode **ResNodeArray;
extern CellDef *mainDef;
extern TileTypeBitMask ResSDTypesBitMask;
extern TileTypeBitMask ResSubTypesBitMask;
extern HashTable ResDevTable;
extern TileTypeBitMask ResNoMergeMask[NT];
extern ResGlobalParams gparams;
extern int ResPortIndex;
extern int ResSimDevice();
extern int ResSimCombineParallel();
extern int ResSimCapacitor();
extern int ResSimResistor();
extern int ResSimAttribute();
extern int ResSimMerge();
extern int ResSimSubckt();
/* Routines used by ResReadExt() */
extern ResisData *ResInit();
extern int ResReadDevice();
extern int ResReadCapacitor();
extern int ResReadResistor();
extern int ResReadAttribute();
extern int ResReadMerge();
extern int ResReadSubckt();
extern int ResProcessNode();
extern int ResExtCombineParallel();
extern int dbSrConnectStartFunc();
extern int ResEach(),ResAddPlumbing(),ResRemovePlumbing();
extern int ResEach();
extern int ResAddPlumbing();
extern int ResRemovePlumbing();
extern float ResCalculateChildCapacitance();
extern ResDevTile *DBTreeCopyConnectDCS();
extern Tile *ResFindTile();
extern resDevice *ResImageAddPlug();
extern resDevice *ResGetDevice();
extern tileJunk *resAddField();
extern resInfo *resAddField();
extern int ResCheckPorts();
extern int ResCheckBlackbox();
extern void ResCheckSimNodes();
extern void ResCheckExtNodes();
extern void ResSortByGate();
extern void ResFixDevName();
extern void ResWriteLumpFile();
@ -641,6 +547,14 @@ extern void ResSortBreaks();
extern Plane *extResPrepSubstrate();
/* C99 compat */
extern void ExtResisForDef(CellDef *celldef, ResisData *resisdata);
extern char *ResExtGetAttribute(char *sptr);
extern int ResReadFET(int argc, char *argv[]);
extern int ResReadPort(int argc, char *argv[]);
extern char *ResExtGetAttribute(char *sptr);
extern ResExtNode *ResExtInitNode();
extern void ResAddToQueue();
extern bool ResCalcTileResistance();
extern void ResCleanNode();
@ -662,10 +576,11 @@ extern void ResPrintReference();
extern void ResPrintResistorList();
extern void ResPrintStats();
extern void ResProcessJunction();
extern int ResReadNode();
extern int ResReadSim();
extern ResExtNode *ResReadNode(int argc, char *argv[]);
extern int ResReadExt();
extern void ResRemoveFromQueue();
extern int ResSimNewNode();
extern int ResExtNewNode();
extern void ResExtProcessDrivePoints();
extern int ResWriteExtFile();
extern void ResPrintExtNode();
extern void ResPrintExtRes();
@ -681,10 +596,9 @@ extern int resWalkleft();
extern int resWalkright();
extern int resWalkup();
/* Macros */
/* macros */
#define InitializeNode(node,x,y,why) \
#define InitializeResNode(node,x,y,why) \
{\
(node)->rn_te = NULL;\
(node)->rn_id=0;\
@ -701,21 +615,21 @@ extern int resWalkup();
(node)->rn_re = (resElement *) NULL;\
}
#define ResJunkInit(Junk) \
#define ResInfoInit(Info) \
{ \
Junk->contactList = (cElement *) NULL; \
Junk->deviceList = (resDevice *) NULL; \
Junk->junctionList = (ResJunction *) NULL; \
Junk->breakList = (Breakpoint *) NULL; \
Junk->portList = (resPort *) NULL; \
Junk->tj_status = FALSE; \
Junk->sourceEdge = 0 ; \
Info->contactList = (cElement *) NULL; \
Info->deviceList = (resDevice *) NULL; \
Info->junctionList = (ResJunction *) NULL; \
Info->breakList = (Breakpoint *) NULL; \
Info->portList = (resPort *) NULL; \
Info->ri_status = FALSE; \
Info->sourceEdge = 0 ; \
}
#define NEWBREAK(node,tile,px,py,crect)\
{\
Breakpoint *bp;\
tileJunk *jX_ = (tileJunk *)((tile)->ti_client); \
resInfo *jX_ = (resInfo *)((tile)->ti_client); \
bp = (Breakpoint *) mallocMagic((unsigned)(sizeof(Breakpoint))); \
bp->br_next= jX_->breakList; \
bp->br_this = (node); \
@ -728,7 +642,7 @@ extern int resWalkup();
#define NEWPORT(node,tile)\
{\
resPort *rp;\
tileJunk *pX_ = (tileJunk *)((tile)->ti_client); \
resInfo *pX_ = (resInfo *)((tile)->ti_client); \
rp = (resPort *) mallocMagic((unsigned)(sizeof(resPort))); \
rp->rp_nextPort = pX_->portList; \
rp->rp_bbox = node->rs_bbox; \

View File

@ -321,14 +321,20 @@ selRedisplayCellFunc(scx, window)
if (scx->scx_use->cu_def->cd_flags & CDFIXEDBBOX)
{
bool found;
char *propval;
PropertyRecord *proprec;
propval = (char *)DBPropGet(scx->scx_use->cu_def, "FIXED_BBOX", &found);
proprec = DBPropGet(scx->scx_use->cu_def, "FIXED_BBOX", &found);
if (found)
{
if (sscanf(propval, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) == 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
GeoTransRect(&scx->scx_trans, &bbox, &tmp);
}
else
found = FALSE;
}

View File

@ -46,14 +46,14 @@ proc magic::drccallback {command} {
}
zoom {
if {$value != {}} {
set snaptype [snap]
snap internal
set curunits [units]
units internal
box values {*}$value
magic::suspendall
magic::findbox zoom
magic::zoom 2
magic::resumeall
snap $snaptype
units {*}$curunits
}
}
}

View File

@ -250,10 +250,10 @@ proc magic::change_label {} {
setlabel size ${lsize}um
}
if {$loff != ""} {
set oldsnap [snap list]
snap internal
set oldunits [units]
units internal
setlabel offset [join $loff]
snap $oldsnap
units $oldunits
}
if {$lrot != ""} {
setlabel rotate $lrot

View File

@ -10,6 +10,11 @@
# Revision 2 (names are hashed from properties)
# March 9, 2021
# Added spice-to-layout procedure
# March 4, 2026
# Changed to make use of new "units" command
# March 26, 2026
# Added behavior to handle ideal devices (resistor, capacitor,
# inductor)
#--------------------------------------------------------------
# Sets up the environment for a toolkit. The toolkit must
# supply a namespace that is the "library name". For each
@ -118,6 +123,8 @@ magic::tag add select "magic::gencell_update %1"
proc magic::move_forward_by_width {instname} {
select cell $instname
set curunits [units]
units internal
set anum [lindex [array -list count] 1]
set xpitch [lindex [array -list pitch] 0]
set bbox [box values]
@ -125,7 +132,8 @@ proc magic::move_forward_by_width {instname} {
set posy [lindex $bbox 1]
set width [expr [lindex $bbox 2] - $posx]
set posx [expr $posx + $width + $xpitch * $anum]
box position ${posx}i ${posy}i
box position ${posx} ${posy}
units {*}$curunits
return [lindex $bbox 3]
}
@ -141,10 +149,13 @@ proc magic::get_and_move_inst {cellname instname {anum 1}} {
if {$newinst == ""} {return}
identify $instname
if {$anum > 1} {array 1 $anum}
set curunits [units]
units internal
set bbox [box values]
set posx [lindex $bbox 2]
set posy [lindex $bbox 1]
box position ${posx}i ${posy}i
box position ${posx} ${posy}
units {*}$curunits
return [lindex $bbox 3]
}
@ -155,11 +166,14 @@ proc magic::get_and_move_inst {cellname instname {anum 1}} {
# given layer. Otherwise, the pin is created on the m1 layer.
proc magic::create_new_pin {pinname portnum {layer m1}} {
box size 1um 1um
set curunits [units]
units microns
box size 1 1
paint $layer
label $pinname FreeSans 16 0 0 0 c $layer
label $pinname FreeSans 1 0 0 0 c $layer
port make $portnum
box move s 2um
box move s 2
units {*}$curunits
}
# generate_layout_add --
@ -172,6 +186,9 @@ proc magic::create_new_pin {pinname portnum {layer m1}} {
proc magic::generate_layout_add {subname subpins complist library} {
global PDKNAMESPACE
set curunits [units]
units internal
# Create a new subcircuit.
load $subname -quiet
@ -241,7 +258,7 @@ proc magic::generate_layout_add {subname subpins complist library} {
box size 0 0
set posx 0
set posy [expr {round(3 / [cif scale out])}]
box position ${posx}i ${posy}i
box position ${posx} ${posy}
# Find all instances in the circuit
select top cell
@ -267,8 +284,13 @@ proc magic::generate_layout_add {subname subpins complist library} {
set paramlist {}
# NOTE: This routine deals with subcircuit calls and devices
# with models. It needs to determine when a device is instantiated
# without a model, and ignore such devices.
# with models. There are two exceptions, for toolkits which
# wish to implement a way to generate unmodeled capacitors,
# resistors, or inductors based on value; for example, metal
# interdigitated capacitors. For those exceptions, the device
# value is recast as a parameter called "value", and the device
# is given a model "capacitor", "resistor", or "inductor",
# respectively.
# Parse SPICE line into pins, device name, and parameters. Make
# sure parameters incorporate quoted expressions as {} or ''.
@ -312,6 +334,23 @@ proc magic::generate_layout_add {subname subpins complist library} {
set devtype [lindex $pinlist end]
set pinlist [lrange $pinlist 0 end-1]
# Ideal device check: "devtype" will start with a digit.
# The instname will begin with "c", "r", or "l".
if {[regexp {^([0-9\.]+.*)} $devtype pval]} {
set comptype [string tolower [string range $instname 0 0]]
if {$comptype == "c"} {
lappend paramlist [list value $pval]
set devtype capacitor
} elseif {$comptype == "r"} {
lappend paramlist [list value $pval]
set devtype resistor
} elseif {$comptype == "l"} {
lappend paramlist [list value $pval]
set devtype inductor
}
}
set mult 1
foreach param $paramlist {
set parmname [lindex $param 0]
@ -323,6 +362,27 @@ proc magic::generate_layout_add {subname subpins complist library} {
}
}
# Check if devtype has routines by looking for ${devtype}_defaults.
# If not found, do a case-insensitive check against all devices
# before deciding that devtype is a subcircuit and not a device.
# If found by case-insensitive check, then change the device name
# to the one used in the library.
if {$library != ""} {
set alldevices [namespace eval ::${library} {info procs}]
} else {
set alldevices [namespace eval ::${PDKNAMESPACE} {info procs}]
}
set devdefault [lsearch $alldevices ${devtype}_defaults]
if {$devdefault == -1} {
set devdefault [lsearch -nocase $alldevices ${devtype}_defaults]
if {$devdefault != -1} {
set devprocname [lindex $alldevices $devdefault]
set devproclist [split $devprocname "_"]
set devtype [lindex $devproclist 0]
}
}
# devtype is assumed to be in library. If not, it will attempt to
# use 'getcell' on devtype. Note that this code depends on the
# PDK setting varible PDKNAMESPACE.
@ -374,6 +434,7 @@ proc magic::generate_layout_add {subname subpins complist library} {
}
}
save $subname
units {*}$curunits
}
#--------------------------------------------------------------
@ -485,7 +546,7 @@ proc magic::netlist_to_layout {netfile library} {
set subname [lindex $ftokens 1]
set subpins [lrange $ftokens 2 end]
set insub true
} elseif {[regexp -nocase {^[xmcrdq]([^ \t]+)[ \t](.*)$} $line \
} elseif {[regexp -nocase {^[xmcrldq]([^ \t]+)[ \t](.*)$} $line \
valid instname rest]} {
lappend toplist $line
} elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \
@ -500,7 +561,7 @@ proc magic::netlist_to_layout {netfile library} {
set subname ""
set subpins ""
set complist {}
} elseif {[regexp -nocase {^[xmcrdq]([^ \t]+)[ \t](.*)$} $line \
} elseif {[regexp -nocase {^[xmcrldq]([^ \t]+)[ \t](.*)$} $line \
valid instname rest]} {
lappend complist $line
} elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \
@ -813,8 +874,8 @@ proc magic::gencell_change {instname gencell_type library parameters} {
return
}
set snaptype [snap list]
snap internal
set curunits [units]
units internal
set savebox [box values]
catch {setpoint 0 0 $Opts(focus)}
@ -881,7 +942,7 @@ proc magic::gencell_change {instname gencell_type library parameters} {
}
identify $newinstname
eval "box values $savebox"
snap $snaptype
units {*}$curunits
# Update window
if {$gname != $old_gname} {
@ -940,8 +1001,8 @@ proc magic::gencell_change_orig {instname gencell_type library parameters} {
return
}
set snaptype [snap list]
snap internal
set curunits [units]
units internal
set savebox [box values]
catch {setpoint 0 0 $Opts(focus)}
@ -969,7 +1030,7 @@ proc magic::gencell_change_orig {instname gencell_type library parameters} {
}
identify $newinstname
eval "box values $savebox"
snap $snaptype
units {*}$curunits
resumeall
redraw
}
@ -1092,8 +1153,8 @@ proc magic::gencell_create {gencell_type library parameters {orient 0}} {
set parameters [dict remove $parameters gencell]
}
set snaptype [snap list]
snap internal
set curunits [units]
units internal
set savebox [box values]
catch {setpoint 0 0 $Opts(focus)}
@ -1123,7 +1184,7 @@ proc magic::gencell_create {gencell_type library parameters {orient 0}} {
identify $newinstname
set instname $newinstname
}
snap $snaptype
units {*}$curunits
resumeall
redraw
return $instname
@ -1163,17 +1224,7 @@ proc magic::add_entry {pname ptext parameters} {
proc magic::add_check_callbacks {gencell_type library} {
set wlist [winfo children .params.body.area.edits]
foreach w $wlist {
if {[regexp {\.params\.body\.area\.edits\.(.+)_ent} $w valid pname]} {
# Add callback on enter or focus out
bind $w <Return> \
"magic::update_dialog {} $pname $gencell_type $library"
bind $w <FocusOut> \
"magic::update_dialog {} $pname $gencell_type $library"
}
if {[regexp {\.params\.body\.area\.edits\.(.+)_sel} $w valid pname]} {
magic::add_dependency \{\} $gencell_type $library $pname
}
if {[regexp {\.params\.body\.area\.edits\.(.+)_chk} $w valid pname]} {
if {[regexp {\.params\.body\.area\.edits\.(.+)_.+} $w valid pname]} {
magic::add_dependency \{\} $gencell_type $library $pname
}
}
@ -1192,6 +1243,11 @@ proc magic::add_check_callbacks {gencell_type library} {
# dictionary.
#
# Also handle dependencies on checkboxes and selection lists
#
# If dependency callbacks exist, then chain them together.
# A final default dependency will be added to all entries
# to run the "check" procedure for the device. Dependencies
# that are more targeted get run first.
#----------------------------------------------------------
proc magic::add_dependency {callback gencell_type library args} {
@ -1206,21 +1262,28 @@ proc magic::add_dependency {callback gencell_type library args} {
foreach pname $args {
if {[lsearch $clist .params.body.area.edits.${pname}_ent] >= 0} {
# Add callback on enter or focus out
bind .params.body.area.edits.${pname}_ent <Return> \
"magic::update_dialog $callback $pname $gencell_type $library"
bind .params.body.area.edits.${pname}_ent <FocusOut> \
"magic::update_dialog $callback $pname $gencell_type $library"
set oldbind [bind .params.body.area.edits.${pname}_ent <Return>]
set newbind "magic::update_dialog $callback $pname $gencell_type $library"
if {$oldbind != {}} {set newbind "$oldbind ; $newbind"}
bind .params.body.area.edits.${pname}_ent <Return> $newbind
set oldbind [bind .params.body.area.edits.${pname}_ent <FocusOut>]
set newbind "magic::update_dialog $callback $pname $gencell_type $library"
if {$oldbind != {}} {set newbind "$oldbind ; $newbind"}
bind .params.body.area.edits.${pname}_ent <FocusOut> $newbind
} elseif {[lsearch $clist .params.body.area.edits.${pname}_chk] >= 0} {
# Add callback on checkbox change state
.params.body.area.edits.${pname}_chk configure -command \
"magic::update_dialog $callback $pname $gencell_type $library"
set oldcmd [.params.body.area.edits.${pname}_chk cget -command]
set newcmd "magic::update_dialog $callback $pname $gencell_type $library"
if {$oldcmd != {}} {set newcmd "$oldcmd ; $newcmd"}
.params.body.area.edits.${pname}_chk configure -command $newcmd
} elseif {[lsearch $clist .params.body.area.edits.${pname}_sel] >= 0} {
set smenu .params.body.area.edits.${pname}_sel.menu
set sitems [${smenu} index end]
for {set idx 0} {$idx <= $sitems} {incr idx} {
set curcommand [${smenu} entrycget $idx -command]
${smenu} entryconfigure $idx -command "$curcommand ; \
magic::update_dialog $callback $pname $gencell_type $library"
set oldcmd [${smenu} entrycget $idx -command]
set newcmd "magic::update_dialog $callback $pname $gencell_type $library"
if {$oldcmd != {}} {set newcmd "$oldcmd ; $newcmd"}
${smenu} entryconfigure $idx -command $newcmd
}
}
}

View File

@ -138,7 +138,11 @@ proc magic::pushstack {{name ""}} {
if {[catch {lindex $editstack end}]} {
set editstack {}
}
# Protect against changing units by always using internal units
set curunits [units]
units internal
lappend editstack [view get]
units {*}$curunits
lappend editstack [cellname list window]
set ltag [tag load]
tag load {}
@ -158,10 +162,11 @@ proc magic::popstack {} {
tag load {}
suspendall
load [lindex $editstack end]
set snaptype [snap]
snap internal
# Protect against changing units by always using internal units
set curunits [units]
units internal
view [lindex $editstack end-1]
snap $snaptype
units {*}$curunits
catch {magic::cellmanager}
catch {magic::captions}
resumeall
@ -186,8 +191,8 @@ proc magic::clearstack {} {
proc magic::pushbox {{values {}}} {
global boxstack
set snaptype [snap list]
snap internal
set curunits [units]
units internal
if {[catch {set boxstack}]} {
set boxstack {}
}
@ -196,7 +201,7 @@ proc magic::pushbox {{values {}}} {
} else {
lappend boxstack $values
}
snap $snaptype
units {*}$curunits
return
}
@ -210,8 +215,8 @@ proc magic::pushbox {{values {}}} {
proc magic::popbox {{type values}} {
global boxstack
set snaptype [snap list]
snap internal
set curunits [units]
units internal
if {[catch {set boxstack}]} {
error "No stack"
} elseif {$boxstack == {}} {
@ -231,7 +236,7 @@ proc magic::popbox {{type values}} {
}
}
set boxstack [lrange $boxstack 0 end-1]
snap $snaptype
units {*}$curunits
return $b
}
@ -355,8 +360,8 @@ proc magic::ruler {{text {}} {orient auto}} {
set mmx [expr {($llx + $urx) / 2}]
set mmy [expr {($lly + $ury) / 2}]
set snapsave [snap]
snap internal
set curunits [units]
units internal
if {$orient == "horizontal"} {
element add line l1_$Opts(rulers) black $llx $lly $llx $ury
@ -410,7 +415,7 @@ proc magic::ruler {{text {}} {orient auto}} {
element configure l3_$Opts(rulers) flags arrowbottom
}
}
snap $snapsave
units {*}$curunits
}
#---------------------------------------------------------------------
@ -534,6 +539,7 @@ proc magic::enable_tools {} {
magic::macro copy pick
magic::tool wiring
macro Control_Button1 "magic::trackwire %W current"
macro Button1 "magic::trackwire %W pick"
macro Button2 "magic::trackwire %W done"
macro Button3 "magic::trackwire %W cancel"
@ -587,6 +593,19 @@ proc magic::trackwire {window {option {}}} {
bind ${window} <Motion> [subst {$Opts(motion); *bypass wire show}]
if {$Opts(motion) == {}} {set Opts(motion) "null"}
cursor 21
} elseif {$option == "current"} {
puts stdout $window
set curunits [units]
units internal
wire type {*}[wire values]
set wiresize [lindex [wire values] 1]
box size $wiresize $wiresize
box move bl cursor
units {*}$curunits
set Opts(motion) [bind ${window} <Motion>]
bind ${window} <Motion> [subst {$Opts(motion); *bypass wire show}]
if {$Opts(motion) == {}} {set Opts(motion) "null"}
cursor 21
}
} else {
if {$option != "cancel"} {

View File

@ -576,6 +576,7 @@ set Opts(toolbar) 0
set Opts(toolscale) 1.0
set Opts(drc) 1
set Opts(autobuttontext) 1
set Opts(cmdentry) 0
# Update cell and tech managers in response to a cif or gds read command
@ -649,18 +650,20 @@ proc magic::boxview {win {cmdstr ""}} {
set framename [winfo parent $win]
if {$framename == "."} {return}
if {[catch {set cr [cif scale out]}]} {return}
set curunits [units list]
units microns noprint
set bval [${win} box values]
set bllx [expr {[lindex $bval 0] * $cr }]
set blly [expr {[lindex $bval 1] * $cr }]
set burx [expr {[lindex $bval 2] * $cr }]
set bury [expr {[lindex $bval 3] * $cr }]
set bllx [lindex $bval 0]
set blly [lindex $bval 1]
set burx [lindex $bval 2]
set bury [lindex $bval 3]
if {[expr {$bllx == int($bllx)}]} {set bllx [expr {int($bllx)}]}
if {[expr {$blly == int($blly)}]} {set blly [expr {int($blly)}]}
if {[expr {$burx == int($burx)}]} {set burx [expr {int($burx)}]}
if {[expr {$bury == int($bury)}]} {set bury [expr {int($bury)}]}
set titletext [format "box (%+g %+g) to (%+g %+g) microns" \
$bllx $blly $burx $bury]
units {*}$curunits
${framename}.titlebar.pos configure -text $titletext
}
}
@ -672,37 +675,30 @@ proc magic::cursorview {win} {
}
*bypass logcommands suspend
set framename [winfo parent $win]
if {[catch {set cr [*bypass cif scale out]}]} {
*bypass logcommands resume
return
}
if {$cr == 0} {return}
set olst [${win} cursor internal]
set olst [${win} cursor microns]
set olstx [lindex $olst 0]
set olsty [lindex $olst 1]
if {$Opts(crosshair)} {
*bypass crosshair ${olstx}i ${olsty}i
*bypass crosshair ${olstx}um ${olsty}um
}
# Use catch, because occasionally this fails on startup
if {[catch {
set olstx [expr {$olstx * $cr}]
set olsty [expr {$olsty * $cr}]
}]} {
*bypass logcommands resume
return
}
if {[${win} box exists]} {
# I do not know why the T/F result gets lost or overridden sometimes
set gotbox [${win} box exists]
if {$gotbox == {}} {set gotbox false}
if {$gotbox} {
set curunits [${win} units list]
${win} units microns noprint
set dlst [${win} box position]
set dx [expr {$olstx - ([lindex $dlst 0]) * $cr }]
set dy [expr {$olsty - ([lindex $dlst 1]) * $cr }]
set dx [expr {$olstx - [lindex $dlst 0]}]
set dy [expr {$olsty - [lindex $dlst 1]}]
if {[expr {$dx == int($dx)}]} {set dx [expr {int($dx)}]}
if {[expr {$dy == int($dy)}]} {set dy [expr {int($dy)}]}
set titletext [format "(%+g %+g) %+g %+g microns" $olstx $olsty $dx $dy]
${framename}.titlebar.pos configure -text $titletext
${win} units {*}$curunits
} else {
set titletext [format "(%+g %+g) microns" $olstx $olsty]
${framename}.titlebar.pos configure -text $titletext
@ -832,8 +828,11 @@ proc magic::setscrollvalues {win} {
global Opts
*bypass logcommands suspend
set curunits [units list]
units internal noprint
set svalues [${win} view get]
set bvalues [${win} view bbox]
units {*}$curunits
set framename [winfo parent ${win}]
if {$framename == "."} {
@ -910,8 +909,11 @@ proc magic::scrollview { w win orient } {
set v2 $scale($orient,update)
set delta [expr {$v2 - $v1}]
set curunits [units list]
units internal noprint
set bvalues [${win} view bbox]
set wvalues [${win} windowpositions]
units {*}$curunits
# Note that adding 0.000 in expression forces floating-point
@ -1187,8 +1189,12 @@ proc magic::openwrapper {{cell ""} {framename ""}} {
bind ${winname} <Motion> "*bypass setpoint %x %y ${winname}; \
magic::cursorview ${winname}"
set Winopts(${framename},toolbar) 1
set Winopts(${framename},cmdentry) 0
if {[catch {set Winopts(${framename},toolbar)}]} {
set Winopts(${framename},toolbar) 1
}
if {[catch {set Winopts(${framename},cmdentry)}]} {
set Winopts(${framename},cmdentry) $Opts(cmdentry)
}
# #################################
# File
@ -1294,7 +1300,17 @@ proc magic::openwrapper {{cell ""} {framename ""}} {
$m add command -label "Grid off" -command {magic::grid off}
$m add command -label "Snap-to-grid on" -command {magic::snap on}
$m add command -label "Snap-to-grid off" -command {magic::snap off}
$m add command -label "Measure box" -command {magic::box }
$m add command -label "Measure box" -command {magic::box}
$m add separator
$m add command -label "Report internal units" -command {magic::units internal}
$m add command -label "Report lambda units" -command {magic::units lambda}
$m add command -label "Report micron units" -command {magic::units microns}
$m add command -label "Report grid units" -command {magic::units grid}
$m add check -label "Display units" -variable Opts(printunits) \
-command [subst {if { \$Opts(printunits) } { \
magic::units print } else { magic::units noprint } }]
$m add separator
$m add command -label "Set grid 0.05um" -command {magic::grid 0.05um}
$m add command -label "Set grid 0.10um" -command {magic::grid 0.10um}
@ -1425,6 +1441,11 @@ proc magic::openwrapper {{cell ""} {framename ""}} {
grid ${layoutframe}.toolbar -row 1 -column 2 -rowspan 2 -sticky new
}
# If the command entry window is enabled, create it now
if { $Winopts(${framename},cmdentry) == 1} {
addcommandentry $framename
}
# Remove "open" and "close" macros so they don't generate non-GUI
# windows or (worse) blow away the window inside the GUI frame

View File

@ -210,7 +210,7 @@ RunStatsRealTime(void)
while (inct >= 10) { inct -= 10; incs++; }
while (incs >= 60) { incs -= 60; incm++; }
sprintf(buf, "%ld:%02ld.%ld %ld:%02ld.%ld",
snprintf(buf, (size_t)50, "%ld:%02ld.%ld %ld:%02ld.%ld",
totm, tots, tott, incm, incs, inct);
lasttime = curtime;

View File

@ -432,7 +432,8 @@ TechLoad(filename, initmask)
char suffix[20], line[MAXLINESIZE], *realname;
char *argv[MAXARGS];
SectionID mask, badMask;
int argc, s;
int argc, s, repeatcount = 0;
off_t repeatpos;
bool retval, skip;
filestack *fstack, *newstack;
filestack topfile;
@ -603,6 +604,33 @@ TechLoad(filename, initmask)
skip = FALSE;
while ((argc = techGetTokens(line, sizeof line, &fstack, argv)) >= 0)
{
/* Check for end-of-loop */
if ((argc == 1) && (!strcmp(argv[0], "endrepeat")))
{
if (repeatcount > 0)
{
repeatcount--;
fseek(fstack->file, repeatpos, SEEK_SET);
}
continue;
}
/* "repeat <number>" reads the lines until "endrepeat" <number> times */
else if ((argc == 2) && (!strcmp(argv[0], "repeat")))
{
if (!StrIsInt(argv[1]))
{
TechError("Error: \"repeat\" with invalid count %s\n", argv[1]);
repeatcount = 0;
}
else
{
repeatcount = atoi(argv[1]) - 1;
repeatpos = ftell(fstack->file);
}
continue;
}
/* Check for file inclusions (can be nested) */
if ((argc > 1) && (!strcmp(argv[0], "include")))
{

View File

@ -440,23 +440,52 @@ windCrashCmd(w, cmd)
* Side effects:
* Prints coordinates (non-Tcl version)
* Return value set to the cursor position as a list (Tcl version)
*
* NOTE: "box position {*}[cursor]" will produce the wrong result if
* "units" have been left as default, because "cursor" will generate
* internal values and "box position" will expect lambda values. Use
* "box move bl cursor" instead.
* ----------------------------------------------------------------------------
*/
#define CURSOR_INTERNAL 0
#define CURSOR_LAMBDA 1
#define CURSOR_USER 2
#define CURSOR_GRID 3
#define CURSOR_MICRONS 4
#define CURSOR_WINDOW 5
#define CURSOR_SCREEN 6
void
windCursorCmd(w, cmd)
MagWindow *w;
TxCommand *cmd;
{
Point p_in, p_out;
int resulttype = DBW_SNAP_INTERNAL;
int resulttype, saveunits, idx;
double cursx, cursy, oscale;
char *dispx, *dispy;
DBWclientRec *crec;
#ifdef MAGIC_WRAPPER
Tcl_Obj *listxy;
#endif
static const char * const cmdCursorOption[] =
{ "internal", "lambda", "user", "grid", "microns", "window", "screen",
"units", 0 };
/* The original behavior was to use internal
* units by default. This remains the case
* unless units are set with the "units"
* command, in which case units follow the
* specified units.
*/
if (DBWUnits == DBW_UNITS_DEFAULT)
resulttype = DBW_UNITS_INTERNAL;
else
resulttype = DBWUnits;
if (cmd->tx_argc == 2)
{
if (StrIsInt(cmd->tx_argv[1]))
@ -465,31 +494,35 @@ windCursorCmd(w, cmd)
(*GrSetCursorPtr)(atoi(cmd->tx_argv[1]));
return;
}
else if (*cmd->tx_argv[1] == 'l')
{
resulttype = DBW_SNAP_LAMBDA;
}
else if (*cmd->tx_argv[1] == 'u')
{
resulttype = DBW_SNAP_USER;
}
else if (*cmd->tx_argv[1] == 'm')
{
resulttype = DBW_SNAP_MICRONS;
}
else if (*cmd->tx_argv[1] == 'w')
{
resulttype = -1; // Use this value for "window"
}
else if (*cmd->tx_argv[1] == 's')
{
resulttype = -2; // Use this value for "screen"
}
else if (*cmd->tx_argv[1] != 'i')
{
TxError("Usage: cursor glyphnum\n");
TxError(" (or): cursor [internal | lambda | microns | user | window]\n");
return;
else {
idx = Lookup(cmd->tx_argv[1], cmdCursorOption);
switch (idx)
{
case CURSOR_INTERNAL:
resulttype = DBW_UNITS_INTERNAL;
break;
case CURSOR_LAMBDA:
resulttype = DBW_UNITS_LAMBDA;
break;
case CURSOR_USER:
case CURSOR_GRID:
resulttype = DBW_UNITS_USER;
break;
case CURSOR_MICRONS:
resulttype = DBW_UNITS_MICRONS;
break;
case CURSOR_WINDOW:
resulttype = -1; // Use this value for "window"
break;
case CURSOR_SCREEN:
resulttype = -2; // Use this value for "screen"
break;
default:
TxError("Usage: cursor glyphnum\n");
TxError(" (or): cursor [internal | lambda | microns | user"
" | window | units]\n");
return;
}
}
}
@ -506,54 +539,37 @@ windCursorCmd(w, cmd)
WindPointToSurface(w, &p_in, &p_out, (Rect *)NULL);
/* Snap the cursor position if snap is in effect */
if (DBWSnapToGrid != DBW_SNAP_INTERNAL)
if (DBWSnapToGrid != DBW_UNITS_INTERNAL)
ToolSnapToGrid(w, &p_out, (Rect *)NULL);
}
/* Transform the result to declared units with option "lambda" or "grid" */
switch (resulttype) {
case -2:
case -1:
cursx = (double)p_in.p_x;
cursy = (double)p_in.p_y;
break;
case DBW_SNAP_INTERNAL:
cursx = (double)p_out.p_x;
cursy = (double)p_out.p_y;
break;
case DBW_SNAP_LAMBDA:
cursx = (double)(p_out.p_x * DBLambda[0]) / (double)DBLambda[1];
cursy = (double)(p_out.p_y * DBLambda[0]) / (double)DBLambda[1];
break;
case DBW_SNAP_MICRONS:
oscale = (double)CIFGetOutputScale(1000);
cursx = (double)(p_out.p_x * oscale);
cursy = (double)(p_out.p_y * oscale);
break;
case DBW_SNAP_USER:
crec = (DBWclientRec *)w->w_clientData;
cursx = (double)((p_out.p_x - crec->dbw_gridRect.r_xbot)
/ (crec->dbw_gridRect.r_xtop - crec->dbw_gridRect.r_xbot));
cursy = (double)((p_out.p_y - crec->dbw_gridRect.r_ybot)
/ (crec->dbw_gridRect.r_ytop - crec->dbw_gridRect.r_ybot));
break;
}
#ifdef MAGIC_WRAPPER
listxy = Tcl_NewListObj(0, NULL);
if ((cursx == round(cursx)) && (cursy == round(cursy)))
saveunits = DBWUnits;
if (resulttype < 0)
{
Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewIntObj((int)cursx));
Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewIntObj((int)cursy));
/* Not really internal units, but that prints integer units verbatim */
DBWUnits = DBW_UNITS_INTERNAL;
cursx = (double)p_in.p_x;
cursy = (double)p_in.p_y;
}
else
{
Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewDoubleObj(cursx));
Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewDoubleObj(cursy));
DBWUnits = resulttype;
cursx = (double)p_out.p_x;
cursy = (double)p_out.p_y;
}
dispx = DBWPrintValue(cursx, w, TRUE);
dispy = DBWPrintValue(cursy, w, FALSE);
DBWUnits = saveunits;
#ifdef MAGIC_WRAPPER
listxy = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewStringObj(dispx, -1));
Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_NewStringObj(dispy, -1));
Tcl_SetObjResult(magicinterp, listxy);
#else
TxPrintf("%g %g\n", cursx, cursy);
TxPrintf("%s %s\n", dispx, dispy);
#endif
}

Some files were not shown because too many files have changed in this diff Show More