Compare commits

..

86 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
R. Timothy Edwards 4d9c7fd7d7 Corrected an inadvertent error in ResMakeRes.c introduced in a
recent commit, and fixed a more long-standing error in ext2spice.c
where a nodeClient structure was initialized to the wrong type.
2026-01-21 14:26:15 -05:00
R. Timothy Edwards a55ec49434 Corrected a callback function call in the router code which was
made outside of a search routine and so needed to have a "dinfo"
argument added.
2026-01-20 15:56:50 -05:00
R. Timothy Edwards c0dbb2067b Corrected an error in "extresist" that can cause a segfault which
is unrelated to recent code changes, and also corrected a bunch
of code to (somewhat) more properly handle non-Manhattan geometry.
2026-01-20 12:59:36 -05:00
R. Timothy Edwards b59708e27a Updating the version number after merging in work done in a
separate branch.  This completes the work preventing magic from
altering tile record contents during a basic search, but also
corrects W and L calculations for non-Manhattan geometry, and
a number of other corrections detailed in the branch's commit
messages.
2026-01-19 17:41:22 -05:00
R. Timothy Edwards c0c5e1b5bf Last set of changes to get non-Manhattan area and perimeter
device extraction working, and also resolved an unrelated error
in "getnode" and another unrelated error reading "resist" values
from the tech file "extract" section.
2026-01-19 17:18:10 -05:00
R. Timothy Edwards 3de9ed9cbf More updates. . . Got it to the point were gpio_ovtv2 is LVS
clean, which has never happened before.
2026-01-17 20:49:52 -05:00
R. Timothy Edwards 846c8e0f65 Additional changes; fixed some of the most problematic issues
involving searches on split tile areas, including one very
important check for interaction between split tiles during
hierarchical extraction.  There is still something wrong in
the hierarchical extraction, but it could be the last remaining
issue.
2026-01-15 21:35:46 -05:00
R. Timothy Edwards 8bd01f5597 Additional work to incorporate handling of split tiles throughout
the extraction, especially for routines like ExtFindNeighbors where
it was previously not handled at all.  A new method was introduced
in which split tiles with neither side TT_SPACE will get an extra
allocated structure that contains pointers to two regions representing
the nodes on the tile's left and right sides, independently.  The fix
(as yet not fully tested) should resolve problems with extracting the
sky130 I/O cells, which contain a FET with 45 degree angles on the
gate, where a split tile is divided between the gate and the source or
drain, and therefore represents two different nodes.  Also, there were
extraction errors related to incorrect handling of split tiles having
only one node, where a split tile became connected to the wrong node.
2026-01-09 12:05:03 -05:00
R. Timothy Edwards 1cb58e973a Committing changes to date, which includes a number of fixes,
especially around the extraction code.  Extraction is now
more or less working, although the original known issues
around areas where split tiles contain two regions has not
yet been addressed.
2026-01-09 12:05:03 -05:00
R. Timothy Edwards 516c9d7635 First cut of pulling the TT_SIDE bit out of the tile database
and forcing it to be passed as an argument to all the callback
functions for the search routines that require it.  Magic now
compiles and runs with the new code, but there are a number of
known issues that need to be fixed up.  Committing now so that
I can rebase on the last update to the master branch.
2026-01-09 12:05:03 -05:00
R. Timothy Edwards d24d52e403 Corrected an error in EFbuild.c in routine efBuildDevice(), which
had one error and one missing method.  The error was an incorrect
argument count for regular (not subcircuit) FETs and BJTs.  The
missing method was to handle parameters w0, w1, w2, etc., like
l0, l1, l2, . . .   Those had been defined for output in ExtBasic.c
but were not being handled on input from the .ext file.  This fix
corresponds more or less to PR #480 on github, although that PR
incorrectly addressed the argument numbering problem, so I have
redone the code changes by hand.
2026-01-09 11:51:11 -05:00
R. Timothy Edwards a93d248a5a Removed some diagnostic print lines that had been used for
debugging the problem that was corrected in the December 29
commit, and which had inadvertently been left in the code.
2026-01-05 16:56:05 -05:00
R. Timothy Edwards 4ccd5a78d1 Corrected a couple of lines in the paint code that had been
improperly messed with during a commit back in August.  At the
time I was unsure of what to do with those lines, but now I'm
quite sure they were correct to have been commented out.  I
have now removed them so that they should not cause trouble in
the future.  Quick explanation:  After a non-Manhattan tile
4-way split, merging should be done to the left conditionally
on the merge flags (the latter part of that being the August
1 fix), but merging should never be done to the right because
the right side is still fractured and has yet to be visited.
The merging will eventually get handled.  Whether the merge
flag has been set or not does not matter.
2026-01-02 19:54:08 -05:00
172 changed files with 10762 additions and 6944 deletions

View File

@ -1 +1 @@
8.3.587 8.3.625

View File

@ -53,6 +53,7 @@ int calmaNonManhattan;
int CalmaFlattenLimit = 10; int CalmaFlattenLimit = 10;
int NameConvertErrors = 0; int NameConvertErrors = 0;
bool CalmaRewound = FALSE; bool CalmaRewound = FALSE;
bool CalmaRecordPaths = FALSE;
TileTypeBitMask *CalmaMaskHints = NULL; TileTypeBitMask *CalmaMaskHints = NULL;
extern HashTable calmaDefInitHash; extern HashTable calmaDefInitHash;
@ -245,7 +246,9 @@ calmaExact(void)
int pNum; int pNum;
Plane *newplane; Plane *newplane;
Plane **parray; Plane **parray;
int gdsCopyPaintFunc(Tile *tile, GDSCopyRec *gdsCopyRec); /* Forward reference */
/* Forward reference */
int gdsCopyPaintFunc(Tile *tile, TileType dinfo, GDSCopyRec *gdsCopyRec);
parray = (Plane **)mallocMagic(MAXCIFRLAYERS * sizeof(Plane *)); parray = (Plane **)mallocMagic(MAXCIFRLAYERS * sizeof(Plane *));
@ -503,28 +506,33 @@ calmaParseStructure(
if (CalmaReadOnly || predefined) if (CalmaReadOnly || predefined)
{ {
PropertyRecord *proprec;
char cstring[1024]; 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 */ /* Substitute variable for PDK path or ~ for home directory */
/* the same way that cell references are handled in .mag files. */ /* the same way that cell references are handled in .mag files. */
DBPathSubstitute(filename, cstring, cifReadCellDef); 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); 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) if (predefined)
{ {
@ -751,6 +759,7 @@ calmaParseElement(
int int
calmaEnumFunc( calmaEnumFunc(
Tile *tile, Tile *tile,
TileType dinfo,
int *plane) int *plane)
{ {
return 1; return 1;
@ -780,8 +789,8 @@ calmaElementSref(
char *filename) char *filename)
{ {
int nbytes, rtype, cols, rows, nref, n, i, savescale; int nbytes, rtype, cols, rows, nref, n, i, savescale;
int xlo, ylo, xhi, yhi, xsep, ysep; int xlo, ylo, xhi, yhi, xsep, ysep, angle;
bool madeinst = FALSE; bool madeinst = FALSE, rotated = FALSE;
char *sname = NULL; char *sname = NULL;
bool isArray = FALSE; bool isArray = FALSE;
bool dolookahead = FALSE; bool dolookahead = FALSE;
@ -789,12 +798,13 @@ calmaElementSref(
Point refarray[3], refunscaled[3], p; Point refarray[3], refunscaled[3], p;
CellUse *use; CellUse *use;
CellDef *def; CellDef *def;
int gdsCopyPaintFunc(Tile *tile, GDSCopyRec *gdsCopyRec); /* Forward reference */
int gdsHasUses(CellUse *use, ClientData clientdata); /* Forward reference */
/* Added by NP */
char *useid = NULL, *arraystr = NULL; char *useid = NULL, *arraystr = NULL;
int propAttrType; int propAttrType;
/* Forward reference */
int gdsCopyPaintFunc(Tile *tile, TileType dinfo, GDSCopyRec *gdsCopyRec);
int gdsHasUses(CellUse *use, ClientData clientdata);
/* Skip CALMA_ELFLAGS, CALMA_PLEX */ /* Skip CALMA_ELFLAGS, CALMA_PLEX */
calmaSkipSet(calmaElementIgnore); calmaSkipSet(calmaElementIgnore);
@ -980,17 +990,73 @@ calmaElementSref(
refarray[2].p_x = refarray[2].p_y = 0; 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 /* If this is a cell reference, then we scale to magic coordinates
* and place the cell in the magic database. However, if this is * 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 * a cell to be flattened a la "gds flatten", then we keep the GDS
* coordinates, and don't scale to the magic database. * 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++) for (n = 0; n < nref; n++)
{ {
savescale = cifCurReadStyle->crs_scaleFactor; 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); refarray[n].p_x = CIFScaleCoord(refarray[n].p_x, COORD_EXACT);
if (savescale != cifCurReadStyle->crs_scaleFactor) if (savescale != cifCurReadStyle->crs_scaleFactor)
{ {
@ -1011,9 +1077,6 @@ calmaElementSref(
} }
refarray[n].p_x *= (savescale / cifCurReadStyle->crs_scaleFactor); refarray[n].p_x *= (savescale / cifCurReadStyle->crs_scaleFactor);
} }
if (FEOF(calmaInputFile))
return -1;
} }
/* Skip remainder */ /* Skip remainder */
@ -1289,27 +1352,28 @@ gdsHasUses(
int int
gdsCopyPaintFunc( gdsCopyPaintFunc(
Tile *tile, Tile *tile,
TileType dinfo,
GDSCopyRec *gdsCopyRec) GDSCopyRec *gdsCopyRec)
{ {
int pNum; int pNum;
TileType dinfo; TileType newdinfo;
Rect sourceRect, targetRect; Rect sourceRect, targetRect;
Transform *trans = gdsCopyRec->trans; Transform *trans = gdsCopyRec->trans;
Plane *plane = gdsCopyRec->plane; Plane *plane = gdsCopyRec->plane;
dinfo = TiGetTypeExact(tile); newdinfo = TiGetTypeExact(tile) | dinfo;
if (trans) if (trans)
{ {
TiToRect(tile, &sourceRect); TiToRect(tile, &sourceRect);
GeoTransRect(trans, &sourceRect, &targetRect); GeoTransRect(trans, &sourceRect, &targetRect);
if (IsSplit(tile)) if (IsSplit(tile))
dinfo = DBTransformDiagonal(TiGetTypeExact(tile), trans); newdinfo = DBTransformDiagonal(TiGetTypeExact(tile) | dinfo, trans);
} }
else else
TiToRect(tile, &targetRect); TiToRect(tile, &targetRect);
DBNMPaintPlane(plane, dinfo, &targetRect, CIFPaintTable, DBNMPaintPlane(plane, newdinfo, &targetRect, CIFPaintTable,
(PaintUndoInfo *)NULL); (PaintUndoInfo *)NULL);
return 0; return 0;

View File

@ -114,6 +114,8 @@ calmaInputRescale(
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
* calmaReadX ---
* calmaReadY ---
* calmaReadPoint --- * calmaReadPoint ---
* *
* Read a point from the input. * Read a point from the input.
@ -132,11 +134,17 @@ calmaInputRescale(
* encountered, then everything in the GDS planes is rescaled * encountered, then everything in the GDS planes is rescaled
* to match. * 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 void
calmaReadPoint( calmaReadX(
Point *p, Point *p,
int iscale) int iscale)
{ {
@ -163,6 +171,15 @@ calmaReadPoint(
} }
} }
p->p_x /= calmaReadScale2; p->p_x /= calmaReadScale2;
}
void
calmaReadY(
Point *p,
int iscale)
{
int rescale;
READI4((p)->p_y); READI4((p)->p_y);
p->p_y *= (calmaReadScale1 * iscale); p->p_y *= (calmaReadScale1 * iscale);
@ -188,6 +205,15 @@ calmaReadPoint(
p->p_y /= calmaReadScale2; 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, CIFPaintWirePath(pathheadp, width,
(pathtype == CALMAPATH_SQUAREFLUSH || pathtype == CALMAPATH_CUSTOM) ? (pathtype == CALMAPATH_SQUAREFLUSH || pathtype == CALMAPATH_CUSTOM) ?
FALSE : TRUE, plane, CIFPaintTable, (PaintUndoInfo *)NULL); FALSE : TRUE, plane, CIFPaintTable, (PaintUndoInfo *)NULL);

View File

@ -97,10 +97,10 @@ typedef struct {
/* Forward declarations */ /* Forward declarations */
extern int calmaWriteInitFunc(CellDef *def); extern int calmaWriteInitFunc(CellDef *def);
extern int calmaWritePaintFunc(Tile *tile, calmaOutputStruct *cos); extern int calmaWritePaintFunc(Tile *tile, TileType dinfo, calmaOutputStruct *cos);
extern int calmaMergePaintFunc(Tile *tile, calmaOutputStruct *cos); extern int calmaMergePaintFunc(Tile *tile, TileType dinfo, calmaOutputStruct *cos);
extern int calmaWriteUseFunc(CellUse *use, FILE *f); extern int calmaWriteUseFunc(CellUse *use, FILE *f);
extern int calmaPaintLabelFunc(Tile *tile, calmaOutputStruct *cos); extern int calmaPaintLabelFunc(Tile *tile, TileType dinfo, calmaOutputStruct *cos);
extern void calmaWriteContacts(FILE *f); extern void calmaWriteContacts(FILE *f);
extern void calmaDelContacts(void); extern void calmaDelContacts(void);
extern void calmaOutFunc(CellDef *def, FILE *f, const Rect *cliprect); extern void calmaOutFunc(CellDef *def, FILE *f, const Rect *cliprect);
@ -528,7 +528,7 @@ calmaDumpStructure(
/* Is view abstract? */ /* Is view abstract? */
DBPropGet(edef, "LEFview", &isAbstract); DBPropGet(edef, "LEFview", &isAbstract);
chklibname = (char *)DBPropGet(edef, "GDS_FILE", &isReadOnly); chklibname = DBPropGetString(edef, "GDS_FILE", &isReadOnly);
if (isAbstract && isReadOnly) if (isAbstract && isReadOnly)
{ {
@ -738,7 +738,7 @@ calmaFullDump(
* names in the GDS file do not shadow any names in the database. * 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"))) if ((!isAbstract) || (strcasecmp(viewopts, "no_prefix")))
{ {
/* Generate a SHORT name for this cell (else it is easy to run into the /* 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, "GDS_END", &hasGDSEnd);
DBPropGet(def, "CIFhier", &needHier); 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 */ /* When used with "calma addendum true", don't output the read-only */
/* cells. This makes the library incomplete and dependent on the */ /* cells. This makes the library incomplete and dependent on the */
@ -1033,13 +1033,12 @@ calmaProcessDef(
} }
else else
{ {
offptr = (char *)DBPropGet(def, "GDS_END", NULL); cval = DBPropGetDouble(def, "GDS_END", NULL);
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
cellend = (off_t)cval; cellend = (off_t)cval;
offptr = (char *)DBPropGet(def, "GDS_BEGIN", &oldStyle); cval = DBPropGetDouble(def, "GDS_BEGIN", &oldStyle);
if (!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 */ /* Write our own header and string name, to ensure */
/* that the magic cell name and GDS name match. */ /* that the magic cell name and GDS name match. */
@ -1056,7 +1055,6 @@ calmaProcessDef(
calmaOutStructName(CALMA_STRNAME, def, outf); calmaOutStructName(CALMA_STRNAME, def, outf);
} }
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
cellstart = (off_t)cval; cellstart = (off_t)cval;
/* GDS_START has been defined as the start of data after the cell */ /* GDS_START has been defined as the start of data after the cell */
@ -1263,7 +1261,7 @@ calmaOutFunc(
int dbunits; int dbunits;
calmaOutputStruct cos; calmaOutputStruct cos;
bool propfound; bool propfound;
char *propvalue; PropertyRecord *proprec;
cos.f = f; cos.f = f;
cos.area = (cliprect == &TiPlaneRect) ? NULL : cliprect; cos.area = (cliprect == &TiPlaneRect) ? NULL : cliprect;
@ -1323,14 +1321,20 @@ calmaOutFunc(
/* Include any fixed bounding box as part of the area to process, */ /* Include any fixed bounding box as part of the area to process, */
/* in case the fixed bounding box is larger than the geometry. */ /* 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) if (propfound)
{ {
Rect bbox; Rect bbox;
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot, if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
&bbox.r_xtop, &bbox.r_ytop) == 4) (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); GeoInclude(&bbox, &bigArea);
}
} }
CIFErrorDef = def; CIFErrorDef = def;
@ -2464,6 +2468,7 @@ calmaProcessBoundary(
int int
calmaMergePaintFunc( calmaMergePaintFunc(
Tile *tile, /* Tile to be written out. */ Tile *tile, /* Tile to be written out. */
TileType dinfo, /* Split tile information (unused) */
calmaOutputStruct *cos) /* Information needed by algorithm */ calmaOutputStruct *cos) /* Information needed by algorithm */
{ {
FILE *f = cos->f; FILE *f = cos->f;
@ -2494,11 +2499,10 @@ calmaMergePaintFunc(
split_type = -1; split_type = -1;
if (IsSplit(t)) if (IsSplit(t))
{ {
/* If we use SplitSide, then we need to set it when the */ /* If we use TT_SIDE, then we need to set it when the */
/* tile is pushed. Since these are one-or-zero mask layers */ /* tile is pushed. Since these are one-or-zero mask layers */
/* I assume it is okay to just check which side is TT_SPACE */ /* I assume it is okay to just check which side is TT_SPACE */
/* split_type = (SplitSide(t) << 1) | SplitDirection(t); */
split_type = SplitDirection(t); split_type = SplitDirection(t);
if (TiGetLeftType(t) == TT_SPACE) split_type |= 2; if (TiGetLeftType(t) == TT_SPACE) split_type |= 2;
num_points = 2; num_points = 2;
@ -2721,7 +2725,9 @@ right_search:
done_searches: done_searches:
if (intedges == 0) if (intedges == 0)
{ {
calmaWritePaintFunc(t, cos); calmaWritePaintFunc(t,
(split_type & 2) ? (TileType)TT_SIDE : (TileType)0,
cos);
/* Although calmaWritePaintFunc is called only on isolated */ /* Although calmaWritePaintFunc is called only on isolated */
/* tiles, we may have expanded it. This could use a LOT of */ /* tiles, we may have expanded it. This could use a LOT of */
@ -2791,6 +2797,7 @@ done_searches:
int int
calmaWritePaintFunc( calmaWritePaintFunc(
Tile *tile, /* Tile to be written out. */ Tile *tile, /* Tile to be written out. */
TileType dinfo, /* Split tile information */
calmaOutputStruct *cos) /* File for output and clipping area */ calmaOutputStruct *cos) /* File for output and clipping area */
{ {
FILE *f = cos->f; FILE *f = cos->f;
@ -2826,7 +2833,7 @@ calmaWritePaintFunc(
/* Coordinates */ /* Coordinates */
calmaOutRH(36, CALMA_XY, CALMA_I4, f); calmaOutRH(36, CALMA_XY, CALMA_I4, f);
switch ((SplitSide(tile) << 1) | SplitDirection(tile)) switch (((dinfo & TT_SIDE) ? 2 : 0) | SplitDirection(tile))
{ {
case 0x0: case 0x0:
calmaOutI4(r.r_xbot, f); calmaOutI4(r.r_ybot, f); calmaOutI4(r.r_xbot, f); calmaOutI4(r.r_ybot, f);
@ -3067,6 +3074,7 @@ calmaWriteLabelFunc(
int int
calmaPaintLabelFunc( calmaPaintLabelFunc(
Tile *tile, /* Tile contains area for label. */ Tile *tile, /* Tile contains area for label. */
TileType dinfo, /* Split tile information (unused) */
calmaOutputStruct *cos) /* File for output and clipping area */ calmaOutputStruct *cos) /* File for output and clipping area */
{ {
FILE *f = cos->f; FILE *f = cos->f;

View File

@ -107,10 +107,10 @@ typedef struct {
} calmaOutputStructZ; } calmaOutputStructZ;
/* Forward declarations */ /* Forward declarations */
extern int calmaWritePaintFuncZ(Tile *tile, calmaOutputStructZ *cos); extern int calmaWritePaintFuncZ(Tile *tile, TileType dinfo, calmaOutputStructZ *cos);
extern int calmaMergePaintFuncZ(Tile *tile, calmaOutputStructZ *cos); extern int calmaMergePaintFuncZ(Tile *tile, TileType dinfo, calmaOutputStructZ *cos);
extern int calmaWriteUseFuncZ(CellUse *use, gzFile f); extern int calmaWriteUseFuncZ(CellUse *use, gzFile f);
extern int calmaPaintLabelFuncZ(Tile *tile, calmaOutputStructZ *cos); extern int calmaPaintLabelFuncZ(Tile *tile, TileType dinfo, calmaOutputStructZ *cos);
extern void calmaWriteContactsZ(gzFile f); extern void calmaWriteContactsZ(gzFile f);
extern void calmaOutFuncZ(CellDef *def, gzFile f, const Rect *cliprect); extern void calmaOutFuncZ(CellDef *def, gzFile f, const Rect *cliprect);
extern void calmaOutStructNameZ(int type, CellDef *def, gzFile f); extern void calmaOutStructNameZ(int type, CellDef *def, gzFile f);
@ -508,7 +508,7 @@ calmaDumpStructureZ(
/* Is view abstract? */ /* Is view abstract? */
DBPropGet(edef, "LEFview", &isAbstract); DBPropGet(edef, "LEFview", &isAbstract);
chklibname = (char *)DBPropGet(edef, "GDS_FILE", &isReadOnly); chklibname = DBPropGetString(edef, "GDS_FILE", &isReadOnly);
if (isAbstract && isReadOnly) if (isAbstract && isReadOnly)
{ {
@ -716,7 +716,7 @@ calmaFullDumpZ(
* names in the GDS file do not shadow any names in the database. * 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"))) if ((!isAbstract) || (strcasecmp(viewopts, "no_prefix")))
{ {
/* Generate a SHORT name for this cell (else it is easy to run into the /* 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_START", &hasContent);
DBPropGet(def, "GDS_END", &hasGDSEnd); DBPropGet(def, "GDS_END", &hasGDSEnd);
DBPropGet(def, "CIFhier", &needHier); 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 */ /* When used with "calma addendum true", don't output the read-only */
/* cells. This makes the library incomplete and dependent on the */ /* cells. This makes the library incomplete and dependent on the */
@ -985,13 +985,12 @@ calmaProcessDefZ(
} }
else else
{ {
offptr = (char *)DBPropGet(def, "GDS_END", NULL); cval = DBPropGetDouble(def, "GDS_END", NULL);
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
cellend = (z_off_t)cval; cellend = (z_off_t)cval;
offptr = (char *)DBPropGet(def, "GDS_BEGIN", &oldStyle); cval = DBPropGetDouble(def, "GDS_BEGIN", &oldStyle);
if (!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 */ /* Write our own header and string name, to ensure */
/* that the magic cell name and GDS name match. */ /* that the magic cell name and GDS name match. */
@ -1008,7 +1007,6 @@ calmaProcessDefZ(
calmaOutStructNameZ(CALMA_STRNAME, def, outf); calmaOutStructNameZ(CALMA_STRNAME, def, outf);
} }
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
cellstart = (z_off_t)cval; cellstart = (z_off_t)cval;
/* GDS_START has been defined as the start of data after the cell */ /* GDS_START has been defined as the start of data after the cell */
@ -1186,6 +1184,7 @@ calmaOutFuncZ(
int dbunits; int dbunits;
calmaOutputStructZ cos; calmaOutputStructZ cos;
bool propfound; bool propfound;
PropertyRecord *proprec;
char *propvalue; char *propvalue;
extern int compport(const void *one, const void *two); /* Forward declaration */ 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, */ /* Include any fixed bounding box as part of the area to process, */
/* in case the fixed bounding box is larger than the geometry. */ /* 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) if (propfound)
{ {
Rect bbox; Rect bbox;
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot, if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
&bbox.r_xtop, &bbox.r_ytop) == 4) (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); GeoInclude(&bbox, &bigArea);
}
} }
CIFErrorDef = def; CIFErrorDef = def;
@ -1899,6 +1904,7 @@ calmaProcessBoundaryZ(
int int
calmaMergePaintFuncZ( calmaMergePaintFuncZ(
Tile *tile, /* Tile to be written out. */ Tile *tile, /* Tile to be written out. */
TileType dinfo, /* Split tile information (unused) */
calmaOutputStructZ *cos) /* Information needed by algorithm */ calmaOutputStructZ *cos) /* Information needed by algorithm */
{ {
gzFile f = cos->f; gzFile f = cos->f;
@ -1929,11 +1935,10 @@ calmaMergePaintFuncZ(
split_type = -1; split_type = -1;
if (IsSplit(t)) if (IsSplit(t))
{ {
/* If we use SplitSide, then we need to set it when the */ /* If we use TT_SIDE, then we need to set it when the */
/* tile is pushed. Since these are one-or-zero mask layers */ /* tile is pushed. Since these are one-or-zero mask layers */
/* I assume it is okay to just check which side is TT_SPACE */ /* I assume it is okay to just check which side is TT_SPACE */
/* split_type = (SplitSide(t) << 1) | SplitDirection(t); */
split_type = SplitDirection(t); split_type = SplitDirection(t);
if (TiGetLeftType(t) == TT_SPACE) split_type |= 2; if (TiGetLeftType(t) == TT_SPACE) split_type |= 2;
num_points = 2; num_points = 2;
@ -2156,7 +2161,9 @@ right_search:
done_searches: done_searches:
if (intedges == 0) if (intedges == 0)
{ {
calmaWritePaintFuncZ(t, cos); calmaWritePaintFuncZ(t,
(split_type & 2) ? (TileType)TT_SIDE : (TileType)0,
cos);
/* Although calmaWritePaintFunc is called only on isolated */ /* Although calmaWritePaintFunc is called only on isolated */
/* tiles, we may have expanded it. This could use a LOT of */ /* tiles, we may have expanded it. This could use a LOT of */
@ -2226,6 +2233,7 @@ done_searches:
int int
calmaWritePaintFuncZ( calmaWritePaintFuncZ(
Tile *tile, /* Tile to be written out. */ Tile *tile, /* Tile to be written out. */
TileType dinfo, /* Split tile information */
calmaOutputStructZ *cos) /* File for output and clipping area */ calmaOutputStructZ *cos) /* File for output and clipping area */
{ {
gzFile f = cos->f; gzFile f = cos->f;
@ -2261,7 +2269,7 @@ calmaWritePaintFuncZ(
/* Coordinates */ /* Coordinates */
calmaOutRHZ(36, CALMA_XY, CALMA_I4, f); calmaOutRHZ(36, CALMA_XY, CALMA_I4, f);
switch ((SplitSide(tile) << 1) | SplitDirection(tile)) switch (((dinfo & TT_SIDE) ? 2 : 0) | SplitDirection(tile))
{ {
case 0x0: case 0x0:
calmaOutI4Z(r.r_xbot, f); calmaOutI4Z(r.r_ybot, f); calmaOutI4Z(r.r_xbot, f); calmaOutI4Z(r.r_ybot, f);
@ -2502,6 +2510,7 @@ calmaWriteLabelFuncZ(
int int
calmaPaintLabelFuncZ( calmaPaintLabelFuncZ(
Tile *tile, /* Tile contains area for label. */ Tile *tile, /* Tile contains area for label. */
TileType dinfo, /* Split tile information (unused) */
calmaOutputStructZ *cos) /* File for output and clipping area */ calmaOutputStructZ *cos) /* File for output and clipping area */
{ {
gzFile f = cos->f; gzFile f = cos->f;

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -209,52 +209,41 @@ typedef struct _maskHintsData
{ {
Transform *mh_trans; Transform *mh_trans;
CellDef *mh_def; CellDef *mh_def;
Plane *mh_plane;
} MaskHintsData; } MaskHintsData;
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
* cifMaskHints -- * cifCopyMaskHintFunc --
* *
* Copy a mask hint into a target cell by adding it to the * Callback function used by cifFlatMaskHints. Transforms a tile
* property list of the target cell. If the target cell already * from the original plane and paints it into the target plane,
* has the same mask hint key, then the mask hint value is * both of which are properties.
* appended to the property in the target cell def.
* *
* Returns: * Results:
* 0 to keep the search going. * Zero to keep the search going.
* *
* Side effects: * Side effects:
* Modifies properties of the target cell def. * Paints geometry into the target plane.
* *
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/* DEPRECATED */
int int
cifMaskHints( cifCopyMaskHintFunc(Tile *tile,
char *name, TileType dinfo,
char *value, ClientData cdata)
CellDef *targetDef)
{ {
char *propvalue, *newval; MaskHintsData *mhd = (MaskHintsData *)cdata;
bool propfound; Rect r, newr;
if (!strncmp(name, "MASKHINTS_", 10)) TiToRect(tile, &r);
{
/* Check if name exists already in the flattened cell */ /* Transform tile area to coordinates of mhd->mh_plane and paint */
propvalue = (char *)DBPropGet(targetDef, name, &propfound); GeoTransRect(mhd->mh_trans, &r, &newr);
if (propfound) DBPaintPlane(mhd->mh_plane, &newr, CIFPaintTable, (PaintUndoInfo *)NULL);
{
/* Append value to the property */
newval = mallocMagic(strlen(value) + strlen(propvalue) + 2);
sprintf(newval, "%s %s", propvalue, value);
}
else
newval = StrDup((char **)NULL, value);
DBPropPut(targetDef, name, newval);
}
return 0; return 0;
} }
@ -264,8 +253,8 @@ cifMaskHints(
* cifFlatMaskHints -- * cifFlatMaskHints --
* *
* Copy a mask hint into a flattened cell by transforming it into the * Copy a mask hint into a flattened cell by transforming it into the
* coordinate system of the flattened cell, and adding it to the * coordinate system of the flattened cell, and painting it into the
* property list of the flattened cell. * property plane of the flattened cell.
* *
* Returns: * Returns:
* 0 to keep the search going. * 0 to keep the search going.
@ -279,67 +268,40 @@ cifMaskHints(
int int
cifFlatMaskHints( cifFlatMaskHints(
char *name, char *name,
char *value, PropertyRecord *proprec,
MaskHintsData *mhd) MaskHintsData *mhd)
{ {
Rect r, newr; Rect r, newr;
char *vptr, *newval, *lastval, *propvalue; char *vptr, *newval, *lastval, *propvalue;
bool propfound; bool propfound;
int lastlen, numvals; int i, lastlen, numvals;
PropertyRecord *newproprec, *oldproprec;
Plane *plane;
if (!strncmp(name, "MASKHINTS_", 10)) 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 */ /* 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) if (propfound)
{ {
/* Append newval to the property */ ASSERT(oldproprec->prop_value.prop_type == PROPERTY_TYPE_PLANE,
lastval = newval; "cifFlatMaskHints");
newval = mallocMagic(strlen(lastval) + strlen(propvalue) + 2); plane = oldproprec->prop_value.prop_plane;
sprintf(newval, "%s %s", propvalue, lastval);
freeMagic(lastval);
} }
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; return 0;
} }
@ -350,9 +312,10 @@ cifFlatMaskHints(
* CIFCopyMaskHints -- * CIFCopyMaskHints --
* *
* Callback function to copy mask hints from one cell into another. * Callback function to copy mask hints from one cell into another.
* (Occasionally called as a standalone function, not as a callback.)
* *
* Results: * Results:
* None. * Return 0 to keep the search going.
* *
* Side effects: * Side effects:
* May modify properties in the target cell. * May modify properties in the target cell.
@ -360,7 +323,7 @@ cifFlatMaskHints(
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
void int
CIFCopyMaskHints( CIFCopyMaskHints(
SearchContext *scx, SearchContext *scx,
CellDef *targetDef) CellDef *targetDef)
@ -370,38 +333,9 @@ CIFCopyMaskHints(
CellDef *sourceDef = scx->scx_use->cu_def; CellDef *sourceDef = scx->scx_use->cu_def;
mhd.mh_trans = &scx->scx_trans; mhd.mh_trans = &scx->scx_trans;
mhd.mh_def = targetDef; mhd.mh_def = targetDef;
mhd.mh_plane = (Plane *)NULL;
DBPropEnum(sourceDef, cifFlatMaskHints, &mhd); 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; return 0;
} }
@ -433,15 +367,16 @@ cifHierCopyMaskHints(
int int
cifHierCopyFunc( cifHierCopyFunc(
Tile *tile, /* Pointer to tile to copy. */ Tile *tile, /* Pointer to tile to copy. */
TileType dinfo, /* Split tile information */
TreeContext *cxp) /* Describes context of search, including TreeContext *cxp) /* Describes context of search, including
* transform and client data. * transform and client data.
*/ */
{ {
TileType type = TiGetTypeExact(tile); TileType type = TiGetTypeExact(tile) | dinfo;
Rect sourceRect, targetRect; Rect sourceRect, targetRect;
int pNum; int pNum;
CellDef *def = (CellDef *) cxp->tc_filter->tf_arg; CellDef *def = (CellDef *) cxp->tc_filter->tf_arg;
int dinfo = 0; TileType newdinfo = 0;
/* Ignore tiles in vendor GDS, unless this is specifically */ /* Ignore tiles in vendor GDS, unless this is specifically */
/* overridden by the "see-vendor" option. */ /* overridden by the "see-vendor" option. */
@ -457,8 +392,8 @@ cifHierCopyFunc(
if (IsSplit(tile)) if (IsSplit(tile))
{ {
dinfo = DBTransformDiagonal(type, &cxp->tc_scx->scx_trans); newdinfo = DBTransformDiagonal(type, &cxp->tc_scx->scx_trans);
type = (SplitSide(tile)) ? SplitRightType(tile) : type = (dinfo & TT_SIDE) ? SplitRightType(tile) :
SplitLeftType(tile); SplitLeftType(tile);
} }
@ -473,7 +408,7 @@ cifHierCopyFunc(
{ {
if (DBPaintOnPlane(type, pNum)) if (DBPaintOnPlane(type, pNum))
{ {
DBNMPaintPlane(def->cd_planes[pNum], dinfo, &targetRect, DBNMPaintPlane(def->cd_planes[pNum], newdinfo, &targetRect,
DBStdPaintTbl(type, pNum), (PaintUndoInfo *) NULL); DBStdPaintTbl(type, pNum), (PaintUndoInfo *) NULL);
} }
} }
@ -525,7 +460,7 @@ cifHierCellFunc(
/* Flatten mask hints in the area of interest */ /* Flatten mask hints in the area of interest */
CIFCopyMaskHints(scx, CIFComponentDef); CIFCopyMaskHints(scx, CIFComponentDef);
DBTreeSrCells(&newscx, 0, cifHierCopyMaskHints, DBTreeSrCells(&newscx, 0, CIFCopyMaskHints,
(ClientData)CIFComponentDef); (ClientData)CIFComponentDef);
/* Set CIFErrorDef to NULL to ignore errors here... these will /* Set CIFErrorDef to NULL to ignore errors here... these will
@ -562,9 +497,11 @@ cifHierCellFunc(
int int
cifHierErrorFunc( cifHierErrorFunc(
Tile *tile, /* Tile that covers area it shouldn't. */ Tile *tile, /* Tile that covers area it shouldn't. */
TileType dinfo, /* Split tile information */
Rect *checkArea) /* Intersection of this and tile is error. */ Rect *checkArea) /* Intersection of this and tile is error. */
{ {
Rect area; Rect area;
bool side = (dinfo & TT_SIDE) ? TRUE : FALSE;
TiToRect(tile, &area); TiToRect(tile, &area);
@ -572,8 +509,8 @@ cifHierErrorFunc(
* space bounds the checkArea. * space bounds the checkArea.
*/ */
if (IsSplit(tile)) if (IsSplit(tile))
if (((area.r_xbot == checkArea->r_xbot) && !SplitSide(tile)) || if (((area.r_xbot == checkArea->r_xbot) && !side) ||
((area.r_xtop == checkArea->r_xtop) && SplitSide(tile))) ((area.r_xtop == checkArea->r_xtop) && side))
return 0; return 0;
GeoClip(&area, checkArea); GeoClip(&area, checkArea);
@ -604,6 +541,7 @@ cifHierErrorFunc(
int int
cifHierCheckFunc( cifHierCheckFunc(
Tile *tile, /* Tile containing CIF. */ Tile *tile, /* Tile containing CIF. */
TileType dinfo, /* Split tile information */
Plane *plane) /* Plane to check against and modify. */ Plane *plane) /* Plane to check against and modify. */
{ {
Rect area; Rect area;
@ -612,10 +550,10 @@ cifHierCheckFunc(
if (IsSplit(tile)) if (IsSplit(tile))
{ {
DBSrPaintNMArea((Tile *)NULL, plane, TiGetTypeExact(tile), DBSrPaintNMArea((Tile *)NULL, plane, TiGetTypeExact(tile) | dinfo,
&area, &DBSpaceBits, cifHierErrorFunc, (ClientData) &area); &area, &DBSpaceBits, cifHierErrorFunc, (ClientData) &area);
DBNMPaintPlane(plane, TiGetTypeExact(tile), &area, CIFEraseTable, DBNMPaintPlane(plane, TiGetTypeExact(tile) | dinfo, &area, CIFEraseTable,
(PaintUndoInfo *) NULL); (PaintUndoInfo *) NULL);
} }
else else
@ -651,6 +589,7 @@ cifHierCheckFunc(
int int
cifHierTempCheckFunc( cifHierTempCheckFunc(
Tile *tile, /* Tile containing CIF. */ Tile *tile, /* Tile containing CIF. */
TileType dinfo, /* Information about split tiles */
Plane *plane) /* Plane to check against and modify. */ Plane *plane) /* Plane to check against and modify. */
{ {
Rect area; Rect area;
@ -658,7 +597,7 @@ cifHierTempCheckFunc(
TiToRect(tile, &area); TiToRect(tile, &area);
if (IsSplit(tile)) if (IsSplit(tile))
DBNMPaintPlane(plane, TiGetTypeExact(tile), &area, CIFEraseTable, DBNMPaintPlane(plane, TiGetTypeExact(tile) | dinfo, &area, CIFEraseTable,
(PaintUndoInfo *) NULL); (PaintUndoInfo *) NULL);
else else
DBPaintPlane(plane, &area, CIFEraseTable, (PaintUndoInfo *) NULL); DBPaintPlane(plane, &area, CIFEraseTable, (PaintUndoInfo *) NULL);
@ -686,6 +625,7 @@ cifHierTempCheckFunc(
int int
cifHierPaintFunc( cifHierPaintFunc(
Tile *tile, Tile *tile,
TileType dinfo, /* Information about split tiles */
Plane *plane) /* Plane in which to paint CIF over tile's Plane *plane) /* Plane in which to paint CIF over tile's
* area. * area.
*/ */
@ -693,9 +633,9 @@ cifHierPaintFunc(
Rect area; Rect area;
TiToRect(tile, &area); TiToRect(tile, &area);
if (CIFCurStyle->cs_flags & CWF_GROW_SLIVERS) cifGrowSliver(tile, &area); if (CIFCurStyle->cs_flags & CWF_GROW_SLIVERS) cifGrowSliver(tile, dinfo, &area);
if (IsSplit(tile)) if (IsSplit(tile))
DBNMPaintPlane(plane, TiGetTypeExact(tile), &area, CIFPaintTable, DBNMPaintPlane(plane, TiGetTypeExact(tile) | dinfo, &area, CIFPaintTable,
(PaintUndoInfo *) NULL); (PaintUndoInfo *) NULL);
else else
DBPaintPlane(plane, &area, CIFPaintTable, (PaintUndoInfo *) NULL); DBPaintPlane(plane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
@ -848,7 +788,7 @@ CIFGenSubcells(
cifHierCopyFunc, (ClientData) CIFTotalDef); cifHierCopyFunc, (ClientData) CIFTotalDef);
/* Flatten mask hints in the area of interest */ /* Flatten mask hints in the area of interest */
CIFCopyMaskHints(&scx, CIFTotalDef); CIFCopyMaskHints(&scx, CIFTotalDef);
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints, DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFTotalDef); (ClientData)CIFTotalDef);
CIFErrorDef = def; CIFErrorDef = def;
@ -1026,14 +966,14 @@ cifHierElementFunc(
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0, (void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
cifHierCopyFunc, (ClientData) CIFTotalDef); cifHierCopyFunc, (ClientData) CIFTotalDef);
CIFCopyMaskHints(&scx, CIFTotalDef); CIFCopyMaskHints(&scx, CIFTotalDef);
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints, DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFTotalDef); (ClientData)CIFTotalDef);
DBCellClearDef(CIFComponentDef); DBCellClearDef(CIFComponentDef);
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0, (void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef); cifHierCopyFunc, (ClientData) CIFComponentDef);
CIFCopyMaskHints(&scx, CIFComponentDef); CIFCopyMaskHints(&scx, CIFComponentDef);
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints, DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFComponentDef); (ClientData)CIFComponentDef);
CIFErrorDef = (CellDef *) NULL; CIFErrorDef = (CellDef *) NULL;
@ -1067,6 +1007,7 @@ cifHierElementFunc(
int int
cifGrowSliver( cifGrowSliver(
Tile *tile, Tile *tile,
TileType dinfo, /* Split tile information, needs to be handled */
Rect *area) Rect *area)
{ {
int height, width, expand_up, expand_side; int height, width, expand_up, expand_side;
@ -1127,22 +1068,24 @@ cifGrowSliver(
int int
cifHierPaintArrayFunc( cifHierPaintArrayFunc(
Tile *tile) Tile *tile,
TileType dinfo,
ClientData clientdata) /* (unused) */
{ {
Rect area; Rect area;
int i, j, xbot, xtop; int i, j, xbot, xtop;
TiToRect(tile, &area); TiToRect(tile, &area);
if (CIFCurStyle->cs_flags & CWF_GROW_SLIVERS) cifGrowSliver(tile, &area); if (CIFCurStyle->cs_flags & CWF_GROW_SLIVERS) cifGrowSliver(tile, dinfo, &area);
xbot = area.r_xbot; xbot = area.r_xbot;
xtop = area.r_xtop; xtop = area.r_xtop;
for (i=0; i<cifHierYCount; i++) for (i=0; i<cifHierYCount; i++)
{ {
for (j=0; j<cifHierXCount; j++) for (j = 0; j < cifHierXCount; j++)
{ {
DBPaintPlane(cifHierCurPlane, &area, CIFPaintTable, DBNMPaintPlane(cifHierCurPlane, TiGetTypeExact(tile) | dinfo,
(PaintUndoInfo *) NULL); &area, CIFPaintTable, (PaintUndoInfo *) NULL);
CIFTileOps += 1; CIFTileOps++;
area.r_xbot += cifHierXSpacing; area.r_xbot += cifHierXSpacing;
area.r_xtop += cifHierXSpacing; area.r_xtop += cifHierXSpacing;
} }

View File

@ -145,6 +145,8 @@ typedef struct cifop
* CIFOP_BRIDGE - Added 6/11/20---Bridge across catecorner gaps * 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_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_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 #define CIFOP_AND 1
@ -172,6 +174,8 @@ typedef struct cifop
#define CIFOP_BRIDGE 23 #define CIFOP_BRIDGE 23
#define CIFOP_BRIDGELIM 24 #define CIFOP_BRIDGELIM 24
#define CIFOP_MASKHINTS 25 #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 */ /* Definitions of bit fields used in the value of co_client for CIFOP_INTERACT */
#define CIFOP_INT_NOT 0x1 /* Inverted sense (not interacting) */ #define CIFOP_INT_NOT 0x1 /* Inverted sense (not interacting) */
@ -335,10 +339,9 @@ extern void CIFClearPlanes(Plane **planes);
extern Plane *CIFGenLayer(CIFOp *op, const Rect *area, CellDef *cellDef, CellDef *origDef, Plane *temps[], extern Plane *CIFGenLayer(CIFOp *op, const Rect *area, CellDef *cellDef, CellDef *origDef, Plane *temps[],
bool hier, ClientData clientdata); bool hier, ClientData clientdata);
extern void CIFInitCells(void); extern void CIFInitCells(void);
extern int cifHierCopyFunc(Tile *tile, TreeContext *cxp); extern int cifHierCopyFunc(Tile *tile, TileType dinfo, TreeContext *cxp);
extern int cifHierCopyMaskHints(SearchContext *scx, ClientData clientData);
extern void CIFLoadStyle(char *stylename); extern void CIFLoadStyle(char *stylename);
extern void CIFCopyMaskHints(SearchContext *scx, CellDef *targetDef); extern int CIFCopyMaskHints(SearchContext *scx, CellDef *targetDef);
/* C99 compat */ /* C99 compat */
extern void CIFCoverageLayer(CellDef *rootDef, Rect *area, char *layer, bool dolist); extern void CIFCoverageLayer(CellDef *rootDef, Rect *area, char *layer, bool dolist);
@ -346,7 +349,7 @@ extern bool CIFWriteFlat(CellDef *rootDef, FILE *f);
extern void CIFScalePlanes(int scalen, int scaled, Plane **planearray); extern void CIFScalePlanes(int scalen, int scaled, Plane **planearray);
extern void CIFInputRescale(int n, int d); extern void CIFInputRescale(int n, int d);
extern int CIFScaleCoord(int cifCoord, int snap_type); extern int CIFScaleCoord(int cifCoord, int snap_type);
extern int cifGrowSliver(Tile *tile, Rect *area); extern int cifGrowSliver(Tile *tile, TileType dinfo, Rect *area);
extern int cifHierElementFunc(CellUse *use, Transform *transform, int x, int y, Rect *checkArea); extern int cifHierElementFunc(CellUse *use, Transform *transform, int x, int y, Rect *checkArea);
extern int cifSquareFunc(Rect *area, CIFOp *op, int *rows, int *columns, Rect *cut); extern int cifSquareFunc(Rect *area, CIFOp *op, int *rows, int *columns, Rect *cut);
extern int cifSquareGridFunc(Rect *area, CIFOp *op, int *rows, int *columns, Rect *cut); extern int cifSquareGridFunc(Rect *area, CIFOp *op, int *rows, int *columns, Rect *cut);

View File

@ -505,6 +505,7 @@ CIFParseStart(void)
int cifCheckPaintFunc( int cifCheckPaintFunc(
Tile *tile, Tile *tile,
TileType dinfo,
ClientData clientData) ClientData clientData)
{ {
return 1; return 1;
@ -515,27 +516,28 @@ int cifCheckPaintFunc(
int int
cifCopyPaintFunc( cifCopyPaintFunc(
Tile *tile, Tile *tile,
TileType dinfo,
CIFCopyRec *cifCopyRec) CIFCopyRec *cifCopyRec)
{ {
int pNum; int pNum;
TileType dinfo; TileType newdinfo;
Rect sourceRect, targetRect; Rect sourceRect, targetRect;
Transform *trans = cifCopyRec->trans; Transform *trans = cifCopyRec->trans;
Plane *plane = cifCopyRec->plane; Plane *plane = cifCopyRec->plane;
dinfo = TiGetTypeExact(tile); newdinfo = TiGetTypeExact(tile) | dinfo;
if (trans) if (trans)
{ {
TiToRect(tile, &sourceRect); TiToRect(tile, &sourceRect);
GeoTransRect(trans, &sourceRect, &targetRect); GeoTransRect(trans, &sourceRect, &targetRect);
if (IsSplit(tile)) if (IsSplit(tile))
dinfo = DBTransformDiagonal(TiGetTypeExact(tile), trans); newdinfo = DBTransformDiagonal(TiGetTypeExact(tile) | dinfo, trans);
} }
else else
TiToRect(tile, &targetRect); TiToRect(tile, &targetRect);
DBNMPaintPlane(plane, dinfo, &targetRect, CIFPaintTable, DBNMPaintPlane(plane, newdinfo, &targetRect, CIFPaintTable,
(PaintUndoInfo *)NULL); (PaintUndoInfo *)NULL);
return 0; return 0;
@ -561,6 +563,7 @@ cifCopyPaintFunc(
int int
cifMaskHintFunc( cifMaskHintFunc(
Tile *tile, Tile *tile,
TileType dinfo, /* Unused, do not support non-manhattan hints */
LinkedRect **lrecp) LinkedRect **lrecp)
{ {
Rect r; Rect r;
@ -597,8 +600,9 @@ int
CIFPaintCurrent( CIFPaintCurrent(
int filetype) int filetype)
{ {
extern int cifMakeBoundaryFunc(Tile *tile, ClientData clientdata); /* Forward declaration. */ /* Forward declarations. */
extern int cifPaintCurrentFunc(Tile *tile, TileType type); /* Forward declaration. */ extern int cifMakeBoundaryFunc(Tile *tile, TileType dinfo, ClientData clientdata);
extern int cifPaintCurrentFunc(Tile *tile, TileType dinfo, TileType type);
Plane *plane, *swapplane; Plane *plane, *swapplane;
int i; int i;
@ -609,7 +613,7 @@ CIFPaintCurrent(
CIFOp *op; CIFOp *op;
plane = CIFGenLayer(cifCurReadStyle->crs_layers[i]->crl_ops, plane = CIFGenLayer(cifCurReadStyle->crs_layers[i]->crl_ops,
&TiPlaneRect, (CellDef *)NULL, (CellDef *)NULL, &TiPlaneRect, cifReadCellDef, cifReadCellDef,
cifCurReadPlanes, FALSE, (ClientData)NULL); cifCurReadPlanes, FALSE, (ClientData)NULL);
/* Generate a paint/erase table, then paint from the CIF /* Generate a paint/erase table, then paint from the CIF
@ -684,6 +688,8 @@ CIFPaintCurrent(
} }
else if (op == NULL) else if (op == NULL)
{ {
LinkedRect *lrec = NULL, *lsrch;
/* Handle boundary layer */ /* Handle boundary layer */
op = cifCurReadStyle->crs_layers[i]->crl_ops; op = cifCurReadStyle->crs_layers[i]->crl_ops;
@ -698,6 +704,102 @@ CIFPaintCurrent(
(ClientData)NULL) == 1)) (ClientData)NULL) == 1))
DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect, DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect,
&CIFSolidBits, cifMakeBoundaryFunc, INT2CD(filetype)); &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 */ /* Swap planes */
@ -786,9 +888,7 @@ CIFPaintCurrent(
for (i = 0; i < cifNReadLayers; i++) for (i = 0; i < cifNReadLayers; i++)
{ {
LinkedRect *lrec = NULL; LinkedRect *lrec = NULL, *lsrch;
char *propstr = NULL;
char locstr[512];
Plane *tempp; Plane *tempp;
if (!TTMaskHasType(CalmaMaskHints, i)) continue; if (!TTMaskHasType(CalmaMaskHints, i)) continue;
@ -813,53 +913,55 @@ CIFPaintCurrent(
(CellDef *)NULL, CIFPlanes, FALSE, (ClientData)NULL); (CellDef *)NULL, CIFPlanes, FALSE, (ClientData)NULL);
/* Scan the resulting plane and generate linked Rect structures for /* 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, DBSrPaintArea((Tile *)NULL, presult, &TiPlaneRect, &CIFSolidBits,
cifMaskHintFunc, (ClientData)&lrec); cifMaskHintFunc, (ClientData)&lrec);
if (lrec != NULL) if (lrec != NULL)
{ {
PropertyRecord *proprec;
bool propfound;
char *propname; char *propname;
Plane *plane;
propname = (char *)mallocMagic(11 + strlen(cifReadLayers[i])); propname = (char *)mallocMagic(11 + strlen(cifReadLayers[i]));
sprintf(propname, "MASKHINTS_%s", cifReadLayers[i]); sprintf(propname, "MASKHINTS_%s", cifReadLayers[i]);
propstr = (char *)NULL; /* Paint all linked Rects into a mask-hints property plane
* in the target cell.
/* Turn all linked Rects into a mask-hints property 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) while (lrec != NULL)
{ {
char *newstr; lrec->r_r.r_xbot /= CIFCurStyle->cs_scaleFactor;
sprintf(locstr, "%d %d %d %d", lrec->r_r.r_ybot /= CIFCurStyle->cs_scaleFactor;
lrec->r_r.r_xbot / CIFCurStyle->cs_scaleFactor, lrec->r_r.r_xtop /= CIFCurStyle->cs_scaleFactor;
lrec->r_r.r_ybot / CIFCurStyle->cs_scaleFactor, lrec->r_r.r_ytop /= 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,
if (propstr == NULL) (PaintUndoInfo *)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;
free_magic1_t mm1 = freeMagic1_init(); free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, lrec); freeMagic1(&mm1, lrec);
lrec = lrec->r_next; lrec = lrec->r_next;
freeMagic1_end(&mm1); freeMagic1_end(&mm1);
} }
/* NOTE: propstr is transferred to the CellDef and should
* not be free'd here.
*/
DBPropPut(cifReadCellDef, propname, propstr);
freeMagic(propname); freeMagic(propname);
} }
@ -891,12 +993,14 @@ CIFPaintCurrent(
int int
cifMakeBoundaryFunc( cifMakeBoundaryFunc(
Tile *tile, /* Tile of CIF information. */ Tile *tile, /* Tile of CIF information. */
TileType dinfo, /* Split tile information (unused) */
ClientData clientdata) /* Pass the file type (CIF or CALMA) */ ClientData clientdata) /* Pass the file type (CIF or CALMA) */
{ {
/* It is assumed that there is one rectangle for the boundary. */ /* It is assumed that there is one rectangle for the boundary. */
/* If there are multiple rectangles defined with the boundary */ /* If there are multiple rectangles defined with the boundary */
/* layer, then the last one defines the FIXED_BBOX property. */ /* layer, then the last one defines the FIXED_BBOX property. */
PropertyRecord *proprec;
Rect area; Rect area;
char propertyvalue[128], *storedvalue; char propertyvalue[128], *storedvalue;
int savescale; int savescale;
@ -928,19 +1032,24 @@ cifMakeBoundaryFunc(
if (cifReadCellDef->cd_flags & CDFIXEDBBOX) if (cifReadCellDef->cd_flags & CDFIXEDBBOX)
{ {
char *propvalue; PropertyRecord *proprec;
bool found; bool found;
/* Only flag a warning if the redefined boundary was */ /* Only flag a warning if the redefined boundary was */
/* different from the original. */ /* different from the original. */
propvalue = (char *)DBPropGet(cifReadCellDef, "FIXED_BBOX", &found); proprec = DBPropGet(cifReadCellDef, "FIXED_BBOX", &found);
if (found) if (found)
{ {
Rect bbox; Rect bbox;
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot, if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
&bbox.r_xtop, &bbox.r_ytop) == 4) (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) || if ((bbox.r_xbot != area.r_xbot) ||
(bbox.r_ybot != area.r_ybot) || (bbox.r_ybot != area.r_ybot) ||
(bbox.r_xtop != area.r_xtop) || (bbox.r_xtop != area.r_xtop) ||
@ -957,10 +1066,15 @@ cifMakeBoundaryFunc(
} }
} }
sprintf(propertyvalue, "%d %d %d %d", proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) + 2 * sizeof(int));
area.r_xbot, area.r_ybot, area.r_xtop, area.r_ytop); proprec->prop_type = PROPERTY_TYPE_DIMENSION;
storedvalue = StrDup((char **)NULL, propertyvalue); proprec->prop_len = 4;
DBPropPut(cifReadCellDef, "FIXED_BBOX", storedvalue); 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; cifReadCellDef->cd_flags |= CDFIXEDBBOX;
return 0; return 0;
} }
@ -970,6 +1084,7 @@ cifMakeBoundaryFunc(
int int
cifPaintCurrentFunc( cifPaintCurrentFunc(
Tile *tile, /* Tile of CIF information. */ Tile *tile, /* Tile of CIF information. */
TileType dinfo, /* Split tile information */
TileType type) /* Magic type to be painted. */ TileType type) /* Magic type to be painted. */
{ {
Rect area; Rect area;
@ -1019,7 +1134,7 @@ cifPaintCurrentFunc(
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++) for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
if (DBPaintOnPlane(type, pNum)) if (DBPaintOnPlane(type, pNum))
{ {
DBNMPaintPlane(cifReadCellDef->cd_planes[pNum], TiGetTypeExact(tile), DBNMPaintPlane(cifReadCellDef->cd_planes[pNum], TiGetTypeExact(tile) | dinfo,
&area, DBStdPaintTbl(type, pNum), (PaintUndoInfo *) NULL); &area, DBStdPaintTbl(type, pNum), (PaintUndoInfo *) NULL);
} }

View File

@ -244,40 +244,61 @@ CIFPropRecordPath(
{ {
extern float CIFGetOutputScale(int convert); extern float CIFGetOutputScale(int convert);
CIFPath *pathp; CIFPath *pathp;
char *pathstr, *sptr; char *namestr = NULL;
int components; int components, i, x, y, mult, pathnum;
float x, y, oscale, mult; PropertyRecord *proprec;
bool propfound;
oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */ /* If "name" is a property, then append a suffix to it to ensure uniqueness */
if (oscale == 0.0) oscale = 1.0; DBPropGet(def, propname, &propfound);
mult = (iswire == TRUE) ? 0.5 : 1.0; if (propfound)
{
pathnum = 0;
namestr = mallocMagic(strlen(propname) + 10);
while (propfound)
{
sprintf(namestr, "%s_%d", propname, pathnum);
DBPropGet(def, namestr, &propfound);
pathnum++;
}
}
pathp = pathheadp; mult = (iswire == TRUE) ? 1 : 0;
components = 0;
/* Count the number of components in the path */ /* Count the number of components in the path */
pathp = pathheadp;
components = 0;
while (pathp != NULL) while (pathp != NULL)
{ {
pathp = pathp->cifp_next;
components++; components++;
pathp = pathp->cifp_next;
} }
/* Allocate enough space to hold 2 * N points at "infinity" */ /* Allocate enough space to hold 2 * N points. */
pathstr = (char *)mallocMagic(components * 40); proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
((components - 1) * 2) * sizeof(int));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = components * 2;
pathp = pathheadp; pathp = pathheadp;
sptr = pathstr; i = 0;
while (pathp != NULL) while (pathp != NULL)
{ {
x = (float)pathp->cifp_x * oscale * mult; x = pathp->cifp_x >> mult;
y = (float)pathp->cifp_y * oscale * mult; y = pathp->cifp_y >> mult;
sprintf(sptr, "%.3f %.3f ", x, y);
sptr = sptr + strlen(sptr); proprec->prop_value.prop_integer[i] = x;
proprec->prop_value.prop_integer[i + 1] = y;
i += 2;
pathp = pathp->cifp_next; pathp = pathp->cifp_next;
} }
if (namestr)
/* Reallocate pathstr to be no larger than needed to hold the path contents */ {
StrDup(&pathstr, pathstr); DBPropPut(def, namestr, proprec);
DBPropPut(def, propname, (ClientData)pathstr); 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 */ /* 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]; layer = cifCurReadStyle->crs_layers[i];
if (layer != NULL) if (layer != NULL)
{ {
free_magic1_t mm1 = freeMagic1_init(); free_magic1_t mm1 = freeMagic1_init();
for (op = layer->crl_ops; op != NULL; op = op->co_next) 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(&mm1, (char *)op);
}
freeMagic1_end(&mm1); freeMagic1_end(&mm1);
freeMagic((char *)layer); freeMagic((char *)layer);
} }
@ -990,6 +995,12 @@ CIFReadTechLine(
newOp->co_opcode = CIFOP_COPYUP; newOp->co_opcode = CIFOP_COPYUP;
else if (strcmp(argv[0], "boundary") == 0) else if (strcmp(argv[0], "boundary") == 0)
newOp->co_opcode = CIFOP_BOUNDARY; 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 else
{ {
TechError("Unknown statement \"%s\".\n", argv[0]); TechError("Unknown statement \"%s\".\n", argv[0]);
@ -1016,6 +1027,15 @@ CIFReadTechLine(
goto errorReturn; goto errorReturn;
} }
break; 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. */ /* Link the new CIFOp onto the list. */
@ -1099,6 +1119,7 @@ CIFReadTechFinal(void)
* *
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
void void
CIFReadLoadStyle( CIFReadLoadStyle(
char *stylename) char *stylename)

View File

@ -78,6 +78,7 @@ typedef struct {
int int
cifPaintDBFunc( cifPaintDBFunc(
Tile *tile, /* Tile of CIF information. */ Tile *tile, /* Tile of CIF information. */
TileType dinfo,
PaintLayerData *pld) PaintLayerData *pld)
{ {
Rect area; Rect area;
@ -106,7 +107,7 @@ cifPaintDBFunc(
if (DBPaintOnPlane(type, pNum)) if (DBPaintOnPlane(type, pNum))
{ {
ui.pu_pNum = pNum; ui.pu_pNum = pNum;
DBNMPaintPlane(paintDef->cd_planes[pNum], TiGetTypeExact(tile), DBNMPaintPlane(paintDef->cd_planes[pNum], TiGetTypeExact(tile) | dinfo,
&area, DBStdPaintTbl(type, pNum), (PaintUndoInfo *) &ui); &area, DBStdPaintTbl(type, pNum), (PaintUndoInfo *) &ui);
} }
@ -165,9 +166,9 @@ CIFPaintLayer(
scx.scx_use = CIFDummyUse; scx.scx_use = CIFDummyUse;
scx.scx_trans = GeoIdentityTransform; scx.scx_trans = GeoIdentityTransform;
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0, (void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef); cifHierCopyFunc, (ClientData) CIFComponentDef);
CIFCopyMaskHints(&scx, CIFComponentDef); CIFCopyMaskHints(&scx, CIFComponentDef);
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints, DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFComponentDef); (ClientData)CIFComponentDef);
oldCount = DBWFeedbackCount; oldCount = DBWFeedbackCount;
@ -219,6 +220,7 @@ CIFPaintLayer(
int int
cifSeeFunc( cifSeeFunc(
Tile *tile, /* Tile to be entered as feedback. */ Tile *tile, /* Tile to be entered as feedback. */
TileType dinfo, /* Split tile information */
SeeLayerData *sld) /* Layer and explanation for the feedback. */ SeeLayerData *sld) /* Layer and explanation for the feedback. */
{ {
Rect area; Rect area;
@ -233,10 +235,10 @@ cifSeeFunc(
(float)area.r_ybot / (float)CIFCurStyle->cs_scaleFactor); (float)area.r_ybot / (float)CIFCurStyle->cs_scaleFactor);
} }
/* (NOTE: Preserve information about the geometry of a diagonal tile) */
DBWFeedbackAdd(&area, sld->text, cifSeeDef, CIFCurStyle->cs_scaleFactor, DBWFeedbackAdd(&area, sld->text, cifSeeDef, CIFCurStyle->cs_scaleFactor,
sld->style | sld->style | ((TiGetTypeExact(tile) | dinfo) &
(TiGetTypeExact(tile) & (TT_DIAGONAL | TT_DIRECTION | TT_SIDE))); (TT_DIAGONAL | TT_DIRECTION | TT_SIDE)));
/* (preserve information about the geometry of a diagonal tile) */
return 0; return 0;
} }
@ -285,9 +287,9 @@ CIFSeeLayer(
scx.scx_use = CIFDummyUse; scx.scx_use = CIFDummyUse;
scx.scx_trans = GeoIdentityTransform; scx.scx_trans = GeoIdentityTransform;
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0, (void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef); cifHierCopyFunc, (ClientData) CIFComponentDef);
CIFCopyMaskHints(&scx, CIFComponentDef); CIFCopyMaskHints(&scx, CIFComponentDef);
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints, DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFComponentDef); (ClientData)CIFComponentDef);
oldCount = DBWFeedbackCount; oldCount = DBWFeedbackCount;
@ -438,9 +440,11 @@ CIFCoverageLayer(
SearchContext scx; SearchContext scx;
TileTypeBitMask mask, depend; TileTypeBitMask mask, depend;
float fcover; float fcover;
int cifCoverageFunc(Tile *tile, ClientData *arg);
bool doBox = (area != &rootDef->cd_bbox) ? TRUE : FALSE; bool doBox = (area != &rootDef->cd_bbox) ? TRUE : FALSE;
/* Forward declaration */
int cifCoverageFunc(Tile *tile, TileType dinfo, ClientData *arg);
/* Check out the CIF layer name. */ /* Check out the CIF layer name. */
if (!CIFNameToMask(layer, &mask, &depend)) return; if (!CIFNameToMask(layer, &mask, &depend)) return;
@ -455,9 +459,9 @@ CIFCoverageLayer(
scx.scx_use = CIFDummyUse; scx.scx_use = CIFDummyUse;
scx.scx_trans = GeoIdentityTransform; scx.scx_trans = GeoIdentityTransform;
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0, (void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef); cifHierCopyFunc, (ClientData) CIFComponentDef);
CIFCopyMaskHints(&scx, CIFComponentDef); CIFCopyMaskHints(&scx, CIFComponentDef);
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints, DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFComponentDef); (ClientData)CIFComponentDef);
CIFGen(CIFComponentDef, rootDef, area, CIFPlanes, &depend, TRUE, TRUE, CIFGen(CIFComponentDef, rootDef, area, CIFPlanes, &depend, TRUE, TRUE,
@ -500,10 +504,10 @@ CIFCoverageLayer(
} }
else 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); "Cell", btotal);
TxPrintf("Layer Bounding Area = %lld CIF units^2\n", atotal); TxPrintf("Layer Bounding Area = %"DLONG_PREFIX"d CIF units^2\n", atotal);
TxPrintf("Layer Total Area = %lld CIF units^2\n", cstats.coverage); TxPrintf("Layer Total Area = %"DLONG_PREFIX"d CIF units^2\n", cstats.coverage);
TxPrintf("Coverage in %s = %1.1f%%\n", doBox ? "box" : TxPrintf("Coverage in %s = %1.1f%%\n", doBox ? "box" :
"cell", 100.0 * fcover); "cell", 100.0 * fcover);
} }
@ -512,6 +516,7 @@ CIFCoverageLayer(
int int
cifCoverageFunc( cifCoverageFunc(
Tile *tile, Tile *tile,
TileType dinfo, /* (unused) */
ClientData *arg) ClientData *arg)
{ {
coverstats *cstats = (coverstats *)arg; coverstats *cstats = (coverstats *)arg;

View File

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

View File

@ -46,8 +46,8 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
/* Forward declarations */ /* Forward declarations */
extern int cifWriteInitFunc(CellDef *def); extern int cifWriteInitFunc(CellDef *def);
extern int cifWriteMarkFunc(CellUse *use); extern int cifWriteMarkFunc(CellUse *use);
extern int cifWritePaintFunc(Tile *tile, FILE *f); extern int cifWritePaintFunc(Tile *tile, TileType dinfo, FILE *f);
extern int cifWriteLabelFunc(Tile *tile, FILE *f); extern int cifWriteLabelFunc(Tile *tile, TileType dinfo, FILE *f);
extern int cifWriteUseFunc(CellUse *use, FILE *f); extern int cifWriteUseFunc(CellUse *use, FILE *f);
extern void cifOutPreamble(FILE *outf, CellDef *cell); extern void cifOutPreamble(FILE *outf, CellDef *cell);
extern void cifOut(FILE *outf); extern void cifOut(FILE *outf);
@ -584,6 +584,7 @@ cifWriteUseFunc(
int int
cifWriteLabelFunc( cifWriteLabelFunc(
Tile *tile, /* Tile to be written out. */ Tile *tile, /* Tile to be written out. */
TileType dinfo, /* Split tile information (unused) */
FILE *f) /* File in which to write. */ FILE *f) /* File in which to write. */
{ {
Rect r; Rect r;
@ -643,7 +644,8 @@ cifWriteLabelFunc(
int int
cifWritePaintFunc( cifWritePaintFunc(
Tile *tile, /* Tile to be written out. */ Tile *tile, /* Tile to be written out. */
FILE *f) /* File in which to write. */ TileType dinfo, /* Split tile information */
FILE *f) /* File in which to write. */
{ {
Rect r; Rect r;
@ -662,7 +664,7 @@ cifWritePaintFunc(
Point points[5]; Point points[5];
int i, np; int i, np;
GrClipTriangle(&r, NULL, FALSE, TiGetTypeExact(tile), points, &np); GrClipTriangle(&r, NULL, FALSE, TiGetTypeExact(tile) | dinfo, points, &np);
/* Write triangle as a CIF polygon */ /* Write triangle as a CIF polygon */

View File

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

View File

@ -117,12 +117,13 @@ bool cmdDumpParseArgs(char *cmdName, MagWindow *w, TxCommand *cmd, CellUse *dumm
#define CALMA_READ 19 #define CALMA_READ 19
#define CALMA_READONLY 20 #define CALMA_READONLY 20
#define CALMA_RESCALE 21 #define CALMA_RESCALE 21
#define CALMA_WARNING 22 #define CALMA_SAVEPATHS 22
#define CALMA_WRITE 23 #define CALMA_WARNING 23
#define CALMA_POLYS 24 #define CALMA_WRITE 24
#define CALMA_PATHS 25 #define CALMA_POLYS 25
#define CALMA_UNDEFINED 26 #define CALMA_PATHS 26
#define CALMA_UNIQUE 27 #define CALMA_UNDEFINED 27
#define CALMA_UNIQUE 28
#define CALMA_WARN_HELP CIF_WARN_END /* undefined by CIF module */ #define CALMA_WARN_HELP CIF_WARN_END /* undefined by CIF module */
@ -175,6 +176,7 @@ CmdCalma(
" into edit cell", " into edit cell",
"readonly [yes|no] set cell as read-only and generate output from GDS file", "readonly [yes|no] set cell as read-only and generate output from GDS file",
"rescale [yes|no] allow or disallow internal grid subdivision", "rescale [yes|no] allow or disallow internal grid subdivision",
"savepaths [yes|no] save path centerlines as cell properties",
"warning [option] set warning information level", "warning [option] set warning information level",
"write file output Calma GDS-II format to \"file\"\n" "write file output Calma GDS-II format to \"file\"\n"
" for the window's root cell", " for the window's root cell",
@ -738,6 +740,27 @@ CmdCalma(
CalmaSubcellPolygons = (unsigned char)option; CalmaSubcellPolygons = (unsigned char)option;
return; 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: case CALMA_NO_DUP:
if (cmd->tx_argc == 2) if (cmd->tx_argc == 2)
{ {
@ -1300,7 +1323,7 @@ CmdCellname(
if (cellDef == (CellDef *) NULL) if (cellDef == (CellDef *) NULL)
TxError("Unknown cell %s\n", cellname); TxError("Unknown cell %s\n", cellname);
else else
CmdDoProperty(cellDef, cmd, 3 + ((dolist) ? 1 : 0)); CmdDoProperty(cellDef, w, cmd, 3 + ((dolist) ? 1 : 0));
break; break;
case IDX_DELETE: case IDX_DELETE:
@ -2396,8 +2419,10 @@ CmdContact(
CCStruct ccs; CCStruct ccs;
Rect area; Rect area;
LinkedRect *lr = NULL; LinkedRect *lr = NULL;
int cmdContactFunc(Tile *tile, CCStruct *ccs); /* Forward declaration */
int cmdContactEraseFunc(Tile *tile, LinkedRect **lr); /* Forward declaration */ /* Forward declarations */
int cmdContactFunc(Tile *tile, TileType dinfo, CCStruct *ccs);
int cmdContactEraseFunc(Tile *tile, TileType dinfo, LinkedRect **lr);
windCheckOnlyWindow(&w, DBWclientID); windCheckOnlyWindow(&w, DBWclientID);
if ((w == (MagWindow *) NULL) || (w->w_client != DBWclientID)) if ((w == (MagWindow *) NULL) || (w->w_client != DBWclientID))
@ -2531,11 +2556,14 @@ CmdContact(
int int
cmdContactFunc( cmdContactFunc(
Tile *tile, Tile *tile,
TileType dinfo,
CCStruct *ccs) CCStruct *ccs)
{ {
TileType stype; TileType stype;
TileTypeBitMask smask; TileTypeBitMask smask;
int cmdContactFunc2(Tile *tile, CCStruct *ccs); /* Forward declaration */
/* Forward declaration */
int cmdContactFunc2(Tile *tile, TileType dinfo, CCStruct *ccs);
TiToRect(tile, &ccs->area); TiToRect(tile, &ccs->area);
GeoClip(&ccs->area, &ccs->clip); GeoClip(&ccs->area, &ccs->clip);
@ -2545,14 +2573,16 @@ cmdContactFunc(
break; break;
TTMaskSetOnlyType(&smask, stype); TTMaskSetOnlyType(&smask, stype);
DBSrPaintArea((Tile *) NULL, ccs->rootDef->cd_planes[DBPlane(stype)], DBSrPaintNMArea((Tile *)NULL, ccs->rootDef->cd_planes[DBPlane(stype)],
&ccs->area, &smask, cmdContactFunc2, (ClientData)ccs); TiGetTypeExact(tile) | dinfo, &ccs->area, &smask,
cmdContactFunc2, (ClientData)ccs);
return 0; return 0;
} }
int int
cmdContactFunc2( cmdContactFunc2(
Tile *tile, Tile *tile,
TileType dinfo, /* (unused) */
CCStruct *ccs) CCStruct *ccs)
{ {
LinkedRect *newlr; LinkedRect *newlr;
@ -2575,6 +2605,7 @@ cmdContactFunc2(
int int
cmdContactEraseFunc( cmdContactEraseFunc(
Tile *tile, Tile *tile,
TileType dinfo, /* (unused) */
LinkedRect **lr) LinkedRect **lr)
{ {
LinkedRect *newlr; LinkedRect *newlr;
@ -2828,14 +2859,15 @@ CmdCorner(
TileTypeBitMask maskBits; TileTypeBitMask maskBits;
Rect editBox; Rect editBox;
SearchContext scx; SearchContext scx;
extern int cmdCornerFunc(Tile *tile, TreeContext *cxp);
bool hasErr = FALSE; bool hasErr = FALSE;
int locargc = cmd->tx_argc; int locargc = cmd->tx_argc;
extern int cmdBevelFunc(Tile *tile, TreeContext *cxp);
bool dobevel = FALSE; bool dobevel = FALSE;
NMCornerPath cmdPathList; NMCornerPath cmdPathList;
/* Forward declarations */
extern int cmdCornerFunc(Tile *tile, TileType dinfo, TreeContext *cxp);
extern int cmdBevelFunc(Tile *tile, TileType dinfo, TreeContext *cxp);
if (cmd->tx_argc < 3 || cmd->tx_argc > 5) if (cmd->tx_argc < 3 || cmd->tx_argc > 5)
{ {
TxError("Usage: %s direction1 direction2 [layers]\n", TxError("Usage: %s direction1 direction2 [layers]\n",
@ -3030,6 +3062,7 @@ CmdCorner(
int int
cmdCornerFunc( cmdCornerFunc(
Tile *tile, /* Tile to fill with. */ Tile *tile, /* Tile to fill with. */
TileType dinfo, /* Split tile information (unused) */
TreeContext *cxp) /* Describes state of search. */ TreeContext *cxp) /* Describes state of search. */
{ {
Rect r1, r2, r3; Rect r1, r2, r3;
@ -3196,6 +3229,7 @@ AddNewPoint(
int int
cmdBevelFunc( cmdBevelFunc(
Tile *tile, /* Tile to fill with. */ Tile *tile, /* Tile to fill with. */
TileType dinfo, /* Split tile information (unused) */
TreeContext *cxp) /* Describes state of search. */ TreeContext *cxp) /* Describes state of search. */
{ {
Rect r1, r2, r3; Rect r1, r2, r3;
@ -4585,6 +4619,7 @@ CmdDrc(
int int
cmdDropPaintCell( cmdDropPaintCell(
Tile *tile, Tile *tile,
TileType dinfo,
TreeContext *cxp) TreeContext *cxp)
{ {
CellDef *cellDef = cxp->tc_scx->scx_use->cu_def; CellDef *cellDef = cxp->tc_scx->scx_use->cu_def;
@ -4593,7 +4628,7 @@ cmdDropPaintCell(
TileType type; TileType type;
Rect area; Rect area;
if (SplitSide(tile)) if (dinfo & TT_SIDE)
type = SplitRightType(tile); type = SplitRightType(tile);
else else
type = SplitLeftType(tile); type = SplitLeftType(tile);
@ -4626,6 +4661,7 @@ cmdDropPaintCell(
int int
cmdDropFunc( cmdDropFunc(
Tile *tile, Tile *tile,
TileType dinfo,
ClientData clientData) ClientData clientData)
{ {
TileTypeBitMask tMask, *lMask = (TileTypeBitMask *)clientData; TileTypeBitMask tMask, *lMask = (TileTypeBitMask *)clientData;
@ -4636,7 +4672,7 @@ cmdDropFunc(
scx.scx_use = EditCellUse; scx.scx_use = EditCellUse;
scx.scx_trans = GeoIdentityTransform; scx.scx_trans = GeoIdentityTransform;
if (SplitSide(tile)) if (dinfo & TT_SIDE)
type = SplitRightType(tile); type = SplitRightType(tile);
else else
type = SplitLeftType(tile); type = SplitLeftType(tile);
@ -4978,15 +5014,20 @@ cmdDumpParseArgs(
bbox = def->cd_bbox; bbox = def->cd_bbox;
if (def->cd_flags & CDFIXEDBBOX) if (def->cd_flags & CDFIXEDBBOX)
{ {
char *propvalue; PropertyRecord *proprec;
bool found; bool found;
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &found); proprec = DBPropGet(def, "FIXED_BBOX", &found);
if (found) if (found)
{ {
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot, if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
&bbox.r_xtop, &bbox.r_ytop) != 4) (proprec->prop_len == 4))
bbox = def->cd_bbox; {
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 DOALL 1
#define DOCAPACITANCE 2 #define DOCAPACITANCE 2
#define DOCOUPLING 3 #define DOCOUPLING 3
#define DOLENGTH 4 #define DOEXTRESIST 4
#define DOLOCAL 5 #define DOLENGTH 5
#define DORESISTANCE 6 #define DOLOCAL 6
#define DOLABELCHECK 7 #define DORESISTANCE 7
#define DOALIASES 8 #define DOLABELCHECK 8
#define DOALIASES 9
#define DOUNIQUE 10
#define DOEXTRESIST2 11
#define LENCLEAR 0 #define LENCLEAR 0
#define LENDRIVER 1 #define LENDRIVER 1
@ -972,11 +975,14 @@ CmdExtract(
"all all options", "all all options",
"capacitance extract substrate capacitance", "capacitance extract substrate capacitance",
"coupling extract coupling capacitance", "coupling extract coupling capacitance",
"extresist extract resistance",
"length compute driver-receiver pathlengths", "length compute driver-receiver pathlengths",
"local put all generated files in the current directory", "local put all generated files in the current directory",
"resistance estimate resistance", "lumped estimate lumped resistance",
"labelcheck check for connections through sticky labels", "labelcheck check for connections through sticky labels",
"aliases output all net name aliases", "aliases output all net name aliases",
"unique ensure unique node names during extraction",
"resistance extract resistance (same as \"do extresist\")",
NULL NULL
}; };
static const char * const cmdExtLength[] = static const char * const cmdExtLength[] =
@ -1120,12 +1126,13 @@ CmdExtract(
} }
else if (argc == 2) else if (argc == 2)
{ {
char *halodisp;
halodisp = DBWPrintValue(ExtCurStyle->exts_sideCoupleHalo,
w, TRUE);
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
Tcl_Obj *tobj; Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(halodisp, -1));
tobj = Tcl_NewIntObj(ExtCurStyle->exts_sideCoupleHalo);
Tcl_SetObjResult(magicinterp, tobj);
#else #else
TxPrintf("Side overlap halo is %d\n", ExtCurStyle->exts_sideCoupleHalo); TxPrintf("Side overlap halo is %s\n", halodisp);
#endif #endif
return; return;
} }
@ -1150,12 +1157,12 @@ CmdExtract(
} }
else if (argc == 2) else if (argc == 2)
{ {
char *stepdisp;
stepdisp = DBWPrintValue(ExtCurStyle->exts_stepSize, w, TRUE);
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
Tcl_Obj *tobj; Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(stepdisp, -1));
tobj = Tcl_NewIntObj(ExtCurStyle->exts_stepSize);
Tcl_SetObjResult(magicinterp, tobj);
#else #else
TxPrintf("Extraction step size is %d\n", ExtCurStyle->exts_stepSize); TxPrintf("Extraction step size is %s\n", stepdisp);
#endif #endif
return; return;
} }
@ -1277,9 +1284,11 @@ CmdExtract(
TxPrintf("%s capacitance\n", OPTSET(EXT_DOCAPACITANCE)); TxPrintf("%s capacitance\n", OPTSET(EXT_DOCAPACITANCE));
TxPrintf("%s coupling\n", OPTSET(EXT_DOCOUPLING)); TxPrintf("%s coupling\n", OPTSET(EXT_DOCOUPLING));
TxPrintf("%s length\n", OPTSET(EXT_DOLENGTH)); 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 label check\n", OPTSET(EXT_DOLABELCHECK));
TxPrintf("%s aliases\n", OPTSET(EXT_DOALIASES)); TxPrintf("%s aliases\n", OPTSET(EXT_DOALIASES));
TxPrintf("%s unique\n", OPTSET(EXT_DOUNIQUE));
TxPrintf("%s resistance (extresist)\n", OPTSET(EXT_DOEXTRESIST));
return; return;
#undef OPTSET #undef OPTSET
} }
@ -1309,6 +1318,9 @@ CmdExtract(
case DORESISTANCE: option = EXT_DORESISTANCE; break; case DORESISTANCE: option = EXT_DORESISTANCE; break;
case DOLABELCHECK: option = EXT_DOLABELCHECK; break; case DOLABELCHECK: option = EXT_DOLABELCHECK; break;
case DOALIASES: option = EXT_DOALIASES; break; case DOALIASES: option = EXT_DOALIASES; break;
case DOUNIQUE: option = EXT_DOUNIQUE; break;
case DOEXTRESIST:
case DOEXTRESIST2: option = EXT_DOEXTRESIST; break;
case DOLOCAL: case DOLOCAL:
/* "extract do local" and "extract no local" are kept for /* "extract do local" and "extract no local" are kept for
* backwards compatibility, but now effectively implement * backwards compatibility, but now effectively implement

View File

@ -102,15 +102,17 @@ struct cmdFPArg
int int
feedPolyFunc( feedPolyFunc(
Tile *tile, Tile *tile,
TileType dinfo,
struct cmdFPArg *arg) struct cmdFPArg *arg)
{ {
Rect area; Rect area;
TiToRect(tile, &area); TiToRect(tile, &area);
/* (NOTE: Preserve information about the geometry of a diagonal tile) */
DBWFeedbackAdd(&area, arg->text, arg->def, FEEDMAGNIFY, DBWFeedbackAdd(&area, arg->text, arg->def, FEEDMAGNIFY,
arg->style | arg->style |
(TiGetTypeExact(tile) & (TT_DIAGONAL | TT_DIRECTION | TT_SIDE))); ((TiGetTypeExact(tile) | dinfo) &
/* (preserve information about the geometry of a diagonal tile) */ (TT_DIAGONAL | TT_DIRECTION | TT_SIDE)));
return 0; return 0;
} }
@ -507,13 +509,15 @@ struct cmdFillArea *cmdFillList; /* List of areas to fill. */
void void
CmdFill( CmdFill(
MagWindow *w, /* Window in which command was invoked. */ MagWindow *w, /* Window in which command was invoked. */
TxCommand *cmd) /* Describes the command that was invoked. */ TxCommand *cmd) /* Describes the command that was invoked. */
{ {
TileTypeBitMask maskBits; TileTypeBitMask maskBits;
Rect editBox; Rect editBox;
SearchContext scx; SearchContext scx;
extern int cmdFillFunc(Tile *tile, TreeContext *cxp);
/* Forward declaration */
extern int cmdFillFunc(Tile *tile, TileType dinfo, TreeContext *cxp);
if (cmd->tx_argc < 2 || cmd->tx_argc > 3) if (cmd->tx_argc < 2 || cmd->tx_argc > 3)
{ {
@ -603,11 +607,16 @@ CmdFill(
* paint here it may mess up the search. Instead, the procedures * paint here it may mess up the search. Instead, the procedures
* save areas on a list. The list is post-processed to paint the * save areas on a list. The list is post-processed to paint the
* areas once the search is finished. * areas once the search is finished.
*
* Split tile information is unused because there is no obvious
* meaning to "filling" from a split tile, although probably reasonable
* methods could be worked out.
*/ */
int int
cmdFillFunc( cmdFillFunc(
Tile *tile, /* Tile to fill with. */ Tile *tile, /* Tile to fill with. */
TileType dinfo, /* Split tile information (unused) */
TreeContext *cxp) /* Describes state of search. */ TreeContext *cxp) /* Describes state of search. */
{ {
Rect r1, r2; Rect r1, r2;
@ -1210,7 +1219,7 @@ CmdGetnode(
TxError("Put the cursor in a layout window\n"); TxError("Put the cursor in a layout window\n");
return; return;
} }
if( is_fast == TRUE ) if (is_fast == TRUE)
{ {
SimRecomputeSel = TRUE; SimRecomputeSel = TRUE;
SimGetsnode(); SimGetsnode();
@ -1218,7 +1227,8 @@ CmdGetnode(
else else
SimGetnode(); SimGetnode();
if (SimGetnodeAlias) { /* "erase" the hash table */ if (SimGetnodeAlias) /* "erase" the hash table */
{
HashKill(&SimGNAliasTbl); HashKill(&SimGNAliasTbl);
HashInit(&SimGNAliasTbl, 120, STRINGS); HashInit(&SimGNAliasTbl, 120, STRINGS);
} }
@ -1604,7 +1614,7 @@ CmdFindNetProc(
int pnum, xpos, ypos; int pnum, xpos, ypos;
char *xstr, *ystr; char *xstr, *ystr;
bool locvalid = FALSE, usefound = TRUE; bool locvalid = FALSE, usefound = TRUE;
TileType ttype; TileType ttype, dinfo = (TileType)0;
scx.scx_use = use; scx.scx_use = use;
scx.scx_trans = GeoIdentityTransform; scx.scx_trans = GeoIdentityTransform;
@ -1642,6 +1652,7 @@ CmdFindNetProc(
if ((xstr = strchr(s, '_')) != NULL) if ((xstr = strchr(s, '_')) != NULL)
{ {
char *hashpos;
bool isNeg = FALSE; bool isNeg = FALSE;
/* The characters up to the leading '_' should match one of the */ /* The characters up to the leading '_' should match one of the */
@ -1685,6 +1696,17 @@ CmdFindNetProc(
} }
} }
} }
/* Format variant used for node regions where a split tile
* occupies the root position of the node but the tile type
* belonging to the node is on the right side of the tile,
* not at the location encoded into the name. An 'x' is
* added before the final hash sign.
*/
hashpos = strrchr(s, '#');
if (hashpos != NULL)
if (*(hashpos - 1) == 'r')
dinfo = TT_DIAGONAL | TT_SIDE;
} }
} }
@ -1707,17 +1729,23 @@ checklocal:
if (locvalid == TRUE) if (locvalid == TRUE)
{ {
int findTile(Tile *tile, TileType *rtype); int findTile(Tile *tile, TileType dinfo, TileAndDinfo *tad);
CellDef *targetdef = use->cu_def; CellDef *targetdef = use->cu_def;
Plane *plane = targetdef->cd_planes[pnum]; Plane *plane = targetdef->cd_planes[pnum];
TileAndDinfo tad;
ttype = TT_SPACE; /* revert to space in case of failure */
/* Find the tile type of the tile at the specified point which */ /* Find the tile type of the tile at the specified point which */
/* exists on the plane pnum. */ /* exists on the plane pnum. Note that in the case of a split */
/* tile region marked with "x" in the name, it does not work to */
/* call DBSrPainNMArea() because the diagonal position is not */
/* known. findTile() determines the proper type and leaves it */
/* in the tad.tad_dinfo record. */
tad.tad_tile = (Tile *)NULL;
tad.tad_dinfo = dinfo;
DBSrPaintArea(NULL, plane, &localrect, &DBAllTypeBits, findTile, DBSrPaintArea(NULL, plane, &localrect, &DBAllTypeBits, findTile,
(ClientData) &ttype); (ClientData) &tad);
ttype = tad.tad_dinfo & TT_LEFTMASK;
} }
else else
{ {
@ -1841,20 +1869,31 @@ CmdGoto(
int int
findTile( findTile(
Tile *tile, Tile *tile,
TileType *rtype) TileType dinfo, /* (unused) */
TileAndDinfo *tad)
{ {
TileType ttype; TileType ttype;
/* Note that since all types are being searched, a split
* tile would cause the callback to be called twice. But
* this routine will pick the indicated side from the
* "tad" structure and return 1 so it does not get called
* a second time. The "dinfo" value passed is irrelevant.
*/
if (IsSplit(tile)) if (IsSplit(tile))
{ {
if (SplitSide(tile)) if (tad->tad_dinfo & TT_SIDE)
ttype = SplitRightType(tile); ttype = SplitRightType(tile);
else else
ttype = SplitLeftType(tile); ttype = SplitLeftType(tile);
} }
else else
ttype = TiGetTypeExact(tile); ttype = TiGetTypeExact(tile);
*rtype = ttype;
/* Leave the tile type in tad_dinfo before returning */
tad->tad_dinfo = ttype;
return 1; /* stop search */ return 1; /* stop search */
} }

View File

@ -45,9 +45,8 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
#include "utils/undo.h" #include "utils/undo.h"
#include "select/select.h" #include "select/select.h"
#include "netmenu/netmenu.h" #include "netmenu/netmenu.h"
/* C99 compat */
#include "cif/cif.h" #include "cif/cif.h"
#include "cif/CIFint.h"
/* Forward declarations */ /* Forward declarations */
@ -2296,6 +2295,8 @@ parsepositions:
editDef->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP); editDef->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
} }
#define PROPERTY_TYPE_COMPAT 4 /* Last entry in cmdPropertyType */
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -2319,47 +2320,449 @@ parsepositions:
void void
CmdDoProperty( CmdDoProperty(
CellDef *def, CellDef *def,
MagWindow *w,
TxCommand *cmd, TxCommand *cmd,
int argstart) int argstart)
{ {
int printPropertiesFunc(); PropertyRecord *proprec;
char *value; char *value;
bool propfound; bool propfound, dolist;
int proptype, proplen, propvalue, i;
dlong dvalue;
int locargc = cmd->tx_argc - argstart + 1; 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) 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 */ /* print all properties and their values */
DBPropEnum(def, printPropertiesFunc, NULL); DBPropEnum(def, printPropertiesFunc, (ClientData)w);
} }
else if (locargc == 2) else if (locargc == 2)
{ {
/* print the value of the indicated property */ /* If the property type was "compat", then give the state of the
value = (char *)DBPropGet(def, cmd->tx_argv[argstart], &propfound); * compatibility flag and return.
if (propfound) */
if (proptype == PROPERTY_TYPE_COMPAT)
{
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
Tcl_SetResult(magicinterp, value, NULL); Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(DBPropCompat));
#else #else
TxPrintf("%s", value); TxPrintf("%s\n", (DBPropCompat == TRUE) ? "True" : "False");
#endif #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 { else {
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
/* If the command was "cellname list property ...", then */ /* If the command was "cellname list property ...", then */
/* just return NULL if the property was not found. */ /* just return NULL if the property was not found. */
if (strcmp(cmd->tx_argv[1], "list")) if (!dolist)
#endif #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) if (strlen(cmd->tx_argv[argstart + 1]) == 0)
DBPropPut(def, cmd->tx_argv[argstart], NULL); DBPropPut(def, cmd->tx_argv[argstart], NULL);
else else
{ {
value = StrDup((char **)NULL, cmd->tx_argv[argstart + 1]); if (proptype == PROPERTY_TYPE_STRING)
DBPropPut(def, cmd->tx_argv[argstart], value); {
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); def->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
} }
@ -2380,10 +2783,14 @@ CmdDoProperty(
* defined in database/DBprop.c. * defined in database/DBprop.c.
* *
* Usage: * Usage:
* property [name] [value] * property [string|integer|dimension] [name] [value]
* *
* "name" is a unique string tag for the property, and "value" is its * If the first argument is present, it must be one of the known
* string value. * 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: * Results:
* None. * None.
@ -2410,9 +2817,62 @@ CmdProperty(
else else
def = ((CellUse *) w->w_surfaceID)->cu_def; 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 * Callback function for printing a single property key:value pair
@ -2422,27 +2882,84 @@ CmdProperty(
int int
printPropertiesFunc( printPropertiesFunc(
const char *name, const char *name,
ClientData value, PropertyRecord *proprec,
ClientData cdata) /* not used */ MagWindow *w)
{ {
#ifdef MAGIC_WRAPPER int i;
char *keyvalue;
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); case PROPERTY_TYPE_STRING:
sprintf(keyvalue, "%s {}", name); 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 Tcl_ListObjAppendElement(magicinterp, tobj, lobj);
{ Tcl_SetObjResult(magicinterp, tobj);
keyvalue = (char *)mallocMagic(strlen(name) + strlen((const char *)value) + 2);
sprintf(keyvalue, "%s %s", name, (const char *)value);
}
Tcl_AppendElement(magicinterp, keyvalue);
freeMagic(keyvalue);
#else #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 #endif
return 0; /* keep the search alive */ return 0; /* keep the search alive */

View File

@ -1084,25 +1084,33 @@ CmdSelect(
*/ */
case SEL_BBOX: case SEL_BBOX:
{
char *selllx, *sellly, *selurx, *selury;
GeoTransRect(&SelectUse->cu_transform, &SelectDef->cd_bbox, &selarea); 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 #ifdef MAGIC_WRAPPER
lobj = Tcl_NewListObj(0, NULL); lobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(selarea.r_xbot)); Tcl_NewStringObj(selllx, -1));
Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(selarea.r_ybot)); Tcl_NewStringObj(sellly, -1));
Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(selarea.r_xtop)); Tcl_NewStringObj(selurx, -1));
Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(selarea.r_ytop)); Tcl_NewStringObj(selury, -1));
Tcl_SetObjResult(magicinterp, lobj); Tcl_SetObjResult(magicinterp, lobj);
#else #else
TxPrintf("Select bounding box: %d %d %d %d\n", TxPrintf("Select bounding box: %s %s %s %s\n",
selarea.r_xbot, selarea.r_ybot, selllx, sellly, selurx, selury);
selarea.r_xtop, selarea.r_ytop);
#endif #endif
return; return;
}
/*-------------------------------------------------------------------- /*--------------------------------------------------------------------
* Make a copy of the selection at its present loction but do not * Make a copy of the selection at its present loction but do not
@ -1985,23 +1993,25 @@ cmdLabelRectFunc(
if (rect == NULL) 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 #ifdef MAGIC_WRAPPER
lobj = Tcl_GetObjResult(magicinterp); lobj = Tcl_GetObjResult(magicinterp);
pobj = Tcl_NewListObj(0, NULL); pobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj, pobj); Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(labllx, -1));
Tcl_NewIntObj((double)label->lab_rect.r_xbot)); Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(lablly, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(laburx, -1));
Tcl_NewIntObj((double)label->lab_rect.r_ybot)); Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(labury, -1));
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_SetObjResult(magicinterp, lobj); Tcl_SetObjResult(magicinterp, lobj);
#else #else
TxPrintf("%d %d %d %d\n", TxPrintf("%s %s %s %s\n", labllx, lablly, laburx,labury);
label->lab_rect.r_xbot, label->lab_rect.r_ybot,
label->lab_rect.r_xtop, label->lab_rect.r_ytop);
#endif #endif
} }
else if (!GEO_SAMERECT(label->lab_rect, *rect)) else if (!GEO_SAMERECT(label->lab_rect, *rect))
@ -2317,11 +2327,13 @@ CmdSetLabel(
{ {
if (locargc == 2) if (locargc == 2)
{ {
char *labsize;
labsize = DBWPrintValue(DefaultLabel->lab_size, w, FALSE);
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(labsize, -1));
Tcl_NewIntObj(DefaultLabel->lab_size));
#else #else
TxPrintf("%d\n", DefaultLabel->lab_size); TxPrintf("%s\n", labsize);
#endif #endif
} }
else else
@ -2360,16 +2372,20 @@ CmdSetLabel(
{ {
if (locargc == 2) 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 #ifdef MAGIC_WRAPPER
lobj = Tcl_NewListObj(0, NULL); lobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(DefaultLabel->lab_offset.p_x)); Tcl_NewStringObj(laboffx, -1));
Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(DefaultLabel->lab_offset.p_y)); Tcl_NewStringObj(laboffy, -1));
Tcl_SetObjResult(magicinterp, lobj); Tcl_SetObjResult(magicinterp, lobj);
#else #else
TxPrintf("%d %d\n", DefaultLabel->lab_offset.p_x, TxPrintf("%s %s\n", laboffx, laboffy);
DefaultLabel->lab_offset.p_y);
#endif #endif
} }
else else
@ -2884,16 +2900,39 @@ CmdSnap(
TxPrintf("Usage: snap [internal | lambda | user]\n"); TxPrintf("Usage: snap [internal | lambda | user]\n");
return; 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) switch (n)
{ {
case SNAP_OFF: case SNAP_INTERNAL: case SNAP_OFF: case SNAP_INTERNAL:
DBWSnapToGrid = DBW_SNAP_INTERNAL; DBWSnapToGrid = DBW_UNITS_INTERNAL;
return; return;
case SNAP_LAMBDA: case SNAP_LAMBDA:
DBWSnapToGrid = DBW_SNAP_LAMBDA; DBWSnapToGrid = DBW_UNITS_LAMBDA;
return; return;
case SNAP_GRID: case SNAP_USER: case SNAP_ON: case SNAP_GRID: case SNAP_USER: case SNAP_ON:
DBWSnapToGrid = DBW_SNAP_USER; DBWSnapToGrid = DBW_UNITS_USER;
return; return;
} }
@ -2901,21 +2940,19 @@ printit:
if (n == SNAP_LIST) /* list */ if (n == SNAP_LIST) /* list */
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
Tcl_SetResult(magicinterp, Tcl_SetResult(magicinterp,
(DBWSnapToGrid == DBW_SNAP_INTERNAL) ? "internal" : (DBWSnapToGrid == DBW_UNITS_INTERNAL) ? "internal" :
((DBWSnapToGrid == DBW_SNAP_LAMBDA) ? "lambda" : "user"), ((DBWSnapToGrid == DBW_UNITS_LAMBDA) ? "lambda" : "user"),
TCL_VOLATILE); TCL_VOLATILE);
#else #else
TxPrintf("%s\n", (DBWSnapToGrid == DBW_SNAP_INTERNAL) ? "internal" : TxPrintf("%s\n", (DBWSnapToGrid == DBW_UNITS_INTERNAL) ? "internal" :
((DBWSnapToGrid == DBW_SNAP_LAMBDA) ? "lambda" : "user")); ((DBWSnapToGrid == DBW_UNITS_LAMBDA) ? "lambda" : "user"));
#endif #endif
else else
TxPrintf("Box is aligned to %s grid\n", TxPrintf("Box is aligned to %s grid\n",
(DBWSnapToGrid == DBW_SNAP_INTERNAL) ? "internal" : (DBWSnapToGrid == DBW_UNITS_INTERNAL) ? "internal" :
((DBWSnapToGrid == DBW_SNAP_LAMBDA) ? "lambda" : "user")); ((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 * lambda, a suffix of "g" indicates the user grid, and a suffix in metric
* notation ("nm", "um", "mm", "cm") indicates natural units. Other valid * notation ("nm", "um", "mm", "cm") indicates natural units. Other valid
* units are "cu" or "centimicrons" for centimicrons, or "microns" for um. * units are "cu" or "centimicrons" for centimicrons, or "microns" for um.
* Units without any suffix are assumed to be in lambda if "snap" * Traditional (backwards-compatible) behavior: Units without any suffix
* (DBWSnapToGrid) is set to lambda, grid units if "snap" is set to the * are assumed to be in lambda if "snap" (DBWSnapToGrid) is set to lambda,
* user grid, and internal units otherwise. * 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 * 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 * 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 int
cmdScaleCoord( cmdScaleCoord(
MagWindow *w, MagWindow *w,
@ -109,107 +129,195 @@ cmdScaleCoord(
{ {
char *endptr; char *endptr;
double dval = 0; double dval = 0;
int mscale = 1; int mscale = 1, curunits;
int retval, curval, parseop;
DBWclientRec *crec; DBWclientRec *crec;
if (*arg == '{') arg++; if (*arg == '{' || *arg == '"') arg++;
while (isspace(*arg)) arg++; while (isspace(*arg) && (*arg != '\0')) arg++;
dval = strtod(arg, &endptr); parseop = PARSEOP_NONE;
dval *= (double)scale; retval = 0;
while (*arg != '\0')
{
dval = strtod(arg, &endptr);
dval *= (double)scale;
mscale = -1;
if (endptr == arg) 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)
{ {
windCheckOnlyWindow(&w, DBWclientID); /* strtod() error condition */
if (w == (MagWindow *)NULL) TxError("Coordinate value cannot be parsed: assuming 0\n");
return round(dval); /* Default, if window is unknown */ curval = 0;
} 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;
} }
/* 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 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 /* lambda or default units */
- crec->dbw_gridRect.r_ybot); dval *= (double)DBLambda[1];
if (!is_relative) dval /= (double)DBLambda[0];
dval += (double)crec->dbw_gridRect.r_ybot;
} }
return round(dval); else if ((*endptr == 'i')
} || (((*endptr == '\0') || isspace(*endptr))
else && (curunits == DBW_UNITS_INTERNAL)))
{ {
/* natural units referred to the current cifoutput style */ /* internal units */
if (*(endptr + 1) == 'm') }
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) switch (*endptr)
{ {
case 'n': case '}':
mscale = 1; case '"':
parseop = PARSEOP_END;
break; break;
case 'u': case '+':
mscale = 1000; parseop = PARSEOP_ADD;
endptr++;
break; break;
case 'm': case '-':
mscale = 1000000; parseop = PARSEOP_SUB;
endptr++;
break; break;
case 'c': case '*':
mscale = 10000000; parseop = PARSEOP_MUL;
endptr++;
break;
case '/':
parseop = PARSEOP_DIV;
endptr++;
break;
case ' ':
case '\t':
endptr++;
break; break;
default: default:
TxError("Unknown metric prefix \"%cm\"; assuming internal units\n", /* Should this flag an error? */
*endptr); return retval;
return round(dval);
} }
if (parseop != PARSEOP_NONE) break;
} }
else if (!strcmp(endptr, "u")) arg = endptr;
/* Maybe "u" is too ambiguous but it is very commonly used as while (isspace(*arg) && (*arg != '\0')) arg++;
* 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);
}
} }
if (!isspace(*endptr)) return retval;
dval /= CIFGetOutputScale(mscale);
return round(dval);
} }
/* /*
@ -653,13 +761,16 @@ cmdSaveCell(
if (!tryRename || (fileName == NULL) || (strcmp(cellDef->cd_name, fileName) == 0)) if (!tryRename || (fileName == NULL) || (strcmp(cellDef->cd_name, fileName) == 0))
goto cleanup; goto cleanup;
/* Rename the cell */ /* Rename the cell, unless fileName is a .tcl file (scripted output) */
if (!DBCellRenameDef(cellDef, fileName)) if ((strlen(fileName) <= 4) || strcmp(fileName + strlen(fileName) - 4, ".tcl"))
{ {
/* This should never happen */ if (!DBCellRenameDef(cellDef, fileName))
TxError("Magic error: there is already a cell named \"%s\"\n", {
/* This should never happen */
TxError("Magic error: there is already a cell named \"%s\"\n",
fileName); fileName);
goto cleanup; goto cleanup;
}
} }
if (EditCellUse && (cellDef == EditCellUse->cu_def)) if (EditCellUse && (cellDef == EditCellUse->cu_def))

View File

@ -61,7 +61,9 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
int int
existFunc( existFunc(
Tile *tile) Tile *tile, /* (unused) */
TileType dinfo, /* (unused) */
ClientData clientdata) /* (unused) */
{ {
return 1; return 1;
} }
@ -453,15 +455,18 @@ CmdTech(
} }
if (!strncmp(cmd->tx_argv[2], "width", 5)) if (!strncmp(cmd->tx_argv[2], "width", 5))
{ {
char *techwidth;
tresult = DRCGetDefaultLayerWidth(t1); tresult = DRCGetDefaultLayerWidth(t1);
techwidth = DBWPrintValue(tresult, w, TRUE);
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult)); Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techwidth, -1));
#else #else
TxPrintf("Minimum width is %d\n", tresult); TxPrintf("Minimum width is %s\n", techwidth);
#endif #endif
} }
else if (!strncmp(cmd->tx_argv[2], "spac", 4)) else if (!strncmp(cmd->tx_argv[2], "spac", 4))
{ {
char *techspace;
if (cmd->tx_argc >= 5) if (cmd->tx_argc >= 5)
{ {
t2 = DBTechNoisyNameType(cmd->tx_argv[4]); t2 = DBTechNoisyNameType(cmd->tx_argv[4]);
@ -473,14 +478,16 @@ CmdTech(
else else
t2 = t1; t2 = t1;
tresult = DRCGetDefaultLayerSpacing(t1, t2); tresult = DRCGetDefaultLayerSpacing(t1, t2);
techspace = DBWPrintValue(tresult, w, TRUE);
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult)); Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techspace, -1));
#else #else
TxPrintf("Minimum spacing is %d\n", tresult); TxPrintf("Minimum spacing is %s\n", techspace);
#endif #endif
} }
else if (!strncmp(cmd->tx_argv[2], "surr", 4)) else if (!strncmp(cmd->tx_argv[2], "surr", 4))
{ {
char *techsurround;
if (cmd->tx_argc >= 5) if (cmd->tx_argc >= 5)
{ {
t2 = DBTechNoisyNameType(cmd->tx_argv[4]); t2 = DBTechNoisyNameType(cmd->tx_argv[4]);
@ -496,14 +503,17 @@ CmdTech(
} }
tresult = DRCGetDefaultLayerSurround(t1, t2); tresult = DRCGetDefaultLayerSurround(t1, t2);
techsurround = DBWPrintValue(tresult, w, TRUE);
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult)); Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techsurround, -1));
#else #else
TxPrintf("Minimum surround is %d\n", tresult); TxPrintf("Minimum surround is %s\n", techsurround);
#endif #endif
} }
else if (!strncmp(cmd->tx_argv[2], "direc", 5)) else if (!strncmp(cmd->tx_argv[2], "direc", 5))
{ {
char *techdirec;
if (cmd->tx_argc >= 5) if (cmd->tx_argc >= 5)
{ {
t2 = DBTechNoisyNameType(cmd->tx_argv[4]); t2 = DBTechNoisyNameType(cmd->tx_argv[4]);
@ -519,10 +529,11 @@ CmdTech(
} }
tresult = DRCGetDirectionalLayerSurround(t1, t2); tresult = DRCGetDirectionalLayerSurround(t1, t2);
techdirec = DBWPrintValue(tresult, w, TRUE);
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult)); Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techdirec, -1));
#else #else
TxPrintf("Minimum surround (in one orientation) is %d\n", tresult); TxPrintf("Minimum surround (in one orientation) is %s\n", techdirec);
#endif #endif
} }
} }
@ -752,6 +763,182 @@ cmdUnexpandFunc(
return 0; 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]);
}
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -839,7 +1026,8 @@ struct linked_id {
int int
cmdWhatPrintCell( cmdWhatPrintCell(
Tile *tile, Tile *tile, /* (unused) */
TileType dinfo, /* (unused) */
TreeContext *cxp) TreeContext *cxp)
{ {
struct linked_id **lid = (struct linked_id **)cxp->tc_filter->tf_arg; struct linked_id **lid = (struct linked_id **)cxp->tc_filter->tf_arg;
@ -894,6 +1082,7 @@ static LabelStore *labelBlockTop, *labelEntry;
int int
cmdFindWhatTileFunc( cmdFindWhatTileFunc(
Tile *tile, Tile *tile,
TileType dinfo,
ClientData clientData) ClientData clientData)
{ {
struct linked_id **lid = (struct linked_id **)clientData; struct linked_id **lid = (struct linked_id **)clientData;
@ -905,7 +1094,7 @@ cmdFindWhatTileFunc(
scx.scx_use = EditCellUse; scx.scx_use = EditCellUse;
scx.scx_trans = GeoIdentityTransform; scx.scx_trans = GeoIdentityTransform;
if (SplitSide(tile)) if (dinfo & TT_SIDE)
type = SplitRightType(tile); type = SplitRightType(tile);
else else
type = SplitLeftType(tile); type = SplitLeftType(tile);
@ -1692,18 +1881,20 @@ CmdWire(
case VALUES: case VALUES:
if (locargc == 2) if (locargc == 2)
{ {
char *wdisp;
width = WireGetWidth(); width = WireGetWidth();
type = WireGetType(); type = WireGetType();
wdisp = DBWPrintValue(width, w, TRUE);
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
lobj = Tcl_NewListObj(0, NULL); lobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(width));
Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(DBTypeLongNameTbl[type], -1)); Tcl_NewStringObj(DBTypeLongNameTbl[type], -1));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(wdisp, -1));
Tcl_SetObjResult(magicinterp, lobj); Tcl_SetObjResult(magicinterp, lobj);
#else #else
TxPrintf("Wire layer %s, width %d\n", TxPrintf("Wire layer %s, width %s\n",
DBTypeLongNameTbl[type], width); DBTypeLongNameTbl[type], wdisp);
#endif #endif
} }
break; break;
@ -1728,12 +1919,14 @@ CmdWire(
case WIDTH: case WIDTH:
if (locargc == 2) if (locargc == 2)
{ {
char *wdisp;
width = WireGetWidth(); width = WireGetWidth();
wdisp = DBWPrintValue(width, w, TRUE);
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
lobj = Tcl_NewIntObj(width); lobj = Tcl_NewStringObj(wdisp, -1);
Tcl_SetObjResult(magicinterp, lobj); Tcl_SetObjResult(magicinterp, lobj);
#else #else
TxPrintf("Wire width is %d\n", width); TxPrintf("Wire width is %s\n", wdisp);
#endif #endif
} }
else if (locargc != 3) else if (locargc != 3)

View File

@ -211,7 +211,8 @@ CmdExtractTest(
int int
tileCountProc( tileCountProc(
Tile *tile, Tile *tile, /* (unused) */
TileType dinfo, /* (unused) */
int *tcount) int *tcount)
{ {
(*tcount)++; (*tcount)++;
@ -800,11 +801,13 @@ cmdStatsCount(
CellDef *def, CellDef *def,
struct countClient *cc) struct countClient *cc)
{ {
int cmdStatsCountTile(Tile *tile, struct cellInfo *ci);
int pNum; int pNum;
struct cellInfo *ci; struct cellInfo *ci;
TileType t; TileType t;
/* Forward declaration */
int cmdStatsCountTile(Tile *tile, TileType dinfo, struct cellInfo *ci);
if (def->cd_client) if (def->cd_client)
return (1); return (1);
@ -829,6 +832,7 @@ cmdStatsCount(
int int
cmdStatsCountTile( cmdStatsCountTile(
Tile *tile, Tile *tile,
TileType dinfo, /* (unused) */
struct cellInfo *ci) struct cellInfo *ci)
{ {
TileType type = TiGetType(tile); TileType type = TiGetType(tile);
@ -1099,17 +1103,18 @@ CmdTsearch(
MagWindow *w, MagWindow *w,
TxCommand *cmd) TxCommand *cmd)
{ {
int cmdTsrFunc(Tile *tp);
char *RunStats(int flags, struct tms *lastt, struct tms *deltat);
char *rstatp; char *rstatp;
static TileTypeBitMask mask; static TileTypeBitMask mask;
static struct tms tlast, tdelta; static struct tms tlast, tdelta;
Rect rtool, rsearch; Rect rtool, rsearch;
/**** Rect *ebox; ****/
Plane *plane; Plane *plane;
int i, pNum, count; int i, pNum, count;
int usPerSearch, usPerTile, usPerL2, us, boxarea; int usPerSearch, usPerTile, usPerL2, us, boxarea;
/* Forward declarations */
int cmdTsrFunc(Tile *tp, TileType dinfo, ClientData clientdata);
char *RunStats(int flags, struct tms *lastt, struct tms *deltat);
if (cmd->tx_argc < 3 || cmd->tx_argc > 5) if (cmd->tx_argc < 3 || cmd->tx_argc > 5)
{ {
TxError("Usage: tsearch plane count [mask [new|mayo]]\n"); TxError("Usage: tsearch plane count [mask [new|mayo]]\n");
@ -1209,7 +1214,9 @@ CmdTsearch(
int int
cmdTsrFunc( cmdTsrFunc(
Tile *tp) Tile *tp,
TileType dinfo, /* (unused) */
ClientData clientdata) /* (unused) */
{ {
if (cmdTsearchDebug) if (cmdTsearchDebug)
TxPrintf("%lx\n", (intptr_t) tp); TxPrintf("%lx\n", (intptr_t) tp);

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 cmdSaveCell(CellDef *cellDef, char *newName, bool noninteractive, bool tryRename);
extern void CmdInit(void); 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); extern void CmdPaintEraseButton(MagWindow *w, Point *refPoint, bool isPaint, bool isScreen);
#endif /* _MAGIC__COMMANDS__COMMANDS_H */ #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 "windows/windows.h"
#include "dbwind/dbwind.h" #include "dbwind/dbwind.h"
#include "commands/commands.h" #include "commands/commands.h"
/* C99 compat */
#include "graphics/graphics.h" #include "graphics/graphics.h"
#include "cif/CIFint.h"
/* /*
* The following variable points to the tables currently used for * The following variable points to the tables currently used for
@ -357,9 +356,43 @@ DBCellCheckCopyAllPaint(scx, mask, xMask, targetUse, func)
struct propUseDefStruct { struct propUseDefStruct {
CellDef *puds_source; CellDef *puds_source;
CellDef *puds_dest; CellDef *puds_dest;
Plane *puds_plane; /* Mask hint plane in dest */
Transform *puds_trans; /* Transform from source use to 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 int
dbCopyMaskHintsFunc(key, value, puds) dbCopyMaskHintsFunc(key, proprec, puds)
char *key; char *key;
ClientData value; PropertyRecord *proprec;
struct propUseDefStruct *puds; struct propUseDefStruct *puds;
{ {
CellDef *dest = puds->puds_dest; CellDef *dest = puds->puds_dest;
Transform *trans = puds->puds_trans; Transform *trans = puds->puds_trans;
char *propstr = (char *)value; Rect *clip = puds->puds_area;
PropertyRecord *parentproprec, *newproprec;
char *parentprop, *newvalue, *vptr; char *parentprop, *newvalue, *vptr;
Rect r, rnew; Rect r, rnew;
bool propfound; bool propfound;
int i, j;
if (!strncmp(key, "MASKHINTS_", 10)) if (!strncmp(key, "MASKHINTS_", 10))
{ {
char *vptr, *lastval; char *vptr, *lastval;
int lastlen; int lastlen;
Plane *plane;
/* Append to existing mask hint (if any) */ ASSERT(proprec->prop_type == PROPERTY_TYPE_PLANE, "dbCopyMaskHintsFunc");
parentprop = (char *)DBPropGet(dest, key, &propfound);
newvalue = (propfound) ? StrDup((char **)NULL, parentprop) : (char *)NULL;
vptr = propstr; /* Get the existing mask hint plane in the parent cell, and
while (*vptr != '\0') * 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, newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
&r.r_xtop, &r.r_ytop) == 4) newproprec->prop_type = PROPERTY_TYPE_PLANE;
{ newproprec->prop_len = 0;
GeoTransRect(trans, &r, &rnew); plane = DBNewPlane((ClientData)TT_SPACE);
newproprec->prop_value.prop_plane = plane;
lastval = newvalue; DBPropPut(dest, key, newproprec);
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;
} }
if (newvalue) puds->puds_plane = plane;
DBPropPut(dest, key, newvalue);
}
/* 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; return 0;
} }
@ -468,6 +490,7 @@ DBCellCopyMaskHints(child, parent, transform)
puds.puds_source = child->cu_def; puds.puds_source = child->cu_def;
puds.puds_dest = parent; puds.puds_dest = parent;
puds.puds_trans = transform; puds.puds_trans = transform;
puds.puds_area = (Rect *)&TiPlaneRect;
DBPropEnum(child->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds); DBPropEnum(child->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
} }
@ -501,6 +524,7 @@ dbFlatCopyMaskHintsFunc(scx, def)
puds.puds_source = scx->scx_use->cu_def; puds.puds_source = scx->scx_use->cu_def;
puds.puds_dest = def; puds.puds_dest = def;
puds.puds_trans = &scx->scx_trans; puds.puds_trans = &scx->scx_trans;
puds.puds_area = &scx->scx_area;
DBPropEnum(use->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds); DBPropEnum(use->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
@ -967,14 +991,15 @@ DBCellGenerateSimpleSubstrate(scx, subType, notSubMask, targetDef)
*/ */
int int
dbEraseSubFunc(tile, cxp) dbEraseSubFunc(tile, dinfo, cxp)
Tile *tile; /* Pointer to source tile with shield type */ Tile *tile; /* Pointer to source tile with shield type */
TileType dinfo; /* Split tile information */
TreeContext *cxp; /* Context from DBTreeSrTiles */ TreeContext *cxp; /* Context from DBTreeSrTiles */
{ {
SearchContext *scx; SearchContext *scx;
Rect sourceRect, targetRect; Rect sourceRect, targetRect;
int pNum; int pNum;
TileType dinfo, loctype, subType; TileType newdinfo, loctype, subType;
Plane *plane; Plane *plane;
struct dbCopySubData *csd; /* Client data */ struct dbCopySubData *csd; /* Client data */
@ -983,13 +1008,14 @@ dbEraseSubFunc(tile, cxp)
plane = csd->csd_plane; plane = csd->csd_plane;
pNum = csd->csd_pNum; pNum = csd->csd_pNum;
subType = csd->csd_subtype; subType = csd->csd_subtype;
dinfo = TiGetTypeExact(tile);
if (IsSplit(tile)) if (IsSplit(tile))
{ {
loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); loctype = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
if (loctype == TT_SPACE) return 0; if (loctype == TT_SPACE) return 0;
dinfo = DBTransformDiagonal(dinfo, &scx->scx_trans); newdinfo = DBTransformDiagonal(TiGetTypeExact(tile) | dinfo, &scx->scx_trans);
} }
else
newdinfo = (TileType)0;
/* Construct the rect for the tile */ /* Construct the rect for the tile */
TITORECT(tile, &sourceRect); TITORECT(tile, &sourceRect);
@ -999,7 +1025,7 @@ dbEraseSubFunc(tile, cxp)
csd->csd_modified = TRUE; csd->csd_modified = TRUE;
return DBNMPaintPlane(plane, dinfo, &targetRect, DBStdEraseTbl(subType, pNum), return DBNMPaintPlane(plane, newdinfo, &targetRect, DBStdEraseTbl(subType, pNum),
(PaintUndoInfo *)NULL); (PaintUndoInfo *)NULL);
} }
@ -1011,14 +1037,15 @@ dbEraseSubFunc(tile, cxp)
*/ */
int int
dbPaintSubFunc(tile, cxp) dbPaintSubFunc(tile, dinfo, cxp)
Tile *tile; /* Pointer to source tile with shield type */ Tile *tile; /* Pointer to source tile with shield type */
TileType dinfo; /* Split tile information */
TreeContext *cxp; /* Context from DBTreeSrTiles */ TreeContext *cxp; /* Context from DBTreeSrTiles */
{ {
SearchContext *scx; SearchContext *scx;
Rect sourceRect, targetRect; Rect sourceRect, targetRect;
int pNum; int pNum;
TileType dinfo, loctype, subType; TileType newdinfo, loctype, subType;
Plane *plane; Plane *plane;
struct dbCopySubData *csd; /* Client data */ struct dbCopySubData *csd; /* Client data */
@ -1027,13 +1054,14 @@ dbPaintSubFunc(tile, cxp)
plane = csd->csd_plane; plane = csd->csd_plane;
pNum = csd->csd_pNum; pNum = csd->csd_pNum;
subType = csd->csd_subtype; subType = csd->csd_subtype;
dinfo = TiGetTypeExact(tile);
if (IsSplit(tile)) if (IsSplit(tile))
{ {
loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); loctype = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
if (loctype == TT_SPACE) return 0; if (loctype == TT_SPACE) return 0;
dinfo = DBTransformDiagonal(dinfo, &scx->scx_trans); newdinfo = DBTransformDiagonal(TiGetTypeExact(tile) | dinfo, &scx->scx_trans);
} }
else
newdinfo = (TileType)0;
/* Construct the rect for the tile */ /* Construct the rect for the tile */
TITORECT(tile, &sourceRect); TITORECT(tile, &sourceRect);
@ -1043,7 +1071,7 @@ dbPaintSubFunc(tile, cxp)
csd->csd_modified = TRUE; csd->csd_modified = TRUE;
return DBNMPaintPlane(plane, dinfo, &targetRect, DBStdPaintTbl(subType, pNum), return DBNMPaintPlane(plane, newdinfo, &targetRect, DBStdPaintTbl(subType, pNum),
(PaintUndoInfo *)NULL); (PaintUndoInfo *)NULL);
} }
@ -1056,14 +1084,15 @@ dbPaintSubFunc(tile, cxp)
*/ */
int int
dbEraseNonSub(tile, cxp) dbEraseNonSub(tile, dinfo, cxp)
Tile *tile; /* Pointer to tile to erase from target */ Tile *tile; /* Pointer to tile to erase from target */
TileType dinfo; /* Split tile information */
TreeContext *cxp; /* Context from DBTreeSrTiles */ TreeContext *cxp; /* Context from DBTreeSrTiles */
{ {
SearchContext *scx; SearchContext *scx;
Rect sourceRect, targetRect; Rect sourceRect, targetRect;
Plane *plane; /* Plane of target data */ Plane *plane; /* Plane of target data */
TileType dinfo, loctype, subType; TileType newdinfo, loctype, subType;
struct dbCopySubData *csd; struct dbCopySubData *csd;
int pNum; int pNum;
@ -1074,13 +1103,14 @@ dbEraseNonSub(tile, cxp)
scx = cxp->tc_scx; scx = cxp->tc_scx;
dinfo = TiGetTypeExact(tile);
if (IsSplit(tile)) if (IsSplit(tile))
{ {
loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); loctype = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
if (loctype == TT_SPACE) return 0; if (loctype == TT_SPACE) return 0;
dinfo = DBTransformDiagonal(dinfo, &scx->scx_trans); newdinfo = DBTransformDiagonal(TiGetTypeExact(tile) | dinfo, &scx->scx_trans);
} }
else
newdinfo = (TileType)0;
/* Construct the rect for the tile */ /* Construct the rect for the tile */
TITORECT(tile, &sourceRect); TITORECT(tile, &sourceRect);
@ -1089,7 +1119,7 @@ dbEraseNonSub(tile, cxp)
GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect); GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect);
/* Erase the substrate type from the area of this tile in the target plane. */ /* Erase the substrate type from the area of this tile in the target plane. */
return DBNMPaintPlane(plane, dinfo, &targetRect, DBStdEraseTbl(subType, pNum), return DBNMPaintPlane(plane, newdinfo, &targetRect, DBStdEraseTbl(subType, pNum),
(PaintUndoInfo *)NULL); (PaintUndoInfo *)NULL);
} }
@ -1101,8 +1131,9 @@ dbEraseNonSub(tile, cxp)
*/ */
int int
dbCopySubFunc(tile, csd) dbCopySubFunc(tile, dinfo, csd)
Tile *tile; /* Pointer to tile to erase from target */ Tile *tile; /* Pointer to tile to erase from target */
TileType dinfo; /* Split tile information */
struct dbCopySubData *csd; /* Client data */ struct dbCopySubData *csd; /* Client data */
{ {
Rect rect; Rect rect;
@ -1112,10 +1143,10 @@ dbCopySubFunc(tile, csd)
plane = csd->csd_plane; plane = csd->csd_plane;
pNum = csd->csd_pNum; pNum = csd->csd_pNum;
type = TiGetTypeExact(tile); type = TiGetTypeExact(tile) | dinfo;
if (IsSplit(tile)) if (IsSplit(tile))
{ {
loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); loctype = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
if (loctype == TT_SPACE) return 0; if (loctype == TT_SPACE) return 0;
} }
else else
@ -1436,8 +1467,9 @@ DBCellCopyLabels(scx, mask, xMask, targetUse, pArea)
***/ ***/
int int
dbCopyManhattanPaint(tile, cxp) dbCopyManhattanPaint(tile, dinfo, cxp)
Tile *tile; /* Pointer to tile to copy */ Tile *tile; /* Pointer to tile to copy */
TileType dinfo; /* Split tile information */
TreeContext *cxp; /* Context from DBTreeSrTiles */ TreeContext *cxp; /* Context from DBTreeSrTiles */
{ {
SearchContext *scx = cxp->tc_scx; SearchContext *scx = cxp->tc_scx;
@ -1483,8 +1515,9 @@ dbCopyManhattanPaint(tile, cxp)
***/ ***/
int int
dbCopyAllPaint(tile, cxp) dbCopyAllPaint(tile, dinfo, cxp)
Tile *tile; /* Pointer to tile to copy */ Tile *tile; /* Pointer to tile to copy */
TileType dinfo; /* Split tile information */
TreeContext *cxp; /* Context from DBTreeSrTiles */ TreeContext *cxp; /* Context from DBTreeSrTiles */
{ {
SearchContext *scx = cxp->tc_scx; SearchContext *scx = cxp->tc_scx;
@ -1492,7 +1525,7 @@ dbCopyAllPaint(tile, cxp)
Rect sourceRect, targetRect; Rect sourceRect, targetRect;
PaintUndoInfo ui; PaintUndoInfo ui;
CellDef *def; CellDef *def;
TileType type = TiGetTypeExact(tile); TileType type = TiGetTypeExact(tile) | dinfo;
int pNum = cxp->tc_plane; int pNum = cxp->tc_plane;
int result; int result;
TileTypeBitMask *typeMask; TileTypeBitMask *typeMask;
@ -1505,13 +1538,13 @@ dbCopyAllPaint(tile, cxp)
*/ */
bool splittile = FALSE; bool splittile = FALSE;
TileType dinfo = 0; TileType newdinfo = 0;
if (IsSplit(tile)) if (IsSplit(tile))
{ {
splittile = TRUE; splittile = TRUE;
dinfo = DBTransformDiagonal(type, &scx->scx_trans); newdinfo = DBTransformDiagonal(type, &scx->scx_trans);
type = (SplitSide(tile)) ? SplitRightType(tile) : type = (dinfo & TT_SIDE) ? SplitRightType(tile) :
SplitLeftType(tile); SplitLeftType(tile);
} }
@ -1571,7 +1604,7 @@ dbCopyAllPaint(tile, cxp)
Rect rrect, orect; Rect rrect, orect;
int np, i, j; int np, i, j;
GrClipTriangle(&targetRect, &arg->caa_rect, TRUE, dinfo, points, &np); GrClipTriangle(&targetRect, &arg->caa_rect, TRUE, newdinfo, points, &np);
if (np == 0) if (np == 0)
return(0); return(0);
@ -1600,7 +1633,7 @@ dbCopyAllPaint(tile, cxp)
rrect.r_ybot = points[0].p_y; rrect.r_ybot = points[0].p_y;
rrect.r_ytop = points[2].p_y; rrect.r_ytop = points[2].p_y;
GeoCanonicalRect(&rrect, &targetRect); GeoCanonicalRect(&rrect, &targetRect);
dinfo = 0; newdinfo = 0;
} }
else if (np >= 4) /* Process extra rectangles in the area */ else if (np >= 4) /* Process extra rectangles in the area */
{ {
@ -1657,7 +1690,7 @@ topbottom:
splitdone: splitdone:
result = (*dbCurPaintPlane)(def, pNum, dinfo | type, &targetRect, &ui); result = (*dbCurPaintPlane)(def, pNum, newdinfo | type, &targetRect, &ui);
if ((result != 0) && (arg->caa_func != NULL)) if ((result != 0) && (arg->caa_func != NULL))
{ {
/* result == 1 used exclusively for DRC off-grid error flagging */ /* result == 1 used exclusively for DRC off-grid error flagging */

View File

@ -152,10 +152,9 @@ DBCellRename(cellname, newname, doforce)
if (doforce && ((celldef->cd_flags & CDVENDORGDS) == CDVENDORGDS)) if (doforce && ((celldef->cd_flags & CDVENDORGDS) == CDVENDORGDS))
{ {
char *chkgdsfile;
bool isReadOnly; bool isReadOnly;
chkgdsfile = (char *)DBPropGet(celldef, "GDS_FILE", &isReadOnly); DBPropGet(celldef, "GDS_FILE", &isReadOnly);
/* Note that clearing GDS_FILE will also clear CDVENDORGDS flag */ /* Note that clearing GDS_FILE will also clear CDVENDORGDS flag */
if (isReadOnly) DBPropPut(celldef, "GDS_FILE", NULL); if (isReadOnly) DBPropPut(celldef, "GDS_FILE", NULL);
@ -1620,7 +1619,9 @@ dbAbutmentUseFunc(selUse, use, transform, data)
{ {
Rect bbox, refbox; Rect bbox, refbox;
Transform *trans; Transform *trans;
PropertyRecord *proprec;
char *propvalue; char *propvalue;
char *refllx, *reflly, *refurx, *refury;
bool found; bool found;
bool *dolist = (bool *)data; bool *dolist = (bool *)data;
@ -1642,32 +1643,47 @@ dbAbutmentUseFunc(selUse, use, transform, data)
} }
trans = &use->cu_transform; trans = &use->cu_transform;
propvalue = (char *)DBPropGet(use->cu_def, "FIXED_BBOX", &found); proprec = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
if (!found) if (!found)
bbox = use->cu_def->cd_bbox; bbox = use->cu_def->cd_bbox;
else else
{ {
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot, if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
&bbox.r_xtop, &bbox.r_ytop) != 4) (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; bbox = use->cu_def->cd_bbox;
}
} }
GeoTransRect(trans, &bbox, &refbox); 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 #ifdef MAGIC_WRAPPER
if (*dolist) if (*dolist)
{ {
pobj = Tcl_NewListObj(0, NULL); pobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_xbot)); Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(refllx, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_ybot)); Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(reflly, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_xtop)); Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(refurx, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_ytop)); Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(refury, -1));
Tcl_SetObjResult(magicinterp, pobj); Tcl_SetObjResult(magicinterp, pobj);
} }
else else
#endif #endif
TxPrintf("Abutment box: %d %d %d %d\n", refbox.r_xbot, refbox.r_ybot, TxPrintf("Abutment box: %s %s %s %s\n", refllx, reflly, refurx, refury);
refbox.r_xtop, refbox.r_ytop);
return 0; return 0;
} }

View File

@ -120,6 +120,7 @@ DBSrCellPlaneArea(BPlane *plane, const Rect *rect, int (*func)(), ClientData arg
* int * int
* func(tile, cxp) * func(tile, cxp)
* Tile *tile; * Tile *tile;
* TileType dinfo;
* TreeContext *cxp; * TreeContext *cxp;
* { * {
* } * }
@ -416,6 +417,7 @@ dbCellUniqueTileSrFunc(scx, fp)
* int * int
* func(tile, cxp) * func(tile, cxp)
* Tile *tile; * Tile *tile;
* TileType dinfo;
* TreeContext *cxp; * TreeContext *cxp;
* { * {
* } * }
@ -914,8 +916,9 @@ DBSeeTypesAll(rootUse, rootRect, xMask, mask)
*/ */
int int
dbSeeTypesAllSrFunc(tile, cxp) dbSeeTypesAllSrFunc(tile, dinfo, cxp)
Tile *tile; Tile *tile;
TileType dinfo;
TreeContext *cxp; TreeContext *cxp;
{ {
Rect tileRect; Rect tileRect;
@ -926,7 +929,7 @@ dbSeeTypesAllSrFunc(tile, cxp)
if (GEO_OVERLAP((&tileRect), area)) if (GEO_OVERLAP((&tileRect), area))
{ {
if (IsSplit(tile)) if (IsSplit(tile))
TTMaskSetType(mask, SplitSide(tile) ? TTMaskSetType(mask, (dinfo & TT_SIDE) ?
SplitRightType(tile) : SplitLeftType(tile)); SplitRightType(tile) : SplitLeftType(tile));
else else
TTMaskSetType(mask, TiGetType(tile)); TTMaskSetType(mask, TiGetType(tile));
@ -1607,8 +1610,9 @@ dbScalePlane(oldplane, newplane, pnum, scalen, scaled, doCIF)
*/ */
int int
dbTileScaleFunc(tile, scvals) dbTileScaleFunc(tile, dinfo, scvals)
Tile *tile; Tile *tile;
TileType dinfo;
struct scaleArg *scvals; struct scaleArg *scvals;
{ {
TileType type; TileType type;
@ -1631,10 +1635,10 @@ dbTileScaleFunc(tile, scvals)
return 0; return 0;
} }
type = TiGetTypeExact(tile); type = TiGetTypeExact(tile) | dinfo;
exact = type; exact = type;
if (IsSplit(tile)) if (IsSplit(tile))
type = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
DBNMPaintPlane(scvals->ptarget, exact, &targetRect, DBNMPaintPlane(scvals->ptarget, exact, &targetRect,
( (
#ifdef CIF_MODULE #ifdef CIF_MODULE
@ -1689,8 +1693,9 @@ dbMovePlane(oldplane, newplane, pnum, origx, origy)
*/ */
int int
dbTileMoveFunc(tile, mvvals) dbTileMoveFunc(tile, dinfo, mvvals)
Tile *tile; Tile *tile;
TileType dinfo;
struct moveArg *mvvals; struct moveArg *mvvals;
{ {
TileType type; TileType type;
@ -1703,12 +1708,12 @@ dbTileMoveFunc(tile, mvvals)
DBMovePoint(&targetRect.r_ll, mvvals->origx, mvvals->origy); DBMovePoint(&targetRect.r_ll, mvvals->origx, mvvals->origy);
DBMovePoint(&targetRect.r_ur, mvvals->origx, mvvals->origy); DBMovePoint(&targetRect.r_ur, mvvals->origx, mvvals->origy);
type = TiGetTypeExact(tile); type = TiGetTypeExact(tile) | dinfo;
exact = type; exact = type;
if (IsSplit(tile)) if (IsSplit(tile))
type = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
DBNMPaintPlane(mvvals->ptarget, exact, &targetRect, DBNMPaintPlane(mvvals->ptarget, exact, &targetRect,
DBStdPaintTbl(type, mvvals->pnum), (mvvals->pnum < 0) ? CIFPaintTable : DBStdPaintTbl(type, mvvals->pnum),
(PaintUndoInfo *)NULL); (PaintUndoInfo *)NULL);
return 0; return 0;
} }
@ -1801,84 +1806,48 @@ typedef struct _cellpropstruct {
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
int dbScaleProp(name, value, cps) int dbScaleProp(name, proprec, cps)
char *name; char *name;
char *value; PropertyRecord *proprec;
CellPropStruct *cps; CellPropStruct *cps;
{ {
int scalen, scaled; int i, scalen, scaled;
char *newvalue, *vptr; Point p;
Rect r;
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, Plane *newplane;
&r.r_xtop, &r.r_ytop) == 4) newplane = DBNewPlane((ClientData)TT_SPACE);
{ DBClearPaintPlane(newplane);
/* Scale numerator held in point X value, */ /* Plane index is unused; arbitrarily substitute -1 */
/* scale denominator held in point Y value */ dbScalePlane(proprec->prop_value.prop_plane, newplane, -1,
scalen, scaled, TRUE);
scalen = cps->cps_point.p_x; DBFreePaintPlane(proprec->prop_value.prop_plane);
scaled = cps->cps_point.p_y; TiFreePlane(proprec->prop_value.prop_plane);
proprec->prop_value.prop_plane = newplane;
DBScalePoint(&r.r_ll, scalen, scaled); return 0;
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);
}
} }
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; if ((i + 1) >= proprec->prop_len) break;
int lastlen;
newvalue = (char *)NULL; p.p_x = proprec->prop_value.prop_integer[i];
vptr = value; p.p_y = proprec->prop_value.prop_integer[i + 1];
while (*vptr != '\0') DBScalePoint(&p, scalen, scaled);
{ proprec->prop_value.prop_integer[i] = p.p_x;
if (sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot, proprec->prop_value.prop_integer[i + 1] = p.p_y;
&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);
} }
return 0; /* Keep enumerating through properties */ return 0; /* Keep enumerating through properties */
} }
@ -1894,33 +1863,47 @@ int dbScaleProp(name, value, cps)
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
int dbMoveProp(name, value, cps) int dbMoveProp(name, proprec, cps)
char *name; char *name;
char *value; PropertyRecord *proprec;
CellPropStruct *cps; CellPropStruct *cps;
{ {
int origx, origy; int i, origx, origy;
char *newvalue; char *newvalue;
Rect r; Point p;
if (((strlen(name) > 5) && !strncmp(name + strlen(name) - 5, "_BBOX", 5)) /* Only "dimension" and "plane" type properties get scaled */
|| !strncmp(name, "MASKHINTS_", 10))
if (proprec->prop_type == PROPERTY_TYPE_PLANE)
{ {
if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot, Plane *newplane;
&r.r_xtop, &r.r_ytop) == 4)
{
origx = cps->cps_point.p_x;
origy = cps->cps_point.p_y;
DBMovePoint(&r.r_ll, origx, origy); newplane = DBNewPlane((ClientData) TT_SPACE);
DBMovePoint(&r.r_ur, origx, origy); DBClearPaintPlane(newplane);
/* Use plane index -1 to indicate use of CIFPaintTable */
newvalue = (char *)mallocMagic(40); dbMovePlane(proprec->prop_value.prop_plane, newplane, -1, origx, origy);
sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot, DBFreePaintPlane(proprec->prop_value.prop_plane);
r.r_xtop, r.r_ytop); TiFreePlane(proprec->prop_value.prop_plane);
DBPropPut(cps->cps_def, name, newvalue); 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 */ return 0; /* Keep enumerating through properties */
} }

View File

@ -128,85 +128,6 @@ DBInvTransformDiagonal(oldtype, trans)
return dinfo; return dinfo;
} }
/*
* ----------------------------------------------------------------------------
*
* DBSrConnectOnePlane --
*
* Search from a starting tile to find all paint that is electrically
* connected to that tile in the same plane.
*
* Results:
* 0 is returned if the search finished normally. 1 is returned
* if the search was aborted.
*
* Side effects:
* For every paint tile that is electrically connected to the initial
* tile, func is called. Func should have the following form:
*
* int
* func(tile, clientData)
* Tile *tile;
* ClientData clientData;
* {
* }
*
* The clientData passed to func is the same one that was passed
* to us. Func returns 0 under normal conditions; if it returns
* 1 then the search is aborted.
*
* *** WARNING ***
*
* Func should not modify any paint during the search, since this
* will mess up pointers kept by these procedures and likely cause
* a core-dump.
*
* ----------------------------------------------------------------------------
*/
int
DBSrConnectOnePlane(startTile, connect, func, clientData)
Tile *startTile; /* Starting tile for search */
TileTypeBitMask *connect; /* Pointer to a table indicating what tile
* types connect to what other tile types.
* Each entry gives a mask of types that
* connect to tiles of a given type.
*/
int (*func)(); /* Function to apply at each connected tile. */
ClientData clientData; /* Client data for above function. */
{
struct conSrArg csa;
int result;
result = 0;
csa.csa_def = (CellDef *)NULL;
csa.csa_bounds = TiPlaneRect;
/* Pass 1. During this pass the client function gets called. */
csa.csa_clientFunc = func;
csa.csa_clientData = clientData;
csa.csa_clientDefault = startTile->ti_client;
csa.csa_clear = FALSE;
csa.csa_connect = connect;
csa.csa_pNum = -1;
if (dbSrConnectFunc(startTile, PTR2CD(&csa)) != 0) result = 1;
/* Pass 2. Don't call any client function, just clear the marks.
* Don't allow any interruptions.
*/
SigDisableInterrupts();
csa.csa_clientFunc = NULL;
csa.csa_clear = TRUE;
(void) dbSrConnectFunc(startTile, PTR2CD(&csa));
SigEnableInterrupts();
return result;
}
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -276,7 +197,7 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
{ {
struct conSrArg csa; struct conSrArg csa;
int startPlane, result; int startPlane, result;
Tile *startTile; /* Starting tile for search. */ TileAndDinfo start_tad; /* Starting tile and split information */
result = 0; result = 0;
csa.csa_def = def; csa.csa_def = def;
@ -287,17 +208,18 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
* the tile address and returns. * the tile address and returns.
*/ */
startTile = NULL; start_tad.tad_tile = NULL;
start_tad.tad_next = NULL; /* unused */
for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++) for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++)
{ {
csa.csa_pNum = startPlane; csa.csa_pNum = startPlane;
if (DBSrPaintArea((Tile *) NULL, if (DBSrPaintArea((Tile *) NULL,
def->cd_planes[startPlane], startArea, mask, def->cd_planes[startPlane], startArea, mask,
dbSrConnectStartFunc, PTR2CD(&startTile)) != 0) break; dbSrConnectStartFunc, PTR2CD(&start_tad)) != 0) break;
} }
if (startTile == NULL) return 0; if (start_tad.tad_tile == NULL) return 0;
/* The following lets us call DBSrConnect recursively */ /* The following lets us call DBSrConnect recursively */
else if (startTile->ti_client == (ClientData)1) return 0; else if (start_tad.tad_tile->ti_client == (ClientData)1) return 0;
/* Pass 1. During this pass the client function gets called. */ /* Pass 1. During this pass the client function gets called. */
@ -306,7 +228,8 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
csa.csa_clientDefault = CLIENTDEFAULT; csa.csa_clientDefault = CLIENTDEFAULT;
csa.csa_clear = FALSE; csa.csa_clear = FALSE;
csa.csa_connect = connect; csa.csa_connect = connect;
if (dbSrConnectFunc(startTile, PTR2CD(&csa)) != 0) result = 1; if (dbSrConnectFunc(start_tad.tad_tile, start_tad.tad_dinfo,
PTR2CD(&csa)) != 0) result = 1;
/* Pass 2. Don't call any client function, just clear the marks. /* Pass 2. Don't call any client function, just clear the marks.
* Don't allow any interruptions. * Don't allow any interruptions.
@ -315,7 +238,7 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
SigDisableInterrupts(); SigDisableInterrupts();
csa.csa_clientFunc = NULL; csa.csa_clientFunc = NULL;
csa.csa_clear = TRUE; csa.csa_clear = TRUE;
(void) dbSrConnectFunc(startTile, PTR2CD(&csa)); (void) dbSrConnectFunc(start_tad.tad_tile, start_tad.tad_dinfo, PTR2CD(&csa));
SigEnableInterrupts(); SigEnableInterrupts();
return result; return result;
@ -325,11 +248,12 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
int int
dbSrConnectStartFunc( dbSrConnectStartFunc(
Tile *tile, /* This will be the starting tile. */ Tile *tile, /* This will be the starting tile. */
ClientData cdata) /* We store tile's address here. */ TileType dinfo, /* (unused) */
/* (Tile **pTile) */ ClientData cdata) /* We store tile and split info here. */
{ {
Tile **pTile = (Tile **)CD2PTR(cdata); TileAndDinfo *tad = (TileAndDinfo *)CD2PTR(cdata);
*pTile = tile; tad->tad_tile = tile;
tad->tad_dinfo = dinfo;
return 1; return 1;
} }
@ -367,7 +291,7 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
{ {
struct conSrArg csa; struct conSrArg csa;
int startPlane, result; int startPlane, result;
Tile *startTile; /* Starting tile for search. */ TileAndDinfo tad;
result = 0; result = 0;
csa.csa_def = def; csa.csa_def = def;
@ -378,17 +302,18 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
* the tile address and returns. * the tile address and returns.
*/ */
startTile = NULL; tad.tad_tile = NULL;
tad.tad_next = NULL; /* unused */
for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++) for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++)
{ {
csa.csa_pNum = startPlane; csa.csa_pNum = startPlane;
if (DBSrPaintArea((Tile *) NULL, if (DBSrPaintArea((Tile *) NULL,
def->cd_planes[startPlane], startArea, mask, def->cd_planes[startPlane], startArea, mask,
dbSrConnectStartFunc, PTR2CD(&startTile)) != 0) break; dbSrConnectStartFunc, PTR2CD(&tad)) != 0) break;
} }
if (startTile == NULL) return 0; if (tad.tad_tile == NULL) return 0;
/* The following lets us call DBSrConnect recursively */ /* The following lets us call DBSrConnect recursively */
else if (startTile->ti_client == (ClientData)1) return 0; else if (tad.tad_tile->ti_client == (ClientData)1) return 0;
/* Pass 1. During this pass the client function gets called. */ /* Pass 1. During this pass the client function gets called. */
@ -397,7 +322,7 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
csa.csa_clientDefault = CLIENTDEFAULT; csa.csa_clientDefault = CLIENTDEFAULT;
csa.csa_clear = FALSE; csa.csa_clear = FALSE;
csa.csa_connect = connect; csa.csa_connect = connect;
if (dbSrConnectFunc(startTile, PTR2CD(&csa)) != 0) result = 1; if (dbSrConnectFunc(tad.tad_tile, tad.tad_dinfo, PTR2CD(&csa)) != 0) result = 1;
return result; return result;
} }
@ -420,12 +345,15 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
*/ */
int int
dbcFindTileFunc(tile, arg) dbcFindTileFunc(tile, dinfo, arg)
Tile *tile; Tile *tile;
TileType dinfo;
ClientData arg; ClientData arg;
{ {
Tile **tptr = (Tile **)arg; TileAndDinfo *tad = (TileAndDinfo *)arg;
*tptr = tile;
tad->tad_tile = tile;
tad->tad_dinfo = dinfo;
return 1; return 1;
} }
@ -465,6 +393,7 @@ dbcFindTileFunc(tile, arg)
int int
dbSrConnectFunc( dbSrConnectFunc(
Tile *tile, /* Tile that is connected. */ Tile *tile, /* Tile that is connected. */
TileType dinfo, /* Split tile information */
ClientData cdata) /* Contains information about the search. */ ClientData cdata) /* Contains information about the search. */
/* (struct conSrArg *csa) */ /* (struct conSrArg *csa) */
{ {
@ -484,11 +413,13 @@ dbSrConnectFunc(
/* Drop the first entry on the stack */ /* Drop the first entry on the stack */
pNum = csa->csa_pNum; pNum = csa->csa_pNum;
STACKPUSH(INT2CD(tile), dbConnectStack); STACKPUSH(INT2CD(tile), dbConnectStack);
STACKPUSH(INT2CD(dinfo), dbConnectStack);
STACKPUSH(INT2CD(pNum), dbConnectStack); STACKPUSH(INT2CD(pNum), dbConnectStack);
while (!StackEmpty(dbConnectStack)) while (!StackEmpty(dbConnectStack))
{ {
pNum = (int)CD2INT(STACKPOP(dbConnectStack)); pNum = (int)CD2INT(STACKPOP(dbConnectStack));
dinfo = (int)CD2INT(STACKPOP(dbConnectStack));
tile = (Tile *)CD2INT(STACKPOP(dbConnectStack)); tile = (Tile *)CD2INT(STACKPOP(dbConnectStack));
if (result == 1) continue; if (result == 1) continue;
@ -522,7 +453,7 @@ dbSrConnectFunc(
if (callClient && (csa->csa_clientFunc != NULL)) if (callClient && (csa->csa_clientFunc != NULL))
{ {
if ((*csa->csa_clientFunc)(tile, pNum, csa->csa_clientData) != 0) if ((*csa->csa_clientFunc)(tile, dinfo, pNum, csa->csa_clientData) != 0)
{ {
result = 1; result = 1;
continue; continue;
@ -536,7 +467,7 @@ dbSrConnectFunc(
if (IsSplit(tile)) if (IsSplit(tile))
{ {
if (SplitSide(tile)) if (dinfo & TT_SIDE)
loctype = SplitRightType(tile); loctype = SplitRightType(tile);
else else
loctype = SplitLeftType(tile); loctype = SplitLeftType(tile);
@ -547,7 +478,7 @@ dbSrConnectFunc(
/* Left side: */ /* Left side: */
if (IsSplit(tile) && SplitSide(tile)) goto bottomside; if (IsSplit(tile) && (dinfo & TT_SIDE)) goto bottomside;
for (t2 = BL(tile); BOTTOM(t2) < tileArea.r_ytop; t2 = RT(t2)) for (t2 = BL(tile); BOTTOM(t2) < tileArea.r_ytop; t2 = RT(t2))
{ {
@ -564,9 +495,11 @@ dbSrConnectFunc(
if (t2->ti_client == csa->csa_clientDefault) continue; if (t2->ti_client == csa->csa_clientDefault) continue;
} }
else if (t2->ti_client == (ClientData) 1) continue; else if (t2->ti_client == (ClientData) 1) continue;
if (IsSplit(t2))
TiSetBody(t2, INT2CD(CD2INT(t2->ti_body) | TT_SIDE)); /* bit set */
STACKPUSH(INT2CD(t2), dbConnectStack); STACKPUSH(INT2CD(t2), dbConnectStack);
if (IsSplit(t2))
STACKPUSH(INT2CD((TileType)TT_SIDE), dbConnectStack);
else
STACKPUSH(INT2CD(0), dbConnectStack);
STACKPUSH(INT2CD(pNum), dbConnectStack); STACKPUSH(INT2CD(pNum), dbConnectStack);
} }
} }
@ -574,7 +507,7 @@ dbSrConnectFunc(
/* Bottom side: */ /* Bottom side: */
bottomside: bottomside:
if (IsSplit(tile) && (!(SplitSide(tile) ^ SplitDirection(tile)))) if (IsSplit(tile) && ((!((dinfo & TT_SIDE) ? 1 : 0)) ^ SplitDirection(tile)))
goto rightside; goto rightside;
for (t2 = LB(tile); LEFT(t2) < tileArea.r_xtop; t2 = TR(t2)) for (t2 = LB(tile); LEFT(t2) < tileArea.r_xtop; t2 = TR(t2))
@ -592,16 +525,17 @@ bottomside:
if (t2->ti_client == csa->csa_clientDefault) continue; if (t2->ti_client == csa->csa_clientDefault) continue;
} }
else if (t2->ti_client == (ClientData) 1) continue; else if (t2->ti_client == (ClientData) 1) continue;
STACKPUSH(INT2CD(t2), dbConnectStack);
if (IsSplit(t2)) if (IsSplit(t2))
{ {
if (SplitDirection(t2)) if (SplitDirection(t2))
/* bit set */ STACKPUSH(INT2CD((TileType)TT_SIDE), dbConnectStack);
TiSetBody(t2, INT2CD(CD2INT(t2->ti_body) | TT_SIDE));
else else
/* bit clear */ /* bit clear */
TiSetBody(t2, INT2CD(CD2INT(t2->ti_body) & ~TT_SIDE)); STACKPUSH(INT2CD(0), dbConnectStack);
} }
STACKPUSH(INT2CD(t2), dbConnectStack); else
STACKPUSH(INT2CD(0), dbConnectStack);
STACKPUSH(INT2CD(pNum), dbConnectStack); STACKPUSH(INT2CD(pNum), dbConnectStack);
} }
} }
@ -609,7 +543,7 @@ bottomside:
/* Right side: */ /* Right side: */
rightside: rightside:
if (IsSplit(tile) && !SplitSide(tile)) goto topside; if (IsSplit(tile) && !(dinfo & TT_SIDE)) goto topside;
for (t2 = TR(tile); ; t2 = LB(t2)) for (t2 = TR(tile); ; t2 = LB(t2))
{ {
@ -626,9 +560,8 @@ rightside:
if (t2->ti_client == csa->csa_clientDefault) goto nextRight; if (t2->ti_client == csa->csa_clientDefault) goto nextRight;
} }
else if (t2->ti_client == (ClientData) 1) goto nextRight; else if (t2->ti_client == (ClientData) 1) goto nextRight;
if (IsSplit(t2))
TiSetBody(t2, INT2CD(CD2INT(t2->ti_body) & ~TT_SIDE)); /* bit clear */
STACKPUSH(INT2CD(t2), dbConnectStack); STACKPUSH(INT2CD(t2), dbConnectStack);
STACKPUSH(INT2CD(0), dbConnectStack);
STACKPUSH(INT2CD(pNum), dbConnectStack); STACKPUSH(INT2CD(pNum), dbConnectStack);
} }
nextRight: if (BOTTOM(t2) <= tileArea.r_ybot) break; nextRight: if (BOTTOM(t2) <= tileArea.r_ybot) break;
@ -637,7 +570,8 @@ rightside:
/* Top side: */ /* Top side: */
topside: topside:
if (IsSplit(tile) && (SplitSide(tile) ^ SplitDirection(tile))) goto donesides; if (IsSplit(tile) && (((dinfo & TT_SIDE) ? 1 : 0) ^ SplitDirection(tile)))
goto donesides;
for (t2 = RT(tile); ; t2 = BL(t2)) for (t2 = RT(tile); ; t2 = BL(t2))
{ {
@ -654,16 +588,18 @@ topside:
if (t2->ti_client == csa->csa_clientDefault) goto nextTop; if (t2->ti_client == csa->csa_clientDefault) goto nextTop;
} }
else if (t2->ti_client == (ClientData) 1) goto nextTop; else if (t2->ti_client == (ClientData) 1) goto nextTop;
STACKPUSH(INT2CD(t2), dbConnectStack);
if (IsSplit(t2)) if (IsSplit(t2))
{ {
if (SplitDirection(t2)) if (SplitDirection(t2))
/* bit clear */ /* bit clear */
TiSetBody(t2, INT2CD(CD2INT(t2->ti_body) & ~TT_SIDE)); STACKPUSH(INT2CD(0), dbConnectStack);
else else
/* bit set */ /* bit set */
TiSetBody(t2, INT2CD(CD2INT(t2->ti_body) | TT_SIDE)); STACKPUSH(INT2CD((TileType)TT_SIDE), dbConnectStack);
} }
STACKPUSH(INT2CD(t2), dbConnectStack); else
STACKPUSH(INT2CD(0), dbConnectStack);
STACKPUSH(INT2CD(pNum), dbConnectStack); STACKPUSH(INT2CD(pNum), dbConnectStack);
} }
nextTop: if (LEFT(t2) <= tileArea.r_xbot) break; nextTop: if (LEFT(t2) <= tileArea.r_xbot) break;
@ -682,6 +618,7 @@ donesides:
{ {
Rect newArea; Rect newArea;
GEO_EXPAND(&tileArea, 1, &newArea); GEO_EXPAND(&tileArea, 1, &newArea);
TileAndDinfo tad;
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++) for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
{ {
@ -689,18 +626,20 @@ donesides:
if (IsSplit(tile)) if (IsSplit(tile))
{ {
if (DBSrPaintNMArea((Tile *) NULL, csa->csa_def->cd_planes[i], if (DBSrPaintNMArea((Tile *) NULL, csa->csa_def->cd_planes[i],
TiGetTypeExact(tile), &newArea, connectMask, TiGetTypeExact(tile) | dinfo, &newArea, connectMask,
dbcFindTileFunc, (ClientData)&t2) != 0) dbcFindTileFunc, (ClientData)&tad) != 0)
{ {
STACKPUSH(INT2CD(t2), dbConnectStack); STACKPUSH(PTR2CD(tad.tad_tile), dbConnectStack);
STACKPUSH(INT2CD(tad.tad_dinfo), dbConnectStack);
STACKPUSH(INT2CD(i), dbConnectStack); STACKPUSH(INT2CD(i), dbConnectStack);
} }
} }
else if (DBSrPaintArea((Tile *) NULL, csa->csa_def->cd_planes[i], else if (DBSrPaintArea((Tile *) NULL, csa->csa_def->cd_planes[i],
&newArea, connectMask, dbcFindTileFunc, &newArea, connectMask, dbcFindTileFunc,
(ClientData)&t2) != 0) (ClientData)&tad) != 0)
{ {
STACKPUSH(INT2CD(t2), dbConnectStack); STACKPUSH(PTR2CD(tad.tad_tile), dbConnectStack);
STACKPUSH(INT2CD(tad.tad_dinfo), dbConnectStack);
STACKPUSH(INT2CD(i), dbConnectStack); STACKPUSH(INT2CD(i), dbConnectStack);
} }
} }
@ -734,9 +673,10 @@ donesides:
/** @typedef cb_database_srpaintnmarea_t */ /** @typedef cb_database_srpaintnmarea_t */
/** @typedef cb_database_srpaintarea_t */ /** @typedef cb_database_srpaintarea_t */
int int
dbcUnconnectFunc(tile, clientData) dbcUnconnectFunc(tile, dinfo, clientData)
Tile *tile; /* Current tile */ Tile *tile; /* Current tile */
ClientData clientData; /* Unused. */ TileType dinfo; /* Split tile information, unused */
ClientData clientData; /* Unused. */
{ {
return 1; return 1;
@ -949,8 +889,9 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
*/ */
int int
dbcConnectFunc(tile, cx) dbcConnectFunc(tile, dinfo, cx)
Tile *tile; /* Tile found. */ Tile *tile; /* Tile found. */
TileType dinfo; /* Split tile information */
TreeContext *cx; /* Describes context of search. The client TreeContext *cx; /* Describes context of search. The client
* data is a pointer to a conSrArg2 record * data is a pointer to a conSrArg2 record
* containing various required information. * containing various required information.
@ -963,8 +904,8 @@ dbcConnectFunc(tile, cx)
Rect *srArea; Rect *srArea;
SearchContext *scx = cx->tc_scx; SearchContext *scx = cx->tc_scx;
SearchContext scx2; SearchContext scx2;
TileType loctype = TiGetTypeExact(tile); TileType loctype = TiGetTypeExact(tile) | dinfo;
TileType dinfo = 0; TileType newdinfo = 0;
int retval, i, pNum = cx->tc_plane; int retval, i, pNum = cx->tc_plane;
CellDef *def; CellDef *def;
@ -996,8 +937,8 @@ dbcConnectFunc(tile, cx)
if (IsSplit(tile)) if (IsSplit(tile))
{ {
dinfo = DBTransformDiagonal(loctype, &scx->scx_trans); newdinfo = DBTransformDiagonal(loctype, &scx->scx_trans);
loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); loctype = ((dinfo & TT_SIDE)) ? SplitRightType(tile) : SplitLeftType(tile);
} }
/* See if the destination cell contains stuff over the whole /* See if the destination cell contains stuff over the whole
@ -1035,7 +976,7 @@ dbcConnectFunc(tile, cx)
def = csa2->csa2_use->cu_def; def = csa2->csa2_use->cu_def;
retval = 1; retval = 1;
if (DBSrPaintNMArea((Tile *) NULL, def->cd_planes[pNum], if (DBSrPaintNMArea((Tile *) NULL, def->cd_planes[pNum],
dinfo, &newarea, &notConnectMask, dbcUnconnectFunc, newdinfo, &newarea, &notConnectMask, dbcUnconnectFunc,
(ClientData) NULL) == 0) (ClientData) NULL) == 0)
retval = 0; retval = 0;
@ -1044,7 +985,7 @@ dbcConnectFunc(tile, cx)
* the storage for the current list element. * the storage for the current list element.
*/ */
DBNMPaintPlane(def->cd_planes[pNum], dinfo, DBNMPaintPlane(def->cd_planes[pNum], newdinfo,
&newarea, DBStdPaintTbl(loctype, pNum), &newarea, DBStdPaintTbl(loctype, pNum),
(PaintUndoInfo *) NULL); (PaintUndoInfo *) NULL);
@ -1061,14 +1002,14 @@ dbcConnectFunc(tile, cx)
/* Only extend those sides bordering the diagonal tile */ /* Only extend those sides bordering the diagonal tile */
if (dinfo & TT_DIAGONAL) if (newdinfo & TT_DIAGONAL)
{ {
if (dinfo & TT_SIDE) /* right */ if (newdinfo & TT_SIDE) /* right */
newarea.r_xtop += 1; newarea.r_xtop += 1;
else /* left */ else /* left */
newarea.r_xbot -= 1; newarea.r_xbot -= 1;
if (((dinfo & TT_SIDE) >> 1) if (((newdinfo & TT_SIDE) >> 1)
== (dinfo & TT_DIRECTION)) /* top */ == (newdinfo & TT_DIRECTION)) /* top */
newarea.r_ytop += 1; newarea.r_ytop += 1;
else /* bottom */ else /* bottom */
newarea.r_ybot -= 1; newarea.r_ybot -= 1;
@ -1108,7 +1049,7 @@ dbcConnectFunc(tile, cx)
csa2->csa2_list[csa2->csa2_top].area = newarea; csa2->csa2_list[csa2->csa2_top].area = newarea;
csa2->csa2_list[csa2->csa2_top].connectMask = connectMask; csa2->csa2_list[csa2->csa2_top].connectMask = connectMask;
csa2->csa2_list[csa2->csa2_top].dinfo = dinfo; csa2->csa2_list[csa2->csa2_top].dinfo = newdinfo;
return 0; return 0;
} }

File diff suppressed because it is too large Load Diff

View File

@ -583,8 +583,9 @@ DBReOrientLabel(cellDef, area, newPos)
*/ */
int int
dbGetLabelArea(tile, area) dbGetLabelArea(tile, dinfo, area)
Tile *tile; /* Tile found. */ Tile *tile; /* Tile found. */
TileType dinfo; /* Split tile information (unused) */
Rect *area; /* Area to be modified. */ Rect *area; /* Area to be modified. */
{ {
Rect r; Rect r;
@ -1085,14 +1086,15 @@ DBPickLabelLayer(def, lab, doCalma)
*/ */
int int
dbPickFunc1(tile, mask) dbPickFunc1(tile, dinfo, mask)
Tile *tile; /* Tile found. */ Tile *tile; /* Tile found. */
TileType dinfo; /* Split tile information */
TileTypeBitMask *mask; /* Mask to be modified. */ TileTypeBitMask *mask; /* Mask to be modified. */
{ {
TileType type; TileType type;
if (IsSplit(tile)) if (IsSplit(tile))
type = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
else else
type = TiGetType(tile); type = TiGetType(tile);
@ -1111,15 +1113,16 @@ dbPickFunc1(tile, mask)
*/ */
int int
dbPickFunc2(tile, mask) dbPickFunc2(tile, dinfo, mask)
Tile *tile; /* Tile found. */ Tile *tile; /* Tile found. */
TileType dinfo; /* Split tile information */
TileTypeBitMask *mask; /* Mask to be modified. */ TileTypeBitMask *mask; /* Mask to be modified. */
{ {
TileType type; TileType type;
TileTypeBitMask tmp, *rMask; TileTypeBitMask tmp, *rMask;
if (IsSplit(tile)) if (IsSplit(tile))
type = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
else else
type = TiGetType(tile); type = TiGetType(tile);

View File

@ -487,8 +487,6 @@ enumerate:
newType = (method == (unsigned char)PAINT_XOR) ? newType = (method == (unsigned char)PAINT_XOR) ?
*resultTbl : resultTbl[oldType]; *resultTbl : resultTbl[oldType];
if (mergeFlags & MRG_RIGHT)
tile = TiNMMergeRight(tile, plane); // was commented out?
if (mergeFlags & MRG_LEFT) if (mergeFlags & MRG_LEFT)
TiNMMergeLeft(LB(newtile), plane); TiNMMergeLeft(LB(newtile), plane);
} }
@ -496,8 +494,6 @@ enumerate:
{ {
if (mergeFlags & MRG_LEFT) if (mergeFlags & MRG_LEFT)
TiNMMergeLeft(newtile, plane); TiNMMergeLeft(newtile, plane);
if (mergeFlags & MRG_RIGHT)
TiNMMergeRight(LB(tile), plane); // was commented out?
} }
} }
else else
@ -1439,10 +1435,6 @@ DBDiagonalProc(oldtype, dinfo)
else else
return -1; return -1;
/* For purposes of "undo" recording, record which side we just painted */
if (dinfo->side)
newtype |= TT_SIDE;
return newtype; return newtype;
} }
@ -1824,14 +1816,15 @@ nextrect:
*/ */
int int
dbNMEnumFunc(tile, arg) dbNMEnumFunc(tile, dinfo, arg)
Tile *tile; Tile *tile;
TileType dinfo;
LinkedRect **arg; LinkedRect **arg;
{ {
LinkedRect *lr; LinkedRect *lr;
/* Ignore the second call to any diagonal---only count once! */ /* Ignore the second call to any diagonal---only count once! */
if (IsSplit(tile) && SplitSide(tile)) return 0; if (IsSplit(tile) && (dinfo & TT_SIDE)) return 0;
lr = (LinkedRect *) mallocMagic(sizeof(LinkedRect)); lr = (LinkedRect *) mallocMagic(sizeof(LinkedRect));
TiToRect(tile, &lr->r_r); TiToRect(tile, &lr->r_r);

View File

@ -119,8 +119,9 @@ DBPaint (cellDef, rect, type)
*/ */
int int
dbResolveImages(tile, cellDef) dbResolveImages(tile, dinfo, cellDef)
Tile *tile; Tile *tile;
TileType dinfo;
CellDef *cellDef; CellDef *cellDef;
{ {
Rect rect; Rect rect;
@ -130,7 +131,7 @@ dbResolveImages(tile, cellDef)
/* Recursive call back to DBPaint---this will ensure that */ /* Recursive call back to DBPaint---this will ensure that */
/* all of the planes of the image type are painted. */ /* all of the planes of the image type are painted. */
DBPaint(cellDef, &rect, TiGetTypeExact(tile)); DBPaint(cellDef, &rect, TiGetTypeExact(tile) | dinfo);
return 0; return 0;
} }

View File

@ -32,6 +32,16 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "database/database.h" #include "database/database.h"
#include "utils/malloc.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 void
DBPropPut(cellDef, name, value) DBPropPut(cellDef, name, value)
CellDef *cellDef; /* Pointer to definition of cell. */ CellDef *cellDef; /* Pointer to definition of cell. */
char *name; /* The name of the property desired. */ char *name; /* The name of the property desired. */
ClientData value; /* MUST point to a malloc'ed structure, or NULL. PropertyRecord *value; /* MUST point to a malloc'ed structure, or NULL.
* This will be freed when the CellDef is freed. * This will be freed when the CellDef is freed.
*/ */
{ {
HashTable *htab; HashTable *htab;
HashEntry *entry; HashEntry *entry;
char *oldvalue; PropertyRecord *oldvalue;
/* Honor the NOEDIT flag. Note that the caller always assumes that */ /* 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 */ /* 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); entry = HashFind(htab, name);
oldvalue = (char *)HashGetValue(entry); oldvalue = (PropertyRecord *)HashGetValue(entry);
if (oldvalue != NULL) freeMagic(oldvalue); /* All properties are allocated as a single block and can just be freed,
if (value == (ClientData)NULL) * 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); HashRemove(htab, name);
else else
HashSetValue(entry, value); HashSetValue(entry, PTR2CD(value));
} }
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
@ -110,13 +131,13 @@ DBPropPut(cellDef, name, value)
* Get a property from a celldef. * Get a property from a celldef.
* *
* Results: * Results:
* NULL if the property didn't exist, or if the property value was NULL. * NULL if the property didn't exist, or if the property record was NULL.
* Otherwise, ClientData that represents the property. * Otherwise, returns a pointer to the property record.
* *
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
ClientData PropertyRecord *
DBPropGet(cellDef, name, found) DBPropGet(cellDef, name, found)
CellDef *cellDef; /* Pointer to definition of cell. */ CellDef *cellDef; /* Pointer to definition of cell. */
char *name; /* The name of the property desired. */ char *name; /* The name of the property desired. */
@ -124,12 +145,12 @@ DBPropGet(cellDef, name, found)
* exists. * exists.
*/ */
{ {
ClientData result; PropertyRecord *result;
bool haveit; bool haveit;
HashTable *htab; HashTable *htab;
HashEntry *entry; HashEntry *entry;
result = (ClientData) NULL; result = (PropertyRecord *)NULL;
haveit = FALSE; haveit = FALSE;
htab = (HashTable *) cellDef->cd_props; htab = (HashTable *) cellDef->cd_props;
if (htab == (HashTable *) NULL) goto done; if (htab == (HashTable *) NULL) goto done;
@ -138,7 +159,7 @@ DBPropGet(cellDef, name, found)
if (entry != NULL) if (entry != NULL)
{ {
haveit = TRUE; haveit = TRUE;
result = (ClientData) HashGetValue(entry); result = (PropertyRecord *)HashGetValue(entry);
} }
done: done:
@ -146,6 +167,109 @@ done:
return result; 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 -- * DBPropEnum --
@ -168,7 +292,7 @@ DBPropEnum(cellDef, func, cdata)
* *
* int foo(name, value, cdata) * int foo(name, value, cdata)
* char *name; * char *name;
* ClientData value; * PropertyRecord *value;
* ClientData cdata; * ClientData cdata;
* { * {
* -- return 0 to continue, * -- return 0 to continue,
@ -189,7 +313,7 @@ DBPropEnum(cellDef, func, cdata)
HashStartSearch(&hs); HashStartSearch(&hs);
while ((entry = HashNext(htab, &hs)) != NULL) 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; if (res != 0) return res;
} }

View File

@ -44,6 +44,296 @@ struct dbCheck
int dbCheckMaxHFunc(), dbCheckMaxVFunc(); int dbCheckMaxHFunc(), dbCheckMaxVFunc();
/*
* --------------------------------------------------------------------
*
* dbEvalCorner --
*
* Used by DBTestNMInteract() to determine whether two non-
* Manhattan areas have crossing diagonals by evaluating the
* corner points of the area of intersection between the two
* tiles. This routine finds the distance from a point in
* the second triangle to the diagonal of the first, in both
* x and y. If the point is below or to the left, the
* distance is negative; otherwise the distance is positive.
*
* Results:
* 1 for a positive result, -1 for a negative result, and 0
* for the same result (point touches the diagonal).
*
* Side effects:
* None.
*
* --------------------------------------------------------------------
*/
int
dbEvalCorner(Point *p, // Point to evaluate
Rect *rect, // Triangular area bounding rectangle
TileType di) // Diagonal information for split rect
{
dlong D;
/* D is the distance from a point to the diagonal of the rectangle.
* The magnitude is not important. It only matters what the sign
* is, so return 1 for positive, -1 for negative, or 0.
*/
if (di & TT_DIRECTION)
D = (p->p_y - rect->r_ybot) * (rect->r_xtop - rect->r_xbot) -
(rect->r_xtop - p->p_x) * (rect->r_ytop - rect->r_ybot);
else
D = (p->p_y - rect->r_ybot) * (rect->r_xtop - rect->r_xbot) -
(p->p_x - rect->r_xbot) * (rect->r_ytop - rect->r_ybot);
if (D > 0) return 1;
if (D < 0) return -1;
return 0;
}
/*
* --------------------------------------------------------------------
*
* DBTestNMInteract --
*
* Determine if a tile (t2) interacts with (touches or overlaps)
* a triangular area (rect1, with diagonal split information in
* di1). Tile t2 may or may not be a split tile. If t2 is
* split, then diagonal split information is in di2.
*
* There are two distinct cases: DBSrPaintNMArea() looks for
* tiles that overlap the area of rect1, but extTestNMInteract()
* looks for tiles that both overlap or touch (indicating
* electrical connectivity between the two). "overlap_only"
* distinguishes between the two use cases. Set "overlap_only"
* to TRUE for overlap searches, and FALSE for interaction
* searches.
*
* Results:
*
* If overlap_only is TRUE:
* Return TRUE if the indicated areas overlap, FALSE if not.
* If overlap_only is FALSE:
* Return TRUE if the indicated areas touch or overlap, FALSE if not.
*
* Side effects:
* None.
*
* --------------------------------------------------------------------
*/
bool
DBTestNMInteract(Rect *rect1,
TileType tt1,
Tile *t2,
TileType di2,
bool overlap_only)
{
Rect rect2, r;
Point p;
int rheight, rwidth, rmax;
dlong f1, f2, f3, f4;
TileType tt2;
int pos, neg, touch, sign;
TiToRect(t2, &rect2);
/* Assuming that rect1 is a split area, then check if any part of t2
* overlaps the split side of interest in rect1, regardless of whether
* t2 is split or not. If there is no overlap, then return FALSE.
*/
rheight = rect1->r_ytop - rect1->r_ybot;
rwidth = rect1->r_xtop - rect1->r_xbot;
rmax = MAX(rheight, rwidth);
f1 = (rect2.r_ybot > MINFINITY + 2) ?
((dlong)(rect1->r_ytop - rect2.r_ybot) * rwidth) : DLONG_MAX;
f2 = (rect2.r_ytop < INFINITY - 2) ?
((dlong)(rect2.r_ytop - rect1->r_ybot) * rwidth) : DLONG_MAX;
if (tt1 & TT_SIDE)
{
/* Outside-of-triangle check---ignore sub-integer slivers */
if (rect2.r_xtop < INFINITY - 2)
{
f3 = (dlong)(rect1->r_xtop - rect2.r_xtop) * rheight;
f3 += rmax;
}
else
f3 = DLONG_MIN;
if ((tt1 & TT_DIRECTION) ? (f2 < f3) : (f1 < f3))
return FALSE;
}
else
{
/* Outside-of-triangle check---ignore sub-integer slivers */
if (rect2.r_xbot > MINFINITY + 2)
{
f4 = (dlong)(rect2.r_xbot - rect1->r_xbot) * rheight;
f4 += rmax;
}
else
f4 = DLONG_MIN;
if ((tt1 & TT_DIRECTION) ? (f1 < f4) : (f2 < f4))
return FALSE;
}
/* If t2 is not split, or its diagonal is the opposite of t1,
* or its side is the same as that of t1, then they overlap.
*/
if (!IsSplit(t2)) return TRUE;
tt2 = TiGetTypeExact(t2) | di2;
if ((tt1 & TT_DIRECTION) != (tt2 & TT_DIRECTION)) return TRUE;
// if ((tt1 & TT_SIDE) == (tt2 & TT_SIDE)) return TRUE;
/* Hard case: Same diagonal direction, opposite sides. To determine
* overlap, count which of the three points of triangle t2 land on
* one side or the other of the rect1 split diagonal. From those
* counts, determine if the triangles are overlapping, touching,
* or disjoint.
*/
/* Evaluate the three corners of the rect2 triangle */
pos = neg = touch = 0;
if (!(tt2 & TT_DIRECTION) || !(tt2 & TT_SIDE))
{
/* Evaluate the lower left corner */
sign = dbEvalCorner(&rect2.r_ll, rect1, tt1);
if (sign == 1)
pos++;
else if (sign == -1)
neg++;
else
touch++;
}
if (!(tt2 & TT_DIRECTION) || (tt2 & TT_SIDE))
{
/* Evaluate the upper right corner */
sign = dbEvalCorner(&rect2.r_ur, rect1, tt1);
if (sign == 1)
pos++;
else if (sign == -1)
neg++;
else
touch++;
}
if ((tt2 & TT_DIRECTION) || !(tt2 & TT_SIDE))
{
/* Evaluate the upper left corner */
p.p_x = rect2.r_xbot;
p.p_y = rect2.r_ytop;
sign = dbEvalCorner(&p, rect1, tt1);
if (sign == 1)
pos++;
else if (sign == -1)
neg++;
else
touch++;
}
if ((tt2 & TT_DIRECTION) || (tt2 & TT_SIDE))
{
/* Evaluate the lower right corner */
p.p_x = rect2.r_xtop;
p.p_y = rect2.r_ybot;
sign = dbEvalCorner(&p, rect1, tt1);
if (sign == 1)
pos++;
else if (sign == -1)
neg++;
else
touch++;
}
/* If side and direction match, then pos and neg need to be swapped */
if (((tt1 & TT_SIDE) && (tt1 & TT_DIRECTION)) ||
(!(tt1 & TT_SIDE) && !(tt1 & TT_DIRECTION)))
{
int temp = neg;
neg = pos;
pos = temp;
}
/* Return TRUE or FALSE depending on the values of pos, neg, and
* touch, and depending on whether overlap_only is set or not.
*/
if (pos == 3)
return FALSE; /* Fully disjoint */
else if (neg == 3)
{
if ((tt1 & TT_SIDE) != (tt2 & TT_SIDE))
return TRUE; /* Fully enclosed */
else
{
/* This is a trickier situation. Both triangles have
* the same TT_SIDE bit, but the triangular area of t2
* could still be outside of rect1. Need to check where
* the inside corner of rect1 lands with respect to the
* t2 diagonal.
*/
if (((tt1 & TT_SIDE) == 0) && ((tt1 & TT_DIRECTION) != 0))
{
sign = dbEvalCorner(&rect1->r_ll, &rect2, tt2);
}
else if (((tt1 & TT_SIDE) == 0) && ((tt1 & TT_DIRECTION) == 0))
{
p.p_x = rect1->r_ll.p_x;
p.p_y = rect1->r_ur.p_y;
sign = dbEvalCorner(&p, &rect2, tt2);
}
else if (((tt1 & TT_SIDE) != 0) && ((tt1 & TT_DIRECTION) == 0))
{
p.p_x = rect1->r_ur.p_x;
p.p_y = rect1->r_ll.p_y;
sign = dbEvalCorner(&p, &rect2, tt2);
}
else /* if (((tt1 & TT_SIDE) != 0) && ((tt1 & TT_DIRECTION) != 0)) */
{
sign = dbEvalCorner(&rect1->r_ur, &rect2, tt2);
}
/* Again, if side and direction match, then sign is backwards
*/
if (((tt2 & TT_SIDE) && (tt2 & TT_DIRECTION)) ||
(!(tt2 & TT_SIDE) && !(tt2 & TT_DIRECTION)))
sign = -sign;
if (sign == 1)
return FALSE; /* Fully disjoint */
else if (sign == -1)
return TRUE; /* Fully overlapping */
else if (overlap_only)
return FALSE; /* Touching but not overlapping */
else
return TRUE; /* Touching but not overlapping */
}
}
else if (overlap_only)
{
if ((touch > 0) && (neg + touch == 3))
return TRUE; /* Enclosed and touching */
else if ((touch > 0) && (pos + touch == 3))
return FALSE; /* Unenclosed but touching */
else
return TRUE; /* Partially overlapping */
}
else /* overlap_only == FALSE */
{
if ((touch > 0) && (neg + touch == 3))
return TRUE; /* Enclosed and touching */
else if ((touch > 0) && (pos + touch == 3))
return TRUE; /* Unenclosed but touching */
else
return TRUE; /* Partially overlapping */
}
}
/* /*
* -------------------------------------------------------------------- * --------------------------------------------------------------------
* *
@ -56,6 +346,7 @@ int dbCheckMaxHFunc(), dbCheckMaxVFunc();
* int * int
* func(tile, cdata) * func(tile, cdata)
* Tile *tile; * Tile *tile;
* TileType dinfo;
* ClientData cdata; * ClientData cdata;
* { * {
* } * }
@ -137,147 +428,26 @@ nm_enum:
/* the tile enumeration if it is not. */ /* the tile enumeration if it is not. */
/* Watch for calculations involving (M)INFINITY in tile (tp)! */ /* Watch for calculations involving (M)INFINITY in tile (tp)! */
rheight = rect->r_ytop - rect->r_ybot;
rwidth = rect->r_xtop - rect->r_xbot;
rmax = MAX(rheight, rwidth);
f1 = (BOTTOM(tp) > MINFINITY + 2) ?
((dlong)(rect->r_ytop - BOTTOM(tp)) * rwidth) : DLONG_MAX;
f2 = (TOP(tp) < INFINITY - 2) ?
((dlong)(TOP(tp) - rect->r_ybot) * rwidth) : DLONG_MAX;
if (ttype & TT_SIDE)
{
/* Outside-of-triangle check---ignore sub-integer slivers */
if (RIGHT(tp) < INFINITY - 2)
{
f3 = (dlong)(rect->r_xtop - RIGHT(tp)) * rheight;
f3 += rmax;
}
else
f3 = DLONG_MIN;
if ((ttype & TT_DIRECTION) ? (f2 < f3) : (f1 < f3))
goto enum_next;
}
else
{
/* Outside-of-triangle check---ignore sub-integer slivers */
if (LEFT(tp) > MINFINITY + 2)
{
f4 = (dlong)(LEFT(tp) - rect->r_xbot) * rheight;
f4 += rmax;
}
else
f4 = DLONG_MIN;
if ((ttype & TT_DIRECTION) ? (f1 < f4) : (f2 < f4))
goto enum_next;
}
/* Secondary checks---if tile is also non-Manhattan, is */
/* either side of it outside the area? If so, restrict it. */
/* This check is only necessary if the split directions are */
/* the same, so we have to see if either of the neighboring */
/* points is also inside the search triangle. */
ignore_sides = 0;
if (IsSplit(tp)) if (IsSplit(tp))
{ {
if (!TTMaskHasType(mask, SplitLeftType(tp))) TileType tpdi = TiGetTypeExact(tp);
ignore_sides |= IGNORE_LEFT;
if (!TTMaskHasType(mask, SplitRightType(tp)))
ignore_sides |= IGNORE_RIGHT;
tpt = TiGetTypeExact(tp); if (TTMaskHasType(mask, SplitLeftType(tp)))
if ((tpt & TT_DIRECTION) == (ttype & TT_DIRECTION)) if (DBTestNMInteract(rect, ttype, tp, tpdi, TRUE))
{ if ((*func)(tp, (TileType)TT_DIAGONAL, arg))
f3 = (LEFT(tp) > MINFINITY + 2) ? return 1;
((dlong)(rect->r_xtop - LEFT(tp)) * rheight) : DLONG_MAX; if (TTMaskHasType(mask, SplitRightType(tp)))
f4 = (RIGHT(tp) < INFINITY - 2) ? if (DBTestNMInteract(rect, ttype, tp, tpdi | TT_SIDE, TRUE))
((dlong)(RIGHT(tp) - rect->r_xbot) * rheight) : DLONG_MAX; if ((*func)(tp, (TileType)TT_DIAGONAL | TT_SIDE, arg))
return 1;
if (ttype & TT_SIDE) }
{
/* Ignore sub-integer slivers */
if (f4 != DLONG_MAX) f4 -= rmax;
if (f3 != DLONG_MAX) f3 += rmax;
if (ttype & TT_DIRECTION)
{
if ((f2 < f3) && (f1 > f4))
/* Tile bottom left is outside search area */
ignore_sides |= IGNORE_LEFT;
}
else
{
if ((f1 < f3) && (f2 > f4))
/* Tile top left is outside search area */
ignore_sides |= IGNORE_LEFT;
}
}
else
{
/* Ignore sub-integer slivers */
if (f4 != DLONG_MAX) f4 += rmax;
if (f3 != DLONG_MAX) f3 -= rmax;
if (ttype & TT_DIRECTION)
{
if ((f2 > f3) && (f1 < f4))
/* Tile top right is outside search area */
ignore_sides |= IGNORE_RIGHT;
}
else
{
if ((f1 > f3) && (f2 < f4))
/* Tile bottom right is outside search area */
ignore_sides |= IGNORE_RIGHT;
}
}
}
/* If the tile is larger than the search area or overlaps */
/* the search area, we need to check if one of the sides */
/* of the tile is disjoint from the search area. */
rheight = TOP(tp) - BOTTOM(tp);
rwidth = RIGHT(tp) - LEFT(tp);
rmax = MAX(rheight, rwidth);
f1 = (TOP(tp) < INFINITY - 2) ?
((dlong)(TOP(tp) - rect->r_ybot) * rwidth) : DLONG_MAX;
f2 = (BOTTOM(tp) > MINFINITY + 2) ?
((dlong)(rect->r_ytop - BOTTOM(tp)) * rwidth) : DLONG_MAX;
f3 = (RIGHT(tp) < INFINITY - 2) ?
((dlong)(RIGHT(tp) - rect->r_xtop) * rheight) : DLONG_MAX;
f4 = (LEFT(tp) > MINFINITY + 2) ?
((dlong)(rect->r_xbot - LEFT(tp)) * rheight) : DLONG_MAX;
/* ignore sub-integer slivers */
if (f4 < DLONG_MAX) f4 += rmax;
if (f3 < DLONG_MAX) f3 += rmax;
if (SplitDirection(tp) ? (f1 < f4) : (f2 < f4))
ignore_sides |= IGNORE_LEFT;
if (SplitDirection(tp) ? (f2 < f3) : (f1 < f3))
ignore_sides |= IGNORE_RIGHT;
/* May call function twice to paint both sides of */
/* the split tile, if necessary. */
if (!(ignore_sides & IGNORE_LEFT))
{
TiSetBody(tp, INT2CD(tpt & ~TT_SIDE)); /* bit clear */
if ((*func)(tp, arg)) return (1);
}
if (!(ignore_sides & IGNORE_RIGHT))
{
TiSetBody(tp, INT2CD(tpt | TT_SIDE)); /* bit set */
if ((*func)(tp, arg)) return (1);
}
}
else else
if (TTMaskHasType(mask, TiGetType(tp)) && (*func)(tp, arg)) {
return (1); if (TTMaskHasType(mask, TiGetType(tp)))
if (DBTestNMInteract(rect, ttype, tp, (TileType)0, TRUE))
if ((*func)(tp, (TileType)0, arg))
return 1;
}
enum_next: enum_next:
tpnew = TR(tp); tpnew = TR(tp);
@ -325,6 +495,7 @@ enum_next:
* int * int
* func(tile, cdata) * func(tile, cdata)
* Tile *tile; * Tile *tile;
* TileType dinfo;
* ClientData cdata; * ClientData cdata;
* { * {
* } * }
@ -416,9 +587,7 @@ enumerate:
(dlong)(rect->r_xbot - LEFT(tp)) * theight : DLONG_MIN; (dlong)(rect->r_xbot - LEFT(tp)) * theight : DLONG_MIN;
if (SplitDirection(tp) ? (f1 > f4) : (f2 > f4)) if (SplitDirection(tp) ? (f1 > f4) : (f2 > f4))
{ {
TiSetBody(tp, INT2CD((TileType)CD2INT(TiGetBody(tp)) if ((*func)(tp, (TileType)TT_DIAGONAL, arg)) return (1);
& ~TT_SIDE)); /* bit clear */
if ((*func)(tp, arg)) return (1);
} }
} }
@ -429,14 +598,12 @@ enumerate:
(dlong)(RIGHT(tp) - rect->r_xtop) * theight : DLONG_MIN; (dlong)(RIGHT(tp) - rect->r_xtop) * theight : DLONG_MIN;
if (SplitDirection(tp) ? (f2 > f3) : (f1 > f3)) if (SplitDirection(tp) ? (f2 > f3) : (f1 > f3))
{ {
TiSetBody(tp, INT2CD((TileType)CD2INT(TiGetBody(tp)) if ((*func)(tp, (TileType)TT_DIAGONAL | TT_SIDE, arg)) return (1);
| TT_SIDE)); /* bit set */
if ((*func)(tp, arg)) return (1);
} }
} }
} }
else else
if (TTMaskHasType(mask, TiGetType(tp)) && (*func)(tp, arg)) if (TTMaskHasType(mask, TiGetType(tp)) && (*func)(tp, (TileType)0, arg))
return (1); return (1);
tpnew = TR(tp); tpnew = TR(tp);
@ -485,6 +652,7 @@ enumerate:
* int * int
* func(tile, cdata) * func(tile, cdata)
* Tile *tile; * Tile *tile;
* TileType dinfo;
* ClientData cdata; * ClientData cdata;
* { * {
* } * }
@ -576,9 +744,7 @@ enumerate:
(dlong)(rect->r_xbot - LEFT(tp)) * (dlong)theight : DLONG_MIN; (dlong)(rect->r_xbot - LEFT(tp)) * (dlong)theight : DLONG_MIN;
if (SplitDirection(tp) ? (f1 > f4) : (f2 > f4)) if (SplitDirection(tp) ? (f1 > f4) : (f2 > f4))
{ {
TiSetBody(tp, INT2CD((TileType)CD2INT(TiGetBody(tp)) if ((tp->ti_client == client) && (*func)(tp, (TileType)TT_DIAGONAL, arg))
& ~TT_SIDE)); /* bit clear */
if ((tp->ti_client == client) && (*func)(tp, arg))
return (1); return (1);
} }
} }
@ -590,16 +756,15 @@ enumerate:
(dlong)(RIGHT(tp) - rect->r_xtop) * (dlong)theight : DLONG_MIN; (dlong)(RIGHT(tp) - rect->r_xtop) * (dlong)theight : DLONG_MIN;
if (SplitDirection(tp) ? (f2 > f3) : (f1 > f3)) if (SplitDirection(tp) ? (f2 > f3) : (f1 > f3))
{ {
TiSetBody(tp, INT2CD((TileType)CD2INT(TiGetBody(tp)) if ((tp->ti_client == client) && (*func)(tp, (TileType)TT_DIAGONAL
| TT_SIDE)); /* bit set */ | TT_SIDE, arg))
if ((tp->ti_client == client) && (*func)(tp, arg))
return (1); return (1);
} }
} }
} }
else else
if (TTMaskHasType(mask, TiGetType(tp)) && tp->ti_client == client if (TTMaskHasType(mask, TiGetType(tp)) && tp->ti_client == client
&& (*func)(tp, arg)) && (*func)(tp, (TileType)0, arg))
return (1); return (1);
tpnew = TR(tp); tpnew = TR(tp);
@ -665,7 +830,7 @@ DBResetTilePlane(plane, cdata)
/* Each iteration visits another tile on the LHS of the search area */ /* Each iteration visits another tile on the LHS of the search area */
while (TOP(tp) > rect->r_ybot) while (TOP(tp) > rect->r_ybot)
{ {
/* Each iteration frees another tile */ /* Each iteration resets another tile */
enumerate: enumerate:
tp->ti_client = cdata; tp->ti_client = cdata;
@ -701,6 +866,88 @@ enumerate:
} }
} }
/*
* --------------------------------------------------------------------
*
* DBResetTilePlaneSpecial --
*
* This routine works like DBResetTilePlane(), but is designed
* specifically to be run after extFindNodes() or ExtFindRegions()
* to check for split tiles that have an allocated ExtSplitRegion
* structure in the ClientData; this needs to be freed before
* resetting the ClientData value to "cdata". It is not necessary
* to know anything about the ExtSplitRegion structure other than
* the condition under which it can be expected to be present,
* which is a split tile with neither side having type TT_SPACE.
*
* Results:
* None.
*
* Side effects:
* Resets the ti_client fields of all tiles.
*
* --------------------------------------------------------------------
*/
void
DBResetTilePlaneSpecial(plane, cdata)
Plane *plane; /* Plane whose tiles are to be reset */
ClientData cdata;
{
Tile *tp, *tpnew;
const Rect *rect = &TiPlaneRect;
/* Start with the leftmost non-infinity tile in the plane */
tp = TR(plane->pl_left);
/* Each iteration visits another tile on the LHS of the search area */
while (TOP(tp) > rect->r_ybot)
{
/* Each iteration resets another tile */
enumerate:
if (IsSplit(tp))
if ((TiGetLeftType(tp) != TT_SPACE) && (TiGetRightType(tp) != TT_SPACE))
if (tp->ti_client != cdata)
{
ASSERT(TiGetBody((Tile *)tp->ti_client) == CLIENTDEFAULT,
"DBResetTilePlaneSpecial");
freeMagic(tp->ti_client);
}
tp->ti_client = cdata;
/* Move along to the next tile */
tpnew = TR(tp);
if (LEFT(tpnew) < rect->r_xtop)
{
while (BOTTOM(tpnew) >= rect->r_ytop) tpnew = LB(tpnew);
if (BOTTOM(tpnew) >= BOTTOM(tp) || BOTTOM(tp) <= rect->r_ybot)
{
tp = tpnew;
goto enumerate;
}
}
/* Each iteration returns one tile further to the left */
while (LEFT(tp) > rect->r_xbot)
{
if (BOTTOM(tp) <= rect->r_ybot)
return;
tpnew = LB(tp);
tp = BL(tp);
if (BOTTOM(tpnew) >= BOTTOM(tp) || BOTTOM(tp) <= rect->r_ybot)
{
tp = tpnew;
goto enumerate;
}
}
/* At left edge -- walk down to next tile along the left edge */
for (tp = LB(tp); RIGHT(tp) <= rect->r_xbot; tp = TR(tp))
/* Nothing */;
}
}
/* /*
* -------------------------------------------------------------------- * --------------------------------------------------------------------
* *
@ -918,8 +1165,9 @@ DBCheckMaxHStrips(plane, area, proc, cdata)
*/ */
int int
dbCheckMaxHFunc(tile, dbc) dbCheckMaxHFunc(tile, dinfo, dbc)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
struct dbCheck *dbc; struct dbCheck *dbc;
{ {
Tile *tp; Tile *tp;
@ -1010,8 +1258,9 @@ DBCheckMaxVStrips(plane, area, proc, cdata)
*/ */
int int
dbCheckMaxVFunc(tile, dbc) dbCheckMaxVFunc(tile, dinfo, dbc)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
struct dbCheck *dbc; struct dbCheck *dbc;
{ {
Tile *tp; Tile *tp;

View File

@ -303,9 +303,14 @@ typedef struct label
#define PORT_SHAPE_RING 0x1000 /* Port is a ring shape */ #define PORT_SHAPE_RING 0x1000 /* Port is a ring shape */
#define PORT_SHAPE_THRU 0x1800 /* Port is a feedthrough 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. */ /* has been previously visited. */
#define LABEL_STICKY 0x4000 /* Label does not change layers */
#define LABEL_GENERATE 0x8000 /* Auto-generated label */ #define LABEL_GENERATE 0x8000 /* Auto-generated label */
/* /*
@ -551,6 +556,18 @@ typedef struct diag_info
bool side; bool side;
} DiagInfo; } DiagInfo;
/* Where search functions need to return a Tile pointer and tile split */
/* information, use this structure. Contains a pointer to its own */
/* structure type so that it may also be used to create a linked list */
/* of tiles including split side information. */
typedef struct tile_and_dinfo
{
struct tile_and_dinfo *tad_next;
Tile *tad_tile;
TileType tad_dinfo;
} TileAndDinfo;
/* This would normally go in geometry.h except that it uses TileType. */ /* This would normally go in geometry.h except that it uses TileType. */
/* Used in selOps.c but also passed back to CmdRS.c for select command. */ /* Used in selOps.c but also passed back to CmdRS.c for select command. */
@ -687,6 +704,25 @@ struct conSrArg2
#define CSA2_LIST_SIZE 65536 /* Number of entries per list */ #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 ------------- */ /* -------------- Undo information passed to DBPaintPlane ------------- */
typedef struct typedef struct
@ -719,6 +755,14 @@ typedef struct
#define PAINT_MARK 1 /* Mark tiles that are painted */ #define PAINT_MARK 1 /* Mark tiles that are painted */
#define PAINT_XOR 2 /* Use with XOR function to prevent double-painting */ #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 -------------------- */ /* -------------------- Exported procedure headers -------------------- */
/* Painting/erasing */ /* Painting/erasing */
@ -904,7 +948,9 @@ extern void DBFreePaintPlane();
/* Cell properties */ /* Cell properties */
extern void DBPropPut(); extern void DBPropPut();
extern ClientData DBPropGet(); extern PropertyRecord *DBPropGet();
extern char *DBPropGetString();
extern dlong DBPropGetDouble();
extern int DBPropEnum(); extern int DBPropEnum();
extern void DBPropClearAll(); extern void DBPropClearAll();
@ -920,9 +966,10 @@ extern int DBArraySr();
extern bool DBNearestLabel(); extern bool DBNearestLabel();
extern int DBSrLabelLoc(); extern int DBSrLabelLoc();
extern TileType DBTransformDiagonal(); extern TileType DBTransformDiagonal();
extern int dbcUnconnectFunc(Tile *tile, ClientData clientData); /* (notused) */ extern bool DBTestNMInteract(Rect *rect1, TileType tt1, Tile *t2, TileType di2, bool overlap_only);
extern int dbSrConnectFunc(Tile *tile, ClientData clientData); /* (struct conSrArg *csa) */ extern int dbcUnconnectFunc(Tile *tile, TileType dinfo, ClientData clientData); /* (notused) */
extern int dbSrConnectStartFunc(Tile *tile, ClientData clientData); /* cb_database_srpaintarea_t (Tile **pTile) */ extern int dbSrConnectFunc(Tile *tile, TileType dinfo, ClientData clientData); /* (struct conSrArg *csa) */
extern int dbSrConnectStartFunc(Tile *tile, TileType dinfo, ClientData clientData); /* cb_database_srpaintarea_t (Tile **pTile) */
/* C99 compat */ /* C99 compat */
extern void DBEraseValid(); extern void DBEraseValid();
@ -969,10 +1016,10 @@ extern int dbIsPrimary();
extern void dbTechMatchResidues(); extern void dbTechMatchResidues();
extern void DBUndoInit(); extern void DBUndoInit();
extern void DBResetTilePlane(); extern void DBResetTilePlane();
extern void DBResetTilePlaneSpecial();
extern void DBNewYank(); extern void DBNewYank();
extern int DBSrPaintClient(); extern int DBSrPaintClient();
extern int DBSrConnect(); extern int DBSrConnect();
extern int DBSrConnectOnePlane();
extern char *dbFgets(); extern char *dbFgets();
extern void DBAdjustLabelsNew(); extern void DBAdjustLabelsNew();
extern bool DBScaleValue(); extern bool DBScaleValue();
@ -1001,6 +1048,7 @@ extern int DBLambda[2];
/* -------------------- Exported magic file suffix -------------------- */ /* -------------------- Exported magic file suffix -------------------- */
extern char *DBSuffix; /* Suffix appended to all Magic cell names */ extern char *DBSuffix; /* Suffix appended to all Magic cell names */
extern bool DBPropCompat; /* Backwards-compatible properties */
/* -------------------- User Interface Stuff -------------------------- */ /* -------------------- User Interface Stuff -------------------------- */

View File

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

View File

@ -571,8 +571,9 @@ DBWredisplay(w, rootArea, clipArea)
*/ */
int int
dbwPaintFunc(tile, cxp) dbwPaintFunc(tile, dinfo, cxp)
Tile *tile; /* Tile to be redisplayed. */ Tile *tile; /* Tile to be redisplayed. */
TileType dinfo; /* Split tile information */
TreeContext *cxp; /* From DBTreeSrTiles */ TreeContext *cxp; /* From DBTreeSrTiles */
{ {
SearchContext *scx = cxp->tc_scx; SearchContext *scx = cxp->tc_scx;
@ -652,7 +653,7 @@ dbwPaintFunc(tile, cxp)
/* whether to render the outline with a fast rectangle- */ /* whether to render the outline with a fast rectangle- */
/* drawing routine or to render it segment by segment. */ /* drawing routine or to render it segment by segment. */
GrBox(dbwWindow, &scx->scx_trans, tile); GrBox(dbwWindow, &scx->scx_trans, tile, dinfo);
return 0; return 0;
} }
@ -1075,8 +1076,10 @@ dbwBBoxFunc(scx)
*/ */
int int
dbwTileFunc(tile) dbwTileFunc(tile, dinfo, clientdata)
Tile *tile; /* A tile to be redisplayed. */ Tile *tile; /* A tile to be redisplayed. */
TileType dinfo; /* Split tile information (unused) */
ClientData clientdata; /* (unused) */
{ {
Rect r, r2; Rect r, r2;
int xoffset, yoffset; int xoffset, yoffset;
@ -1113,7 +1116,7 @@ dbwTileFunc(tile)
if (dbwSeeTypes) if (dbwSeeTypes)
{ {
(void) sprintf(string, "%s",DBTypeShortName(TiGetType(tile))); (void) sprintf(string, "%s", DBTypeShortName(TiGetType(tile)));
} }
else else
{ {
@ -1129,7 +1132,7 @@ dbwTileFunc(tile)
#define XYOFFSET 12 #define XYOFFSET 12
for (i=0; i<4; i++) for (i = 0; i < 4; i++)
{ {
xoffset = 0; xoffset = 0;
yoffset = 0; yoffset = 0;
@ -1172,13 +1175,13 @@ dbwTileFunc(tile)
yoffset = temp; yoffset = temp;
} }
if ( (dbwWatchTrans.t_a < 0) || (dbwWatchTrans.t_b < 0) ) if ((dbwWatchTrans.t_a < 0) || (dbwWatchTrans.t_b < 0))
{ {
/* mirror in x */ /* mirror in x */
xoffset = -xoffset; xoffset = -xoffset;
} }
if ( (dbwWatchTrans.t_d < 0) || (dbwWatchTrans.t_e < 0) ) if ((dbwWatchTrans.t_d < 0) || (dbwWatchTrans.t_e < 0))
{ {
/* mirror in y */ /* mirror in y */
yoffset = -yoffset; yoffset = -yoffset;

View File

@ -249,7 +249,10 @@ DBWFeedbackRedraw(window, plane)
} }
int int
dbwFeedbackAlways1() dbwFeedbackAlways1(
Tile *tile, /* (unused) */
TileType dinfo, /* (unused) */
ClientData clientdata) /* (unused) */
{ {
return 1; return 1;
} }

View File

@ -392,8 +392,9 @@ DBWHLRedrawWind(window)
*/ */
int int
dbwhlEraseFunc(tile, window) dbwhlEraseFunc(tile, dinfo, window)
Tile *tile; /* Tile describing area to be erased. */ Tile *tile; /* Tile describing area to be erased. */
TileType dinfo; /* Split tile information (unused) */
MagWindow *window; /* Window that is being altered. */ MagWindow *window; /* Window that is being altered. */
{ {
Rect area; Rect area;

View File

@ -25,6 +25,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include "tcltk/tclmagic.h"
#include "utils/main.h" #include "utils/main.h"
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/geometry.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 "utils/hash.h"
#include "database/database.h" #include "database/database.h"
#include "utils/main.h" #include "utils/main.h"
#include "cif/cif.h"
#include "commands/commands.h" #include "commands/commands.h"
#include "dbwind/dbwind.h" #include "dbwind/dbwind.h"
#include "graphics/graphics.h" #include "graphics/graphics.h"
@ -653,6 +655,311 @@ DBWexit()
return (CmdWarnWrite() == 1); 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 */ 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 * 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: */ /* Forward reference: */
@ -82,8 +92,8 @@ extern int DBWToolDraw();
* toolFindPoint -- * toolFindPoint --
* *
* Returns the point in root coordinates. * Returns the point in root coordinates.
* If DBWSnapToGrid is DBW_SNAP_USER, pick the nearest point that is * If DBWSnapToGrid is DBW_UNITS_USER, pick the nearest point that is
* aligned with the window's grid. If DBWSnapToGrid is DBW_SNAP_LAMBDA, * aligned with the window's grid. If DBWSnapToGrid is DBW_UNITS_LAMBDA,
* pick the nearest point that is an integer lambda value. * pick the nearest point that is an integer lambda value.
* *
* Results: * Results:
@ -120,7 +130,7 @@ toolFindPoint(p, rootPoint, rootArea)
if (!GEO_ENCLOSE(p, &WindCurrentWindow->w_screenArea)) return NULL; if (!GEO_ENCLOSE(p, &WindCurrentWindow->w_screenArea)) return NULL;
WindPointToSurface(WindCurrentWindow, p, rootPoint, rootArea); WindPointToSurface(WindCurrentWindow, p, rootPoint, rootArea);
if (DBWSnapToGrid != DBW_SNAP_INTERNAL) if (DBWSnapToGrid != DBW_UNITS_INTERNAL)
ToolSnapToGrid(WindCurrentWindow, rootPoint, rootArea); ToolSnapToGrid(WindCurrentWindow, rootPoint, rootArea);
return WindCurrentWindow; return WindCurrentWindow;
@ -764,7 +774,10 @@ DBWDrawBox(window, plane)
} }
int int
dbwBoxAlways1() dbwBoxAlways1(
Tile *tile, /* (unused) */
TileType dinfo, /* (unused) */
ClientData clientdata) /* (unused) */
{ {
return 1; return 1;
} }
@ -841,8 +854,8 @@ DBWResetBox(CellDef *def)
* Repositions the box by one of its corners. * Repositions the box by one of its corners.
* If the point given to reposition the box is in screen coordinates, * 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 * the box corner is snapped to the user's grid (set with the :grid
* command) if DBWSnapToGrid is DBW_SNAP_USER. If DBWSnapToGrid is * command) if DBWSnapToGrid is DBW_UNITS_USER. If DBWSnapToGrid is
* DBW_SNAP_LAMBDA, the box corner is snapped to the nearest integer * DBW_UNITS_LAMBDA, the box corner is snapped to the nearest integer
* lambda value. * lambda value.
* *
* Results: * Results:
@ -945,8 +958,8 @@ ToolMoveBox(corner, point, screenCoords, rootDef)
* *
* If the point given to reposition the box is in screen coordinates, * 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 * the box corner is snapped to the user's grid (set with the :grid
* command) if DBWSnapToGrid is DBW_SNAP_USER. If DBWSnapToGrid is * command) if DBWSnapToGrid is DBW_UNITS_USER. If DBWSnapToGrid is
* DBW_SNAP_LAMBDA, the box corner is snapped to the nearest integer * DBW_UNITS_LAMBDA, the box corner is snapped to the nearest integer
* lambda value. * lambda value.
* *
* Results: * Results:
@ -1089,7 +1102,7 @@ ToolSnapToGrid(w, p, rEnclose)
if (crec == NULL || p == NULL) if (crec == NULL || p == NULL)
return; return;
if (DBWSnapToGrid == DBW_SNAP_LAMBDA) if (DBWSnapToGrid == DBW_UNITS_LAMBDA)
{ {
lr.r_xbot = lr.r_ybot = 0; lr.r_xbot = lr.r_ybot = 0;
lr.r_xtop = DBLambda[1] / DBLambda[0]; lr.r_xtop = DBLambda[1] / DBLambda[0];

View File

@ -113,6 +113,7 @@ typedef struct DBW1 {
extern WindClient DBWclientID; extern WindClient DBWclientID;
extern int DBWSnapToGrid; extern int DBWSnapToGrid;
extern int DBWUnits;
extern int DBWMaxTechStyles; extern int DBWMaxTechStyles;
extern int DBWMaxTileStyles; extern int DBWMaxTileStyles;
@ -121,13 +122,17 @@ extern int DBWNumStyles;
extern int RtrPolyWidth, RtrMetalWidth, RtrContactWidth; extern int RtrPolyWidth, RtrMetalWidth, RtrContactWidth;
/* /*
* Exported procedure headers for redisplay * Exported procedure headers for redisplay and output
*/ */
extern int DBWWatchTiles(); extern int DBWWatchTiles();
extern void DBWAreaChanged(); extern void DBWAreaChanged();
extern void DBWLabelChanged(); extern void DBWLabelChanged();
extern void DBWDrawLabel(); 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 * Exported procedures and variables related to the technology file
@ -169,14 +174,36 @@ extern void DBWBoxHandler();
#define TOOL_ILG -1 #define TOOL_ILG -1
/* The following defines are used to indicate which coordinate system /* The following defines are used to indicate which coordinate system
* the cursor box snaps to when moved with mouse clicks (values for * is used when displaying or returning values. By default this is
* DBWSnapToGrid). * 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_UNITS_DEFAULT -1 /* backwards-compatible behavior */
#define DBW_SNAP_LAMBDA 1 /* lambda units (coarse grid) */ #define DBW_UNITS_INTERNAL 0 /* internal units */
#define DBW_SNAP_USER 2 /* user grid units (user grid) */ #define DBW_UNITS_LAMBDA 1 /* lambda units */
#define DBW_SNAP_MICRONS 3 /* micron 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 /* The following window mask can be used to select all database windows
* for things like the mask parameter to DBWAreaChanged. * for things like the mask parameter to DBWAreaChanged.

View File

@ -334,23 +334,23 @@
</TR> </TR>
<TR> <TR>
<TD> <A HREF=undo.html> <B>undo</B></A> </TD> <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=updatedisplay.html> <B>updatedisplay</B></A> </TD>
<TD> <A HREF=version.html> <B>version</B></A> </TD>
</TR> </TR>
<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=view.html> <B>view</B></A> </TD>
<TD> <A HREF=windowborder.html> <B>windowborder</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>
<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=windownames.html> <B>windownames</B></A> </TD>
<TD> <A HREF=windowscrollbars.html> <B>windowscrollbars</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>
<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=zoom.html> <B>zoom</B></A> </TD>
<TD> <A HREF=tk_path_name.html> <I>tk_path_name</I></A> </TD> <TD> <A HREF=tk_path_name.html> <I>tk_path_name</I></A> </TD>
<TD> </TD>
</TR> </TR>
</TBODY> </TBODY>
</TABLE> </TABLE>

View File

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

View File

@ -42,9 +42,11 @@ Circuit netlist extractor
<DL> <DL>
<DT> <B>capacitance</B> <DT> <B>capacitance</B>
<DD> Extract local parasitic capacitance values to substrate <DD> Extract local parasitic capacitance values to substrate
<DT> <B>resistance</B> <DT> <B>coupling</B>
<DD> Extract lumped resistance values. Note that this <DD> Extract the parasitic coupling capacitance between
is <I>not</I> the same as full parasitic resistance. nodes.
<DT> <B>lumped</B>
<DD> Extract lumped resistance values.
The values extracted are "lumped" resistance and The values extracted are "lumped" resistance and
indicate the value for which the delay through the indicate the value for which the delay through the
net can be computed with R times C, where R is 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 command. Lumped resistances have no meaning in
SPICE netlists and will only be used when running SPICE netlists and will only be used when running
<B>ext2sim</B> to generate a .sim netlist. <B>ext2sim</B> to generate a .sim netlist.
<DT> <B>coupling</B> Prior to magic version 8.3.597, this option was
<DD> Extract the parasitic coupling capacitance between <B>resistance</B>, but as that was often confused
nodes. with full parasitic resistance extraction, it has
been changed.
<DT> <B>length</B> <DT> <B>length</B>
<DD> Extract the length of the shortest path from a driver <DD> Extract the length of the shortest path from a driver
to a receiver, for computing more accurate parasitic to a receiver, for computing more accurate parasitic
@ -73,7 +76,7 @@ Circuit netlist extractor
array instances, is guaranteed to be strictly positive. array instances, is guaranteed to be strictly positive.
<DT> <B>all</B> <DT> <B>all</B>
<DD> Apply all standard options (does not include options <DD> Apply all standard options (does not include options
"local", "labelcheck", or "aliases"). "local", "labelcheck", "aliases", or "resistance").
<DT> <B>local</B> <DT> <B>local</B>
<DD> Write all .ext files to the current working directory. <DD> Write all .ext files to the current working directory.
If not specified, each .ext file will be placed in the 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 but will usually just slow down processing by commands
like "ext2spice" that use the .ext file contents, so it like "ext2spice" that use the .ext file contents, so it
is disabled by default. 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> </DL>
</BLOCKQUOTE> </BLOCKQUOTE>
These options (except for "local") determine how much These options (except for "local") determine how much
@ -213,7 +238,9 @@ Circuit netlist extractor
<I>Warning:</I> This operation immediately modifies the <I>Warning:</I> This operation immediately modifies the
existing layout in preparation for extraction. Label existing layout in preparation for extraction. Label
modifications are permanent, and cannot be undone. All 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>] <DT> <B>warn</B> [[<B>no</B>] <I>option</I>]
<DD> Enable/disable reporting of non-fatal errors, where <I>option</I> <DD> Enable/disable reporting of non-fatal errors, where <I>option</I>
may be one of the following: may be one of the following:

View File

@ -92,17 +92,25 @@ information.
The <B>extresist</B> command provides a method for generating The <B>extresist</B> command provides a method for generating
a more detailed model of resistance, in which long network a more detailed model of resistance, in which long network
routes and branching routes are replaced with resistor devices 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 Using <B>extresist</B> as a standalone command is a multi-step
necessary to run both <B>extract</B> and <B>ext2sim</B> to get process. It is first necessary to run <B>extract</B> to get
the initial netlist (with lumped, not detailed, resistances). the initial netlist.
After a <TT>.sim</TT> file has been generated, the After a <TT>.ext</TT> file has been generated, the
<B>extresist all</B> command may be run. The output is <B>extresist</B> command may be run. The output is
a file <TT>.res.ext</TT> for each cell in the hierarchy. a file <TT>.res.ext</TT> for each cell in the hierarchy.
Finally, with the option <B>extresist on</B> set, Finally, with the option <B>extresist on</B> set, <B>ext2spice</B>
<B>ext2sim</B> or <B>ext2spice</B> will generate the final, will generate the final, detailed simulation file. <P>
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 More details on using <B>extresist</B> can be found in
<B>magic</B> Tutorial number 8. <B>magic</B> Tutorial number 8.
@ -117,6 +125,7 @@ information.
<BLOCKQUOTE> <BLOCKQUOTE>
<A HREF=extract.html><B>extract</B></A> <BR> <A HREF=extract.html><B>extract</B></A> <BR>
<A HREF=ext2sim.html><B>ext2sim</B></A> <BR> <A HREF=ext2sim.html><B>ext2sim</B></A> <BR>
<A HREF=ext2spice.html><B>ext2spice</B></A> <BR>
</BLOCKQUOTE> </BLOCKQUOTE>
<P><IMG SRC=graphics/line1.gif><P> <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. than to subsplit the internal grid to such a fine value.
The "<B>cif limit</B>" function may also be used to limit The "<B>cif limit</B>" function may also be used to limit
grid subdivision to a minimum value. 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>] <DT> <B>unique</B> [<B>yes</B>|<B>no</B>]
<DD> When reading a GDS file, this option forces magic to rename <DD> When reading a GDS file, this option forces magic to rename
cell definitions in the database when a cell of the same name 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> to another layer. <P>
</BLOCKQUOTE> </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> <H3>Implementation Notes:</H3>
<BLOCKQUOTE> <BLOCKQUOTE>
<B>label</B> is implemented as a built-in command in <B>magic</B>. <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> <H3>Usage:</H3>
<BLOCKQUOTE> <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> <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>
</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 with the key is returned. With both arguments, the string
<I>value</I> is associated with the string <I>key</I> as a <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 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>
<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> <DL>
<DT> <B>GDS_FILE</B> <DT> <B>GDS_FILE</B>
<DD> The value is the name of a GDS file which contains the mask <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 <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 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 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> <DT> <B>GDS_END</B>
<DD> If a <B>GDS_FILE</B> is defined, then this value indicates the <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 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 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> <DT> <B>LEFview</B>
<DD> If set to <B>TRUE</B>, this cell is an abstract view such as that <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 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 corresponding to the abutment box of the cell, in magic's internal
units. The abutment box is automatically read from LEF files, but units. The abutment box is automatically read from LEF files, but
may be defined for any file and can be used for placement alignment. 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> <DT> <B>OBS_BBOX</B>
<DD> This property value is a space-sparated list of four integer values <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 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 will be entirely covered in obstruction layers (unless cut-outs
are required to accommodate pins). Any set-back applied by the are required to accommodate pins). Any set-back applied by the
"lef write -hide <value>" option will be applied to this obstruction "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> <DT> <B>flatten</B>
<DD> This property is used in conjunction with the "flatten -doproperty" <DD> This property is used in conjunction with the "flatten -doproperty"
command option and marks the cell for flattening. Cells without 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 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, 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, 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> </DL>
</BLOCKQUOTE> </BLOCKQUOTE>
@ -157,6 +220,11 @@ Attach a "property" (string key and value pair) to the edit cell
the cell definition structure. the cell definition structure.
</BLOCKQUOTE> </BLOCKQUOTE>
<H3>See Also:</H3>
<BLOCKQUOTE>
<A HREF=units.html><B>units</B></A> <BR>
</BLOCKQUOTE>
<P><IMG SRC=graphics/line1.gif><P> <P><IMG SRC=graphics/line1.gif><P>
<TABLE BORDER=0> <TABLE BORDER=0>
<TR> <TR>

View File

@ -39,21 +39,15 @@ in the selected grid.
feature size, and <B>user</B>, based on the value given by the feature size, and <B>user</B>, based on the value given by the
user to the <B>grid</B> command. <P> user to the <B>grid</B> command. <P>
In addition to changing the behavior of the box to mouse Historically, in addition to changing the behavior of the box
button events, the <B>snap</B> command also changes the way to mouse button events, the <B>snap</B> command also changed
that <A HREF=distance.html>distance measurements</A> are the way that <A HREF=distance.html>distance measurements</A>
interpreted in commands that take distance arguments, such are interpreted in commands that take distance arguments.
as <B>move</B>, <B>copy</B>, and <B>stretch</B>. An integer This behavior remains the default for backwards compatibility.
number with no other identifying units is interpreted as a The <B>units</B> command overrides this behavior and allows
measurement in the current snap grid. All other measurements <B>snap</B> to control only the box positioning behavior,
must have an identifying unit: <B>i</B> for internal units, independently of how unsuffixed values are parsed by the
<B>l</B> for lambda units, and <B>g</B> for user grid units interpreter. <P>
(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>
<B>snap</B> with no arguments returns the current snap grid <B>snap</B> with no arguments returns the current snap grid
type. <P> type. <P>
@ -80,6 +74,7 @@ in the selected grid.
<H3>See Also:</H3> <H3>See Also:</H3>
<BLOCKQUOTE> <BLOCKQUOTE>
<A HREF=units.html><B>units</B></A> <BR>
<A HREF=grid.html><B>grid</B></A> <BR> <A HREF=grid.html><B>grid</B></A> <BR>
</BLOCKQUOTE> </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> 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, <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 <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 <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 corners of the screen are at the indicated positions in the

View File

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

View File

@ -27,6 +27,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include <stdio.h> #include <stdio.h>
#include <string.h> // for memcpy() #include <string.h> // for memcpy()
#include <math.h> // for sqrt() for diagonal check #include <math.h> // for sqrt() for diagonal check
#include "tcltk/tclmagic.h"
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "tiles/tile.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/signals.h"
#include "utils/maxrect.h" #include "utils/maxrect.h"
#include "utils/malloc.h" #include "utils/malloc.h"
#include "utils/undo.h"
#include "textio/textio.h" #include "textio/textio.h"
#include "cif/CIFint.h"
int dbDRCDebug = 0; int dbDRCDebug = 0;
@ -48,7 +52,7 @@ int dbDRCDebug = 0;
static DRCCookie drcOverlapCookie = { static DRCCookie drcOverlapCookie = {
0, 0, 0, 0, 0, 0, 0, 0,
{ {0} }, { {0} }, { {0} }, { {0} },
0, 0, 0, 0, DRC_EXCEPTION_NONE, 0, 0,
DRC_OVERLAP_TAG, DRC_OVERLAP_TAG,
(DRCCookie *) NULL (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) * Euclidean-distance point-to-segment distance (squared)
* calculation (borrowed from XCircuit) * calculation (borrowed from XCircuit)
@ -140,8 +170,9 @@ drcCifPointToSegment(px, py, s1x, s1y, s2x, s2y)
*/ */
int int
areaCheck(tile, arg) areaCheck(tile, dinfo, arg)
Tile *tile; Tile *tile;
TileType dinfo;
struct drcClientData *arg; struct drcClientData *arg;
{ {
Rect rect; /* Area where error is to be recorded. */ Rect rect; /* Area where error is to be recorded. */
@ -195,7 +226,7 @@ areaCheck(tile, arg)
- arg->dCD_constraint->r_ytop + sdist) >= 0) - arg->dCD_constraint->r_ytop + sdist) >= 0)
&& ((sqx * sqx + sqy * sqy) >= ssdist)) && ((sqx * sqx + sqy * sqy) >= ssdist))
return 0; return 0;
else if (IsSplit(tile) && !SplitDirection(tile) && !SplitSide(tile)) else if (IsSplit(tile) && !SplitDirection(tile) && !(dinfo & TT_SIDE))
{ {
sstest = drcCifPointToSegment(arg->dCD_constraint->r_xbot + sdist, sstest = drcCifPointToSegment(arg->dCD_constraint->r_xbot + sdist,
arg->dCD_constraint->r_ytop - sdist, arg->dCD_constraint->r_ytop - sdist,
@ -210,7 +241,7 @@ areaCheck(tile, arg)
- arg->dCD_constraint->r_ytop + sdist) >= 0) - arg->dCD_constraint->r_ytop + sdist) >= 0)
&& ((sqx * sqx + sqy * sqy) >= ssdist)) && ((sqx * sqx + sqy * sqy) >= ssdist))
return 0; return 0;
else if (IsSplit(tile) && SplitDirection(tile) && SplitSide(tile)) else if (IsSplit(tile) && SplitDirection(tile) && (dinfo & TT_SIDE))
{ {
sstest = drcCifPointToSegment(arg->dCD_constraint->r_xtop - sdist, sstest = drcCifPointToSegment(arg->dCD_constraint->r_xtop - sdist,
arg->dCD_constraint->r_ytop - sdist, arg->dCD_constraint->r_ytop - sdist,
@ -226,7 +257,7 @@ areaCheck(tile, arg)
+ sdist - rect.r_ytop) >= 0) + sdist - rect.r_ytop) >= 0)
&& ((sqx * sqx + sqy * sqy) >= ssdist)) && ((sqx * sqx + sqy * sqy) >= ssdist))
return 0; return 0;
else if (IsSplit(tile) && SplitDirection(tile) && !SplitSide(tile)) else if (IsSplit(tile) && SplitDirection(tile) && !(dinfo & TT_SIDE))
{ {
sstest = drcCifPointToSegment(arg->dCD_constraint->r_xbot + sdist, sstest = drcCifPointToSegment(arg->dCD_constraint->r_xbot + sdist,
arg->dCD_constraint->r_ybot + sdist, arg->dCD_constraint->r_ybot + sdist,
@ -242,7 +273,7 @@ areaCheck(tile, arg)
+ sdist - rect.r_ytop) >= 0) + sdist - rect.r_ytop) >= 0)
&& ((sqx * sqx + sqy * sqy) >= ssdist)) && ((sqx * sqx + sqy * sqy) >= ssdist))
return 0; return 0;
else if (IsSplit(tile) && !SplitDirection(tile) && SplitSide(tile)) else if (IsSplit(tile) && !SplitDirection(tile) && (dinfo & TT_SIDE))
{ {
sstest = drcCifPointToSegment(arg->dCD_constraint->r_xtop - sdist, sstest = drcCifPointToSegment(arg->dCD_constraint->r_xtop - sdist,
arg->dCD_constraint->r_ybot + sdist, arg->dCD_constraint->r_ybot + sdist,
@ -306,8 +337,9 @@ areaCheck(tile, arg)
*/ */
int int
areaNMReject(tile, arg) areaNMReject(tile, dinfo, arg)
Tile *tile; Tile *tile;
TileType dinfo;
ClientData *arg; ClientData *arg;
{ {
Tile *checktile = (Tile *)arg; Tile *checktile = (Tile *)arg;
@ -337,8 +369,9 @@ areaNMReject(tile, arg)
*/ */
int int
areaNMCheck(tile, arg) areaNMCheck(tile, dinfo, arg)
Tile *tile; Tile *tile;
TileType dinfo;
struct drcClientData *arg; struct drcClientData *arg;
{ {
Rect rect; /* Area where error is to be recorded. */ Rect rect; /* Area where error is to be recorded. */
@ -375,7 +408,8 @@ areaNMCheck(tile, arg)
TTMaskSetOnlyType(&mask, TiGetLeftType(tile)); TTMaskSetOnlyType(&mask, TiGetLeftType(tile));
TTMaskSetType(&mask, TiGetRightType(tile)); TTMaskSetType(&mask, TiGetRightType(tile));
if (DBSrPaintNMArea((Tile *)tile, (Plane *)NULL, dinfo, arg->dCD_rlist, if (DBSrPaintNMArea((Tile *)tile, (Plane *)NULL,
TiGetTypeExact(tile) | dinfo, arg->dCD_rlist,
&mask, areaNMReject, (ClientData)tile) == 0) &mask, areaNMReject, (ClientData)tile) == 0)
return 0; return 0;
} }
@ -464,6 +498,13 @@ DRCBasicCheck (celldef, checkRect, clipRect, function, cdata)
DBResetTilePlane(celldef->cd_planes[planeNum], DRC_UNPROCESSED); DBResetTilePlane(celldef->cd_planes[planeNum], DRC_UNPROCESSED);
(void) DBSrPaintArea ((Tile *) NULL, celldef->cd_planes[planeNum], (void) DBSrPaintArea ((Tile *) NULL, celldef->cd_planes[planeNum],
checkRect, &DBAllTypeBits, drcTile, (ClientData) &arg); 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); drcCifCheck(&arg);
if (arg.dCD_rlist != NULL) freeMagic(arg.dCD_rlist); if (arg.dCD_rlist != NULL) freeMagic(arg.dCD_rlist);
@ -492,8 +533,9 @@ DRCBasicCheck (celldef, checkRect, clipRect, function, cdata)
*/ */
int int
drcTile (tile, arg) drcTile (tile, dinfo, arg)
Tile *tile; /* Tile being examined */ Tile *tile; /* Tile being examined */
TileType dinfo; /* Split tile information */
struct drcClientData *arg; struct drcClientData *arg;
{ {
DRCCookie *cptr; /* Current design rule on list */ DRCCookie *cptr; /* Current design rule on list */
@ -533,7 +575,7 @@ drcTile (tile, arg)
/* DRC searches only one direction on regular tiles, the split */ /* DRC searches only one direction on regular tiles, the split */
/* tiles are only processed for one of the two cases. */ /* tiles are only processed for one of the two cases. */
if (IsSplit(tile) && !SplitSide(tile)) if (IsSplit(tile) && !(dinfo & TT_SIDE))
{ {
int deltax, deltay; int deltax, deltay;
TileType tt, to; TileType tt, to;
@ -555,7 +597,7 @@ drcTile (tile, arg)
{ {
int deltax, deltay, w, h; int deltax, deltay, w, h;
double r; double r;
TileType dinfo, dsplit; TileType newdinfo, dsplit;
/* Work to be done: Handle triggering rules for non-Manhattan */ /* Work to be done: Handle triggering rules for non-Manhattan */
/* edges; especially important for the wide-spacing rule. */ /* edges; especially important for the wide-spacing rule. */
@ -605,7 +647,7 @@ drcTile (tile, arg)
if (SplitDirection(tile) == 0) deltay = -deltay; if (SplitDirection(tile) == 0) deltay = -deltay;
dinfo = TiGetTypeExact(tile) & (TT_DIAGONAL | TT_DIRECTION); newdinfo = TiGetTypeExact(tile) & (TT_DIAGONAL | TT_DIRECTION);
if (!(cptr->drcc_flags & DRC_REVERSE)) if (!(cptr->drcc_flags & DRC_REVERSE))
{ {
/* Forward case is behind the triangle */ /* Forward case is behind the triangle */
@ -613,19 +655,19 @@ drcTile (tile, arg)
deltay = -deltay; deltay = -deltay;
/* Split side changes in the reverse case */ /* Split side changes in the reverse case */
dinfo |= TT_SIDE; newdinfo |= TT_SIDE;
} }
/* The area to check is bounded between the diagonals of /* The area to check is bounded between the diagonals of
* tile and errRect (which is the tile area, offset). * tile and errRect (which is the tile area, offset).
* Pass errRect and dinfo to areaNMCheck using the * Pass errRect and newdinfo to areaNMCheck using the
* ClientData structure arg->dCD_rlist and arg->dCD_entries, * ClientData structure arg->dCD_rlist and arg->dCD_entries,
* which are not used by areaNMCheck. * which are not used by areaNMCheck.
*/ */
arg->dCD_rlist = (Rect *)mallocMagic(sizeof(Rect)); arg->dCD_rlist = (Rect *)mallocMagic(sizeof(Rect));
*(arg->dCD_rlist) = errRect; *(arg->dCD_rlist) = errRect;
arg->dCD_entries = dinfo; arg->dCD_entries = newdinfo;
if (dinfo & TT_SIDE) if (newdinfo & TT_SIDE)
arg->dCD_entries &= ~TT_SIDE; arg->dCD_entries &= ~TT_SIDE;
else else
arg->dCD_entries |= TT_SIDE; arg->dCD_entries |= TT_SIDE;
@ -637,7 +679,7 @@ drcTile (tile, arg)
errRect.r_ytop += deltay; errRect.r_ytop += deltay;
DBSrPaintNMArea((Tile *) NULL, DBSrPaintNMArea((Tile *) NULL,
arg->dCD_celldef->cd_planes[cptr->drcc_plane], dinfo, arg->dCD_celldef->cd_planes[cptr->drcc_plane], newdinfo,
&errRect, &tmpMask, areaNMCheck, (ClientData) arg); &errRect, &tmpMask, areaNMCheck, (ClientData) arg);
arg->dCD_entries = 0; arg->dCD_entries = 0;
@ -722,6 +764,43 @@ drcTile (tile, arg)
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL; for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
cptr = cptr->drcc_next) 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 */ /* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
/* the code above for non-Manhattan shapes and do not */ /* the code above for non-Manhattan shapes and do not */
/* need to be processed again. */ /* need to be processed again. */
@ -1131,6 +1210,49 @@ drcTile (tile, arg)
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL; for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
cptr = cptr->drcc_next) 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 */ /* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
/* the code above for non-Manhattan shapes and do not */ /* the code above for non-Manhattan shapes and do not */
/* need to be processed again. */ /* need to be processed again. */

View File

@ -603,8 +603,9 @@ drcCifCheck(arg)
*/ */
int int
drcCifTile (tile, arg) drcCifTile (tile, dinfo, arg)
Tile *tile; /* Tile being examined */ Tile *tile; /* Tile being examined */
TileType dinfo; /* Split tile information */
struct drcClientData *arg; struct drcClientData *arg;
{ {
DRCCookie *cptr; /* Current design rule on list */ DRCCookie *cptr; /* Current design rule on list */
@ -628,7 +629,7 @@ drcCifTile (tile, arg)
/* check. */ /* check. */
if (IsSplit(tile)) if (IsSplit(tile))
if (SplitSide(tile)) if (dinfo & TT_SIDE)
goto tbcheck; goto tbcheck;
/* /*
@ -826,7 +827,7 @@ tbcheck:
/* bottom check. */ /* bottom check. */
if (IsSplit(tile)) if (IsSplit(tile))
if (SplitSide(tile) == SplitDirection(tile)) if (((dinfo & TT_SIDE) ? 1 : 0) == SplitDirection(tile))
return 0; return 0;
/* /*
@ -1031,8 +1032,9 @@ tbcheck:
*/ */
int int
areaCifCheck(tile, arg) areaCifCheck(tile, dinfo, arg)
Tile *tile; Tile *tile;
TileType dinfo;
struct drcClientData *arg; struct drcClientData *arg;
{ {
Rect rect; /* Area where error is to be recorded. */ Rect rect; /* Area where error is to be recorded. */
@ -1085,7 +1087,7 @@ areaCifCheck(tile, arg)
- arg->dCD_constraint->r_ytop + sdist) >= 0) - arg->dCD_constraint->r_ytop + sdist) >= 0)
&& ((sqx * sqx + sqy * sqy) >= ssdist)) && ((sqx * sqx + sqy * sqy) >= ssdist))
return 0; return 0;
else if (IsSplit(tile) && !SplitDirection(tile) && !SplitSide(tile)) else if (IsSplit(tile) && !SplitDirection(tile) && !(dinfo & TT_SIDE))
{ {
sstest = drcCifPointToSegment(arg->dCD_constraint->r_xbot + sdist, sstest = drcCifPointToSegment(arg->dCD_constraint->r_xbot + sdist,
arg->dCD_constraint->r_ytop - sdist, arg->dCD_constraint->r_ytop - sdist,
@ -1100,7 +1102,7 @@ areaCifCheck(tile, arg)
- arg->dCD_constraint->r_ytop + sdist) >= 0) - arg->dCD_constraint->r_ytop + sdist) >= 0)
&& ((sqx * sqx + sqy * sqy) >= ssdist)) && ((sqx * sqx + sqy * sqy) >= ssdist))
return 0; return 0;
else if (IsSplit(tile) && SplitDirection(tile) && SplitSide(tile)) else if (IsSplit(tile) && SplitDirection(tile) && (dinfo & TT_SIDE))
{ {
sstest = drcCifPointToSegment(arg->dCD_constraint->r_xtop - sdist, sstest = drcCifPointToSegment(arg->dCD_constraint->r_xtop - sdist,
arg->dCD_constraint->r_ytop - sdist, arg->dCD_constraint->r_ytop - sdist,
@ -1116,7 +1118,7 @@ areaCifCheck(tile, arg)
+ sdist - cifrect.r_ytop) >= 0) + sdist - cifrect.r_ytop) >= 0)
&& ((sqx * sqx + sqy * sqy) >= ssdist)) && ((sqx * sqx + sqy * sqy) >= ssdist))
return 0; return 0;
else if (IsSplit(tile) && SplitDirection(tile) && !SplitSide(tile)) else if (IsSplit(tile) && SplitDirection(tile) && !(dinfo & TT_SIDE))
{ {
sstest = drcCifPointToSegment(arg->dCD_constraint->r_xbot + sdist, sstest = drcCifPointToSegment(arg->dCD_constraint->r_xbot + sdist,
arg->dCD_constraint->r_ybot + sdist, arg->dCD_constraint->r_ybot + sdist,
@ -1132,7 +1134,7 @@ areaCifCheck(tile, arg)
+ sdist - cifrect.r_ytop) >= 0) + sdist - cifrect.r_ytop) >= 0)
&& ((sqx * sqx + sqy * sqy) >= ssdist)) && ((sqx * sqx + sqy * sqy) >= ssdist))
return 0; return 0;
else if (IsSplit(tile) && !SplitDirection(tile) && SplitSide(tile)) else if (IsSplit(tile) && !SplitDirection(tile) && (dinfo & TT_SIDE))
{ {
sstest = drcCifPointToSegment(arg->dCD_constraint->r_xtop - sdist, sstest = drcCifPointToSegment(arg->dCD_constraint->r_xtop - sdist,
arg->dCD_constraint->r_ybot + sdist, arg->dCD_constraint->r_ybot + sdist,

View File

@ -639,9 +639,10 @@ checkDone:
/* ARGSUSED */ /* ARGSUSED */
int int
drcCheckTile(tile, arg) drcCheckTile(tile, dinfo, arg)
Tile * tile; /* tile in DRC_CHECK plane */ Tile *tile; /* Tile in DRC_CHECK plane */
ClientData arg; /* Not used. */ TileType dinfo; /* Split tile information (unused) */
ClientData arg; /* Not used. */
{ {
Rect square; /* Square area of the checkerboard Rect square; /* Square area of the checkerboard
* being processed right now. * being processed right now.
@ -767,13 +768,15 @@ drcCheckTile(tile, arg)
*/ */
int int
drcXorFunc(tile) drcXorFunc(tile, dinfo, clientdata)
Tile *tile; Tile *tile;
TileType dinfo;
ClientData clientdata;
{ {
Rect area; Rect area;
TiToRect(tile, &area); TiToRect(tile, &area);
DBPaintPlane(drcDisplayPlane, &area, drcXorTable, (PaintUndoInfo *) NULL); DBNMPaintPlane(drcDisplayPlane, dinfo, &area, drcXorTable, (PaintUndoInfo *) NULL);
return 0; return 0;
} }
@ -782,14 +785,15 @@ drcXorFunc(tile)
*/ */
int int
drcPutBackFunc(tile, cellDef) drcPutBackFunc(tile, dinfo, cellDef)
Tile *tile; /* Error tile, from drcTempPlane. */ Tile *tile; /* Error tile, from drcTempPlane. */
TileType dinfo; /* Split tile information */
CellDef *cellDef; /* Celldef in which to paint error. */ CellDef *cellDef; /* Celldef in which to paint error. */
{ {
Rect area; Rect area;
TiToRect(tile, &area); TiToRect(tile, &area);
DBPaintPlane(cellDef->cd_planes[PL_DRC_ERROR], &area, DBNMPaintPlane(cellDef->cd_planes[PL_DRC_ERROR], dinfo, &area,
DBStdPaintTbl(TiGetType(tile), PL_DRC_ERROR), DBStdPaintTbl(TiGetType(tile), PL_DRC_ERROR),
(PaintUndoInfo *) NULL); (PaintUndoInfo *) NULL);
return 0; return 0;
@ -816,8 +820,9 @@ drcPutBackFunc(tile, cellDef)
*/ */
int int
drcIncludeArea(tile, rect) drcIncludeArea(tile, dinfo, rect)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
Rect *rect; /* Rectangle in which to record total area. */ Rect *rect; /* Rectangle in which to record total area. */
{ {
Rect dum; Rect dum;

View File

@ -468,8 +468,9 @@ drcCheckRectSize(starttile, arg, cptr)
int int
MaxRectsExclude( MaxRectsExclude(
Tile *tile, Tile *tile, /* (unused) */
ClientData clientdata) TileType dinfo, /* (unused) */
ClientData clientdata) /* (unused) */
{ {
return 1; return 1;
} }

View File

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

View File

@ -52,7 +52,7 @@ static ClientData drcSubClientData; /* To be passed to error function. */
static DRCCookie drcSubcellCookie = { static DRCCookie drcSubcellCookie = {
0, 0, 0, 0, 0, 0, 0, 0,
{ {0} }, { {0} }, { {0} }, { {0} },
0, 0, 0, 0, DRC_EXCEPTION_NONE, 0, 0,
DRC_SUBCELL_OVERLAP_TAG, DRC_SUBCELL_OVERLAP_TAG,
(DRCCookie *) NULL (DRCCookie *) NULL
}; };
@ -65,7 +65,7 @@ static DRCCookie drcSubcellCookie = {
static DRCCookie drcInSubCookie = { static DRCCookie drcInSubCookie = {
0, 0, 0, 0, 0, 0, 0, 0,
{ {0} }, { {0} }, { {0} }, { {0} },
0, 0, 0, 0, DRC_EXCEPTION_NONE, 0, 0,
DRC_IN_SUBCELL_TAG, DRC_IN_SUBCELL_TAG,
(DRCCookie *) NULL (DRCCookie *) NULL
}; };
@ -79,7 +79,7 @@ static DRCCookie drcInSubCookie = {
static DRCCookie drcOffGridCookie = { static DRCCookie drcOffGridCookie = {
0, 0, 0, 0, 0, 0, 0, 0,
{ {0} }, { {0} }, { {0} }, { {0} },
0, 0, 0, 0, DRC_EXCEPTION_NONE, 0, 0,
DRC_OFFGRID_TAG, DRC_OFFGRID_TAG,
(DRCCookie *) NULL (DRCCookie *) NULL
}; };
@ -158,8 +158,9 @@ drcFindOtherCells(use, dlu)
*/ */
int int
drcSubCopyErrors(tile, cxp) drcSubCopyErrors(tile, dinfo, cxp)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
TreeContext *cxp; TreeContext *cxp;
{ {
Rect area; Rect area;
@ -317,7 +318,9 @@ drcSubcellFunc(subUse, dsa)
*/ */
int int
drcAlwaysOne() drcAlwaysOne(Tile *tile,
TileType dinfo,
ClientData clientdata)
{ {
return 1; return 1;
} }
@ -419,7 +422,6 @@ DRCFindInteractions(def, area, radius, interaction)
CellUse *use; CellUse *use;
SearchContext scx; SearchContext scx;
Rect searchArea, intArea; Rect searchArea, intArea;
int flags;
struct drcSubcellArg dsa; struct drcSubcellArg dsa;
struct drcLinkedUse *curDLU; struct drcLinkedUse *curDLU;
@ -492,24 +494,21 @@ DRCFindInteractions(def, area, radius, interaction)
/* If errors are being propagated up from child to parent, */ /* If errors are being propagated up from child to parent, */
/* then the interaction area is always valid. */ /* then the interaction area is always valid. */
if (!(flags & PROPAGATE_FLAG)) for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
{ {
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++) if (DBSrPaintArea((Tile *) NULL, def->cd_planes[i],
&intArea, &DBAllButSpaceBits, drcAlwaysOne,
(ClientData) NULL) != 0)
{ {
if (DBSrPaintArea((Tile *) NULL, def->cd_planes[i], use = (CellUse *) -1;
&intArea, &DBAllButSpaceBits, drcAlwaysOne, break;
(ClientData) NULL) != 0)
{
use = (CellUse *) -1;
break;
}
} }
scx.scx_use = DRCDummyUse;
scx.scx_trans = GeoIdentityTransform;
scx.scx_area = intArea;
if (DBTreeSrCells(&scx, 0, drcSubCheckPaint, (ClientData) &use) == 0)
return 0;
} }
scx.scx_use = DRCDummyUse;
scx.scx_trans = GeoIdentityTransform;
scx.scx_area = intArea;
if (DBTreeSrCells(&scx, 0, drcSubCheckPaint, (ClientData) &use) == 0)
return 0;
/* OK, no more excuses, there's really an interaction area here. */ /* OK, no more excuses, there's really an interaction area here. */
@ -540,8 +539,9 @@ DRCFindInteractions(def, area, radius, interaction)
*/ */
int int
drcExactOverlapCheck(tile, arg) drcExactOverlapCheck(tile, dinfo, arg)
Tile *tile; /* Tile to check. */ Tile *tile; /* Tile to check. */
TileType dinfo; /* Split tile information (unused) */
struct drcClientData *arg; /* How to detect and process errors. */ struct drcClientData *arg; /* How to detect and process errors. */
{ {
Rect rect; Rect rect;
@ -579,8 +579,9 @@ drcExactOverlapCheck(tile, arg)
*/ */
int int
drcExactOverlapTile(tile, cxp) drcExactOverlapTile(tile, dinfo, cxp)
Tile *tile; /* Tile that must overlap exactly. */ Tile *tile; /* Tile that must overlap exactly. */
TileType dinfo; /* Split tile information (unused) */
TreeContext *cxp; /* Tells how to translate out of subcell. TreeContext *cxp; /* Tells how to translate out of subcell.
* The client data must be a drcClientData * The client data must be a drcClientData
* record, and the caller must have filled * record, and the caller must have filled
@ -825,6 +826,7 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
*/ */
subArea = *erasebox; subArea = *erasebox;
GeoClip(&subArea, &cliparea); GeoClip(&subArea, &cliparea);
if (GEO_RECTNULL(&subArea)) continue;
GEO_EXPAND(&subArea, DRCTechHalo, &intArea); GEO_EXPAND(&subArea, DRCTechHalo, &intArea);
errorSaveType = DRCErrorType; errorSaveType = DRCErrorType;

View File

@ -72,6 +72,12 @@ static int drcRulesOptimized = 0;
static int DRCtag = 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. * Forward declarations.
*/ */
@ -79,6 +85,7 @@ int drcWidth(), drcSpacing(), drcEdge(), drcNoOverlap();
int drcExactOverlap(), drcExtend(); int drcExactOverlap(), drcExtend();
int drcSurround(), drcRectOnly(), drcOverhang(); int drcSurround(), drcRectOnly(), drcOverhang();
int drcStepSize(), drcOption(), drcOffGrid(); int drcStepSize(), drcOption(), drcOffGrid();
int drcException(), drcExemption();
int drcMaxwidth(), drcArea(), drcRectangle(), drcAngles(); int drcMaxwidth(), drcArea(), drcRectangle(), drcAngles();
int drcCifSetStyle(), drcCifWidth(), drcCifSpacing(); int drcCifSetStyle(), drcCifWidth(), drcCifSpacing();
int drcCifMaxwidth(), drcCifArea(); int drcCifMaxwidth(), drcCifArea();
@ -301,6 +308,12 @@ drcTechFreeStyle()
/* Clear the Why string list */ /* Clear the Why string list */
freeMagic(DRCCurStyle->DRCWhyList); 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); freeMagic(DRCCurStyle);
DRCCurStyle = NULL; DRCCurStyle = NULL;
} }
@ -384,6 +397,60 @@ drcWhyCreate(whystring)
return DRCCurStyle->DRCWhySize; 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->DRCStepSize = 0;
DRCCurStyle->DRCFlags = (char)0; DRCCurStyle->DRCFlags = (char)0;
DRCCurStyle->DRCWhySize = 0; DRCCurStyle->DRCWhySize = 0;
DRCCurStyle->DRCExceptionList = (char **)NULL;
DRCCurStyle->DRCExceptionSize = 0;
HashInit(&DRCWhyErrorTable, 16, HT_STRINGKEYS); HashInit(&DRCWhyErrorTable, 16, HT_STRINGKEYS);
@ -663,6 +732,7 @@ DRCTechStyleInit()
} }
drcCifInit(); 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_plane = planeto;
(cookie)->drcc_mod = 0; (cookie)->drcc_mod = 0;
(cookie)->drcc_cmod = 0; (cookie)->drcc_cmod = 0;
(cookie)->drcc_exception = drcCurException;
} }
// This is like drcCifAssign, but checks for bad plane numbers in planeto and // 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 */ int (*rk_proc)(); /* Procedure implementing this keyword */
const char *rk_err; /* Error message */ const char *rk_err; /* Error message */
} ruleKeys[] = { } ruleKeys[] = {
{"angles", 4, 4, drcAngles, {"angles", 4, 4, drcAngles, "layers 45|90 why"},
"layers 45|90 why"},
{"edge", 8, 10, drcEdge, {"edge", 8, 10, drcEdge,
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"}, "layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
{"edge4way", 8, 10, drcEdge, {"edge4way", 8, 10, drcEdge,
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"}, "layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
{"exact_overlap", 2, 2, drcExactOverlap, {"exact_overlap", 2, 2, drcExactOverlap, "layers"},
"layers"}, {"exception", 2, 2, drcException, "name"},
{"exemption", 2, 2, drcExemption, "name"},
{"extend", 5, 6, drcExtend, {"extend", 5, 6, drcExtend,
"layers1 layers2 distance [option] why"}, "layers1 layers2 distance [option] why"},
{"no_overlap", 3, 3, drcNoOverlap, {"no_overlap", 3, 3, drcNoOverlap, "layers1 layers2"},
"layers1 layers2"}, {"option", 2, 2, drcOption, "option_name option_value"},
{"option", 2, 2, drcOption, {"overhang", 5, 5, drcOverhang, "layers1 layers2 distance why"},
"option_name option_value"}, {"rect_only", 3, 3, drcRectOnly, "layers why"},
{"overhang", 5, 5, drcOverhang,
"layers1 layers2 distance why"},
{"rect_only", 3, 3, drcRectOnly,
"layers why"},
{"spacing", 6, 7, drcSpacing, {"spacing", 6, 7, drcSpacing,
"layers1 layers2 separation [layers3] adjacency why"}, "layers1 layers2 separation [layers3] adjacency why"},
{"stepsize", 2, 2, drcStepSize, {"stepsize", 2, 2, drcStepSize, "step_size"},
"step_size"},
{"surround", 6, 7, drcSurround, {"surround", 6, 7, drcSurround,
"layers1 layers2 distance presence why"}, "layers1 layers2 distance presence why"},
{"width", 4, 5, drcWidth, {"width", 4, 5, drcWidth, "layers width why"},
"layers width why"},
{"widespacing", 7, 8, drcSpacing, {"widespacing", 7, 8, drcSpacing,
"layers1 width layers2 separation adjacency why"}, "layers1 width layers2 separation adjacency why"},
{"area", 5, 5, drcArea, {"area", 5, 5, drcArea, "layers area horizon why"},
"layers area horizon why"}, {"off_grid", 4, 4, drcOffGrid, "layers pitch why"},
{"off_grid", 4, 4, drcOffGrid, {"maxwidth", 4, 6, drcMaxwidth, "layers maxwidth bends why"},
"layers pitch why"}, {"cifstyle", 2, 2, drcCifSetStyle, "cif_style"},
{"maxwidth", 4, 6, drcMaxwidth, {"cifwidth", 4, 4, drcCifWidth, "layers width why"},
"layers maxwidth bends why"},
{"cifstyle", 2, 2, drcCifSetStyle,
"cif_style"},
{"cifwidth", 4, 4, drcCifWidth,
"layers width why"},
{"cifspacing", 6, 6, drcCifSpacing, {"cifspacing", 6, 6, drcCifSpacing,
"layers1 layers2 separation adjacency why"}, "layers1 layers2 separation adjacency why"},
{"cifarea", 5, 5, drcCifArea, {"cifarea", 5, 5, drcCifArea, "layers area horizon why"},
"layers area horizon why"}, {"cifmaxwidth", 5, 5, drcCifMaxwidth, "layers maxwidth bends why"},
{"cifmaxwidth", 5, 5, drcCifMaxwidth,
"layers maxwidth bends why"},
{"rectangle", 5, 5, drcRectangle, {"rectangle", 5, 5, drcRectangle,
"layers maxwidth [even|odd|any] why"}, "layers maxwidth [even|odd|any] why"},
{0} {0}
@ -1695,7 +1753,7 @@ drcMaxwidth(argc, argv)
if (PlaneMaskHasPlane(pmask2, plane2)) if (PlaneMaskHasPlane(pmask2, plane2))
break; break;
if (plane2 == plane) if (PlaneMaskHasPlane(pmask, plane2))
TechError("Warning: Exclude types for \"maxwidth\" are on the " TechError("Warning: Exclude types for \"maxwidth\" are on the "
"same plane and so cannot be checked.\n"); "same plane and so cannot be checked.\n");
} }
@ -3634,6 +3692,83 @@ drcRectangle(argc, argv)
return maxwidth; 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_dist > next->drcc_dist) continue;
if (dp->drcc_cdist > next->drcc_cdist) continue; if (dp->drcc_cdist > next->drcc_cdist) continue;
if (dp->drcc_plane != next->drcc_plane) continue; if (dp->drcc_plane != next->drcc_plane) continue;
if (dp->drcc_exception != next->drcc_exception) continue;
if (dp->drcc_flags & DRC_REVERSE) if (dp->drcc_flags & DRC_REVERSE)
{ {
if (!(next->drcc_flags & DRC_REVERSE)) continue; 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_mask; /* Legal types on RHS */
TileTypeBitMask drcc_corner; /* Types that trigger corner check */ TileTypeBitMask drcc_corner; /* Types that trigger corner check */
unsigned short drcc_flags; /* Miscellaneous flags, see below. */ unsigned short drcc_flags; /* Miscellaneous flags, see below. */
char drcc_exception; /* Index to list of exceptions */
int drcc_edgeplane; /* Plane of edge */ int drcc_edgeplane; /* Plane of edge */
int drcc_plane; /* Index of plane on which to check int drcc_plane; /* Index of plane on which to check
* legal types. */ * legal types. */
@ -91,6 +92,9 @@ typedef struct drccookie
#define DRC_UNPROCESSED CLIENTDEFAULT #define DRC_UNPROCESSED CLIENTDEFAULT
#define DRC_PROCESSED 1 #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 * Background DRC (DRC Idle proc) for Tcl-based Magic
*/ */
@ -177,6 +181,8 @@ typedef struct drcstyle
unsigned short DRCFlags; /* Option flags */ unsigned short DRCFlags; /* Option flags */
char **DRCWhyList; /* Indexed list of "why" text strings */ char **DRCWhyList; /* Indexed list of "why" text strings */
int DRCWhySize; /* Length of DRCWhyList */ int DRCWhySize; /* Length of DRCWhyList */
char **DRCExceptionList; /* Indexed list of DRC exceptions */
int DRCExceptionSize; /* Length of DRCExceptionList */
PaintResultType DRCPaintTable[NP][NT][NT]; PaintResultType DRCPaintTable[NP][NT][NT];
} DRCStyle; } DRCStyle;

View File

@ -35,9 +35,9 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
#include "dbwind/dbwind.h" /* for DBWclientID */ #include "dbwind/dbwind.h" /* for DBWclientID */
#include "commands/commands.h" /* for module auto-load */ #include "commands/commands.h" /* for module auto-load */
#include "textio/txcommands.h" #include "textio/txcommands.h"
#include "extract/extract.h" /* for extDevTable */
#include "extflat/extflat.h" #include "extflat/extflat.h"
#include "extflat/EFint.h" #include "extflat/EFint.h"
#include "extract/extract.h" /* for extDevTable */
#include "utils/runstats.h" #include "utils/runstats.h"
#include "utils/malloc.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 "commands/commands.h" /* for module auto-load */
#include "textio/txcommands.h" #include "textio/txcommands.h"
#include "extflat/extflat.h" #include "extflat/extflat.h"
#include "extflat/EFint.h"
#include "extract/extract.h" /* for extDevTable */ #include "extract/extract.h" /* for extDevTable */
#include "extflat/EFint.h"
#include "utils/runstats.h" #include "utils/runstats.h"
#include "ext2spice/ext2spice.h" #include "ext2spice/ext2spice.h"
/* C99 compat */
#include "extflat/extflat.h"
/* These global values are defined in ext2spice.c */ /* These global values are defined in ext2spice.c */
extern HashTable subcktNameTable; extern HashTable subcktNameTable;
extern DQueue subcktNameQueue; extern DQueue subcktNameQueue;
@ -242,20 +239,9 @@ spcHierWriteParams(
/* Write all requested parameters to the subcircuit call. */ /* Write all requested parameters to the subcircuit call. */
bool checkme = FALSE;
if ((!strcmp(EFDevTypes[dev->dev_type], "pfet_06v0_dss")) ||
(!strcmp(EFDevTypes[dev->dev_type], "nfet_06v0_dss")))
{
checkme = TRUE;
TxPrintf("Diagnostic: Parameter list for %s\n", EFDevTypes[dev->dev_type]);
}
plist = efGetDeviceParams(EFDevTypes[dev->dev_type]); plist = efGetDeviceParams(EFDevTypes[dev->dev_type]);
while (plist != NULL) while (plist != NULL)
{ {
if (checkme) TxPrintf("Plist entry %s %s\n", plist->parm_name, plist->parm_type);
switch (plist->parm_type[0]) switch (plist->parm_type[0])
{ {
case 'a': case 'a':
@ -356,7 +342,6 @@ spcHierWriteParams(
// Check for device length vs. terminal length // Check for device length vs. terminal length
if (plist->parm_type[1] == '\0' || plist->parm_type[1] == '0') if (plist->parm_type[1] == '\0' || plist->parm_type[1] == '0')
{ {
if (checkme) TxPrintf("Handling entry l or l0\n");
fprintf(esSpiceF, " %s=", plist->parm_name); fprintf(esSpiceF, " %s=", plist->parm_name);
if (esScale < 0) if (esScale < 0)
fprintf(esSpiceF, "%g", l * scale); fprintf(esSpiceF, "%g", l * scale);
@ -371,10 +356,8 @@ spcHierWriteParams(
{ {
/* l1, l2, etc. used to indicate the length of the terminal */ /* l1, l2, etc. used to indicate the length of the terminal */
/* Find value in dev_params */ /* Find value in dev_params */
if (checkme) TxPrintf("Handling entry l1 or l2\n");
for (dparam = dev->dev_params; dparam; dparam = dparam->parm_next) for (dparam = dev->dev_params; dparam; dparam = dparam->parm_next)
{ {
if (checkme) TxPrintf("Checking dev_params entry %s\n", dparam->parm_name);
if ((strlen(dparam->parm_name) > 2) && if ((strlen(dparam->parm_name) > 2) &&
(dparam->parm_name[0] == 'l') && (dparam->parm_name[0] == 'l') &&
(dparam->parm_name[1] == plist->parm_type[1]) && (dparam->parm_name[1] == plist->parm_type[1]) &&
@ -383,8 +366,6 @@ spcHierWriteParams(
int dval; int dval;
if (sscanf(&dparam->parm_name[3], "%d", &dval) == 1) if (sscanf(&dparam->parm_name[3], "%d", &dval) == 1)
{ {
if (checkme) TxPrintf("Handling dev_params entry %s (to be "
"culled at end)\n", dparam->parm_name);
fprintf(esSpiceF, " %s=", plist->parm_name); fprintf(esSpiceF, " %s=", plist->parm_name);
if (esScale < 0) if (esScale < 0)
fprintf(esSpiceF, "%g", dval * scale); fprintf(esSpiceF, "%g", dval * scale);
@ -653,7 +634,7 @@ subcktHierVisit(
if (hasports || is_top) if (hasports || is_top)
return subcktVisit(use, hierName, 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; return 0;
else else
return subcktVisit(use, hierName, is_top); return subcktVisit(use, hierName, is_top);
@ -1107,6 +1088,7 @@ spcdevHierVisit(
if (!has_model) if (!has_model)
{ {
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap); esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE); spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
} }
@ -1157,6 +1139,7 @@ spcdevHierVisit(
if (!has_model) if (!has_model)
{ {
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap); esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE); 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 "dbwind/dbwind.h" /* for DBWclientID */
#include "commands/commands.h" /* for module auto-load */ #include "commands/commands.h" /* for module auto-load */
#include "textio/txcommands.h" #include "textio/txcommands.h"
#include "extract/extract.h" /* for extDevTable */
#include "extflat/extflat.h" #include "extflat/extflat.h"
#include "extflat/EFint.h" #include "extflat/EFint.h"
#include "extract/extract.h" /* for extDevTable */
#include "utils/runstats.h" #include "utils/runstats.h"
#include "ext2spice/ext2spice.h" #include "ext2spice/ext2spice.h"
@ -1689,23 +1689,43 @@ subcktVisit(
HashStartSearch(&hs); HashStartSearch(&hs);
while ((he = HashNext(&def->def_nodes, &hs))) while ((he = HashNext(&def->def_nodes, &hs)))
{ {
bool found = FALSE;
sname = (EFNodeName *) HashGetValue(he); sname = (EFNodeName *) HashGetValue(he);
if (sname == NULL) continue; if (sname == NULL) continue;
snode = sname->efnn_node; snode = sname->efnn_node;
if ((snode == NULL) || !(snode->efnode_flags & EF_PORT)) continue; 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) for (nodeName = sname; nodeName != NULL; nodeName = nodeName->efnn_next)
{ {
if (found == TRUE) break;
portidx = nodeName->efnn_port; portidx = nodeName->efnn_port;
if (portidx < 0) continue; if (portidx < 0) continue;
if (nodeList[portidx] == NULL) if (nodeList[portidx] == NULL)
{ {
nodeList[portidx] = nodeName; nodeList[portidx] = nodeName;
found = TRUE;
} }
else if (EFHNBest(nodeName->efnn_hier, nodeList[portidx]->efnn_hier)) else if (EFHNBest(nodeName->efnn_hier, nodeList[portidx]->efnn_hier))
{ {
nodeList[portidx] = nodeName; nodeList[portidx] = nodeName;
found = TRUE;
} }
} }
} }
@ -1932,6 +1952,7 @@ topVisit(
{ {
char stmp[MAX_STR_SIZE]; char stmp[MAX_STR_SIZE];
int portidx; int portidx;
bool found = FALSE;
sname = (EFNodeName *) HashGetValue(he); sname = (EFNodeName *) HashGetValue(he);
if (sname == NULL) continue; /* Should not happen */ if (sname == NULL) continue; /* Should not happen */
@ -1939,33 +1960,68 @@ topVisit(
snode = sname->efnn_node; snode = sname->efnn_node;
if ((!snode) || (!(snode->efnode_flags & EF_PORT))) continue; 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) for (nodeName = sname; nodeName != NULL; nodeName = nodeName->efnn_next)
{ {
if (found == TRUE) break;
portidx = nodeName->efnn_port; portidx = nodeName->efnn_port;
if (portidx < 0) continue; 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) 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); EFHNSprintf(stmp, nodeName->efnn_hier);
pname = stmp; pname = stmp;
} }
else else
// pname = nodeSpiceName(snode->efnode_name->efnn_hier, NULL);
pname = nodeSpiceName(nodeName->efnn_hier, NULL); pname = nodeSpiceName(nodeName->efnn_hier, NULL);
if (heh == (HashEntry *)NULL) /* pname now resolved for log output */ if (heh == (HashEntry *)NULL) /* pname now resolved for log output */
@ -1983,7 +2039,10 @@ topVisit(
hep = HashFind(&portNameTable, pname); hep = HashFind(&portNameTable, pname);
HashSetValue(hep, (ClientData)(pointertype)nodeName->efnn_port); HashSetValue(hep, (ClientData)(pointertype)nodeName->efnn_port);
if (sorted_ports[portidx] == NULL) if (sorted_ports[portidx] == NULL)
{
sorted_ports[portidx] = StrDup((char **)NULL, pname); sorted_ports[portidx] = StrDup((char **)NULL, pname);
found = TRUE;
}
} }
else else
{ {
@ -3081,6 +3140,7 @@ spcdevVisit(
if (!has_model) if (!has_model)
{ {
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap); esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE); spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
} }
@ -3127,6 +3187,7 @@ spcdevVisit(
if (!has_model) if (!has_model)
{ {
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap); esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE); spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
} }
@ -3314,12 +3375,15 @@ spcdevSubstrate(
/* Canonical name */ /* Canonical name */
nn = (EFNodeName *) HashGetValue(he); nn = (EFNodeName *) HashGetValue(he);
if (outf) if (outf)
fprintf(outf, "%s", nodeSpiceName(nn->efnn_node->efnode_name->efnn_hier, {
NULL)); const char *spicename;
spicename = nodeSpiceName(nn->efnn_node->efnode_name->efnn_hier, NULL);
fprintf(outf, "%s", spicename);
}
/* Create node client if it doesn't exist */ /* Create node client if it doesn't exist */
if ((nodeClient *)nn->efnn_node->efnode_client == (nodeClient *)NULL) if ((nodeClient *)nn->efnn_node->efnode_client == (nodeClient *)NULL)
initNodeClientHier(nn->efnn_node); initNodeClient(nn->efnn_node);
/* Mark node as visited (set bit one higher than number of resist classes) */ /* Mark node as visited (set bit one higher than number of resist classes) */
if (esDistrJunct) if (esDistrJunct)

View File

@ -754,8 +754,9 @@ antennacheckVisit(
*/ */
int int
areaMarkFunc(tile, ams) areaMarkFunc(tile, dinfo, ams)
Tile *tile; Tile *tile;
TileType dinfo;
AntennaMarkStruct *ams; AntennaMarkStruct *ams;
{ {
Rect rect; Rect rect;
@ -778,8 +779,9 @@ areaMarkFunc(tile, ams)
*/ */
int int
areaAccumFunc(tile, gdas) areaAccumFunc(tile, dinfo, gdas)
Tile *tile; Tile *tile;
TileType dinfo;
GateDiffAccumStruct *gdas; GateDiffAccumStruct *gdas;
{ {
Rect *rect = &(gdas->r); Rect *rect = &(gdas->r);
@ -788,7 +790,7 @@ areaAccumFunc(tile, gdas)
/* Avoid double-counting the area of contacts */ /* Avoid double-counting the area of contacts */
if (IsSplit(tile)) if (IsSplit(tile))
type = SplitSide(tile) ? SplitRightType(tile) : SplitLeftType(tile); type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
else else
type = TiGetType(tile); type = TiGetType(tile);
@ -798,6 +800,7 @@ areaAccumFunc(tile, gdas)
TiToRect(tile, rect); TiToRect(tile, rect);
area = (dlong)(rect->r_xtop - rect->r_xbot) * (dlong)(rect->r_ytop - rect->r_ybot); area = (dlong)(rect->r_xtop - rect->r_xbot) * (dlong)(rect->r_ytop - rect->r_ybot);
if (IsSplit(tile)) area /= 2;
gdas->accum += area; gdas->accum += area;
return 0; return 0;
} }
@ -816,8 +819,9 @@ areaAccumFunc(tile, gdas)
*/ */
int int
antennaAccumFunc(tile, aaptr) antennaAccumFunc(tile, dinfo, aaptr)
Tile *tile; Tile *tile;
TileType dinfo; /* Not used, but should be handled */
AntennaAccumStruct *aaptr; AntennaAccumStruct *aaptr;
{ {
Rect *rect = &(aaptr->r); Rect *rect = &(aaptr->r);
@ -1003,6 +1007,7 @@ antennaAccumFunc(tile, aaptr)
TiToRect(tile, rect); TiToRect(tile, rect);
area = (dlong)(rect->r_xtop - rect->r_xbot) area = (dlong)(rect->r_xtop - rect->r_xbot)
* (dlong)(rect->r_ytop - rect->r_ybot); * (dlong)(rect->r_ytop - rect->r_ybot);
if (IsSplit(tile)) area /= 2;
typeareas[type] += area; typeareas[type] += area;
} }

View File

@ -34,8 +34,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header$";
#include "tiles/tile.h" #include "tiles/tile.h"
#include "database/database.h" /* for TileType definition */ #include "database/database.h" /* for TileType definition */
#include "extflat/extflat.h" #include "extflat/extflat.h"
#include "extflat/extparse.h"
#include "extflat/EFint.h" #include "extflat/EFint.h"
#include "extract/extract.h" /* for device class list */ #include "extract/extract.h"
#include "extract/extractInt.h" /* for extGetDevType() */ #include "extract/extractInt.h" /* for extGetDevType() */
/* C99 compat */ /* C99 compat */
@ -647,8 +648,21 @@ efBuildEquiv(def, nodeName1, nodeName2, resist, isspice)
return; return;
} }
else if (!resist) 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); "shorted.\n", nodeName1, nodeName2);
if (uptr1) *uptr1 = '_';
if (uptr2) *uptr2 = '_';
}
else else
/* Do not merge the nodes when folding in extresist parasitics */ /* Do not merge the nodes when folding in extresist parasitics */
return; return;
@ -860,13 +874,13 @@ efBuildDevice(
const Rect *r, /* Coordinates of 1x1 rectangle entirely inside device */ const Rect *r, /* Coordinates of 1x1 rectangle entirely inside device */
int argc, /* Size of argv */ int argc, /* Size of argv */
char *argv[]) /* Tokens for the rest of the dev line. char *argv[]) /* Tokens for the rest of the dev line.
* Starts with the last two position values, used to * Starts after the four device coordinate arguments.
* hash the device record. The next arguments depend * The next arguments (0, 1, or 2) depend on the type of
* on the type of device. The rest are taken in groups * device, followed by optional parameters. The rest are
* of 3, one for each terminal. Each group of 3 consists * taken in groups of 3, one for each terminal. Each
* of the node name to which the terminal connects, the * group of 3 consists of the node name to which the
* length of the terminal, and an attribute list (or the * terminal connects, the length of the terminal, and
* token 0). * an attribute list (or the token 0).
*/ */
{ {
int n, nterminals, pn; int n, nterminals, pn;
@ -878,7 +892,7 @@ efBuildDevice(
int dev_type; int dev_type;
char ptype, *pptr, **av; char ptype, *pptr, **av;
char devhash[64]; char devhash[64];
int argstart = 1; /* start of terminal list in argv[] */ int termstart;
bool hasModel = strcmp(type, "None") ? TRUE : FALSE; bool hasModel = strcmp(type, "None") ? TRUE : FALSE;
int area, perim; /* Total area, perimeter of primary type (i.e., channel) */ int area, perim; /* Total area, perimeter of primary type (i.e., channel) */
@ -893,24 +907,40 @@ efBuildDevice(
devtmp.dev_width = 0; devtmp.dev_width = 0;
devtmp.dev_params = NULL; devtmp.dev_params = NULL;
termstart = 1; /* Start of terminal list in argv[]; this is a default
* value if none of the cases below applies. The value
* of termstart does not initially account for parameter
* entries (<param>=<value>) but is adjusted as the
* parameters are parsed. The first terminal may be an
* (optional) substrate which is determined by whether
* the number of remaining arguments is divisible by 3
* or not.
*/
switch (class) switch (class)
{ {
case DEV_FET: case DEV_FET:
case DEV_MOSFET: case DEV_MOSFET:
case DEV_ASYMMETRIC: case DEV_ASYMMETRIC:
/* Terminals start after L and W values, substrate, and parameters */
termstart = 3;
break;
case DEV_BJT: case DEV_BJT:
argstart = 3; /* Terminals start after L and W values, plus parameters */
termstart = 2;
break; break;
case DEV_DIODE: case DEV_DIODE:
case DEV_NDIODE: case DEV_NDIODE:
case DEV_PDIODE: case DEV_PDIODE:
argstart = 0; /* Terminals start immediately after parameters */
termstart = 0;
break; break;
case DEV_RES: case DEV_RES:
case DEV_CAP: case DEV_CAP:
case DEV_CAPREV: case DEV_CAPREV:
if (hasModel) if (hasModel)
argstart = 2; /* Terminals start after L and W values, plus parameters */
termstart = 2;
/* Otherwise, terminals start after device value, plus parameters */
break; break;
case DEV_SUBCKT: case DEV_SUBCKT:
case DEV_VERILOGA: case DEV_VERILOGA:
@ -918,13 +948,14 @@ efBuildDevice(
case DEV_RSUBCKT: case DEV_RSUBCKT:
case DEV_CSUBCKT: case DEV_CSUBCKT:
case DEV_DSUBCKT: case DEV_DSUBCKT:
argstart = 0; /* Terminals start immediately after parameters */
termstart = 0;
} }
devp = efGetDeviceParams(type); devp = efGetDeviceParams(type);
/* Parse initial arguments for parameters */ /* Parse initial arguments for parameters */
while ((pptr = strchr(argv[argstart], '=')) != NULL) while ((pptr = strchr(argv[termstart], '=')) != NULL)
{ {
/* If the parameter is in the parameter list "devp", then save /* If the parameter is in the parameter list "devp", then save
* the value as appropriate. If not, then the entire phrase * the value as appropriate. If not, then the entire phrase
@ -936,7 +967,7 @@ efBuildDevice(
*pptr = '\0'; *pptr = '\0';
for (sparm = devp; sparm; sparm = sparm->parm_next) for (sparm = devp; sparm; sparm = sparm->parm_next)
if (!strncasecmp(sparm->parm_type, argv[argstart], 2)) if (!strncasecmp(sparm->parm_type, argv[termstart], 2))
break; break;
*pptr = '='; *pptr = '=';
if (sparm == NULL) if (sparm == NULL)
@ -944,18 +975,18 @@ efBuildDevice(
/* Copy the whole string into dev_params */ /* Copy the whole string into dev_params */
/* (parm_type and parm_scale records are not used) */ /* (parm_type and parm_scale records are not used) */
newparm = (DevParam *)mallocMagic(sizeof(DevParam)); newparm = (DevParam *)mallocMagic(sizeof(DevParam));
newparm->parm_name = StrDup((char **)NULL, argv[argstart]); newparm->parm_name = StrDup((char **)NULL, argv[termstart]);
newparm->parm_next = devtmp.dev_params; newparm->parm_next = devtmp.dev_params;
devtmp.dev_params = newparm; devtmp.dev_params = newparm;
argstart++; termstart++;
continue; continue;
} }
pptr++; pptr++;
switch(*argv[argstart]) switch(*argv[termstart])
{ {
case 'a': case 'a':
if ((pptr - argv[argstart]) == 2) if ((pptr - argv[termstart]) == 2)
devtmp.dev_area = (int)(0.5 + (float)atoi(pptr) devtmp.dev_area = (int)(0.5 + (float)atoi(pptr)
* locScale * locScale); * locScale * locScale);
else else
@ -963,7 +994,7 @@ efBuildDevice(
/* Check for a0, a1, a2, ... If a0, handle like "a". /* Check for a0, a1, a2, ... If a0, handle like "a".
* Otherwise, don't handle it here. * Otherwise, don't handle it here.
*/ */
pn = *(argv[argstart] + 1) - '0'; pn = *(argv[termstart] + 1) - '0';
if (pn == 0) if (pn == 0)
devtmp.dev_area = (int)(0.5 + (float)atoi(pptr) devtmp.dev_area = (int)(0.5 + (float)atoi(pptr)
* locScale * locScale); * locScale * locScale);
@ -971,21 +1002,21 @@ efBuildDevice(
break; break;
case 'p': case 'p':
if ((pptr - argv[argstart]) == 2) if ((pptr - argv[termstart]) == 2)
devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale); devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale);
else else
{ {
/* Check for p0, p1, p2, ... If p0, handle like "p". /* Check for p0, p1, p2, ... If p0, handle like "p".
* Otherwise, don't handle it here. * Otherwise, don't handle it here.
*/ */
pn = *(argv[argstart] + 1) - '0'; pn = *(argv[termstart] + 1) - '0';
if (pn == 0) if (pn == 0)
devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale); devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale);
} }
break; break;
case 'l': case 'l':
if ((pptr - argv[argstart]) == 2) if ((pptr - argv[termstart]) == 2)
devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale); devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale);
else else
{ {
@ -995,14 +1026,14 @@ efBuildDevice(
* values like "a1, a2, ..." or "p1, p2, ...". * values like "a1, a2, ..." or "p1, p2, ...".
*/ */
pn = *(argv[argstart] + 1) - '0'; pn = *(argv[termstart] + 1) - '0';
if (pn == 0) if (pn == 0)
devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale); devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale);
else else
{ {
/* Copy the whole string into dev_params */ /* Copy the whole string into dev_params */
newparm = (DevParam *)mallocMagic(sizeof(DevParam)); newparm = (DevParam *)mallocMagic(sizeof(DevParam));
newparm->parm_name = StrDup((char **)NULL, argv[argstart]); newparm->parm_name = StrDup((char **)NULL, argv[termstart]);
newparm->parm_next = devtmp.dev_params; newparm->parm_next = devtmp.dev_params;
devtmp.dev_params = newparm; devtmp.dev_params = newparm;
} }
@ -1010,7 +1041,28 @@ efBuildDevice(
break; break;
case 'w': case 'w':
devtmp.dev_width = (int)(0.5 + (float)atoi(pptr) * locScale); if ((pptr - argv[termstart]) == 2)
devtmp.dev_width = (int)(0.5 + (float)atoi(pptr) * locScale);
else
{
/* Check for w0, w1, w2, ... If w0, handle like "w".
* Otherwise, save it verbatim like an unknown parameter,
* because its value will not be calculated from terminal
* values like "a1, a2, ..." or "p1, p2, ...".
*/
pn = *(argv[termstart] + 1) - '0';
if (pn == 0)
devtmp.dev_width = (int)(0.5 + (float)atoi(pptr) * locScale);
else
{
/* Copy the whole string into dev_params */
newparm = (DevParam *)mallocMagic(sizeof(DevParam));
newparm->parm_name = StrDup((char **)NULL, argv[termstart]);
newparm->parm_next = devtmp.dev_params;
devtmp.dev_params = newparm;
}
}
break; break;
case 'c': case 'c':
devtmp.dev_cap = (float)atof(pptr); devtmp.dev_cap = (float)atof(pptr);
@ -1019,7 +1071,7 @@ efBuildDevice(
devtmp.dev_res = (float)atof(pptr); devtmp.dev_res = (float)atof(pptr);
break; break;
} }
argstart++; termstart++;
} }
/* Check for optional substrate node */ /* Check for optional substrate node */
@ -1027,6 +1079,7 @@ efBuildDevice(
{ {
case DEV_RES: case DEV_RES:
case DEV_CAP: case DEV_CAP:
case DEV_BJT:
case DEV_CAPREV: case DEV_CAPREV:
case DEV_RSUBCKT: case DEV_RSUBCKT:
case DEV_CSUBCKT: case DEV_CSUBCKT:
@ -1037,22 +1090,22 @@ efBuildDevice(
case DEV_DIODE: case DEV_DIODE:
case DEV_NDIODE: case DEV_NDIODE:
case DEV_PDIODE: case DEV_PDIODE:
n = argc - argstart; n = argc - termstart;
if ((n % 3) == 1) if ((n % 3) == 1)
{ {
if (strncmp(argv[argstart], "None", 4) != 0) if (strncmp(argv[termstart], "None", 4) != 0)
devtmp.dev_subsnode = efBuildDevNode(def, argv[argstart], TRUE); devtmp.dev_subsnode = efBuildDevNode(def, argv[termstart], TRUE);
argstart++; termstart++;
} }
break; break;
} }
/* Between argstart and argc, we should only have terminal triples */ /* Between termstart and argc, we should only have terminal triples */
if (((argc - argstart) % 3) != 0) if (((argc - termstart) % 3) != 0)
return 1; return 1;
nterminals = (argc - argstart) / 3; nterminals = (argc - termstart) / 3;
dev_type = efBuildAddStr(EFDevTypes, &EFDevNumTypes, TT_MAXTYPES, type); dev_type = efBuildAddStr(EFDevTypes, &EFDevNumTypes, TT_MAXTYPES, type);
@ -1215,17 +1268,17 @@ efBuildDevice(
case DEV_ASYMMETRIC: case DEV_ASYMMETRIC:
case DEV_BJT: case DEV_BJT:
/* "None" in the place of the substrate name means substrate is ignored */ /* "None" in the place of the substrate name means substrate is ignored */
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0)) if ((termstart == 3) && (strncmp(argv[2], "None", 4) != 0))
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE); newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
break; break;
case DEV_RES: case DEV_RES:
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0)) if ((termstart == 3) && (strncmp(argv[2], "None", 4) != 0))
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE); newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
break; break;
case DEV_CAP: case DEV_CAP:
case DEV_CAPREV: case DEV_CAPREV:
if ((argstart == 3) && (strncmp(argv[2], "None", 4) != 0)) if ((termstart == 3) && (strncmp(argv[2], "None", 4) != 0))
newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE); newdev->dev_subsnode = efBuildDevNode(def, argv[2], TRUE);
break; break;
@ -1235,7 +1288,7 @@ efBuildDevice(
#define TERM_PERIM 1 #define TERM_PERIM 1
#define TERM_ATTRS 2 #define TERM_ATTRS 2
for (av = &argv[argstart], n = 0; n < nterminals; n++, av += 3) for (av = &argv[termstart], n = 0; n < nterminals; n++, av += 3)
{ {
term = &newdev->dev_terms[n]; term = &newdev->dev_terms[n];
term->dterm_node = efBuildDevNode(def, av[TERM_NAME], FALSE); term->dterm_node = efBuildDevNode(def, av[TERM_NAME], FALSE);
@ -2063,7 +2116,7 @@ efNodeMerge(node1ptr, node2ptr)
/* Make all EFNodeNames point to "keeping" */ /* Make all EFNodeNames point to "keeping" */
if (removing->efnode_name) if (removing->efnode_name)
{ {
bool topportk, topportr, bestname; bool topportk, topportr, bestname, swapnames;
for (nn = removing->efnode_name; nn; nn = nn->efnn_next) for (nn = removing->efnode_name; nn; nn = nn->efnn_next)
{ {
@ -2074,10 +2127,31 @@ efNodeMerge(node1ptr, node2ptr)
topportk = (keeping->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE; topportk = (keeping->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
topportr = (removing->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE; topportr = (removing->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
/* Concatenate list of EFNodeNames, taking into account precedence */ /* The node "keeping" is being kept, but we need to decide which
if ((!keeping->efnode_name) || (!topportk && topportr) * node name of the two will be the node name of "keeping". If
|| EFHNBest(removing->efnode_name->efnn_hier, * "keeping" has the best node name, then we're good; otherwise,
keeping->efnode_name->efnn_hier)) * 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". * New official name is that of "removing".
@ -2164,6 +2238,14 @@ efNodeMerge(node1ptr, node2ptr)
if (removing->efnode_flags & EF_SUBS_NODE) if (removing->efnode_flags & EF_SUBS_NODE)
keeping->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 /* If EFSaveLocs is set, then merge any disjoint segments from
* removing to keeping. * 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/magic.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "textio/textio.h" #include "textio/textio.h"
#include "extflat/extparse.h"
extern char *efReadFileName;
extern int efReadLineNum;
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
extern int Tcl_printf(); extern int Tcl_printf();

View File

@ -61,15 +61,17 @@ int efFlatGlobHash(HierName *);
bool efFlatGlobCmp(HierName *, HierName *); bool efFlatGlobCmp(HierName *, HierName *);
char *efFlatGlobCopy(HierName *); char *efFlatGlobCopy(HierName *);
void efFlatGlobError(EFNodeName *nameGlob, EFNodeName *nameFlat); void efFlatGlobError(EFNodeName *nameGlob, EFNodeName *nameFlat);
int efAddNodes(HierContext *hc, bool stdcell); int efAddNodes(HierContext *hc, int flags);
int efAddConns(HierContext *hc, bool doWarn); int efAddConns(HierContext *hc, int flags);
int efAddOneConn(HierContext *hc, char *name1, char *name2, Connection *conn, bool doWarn); int efAddOneConn(HierContext *hc, char *name1, char *name2, Connection *conn, int flags);
/* Flags passed to efFlatNode() */ /* Flags passed to efFlatNode() */
#define FLATNODE_STDCELL 0x01 #define FLATNODE_STDCELL 0x01
#define FLATNODE_DOWARN 0x02 #define FLATNODE_DOWARN 0x02
#define FLATNODE_NOABSTRACT 0x04 #define FLATNODE_NOABSTRACT 0x04
#define FLATNODE_HIER 0x08
#define FLATNODE_CHILD 0x10
/* /*
@ -216,7 +218,7 @@ EFFlatBuildOneLevel(def, flags)
efFlatRootUse.use_def = efFlatRootDef; efFlatRootUse.use_def = efFlatRootDef;
/* Record all nodes down the hierarchy from here */ /* Record all nodes down the hierarchy from here */
flatnodeflags = 0; /* No FLATNODE_DOWARN */ flatnodeflags = FLATNODE_HIER; /* No FLATNODE_DOWARN */
efFlatNodes(&efFlatContext, INT2CD(flatnodeflags)); efFlatNodes(&efFlatContext, INT2CD(flatnodeflags));
/* Expand all subcells that contain connectivity information but */ /* Expand all subcells that contain connectivity information but */
@ -320,9 +322,7 @@ efFlatNodes(hc, clientData)
ClientData clientData; ClientData clientData;
{ {
int flags = (int)CD2INT(clientData); int flags = (int)CD2INT(clientData);
int hierflags = 0;
bool stdcell = (flags & FLATNODE_STDCELL) ? TRUE : FALSE;
bool doWarn = (flags & FLATNODE_DOWARN) ? TRUE : FALSE;
if (flags & FLATNODE_NOABSTRACT) if (flags & FLATNODE_NOABSTRACT)
{ {
@ -332,13 +332,19 @@ efFlatNodes(hc, clientData)
def->def_name); 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 */ /* Add all our own nodes to the table */
efAddNodes(hc, stdcell); efAddNodes(hc, flags);
/* Process our own connections and adjustments */ /* Process our own connections and adjustments */
(void) efAddConns(hc, doWarn); (void) efAddConns(hc, flags);
return (0); return (0);
} }
@ -386,11 +392,11 @@ efFlatNodesStdCell(hc)
} }
/* Add all our own nodes to the table */ /* Add all our own nodes to the table */
efAddNodes(hc, TRUE); efAddNodes(hc, (int)FLATNODE_STDCELL);
/* Process our own connections and adjustments */ /* Process our own connections and adjustments */
if (!(hc->hc_use->use_def->def_flags & DEF_SUBCIRCUIT)) if (!(hc->hc_use->use_def->def_flags & DEF_SUBCIRCUIT))
(void) efAddConns(hc, TRUE); (void) efAddConns(hc, (int)FLATNODE_DOWARN);
return (0); return (0);
} }
@ -413,10 +419,10 @@ efFlatNodesDeviceless(hc, cdata)
if ((HashGetNumEntries(&hc->hc_use->use_def->def_devs) == 0) && (newcount == 0)) if ((HashGetNumEntries(&hc->hc_use->use_def->def_devs) == 0) && (newcount == 0))
{ {
/* Add all our own nodes to the table */ /* Add all our own nodes to the table */
efAddNodes(hc, TRUE); efAddNodes(hc, (int)FLATNODE_STDCELL);
/* Process our own connections and adjustments */ /* 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 */ /* Mark this definition as having no devices, so it will not be visited */
hc->hc_use->use_def->def_flags |= DEF_NODEVICES; hc->hc_use->use_def->def_flags |= DEF_NODEVICES;
@ -455,7 +461,7 @@ efFlatNodesDeviceless(hc, cdata)
int int
efAddNodes( efAddNodes(
HierContext *hc, HierContext *hc,
bool stdcell) int flags)
{ {
Def *def = hc->hc_use->use_def; Def *def = hc->hc_use->use_def;
EFNodeName *nn, *newname, *oldname; EFNodeName *nn, *newname, *oldname;
@ -465,6 +471,8 @@ efAddNodes(
HierName *hierName; HierName *hierName;
int size, asize; int size, asize;
HashEntry *he; 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; bool is_subcircuit = (def->def_flags & DEF_SUBCIRCUIT) ? TRUE : FALSE;
size = sizeof (EFNode) + (efNumResistClasses-1) * sizeof (EFPerimArea); size = sizeof (EFNode) + (efNumResistClasses-1) * sizeof (EFPerimArea);
@ -503,12 +511,15 @@ efAddNodes(
// If called with "hierarchy on", all local node caps and adjustments // If called with "hierarchy on", all local node caps and adjustments
// have been output and should be ignored. // 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_client = (ClientData) NULL;
newnode->efnode_flags = node->efnode_flags; newnode->efnode_flags = node->efnode_flags;
newnode->efnode_type = node->efnode_type; newnode->efnode_type = node->efnode_type;
newnode->efnode_num = 1; newnode->efnode_num = 1;
if (!stdcell) if (!stdcell && !is_child)
bcopy((char *) node->efnode_pa, (char *) newnode->efnode_pa, bcopy((char *) node->efnode_pa, (char *) newnode->efnode_pa,
efNumResistClasses * sizeof (EFPerimArea)); efNumResistClasses * sizeof (EFPerimArea));
else else
@ -601,7 +612,7 @@ efAddNodes(
int int
efAddConns( efAddConns(
HierContext *hc, HierContext *hc,
bool doWarn) int flags)
{ {
Connection *conn; Connection *conn;
@ -614,9 +625,9 @@ efAddConns(
{ {
/* Special case for speed when no array info is present */ /* Special case for speed when no array info is present */
if (conn->conn_1.cn_nsubs == 0) 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 else
efHierSrArray(hc, conn, efAddOneConn, INT2CD(doWarn)); efHierSrArray(hc, conn, efAddOneConn, INT2CD(flags));
} }
return (0); return (0);
@ -648,18 +659,23 @@ efAddOneConn(
char *name1, /* These are strings, not HierNames */ char *name1, /* These are strings, not HierNames */
char *name2, char *name2,
Connection *conn, Connection *conn,
bool doWarn) int flags)
{ {
HashEntry *he1, *he2; HashEntry *he1, *he2;
EFNode *node, *newnode; EFNode *node, *newnode;
int n; 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); he1 = EFHNLook(hc->hc_hierName, name1, (doWarn) ? "connect(1)" : NULL);
if (he1 == NULL) if (he1 == NULL)
return 0; return 0;
/* Adjust the resistance and capacitance of its corresponding node */
node = ((EFNodeName *) HashGetValue(he1))->efnn_node; node = ((EFNodeName *) HashGetValue(he1))->efnn_node;
/* Adjust the resistance and capacitance of its corresponding node */
node->efnode_cap += conn->conn_cap; node->efnode_cap += conn->conn_cap;
for (n = 0; n < efNumResistClasses; n++) 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 * variables cause nets named VDD and GND to become globals, which was
* not intended. * 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: * Results:
* TRUE if the name is a global. * TRUE if the name is a global.
* *
@ -99,12 +105,10 @@ EFHNIsGlob(hierName)
char *retstr; char *retstr;
retstr = (char *)Tcl_GetVar2(magicinterp, "globals", hierName->hn_name, retstr = (char *)Tcl_GetVar2(magicinterp, "globals", hierName->hn_name,
TCL_GLOBAL_ONLY); TCL_GLOBAL_ONLY);
if (retstr != NULL) return TRUE; return (retstr != NULL) ? TRUE : FALSE;
#else
// retstr = (char *)Tcl_GetVar(magicinterp, hierName->hn_name, TCL_GLOBAL_ONLY);
// if (retstr != NULL) return TRUE;
#endif
return hierName->hn_name[strlen(hierName->hn_name) - 1] == '!'; 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]; last1 = hierName1->hn_name[strlen(hierName1->hn_name) - 1];
last2 = hierName2->hn_name[strlen(hierName2->hn_name) - 1]; last2 = hierName2->hn_name[strlen(hierName2->hn_name) - 1];
if (last1 != '!' || last2 != '!') 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 */ /* Prefer global over local names */
if (last1 == '!') return TRUE; if (last1 == '!') return TRUE;
if (last2 == '!') return FALSE; 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 TRUE;
if (last1 == '#' && last2 != '#') return FALSE; 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 "commands/commands.h"
#include "database/database.h" #include "database/database.h"
#include "extflat/extflat.h" #include "extflat/extflat.h"
#include "extflat/extparse.h"
#include "extflat/EFint.h" #include "extflat/EFint.h"
#include "extract/extract.h" #include "extract/extract.h"
#include "extract/extractInt.h" #include "extract/extractInt.h"
@ -48,58 +49,11 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#ifndef MAGIC_WRAPPER #ifndef MAGIC_WRAPPER
/* This must match the definition for extDevTable in extract/ExtBasic.c */ /* This must match the definition for extDevTable in extract/ExtBasic.c */
const char * const extDevTable[] = {"fet", "mosfet", "asymmetric", "bjt", "devres", const char * const extDevTable[] = {"fet", "mosfet", "asymmetric", "bjt", "devres",
"devcap", "devcaprev", "vsource", "diode", "pdiode", "devcap", "devcaprev", "vsource", "diode", "pdiode",
"ndiode", "subckt", "rsubckt", "msubckt", "csubckt", "ndiode", "subckt", "rsubckt", "msubckt", "csubckt",
"dsubckt", "veriloga", NULL}; "dsubckt", "veriloga", NULL};
#endif #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 */ /* Data shared with EFerror.c */
char *efReadFileName; /* Name of file currently being read */ char *efReadFileName; /* Name of file currently being read */
int efReadLineNum; /* Current line number in above file */ 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 */ /* Data local to this file */
static bool efReadDef(Def *def, bool dosubckt, bool resist, bool noscale, bool toplevel, bool isspice); 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/EFtypes.h" /* EFCapValue, HierName, EFPerimArea, EFNode */
#include "extflat/EFint.h" /* Def, HierContext, Connection, Distance, CallArg */ #include "extflat/EFint.h" /* Def, HierContext, Connection, Distance, CallArg */
extern float EFScale; /* Scale factor to multiply all coords by */ extern float EFScale; /* Scale factor to multiply all coords by */
extern char *EFTech; /* Technology of extracted circuit */ extern char *EFTech; /* Technology of extracted circuit */
extern char *EFStyle; /* Extraction style 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

@ -713,14 +713,15 @@ extArrayNodeName(np, ha, et1, et2)
ExtTree *et1, *et2; ExtTree *et1, *et2;
{ {
Tile *tp; Tile *tp;
TileType dinfo;
tp = extNodeToTile(np, et1); tp = extNodeToTile(np, et1, &dinfo);
if (tp && TiGetType(tp) != TT_SPACE && extHasRegion(tp, extUnInit)) if (tp && TiGetType(tp) != TT_SPACE && extHasRegion(tp, CLIENTDEFAULT))
return (extArrayTileToNode(tp, np->nreg_pnum, et1, ha, TRUE)); return (extArrayTileToNode(tp, dinfo, np->nreg_pnum, et1, ha, TRUE));
tp = extNodeToTile(np, et2); tp = extNodeToTile(np, et2, &dinfo);
if (tp && TiGetType(tp) != TT_SPACE && extHasRegion(tp, extUnInit)) if (tp && TiGetType(tp) != TT_SPACE && extHasRegion(tp, CLIENTDEFAULT))
return (extArrayTileToNode(tp, np->nreg_pnum, et2, ha, TRUE)); return (extArrayTileToNode(tp, dinfo, np->nreg_pnum, et2, ha, TRUE));
return ("(none)"); return ("(none)");
} }
@ -768,8 +769,9 @@ extArrayNodeName(np, ha, et1, et2)
*/ */
char * char *
extArrayTileToNode(tp, pNum, et, ha, doHard) extArrayTileToNode(tp, dinfo, pNum, et, ha, doHard)
Tile *tp; Tile *tp;
TileType dinfo;
int pNum; int pNum;
ExtTree *et; ExtTree *et;
HierExtractArg *ha; HierExtractArg *ha;
@ -791,15 +793,15 @@ extArrayTileToNode(tp, pNum, et, ha, doHard)
LabRegion *reg; LabRegion *reg;
Rect r; Rect r;
if (extHasRegion(tp, extUnInit)) if (extHasRegion(tp, CLIENTDEFAULT))
{ {
reg = (LabRegion *) extGetRegion(tp); reg = (LabRegion *) ExtGetRegion(tp, dinfo);
if (reg->lreg_labels) if (reg->lreg_labels)
goto found; goto found;
} }
if (!DebugIsSet(extDebugID, extDebNoHard)) if (!DebugIsSet(extDebugID, extDebNoHard))
if ((reg = (LabRegion *) extArrayHardNode(tp, pNum, def, ha))) if ((reg = (LabRegion *) extArrayHardNode(tp, dinfo, pNum, def, ha)))
goto found; goto found;
/* Blew it */ /* Blew it */
@ -934,17 +936,23 @@ extArrayRange(dstp, lo, hi, prevRange, followRange)
*/ */
LabRegion * LabRegion *
extArrayHardNode(tp, pNum, def, ha) extArrayHardNode(tp, dinfo, pNum, def, ha)
Tile *tp; Tile *tp;
TileType dinfo;
int pNum; int pNum;
CellDef *def; CellDef *def;
HierExtractArg *ha; HierExtractArg *ha;
{ {
TileType type = TiGetType(tp); TileType type;
char labelBuf[4096]; char labelBuf[4096];
SearchContext scx; SearchContext scx;
HardWay arg; HardWay arg;
if (IsSplit(tp))
type = (dinfo & TT_SIDE) ? TiGetRightType(tp) : TiGetLeftType(tp);
else
type = TiGetType(tp);
arg.hw_ha = ha; arg.hw_ha = ha;
arg.hw_label = (Label *) NULL; arg.hw_label = (Label *) NULL;
arg.hw_mask = DBPlaneTypes[pNum]; arg.hw_mask = DBPlaneTypes[pNum];
@ -971,7 +979,7 @@ extArrayHardNode(tp, pNum, def, ha)
LabRegion *lreg; LabRegion *lreg;
LabelList *ll; LabelList *ll;
lreg = (LabRegion *) extGetRegion(tp); lreg = (LabRegion *) ExtGetRegion(tp, dinfo);
ll = (LabelList *) mallocMagic((unsigned) (sizeof (LabelList))); ll = (LabelList *) mallocMagic((unsigned) (sizeof (LabelList)));
lreg->lreg_labels = ll; lreg->lreg_labels = ll;
ll->ll_next = (LabelList *) NULL; ll->ll_next = (LabelList *) NULL;

File diff suppressed because it is too large Load Diff

View File

@ -46,20 +46,10 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/main.h" #include "utils/main.h"
#include "utils/undo.h" #include "utils/undo.h"
/* --------------------------- Global data ---------------------------- */
/*
* Value normally present in ti_client to indicate tiles that have not
* been marked with their associated region.
*/
ClientData extUnInit = (ClientData) CLIENTDEFAULT;
/* ------------------------ Data local to this file ------------------- */ /* ------------------------ Data local to this file ------------------- */
/* Forward declarations */ /* Forward declarations */
int extOutputUsesFunc(); int extOutputUsesFunc();
FILE *extFileOpen();
Plane* extCellFile(); Plane* extCellFile();
void extHeader(); void extHeader();
@ -105,7 +95,7 @@ ExtCell(def, outName, doLength)
if (def->cd_flags & CDNOEXTRACT) if (def->cd_flags & CDNOEXTRACT)
return extPrepSubstrate(def); 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); TxPrintf("Extracting %s into %s:\n", def->cd_name, filename);
@ -141,7 +131,7 @@ ExtCell(def, outName, doLength)
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
* extFileOpen -- * ExtFileOpen --
* *
* Open the .ext file corresponding to a .mag file. * 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 * If def->cd_file is non-NULL, the .ext file is just def->cd_file with
@ -159,7 +149,7 @@ ExtCell(def, outName, doLength)
*/ */
FILE * FILE *
extFileOpen(def, file, mode, prealfile) ExtFileOpen(def, file, mode, prealfile)
CellDef *def; /* Cell whose .ext file is to be written */ CellDef *def; /* Cell whose .ext file is to be written */
char *file; /* If non-NULL, open 'name'.ext; otherwise, char *file; /* If non-NULL, open 'name'.ext; otherwise,
* derive filename from 'def' as described * derive filename from 'def' as described
@ -495,8 +485,17 @@ extCellFile(def, f, doLength)
UndoDisable(); 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 */ /* 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 */ /* Remove any label markers that were made by a previous extraction */
for (lab = def->cd_labels; lab; lab = lab->lab_next) for (lab = def->cd_labels; lab; lab = lab->lab_next)
@ -517,7 +516,7 @@ extCellFile(def, f, doLength)
/* Clean up from basic extraction */ /* Clean up from basic extraction */
if (reg) ExtFreeLabRegions((LabRegion *) reg); if (reg) ExtFreeLabRegions((LabRegion *) reg);
ExtResetTiles(def, extUnInit); ExtResetTiles(def, CLIENTDEFAULT);
/* Final pass: extract length information if desired */ /* Final pass: extract length information if desired */
if (!SigInterruptPending && doLength && (ExtOptions & EXT_DOLENGTH)) if (!SigInterruptPending && doLength && (ExtOptions & EXT_DOLENGTH))
@ -595,7 +594,7 @@ extHeader(def, f)
/* are to be passed to instances of the cell */ /* are to be passed to instances of the cell */
/* (created by defining property "parameter") */ /* (created by defining property "parameter") */
propvalue = (char *)DBPropGet(def, "parameter", &propfound); propvalue = DBPropGetString(def, "parameter", &propfound);
if (propfound) if (propfound)
{ {
// Use device parameter table to store the cell def parameters, // Use device parameter table to store the cell def parameters,

View File

@ -67,6 +67,7 @@ typedef struct _ecs {
typedef struct _ecpls { typedef struct _ecpls {
Tile *tile; Tile *tile;
TileType dinfo;
int plane_of_tile; int plane_of_tile;
int plane_checked; int plane_checked;
} extCoupleStruct; } extCoupleStruct;
@ -311,8 +312,9 @@ extOutputCoupling(table, outFile)
*/ */
int int
extBasicOverlap(tile, ecs) extBasicOverlap(tile, dinfo, ecs)
Tile *tile; Tile *tile;
TileType dinfo;
extCapStruct *ecs; extCapStruct *ecs;
{ {
int thisType; int thisType;
@ -325,7 +327,7 @@ extBasicOverlap(tile, ecs)
extCoupleStruct ecpls; extCoupleStruct ecpls;
if (IsSplit(tile)) if (IsSplit(tile))
thisType = (SplitSide(tile)) ? SplitRightType(tile) : thisType = ((dinfo & TT_SIDE)) ? SplitRightType(tile) :
SplitLeftType(tile); SplitLeftType(tile);
else else
thisType = TiGetTypeExact(tile); thisType = TiGetTypeExact(tile);
@ -344,6 +346,7 @@ extBasicOverlap(tile, ecs)
} }
ecpls.tile = tile; ecpls.tile = tile;
ecpls.dinfo = dinfo;
ecpls.plane_of_tile = thisPlane; ecpls.plane_of_tile = thisPlane;
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
@ -410,8 +413,9 @@ struct sideoverlap
}; };
int int
extAddOverlap(tbelow, ecpls) extAddOverlap(tbelow, dinfo, ecpls)
Tile *tbelow; Tile *tbelow;
TileType dinfo; /* unused, but needs to be handled */
extCoupleStruct *ecpls; extCoupleStruct *ecpls;
{ {
int extSubtractOverlap(), extSubtractOverlap2(); int extSubtractOverlap(), extSubtractOverlap2();
@ -430,8 +434,8 @@ extAddOverlap(tbelow, ecpls)
/* subtract off any substrate (area) capacitance previously added */ /* subtract off any substrate (area) capacitance previously added */
/* (Correction made 4/29/04 by Tim from a tip by Jeff Sondeen). */ /* (Correction made 4/29/04 by Tim from a tip by Jeff Sondeen). */
rabove = (NodeRegion *) extGetRegion(tabove); rabove = (NodeRegion *) ExtGetRegion(tabove, ecpls->dinfo);
rbelow = (NodeRegion *) extGetRegion(tbelow); rbelow = (NodeRegion *) ExtGetRegion(tbelow, dinfo);
/* Quick check on validity of tile's ti_client record */ /* Quick check on validity of tile's ti_client record */
if (rbelow == (NodeRegion *)CLIENTDEFAULT) return 0; if (rbelow == (NodeRegion *)CLIENTDEFAULT) return 0;
@ -448,8 +452,16 @@ extAddOverlap(tbelow, ecpls)
} }
ov.o_area = (ov.o_clip.r_ytop - ov.o_clip.r_ybot) ov.o_area = (ov.o_clip.r_ytop - ov.o_clip.r_ybot)
* (ov.o_clip.r_xtop - ov.o_clip.r_xbot); * (ov.o_clip.r_xtop - ov.o_clip.r_xbot);
ta = TiGetType(tabove);
tb = TiGetType(tbelow); if (IsSplit(tabove))
ta = (ecpls->dinfo & TT_SIDE) ? TiGetRightType(tabove) : TiGetLeftType(tabove);
else
ta = TiGetTypeExact(tabove);
if (IsSplit(tbelow))
tb = (dinfo & TT_SIDE) ? TiGetRightType(tbelow) : TiGetLeftType(tbelow);
else
tb = TiGetTypeExact(tbelow);
/* Revert any contacts to their residues */ /* Revert any contacts to their residues */
@ -539,8 +551,9 @@ extAddOverlap(tbelow, ecpls)
/* Simple overlap. The area of overlap is subtracted from ov->o_area */ /* Simple overlap. The area of overlap is subtracted from ov->o_area */
int int
extSubtractOverlap(tile, ov) extSubtractOverlap(tile, dinfo, ov)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
struct overlap *ov; struct overlap *ov;
{ {
Rect r; Rect r;
@ -549,6 +562,7 @@ extSubtractOverlap(tile, ov)
TITORECT(tile, &r); TITORECT(tile, &r);
GEOCLIP(&r, &ov->o_clip); GEOCLIP(&r, &ov->o_clip);
area = (r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot); area = (r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot);
if (IsSplit(tile)) area /= 2;
if (area > 0) if (area > 0)
ov->o_area -= area; ov->o_area -= area;
@ -561,10 +575,12 @@ extSubtractOverlap(tile, ov)
/* shielding plane. */ /* shielding plane. */
int int
extSubtractOverlap2(tile, ov) extSubtractOverlap2(tile, dinfo, ov)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
struct overlap *ov; struct overlap *ov;
{ {
TileType ttype;
struct overlap ovnew; struct overlap ovnew;
int area, pNum; int area, pNum;
Rect r; Rect r;
@ -574,9 +590,16 @@ extSubtractOverlap2(tile, ov)
area = (r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot); area = (r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot);
if (area <= 0) if (area <= 0)
return (0); return (0);
if (IsSplit(tile))
{
area /= 2;
ttype = (dinfo & TT_SIDE) ? TiGetRightType(tile) : TiGetLeftType(tile);
}
else
ttype = TiGetTypeExact(tile);
/* This tile shields everything below */ /* This tile shields everything below */
if (TTMaskHasType(&ov->o_tmask, TiGetType(tile))) if (TTMaskHasType(&ov->o_tmask, ttype))
{ {
ov->o_area -= area; ov->o_area -= area;
return (0); return (0);
@ -614,8 +637,9 @@ extSubtractOverlap2(tile, ov)
*/ */
int int
extSubtractSideOverlap(tile, sov) extSubtractSideOverlap(tile, dinfo, sov)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
struct sideoverlap *sov; struct sideoverlap *sov;
{ {
Rect r; Rect r;
@ -691,24 +715,31 @@ extSubtractSideOverlap(tile, sov)
/* shielding plane. */ /* shielding plane. */
int int
extSubtractSideOverlap2(tile, sov) extSubtractSideOverlap2(tile, dinfo, sov)
Tile *tile; Tile *tile;
TileType dinfo;
struct sideoverlap *sov; struct sideoverlap *sov;
{ {
TileType ttype;
struct sideoverlap sovnew; struct sideoverlap sovnew;
int area, pNum; int area, pNum;
Rect r; Rect r;
if (IsSplit(tile))
ttype = (dinfo & TT_SIDE) ? TiGetRightType(tile) : TiGetLeftType(tile);
else
ttype = TiGetTypeExact(tile);
TITORECT(tile, &r); TITORECT(tile, &r);
GEOCLIP(&r, &sov->so_clip); GEOCLIP(&r, &sov->so_clip);
area = (r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot); area = (r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot);
if (area <= 0) if (area <= 0) return (0);
return (0); if (IsSplit(tile)) area /= 2;
/* This tile shields everything below */ /* This tile shields everything below */
if (TTMaskHasType(&sov->so_tmask, TiGetType(tile))) if (TTMaskHasType(&sov->so_tmask, ttype))
{ {
extSubtractSideOverlap(tile, sov); extSubtractSideOverlap(tile, dinfo, sov);
return (0); return (0);
} }
@ -764,15 +795,250 @@ extSubtractSideOverlap2(tile, sov)
*/ */
int int
extBasicCouple(tile, ecs) extBasicCouple(tile, dinfo, ecs)
Tile *tile; Tile *tile;
TileType dinfo;
extCapStruct *ecs; extCapStruct *ecs;
{ {
(void) extEnumTilePerim(tile, &ExtCurStyle->exts_sideEdges[TiGetType(tile)], TileType ttype;
if (IsSplit(tile))
ttype = (dinfo & TT_SIDE) ? TiGetRightType(tile) : TiGetLeftType(tile);
else
ttype = TiGetTypeExact(tile);
(void) extEnumTilePerim(tile, dinfo, &ExtCurStyle->exts_sideEdges[ttype],
ecs->plane, extAddCouple, (ClientData) ecs); ecs->plane, extAddCouple, (ClientData) ecs);
return (0); return (0);
} }
/*
* ----------------------------------------------------------------------------
*
* extGetBoundaryTypes ---
*
* Return the tile types of the boundary inside and outside type in the
* argument pointers. The routine takes care of deciding if either side
* of the boundary is a split tile, and choosing the correct type based
* on the direction of the boundary.
*
* Result:
* None.
*
* Side effects:
* The tile types are passed by pointer reference in the arguments.
*
* ----------------------------------------------------------------------------
*/
void
extGetBoundaryTypes(Boundary *bp,
TileType *tin,
TileType *tout)
{
TileType loctin, loctout;
if (IsSplit(bp->b_inside))
{
switch (bp->b_direction)
{
case BD_LEFT:
loctin = TiGetLeftType(bp->b_inside);
break;
case BD_RIGHT:
loctin = TiGetRightType(bp->b_inside);
break;
case BD_TOP:
loctin = TiGetTopType(bp->b_inside);
break;
case BD_BOTTOM:
loctin = TiGetBottomType(bp->b_inside);
break;
}
}
else
loctin = TiGetTypeExact(bp->b_inside);
if (IsSplit(bp->b_outside))
{
switch (bp->b_direction)
{
case BD_LEFT:
loctout = TiGetRightType(bp->b_outside);
break;
case BD_RIGHT:
loctout = TiGetLeftType(bp->b_outside);
break;
case BD_TOP:
loctout = TiGetBottomType(bp->b_outside);
break;
case BD_BOTTOM:
loctout = TiGetTopType(bp->b_outside);
break;
}
}
else
loctout = TiGetTypeExact(bp->b_outside);
*tin = loctin;
*tout = loctout;
}
/*
* ----------------------------------------------------------------------------
*
* extGetBoundaryTypes2 ---
*
* Similar to extGetBoundaryTypes(), but where the tiles for which we
* want to get the tile type are not necessarily the ones in the boundary
* record; the boundary just provides the direction that determines which
* side the tile type is on, in the case of a split tile.
*
* Result:
* None.
*
* Side effects:
* The tile types are passed by pointer reference in the arguments.
*
* ----------------------------------------------------------------------------
*/
void
extGetBoundaryTypes2(int bdir,
Tile *tbin,
Tile *tbout,
TileType *tin,
TileType *tout)
{
TileType loctin, loctout;
if (IsSplit(tbin))
{
switch (bdir)
{
case BD_LEFT:
loctin = TiGetLeftType(tbin);
break;
case BD_RIGHT:
loctin = TiGetRightType(tbin);
break;
case BD_TOP:
loctin = TiGetTopType(tbin);
break;
case BD_BOTTOM:
loctin = TiGetBottomType(tbin);
break;
}
}
else
loctin = TiGetTypeExact(tbin);
if (IsSplit(tbout))
{
switch (bdir)
{
case BD_LEFT:
loctout = TiGetRightType(tbout);
break;
case BD_RIGHT:
loctout = TiGetLeftType(tbout);
break;
case BD_TOP:
loctout = TiGetBottomType(tbout);
break;
case BD_BOTTOM:
loctout = TiGetTopType(tbout);
break;
}
}
else
loctout = TiGetTypeExact(tbout);
*tin = loctin;
*tout = loctout;
}
/*
* ----------------------------------------------------------------------------
*
* extGetBoundaryRegions ---
*
* Given a boundary direction and two tiles, one on the boundary inside
* and one on the boundary outside, find the two node regions associated
* with the facing sides of the two tiles.
*
* Results:
* None.
*
* Side effects:
* The tile types are passed by pointer reference in the arguments.
*
* ----------------------------------------------------------------------------
*/
void
extGetBoundaryRegions(int bdir,
Tile *tbin,
Tile *tbout,
NodeRegion **rinptr,
NodeRegion **routptr)
{
NodeRegion *locrin, *locrout;
if (IsSplit(tbin))
{
switch (bdir)
{
case BD_LEFT:
locrin = (NodeRegion *)ExtGetRegion(tbin, (TileType)0);
break;
case BD_RIGHT:
locrin = (NodeRegion *)ExtGetRegion(tbin, (TileType)TT_SIDE);
break;
case BD_TOP:
locrin = (NodeRegion *)ExtGetRegion(tbin,
TiGetTypeExact(tbin) & TT_DIRECTION ?
(TileType)TT_SIDE : (TileType)0);
break;
case BD_BOTTOM:
locrin = (NodeRegion *)ExtGetRegion(tbin,
TiGetTypeExact(tbin) & TT_DIRECTION ?
(TileType)0 : (TileType)TT_SIDE);
break;
}
}
else
locrin = (NodeRegion *)ExtGetRegion(tbin, (TileType)0);
if (IsSplit(tbout))
{
switch (bdir)
{
case BD_LEFT:
locrout = (NodeRegion *)ExtGetRegion(tbout, (TileType)TT_SIDE);
break;
case BD_RIGHT:
locrout = (NodeRegion *)ExtGetRegion(tbout, (TileType)0);
break;
case BD_TOP:
locrout = (NodeRegion *)ExtGetRegion(tbout,
TiGetTypeExact(tbin) & TT_DIRECTION ?
(TileType)0 : (TileType)TT_SIDE);
break;
case BD_BOTTOM:
locrout = (NodeRegion *)ExtGetRegion(tbout,
TiGetTypeExact(tbin) & TT_DIRECTION ?
(TileType)TT_SIDE : (TileType)0);
break;
}
}
else
locrout = (NodeRegion *)ExtGetRegion(tbout, (TileType)0);
*rinptr = locrin;
*routptr = locrout;
}
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -808,7 +1074,7 @@ extAddCouple(bp, ecs)
Boundary *bp; /* Boundary being considered */ Boundary *bp; /* Boundary being considered */
extCapStruct *ecs; extCapStruct *ecs;
{ {
TileType tin = TiGetType(bp->b_inside), tout = TiGetType(bp->b_outside); TileType tin, tout;
int pNum; int pNum;
PlaneMask pMask; PlaneMask pMask;
Boundary bpCopy; Boundary bpCopy;
@ -816,6 +1082,21 @@ extAddCouple(bp, ecs)
extSidewallStruct esws; extSidewallStruct esws;
int distFringe; int distFringe;
/* Non-Manhattan boundaries are not handled. This is
* future work to be done.
*/
switch (bp->b_direction)
{
case BD_NW:
case BD_NE:
case BD_SW:
case BD_SE:
return 0;
}
/* Get the types on the inside and outside of the boundary */
extGetBoundaryTypes(bp, &tin, &tout);
/* Check here for a zero exts_sideCoupleOtherEdges mask. /* Check here for a zero exts_sideCoupleOtherEdges mask.
* that handles cases such as FET types not being declared in * that handles cases such as FET types not being declared in
* defaultperimeter, as the edge between poly and FET will be * defaultperimeter, as the edge between poly and FET will be
@ -905,7 +1186,7 @@ extAddCouple(bp, ecs)
extSideBottom, bp, &esws); extSideBottom, bp, &esws);
break; break;
} }
return (0); return 0;
} }
/* /*
@ -936,9 +1217,10 @@ extRemoveSubcap(bp, clip, esws)
if (!esws->fringe_halo) return; if (!esws->fringe_halo) return;
ta = TiGetType(bp->b_inside); /* Get the types on the inside and outside of the boundary */
tb = TiGetType(bp->b_outside); extGetBoundaryTypes(bp, &ta, &tb);
rbp = (NodeRegion *)extGetRegion(bp->b_inside);
rbp = (NodeRegion *)ExtGetRegion(bp->b_inside, (TileType)0);
if (bp->b_segment.r_xtop == bp->b_segment.r_xbot) if (bp->b_segment.r_xtop == bp->b_segment.r_xbot)
length = bp->b_segment.r_ytop - bp->b_segment.r_ybot; length = bp->b_segment.r_ytop - bp->b_segment.r_ybot;
@ -1007,6 +1289,14 @@ extFindOverlap(tp, area, esws)
TileType tin = TiGetType(bp->b_inside); TileType tin = TiGetType(bp->b_inside);
TileType tout = TiGetType(bp->b_outside); 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]; pMask = ExtCurStyle->exts_sideOverlapOtherPlanes[tin][tout];
extOverlapDef = esws->def; extOverlapDef = esws->def;
@ -1055,13 +1345,14 @@ extFindOverlap(tp, area, esws)
*/ */
int int
extSideOverlapHalo(tp, esws) extSideOverlapHalo(tp, dinfo, esws)
Tile *tp; /* Overlapped tile */ Tile *tp; /* Overlapped tile */
TileType dinfo; /* Split tile information */
extSidewallStruct *esws; /* Overlapping edge and plane information */ extSidewallStruct *esws; /* Overlapping edge and plane information */
{ {
Boundary *bp = esws->bp; /* Overlapping edge */ Boundary *bp = esws->bp; /* Overlapping edge */
NodeRegion *rtp = (NodeRegion *) extGetRegion(tp); NodeRegion *rtp = (NodeRegion *) ExtGetRegion(tp, dinfo);
NodeRegion *rbp = (NodeRegion *) extGetRegion(bp->b_inside); NodeRegion *rbp = (NodeRegion *) ExtGetRegion(bp->b_inside, (TileType)0);
TileType ta, tb; TileType ta, tb;
Rect tpr; Rect tpr;
struct sideoverlap sov; struct sideoverlap sov;
@ -1076,7 +1367,10 @@ extSideOverlapHalo(tp, esws)
/* Nothing to do for space tiles, so just return. */ /* Nothing to do for space tiles, so just return. */
/* (TO DO: Make sure TT_SPACE is removed from all exts_sideOverlapOtherTypes */ /* (TO DO: Make sure TT_SPACE is removed from all exts_sideOverlapOtherTypes */
tb = TiGetType(tp); if (IsSplit(tp))
tb = (dinfo & TT_SIDE) ? TiGetRightType(tp) : TiGetLeftType(tp);
else
tb = TiGetTypeExact(tp);
if (tb == TT_SPACE) return (0); if (tb == TT_SPACE) return (0);
/* Get the area of the coupling tile, and clip to the fringe area */ /* Get the area of the coupling tile, and clip to the fringe area */
@ -1152,7 +1446,7 @@ extSideOverlapHalo(tp, esws)
if (!PlaneMaskHasPlane(e->ec_pmask, esws->plane_checked)) continue; if (!PlaneMaskHasPlane(e->ec_pmask, esws->plane_checked)) continue;
/* Does this rule "e" include the tile we found? */ /* Does this rule "e" include the tile we found? */
if (TTMaskHasType(&e->ec_near, TiGetType(tp))) if (TTMaskHasType(&e->ec_near, tb))
{ {
/* We have a possible capacitor, but are the tiles shielded from /* We have a possible capacitor, but are the tiles shielded from
* each other part of the way? * each other part of the way?
@ -1282,13 +1576,14 @@ extSideOverlapHalo(tp, esws)
*/ */
int int
extSideOverlap(tp, esws) extSideOverlap(tp, dinfo, esws)
Tile *tp; /* Overlapped tile */ Tile *tp; /* Overlapped tile */
TileType dinfo; /* Split tile information */
extSidewallStruct *esws; /* Overlapping edge and plane information */ extSidewallStruct *esws; /* Overlapping edge and plane information */
{ {
Boundary *bp = esws->bp; /* Overlapping edge */ Boundary *bp = esws->bp; /* Overlapping edge */
NodeRegion *rtp = (NodeRegion *) extGetRegion(tp); NodeRegion *rtp = (NodeRegion *) ExtGetRegion(tp, dinfo);
NodeRegion *rbp = (NodeRegion *) extGetRegion(bp->b_inside); NodeRegion *rbp = (NodeRegion *) ExtGetRegion(bp->b_inside, (TileType)0);
TileType ta, tb; TileType ta, tb;
Rect tpr; Rect tpr;
struct overlap ov; struct overlap ov;
@ -1301,7 +1596,10 @@ extSideOverlap(tp, esws)
/* Nothing to do for space tiles, so just return. */ /* Nothing to do for space tiles, so just return. */
/* (TO DO: Make sure TT_SPACE is removed from all exts_sideOverlapOtherTypes */ /* (TO DO: Make sure TT_SPACE is removed from all exts_sideOverlapOtherTypes */
tb = TiGetType(tp); if (IsSplit(tp))
tb = (dinfo & TT_SIDE) ? TiGetRightType(tp) : TiGetLeftType(tp);
else
tb = TiGetTypeExact(tp);
if (tb == TT_SPACE) return (0); if (tb == TT_SPACE) return (0);
if (bp->b_segment.r_xtop == bp->b_segment.r_xbot) if (bp->b_segment.r_xtop == bp->b_segment.r_xbot)
@ -1336,7 +1634,7 @@ extSideOverlap(tp, esws)
if (!PlaneMaskHasPlane(e->ec_pmask, esws->plane_checked)) continue; if (!PlaneMaskHasPlane(e->ec_pmask, esws->plane_checked)) continue;
/* Does this rule "e" include the tile we found? */ /* Does this rule "e" include the tile we found? */
if (TTMaskHasType(&e->ec_near, TiGetType(tp))) if (TTMaskHasType(&e->ec_near, tb))
{ {
/* We have a possible capacitor, but are the tiles shielded from /* We have a possible capacitor, but are the tiles shielded from
* each other part of the way? * each other part of the way?
@ -1478,11 +1776,7 @@ extWalkTop(area, mask, func, bp, esws)
tp = tile; tp = tile;
while (RIGHT(tp) > area->r_xbot) while (RIGHT(tp) > area->r_xbot)
{ {
if (IsSplit(tp)) ttype = TiGetBottomType(tp);
ttype = (SplitSide(tp)) ? SplitRightType(tp) : SplitLeftType(tp);
else
ttype = TiGetTypeExact(tp);
if (TTMaskHasType(mask, ttype)) if (TTMaskHasType(mask, ttype))
{ {
bool lookLeft, lookRight; bool lookLeft, lookRight;
@ -1590,11 +1884,7 @@ extWalkBottom(area, mask, func, bp, esws)
tp = tile; tp = tile;
while (LEFT(tp) < area->r_xtop) while (LEFT(tp) < area->r_xtop)
{ {
if (IsSplit(tp)) ttype = TiGetTopType(tp);
ttype = (SplitSide(tp)) ? SplitRightType(tp) : SplitLeftType(tp);
else
ttype = TiGetTypeExact(tp);
if (TTMaskHasType(mask, ttype)) if (TTMaskHasType(mask, ttype))
{ {
bool lookLeft, lookRight; bool lookLeft, lookRight;
@ -1702,11 +1992,7 @@ extWalkRight(area, mask, func, bp, esws)
tp = tile; tp = tile;
while (TOP(tp) > area->r_ybot) while (TOP(tp) > area->r_ybot)
{ {
if (IsSplit(tp)) ttype = TiGetLeftType(tp);
ttype = (SplitSide(tp)) ? SplitRightType(tp) : SplitLeftType(tp);
else
ttype = TiGetTypeExact(tp);
if (TTMaskHasType(mask, ttype)) if (TTMaskHasType(mask, ttype))
{ {
bool lookDown, lookUp; bool lookDown, lookUp;
@ -1814,11 +2100,7 @@ extWalkLeft(area, mask, func, bp, esws)
tp = tile; tp = tile;
while (BOTTOM(tp) < area->r_ytop) while (BOTTOM(tp) < area->r_ytop)
{ {
if (IsSplit(tp)) ttype = TiGetRightType(tp);
ttype = (SplitSide(tp)) ? SplitRightType(tp) : SplitLeftType(tp);
else
ttype = TiGetTypeExact(tp);
if (TTMaskHasType(mask, ttype)) if (TTMaskHasType(mask, ttype))
{ {
bool lookDown, lookUp; bool lookDown, lookUp;
@ -1917,11 +2199,13 @@ extSideLeft(tpfar, bp, esws)
Boundary *bp; Boundary *bp;
extSidewallStruct *esws; extSidewallStruct *esws;
{ {
NodeRegion *rinside = (NodeRegion *) extGetRegion(bp->b_inside); NodeRegion *rinside, *rfar;
NodeRegion *rfar = (NodeRegion *) extGetRegion(tpfar);
Tile *tpnear; Tile *tpnear;
if (rfar != (NodeRegion *) extUnInit && rfar != rinside) /* Get the regions associated with bp->b_inside and tpfar */
extGetBoundaryRegions(bp->b_direction, bp->b_inside, tpfar, &rinside, &rfar);
if (rfar != (NodeRegion *)CLIENTDEFAULT && rfar != rinside)
{ {
int sep = bp->b_segment.r_xbot - RIGHT(tpfar); int sep = bp->b_segment.r_xbot - RIGHT(tpfar);
int limit = MAX(bp->b_segment.r_ybot, BOTTOM(tpfar)); int limit = MAX(bp->b_segment.r_ybot, BOTTOM(tpfar));
@ -1931,8 +2215,8 @@ extSideLeft(tpfar, bp, esws)
{ {
int overlap = MIN(TOP(tpnear), start) - MAX(BOTTOM(tpnear), limit); int overlap = MIN(TOP(tpnear), start) - MAX(BOTTOM(tpnear), limit);
if (overlap > 0) if (overlap > 0)
extSideCommon(rinside, rfar, tpnear, tpfar, overlap, sep, extSideCommon(rinside, rfar, tpnear, tpfar, bp->b_direction,
esws->extCoupleList); overlap, sep, esws->extCoupleList);
} }
} }
@ -1967,11 +2251,13 @@ extSideRight(tpfar, bp, esws)
Boundary *bp; Boundary *bp;
extSidewallStruct *esws; extSidewallStruct *esws;
{ {
NodeRegion *rinside = (NodeRegion *) extGetRegion(bp->b_inside); NodeRegion *rinside, *rfar;
NodeRegion *rfar = (NodeRegion *) extGetRegion(tpfar);
Tile *tpnear; Tile *tpnear;
if (rfar != (NodeRegion *) extUnInit && rfar != rinside) /* Get the regions associated with bp->b_inside and tpfar */
extGetBoundaryRegions(bp->b_direction, bp->b_inside, tpfar, &rinside, &rfar);
if (rfar != (NodeRegion *) CLIENTDEFAULT && rfar != rinside)
{ {
int sep = LEFT(tpfar) - bp->b_segment.r_xtop; int sep = LEFT(tpfar) - bp->b_segment.r_xtop;
int limit = MIN(bp->b_segment.r_ytop, TOP(tpfar)); int limit = MIN(bp->b_segment.r_ytop, TOP(tpfar));
@ -1981,8 +2267,8 @@ extSideRight(tpfar, bp, esws)
{ {
int overlap = MIN(TOP(tpnear), limit) - MAX(BOTTOM(tpnear), start); int overlap = MIN(TOP(tpnear), limit) - MAX(BOTTOM(tpnear), start);
if (overlap > 0) if (overlap > 0)
extSideCommon(rinside, rfar, tpnear, tpfar, overlap, sep, extSideCommon(rinside, rfar, tpnear, tpfar, bp->b_direction,
esws->extCoupleList); overlap, sep, esws->extCoupleList);
} }
} }
@ -2017,11 +2303,13 @@ extSideTop(tpfar, bp, esws)
Boundary *bp; Boundary *bp;
extSidewallStruct *esws; extSidewallStruct *esws;
{ {
NodeRegion *rinside = (NodeRegion *) extGetRegion(bp->b_inside); NodeRegion *rinside, *rfar;
NodeRegion *rfar = (NodeRegion *) extGetRegion(tpfar);
Tile *tpnear; Tile *tpnear;
if (rfar != (NodeRegion *) extUnInit && rfar != rinside) /* Get the regions associated with bp->b_inside and tpfar */
extGetBoundaryRegions(bp->b_direction, bp->b_inside, tpfar, &rinside, &rfar);
if (rfar != (NodeRegion *) CLIENTDEFAULT && rfar != rinside)
{ {
int sep = BOTTOM(tpfar) - bp->b_segment.r_ytop; int sep = BOTTOM(tpfar) - bp->b_segment.r_ytop;
int limit = MIN(bp->b_segment.r_xtop, RIGHT(tpfar)); int limit = MIN(bp->b_segment.r_xtop, RIGHT(tpfar));
@ -2031,8 +2319,8 @@ extSideTop(tpfar, bp, esws)
{ {
int overlap = MIN(RIGHT(tpnear), limit) - MAX(LEFT(tpnear), start); int overlap = MIN(RIGHT(tpnear), limit) - MAX(LEFT(tpnear), start);
if (overlap > 0) if (overlap > 0)
extSideCommon(rinside, rfar, tpnear, tpfar, overlap, sep, extSideCommon(rinside, rfar, tpnear, tpfar, bp->b_direction,
esws->extCoupleList); overlap, sep, esws->extCoupleList);
} }
} }
@ -2067,11 +2355,13 @@ extSideBottom(tpfar, bp, esws)
Boundary *bp; Boundary *bp;
extSidewallStruct *esws; extSidewallStruct *esws;
{ {
NodeRegion *rinside = (NodeRegion *) extGetRegion(bp->b_inside); NodeRegion *rinside, *rfar;
NodeRegion *rfar = (NodeRegion *) extGetRegion(tpfar);
Tile *tpnear; Tile *tpnear;
if (rfar != (NodeRegion *) extUnInit && rfar != rinside) /* Get the regions associated with bp->b_inside and tpfar */
extGetBoundaryRegions(bp->b_direction, bp->b_inside, tpfar, &rinside, &rfar);
if (rfar != (NodeRegion *) CLIENTDEFAULT && rfar != rinside)
{ {
int sep = bp->b_segment.r_ybot - TOP(tpfar); int sep = bp->b_segment.r_ybot - TOP(tpfar);
int limit = MAX(bp->b_segment.r_xbot, LEFT(tpfar)); int limit = MAX(bp->b_segment.r_xbot, LEFT(tpfar));
@ -2081,8 +2371,8 @@ extSideBottom(tpfar, bp, esws)
{ {
int overlap = MIN(RIGHT(tpnear), start) - MAX(LEFT(tpnear), limit); int overlap = MIN(RIGHT(tpnear), start) - MAX(LEFT(tpnear), limit);
if (overlap > 0) if (overlap > 0)
extSideCommon(rinside, rfar, tpnear, tpfar, overlap, sep, extSideCommon(rinside, rfar, tpnear, tpfar, bp->b_direction,
esws->extCoupleList); overlap, sep, esws->extCoupleList);
} }
} }
@ -2096,7 +2386,7 @@ extSideBottom(tpfar, bp, esws)
* *
* Perform the actual update to the hash table entry for * Perform the actual update to the hash table entry for
* the regions 'rinside' and 'rfar'. We assume that neither * the regions 'rinside' and 'rfar'. We assume that neither
* 'rinside' nor 'rfar' are extUnInit, and further that they * 'rinside' nor 'rfar' are CLIENTDEFAULT, and further that they
* are not equal. * are not equal.
* *
* Walk along the rules in extCoupleList, applying the appropriate * Walk along the rules in extCoupleList, applying the appropriate
@ -2113,20 +2403,24 @@ extSideBottom(tpfar, bp, esws)
*/ */
void void
extSideCommon(rinside, rfar, tpnear, tpfar, overlap, sep, extCoupleList) extSideCommon(rinside, rfar, tpnear, tpfar, bdir, overlap, sep, extCoupleList)
NodeRegion *rinside, *rfar; /* Both must be valid */ NodeRegion *rinside, *rfar; /* Both must be valid */
Tile *tpnear, *tpfar; /* Tiles on near and far side of edge */ Tile *tpnear, *tpfar; /* Tiles on near and far side of edge */
int bdir; /* Boundary direction */
int overlap, sep; /* Overlap of this edge with original one, int overlap, sep; /* Overlap of this edge with original one,
* and distance between the two. * and distance between the two.
*/ */
EdgeCap *extCoupleList; /* List of sidewall capacitance rules */ EdgeCap *extCoupleList; /* List of sidewall capacitance rules */
{ {
TileType near = TiGetType(tpnear), far = TiGetType(tpfar); TileType near, far;
HashEntry *he; HashEntry *he;
EdgeCap *e; EdgeCap *e;
CoupleKey ck; CoupleKey ck;
CapValue cap; CapValue cap;
/* Get the tile types of tpnear and tpfar */
extGetBoundaryTypes2(bdir, tpnear, tpfar, &near, &far);
if (rinside < rfar) ck.ck_1 = rinside, ck.ck_2 = rfar; if (rinside < rfar) ck.ck_1 = rinside, ck.ck_2 = rfar;
else ck.ck_1 = rfar, ck.ck_2 = rinside; else ck.ck_1 = rfar, ck.ck_2 = rinside;
he = HashFind(extCoupleHashPtr, (char *) &ck); he = HashFind(extCoupleHashPtr, (char *) &ck);

View File

@ -71,8 +71,9 @@ bool extHardSetLabel();
*/ */
ExtRegion * ExtRegion *
extLabFirst(tile, arg) extLabFirst(tile, dinfo, arg)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
FindRegion *arg; FindRegion *arg;
{ {
TransRegion *reg; TransRegion *reg;
@ -82,6 +83,11 @@ extLabFirst(tile, arg)
reg->treg_pnum = DBNumPlanes; reg->treg_pnum = DBNumPlanes;
reg->treg_area = DBNumPlanes; reg->treg_area = DBNumPlanes;
reg->treg_tile = tile; reg->treg_tile = tile;
reg->treg_dinfo = dinfo;
/* Setting treg_pnum to DBNumPlanes ensures that treg_ll and treg_type
* will be set for identifying the node when extSetNodeNum() is called.
*/
/* Prepend it to the region list */ /* Prepend it to the region list */
reg->treg_next = (TransRegion *) arg->fra_region; reg->treg_next = (TransRegion *) arg->fra_region;
@ -91,25 +97,16 @@ extLabFirst(tile, arg)
/*ARGSUSED*/ /*ARGSUSED*/
int int
extLabEach(tile, pNum, arg) extLabEach(tile, dinfo, pNum, arg)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
int pNum; int pNum;
FindRegion *arg; FindRegion *arg;
{ {
/* Avoid setting the region's tile pointer to a split tile if we can */
/*
if (IsSplit(reg->treg_tile) && !IsSplit(tile))
{
reg->treg_tile = tile;
reg->treg_area = pNum;
}
*/
TransRegion *reg = (TransRegion *) arg->fra_region; TransRegion *reg = (TransRegion *) arg->fra_region;
if (reg->treg_area == DBNumPlanes) reg->treg_area = pNum; if (reg->treg_area == DBNumPlanes) reg->treg_area = pNum;
extSetNodeNum((LabRegion *)reg, pNum, tile); extSetNodeNum((LabRegion *)reg, pNum, tile, dinfo);
return (0); return (0);
} }
@ -172,7 +169,7 @@ extHardProc(scx, arg)
CellDef *def = scx->scx_use->cu_def; CellDef *def = scx->scx_use->cu_def;
TransRegion *reg; TransRegion *reg;
TransRegion *labRegList; TransRegion *labRegList;
LabelList *subList; LabelList *subList = NULL;
char *savenext; char *savenext;
int ret = 0; int ret = 0;
@ -203,7 +200,7 @@ extHardProc(scx, arg)
* single child. * single child.
*/ */
labRegList = (TransRegion *) ExtFindRegions(def, &scx->scx_area, labRegList = (TransRegion *) ExtFindRegions(def, &scx->scx_area,
&arg->hw_mask, ExtCurStyle->exts_nodeConn, extUnInit, &arg->hw_mask, ExtCurStyle->exts_nodeConn,
extLabFirst, extLabEach); extLabFirst, extLabEach);
if (labRegList) if (labRegList)
{ {
@ -240,7 +237,8 @@ extHardProc(scx, arg)
*/ */
if (ExtCurStyle->exts_globSubstrateDefaultType != -1) if (ExtCurStyle->exts_globSubstrateDefaultType != -1)
for (reg = labRegList; reg; reg = reg->treg_next) for (reg = labRegList; reg; reg = reg->treg_next)
if (TTMaskHasType(&ExtCurStyle->exts_globSubstrateTypes, reg->treg_type)) if (TTMaskHasType(&ExtCurStyle->exts_globSubstrateTypes,
reg->treg_type & TT_LEFTMASK))
if (reg->treg_pnum != ExtCurStyle->exts_globSubstratePlane) if (reg->treg_pnum != ExtCurStyle->exts_globSubstratePlane)
{ {
reg->treg_labels = subList; reg->treg_labels = subList;
@ -261,6 +259,7 @@ extHardProc(scx, arg)
goto done; goto done;
success: success:
if (subList != NULL) freeMagic(subList);
extHardFreeAll(def, labRegList); extHardFreeAll(def, labRegList);
ret = 1; ret = 1;
@ -338,7 +337,7 @@ extHardSetLabel(scx, reg, arg)
tp = PlaneGetHint(scx->scx_use->cu_def->cd_planes[pNum]); tp = PlaneGetHint(scx->scx_use->cu_def->cd_planes[pNum]);
GOTOPOINT(tp, &r.r_ll); GOTOPOINT(tp, &r.r_ll);
PlaneSetHint(scx->scx_use->cu_def->cd_planes[pNum], tp); PlaneSetHint(scx->scx_use->cu_def->cd_planes[pNum], tp);
if ((TransRegion *)extGetRegion(tp) == reg) if ((TransRegion *)ExtGetRegion(tp, (TileType)0) == reg)
{ {
/* found an OK point */ /* found an OK point */
r.r_ur.p_x =r.r_ll.p_x+1; r.r_ur.p_x =r.r_ll.p_x+1;
@ -347,7 +346,7 @@ extHardSetLabel(scx, reg, arg)
else else
{ {
GOTOPOINT(tp, &r.r_ur); GOTOPOINT(tp, &r.r_ur);
if ((TransRegion *)extGetRegion(tp) == reg) if ((TransRegion *)ExtGetRegion(tp, (TileType)0) == reg)
{ {
r.r_ll = r.r_ur; r.r_ll = r.r_ur;
} }
@ -493,17 +492,17 @@ extHardFreeAll(def, tReg)
arg.fra_connectsTo = ExtCurStyle->exts_nodeConn; arg.fra_connectsTo = ExtCurStyle->exts_nodeConn;
arg.fra_def = def; arg.fra_def = def;
arg.fra_each = (int (*)()) NULL; arg.fra_each = (int (*)()) NULL;
arg.fra_region = (ExtRegion *) extUnInit; arg.fra_region = (ExtRegion *) CLIENTDEFAULT;
free_magic1_t mm1 = freeMagic1_init(); free_magic1_t mm1 = freeMagic1_init();
for (reg = tReg; reg; reg = reg->treg_next) for (reg = tReg; reg; reg = reg->treg_next)
{ {
/* Reset all ti_client fields to extUnInit */ /* Reset all ti_client fields to CLIENTDEFAULT */
arg.fra_uninit = (ClientData) reg; arg.fra_uninit = (ClientData) reg;
if (reg->treg_tile) if (reg->treg_tile)
{ {
arg.fra_pNum = reg->treg_area; arg.fra_pNum = reg->treg_area;
ExtFindNeighbors(reg->treg_tile, arg.fra_pNum, &arg); ExtFindNeighbors(reg->treg_tile, reg->treg_dinfo, arg.fra_pNum, &arg);
} }
/* Free all LabelLists and then the region */ /* Free all LabelLists and then the region */

View File

@ -60,34 +60,93 @@ int extHierConnectFunc2();
int extHierConnectFunc3(); int extHierConnectFunc3();
Node *extHierNewNode(); Node *extHierNewNode();
/*----------------------------------------------------------------------*/ /*
/* extHierSubShieldFunc -- */ *----------------------------------------------------------------------
/* */ *
/* Simple callback function for extHierSubstrate() that halts the */ * extTestNMInteract --
/* search if any substrate shield type is found in the search area */ *
/* */ * Determine if two tiles overlap, including split tiles. Since
/*----------------------------------------------------------------------*/ * this is a much more complicated check than the simple overlap
* of two rectangular tiles, it is assumed that at least tile t1
* is a split tile, and does not check for simple rectangular
* overlap. The insideness test is the same used by
* DBSrPaintNMArea(), but in the context of extHierConnectFunc,
* the two tiles are already known, so just run the equations.
* Because this test is for electrical connectivity, touching
* shapes are equivalent to overlapping shapes.
*
* The information about which side of a triangular tile is to
* be checked for overlap is in the "dinfo" argument corresponding
* to the tile. If the tile is not a split tile, then "dinfo" is
* ignored.
*
* Tile t1 is always a split tile. Tile t2 may be a simple Manhattan
* tile, in which case the possibility that t2 has "infinite" width
* or height must be considered.
*
* Results:
* TRUE if the tiles overlap or touch, FALSE if not.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
bool extTestNMInteract(Tile *t1, TileType di1, Tile *t2, TileType di2)
{
Rect rect1;
TileType tt1;
/* Turn the first tile into a Rect and a TileType containing
* the information about both diagonal and split side, and
* then call the function DBTestNMInteract() which is used by
* DBSrPaintNMArea() to determine interaction between non-
* Manhattan areas. Note that DBTestNMInteract() is called
* with the overlap_only flag set to FALSE because this should
* test for shapes either overlapping *or* touching.
*/
TiToRect(t1, &rect1);
tt1 = TiGetTypeExact(t1) | di1;
return DBTestNMInteract(&rect1, tt1, t2, di2, FALSE);
}
/*
*----------------------------------------------------------------------
* extHierSubShieldFunc --
*
* Simple callback function for extHierSubstrate() that halts the
* search if any substrate shield type is found in the search area
*
*----------------------------------------------------------------------
*/
int int
extHierSubShieldFunc(tile) extHierSubShieldFunc(tile, dinfo, clientdata)
Tile *tile; Tile *tile; /* (unused) */
TileType dinfo; /* (unused) */
ClientData clientdata; /* (unused) */
{ {
return 1; return 1;
} }
/*----------------------------------------------------------------------*/ /*
/* extHierSubstrate -- */ *----------------------------------------------------------------------
/* */ * extHierSubstrate --
/* Find the substrate node of a child cell and make a connection */ *
/* between parent and child substrates. If either of the */ * Find the substrate node of a child cell and make a connection
/* substrate nodes is already in the hash table, then the table */ * between parent and child substrates. If either of the
/* will be updated as necessary. */ * substrate nodes is already in the hash table, then the table
/* */ * will be updated as necessary.
/* This function also determines if a child cell's substrate is */ *
/* isolated by a substrate shield type, in which case no merge is */ * This function also determines if a child cell's substrate is
/* done. */ * isolated by a substrate shield type, in which case no merge is
/* */ * done.
/*----------------------------------------------------------------------*/ *
*----------------------------------------------------------------------
*/
void void
extHierSubstrate(ha, use, x, y) extHierSubstrate(ha, use, x, y)
@ -124,6 +183,7 @@ extHierSubstrate(ha, use, x, y)
/* The parent def's substrate node is in glob_subsnode */ /* The parent def's substrate node is in glob_subsnode */
name1 = extNodeName(glob_subsnode); name1 = extNodeName(glob_subsnode);
if (*name1 == '(' && !strcmp(name1, "(none)")) return; /* Don't process "(none)" nodes! */
he = HashFind(table, name1); he = HashFind(table, name1);
nn = (NodeName *) HashGetValue(he); nn = (NodeName *) HashGetValue(he);
node1 = nn ? nn->nn_node : extHierNewNode(he); node1 = nn ? nn->nn_node : extHierNewNode(he);
@ -132,7 +192,7 @@ extHierSubstrate(ha, use, x, y)
nodeList = extFindNodes(use->cu_def, (Rect *) NULL, TRUE); nodeList = extFindNodes(use->cu_def, (Rect *) NULL, TRUE);
if (nodeList == NULL) if (nodeList == NULL)
{ {
ExtResetTiles(use->cu_def, extUnInit); ExtResetTiles(use->cu_def, CLIENTDEFAULT);
return; return;
} }
@ -172,7 +232,7 @@ extHierSubstrate(ha, use, x, y)
extHierSubShieldFunc, (ClientData)NULL) != 0) extHierSubShieldFunc, (ClientData)NULL) != 0)
{ {
freeMagic(nodeList); freeMagic(nodeList);
ExtResetTiles(use->cu_def, extUnInit); ExtResetTiles(use->cu_def, CLIENTDEFAULT);
return; return;
} }
} }
@ -181,7 +241,7 @@ extHierSubstrate(ha, use, x, y)
/* Make sure substrate labels are represented */ /* Make sure substrate labels are represented */
ExtLabelRegions(use->cu_def, ExtCurStyle->exts_nodeConn, &nodeList, ExtLabelRegions(use->cu_def, ExtCurStyle->exts_nodeConn, &nodeList,
&TiPlaneRect); &TiPlaneRect);
ExtResetTiles(use->cu_def, extUnInit); ExtResetTiles(use->cu_def, CLIENTDEFAULT);
name2 = extNodeName(temp_subsnode); name2 = extNodeName(temp_subsnode);
@ -294,8 +354,8 @@ extHierConnections(ha, cumFlat, oneFlat)
if (!(lab->lab_flags & LABEL_STICKY)) continue; if (!(lab->lab_flags & LABEL_STICKY)) continue;
r = lab->lab_rect; r = lab->lab_rect;
if (!GEO_TOUCH(&r, &ha->ha_subArea)) continue;
GEOCLIP(&r, &ha->ha_subArea); GEOCLIP(&r, &ha->ha_subArea);
if (GEO_RECTNULL(&r)) continue;
cumDef = cumFlat->et_use->cu_def; cumDef = cumFlat->et_use->cu_def;
connected = &DBConnectTbl[lab->lab_type]; connected = &DBConnectTbl[lab->lab_type];
@ -325,8 +385,9 @@ extHierConnections(ha, cumFlat, oneFlat)
*/ */
int int
extHierConnectFunc1(oneTile, ha) extHierConnectFunc1(oneTile, dinfo, ha)
Tile *oneTile; /* Comes from 'oneFlat' in extHierConnections */ Tile *oneTile; /* Comes from 'oneFlat' in extHierConnections */
TileType dinfo; /* Split tile information (unused) */
HierExtractArg *ha; /* Extraction context */ HierExtractArg *ha; /* Extraction context */
{ {
CellDef *cumDef = extHierCumFlat->et_use->cu_def; CellDef *cumDef = extHierCumFlat->et_use->cu_def;
@ -347,12 +408,16 @@ extHierConnectFunc1(oneTile, ha)
if (IsSplit(oneTile)) if (IsSplit(oneTile))
{ {
rtype = ha->hierType; /* For split tiles, move the tile type to lower (right side) field
ha->hierType = (rtype & TT_SIDE) ? SplitRightType(oneTile) : * but retain the TT_SIDE bit, to indicate which side of hierOneTile
* is the connected side.
*/
ha->hierType = (dinfo & TT_SIDE) ? SplitRightType(oneTile) :
SplitLeftType(oneTile); SplitLeftType(oneTile);
ha->hierType |= (dinfo & (TT_DIAGONAL | TT_DIRECTION | TT_SIDE));
} }
connected = &(ExtCurStyle->exts_nodeConn[ha->hierType]); connected = &(ExtCurStyle->exts_nodeConn[ha->hierType & TT_LEFTMASK]);
TITORECT(oneTile, &r); TITORECT(oneTile, &r);
GEOCLIP(&r, &ha->ha_subArea); GEOCLIP(&r, &ha->ha_subArea);
r.r_xbot--, r.r_ybot--, r.r_xtop++, r.r_ytop++; r.r_xbot--, r.r_ybot--, r.r_xtop++, r.r_ytop++;
@ -364,7 +429,7 @@ extHierConnectFunc1(oneTile, ha)
{ {
if (IsSplit(oneTile)) if (IsSplit(oneTile))
DBSrPaintNMArea((Tile *) NULL, cumDef->cd_planes[i], DBSrPaintNMArea((Tile *) NULL, cumDef->cd_planes[i],
rtype, &r, ha->hierType, &r,
((i == ha->hierPNum) ? &ExtCurStyle->exts_activeTypes ((i == ha->hierPNum) ? &ExtCurStyle->exts_activeTypes
: connected), extHierConnectFunc2, (ClientData) ha); : connected), extHierConnectFunc2, (ClientData) ha);
else else
@ -412,8 +477,9 @@ extHierConnectFunc1(oneTile, ha)
nn = (NodeName *) HashGetValue(he); nn = (NodeName *) HashGetValue(he);
node1 = nn ? nn->nn_node : extHierNewNode(he); node1 = nn ? nn->nn_node : extHierNewNode(he);
name = (*ha->ha_nodename)(ha->hierOneTile, ha->hierPNum, name = (*ha->ha_nodename)(ha->hierOneTile, ha->hierType, ha->hierPNum,
extHierOneFlat, ha, TRUE); extHierOneFlat, ha, TRUE);
if (*name == '(' && !strcmp(name, "(none)")) return 0; /* Don't process "(none)" nodes! */
he = HashFind(table, name); he = HashFind(table, name);
nn = (NodeName *) HashGetValue(he); nn = (NodeName *) HashGetValue(he);
node2 = nn ? nn->nn_node : extHierNewNode(he); node2 = nn ? nn->nn_node : extHierNewNode(he);
@ -475,8 +541,9 @@ extHierConnectFunc1(oneTile, ha)
*/ */
int int
extHierConnectFunc2(cum, ha) extHierConnectFunc2(cum, dinfo, ha)
Tile *cum; /* Comes from extHierCumFlat->et_use->cu_def */ Tile *cum; /* Comes from extHierCumFlat->et_use->cu_def */
TileType dinfo; /* Split tile information */
HierExtractArg *ha; /* Extraction context */ HierExtractArg *ha; /* Extraction context */
{ {
HashTable *table = &ha->ha_connHash; HashTable *table = &ha->ha_connHash;
@ -496,7 +563,22 @@ extHierConnectFunc2(cum, ha)
/* If the tiles don't even touch, they don't connect */ /* If the tiles don't even touch, they don't connect */
if (r.r_xtop < r.r_xbot || r.r_ytop < r.r_ybot if (r.r_xtop < r.r_xbot || r.r_ytop < r.r_ybot
|| (r.r_xtop == r.r_xbot && r.r_ytop == r.r_ybot)) || (r.r_xtop == r.r_xbot && r.r_ytop == r.r_ybot))
return (0); return 0;
/* If either tile is a split tile, then check if the areas of
* interest overlap. The first argument to extTestNMInteract()
* must be a split tile.
*/
if (IsSplit(cum))
{
if (!extTestNMInteract(cum, dinfo, ha->hierOneTile, ha->hierType))
return 0;
}
else if (IsSplit(ha->hierOneTile))
{
if (!extTestNMInteract(ha->hierOneTile, ha->hierType, cum, dinfo))
return 0;
}
/* /*
* Only make a connection if the types of 'ha->hierOneTile' and 'cum' * Only make a connection if the types of 'ha->hierOneTile' and 'cum'
@ -507,17 +589,19 @@ extHierConnectFunc2(cum, ha)
ttype = TiGetTypeExact(cum); ttype = TiGetTypeExact(cum);
if (IsSplit(cum)) if (IsSplit(cum))
ttype = (ttype & TT_SIDE) ? SplitRightType(cum) : SplitLeftType(cum); ttype = (dinfo & TT_SIDE) ? SplitRightType(cum) : SplitLeftType(cum);
if (extConnectsTo(ha->hierType, ttype, ExtCurStyle->exts_nodeConn)) if (extConnectsTo(ha->hierType & TT_LEFTMASK, ttype, ExtCurStyle->exts_nodeConn))
{ {
name1 = (*ha->ha_nodename)(cum, ha->hierPNumBelow, extHierCumFlat, ha, TRUE); name1 = (*ha->ha_nodename)(cum, dinfo, ha->hierPNumBelow, extHierCumFlat, ha, TRUE);
if (*name1 == '(' && !strcmp(name1, "(none)")) return 0; /* Don't process "(none)" nodes! */
he = HashFind(table, name1); he = HashFind(table, name1);
nn = (NodeName *) HashGetValue(he); nn = (NodeName *) HashGetValue(he);
node1 = nn ? nn->nn_node : extHierNewNode(he); node1 = nn ? nn->nn_node : extHierNewNode(he);
name2 = (*ha->ha_nodename)(ha->hierOneTile, ha->hierPNum, extHierOneFlat, name2 = (*ha->ha_nodename)(ha->hierOneTile, ha->hierType, ha->hierPNum,
ha, TRUE); extHierOneFlat, ha, TRUE);
if (*name2 == '(' && !strcmp(name2, "(none)")) return 0; /* Don't process "(none)" nodes! */
he = HashFind(table, name2); he = HashFind(table, name2);
nn = (NodeName *) HashGetValue(he); nn = (NodeName *) HashGetValue(he);
node2 = nn ? nn->nn_node : extHierNewNode(he); node2 = nn ? nn->nn_node : extHierNewNode(he);
@ -562,7 +646,7 @@ extHierConnectFunc2(cum, ha)
snprintf(message, sizeof(message), snprintf(message, sizeof(message),
"Illegal overlap between %s and %s (types do not connect)", "Illegal overlap between %s and %s (types do not connect)",
DBTypeLongNameTbl[ha->hierType], DBTypeLongNameTbl[ttype]); DBTypeLongNameTbl[ha->hierType & TT_LEFTMASK], DBTypeLongNameTbl[ttype]);
extNumErrors++; extNumErrors++;
if (!DebugIsSet(extDebugID, extDebNoFeedback)) if (!DebugIsSet(extDebugID, extDebNoFeedback))
@ -584,8 +668,9 @@ extHierConnectFunc2(cum, ha)
*/ */
int int
extHierConnectFunc3(cum, ha) extHierConnectFunc3(cum, dinfo, ha)
Tile *cum; /* Comes from extHierCumFlat->et_use->cu_def */ Tile *cum; /* Comes from extHierCumFlat->et_use->cu_def */
TileType dinfo; /* Split tile information */
HierExtractArg *ha; /* Extraction context */ HierExtractArg *ha; /* Extraction context */
{ {
HashTable *table = &ha->ha_connHash; HashTable *table = &ha->ha_connHash;
@ -616,16 +701,19 @@ extHierConnectFunc3(cum, ha)
ttype = TiGetTypeExact(cum); ttype = TiGetTypeExact(cum);
if (IsSplit(cum)) if (IsSplit(cum))
ttype = (ttype & TT_SIDE) ? SplitRightType(cum) : SplitLeftType(cum); ttype = (dinfo & TT_SIDE) ? SplitRightType(cum) : SplitLeftType(cum);
if (extConnectsTo(ha->hierType, ttype, ExtCurStyle->exts_nodeConn)) if (extConnectsTo(ha->hierType & TT_LEFTMASK, ttype, ExtCurStyle->exts_nodeConn))
{ {
name1 = (*ha->ha_nodename)(cum, ha->hierPNumBelow, extHierCumFlat, ha, TRUE); name1 = (*ha->ha_nodename)(cum, ha->hierType, ha->hierPNumBelow,
extHierCumFlat, ha, TRUE);
if (*name1 == '(' && !strcmp(name1, "(none)")) return 0; /* Don't process "(none)" nodes! */
he = HashFind(table, name1); he = HashFind(table, name1);
nn = (NodeName *) HashGetValue(he); nn = (NodeName *) HashGetValue(he);
node1 = nn ? nn->nn_node : extHierNewNode(he); node1 = nn ? nn->nn_node : extHierNewNode(he);
name2 = lab->lab_text; name2 = lab->lab_text;
if (*name2 == '(' && !strcmp(name2, "(none)")) return 0; /* Don't process "(none)" nodes! */
he = HashFind(table, name2); he = HashFind(table, name2);
nn = (NodeName *) HashGetValue(he); nn = (NodeName *) HashGetValue(he);
node2 = nn ? nn->nn_node : extHierNewNode(he); node2 = nn ? nn->nn_node : extHierNewNode(he);
@ -670,7 +758,7 @@ extHierConnectFunc3(cum, ha)
snprintf(message, sizeof(message), snprintf(message, sizeof(message),
"Illegal overlap between %s and %s (types do not connect)", "Illegal overlap between %s and %s (types do not connect)",
DBTypeLongNameTbl[ha->hierType], DBTypeLongNameTbl[ttype]); DBTypeLongNameTbl[ha->hierType & TT_LEFTMASK], DBTypeLongNameTbl[ttype]);
extNumErrors++; extNumErrors++;
if (!DebugIsSet(extDebugID, extDebNoFeedback)) if (!DebugIsSet(extDebugID, extDebNoFeedback))
@ -771,18 +859,20 @@ extHierAdjustments(ha, cumFlat, oneFlat, lookFlat)
*/ */
for (np = oneFlat->et_nodes; np; np = np->nreg_next) for (np = oneFlat->et_nodes; np; np = np->nreg_next)
{ {
TileType dinfo;
/* Ignore orphaned nodes (non-Manhattan shards outside the clip box) */ /* Ignore orphaned nodes (non-Manhattan shards outside the clip box) */
if (np->nreg_pnum == DBNumPlanes) continue; if (np->nreg_pnum == DBNumPlanes) continue;
tp = extNodeToTile(np, lookFlat); tp = extNodeToTile(np, lookFlat, &dinfo);
/* Ignore regions that do not participate in extraction */ /* Ignore regions that do not participate in extraction */
if (!extHasRegion(tp, extUnInit)) continue; if (!extHasRegion(tp, CLIENTDEFAULT)) continue;
/* Ignore substrate nodes (failsafe: should not happen) */ /* Ignore substrate nodes (failsafe: should not happen) */
if (TiGetTypeExact(tp) == TT_SPACE) continue; if (TiGetTypeExact(tp) == TT_SPACE) continue;
if (tp && (name = (*ha->ha_nodename)(tp, np->nreg_pnum, lookFlat, ha, FALSE)) if (tp && (name = (*ha->ha_nodename)(tp, dinfo, np->nreg_pnum, lookFlat, ha, FALSE))
&& (he = HashLookOnly(&ha->ha_connHash, name)) && (he = HashLookOnly(&ha->ha_connHash, name))
&& (nn = (NodeName *) HashGetValue(he))) && (nn = (NodeName *) HashGetValue(he)))
{ {
@ -946,8 +1036,9 @@ extHierNewNode(he)
/*ARGSUSED*/ /*ARGSUSED*/
ExtRegion * ExtRegion *
extHierLabFirst(tile, arg) extHierLabFirst(tile, dinfo, arg)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
FindRegion *arg; FindRegion *arg;
{ {
LabRegion *new; LabRegion *new;
@ -966,15 +1057,16 @@ extHierLabFirst(tile, arg)
/*ARGSUSED*/ /*ARGSUSED*/
int int
extHierLabEach(tile, pNum, arg) extHierLabEach(tile, dinfo, pNum, arg)
Tile *tile; Tile *tile;
TileType dinfo;
int pNum; int pNum;
FindRegion *arg; FindRegion *arg;
{ {
LabRegion *reg; LabRegion *reg;
reg = (LabRegion *) arg->fra_region; reg = (LabRegion *) arg->fra_region;
extSetNodeNum(reg, pNum, tile); extSetNodeNum(reg, pNum, tile, dinfo);
return (0); return (0);
} }

View File

@ -270,8 +270,9 @@ extInterSubtreeElement(use, trans, x, y, r)
*/ */
int int
extInterSubtreeTile(tile, cxp) extInterSubtreeTile(tile, dinfo, cxp)
Tile *tile; Tile *tile;
TileType dinfo;
TreeContext *cxp; TreeContext *cxp;
{ {
SearchContext newscx; SearchContext newscx;

View File

@ -434,8 +434,9 @@ extLengthYank(use, labList)
*/ */
int int
extLengthLabels(tile, rootUse) extLengthLabels(tile, dinfo, rootUse)
Tile *tile; /* Some tile in extPathDef */ Tile *tile; /* Some tile in extPathDef */
TileType dinfo; /* Split tile information (unused) */
CellUse *rootUse; /* The original root cell */ CellUse *rootUse; /* The original root cell */
{ {
char name[MAXNAMESIZE]; char name[MAXNAMESIZE];
@ -727,8 +728,9 @@ extPathResetClient(tile)
*/ */
int int
extPathPairFunc(tile, epa) extPathPairFunc(tile, dinfo, epa)
Tile *tile; Tile *tile;
TileType dinfo; // Unused
struct extPathArg *epa; struct extPathArg *epa;
{ {
Point startPoint; Point startPoint;
@ -909,8 +911,9 @@ extPathFlood(tile, p, distance, epa)
} }
int int
extPathFloodFunc(dstTile, epfa) extPathFloodFunc(dstTile, dinfo, epfa)
Tile *dstTile; Tile *dstTile;
TileType dinfo; // Unused
struct extPathFloodArg *epfa; struct extPathFloodArg *epfa;
{ {
Rect srcRect, dstRect; Rect srcRect, dstRect;

View File

@ -35,6 +35,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "debug/debug.h" #include "debug/debug.h"
#include "extract/extract.h" #include "extract/extract.h"
#include "extract/extractInt.h" #include "extract/extractInt.h"
#include "resis/resis.h"
#include "utils/signals.h" #include "utils/signals.h"
#include "utils/stack.h" #include "utils/stack.h"
#include "utils/utils.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/main.h"
#include "utils/undo.h" #include "utils/undo.h"
/* Imports from elsewhere in this module */
extern FILE *extFileOpen();
/* ------------------------ Exported variables ------------------------ */ /* ------------------------ Exported variables ------------------------ */
/* /*
@ -83,16 +81,6 @@ typedef struct _linkedDef {
struct _linkedDef *ld_next; struct _linkedDef *ld_next;
} LinkedDef; } 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 of defs pending extraction */
Stack *extDefStack; Stack *extDefStack;
@ -209,9 +197,10 @@ extIsUsedFunc(use, clientData)
*/ */
int int
extEnumFunc(tile, plane) extEnumFunc(tile, dinfo, clientdata)
Tile *tile; Tile *tile; /* (unused) */
int *plane; TileType dinfo; /* (unused) */
ClientData clientdata; /* (unused) */
{ {
return 1; return 1;
} }
@ -605,7 +594,7 @@ extParents(use, doExtract)
extDefParentFunc(use->cu_def); extDefParentFunc(use->cu_def);
/* Now extract all the cells we just found */ /* Now extract all the cells we just found */
extExtractStack(extDefStack, doExtract, (CellDef *) NULL); extExtractStack(extDefStack, doExtract, (CellDef *)NULL);
StackFree(extDefStack); StackFree(extDefStack);
/* Replace any modified substrate planes in use->cu_def's children */ /* Replace any modified substrate planes in use->cu_def's children */
@ -687,7 +676,7 @@ ExtParentArea(use, changedArea, doExtract)
extDefParentAreaFunc(use->cu_def, use->cu_def, (CellUse *) NULL, &area); extDefParentAreaFunc(use->cu_def, use->cu_def, (CellUse *) NULL, &area);
/* Now extract all the cells we just found */ /* Now extract all the cells we just found */
extExtractStack(extDefStack, doExtract, (CellDef *) NULL); extExtractStack(extDefStack, doExtract, (CellDef *)NULL);
StackFree(extDefStack); StackFree(extDefStack);
} }
@ -805,12 +794,30 @@ ExtractOneCell(def, outName, doLength)
savePlane = ExtCell(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); if (savePlane != NULL) ExtRevertSubstrate(def, savePlane);
free_magic1_t mm1 = freeMagic1_init(); free_magic1_t mm1 = freeMagic1_init();
for (; sl; sl = sl->sl_next) for (; sl; sl = sl->sl_next)
{ {
if (EXT_DOUNIQUE) ExtRevertUniqueCell(sl->sl_def);
ExtRevertSubstrate(sl->sl_def, sl->sl_plane); ExtRevertSubstrate(sl->sl_def, sl->sl_plane);
freeMagic1(&mm1, sl); freeMagic1(&mm1, sl);
} }
@ -854,7 +861,10 @@ extContainsCellFunc(
} }
int int
extContainsPaintFunc() extContainsPaintFunc(
Tile *tile, /* (unused) */
TileType dinfo, /* (unused) */
ClientData clientdata) /* (unused) */
{ {
return (1); return (1);
} }
@ -940,7 +950,7 @@ extTimestampMisMatch(def)
doLocal = (ExtLocalPath == NULL) ? FALSE : TRUE; doLocal = (ExtLocalPath == NULL) ? FALSE : TRUE;
extFile = extFileOpen(def, (char *) NULL, "r", (char **) NULL); extFile = ExtFileOpen(def, (char *) NULL, "r", (char **) NULL);
if (extFile == NULL) if (extFile == NULL)
return (TRUE); return (TRUE);
@ -986,10 +996,18 @@ extExtractStack(stack, doExtract, rootDef)
bool first = TRUE; bool first = TRUE;
Plane *savePlane; Plane *savePlane;
CellDef *def; CellDef *def;
LinkedDef *savelist = NULL, *revlist = NULL, *newld;
struct saveList *newsl, *sl = (struct saveList *)NULL; struct saveList *newsl, *sl = (struct saveList *)NULL;
while ((def = (CellDef *) StackPop(stack))) 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; def->cd_client = (ClientData) 0;
if (!SigInterruptPending) if (!SigInterruptPending)
{ {
@ -1004,6 +1022,8 @@ extExtractStack(stack, doExtract, rootDef)
newsl->sl_next = sl; newsl->sl_next = sl;
sl = newsl; sl = newsl;
} }
else
def->cd_flags &= ~CDNOEXTRACT;
errorcnt += extNumErrors; errorcnt += extNumErrors;
warnings += extNumWarnings; warnings += extNumWarnings;
@ -1015,13 +1035,55 @@ extExtractStack(stack, doExtract, rootDef)
TxFlush(); TxFlush();
first = FALSE; first = FALSE;
} }
else
def->cd_flags &= ~CDNOEXTRACT;
} }
} }
/* 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(); free_magic1_t mm1 = freeMagic1_init();
for (; sl; sl = sl->sl_next) for (; sl; sl = sl->sl_next)
{ {
if (EXT_DOUNIQUE) ExtRevertUniqueCell(sl->sl_def);
ExtRevertSubstrate(sl->sl_def, sl->sl_plane); ExtRevertSubstrate(sl->sl_def, sl->sl_plane);
sl->sl_def->cd_flags &= ~CDNOEXTRACT; sl->sl_def->cd_flags &= ~CDNOEXTRACT;
freeMagic1(&mm1, sl); freeMagic1(&mm1, sl);

View File

@ -45,9 +45,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
* the value VISITPENDING in its ti_client field. * the value VISITPENDING in its ti_client field.
*/ */
/* Used for communicating with extNbrPushFunc */
ClientData extNbrUn;
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -74,41 +71,44 @@ ClientData extNbrUn;
*/ */
int int
ExtFindNeighbors(tile, tilePlaneNum, arg) ExtFindNeighbors(tile, dinfo, tilePlaneNum, arg)
Tile *tile; Tile *tile;
TileType dinfo;
int tilePlaneNum; int tilePlaneNum;
FindRegion *arg; FindRegion *arg;
{ {
TileTypeBitMask *connTo = arg->fra_connectsTo; TileTypeBitMask *connTo = arg->fra_connectsTo;
Tile *tp; Tile *tp;
TileType type, t; TileType type, t, tpdinfo;
TileTypeBitMask *mask; TileTypeBitMask *mask;
Rect biggerArea; Rect biggerArea;
int pNum, tilesfound; int pNum, tilesfound;
PlaneMask pMask; PlaneMask pMask;
PlaneAndArea pla; PlaneAndArea pla;
ClientData extNbrUn = arg->fra_uninit;
tilesfound = 0; tilesfound = 0;
extNbrUn = arg->fra_uninit;
if (extNodeStack == (Stack *) NULL) if (extNodeStack == (Stack *) NULL)
extNodeStack = StackNew(64); extNodeStack = StackNew(64);
/* Mark this tile as pending and push it */ /* Mark this tile as pending and push it */
PUSHTILE(tile, tilePlaneNum); PUSHTILE(tile, dinfo, tilePlaneNum);
while (!StackEmpty(extNodeStack)) while (!StackEmpty(extNodeStack))
{ {
POPTILE(tile, tilePlaneNum); POPTILE(tile, dinfo, tilePlaneNum);
if (IsSplit(tile)) if (IsSplit(tile))
{ {
type = (SplitSide(tile)) ? SplitRightType(tile): type = (dinfo & TT_SIDE) ? SplitRightType(tile):
SplitLeftType(tile); SplitLeftType(tile);
} }
else else
type = TiGetTypeExact(tile); type = TiGetTypeExact(tile);
ASSERT(type != TT_SPACE, "ExtFindNeighbors");
mask = &connTo[type]; mask = &connTo[type];
/* /*
@ -117,23 +117,27 @@ ExtFindNeighbors(tile, tilePlaneNum, arg)
* been visited in the meantime. If it's still unvisited, * been visited in the meantime. If it's still unvisited,
* visit it and process its neighbors. * visit it and process its neighbors.
*/ */
if (TiGetClientPTR(tile) == arg->fra_region)
if (ExtGetRegion(tile, dinfo) == arg->fra_region)
continue; continue;
TiSetClientPTR(tile, arg->fra_region);
ExtSetRegion(tile, dinfo, arg->fra_region);
tilesfound++; tilesfound++;
if (DebugIsSet(extDebugID, extDebNeighbor)) if (DebugIsSet(extDebugID, extDebNeighbor))
extShowTile(tile, "neighbor", 1); extShowTile(tile, "neighbor", 1);
/* Top */ /* Top */
topside: topside:
if (IsSplit(tile) && (SplitSide(tile) ^ SplitDirection(tile))) goto leftside; if (IsSplit(tile) && ((dinfo & TT_SIDE) ? 1 : 0) ^ SplitDirection(tile))
goto leftside;
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp)) for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
{ {
if (IsSplit(tp)) if (IsSplit(tp))
{ {
t = SplitBottomType(tp); t = SplitBottomType(tp);
// if (TiGetClient(tp) == extNbrUn && TTMaskHasType(mask, t)) tpdinfo = SplitDirection(tp) ? (TileType)0 : (TileType)TT_SIDE;
if (TiGetClientPTR(tp) != arg->fra_region && TTMaskHasType(mask, t)) if (ExtGetRegion(tp, tpdinfo) == CD2PTR(extNbrUn) && TTMaskHasType(mask, t))
{ {
PUSHTILEBOTTOM(tp, tilePlaneNum); PUSHTILEBOTTOM(tp, tilePlaneNum);
} }
@ -143,21 +147,21 @@ topside:
t = TiGetTypeExact(tp); t = TiGetTypeExact(tp);
if (TiGetClient(tp) == extNbrUn && TTMaskHasType(mask, t)) if (TiGetClient(tp) == extNbrUn && TTMaskHasType(mask, t))
{ {
PUSHTILE(tp, tilePlaneNum); PUSHTILELEFT(tp, tilePlaneNum);
} }
} }
} }
/* Left */ /* Left */
leftside: leftside:
if (IsSplit(tile) && SplitSide(tile)) goto bottomside; if (IsSplit(tile) && (dinfo & TT_SIDE)) goto bottomside;
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp)) for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
{ {
if (IsSplit(tp)) if (IsSplit(tp))
{ {
t = SplitRightType(tp); t = SplitRightType(tp);
// if (TiGetClient(tp) == extNbrUn && TTMaskHasType(mask, t)) if (ExtGetRegion(tp, (TileType)TT_SIDE) == CD2PTR(extNbrUn)
if (TiGetClientPTR(tp) != arg->fra_region && TTMaskHasType(mask, t)) && TTMaskHasType(mask, t))
{ {
PUSHTILERIGHT(tp, tilePlaneNum); PUSHTILERIGHT(tp, tilePlaneNum);
} }
@ -167,22 +171,22 @@ leftside:
t = TiGetTypeExact(tp); t = TiGetTypeExact(tp);
if (TiGetClient(tp) == extNbrUn && TTMaskHasType(mask, t)) if (TiGetClient(tp) == extNbrUn && TTMaskHasType(mask, t))
{ {
PUSHTILE(tp, tilePlaneNum); PUSHTILELEFT(tp, tilePlaneNum);
} }
} }
} }
/* Bottom */ /* Bottom */
bottomside: bottomside:
if (IsSplit(tile) && (!(SplitSide(tile) ^ SplitDirection(tile)))) if (IsSplit(tile) && (!(((dinfo & TT_SIDE) ? 1 : 0) ^ SplitDirection(tile))))
goto rightside; goto rightside;
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
{ {
if (IsSplit(tp)) if (IsSplit(tp))
{ {
t = SplitTopType(tp); t = SplitTopType(tp);
// if (TiGetClient(tp) == extNbrUn && TTMaskHasType(mask, t)) tpdinfo = SplitDirection(tp) ? (TileType)TT_SIDE : (TileType)0;
if (TiGetClientPTR(tp) != arg->fra_region && TTMaskHasType(mask, t)) if (ExtGetRegion(tp, tpdinfo) == CD2PTR(extNbrUn) && TTMaskHasType(mask, t))
{ {
PUSHTILETOP(tp, tilePlaneNum); PUSHTILETOP(tp, tilePlaneNum);
} }
@ -192,21 +196,21 @@ bottomside:
t = TiGetTypeExact(tp); t = TiGetTypeExact(tp);
if (TiGetClient(tp) == extNbrUn && TTMaskHasType(mask, t)) if (TiGetClient(tp) == extNbrUn && TTMaskHasType(mask, t))
{ {
PUSHTILE(tp, tilePlaneNum); PUSHTILELEFT(tp, tilePlaneNum);
} }
} }
} }
/* Right */ /* Right */
rightside: rightside:
if (IsSplit(tile) && !SplitSide(tile)) goto donesides; if (IsSplit(tile) && !(dinfo & TT_SIDE)) goto donesides;
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp)) for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
{ {
if (IsSplit(tp)) if (IsSplit(tp))
{ {
t = SplitLeftType(tp); t = SplitLeftType(tp);
// if (TiGetClient(tp) == extNbrUn && TTMaskHasType(mask, t)) if (ExtGetRegion(tp, (TileType)0) == CD2PTR(extNbrUn)
if (TiGetClientPTR(tp) != arg->fra_region && TTMaskHasType(mask, t)) && TTMaskHasType(mask, t))
{ {
PUSHTILELEFT(tp, tilePlaneNum); PUSHTILELEFT(tp, tilePlaneNum);
} }
@ -216,7 +220,7 @@ rightside:
t = TiGetTypeExact(tp); t = TiGetTypeExact(tp);
if (TiGetClient(tp) == extNbrUn && TTMaskHasType(mask, t)) if (TiGetClient(tp) == extNbrUn && TTMaskHasType(mask, t))
{ {
PUSHTILE(tp, tilePlaneNum); PUSHTILELEFT(tp, tilePlaneNum);
} }
} }
} }
@ -224,9 +228,14 @@ rightside:
donesides: donesides:
/* Apply the client's filter procedure if one exists */ /* Apply the client's filter procedure if one exists */
if (arg->fra_each) if (arg->fra_each)
if ((*arg->fra_each)(tile, tilePlaneNum, arg)) if ((*arg->fra_each)(tile, dinfo, tilePlaneNum, arg))
goto fail; goto fail;
/* Use tilePlaneNum value -1 to force ExtFindNeighbors to stay
* on a single plane.
*/
if (tilePlaneNum < 0) continue;
/* If this is a contact, visit all the other planes */ /* If this is a contact, visit all the other planes */
if (DBIsContact(type)) if (DBIsContact(type))
{ {
@ -235,6 +244,7 @@ donesides:
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(pMask, pNum)) if (PlaneMaskHasPlane(pMask, pNum))
{ {
ExtRegion *tpreg;
Plane *plane = arg->fra_def->cd_planes[pNum]; Plane *plane = arg->fra_def->cd_planes[pNum];
/* Find the point on the new plane */ /* Find the point on the new plane */
@ -242,14 +252,14 @@ donesides:
GOTOPOINT(tp, &tile->ti_ll); GOTOPOINT(tp, &tile->ti_ll);
PlaneSetHint(plane, tp); PlaneSetHint(plane, tp);
/* If not yet visited, process tp */
if (TiGetClient(tp) != extNbrUn) continue;
/* tp and tile should have the same geometry for a contact */ /* tp and tile should have the same geometry for a contact */
if (IsSplit(tile) && IsSplit(tp)) if (IsSplit(tile) && IsSplit(tp))
{ {
if (SplitSide(tile)) if (dinfo & TT_SIDE)
{ {
/* Only process tp if not yet visited */
tpreg = ExtGetRegion(tp, (TileType)TT_SIDE);
if (tpreg != CD2PTR(extNbrUn)) continue;
t = SplitRightType(tp); t = SplitRightType(tp);
if (TTMaskHasType(mask, t)) if (TTMaskHasType(mask, t))
{ {
@ -258,6 +268,9 @@ donesides:
} }
else else
{ {
/* Only process tp if not yet visited */
tpreg = ExtGetRegion(tp, (TileType)0);
if (tpreg != CD2PTR(extNbrUn)) continue;
t = SplitLeftType(tp); t = SplitLeftType(tp);
if (TTMaskHasType(mask, t)) if (TTMaskHasType(mask, t))
{ {
@ -267,23 +280,36 @@ donesides:
} }
else if (IsSplit(tp)) else if (IsSplit(tp))
{ {
t = SplitRightType(tp); /* Only process tp if not yet visited */
if (TTMaskHasType(mask, t)) tpreg = ExtGetRegion(tp, (TileType)TT_SIDE);
if (tpreg == CD2PTR(extNbrUn))
{ {
PUSHTILERIGHT(tp, pNum); t = SplitRightType(tp);
if (TTMaskHasType(mask, t))
{
PUSHTILERIGHT(tp, pNum);
}
} }
t = SplitLeftType(tp); /* Try both sides */
if (TTMaskHasType(mask, t)) tpreg = ExtGetRegion(tp, (TileType)0);
if (tpreg == CD2PTR(extNbrUn))
{ {
PUSHTILELEFT(tp, pNum); t = SplitLeftType(tp);
if (TTMaskHasType(mask, t))
{
PUSHTILELEFT(tp, pNum);
}
} }
} }
else else
{ {
/* Only process tp if not yet visited */
tpreg = ExtGetRegion(tp, (TileType)0);
if (tpreg != CD2PTR(extNbrUn)) continue;
t = TiGetTypeExact(tp); t = TiGetTypeExact(tp);
if (TTMaskHasType(mask, t)) if (TTMaskHasType(mask, t))
{ {
PUSHTILE(tp, pNum); PUSHTILELEFT(tp, pNum);
} }
} }
} }
@ -300,27 +326,28 @@ donesides:
*/ */
if ((pMask = DBAllConnPlanes[type])) if ((pMask = DBAllConnPlanes[type]))
{ {
pla.uninit = extNbrUn;
TITORECT(tile, &pla.area); TITORECT(tile, &pla.area);
GEO_EXPAND(&pla.area, 1, &biggerArea); GEO_EXPAND(&pla.area, 1, &biggerArea);
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if ((pNum != tilePlaneNum) && PlaneMaskHasPlane(pMask, pNum)) if ((pNum != tilePlaneNum) && PlaneMaskHasPlane(pMask, pNum))
{ {
pla.plane = pNum; pla.plane = pNum;
(void) DBSrPaintArea((Tile *) NULL, (void) DBSrPaintNMArea((Tile *) NULL,
arg->fra_def->cd_planes[pNum], &biggerArea, arg->fra_def->cd_planes[pNum],
TiGetTypeExact(tile) | dinfo, &biggerArea,
mask, extNbrPushFunc, (ClientData) &pla); mask, extNbrPushFunc, (ClientData) &pla);
} }
} }
} }
return tilesfound; return tilesfound;
fail: fail:
/* Flush the stack */ /* Flush the stack */
while (!StackEmpty(extNodeStack)) while (!StackEmpty(extNodeStack))
{ {
POPTILE(tile, tilePlaneNum); POPTILE(tile, dinfo, tilePlaneNum);
TiSetClientPTR(tile, arg->fra_region); ExtSetRegion(tile, dinfo, arg->fra_region);
} }
return -1; return -1;
} }
@ -335,9 +362,9 @@ fail:
* with tileArea, and it hasn't already been visited, push it on the stack * with tileArea, and it hasn't already been visited, push it on the stack
* extNodeStack. * extNodeStack.
* *
* Uses the global parameter extNbrUn to determine whether or not a tile * Uses the value pla->uninit to determine whether or not a tile has been
* has been visited; if the tile's client field is equal to extNbrUn, then * visited; if the tile's client field is equal to pla->uninit, then this
* this is the first time the tile has been seen. * is the first time the tile has been seen.
* *
* Results: * Results:
* Always returns 0. * Always returns 0.
@ -349,8 +376,9 @@ fail:
*/ */
int int
extNbrPushFunc(tile, pla) extNbrPushFunc(tile, dinfo, pla)
Tile *tile; Tile *tile;
TileType dinfo;
PlaneAndArea *pla; PlaneAndArea *pla;
{ {
Rect *tileArea; Rect *tileArea;
@ -359,7 +387,7 @@ extNbrPushFunc(tile, pla)
tileArea = &pla->area; tileArea = &pla->area;
/* Ignore tile if it's already been visited */ /* Ignore tile if it's already been visited */
if (TiGetClient(tile) != extNbrUn) if (ExtGetRegion(tile, dinfo) != CD2PTR(pla->uninit))
return 0; return 0;
/* Only consider tile if it overlaps tileArea or shares part of a side */ /* Only consider tile if it overlaps tileArea or shares part of a side */
@ -372,7 +400,232 @@ extNbrPushFunc(tile, pla)
} }
/* Push tile on the stack and mark as being visited */ /* Push tile on the stack and mark as being visited */
PUSHTILE(tile, pla->plane); PUSHTILE(tile, dinfo, pla->plane);
return 0; return 0;
} }
/*
* ----------------------------------------------------------------------------
*
* extEnumTerminal ---
*
* Search out an area belonging to a device terminal starting with a given
* tile, and running a callback function for each tile found. Note that
* this routine is called from inside extEnumTilePerim and so is already
* inside an extFindNeighbors() search function. The function must be
* careful not to modify regions, as the outer search function depends on
* them. Because a device terminal should be a compact area, it is okay
* to create a linked list of tiles and use the linked list to reset the
* regions at the end, rather than depending on the state of any tile's
* ClientData record.
*
* Results:
* None.
*
* Side effects:
* Whatever the callback function does. Specifically, changing tile
* ClientData records is *not* supposed to be a side effect of this
* function, and all ClientData modifications must be put back exactly
* as they were found.
*
* NOTE: This routine should be called only once for each device terminal.
* Once the terminal area and perimeter have been measured, it will not be
* called again.
*
* ----------------------------------------------------------------------------
*/
void
extEnumTerminal(Tile *tile, /* Starting tile for search */
TileType dinfo, /* Split tile information */
TileTypeBitMask *connect, /* Pointer to connection table */
void (*func)(), /* Callback function */
ClientData clientData) /* Client data for callback function */
{
ExtRegion *termreg;
TileAndDinfo *pendlist = NULL, *resetlist = NULL;
TileAndDinfo *curtad;
const TileTypeBitMask *connectMask;
Tile *tp, *t2;
TileType tpdi, t2di;
TileType loctype, checktype;
Rect tileArea;
/* The region attached to the first terminal tile will be the
* "uninitialized" value to check.
*/
termreg = ExtGetRegion(tile, dinfo);
/* Set the ClientData to VISITPENDING */
ExtSetRegion(tile, dinfo, (ExtRegion *)VISITPENDING);
/* Start the linked list with this file */
curtad = (TileAndDinfo *)mallocMagic(sizeof(TileAndDinfo));
curtad->tad_tile = tile;
curtad->tad_dinfo = dinfo;
curtad->tad_next = NULL;
pendlist = curtad;
/* Yet another boundary search routine. Just done with a linked list
* and not a stack because it's expected to search only a handful of
* tiles.
*/
while (pendlist != NULL)
{
tp = pendlist->tad_tile;
tpdi = pendlist->tad_dinfo;
TiToRect(tp, &tileArea);
/* Call the client function. The function has no return value. */
(*func)(tp, tpdi, clientData);
/* Move this tile entry to reset list */
curtad = pendlist;
pendlist = pendlist->tad_next;
curtad->tad_next = resetlist;
resetlist = curtad;
/* Search all sides of the tile for other tiles having the same
* terminal node (same region in the ClientData record),
* and add them to the linked list. This code is largely copied
* from dbSrConnectFunc(). Note that the connect table is used
* because the device's gate node may have the same region but
* is not part of the terminal.
*/
if (IsSplit(tp))
{
if (tpdi & TT_SIDE)
loctype = SplitRightType(tp);
else
loctype = SplitLeftType(tp);
}
else
loctype = TiGetTypeExact(tp);
connectMask = &connect[loctype];
/* Left side */
if (IsSplit(tp) && (tpdi & TT_SIDE)) goto termbottom;
for (t2 = BL(tp); BOTTOM(t2) < tileArea.r_ytop; t2 = RT(t2))
{
if (IsSplit(t2))
checktype = SplitRightType(t2);
else
checktype = TiGetTypeExact(t2);
if (TTMaskHasType(connectMask, checktype))
{
t2di = (TileType)TT_SIDE;
/* Tile must belong to the terminal node and not been visited */
if (ExtGetRegion(t2, t2di) != termreg) continue;
/* Add t2 to the linked list */
curtad = (TileAndDinfo *)mallocMagic(sizeof(TileAndDinfo));
curtad->tad_tile = t2;
curtad->tad_dinfo = t2di;
curtad->tad_next = pendlist;
pendlist = curtad;
/* Set the ClientData to VISITPENDING */
ExtSetRegion(t2, t2di, (ExtRegion *)VISITPENDING);
}
}
/* Bottom side */
termbottom:
if (IsSplit(tp) && ((!((tpdi & TT_SIDE) ? 1 : 0)) ^ SplitDirection(tp)))
goto termright;
for (t2 = LB(tp); LEFT(t2) < tileArea.r_xtop; t2 = TR(t2))
{
if (IsSplit(t2))
checktype = SplitTopType(t2);
else
checktype = TiGetTypeExact(t2);
if (TTMaskHasType(connectMask, checktype))
{
t2di = SplitDirection(t2) ? (TileType)TT_SIDE : (TileType)0;
/* Tile must belong to the terminal node and not been visited */
if (ExtGetRegion(t2, t2di) != termreg) continue;
/* Add t2 to the linked list */
curtad = (TileAndDinfo *)mallocMagic(sizeof(TileAndDinfo));
curtad->tad_tile = t2;
curtad->tad_dinfo = t2di;
curtad->tad_next = pendlist;
pendlist = curtad;
/* Set the ClientData to VISITPENDING */
ExtSetRegion(t2, t2di, (ExtRegion *)VISITPENDING);
}
}
/* Right side: */
termright:
if (IsSplit(tp) && !(tpdi & TT_SIDE)) goto termtop;
for (t2 = TR(tp); TOP(t2) > tileArea.r_ybot; t2 = LB(t2))
{
if (IsSplit(t2))
checktype = SplitLeftType(t2);
else
checktype = TiGetTypeExact(t2);
if (TTMaskHasType(connectMask, checktype))
{
t2di = (TileType)0;
/* Tile must belong to the terminal node and not been visited */
if (ExtGetRegion(t2, t2di) != termreg) continue;
/* Add t2 to the linked list */
curtad = (TileAndDinfo *)mallocMagic(sizeof(TileAndDinfo));
curtad->tad_tile = t2;
curtad->tad_dinfo = t2di;
curtad->tad_next = pendlist;
pendlist = curtad;
/* Set the ClientData to VISITPENDING */
ExtSetRegion(t2, t2di, (ExtRegion *)VISITPENDING);
}
}
/* Top side */
termtop:
if (IsSplit(tp) && (((tpdi & TT_SIDE) ? 1 : 0) ^ SplitDirection(tp)))
goto termdone;
for (t2 = RT(tp); RIGHT(t2) > tileArea.r_xbot; t2 = BL(t2))
{
if (IsSplit(t2))
checktype = SplitBottomType(t2);
else
checktype = TiGetTypeExact(t2);
if (TTMaskHasType(connectMask, checktype))
{
t2di = SplitDirection(t2) ? (TileType)0 : (TileType)TT_SIDE;
/* Tile must belong to the terminal node and not been visited */
if (ExtGetRegion(t2, t2di) != termreg) continue;
/* Add t2 to the linked list */
curtad = (TileAndDinfo *)mallocMagic(sizeof(TileAndDinfo));
curtad->tad_tile = t2;
curtad->tad_dinfo = t2di;
curtad->tad_next = pendlist;
pendlist = curtad;
/* Set the ClientData to VISITPENDING */
ExtSetRegion(t2, t2di, (ExtRegion *)VISITPENDING);
}
}
termdone:
/* (continue) */
}
/* Clean up---Put the ClientData entries in the tiles back to
* term reg and free up the linked list memory.
*/
while (resetlist != NULL)
{
curtad = resetlist->tad_next;
ExtSetRegion(resetlist->tad_tile, resetlist->tad_dinfo, termreg);
freeMagic(resetlist);
resetlist = curtad;
}
}

View File

@ -36,7 +36,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "extract/extract.h" #include "extract/extract.h"
#include "extract/extractInt.h" #include "extract/extractInt.h"
#define POINTEQUAL(p, q) ((p)->p_x == (q)->p_x && (p)->p_y == (q)->p_y) #define POINTEQUAL(p, q) (((p)->p_x == (q)->p_x) && ((p)->p_y == (q)->p_y))
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
@ -57,7 +57,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
* { * {
* } * }
* *
* The value returned by this function is ignored. * The value returned by the callback function is ignored.
* *
* Results: * Results:
* Returns the total length of the portion of the perimeter of * Returns the total length of the portion of the perimeter of
@ -68,10 +68,10 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
* to each qualifying segment of the boundary. * to each qualifying segment of the boundary.
* *
* Note: * Note:
* The width/length calculation method is manhattan-only. So this * The width/length calculation method is manhattan-only, and will
* routine is pseudo-manhattan. It computes the true non-manhattan * likely need correcting. This routine computes the true perimeter
* perimeter, but calls the function on the perimeter tiles as if * length and calls the callback function on the perimeter tiles of
* the whole tile is the transistor type. * the correct tile type.
* *
* Non-interruptible. * Non-interruptible.
* *
@ -81,28 +81,34 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
int int
extEnumTilePerim( extEnumTilePerim(
Tile *tpIn, Tile *tpIn,
TileType dinfo,
const TileTypeBitMask *maskp, const TileTypeBitMask *maskp,
int pNum, /* Plane of perimeter */ int pNum, /* Plane of perimeter */
int (*func)(), int (*func)(),
ClientData cdata) ClientData cdata)
{ {
TileTypeBitMask mask = *maskp; /* TTMaskCopy(&mask, maskp) */ TileTypeBitMask mask = *maskp;
TileType origType;
Tile *tpOut; Tile *tpOut;
int perimCorrect; int perimCorrect;
Boundary b; Boundary b;
unsigned char sides = 0; unsigned char sides = 0; /* Sides to be ignored */
b.b_inside = tpIn; b.b_inside = tpIn;
b.b_plane = pNum; b.b_plane = pNum;
perimCorrect = 0; perimCorrect = 0;
/* Diagonal */
if (IsSplit(tpIn)) if (IsSplit(tpIn))
{ {
TileType otype = (SplitSide(tpIn)) ? SplitLeftType(tpIn): SplitRightType(tpIn); /* Handle a diagonal boundary across a split tile.
TileType itype = (SplitSide(tpIn)) ? SplitRightType(tpIn): SplitLeftType(tpIn); * "dinfo" determines which side of the split tile is considered "inside" the
origType = TiGetTypeExact(tpIn); * boundary and which is "outside". Invoke the callback function for the
* diagonal, then determine which two sides don't need to be searched and
* set the corresponding boundary direction bit in "sides".
*/
TileType otype = (dinfo & TT_SIDE) ? SplitLeftType(tpIn): SplitRightType(tpIn);
TileType itype = (dinfo & TT_SIDE) ? SplitRightType(tpIn): SplitLeftType(tpIn);
if (TTMaskHasType(&mask, otype)) if (TTMaskHasType(&mask, otype))
{ {
int width = RIGHT(tpIn) - LEFT(tpIn); int width = RIGHT(tpIn) - LEFT(tpIn);
@ -110,75 +116,104 @@ extEnumTilePerim(
perimCorrect = width * width + height * height; perimCorrect = width * width + height * height;
perimCorrect = (int)sqrt((double)perimCorrect); perimCorrect = (int)sqrt((double)perimCorrect);
} }
sides = (SplitSide(tpIn)) ? BD_LEFT : BD_RIGHT;
sides |= (SplitSide(tpIn) == SplitDirection(tpIn)) ? BD_BOTTOM : BD_TOP; /* Invoke the callback function on diagonal boundaries */
TiSetBody(tpIn, itype);
b.b_outside = tpIn; /* Same tile on both sides of the boundary */
TiToRect(tpIn, &b.b_segment);
if (SplitDirection(tpIn))
{
if (dinfo & TT_SIDE)
b.b_direction = BD_NE;
else
b.b_direction = BD_SW;
}
else
{
if (dinfo & TT_SIDE)
b.b_direction = BD_SE;
else
b.b_direction = BD_NW;
}
if (func) (*func)(&b, cdata);
/* Flag which two sides of the tile don't need searching */
sides = (dinfo & TT_SIDE) ? BD_LEFT : BD_RIGHT;
sides |= (((dinfo & TT_SIDE) ? 1 : 0) == SplitDirection(tpIn)) ?
BD_BOTTOM : BD_TOP;
} }
else else
sides = 0; sides = 0;
/* Top */ /* Top */
b.b_segment.r_ybot = b.b_segment.r_ytop = TOP(tpIn); if (!(sides & BD_TOP))
b.b_direction = BD_TOP;
for (tpOut = RT(tpIn); RIGHT(tpOut) > LEFT(tpIn); tpOut = BL(tpOut))
{ {
if (TTMaskHasType(&mask, TiGetBottomType(tpOut))) b.b_segment.r_ybot = b.b_segment.r_ytop = TOP(tpIn);
b.b_direction = BD_TOP;
for (tpOut = RT(tpIn); RIGHT(tpOut) > LEFT(tpIn); tpOut = BL(tpOut))
{ {
b.b_segment.r_xbot = MAX(LEFT(tpIn), LEFT(tpOut)); if (TTMaskHasType(&mask, TiGetBottomType(tpOut)))
b.b_segment.r_xtop = MIN(RIGHT(tpIn), RIGHT(tpOut)); {
b.b_outside = tpOut; b.b_segment.r_xbot = MAX(LEFT(tpIn), LEFT(tpOut));
if (sides & BD_TOP) perimCorrect -= BoundaryLength(&b); b.b_segment.r_xtop = MIN(RIGHT(tpIn), RIGHT(tpOut));
if (func) (*func)(&b, cdata); b.b_outside = tpOut;
if (func) (*func)(&b, cdata);
}
} }
} }
/* Bottom */ /* Bottom */
b.b_segment.r_ybot = b.b_segment.r_ytop = BOTTOM(tpIn); if (!(sides & BD_BOTTOM))
b.b_direction = BD_BOTTOM;
for (tpOut = LB(tpIn); LEFT(tpOut) < RIGHT(tpIn); tpOut = TR(tpOut))
{ {
if (TTMaskHasType(&mask, TiGetTopType(tpOut))) b.b_segment.r_ybot = b.b_segment.r_ytop = BOTTOM(tpIn);
b.b_direction = BD_BOTTOM;
for (tpOut = LB(tpIn); LEFT(tpOut) < RIGHT(tpIn); tpOut = TR(tpOut))
{ {
b.b_segment.r_xbot = MAX(LEFT(tpIn), LEFT(tpOut)); if (TTMaskHasType(&mask, TiGetTopType(tpOut)))
b.b_segment.r_xtop = MIN(RIGHT(tpIn), RIGHT(tpOut)); {
b.b_outside = tpOut; b.b_segment.r_xbot = MAX(LEFT(tpIn), LEFT(tpOut));
if (sides & BD_BOTTOM) perimCorrect -= BoundaryLength(&b); b.b_segment.r_xtop = MIN(RIGHT(tpIn), RIGHT(tpOut));
if (func) (*func)(&b, cdata); b.b_outside = tpOut;
if (func) (*func)(&b, cdata);
}
} }
} }
/* Left */ /* Left */
b.b_segment.r_xbot = b.b_segment.r_xtop = LEFT(tpIn); if (!(sides & BD_LEFT))
b.b_direction = BD_LEFT;
for (tpOut = BL(tpIn); BOTTOM(tpOut) < TOP(tpIn); tpOut = RT(tpOut))
{ {
if (TTMaskHasType(&mask, TiGetRightType(tpOut))) b.b_segment.r_xbot = b.b_segment.r_xtop = LEFT(tpIn);
b.b_direction = BD_LEFT;
for (tpOut = BL(tpIn); BOTTOM(tpOut) < TOP(tpIn); tpOut = RT(tpOut))
{ {
b.b_segment.r_ybot = MAX(BOTTOM(tpIn), BOTTOM(tpOut)); if (TTMaskHasType(&mask, TiGetRightType(tpOut)))
b.b_segment.r_ytop = MIN(TOP(tpIn), TOP(tpOut)); {
b.b_outside = tpOut; b.b_segment.r_ybot = MAX(BOTTOM(tpIn), BOTTOM(tpOut));
if (sides & BD_LEFT) perimCorrect -= BoundaryLength(&b); b.b_segment.r_ytop = MIN(TOP(tpIn), TOP(tpOut));
if (func) (*func)(&b, cdata); b.b_outside = tpOut;
if (func) (*func)(&b, cdata);
}
} }
} }
/* Right */ /* Right */
b.b_segment.r_xbot = b.b_segment.r_xtop = RIGHT(tpIn); if (!(sides & BD_RIGHT))
b.b_direction = BD_RIGHT;
for (tpOut = TR(tpIn); TOP(tpOut) > BOTTOM(tpIn); tpOut = LB(tpOut))
{ {
if (TTMaskHasType(&mask, TiGetLeftType(tpOut))) b.b_segment.r_xbot = b.b_segment.r_xtop = RIGHT(tpIn);
b.b_direction = BD_RIGHT;
for (tpOut = TR(tpIn); TOP(tpOut) > BOTTOM(tpIn); tpOut = LB(tpOut))
{ {
b.b_segment.r_ybot = MAX(BOTTOM(tpIn), BOTTOM(tpOut)); if (TTMaskHasType(&mask, TiGetLeftType(tpOut)))
b.b_segment.r_ytop = MIN(TOP(tpIn), TOP(tpOut)); {
b.b_outside = tpOut; b.b_segment.r_ybot = MAX(BOTTOM(tpIn), BOTTOM(tpOut));
if (sides & BD_RIGHT) perimCorrect -= BoundaryLength(&b); b.b_segment.r_ytop = MIN(TOP(tpIn), TOP(tpOut));
if (func) (*func)(&b, cdata); b.b_outside = tpOut;
if (func) (*func)(&b, cdata);
}
} }
} }
if (sides != 0)
TiSetBody(tpIn, origType);
return (perimCorrect); return (perimCorrect);
} }

View File

@ -36,6 +36,58 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "extract/extractInt.h" #include "extract/extractInt.h"
#include "utils/signals.h" #include "utils/signals.h"
/*
* ----------------------------------------------------------------------------
* ExtGetRegion ---
*
* Get the region from the ClientData of a tile. Normally this is just the
* ClientData record recast as an ExtRegion pointer. However, if the tile
* is split and neither tile side is TT_SPACE, then the Tile will be given
* an ExtSplitRegion structure, and the returned region depends on the side
* specified by "dinfo" (bit TT_SIDE).
*
* Results:
* Returns the tile's client data record cast to a region pointer.
*
* Side effects:
* None.
*
* Notes:
* This routine was previously implemented as an in-line definition
* "extGetRegion(Tile *tp)".
*
* ----------------------------------------------------------------------------
*/
ExtRegion *
ExtGetRegion(Tile *tp, /* Tile to get region record from */
TileType dinfo) /* Split tile information, if relevant */
{
ExtSplitRegion *esr;
if (IsSplit(tp))
{
if ((TiGetLeftType(tp) == TT_SPACE) || (TiGetRightType(tp) == TT_SPACE))
return (ExtRegion *)tp->ti_client;
else
{
esr = (ExtSplitRegion *)tp->ti_client;
/* If this tile has not been handled and no ExtSplitRegion has
* been created, then ti_client should be either CLIENTDEFAULT
* or VISITPENDING. It should not have any other values.
*/
if ((ClientData)esr == CLIENTDEFAULT)
return CD2PTR(CLIENTDEFAULT);
else if ((ClientData)esr == VISITPENDING)
return CD2PTR(VISITPENDING);
return (dinfo & TT_SIDE) ? esr->reg_right : esr->reg_left;
}
}
else
return (ExtRegion *)tp->ti_client;
}
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -53,6 +105,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
* ExtRegion * * ExtRegion *
* (*first)(tile, arg) * (*first)(tile, arg)
* Tile *tile; /# Tile is on plane arg->fra_pNum #/ * Tile *tile; /# Tile is on plane arg->fra_pNum #/
* TileType dinfo; /# Split tile information #/
* FindRegion *arg; * FindRegion *arg;
* { * {
* } * }
@ -62,6 +115,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
* *
* (*each)(tile, planeNum, arg) * (*each)(tile, planeNum, arg)
* Tile *tile; * Tile *tile;
* TileType dinfo; /# Split tile information #/
* int planeNum; /# May be different than arg->fra_pNum #/ * int planeNum; /# May be different than arg->fra_pNum #/
* FindRegion *arg; * FindRegion *arg;
* { * {
@ -85,7 +139,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
*/ */
ExtRegion * ExtRegion *
ExtFindRegions(def, area, mask, connectsTo, uninit, first, each) ExtFindRegions(def, area, mask, connectsTo, first, each)
CellDef *def; /* Cell definition being searched */ CellDef *def; /* Cell definition being searched */
Rect *area; /* Area to search initially for tiles */ Rect *area; /* Area to search initially for tiles */
TileTypeBitMask *mask; /* In the initial area search, only visit TileTypeBitMask *mask; /* In the initial area search, only visit
@ -101,9 +155,6 @@ ExtFindRegions(def, area, mask, connectsTo, uninit, first, each)
* so this is the same as: * so this is the same as:
* TTMaskHasType(&connectsTo[t2], t1) * TTMaskHasType(&connectsTo[t2], t1)
*/ */
ClientData uninit; /* Contents of a ti_client field indicating
* that the tile has not yet been visited.
*/
ExtRegion * (*first)(); /* Applied to first tile in region */ ExtRegion * (*first)(); /* Applied to first tile in region */
int (*each)(); /* Applied to each tile in region */ int (*each)(); /* Applied to each tile in region */
{ {
@ -113,7 +164,7 @@ ExtFindRegions(def, area, mask, connectsTo, uninit, first, each)
ASSERT(first != NULL, "ExtFindRegions"); ASSERT(first != NULL, "ExtFindRegions");
arg.fra_connectsTo = connectsTo; arg.fra_connectsTo = connectsTo;
arg.fra_def = def; arg.fra_def = def;
arg.fra_uninit = uninit; arg.fra_uninit = CLIENTDEFAULT;
arg.fra_first = first; arg.fra_first = first;
arg.fra_each = each; arg.fra_each = each;
arg.fra_region = (ExtRegion *) NULL; arg.fra_region = (ExtRegion *) NULL;
@ -124,7 +175,7 @@ ExtFindRegions(def, area, mask, connectsTo, uninit, first, each)
SigDisableInterrupts(); SigDisableInterrupts();
for (arg.fra_pNum=PL_TECHDEPBASE; arg.fra_pNum<DBNumPlanes; arg.fra_pNum++) for (arg.fra_pNum=PL_TECHDEPBASE; arg.fra_pNum<DBNumPlanes; arg.fra_pNum++)
(void) DBSrPaintClient((Tile *) NULL, def->cd_planes[arg.fra_pNum], (void) DBSrPaintClient((Tile *) NULL, def->cd_planes[arg.fra_pNum],
area, mask, uninit, extRegionAreaFunc, (ClientData) &arg); area, mask, CLIENTDEFAULT, extRegionAreaFunc, (ClientData) &arg);
SigEnableInterrupts(); SigEnableInterrupts();
return (arg.fra_region); return (arg.fra_region);
@ -155,19 +206,20 @@ ExtFindRegions(def, area, mask, connectsTo, uninit, first, each)
*/ */
int int
extRegionAreaFunc(tile, arg) extRegionAreaFunc(tile, dinfo, arg)
Tile *tile; Tile *tile;
TileType dinfo;
FindRegion *arg; FindRegion *arg;
{ {
/* Allocate a new region */ /* Allocate a new region */
if (arg->fra_first) if (arg->fra_first)
(void) (*arg->fra_first)(tile, arg); (void) (*arg->fra_first)(tile, dinfo, arg);
if (DebugIsSet(extDebugID, extDebAreaEnum)) if (DebugIsSet(extDebugID, extDebAreaEnum))
extShowTile(tile, "area enum", 0); extShowTile(tile, "area enum", 0);
/* Recursively visit all tiles surrounding this one that we connect to */ /* Recursively visit all tiles surrounding this one that we connect to */
(void) ExtFindNeighbors(tile, arg->fra_pNum, arg); (void) ExtFindNeighbors(tile, dinfo, arg->fra_pNum, arg);
return (0); return (0);
} }
@ -180,7 +232,7 @@ extRegionAreaFunc(tile, arg)
* Given a CellDef whose tiles have been set to point to LabRegions * Given a CellDef whose tiles have been set to point to LabRegions
* by ExtFindRegions, walk down the label list and assign labels * by ExtFindRegions, walk down the label list and assign labels
* to regions. If the tile over which a label lies is still uninitialized * to regions. If the tile over which a label lies is still uninitialized
* ie, points to extUnInit, we skip the label. * ie, points to CLIENTDEFAULT, we skip the label.
* *
* A label is attached to the LabRegion for a tile if the label's * A label is attached to the LabRegion for a tile if the label's
* type and the tile's type are connected according to the table * type and the tile's type are connected according to the table
@ -245,10 +297,10 @@ ExtLabelRegions(def, connTo, nodeList, clipArea)
GOTOPOINT(tp, &p); GOTOPOINT(tp, &p);
PlaneSetHint(def->cd_planes[pNum], tp); PlaneSetHint(def->cd_planes[pNum], tp);
if (extConnectsTo(TiGetType(tp), lab->lab_type, connTo) if (extConnectsTo(TiGetType(tp), lab->lab_type, connTo)
&& extHasRegion(tp, extUnInit)) && extHasRegion(tp, CLIENTDEFAULT))
{ {
found = TRUE; found = TRUE;
reg = (LabRegion *) extGetRegion(tp); reg = (LabRegion *) ExtGetRegion(tp, (TileType)0);
ll = (LabelList *) mallocMagic((unsigned) (sizeof (LabelList))); ll = (LabelList *) mallocMagic((unsigned) (sizeof (LabelList)));
ll->ll_label = lab; ll->ll_label = lab;
if (lab->lab_flags & PORT_DIR_MASK) if (lab->lab_flags & PORT_DIR_MASK)
@ -412,7 +464,7 @@ ExtLabelOneRegion(def, connTo, reg)
GOTOPOINT(tp, &p); GOTOPOINT(tp, &p);
PlaneSetHint(def->cd_planes[pNum], tp); PlaneSetHint(def->cd_planes[pNum], tp);
if (extConnectsTo(TiGetType(tp), lab->lab_type, connTo) if (extConnectsTo(TiGetType(tp), lab->lab_type, connTo)
&& (NodeRegion *) extGetRegion(tp) == reg) && (NodeRegion *) ExtGetRegion(tp, (TileType)0) == reg)
{ {
ll = (LabelList *) mallocMagic((unsigned) (sizeof (LabelList))); ll = (LabelList *) mallocMagic((unsigned) (sizeof (LabelList)));
ll->ll_label = lab; ll->ll_label = lab;
@ -444,7 +496,6 @@ ExtLabelOneRegion(def, connTo, reg)
} }
} }
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -475,7 +526,7 @@ ExtResetTiles(def, resetTo)
int pNum; int pNum;
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
DBResetTilePlane(def->cd_planes[pNum], resetTo); DBResetTilePlaneSpecial(def->cd_planes[pNum], resetTo);
} }
/* /*

View File

@ -197,6 +197,7 @@ extSubtree(parentUse, reg, f)
ha.ha_parentUse = parentUse; ha.ha_parentUse = parentUse;
ha.ha_parentReg = reg; ha.ha_parentReg = reg;
ha.ha_nodename = extSubtreeTileToNode; ha.ha_nodename = extSubtreeTileToNode;
ha.ha_interArea = GeoNullRect;
ha.ha_cumFlat.et_use = extYuseCum; ha.ha_cumFlat.et_use = extYuseCum;
HashInit(&ha.ha_connHash, 32, 0); HashInit(&ha.ha_connHash, 32, 0);
@ -250,6 +251,17 @@ extSubtree(parentUse, reg, f)
if (result == 0) { if (result == 0) {
/* If result == FALSE then ha.ha_interArea is invalid. */ /* If result == FALSE then ha.ha_interArea is invalid. */
ha.ha_interArea = rlab; 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; result = 1;
} }
else else
@ -345,8 +357,9 @@ done:
#ifdef exactinteractions #ifdef exactinteractions
int int
extSubtreeCopyPlane(tile, plane) extSubtreeCopyPlane(tile, dinfo, plane)
Tile *tile; Tile *tile;
TileType dinfo;
Plane *plane; Plane *plane;
{ {
Rect r; Rect r;
@ -358,8 +371,9 @@ extSubtreeCopyPlane(tile, plane)
} }
int int
extSubtreeShrinkPlane(tile, plane) extSubtreeShrinkPlane(tile, dinfo, plane)
Tile *tile; Tile *tile;
TileType dinfo;
Plane *plane; Plane *plane;
{ {
Rect r; Rect r;
@ -374,8 +388,9 @@ extSubtreeShrinkPlane(tile, plane)
} }
int int
extSubtreeInterFunc(tile, ha) extSubtreeInterFunc(tile, dinfo, ha)
Tile *tile; Tile *tile;
TileType dinfo;
HierExtractArg *ha; HierExtractArg *ha;
{ {
TITORECT(tile, &ha->ha_interArea); TITORECT(tile, &ha->ha_interArea);
@ -684,18 +699,22 @@ extSubtreeOutputCoupling(ha)
HashStartSearch(&hs); HashStartSearch(&hs);
while ((he = HashNext(&ha->ha_cumFlat.et_coupleHash, &hs))) while ((he = HashNext(&ha->ha_cumFlat.et_coupleHash, &hs)))
{ {
TileType dinfo;
cap = extGetCapValue(he) / ExtCurStyle->exts_capScale; cap = extGetCapValue(he) / ExtCurStyle->exts_capScale;
if (cap == 0) if (cap == 0)
continue; continue;
ck = (CoupleKey *) he->h_key.h_words; ck = (CoupleKey *) he->h_key.h_words;
tp = extNodeToTile(ck->ck_1, &ha->ha_cumFlat); tp = extNodeToTile(ck->ck_1, &ha->ha_cumFlat, &dinfo);
name = extSubtreeTileToNode(tp, ck->ck_1->nreg_pnum, &ha->ha_cumFlat, ha, TRUE); name = extSubtreeTileToNode(tp, dinfo, ck->ck_1->nreg_pnum,
&ha->ha_cumFlat, ha, TRUE);
fprintf(ha->ha_outf, "cap \"%s\" ", name); fprintf(ha->ha_outf, "cap \"%s\" ", name);
tp = extNodeToTile(ck->ck_2, &ha->ha_cumFlat); tp = extNodeToTile(ck->ck_2, &ha->ha_cumFlat, &dinfo);
name = extSubtreeTileToNode(tp, ck->ck_2->nreg_pnum, &ha->ha_cumFlat, ha, TRUE); name = extSubtreeTileToNode(tp, dinfo, ck->ck_2->nreg_pnum,
&ha->ha_cumFlat, ha, TRUE);
fprintf(ha->ha_outf, "\"%s\" %lg\n", name, cap); fprintf(ha->ha_outf, "\"%s\" %lg\n", name, cap);
} }
} }
@ -713,8 +732,9 @@ extSubtreeOutputCoupling(ha)
*/ */
int int
extFoundProc(tile, clientData) extFoundProc(tile, dinfo, clientData)
Tile *tile; Tile *tile;
TileType dinfo;
ClientData clientData; ClientData clientData;
{ {
return 1; return 1;
@ -770,6 +790,7 @@ extSubtreeFunc(scx, ha)
*/ */
ha->ha_subArea = use->cu_bbox; ha->ha_subArea = use->cu_bbox;
GEOCLIP(&ha->ha_subArea, &ha->ha_interArea); GEOCLIP(&ha->ha_subArea, &ha->ha_interArea);
hy.hy_area = &ha->ha_subArea; hy.hy_area = &ha->ha_subArea;
hy.hy_target = oneFlat->et_use; hy.hy_target = oneFlat->et_use;
hy.hy_prefix = TRUE; hy.hy_prefix = TRUE;
@ -882,7 +903,7 @@ extSubtreeFunc(scx, ha)
(NodeRegion *) ExtFindRegions(cumUse->cu_def, &TiPlaneRect, (NodeRegion *) ExtFindRegions(cumUse->cu_def, &TiPlaneRect,
&ExtCurStyle->exts_activeTypes, &ExtCurStyle->exts_activeTypes,
ExtCurStyle->exts_nodeConn, ExtCurStyle->exts_nodeConn,
extUnInit, extHierLabFirst, (int (*)()) NULL); extHierLabFirst, (int (*)()) NULL);
ExtLabelRegions(cumUse->cu_def, ExtCurStyle->exts_nodeConn, ExtLabelRegions(cumUse->cu_def, ExtCurStyle->exts_nodeConn,
&(ha->ha_cumFlat.et_nodes), &TiPlaneRect); &(ha->ha_cumFlat.et_nodes), &TiPlaneRect);
} }
@ -919,7 +940,7 @@ extSubtreeFunc(scx, ha)
/* Free the cumulative node list we extracted above */ /* Free the cumulative node list we extracted above */
if (ha->ha_cumFlat.et_nodes) if (ha->ha_cumFlat.et_nodes)
{ {
ExtResetTiles(cumUse->cu_def, extUnInit); ExtResetTiles(cumUse->cu_def, CLIENTDEFAULT);
ExtFreeLabRegions((LabRegion *) ha->ha_cumFlat.et_nodes); ExtFreeLabRegions((LabRegion *) ha->ha_cumFlat.et_nodes);
ha->ha_cumFlat.et_nodes = (NodeRegion *) NULL; ha->ha_cumFlat.et_nodes = (NodeRegion *) NULL;
} }
@ -1040,9 +1061,10 @@ extSubstrateFunc(scx, ha)
*/ */
char * char *
extSubtreeTileToNode(tp, pNum, et, ha, doHard) extSubtreeTileToNode(tp, dinfo, pNum, et, ha, doHard)
Tile *tp; /* Tile whose node name is to be found */ Tile *tp; /* Tile whose node name is to be found */
int pNum; /* Plane of the tile */ TileType dinfo; /* Split tile information */
int pNum; /* Plane of the tile */
ExtTree *et; /* Yank buffer to search */ ExtTree *et; /* Yank buffer to search */
HierExtractArg *ha; /* Extraction context */ HierExtractArg *ha; /* Extraction context */
bool doHard; /* If TRUE, we look up this node's name the hard way bool doHard; /* If TRUE, we look up this node's name the hard way
@ -1061,9 +1083,9 @@ extSubtreeTileToNode(tp, pNum, et, ha, doHard)
TileType ttype; TileType ttype;
/* If there is a label list, use it */ /* If there is a label list, use it */
if (extHasRegion(tp, extUnInit)) if (extHasRegion(tp, CLIENTDEFAULT))
{ {
reg = (LabRegion *) extGetRegion(tp); reg = (LabRegion *) ExtGetRegion(tp, dinfo);
if (reg->lreg_labels) if (reg->lreg_labels)
return (extNodeName(reg)); return (extNodeName(reg));
} }
@ -1080,12 +1102,7 @@ extSubtreeTileToNode(tp, pNum, et, ha, doHard)
* can cause problems. * can cause problems.
*/ */
if (IsSplit(tp)) if (IsSplit(tp))
{ ttype = (dinfo & TT_SIDE) ? SplitRightType(tp) : SplitLeftType(tp);
if (SplitSide(tp))
ttype = SplitRightType(tp);
else
ttype = SplitLeftType(tp);
}
else else
ttype = TiGetTypeExact(tp); ttype = TiGetTypeExact(tp);
@ -1095,7 +1112,7 @@ extSubtreeTileToNode(tp, pNum, et, ha, doHard)
{ {
if (DBSrPaintNMArea((Tile *) NULL, if (DBSrPaintNMArea((Tile *) NULL,
et->et_lookNames->cd_planes[pNum], et->et_lookNames->cd_planes[pNum],
TiGetTypeExact(tp), &r, &DBAllButSpaceBits, TiGetTypeExact(tp) | dinfo, &r, &DBAllButSpaceBits,
extConnFindFunc, (ClientData) &reg)) extConnFindFunc, (ClientData) &reg))
{ {
if (SigInterruptPending) if (SigInterruptPending)
@ -1119,8 +1136,8 @@ extSubtreeTileToNode(tp, pNum, et, ha, doHard)
/* We have to do it the hard way */ /* We have to do it the hard way */
if (!doHard) return ((char *) NULL); if (!doHard) return ((char *) NULL);
if (extHasRegion(tp, extUnInit) if (extHasRegion(tp, CLIENTDEFAULT)
&& (reg = extSubtreeHardNode(tp, pNum, et, ha))) && (reg = extSubtreeHardNode(tp, dinfo, pNum, et, ha)))
{ {
if (ExtDoWarn & EXTWARN_LABELS) if (ExtDoWarn & EXTWARN_LABELS)
{ {
@ -1154,13 +1171,14 @@ extSubtreeTileToNode(tp, pNum, et, ha, doHard)
*/ */
int int
extConnFindFunc(tp, preg) extConnFindFunc(tp, dinfo, preg)
Tile *tp; Tile *tp;
TileType dinfo; // Unused, but needs to be handled
LabRegion **preg; LabRegion **preg;
{ {
if (extHasRegion(tp, extUnInit)) if (extHasRegion(tp, CLIENTDEFAULT))
{ {
*preg = (LabRegion *) extGetRegion(tp); *preg = (LabRegion *)ExtGetRegion(tp, dinfo);
return (1); return (1);
} }
@ -1198,13 +1216,14 @@ extConnFindFunc(tp, preg)
*/ */
LabRegion * LabRegion *
extSubtreeHardNode(tp, pNum, et, ha) extSubtreeHardNode(tp, dinfo, pNum, et, ha)
Tile *tp; Tile *tp;
TileType dinfo;
int pNum; int pNum;
ExtTree *et; ExtTree *et;
HierExtractArg *ha; HierExtractArg *ha;
{ {
LabRegion *lreg = (LabRegion *) extGetRegion(tp); LabRegion *lreg = (LabRegion *) ExtGetRegion(tp, dinfo);
CellDef *def = et->et_use->cu_def; CellDef *def = et->et_use->cu_def;
TileType ttype; TileType ttype;
char labelBuf[4096]; char labelBuf[4096];
@ -1215,7 +1234,7 @@ extSubtreeHardNode(tp, pNum, et, ha)
if (IsSplit(tp)) if (IsSplit(tp))
{ {
if (SplitSide(tp)) if (dinfo & TT_SIDE)
ttype = SplitRightType(tp); ttype = SplitRightType(tp);
else else
ttype = SplitLeftType(tp); ttype = SplitLeftType(tp);

View File

@ -1368,7 +1368,7 @@ ExtTechSimplePerimCap(argc, argv)
if (ExtCurStyle->exts_planeOrderStatus != seenPlaneOrder) 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; return;
} }
@ -1376,9 +1376,14 @@ ExtTechSimplePerimCap(argc, argv)
TTMaskSetMask(allExtractTypes, &types); TTMaskSetMask(allExtractTypes, &types);
plane1 = DBTechNoisyNamePlane(argv[2]); 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(&types, &DBPlaneTypes[plane1]);
TTMaskAndMask(&nottypes, &DBPlaneTypes[plane1]);
capVal = aToCap(argv[argc - 1]); capVal = aToCap(argv[argc - 1]);
@ -1632,7 +1637,7 @@ ExtTechSimpleOverlapCap(argv)
if (ExtCurStyle->exts_planeOrderStatus != seenPlaneOrder) 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; return;
} }
@ -1732,7 +1737,7 @@ ExtTechSimpleSideOverlapCap(argv)
if (ExtCurStyle->exts_planeOrderStatus != seenPlaneOrder) 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; return;
} }
@ -1740,9 +1745,14 @@ ExtTechSimpleSideOverlapCap(argv)
TTMaskSetMask(allExtractTypes, &types); TTMaskSetMask(allExtractTypes, &types);
plane1 = DBTechNoisyNamePlane(argv[2]); 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(&types, &DBPlaneTypes[plane1]);
TTMaskAndMask(&nottypes, &DBPlaneTypes[plane1]);
DBTechNoisyNameMask(argv[3], &ov); DBTechNoisyNameMask(argv[3], &ov);
TTMaskSetMask(allExtractTypes, &ov); TTMaskSetMask(allExtractTypes, &ov);
@ -2747,24 +2757,34 @@ ExtTechLine(sectionName, argc, argv)
DBTechNoisyNameMask(argv[4], &termtypes[0]); /* bottom */ DBTechNoisyNameMask(argv[4], &termtypes[0]); /* bottom */
TTMaskSetMask(allExtractTypes, &termtypes[0]); TTMaskSetMask(allExtractTypes, &termtypes[0]);
termtypes[1] = DBZeroTypeBits; 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; 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); TTMaskSetMask(allExtractTypes, &subsTypes);
} }
else else
subsTypes = DBZeroTypeBits; subsTypes = DBZeroTypeBits;
if (argc > 7) subsName = argv[6]; if (argc > 6) subsName = argv[6];
break; break;
case DEV_SUBCKT: case DEV_SUBCKT:
@ -3350,7 +3370,22 @@ ExtTechLine(sectionName, argc, argv)
} }
else else
{ {
TxError("Resist argument must be integer or \"None\".\n"); char *decimal;
if ((decimal = strchr(argv[2], '.')) != NULL)
{
*decimal = '\0';
if (StrIsInt(argv[2]))
{
resVal = aToRes(argv[2]);
if (strcmp(decimal + 1, "0"))
TxError("Resist argument truncated to integer value.\n");
}
else
TxError("Unparseable resist argument \"%s\"\n", argv[2]);
}
else
TxError("Resist argument must be integer or \"None\".\n");
break; break;
} }
} }

View File

@ -316,8 +316,10 @@ ExtractTest(w, cmd)
} }
int int
extShowInter(tile) extShowInter(tile, dinfo, clientdata)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
ClientData clientdata; /* (unused) */
{ {
Rect r; Rect r;

View File

@ -358,8 +358,8 @@ extTimesCellFunc(cs)
/* Count the number of transistors */ /* Count the number of transistors */
transList = (TransRegion *) ExtFindRegions(def, &TiPlaneRect, transList = (TransRegion *) ExtFindRegions(def, &TiPlaneRect,
&ExtCurStyle->exts_deviceMask, ExtCurStyle->exts_deviceConn, &ExtCurStyle->exts_deviceMask, ExtCurStyle->exts_deviceConn,
extUnInit, extTransFirst, extTransEach); extTransFirst, extTransEach);
ExtResetTiles(def, extUnInit); ExtResetTiles(def, CLIENTDEFAULT);
for (tl = transList; tl; tl = tl->treg_next) for (tl = transList; tl; tl = tl->treg_next)
cs->cs_fets++; cs->cs_fets++;
ExtFreeLabRegions((LabRegion *) transList); ExtFreeLabRegions((LabRegion *) transList);
@ -396,8 +396,9 @@ extTimesCellFunc(cs)
*/ */
int int
extCountTiles(tile, cs) extCountTiles(tile, dinfo, cs)
Tile *tile; /* UNUSED */ Tile *tile; /* (unused) */
TileType dinfo; /* (unused) */
struct cellStats *cs; struct cellStats *cs;
{ {
cs->cs_rects++; cs->cs_rects++;
@ -843,7 +844,7 @@ extPaintOnly(def)
reg = extBasic(def, extDevNull); reg = extBasic(def, extDevNull);
if (reg) ExtFreeLabRegions((LabRegion *) reg); if (reg) ExtFreeLabRegions((LabRegion *) reg);
ExtResetTiles(def, extUnInit); ExtResetTiles(def, CLIENTDEFAULT);
} }
/* /*
@ -1115,8 +1116,9 @@ extInterAreaFunc(use, f)
} }
int int
extInterCountFunc(tile, pArea) extInterCountFunc(tile, dinfo, pArea)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
int *pArea; int *pArea;
{ {
Rect r; Rect r;

View File

@ -61,6 +61,11 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
* names that don't end in '!'. * names that don't end in '!'.
* If option is EXT_UNIQ_NOPORTS, then generate unique names as for * If option is EXT_UNIQ_NOPORTS, then generate unique names as for
* option 0 only if the label is not a port. * 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: * Results:
* Returns the number of warnings generated. * Returns the number of warnings generated.
@ -109,7 +114,7 @@ extUniqueCell(def, option)
lregList = (LabRegion *) ExtFindRegions(def, &TiPlaneRect, lregList = (LabRegion *) ExtFindRegions(def, &TiPlaneRect,
&ExtCurStyle->exts_activeTypes, &ExtCurStyle->exts_activeTypes,
ExtCurStyle->exts_nodeConn, ExtCurStyle->exts_nodeConn,
extUnInit, extHierLabFirst, (int (*)()) NULL); extHierLabFirst, (int (*)()) NULL);
/* Assign the labels to their associated regions */ /* Assign the labels to their associated regions */
ExtLabelRegions(def, ExtCurStyle->exts_nodeConn, &lregList, &TiPlaneRect); ExtLabelRegions(def, ExtCurStyle->exts_nodeConn, &lregList, &TiPlaneRect);
@ -187,7 +192,7 @@ extUniqueCell(def, option)
HashKill(&labelHash); HashKill(&labelHash);
ExtFreeLabRegions((LabRegion *) lregList); ExtFreeLabRegions((LabRegion *) lregList);
if (nodeList) freeMagic(nodeList); if (nodeList) freeMagic(nodeList);
ExtResetTiles(def, extUnInit); ExtResetTiles(def, CLIENTDEFAULT);
if (nwarn) if (nwarn)
TxError("%s: %d warnings\n", def->cd_name, nwarn); TxError("%s: %d warnings\n", def->cd_name, nwarn);
return (nwarn); return (nwarn);
@ -219,7 +224,7 @@ extMakeUnique(def, ll, lreg, lregList, labelHash, option)
* changes a label to make it unique. * changes a label to make it unique.
*/ */
text = ll->ll_label->lab_text; text = ll->ll_label->lab_text;
if (option == EXT_UNIQ_ALL) if (option == EXT_UNIQ_ALL || option == EXT_UNIQ_TEMP)
goto makeUnique; goto makeUnique;
else if ((option == EXT_UNIQ_NOPORTS || option == EXT_UNIQ_NOTOPPORTS) else if ((option == EXT_UNIQ_NOPORTS || option == EXT_UNIQ_NOTOPPORTS)
&& !(ll->ll_label->lab_flags & PORT_DIR_MASK)) && !(ll->ll_label->lab_flags & PORT_DIR_MASK))
@ -320,8 +325,11 @@ makeUnique:
lab = ll2->ll_label; lab = ll2->ll_label;
saveLab = *lab; saveLab = *lab;
/* Flag this label as having been modified */
if (option == EXT_UNIQ_TEMP) flags |= LABEL_UNIQUE;
DBRemoveLabel(def, lab); 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_font, saveLab.lab_size, saveLab.lab_rotate,
&saveLab.lab_offset, saveLab.lab_just, name2, &saveLab.lab_offset, saveLab.lab_just, name2,
saveLab.lab_type, flags, (unsigned int)portno); saveLab.lab_type, flags, (unsigned int)portno);
@ -334,3 +342,64 @@ makeUnique:
return 0; 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_DOADJUST 0x001 /* Extract hierarchical adjustments */
#define EXT_DOCAPACITANCE 0x002 /* Extract capacitance */ #define EXT_DOCAPACITANCE 0x002 /* Extract capacitance */
#define EXT_DOCOUPLING 0x004 /* Extract coupling 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_DOLENGTH 0x010 /* Extract pathlengths */
#define EXT_DOFRINGEHALO 0x020 /* Distributed fringe capacitance */ #define EXT_DOFRINGEHALO 0x020 /* Distributed fringe capacitance */
#define EXT_DOALL 0x03f /* ALL OF THE ABOVE */ #define EXT_DOALL 0x03f /* ALL OF THE ABOVE */
#define EXT_DOLABELCHECK 0x040 /* Check for connections by label */ #define EXT_DOLABELCHECK 0x040 /* Check for connections by label */
#define EXT_DOALIASES 0x080 /* Output all node aliases */ #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 int ExtOptions; /* Bitmask of above */
extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */ 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_TAGGED 1
#define EXT_UNIQ_NOPORTS 2 #define EXT_UNIQ_NOPORTS 2
#define EXT_UNIQ_NOTOPPORTS 3 #define EXT_UNIQ_NOTOPPORTS 3
#define EXT_UNIQ_TEMP 4 /* Used only with "EXT_DOUNIQUE" */
extern bool ExtTechLine(); extern bool ExtTechLine();
extern void ExtTechInit(); extern void ExtTechInit();
@ -108,8 +111,10 @@ extern void ExtGetZAxis();
extern void ExtDumpCaps(); extern void ExtDumpCaps();
extern int extEnumTilePerim(Tile *tpIn, const TileTypeBitMask *maskp, int pNum, int (*func)(), ClientData cdata); extern int extEnumTilePerim(Tile *tpIn, TileType dinfo, const TileTypeBitMask *maskp, int pNum, int (*func)(), ClientData cdata);
extern Plane *extPrepSubstrate(); extern Plane *extPrepSubstrate();
extern FILE *ExtFileOpen(CellDef *def, char *file, char *mode, char **prealfile);
/* C99 compat */ /* C99 compat */
extern void ExtAll(); extern void ExtAll();

View File

@ -154,6 +154,19 @@ typedef struct reg
struct reg *reg_next; /* Next region in list */ struct reg *reg_next; /* Next region in list */
} ExtRegion; } ExtRegion;
/*
* Special structure for split tiles which have something other than
* TT_SPACE on both sides and require two regions to represent both
* nets connected to the tile.
*/
typedef struct split_reg
{
ExtRegion *reg_guard; // Use this to guard against failure to
// identify a split region (temporary).
ExtRegion *reg_left; // Region belonging to tile left side
ExtRegion *reg_right; // Region belonging to tile right side
} ExtSplitRegion;
/* /*
* GENERIC region with labels. * GENERIC region with labels.
* Any other structure that wants to reference node names * Any other structure that wants to reference node names
@ -196,6 +209,7 @@ typedef struct nreg
* in X, then in Y. * in X, then in Y.
*/ */
LabelList *nreg_labels; /* See LabRegion for description */ LabelList *nreg_labels; /* See LabRegion for description */
ClientData nreg_subnet; /* Subnet record generated by extresist */
CapValue nreg_cap; /* Capacitance to ground */ CapValue nreg_cap; /* Capacitance to ground */
ResValue nreg_resist; /* Resistance estimate */ ResValue nreg_resist; /* Resistance estimate */
PerimArea nreg_pa[1]; /* Dummy; each node actually has PerimArea nreg_pa[1]; /* Dummy; each node actually has
@ -212,16 +226,18 @@ typedef struct treg
{ {
struct treg *treg_next; /* Next region in list */ struct treg *treg_next; /* Next region in list */
int treg_pnum; /* UNUSED */ int treg_pnum; /* UNUSED */
int treg_type; /* Type of tile that contains treg_ll */ int treg_type; /* UNUSED */
Point treg_ll; /* UNUSED */ Point treg_ll; /* UNUSED */
LabelList *treg_labels; /* Attribute list */ LabelList *treg_labels; /* Attribute list */
Tile *treg_tile; /* Some tile in the channel */ Tile *treg_tile; /* Some tile in the channel */
TileType treg_dinfo; /* Diagonal information for treg_tile* */
int treg_area; /* Area of channel */ int treg_area; /* Area of channel */
} TransRegion; } TransRegion;
typedef struct { /* Maintain plane information when pushing */ typedef struct { /* Maintain plane information when pushing */
Rect area; /* tiles on the node stack. For use with */ Rect area; /* tiles on the node stack. For use with */
int plane; /* function extNbrPushFunc(). */ int plane; /* function extNbrPushFunc(). */
ClientData uninit; /* Value of an unvisited region */
} PlaneAndArea; } PlaneAndArea;
/* Structure to be kept in a hash table of node regions for the current */ /* Structure to be kept in a hash table of node regions for the current */
@ -253,7 +269,7 @@ typedef struct
CellDef *fra_def; /* Def being searched */ CellDef *fra_def; /* Def being searched */
int fra_pNum; /* Plane currently searching */ int fra_pNum; /* Plane currently searching */
ClientData fra_uninit; /* This value appears in the ti_client ClientData fra_uninit; /* This value appears in the ti_client
* field of a tile if it's not yet * field of a tile if it has not yet
* been visited. * been visited.
*/ */
ExtRegion *(*fra_first)(); /* Function to init new region */ ExtRegion *(*fra_first)(); /* Function to init new region */
@ -281,16 +297,27 @@ typedef struct
int b_plane; /* extract argument for extSideOverlap */ int b_plane; /* extract argument for extSideOverlap */
} Boundary; } Boundary;
/* Define Manhattan boundary length */
#define BoundaryLength(bp) \ #define BoundaryLength(bp) \
((bp)->b_segment.r_xtop - (bp)->b_segment.r_xbot \ ((bp)->b_segment.r_xtop - (bp)->b_segment.r_xbot \
+ (bp)->b_segment.r_ytop - (bp)->b_segment.r_ybot) + (bp)->b_segment.r_ytop - (bp)->b_segment.r_ybot)
/* Directions in which we can be following the boundary of a perimeter */ /* Directions in which we can be following the boundary of a perimeter */
#define BD_LEFT 1 /* Inside is to right */ #define BD_LEFT 0x01 /* Inside is to right */
#define BD_TOP 2 /* Inside is below */ #define BD_TOP 0x02 /* Inside is below */
#define BD_RIGHT 4 /* Inside is to left */ #define BD_RIGHT 0x04 /* Inside is to left */
#define BD_BOTTOM 8 /* Inside is above */ #define BD_BOTTOM 0x08 /* Inside is above */
/* Non-manhattan boundary directions. Inside is in the
* direction indicated (e.g., BD_NW, inside is top left)
*/
#define BD_NW 0x10 /* TT_SIDE = 0 TT_DIR = 0 */
#define BD_SW 0x20 /* TT_SIDE = 0 TT_DIR = 1 */
#define BD_SE 0x40 /* TT_SIDE = 1 TT_DIR = 0 */
#define BD_NE 0x80 /* TT_SIDE = 1 TT_DIR = 1 */
/* -------- Yank buffers for hierarchical and array extraction -------- */ /* -------- Yank buffers for hierarchical and array extraction -------- */
@ -342,6 +369,7 @@ typedef struct extTree
* char * * char *
* proc(tp, et, ha) * proc(tp, et, ha)
* Tile *tp; * Tile *tp;
* TileType dinfo;
* ExtTree *et; * ExtTree *et;
* HierExtractArg *ha; * HierExtractArg *ha;
* { * {
@ -372,7 +400,7 @@ typedef struct
*/ */
Tile *hierOneTile; /* Used in ExtHier.c, tile from extHierOneFlat */ Tile *hierOneTile; /* Used in ExtHier.c, tile from extHierOneFlat */
int hierPNum; /* Used in ExtHier.c, plane of tile above */ int hierPNum; /* Used in ExtHier.c, plane of tile above */
TileType hierType; /* Used in ExtHier.c, type of tile above */ TileType hierType; /* Used in ExtHier.c, type of tile above, incl. TT_SIDE */
int hierPNumBelow; /* Used in ExtHier.c, plane of tile below */ int hierPNumBelow; /* Used in ExtHier.c, plane of tile below */
} HierExtractArg; } HierExtractArg;
@ -934,12 +962,6 @@ extern ExtStyle *ExtCurStyle;
/* ------------------- Hierarchical node merging ---------------------- */ /* ------------------- Hierarchical node merging ---------------------- */
/*
* Table used to hold all merged nodes during hierarchical extraction.
* Used for duplicate suppression.
*/
extern HashTable extHierMergeTable;
/* /*
* Each hash entry in the above table points to a NodeName struct. * Each hash entry in the above table points to a NodeName struct.
* Each NodeName points to the Node corresponding to that name. * Each NodeName points to the Node corresponding to that name.
@ -968,17 +990,10 @@ typedef struct node
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* extern ExtRegion *ExtGetRegion(Tile *tile, TileType dinfo);
* Value normally resident in the ti_client field of a tile,
* indicating that the tile has not yet been visited in a
* region search.
*/
extern ClientData extUnInit;
#define extGetRegion(tp) ( (tp)->ti_client )
#define extHasRegion(tp,und) ( (tp)->ti_client != (und) ) #define extHasRegion(tp,und) ( (tp)->ti_client != (und) )
/* For non-recursive flooding algorithm */ /* For non-recursive flooding algorithm */
#define VISITPENDING ((ClientData) NULL) /* Marks tiles on stack */ #define VISITPENDING ((ClientData) NULL) /* Marks tiles on stack */
@ -989,44 +1004,47 @@ extern ClientData extUnInit;
/* because the search algorithm can overwrite it between the */ /* because the search algorithm can overwrite it between the */
/* time the tile is pushed and the time that it is popped. */ /* time the tile is pushed and the time that it is popped. */
#define PUSHTILE(tp, pl) \ #define PUSHTILE(tp, di, pl) \
(tp)->ti_client = VISITPENDING; \ ExtSetRegion(tp, di, (ExtRegion *)VISITPENDING); \
STACKPUSH((ClientData)(pointertype)(pl | \ STACKPUSH((ClientData)(pointertype)pl, extNodeStack); \
((TileType)(spointertype)(tp)->ti_body & TT_SIDE)), extNodeStack); \ STACKPUSH((ClientData)(pointertype)di, extNodeStack); \
STACKPUSH((ClientData)(pointertype)tp, extNodeStack) STACKPUSH((ClientData)(pointertype)tp, extNodeStack)
#define POPTILE(tp, pl) \ #define POPTILE(tp, di, pl) \
tp = (Tile *) STACKPOP(extNodeStack); \ tp = (Tile *) STACKPOP(extNodeStack); \
pl = (spointertype) STACKPOP(extNodeStack); \ di = (spointertype) STACKPOP(extNodeStack); \
if (pl & TT_SIDE) { \ pl = (spointertype) STACKPOP(extNodeStack)
TiSetBody((tp), TiGetTypeExact(tp) | TT_SIDE); \
pl &= (~TT_SIDE); \
} \
else \
TiSetBody((tp), TiGetTypeExact(tp) & (~TT_SIDE))
/* Variations of "pushtile" to force a specific value on TT_SIDE */ /* Variations of "pushtile" to force a specific value on TT_SIDE */
#define PUSHTILEBOTTOM(tp, pl) \ #define PUSHTILEBOTTOM(tp, pl) \
(tp)->ti_client = VISITPENDING; \ { \
STACKPUSH((ClientData)(pointertype)(pl | \ TileType di = (SplitDirection(tp)) ? 0 : TT_SIDE; \
((SplitDirection(tp)) ? 0 : TT_SIDE)), extNodeStack) ;\ ExtSetRegion(tp, di, (ExtRegion *)VISITPENDING); \
STACKPUSH((ClientData)(pointertype)tp, extNodeStack) STACKPUSH((ClientData)(pointertype)pl, extNodeStack); \
STACKPUSH((ClientData)(pointertype)di, extNodeStack); \
STACKPUSH((ClientData)(pointertype)tp, extNodeStack); \
}
#define PUSHTILETOP(tp, pl) \ #define PUSHTILETOP(tp, pl) \
(tp)->ti_client = VISITPENDING; \ { \
STACKPUSH((ClientData)(pointertype)(pl | \ TileType di = (SplitDirection(tp)) ? TT_SIDE : 0; \
((SplitDirection(tp)) ? TT_SIDE : 0)), extNodeStack) ;\ ExtSetRegion(tp, di, (ExtRegion *)VISITPENDING); \
STACKPUSH((ClientData)(pointertype)tp, extNodeStack) STACKPUSH((ClientData)(pointertype)pl, extNodeStack); \
STACKPUSH((ClientData)(pointertype)di, extNodeStack); \
STACKPUSH((ClientData)(pointertype)tp, extNodeStack); \
}
#define PUSHTILELEFT(tp, pl) \ #define PUSHTILELEFT(tp, pl) \
(tp)->ti_client = VISITPENDING; \ ExtSetRegion(tp, (TileType)0, (ExtRegion *)VISITPENDING); \
STACKPUSH((ClientData)(pointertype)(pl), extNodeStack); \ STACKPUSH((ClientData)(pointertype)(pl), extNodeStack); \
STACKPUSH((ClientData)(pointertype)0, extNodeStack); \
STACKPUSH((ClientData)(pointertype)tp, extNodeStack) STACKPUSH((ClientData)(pointertype)tp, extNodeStack)
#define PUSHTILERIGHT(tp, pl) \ #define PUSHTILERIGHT(tp, pl) \
(tp)->ti_client = VISITPENDING; \ ExtSetRegion(tp, (TileType)TT_SIDE, (ExtRegion *)VISITPENDING); \
STACKPUSH((ClientData)(pointertype)(pl | TT_SIDE), extNodeStack); \ STACKPUSH((ClientData)(pointertype)pl, extNodeStack); \
STACKPUSH((ClientData)(pointertype)TT_SIDE, extNodeStack); \
STACKPUSH((ClientData)(pointertype)tp, extNodeStack) STACKPUSH((ClientData)(pointertype)tp, extNodeStack)
/* ------------------------- Region finding --------------------------- */ /* ------------------------- Region finding --------------------------- */
@ -1056,11 +1074,12 @@ extern Tile *extNodeToTile();
#define NODETONODE(nold, et, nnew) \ #define NODETONODE(nold, et, nnew) \
if (1) { \ if (1) { \
Tile *tp; \ Tile *tp; \
TileType di; \
\ \
(nnew) = (NodeRegion *) NULL; \ (nnew) = (NodeRegion *) NULL; \
tp = extNodeToTile((nold), (et)); \ tp = extNodeToTile((nold), (et), (TileType *)&di); \
if (tp && extHasRegion(tp, extUnInit)) \ if (tp && extHasRegion(tp, CLIENTDEFAULT)) \
(nnew) = (NodeRegion *) extGetRegion(tp); \ (nnew) = (NodeRegion *) ExtGetRegion(tp, di); \
} }
/* -------------------- Miscellaneous procedures ---------------------- */ /* -------------------- Miscellaneous procedures ---------------------- */
@ -1072,6 +1091,7 @@ extern ExtTree *extHierNewOne();
extern int extNbrPushFunc(); extern int extNbrPushFunc();
extern TileType extGetDevType(); extern TileType extGetDevType();
extern void extMakeNodeNumPrint(); extern void extMakeNodeNumPrint();
extern void ExtSetRegion();
/* --------------------- Miscellaneous globals ------------------------ */ /* --------------------- Miscellaneous globals ------------------------ */
@ -1104,6 +1124,11 @@ extern Plane *extCellFile();
extern int extInterAreaFunc(); extern int extInterAreaFunc();
extern int extTreeSrPaintArea(); extern int extTreeSrPaintArea();
extern int extMakeUnique(); 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 ------------------- */ /* ------------------ Connectivity table management ------------------- */

File diff suppressed because it is too large Load Diff

View File

@ -482,8 +482,9 @@ gaPropagateBlockages(list)
*/ */
int int
gaSetClient(tile, cdata) gaSetClient(tile, dinfo, cdata)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
ClientData cdata; ClientData cdata;
{ {
tile->ti_client = (ClientData) cdata; tile->ti_client = (ClientData) cdata;
@ -511,8 +512,9 @@ gaSetClient(tile, cdata)
*/ */
int int
gaSplitTile(tile, r) gaSplitTile(tile, dinfo, r)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
Rect *r; Rect *r;
{ {
Tile *tp; Tile *tp;
@ -632,7 +634,7 @@ gaInitRiverBlockages(routeUse, ch)
} }
int int
gaAlwaysOne() gaAlwaysOne(Tile *tile, TileType dinfo, ClientData clientdata)
{ {
return (1); return (1);
} }

View File

@ -572,8 +572,9 @@ gaIsClear(use, r, mask)
*/ */
int int
gaIsClearFunc(tile, cxp) gaIsClearFunc(tile, dinfo, cxp)
Tile *tile; Tile *tile;
TileType dinfo;
TreeContext *cxp; TreeContext *cxp;
{ {
return 1; return 1;

View File

@ -322,6 +322,7 @@ overlap:
} }
/* /*
* ----------------------------------------------------------------------------
* gaStemContainingChannelFunc -- * gaStemContainingChannelFunc --
* *
* Called via DBSrPaintArea on behalf of gaStemContainingChannel above * Called via DBSrPaintArea on behalf of gaStemContainingChannel above
@ -341,8 +342,9 @@ overlap:
*/ */
int int
gaStemContainingChannelFunc(tile, pCh) gaStemContainingChannelFunc(tile, dinfo, pCh)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
GCRChannel **pCh; GCRChannel **pCh;
{ {
GCRChannel *ch; GCRChannel *ch;

View File

@ -254,8 +254,9 @@ GAGenChans(chanType, area, f)
*/ */
int int
gaSplitOut(tile, f) gaSplitOut(tile, dinfo, f)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
FILE *f; FILE *f;
{ {
Rect r; Rect r;

View File

@ -231,9 +231,10 @@ w3dFillDiagonal(x1, y1, x2, y2, ztop, zbot)
} }
void void
w3dFillOps(trans, tile, cliprect, ztop, zbot) w3dFillOps(trans, tile, dinfo, cliprect, ztop, zbot)
Transform *trans; Transform *trans;
Tile *tile; Tile *tile;
TileType dinfo;
Rect *cliprect; Rect *cliprect;
float ztop; float ztop;
float zbot; float zbot;
@ -254,15 +255,15 @@ w3dFillOps(trans, tile, cliprect, ztop, zbot)
if (IsSplit(tile)) if (IsSplit(tile))
{ {
Rect fullr; Rect fullr;
TileType dinfo; TileType newdinfo;
dinfo = DBTransformDiagonal(TiGetTypeExact(tile), trans); newdinfo = DBTransformDiagonal(TiGetTypeExact(tile) | dinfo, trans);
fullr = r; fullr = r;
if (cliprect != NULL) if (cliprect != NULL)
GeoClip(&r, cliprect); GeoClip(&r, cliprect);
GrClipTriangle(&fullr, &r, cliprect != NULL, dinfo, p, &np); GrClipTriangle(&fullr, &r, cliprect != NULL, newdinfo, p, &np);
if (np > 0) if (np > 0)
{ {
@ -289,7 +290,7 @@ w3dFillOps(trans, tile, cliprect, ztop, zbot)
/* Find tile outline and render sides */ /* Find tile outline and render sides */
if (GrBoxOutline(tile, &tilesegs)) if (GrBoxOutline(tile, dinfo, &tilesegs))
{ {
xbot = (float)r.r_xbot; xbot = (float)r.r_xbot;
ybot = (float)r.r_ybot; ybot = (float)r.r_ybot;
@ -380,8 +381,9 @@ w3dFillOps(trans, tile, cliprect, ztop, zbot)
} }
void void
w3dRenderVolume(tile, trans, cliprect) w3dRenderVolume(tile, dinfo, trans, cliprect)
Tile *tile; Tile *tile;
TileType dinfo;
Transform *trans; Transform *trans;
Rect *cliprect; Rect *cliprect;
{ {
@ -403,7 +405,7 @@ w3dRenderVolume(tile, trans, cliprect)
if ((grCurFill == GR_STSOLID) || (grCurFill == GR_STSTIPPLE)) if ((grCurFill == GR_STSOLID) || (grCurFill == GR_STSTIPPLE))
{ {
w3dFillOps(trans, tile, cliprect, ztop, zbot); w3dFillOps(trans, tile, dinfo, cliprect, ztop, zbot);
} }
/* To do: Outlines and contact crosses */ /* To do: Outlines and contact crosses */
@ -411,8 +413,9 @@ w3dRenderVolume(tile, trans, cliprect)
} }
void void
w3dRenderCIF(tile, layer, trans) w3dRenderCIF(tile, dinfo, layer, trans)
Tile *tile; Tile *tile;
TileType dinfo;
CIFLayer *layer; CIFLayer *layer;
Transform *trans; Transform *trans;
{ {
@ -435,7 +438,7 @@ w3dRenderCIF(tile, layer, trans)
if ((grCurFill == GR_STSOLID) || (grCurFill == GR_STSTIPPLE)) if ((grCurFill == GR_STSOLID) || (grCurFill == GR_STSTIPPLE))
{ {
w3dFillOps(trans, tile, NULL, ztop, zbot); w3dFillOps(trans, tile, dinfo, NULL, ztop, zbot);
} }
/* To do: Outlines */ /* To do: Outlines */
@ -543,8 +546,9 @@ w3dSetProjection(w)
/* Magic layer tile painting function */ /* Magic layer tile painting function */
int int
w3dPaintFunc(tile, cxp) w3dPaintFunc(tile, dinfo, cxp)
Tile *tile; /* Tile to be displayed */ Tile *tile; /* Tile to be displayed */
TileType dinfo; /* Split tile information */
TreeContext *cxp; /* From DBTreeSrTiles */ TreeContext *cxp; /* From DBTreeSrTiles */
{ {
SearchContext *scx = cxp->tc_scx; SearchContext *scx = cxp->tc_scx;
@ -582,15 +586,16 @@ w3dPaintFunc(tile, cxp)
w3dNeedStyle = FALSE; w3dNeedStyle = FALSE;
} }
w3dRenderVolume(tile, &scx->scx_trans, &scx->scx_area); w3dRenderVolume(tile, dinfo, &scx->scx_trans, &scx->scx_area);
return 0; /* keep the search going! */ return 0; /* keep the search going! */
} }
/* CIF layer tile painting function */ /* CIF layer tile painting function */
int int
w3dCIFPaintFunc(tile, arg) w3dCIFPaintFunc(tile, dinfo, arg)
Tile *tile; /* Tile to be displayed */ Tile *tile; /* Tile to be displayed */
TileType dinfo; /* Split tile information */
ClientData *arg; /* is NULL */ ClientData *arg; /* is NULL */
{ {
CIFLayer *layer = (CIFLayer *)arg; CIFLayer *layer = (CIFLayer *)arg;
@ -626,7 +631,7 @@ w3dCIFPaintFunc(tile, arg)
w3dNeedStyle = FALSE; w3dNeedStyle = FALSE;
} }
w3dRenderCIF(tile, layer, &GeoIdentityTransform); w3dRenderCIF(tile, dinfo, layer, &GeoIdentityTransform);
return 0; /* keep the search going! */ return 0; /* keep the search going! */
} }
@ -689,15 +694,22 @@ w3dCutBox(w, cmd)
{ {
if (crec->clipped) 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_Obj *rlist = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, rlist, Tcl_ListObjAppendElement(magicinterp, rlist,
Tcl_NewIntObj((int)(crec->cutbox.r_xbot))); Tcl_NewStringObj(cllx, -1));
Tcl_ListObjAppendElement(magicinterp, rlist, Tcl_ListObjAppendElement(magicinterp, rlist,
Tcl_NewIntObj((int)(crec->cutbox.r_ybot))); Tcl_NewStringObj(clly, -1));
Tcl_ListObjAppendElement(magicinterp, rlist, Tcl_ListObjAppendElement(magicinterp, rlist,
Tcl_NewIntObj((int)(crec->cutbox.r_xtop))); Tcl_NewStringObj(curx, -1));
Tcl_ListObjAppendElement(magicinterp, rlist, Tcl_ListObjAppendElement(magicinterp, rlist,
Tcl_NewIntObj((int)(crec->cutbox.r_ytop))); Tcl_NewStringObj(cury, -1));
Tcl_SetObjResult(magicinterp, rlist); Tcl_SetObjResult(magicinterp, rlist);
} }

View File

@ -571,8 +571,9 @@ grAddSegment(llx, lly, urx, ury, segments)
*/ */
bool bool
GrBoxOutline(tile, tilesegs) GrBoxOutline(tile, dinfo, tilesegs)
Tile *tile; Tile *tile;
TileType dinfo;
LinkedRect **tilesegs; LinkedRect **tilesegs;
{ {
Rect rect; Rect rect;
@ -586,7 +587,7 @@ GrBoxOutline(tile, tilesegs)
*tilesegs = NULL; *tilesegs = NULL;
TiToRect(tile, &rect); TiToRect(tile, &rect);
if (IsSplit(tile) && SplitSide(tile)) if (IsSplit(tile) && (dinfo & TT_SIDE))
isolate |= 0x1; isolate |= 0x1;
else else
{ {
@ -620,7 +621,7 @@ GrBoxOutline(tile, tilesegs)
} }
} }
} }
if (IsSplit(tile) && !SplitSide(tile)) if (IsSplit(tile) && !(dinfo & TT_SIDE))
isolate |= 0x2; isolate |= 0x2;
else else
{ {
@ -656,7 +657,7 @@ GrBoxOutline(tile, tilesegs)
} }
if (IsSplit(tile) && if (IsSplit(tile) &&
(SplitSide(tile) == SplitDirection(tile))) (((dinfo & TT_SIDE) ? 1 : 0) == SplitDirection(tile)))
isolate |= 0x4; isolate |= 0x4;
else else
{ {
@ -692,7 +693,7 @@ GrBoxOutline(tile, tilesegs)
} }
if (IsSplit(tile) && if (IsSplit(tile) &&
(SplitSide(tile) != SplitDirection(tile))) (((dinfo & TT_SIDE) ? 1 : 0) != SplitDirection(tile)))
isolate |= 0x8; isolate |= 0x8;
else else
{ {
@ -773,7 +774,7 @@ GrBoxOutline(tile, tilesegs)
*--------------------------------------------------------- *---------------------------------------------------------
*/ */
void void
GrBox(MagWindow *mw, Transform *trans, Tile *tile) GrBox(MagWindow *mw, Transform *trans, Tile *tile, TileType dinfo)
{ {
Rect r, r2, clipr; Rect r, r2, clipr;
bool needClip, needObscure, simpleBox; bool needClip, needObscure, simpleBox;
@ -813,16 +814,16 @@ GrBox(MagWindow *mw, Transform *trans, Tile *tile)
if (IsSplit(tile)) if (IsSplit(tile))
{ {
/* Perform matrix transformations on split tiles */ /* Perform matrix transformations on split tiles */
TileType dinfo; TileType newdinfo;
Rect fullr; Rect fullr;
dinfo = DBTransformDiagonal(TiGetTypeExact(tile), trans); newdinfo = DBTransformDiagonal(TiGetTypeExact(tile) | dinfo, trans);
clipr = fullr = r; clipr = fullr = r;
if (needClip) if (needClip)
GeoClip(&clipr, &grCurClip); GeoClip(&clipr, &grCurClip);
GrClipTriangle(&fullr, &clipr, needClip, dinfo, polyp, &np); GrClipTriangle(&fullr, &clipr, needClip, newdinfo, polyp, &np);
if ((grCurFill == GR_STSOLID) || if ((grCurFill == GR_STSOLID) ||
(grCurFill == GR_STSTIPPLE) || (grCurFill == GR_STGRID) ) (grCurFill == GR_STSTIPPLE) || (grCurFill == GR_STGRID) )
@ -891,7 +892,7 @@ GrBox(MagWindow *mw, Transform *trans, Tile *tile)
if (grCurOutline != 0) if (grCurOutline != 0)
{ {
if (GrBoxOutline(tile, &tilesegs)) if (GrBoxOutline(tile, dinfo, &tilesegs))
{ {
/* simple box (from GrFastBox)*/ /* simple box (from GrFastBox)*/

View File

@ -235,8 +235,10 @@ glChanBuildMap(chanList)
*/ */
int int
glChanFeedFunc(tile) glChanFeedFunc(tile, dinfo, clientdata)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
ClientData clientdata; /* (unused) */
{ {
char *mesg; char *mesg;
Rect r; Rect r;
@ -342,8 +344,9 @@ glChanCheckCover(chanList, mask)
*/ */
int int
glChanCheckFunc(tile, ch) glChanCheckFunc(tile, dinfo, ch)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
GCRChannel *ch; GCRChannel *ch;
{ {
char mesg[1024]; char mesg[1024];
@ -454,8 +457,10 @@ glChanShowTiles(mesg)
} }
int int
glChanShowFunc(tile) glChanShowFunc(tile, dinfo, clientdata)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
ClientData clientdata; /* (unused) */
{ {
GCRChannel *ch; GCRChannel *ch;
char mesg[1024]; char mesg[1024];
@ -498,8 +503,9 @@ glChanShowFunc(tile)
*/ */
int int
glChanClipFunc(tile, area) glChanClipFunc(tile, dinfo, area)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
Rect *area; Rect *area;
{ {
ClientData tileClient = tile->ti_client; ClientData tileClient = tile->ti_client;
@ -567,8 +573,10 @@ glChanClipFunc(tile, area)
*/ */
int int
glChanMergeFunc(tile) glChanMergeFunc(tile, dinfo, clientdata)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
ClientData clientdata; /* (unused) */
{ {
GCRChannel *ch = (GCRChannel *) tile->ti_client; GCRChannel *ch = (GCRChannel *) tile->ti_client;
Tile *delayed = NULL; /* delayed free to extend lifetime */ Tile *delayed = NULL; /* delayed free to extend lifetime */
@ -774,8 +782,9 @@ glChanBlockDens(ch)
} }
int int
glChanPaintFunc(tile, type) glChanPaintFunc(tile, dinfo, type)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
TileType type; TileType type;
{ {
static TileType changeTable[4][4] = { static TileType changeTable[4][4] = {
@ -869,8 +878,9 @@ glChanFlood(area, type)
} }
int int
glChanFloodVFunc(tile, area) glChanFloodVFunc(tile, dinfo, area)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
Rect *area; Rect *area;
{ {
PaintArea *pa; PaintArea *pa;
@ -888,8 +898,9 @@ glChanFloodVFunc(tile, area)
} }
int int
glChanFloodHFunc(tile, area) glChanFloodHFunc(tile, dinfo, area)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
Rect *area; Rect *area;
{ {
PaintArea *pa; PaintArea *pa;
@ -928,8 +939,10 @@ glChanFloodHFunc(tile, area)
*/ */
int int
glChanSplitRiver(tile) glChanSplitRiver(tile, dinfo, clientdata)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
ClientData clientdata; /* (unused) */
{ {
ClientData tileClient = tile->ti_client; ClientData tileClient = tile->ti_client;
Tile *tp, *newTile; Tile *tp, *newTile;
@ -1009,8 +1022,10 @@ glChanSplitRiver(tile)
*/ */
int int
glChanRiverBlock(tile) glChanRiverBlock(tile, dinfo, clientdata)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
ClientData clientdata; /* (unused) */
{ {
GCRPin *pin, *pinLast; GCRPin *pin, *pinLast;
GCRChannel *ch; GCRChannel *ch;

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