Compare commits

...

215 Commits

Author SHA1 Message Date
R. Timothy Edwards d157eea7f3 Fixed an error that was discovered with the drcCanonicalMaxwidth()
routine, which in turn affects various DRC rules like maxrect,
widespacing, and runlength spacing.  drcTile() was computing
the drcCanonicalMaxwidth() result for the tile and reusing it,
failing to account for the fact that within the loop over
DRCCookies, other rules might require calling drcCanonicalMaxwidth()
on a neighboring tile, or on the same tile with a different width
requirement.  Implemented a cached version, in which three results
are kept:  One for neighboring tiles (which can never be reused on
the same edge), one for the first required use of the routine for
the tile, and one for any other use required for the tile.  If
there are one or two such rules for an edge, then the routine will
work at maximum efficiency.  If there are three rules, then one
will always be a cache hit and reduce the total amount of
computation, although it will still be doing a massive amount of
redundant computation.  If this seems to be something that
occurs regularly, then it can be revisited.  The existing
implementation works fine for all the open PDKs.  Some more
advanced PDKs with a number of staged wide-spacing rules could
have issues.
2026-04-14 17:37:10 -04:00
R. Timothy Edwards 67c6ed9395 Corrected the handling of toolkit callbacks created by the
"magic::add_dependency" procedure.  The "check" function should always
be called first, followed by the dependencies.  Because otherwise, if
an incorrect value is entered for a device parameter, then it gets
used to calculate dependent values *before* it gets corrected by the
"check" procedure, resulting in an incorrect value being displayed
for the dependent value, even after the bad entry has been corrected.
2026-04-13 15:29:51 -04:00
R. Timothy Edwards f15f0dabbb Added HTML documentation for the "macro" command, after finding that
the exiting documentation does not include the handful of options
available to the macro command, nor does it explain the relationship
between tools and macro sets.
2026-04-13 13:01:54 -04:00
R. Timothy Edwards ae6d26578e Fixed issues with the "macro" command that have existed since the
"tool" command was changed to be overridden by a Tcl command.  Due
to macro clients being registered with the tool name instead of
just "layout", the "macro" command with no arguments or with a
window client argument was just broken.  In the process of fixing
this, I realized that there was a conflict between the use of
"netlist" as a window name and also as the name of a tool, so I
changed the tool name to "nettool", a change which should be
transparent to the end user.  Otherwise, "macro netlist" returns
the key bindings for the window, and the only way to get the key
bindings for the tool is to make the tool active and then use
"macro" without arguments.  One remaining issue is that there is
no syntax error that will cause the list of valid windows and
tools to be printed.  Probably "macro help" should print usage
information instead of acting like "macro" with no arguments.
2026-04-13 12:26:42 -04:00
R. Timothy Edwards cb1653b157 Found that I needed to apply the same correction as the last
commit to the "tagged" GDS/CIF operator, or else this will have
exactly the same issue as "bloat-all".
2026-04-10 13:39:17 -04:00
R. Timothy Edwards a3f5e665d1 Found an extremely bad error, where the "bloat-all" GDS output
operator does a second search to reset tiles and clear the
"processed" mark.  This second search was only searching on the
types being bloated *into* and not the original types being
bloated.  This caused tiles to remain marked as "processed" which
could in turn cause the tiles to be ignored forever after, potentially
resulting in bad GDS output.
2026-04-09 11:13:30 -04:00
R. Timothy Edwards 2eea849c06 Corrected a crash condition in R-C extraction (extresist) caused
by old code that still references devices like FETs assuming
four ports.  I resolved the crash condition but have not worked
on fixing the code to properly handle a variable number of
terminals per device.
2026-04-07 21:15:56 -04:00
R. Timothy Edwards 6e295d030e Also updated the HTML command reference for the "expand" and
"unexpand" commands to include the options just implemented.
2026-04-04 21:03:06 -04:00
R. Timothy Edwards ceba050a21 Fixed the mess that is the "expand"/"unexpand" command set. This
had numerous problems, the main one being that each of the three
commands was inconsistent:  "expand toggle" inverts the expansion
of the selection and syncs with the layout.  But "expand" expands
the layout where instances overlap the box and does not sync to
the selection, and "unexpand" unexpands the layout where the box
completely surrounds instances.  Added a set of options to
"expand" and "unexpand" so that these functions can be made
consistent with each other.  All varieties of the function now
always sync the selection and the layout.
2026-04-04 20:47:04 -04:00
R. Timothy Edwards f7cceed5e3 Made a fairly major overhaul to the toolkit for generated devices.
The main changes are:
(1) Changed the hash function used to generate the 6-character
    suffix for generated device cell names.  The original hash
    function is not good for ensuring unique names, and can
    cause cell name collisions (two different parameter sets
    having the same cell name).  The chance of name collisions
    should now be diminishingly small.
(2) Modified the string passed to the hash:
    (A) Ordered the parameter names alphabetically, since iterating
        through dictionary keys is not guaranteed to be in any
        specific order, leading to different strings for the same
	parameter set
    (B) Normalized numerical parameters, so that "2", "2.0", "2e0"
	are all hashed the same, again to avoid having multiple
	cell names for the same set of parameters.
(3) Fixed a problem in which when changing parameters for a cell
    instance, the instance would become unselected and the instance
    name would be lost and revert to magic's auto-generated name.
(4) Fixed the annoyance of having a pop-up dialog whenever magic
    decides that a parameterized cell name is not being used anywhere,
    and it can safely delete the cell.
(5) Fixed an issue where the check for whether a cell can be deleted
    is not run consistently.
The result is, I hope, a much more pleasant experience with generated
cells.
2026-04-02 17:13:17 -04:00
R. Timothy Edwards 5d35ae38b5 Corrected an issue causing MASKHINTS values to fail to be written
back to the file, instead resulting in a property key only and no
value;  this in turn produces an error when read back in.  Another
cycle of reading and writing causes the property to disappear
altogether.

Also:  Corrected another related error that claims to have truncated
the mask hints when in fact everything was working normally.
2026-04-02 14:45:08 -04:00
R. Timothy Edwards 05561b90f3 Solved three issues:
(1) There was still one place that dimensional units were not being
    printed, which was "setlabel", with both "setlabel size" and
    "setlabel offset".  This has been fixed.
(2) Fixing (1) surfaced an error in the text helper dialog, which was
    not setting units properly when checking the size and offset entries.
(3) Fixed a very long-standing problem in which port labels were showing
    up with the "pale" style of a subcell's label being drawn on top
    when the parent and child had the same label in exactly the same
    position.  This was due to a parent-first search resulting in the
    child cell being visited last, so its "pale" style label being drawn
    last.  Added a flag for label searches for display to reverse the
    search order, visiting children first and then the parent, so that
    the top cell's labels are the last to be drawn.
2026-04-01 21:17:54 -04:00
R. Timothy Edwards 06eab7feb6 Removed three lines of code that were meant to be a test of how
much performance can be sped up if the DRC process can be
interrupted at much finer intervals.  Unfortunately, the method
cannot work without an additional method to ensure that magic is
immediately aware when a search routine has been entered
recursively and to then break out of the search and clean up
after itself.  For now, I am just commenting out the code so that
magic isn't unstable.
2026-03-26 19:44:00 -04:00
R. Timothy Edwards 9ade4c931e Updated the version to go along with the merge of two pull
requests from Darryl Miles.  The second of these should finally
put to rest all the compile-time issues related to "termio/termios"
(yay).
2026-03-26 09:23:58 -04:00
Darryl L. Miles 1bb5316d8d utils/magsgtty.h removal and fixup 2026-03-26 09:21:18 -04:00
Darryl L. Miles 2f26237b8b GHA: main.yml/main-aarch64.yml: WASM build
-DEMSCRIPTEN=1 appears to not be present any more by default in emcc compiler.

There is -D__EMSCRIPTEN__=1 but that would require modifying many locations
in the codebase which are already being reviewed separately under a single
source multi-platform build cleanup process.

Anyhow maybe ./configure would set -DEMSCRIPTEN=1 itself, much like -Dlinux=1
for other targets.  This commits defers evaluation on that until later and just
restores how it worked before.
2026-03-26 09:20:07 -04:00
Darryl L. Miles 003506ba62 CmdLQ.c: fix MAGIC_WRAPPER code section(s) for WASM build 2026-03-26 09:20:07 -04:00
Darryl L. Miles d659b5e1df textio.h: add include <stdarg.h> due to va_list type use in file 2026-03-26 09:20:07 -04:00
Darryl L. Miles a0afe242c8 extract/ExtNghbors.c: fix older compiler support for label
ExtNghbors.c:615:1: error: label at end of compound statement

since: 846c8e0f6 (2026-01-15 8.3.591)

This fixes AppImage 7/8/9 which use older compiler versions.
2026-03-26 09:20:07 -04:00
Darryl L. Miles 88ca77f6a4 GHA: main.yml: remove vezzal task
This task is failing due to invalid gmail email address or email outbound
MTA credentials via gmail, maybe the ${{secrets.MAILING_KEY}} is invalidated ?

While the docker image at vezzal/vezzal:v1 was last updated over 3y ago,
with vezzal/vezzal:v2 was last updated over 4y ago.

The project references a github upstream project that appears to be deleted
along with the entire user account associated with it.

https://hub.docker.com/r/vezzal/vezzal
https://github.com/lankasaicharan/vezzal

Because this does not appear to exist this now becomes a security concern
as the docker contents can not be audited as to what it does and it runs in the
context of the main project GHA CI that produces redistributable artifacts.

If this is be reinstated maybe it should be done as .github/workflows/vezzal.yml
so an independant workflow outside of the main.yml CI workflow that is used to
quickly cross check compilation state of the project.
2026-03-26 09:20:07 -04:00
Darryl L. Miles 9d967bdf64 GHA: canary-matrix.yml: apt-get update 2026-03-26 09:20:07 -04:00
R. Timothy Edwards 7fd2ef8100 I admit I was juggling with too many balls in the air yesterday
and managed to commit some code that I thought I had tested---
but apparently what I tested was not the latest version of the
code.  So 8.3.627 is quite broken and won't even compile.  This
update fixes that.
2026-03-25 14:07:54 -04:00
R. Timothy Edwards e789f18523 Yet another pass at the problem caused by implementing DRC
exceptions;  avoided the use of "signed char" altogether by just
making the drcc_exception value a bit mask with the lower 7 bits
being the index and the upper bit being the flag for exception (0)
vs. exemption (1), with the value 0xff being reserved for "none"
(no exception or exemption).  This implementation should avoid any
issues caused by ambiguity in the use of signed vs. unsigned char.
2026-03-24 09:37:50 -04:00
R. Timothy Edwards 460a357730 Corrected what appears to be a long-standing error in the GDS read
routine, in which it calls the same "cleanup" routine as for CIF
files, which in turn processes the top level cell.  However, GDS
doesn't have the same concept of a top level cell, so it ends up
re-processing part of the last cell read.  This would appear to be
harmless, except that there is some kind of scaling discrepancy
in which the cell bounding box can get incorrectly scaled by the
cleanup routine.  The solution appears to be simply (?) to not do
the "top level" processing.  Bypassing the CIFPaintCurrent() from
the cleanup routine when reading a GDS file appears to solve the
problem.
2026-03-22 13:11:27 -04:00
R. Timothy Edwards 7ceeccef56 Corrected an issue found by Harald Pretl and solved by Claude.
Use of "char" does *not* implicitly mean "signed" on ARM
architectures.
2026-03-22 11:14:19 -04:00
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
R. Timothy Edwards f998f8ee6f Corrected an error that has been known for a while but which had
not previously been tracked down.  Behavior was that GDS additions
to correct hierarchical interactions would miss areas, especially
on large chip designs.  This was found to be caused by a nested
use of DBSrCellPlaneArea();  the inner use was changing the outer
use's search area and causing it to exit early.  Corrected by
removing the nested use of the subroutines.  Also, created a
proper client data structure to pass information to and from the
subroutine, eliminating the ugly global variables that had been
used for that purpose.
2025-12-30 12:15:15 -05:00
R. Timothy Edwards 662e21a2d1 Corrected an error that had been introduced when creating the
parameter types "l1", "l2", etc., for terminal lengths.  There
was a string comparison against an unterminated character array
which was causing intermittant errors.  This problem was masking
the incorrect handling of "l1", "l2", etc., parameters.  The
parameter types had been introduced to cover a specific type of
drain-unsalicided FET in GF180MCU, which is used as an ESD
device in the foundry I/O cells, so the impact had been
relatively limited, although typically showed up as unexpected
property errors on the ESD devices when running LVS on a chip
top level.  Both discovered errors have been fixed.
2025-12-29 10:52:08 -05:00
R. Timothy Edwards 949ec7672c Reworked the code from the previous commit in a completely different
way.  The code as previously written was undermining other code
written to avoid long run-times on ext2spice, and didn't solve at
least one issue with unnecessary resistor shorts being added to the
netlist output.  The current solution fixes one underlying problem
where a wrongly-placed parenthesis caused the "preferred net name"
routine EFHNBest() not to be run, which prevented original node
names from being preferred over their suffixed versions created by
"extract unique".  However, I also added code to EFbuild.c to
merge unique nodes when the nodes are not really unique.  The
problem is caused by "extract unique" operating only on one level
of hierarchy and being unable to see where nets may connect through
subcircuits.  That can be determined from the "merge" statements
in the .ext file, and now the EFbuild routines will merge these
"false unique" names back into the original net.
2025-12-24 16:00:08 -05:00
R. Timothy Edwards bd417aa54b Updating the version number to go along with the merge of pull
request #478 from Mitch Bailey.  Also edited the code from the
PR for programming style.
2025-12-24 11:31:43 -05:00
Mitch Bailey 73e08e0c88 Prefer original ports over duplicate ports in extracted spice netlist.
Prioritize lowest port number when merging nodes.

Signed-off-by: Mitch Bailey <d.mitch.bailey@gmail.com>
2025-12-24 11:19:16 -05:00
R. Timothy Edwards 893a36cae7 Updated the version to go along with the merge of pull requests
475, 476, and 477 (first ones for mac OS and arch Linux support
on github;  the last to modify recent code changes to work with
the last code merge for eliminating the one-off freeMagic().
2025-12-22 09:57:56 -05:00
Darryl L. Miles 3b4d66e7d7 freeMagic1() additions
These additional uses of freeMagic() also require defer-by-one using stack
storage (not global storage idiom, recently introduced).
Not sure if they were missed original or new/modified code in the past
12 months.  Some areas/line-of-code are not usually compiled, maybe that
is why they were originally missed.
2025-12-22 09:57:42 -05:00
Darryl L. Miles 5e8a3f038a CalmaWrite: fix: introduced memory leak, missed free
Appears the 'listtop' is a sentinal/entryexit value to a circular list
My recent patch does not copy original behaviour in freeing this list
entry (as well as the reset of the list).
2025-12-22 09:57:42 -05:00
Darryl L. Miles 9850c5586e GHA: main-aarch64.yml: insert apt-get update 2025-12-22 09:57:29 -05:00
Darryl L. Miles 27df5f9c5f GHA: Migrate macos-13 => macos-15-intel 2025-12-22 09:57:04 -05:00
Darryl L. Miles e9202c1d29 malloc: remove #pragma weak as MacOS does not like
Originally the use of a weak symbol was to provide a fallback for
non-inline supporting compilers.  However all compilers (we care about)
support inline keyword (which was not known at the original time of the
work).  Furthermore GCC have already worked through the solution and make
it easy to implement.

The use of __GNUC_STDC_INLINE__ pattern in this way manages the fallback
and emits a hard symbol this can be tested with:

CFLAGS="-g" ./configure; make; nm */lib*.o | grep freeMagic1

CFLAGS="-O3" ./configure; make; nm */lib*.o | grep freeMagic1

A hard 'T' symbol is emitted (to provide fallback) with all builds, but
in the -O3 all usage is inlined.  So an individual file can decide to
inline or not at the occasion (compile time options) allows.
2025-12-19 09:31:58 -05:00
Darryl L. Miles ea1a89b19c EFbuild.c: efConnectionFreeLinkedList() remove delay-by-one assumption
freeMagic1 series 2nd order find
2025-12-19 09:31:58 -05:00
Darryl L. Miles 9489b23985 freeMagic1() idiom insertion at all sites reported by static code analysis 2025-12-19 09:31:58 -05:00
Darryl L. Miles c74215ad55 scripts/defs.mak.in: FEATURE_FLAGS -DSUPPORT_DIRECT_MALLOC -DSUPPORT_REMOVE_MALLOC_LEGACY
./configure
 # If you are brave, enable with your favourite editor after ./configure
 sed -e 's/^#FEATURE_FLAGS /FEATURE_FLAGS /' -i defs.mak
 make
 make install
2025-12-19 09:31:58 -05:00
Darryl L. Miles 4201f56048 callocMagic has same API argument convention as calloc() 2025-12-19 09:31:58 -05:00
Darryl L. Miles 26372f5d50 gtTkCommon.c: SUPPORT_DIRECT_MALLOC around function pointer use of legacy malloc
Just in case I also modify the allocation to ensure it was also performed
via exactly the same method.
2025-12-19 09:31:58 -05:00
Darryl L. Miles ef419258ab SUPPORT_DIRECT_MALLOC and SUPPORT_REMOVE_MALLOC_LEGACY
This supports three build modes:

No additional -D options, default legacy mode

-DSUPPORT_DIRECT_MALLOC, magic will use direct calls to libc malloc/free
 and will leave in place the symbols now renamed as mallocMagicLegacy()
 freeMagicLegacy() and callocMagicLegacy().

-DSUPPORT_DIRECT_MALLOC -DSUPPORT_REMOVE_MALLOC_LEGACY as above but will
 remove the three legacy functions from the binary to provide assurance
 they can not be used.

The system malloc is thread-safe the legacy magic malloc has a global
deferred free pointer and the mmap() allocate has a free-list that is
not thread-safe making use of free not thread-safe.
This could of course be improved with the use of
atomic_compare_and_exchange operations but for what gain ?

Then there is the additional function call overhead (of the indirection)
and a few tests/branches inserted into a commonly used code paths around
memory allocation, it hides the call site of the malloc/free usage from
the compiler which maybe have special optimization cases.

The existing malloc/free makes static code analysis around memory
allocation more problematic, also use of runtime analysers will operate
better with a fail-fast to bad memory usage.
2025-12-19 09:31:58 -05:00
R. Timothy Edwards 97134848ab A few minor changes to message reporting, plus some additional
support for compressed formats, specifically when given on the
command line (which is handled in a Tcl script, not in the C
code).
2025-12-19 09:30:35 -05:00
R. Timothy Edwards 00c692b140 Added better support for compressed .mag files. While magic doesn't
generate compressed .mag files itself, it is often very useful to
compress a massive layout file to save disk space or to hit a github
size target.  The code change looks for files with either ".mag" (default)
or ".mag.gz" extensions.  No check is made to see if both files might
exist at the same time and have incompatible content;  it is up to the
end user to manage the file compression.
2025-12-11 09:55:28 -05:00
R. Timothy Edwards 203ece1a16 Fixed the "interacting" GDS output operator (which includes
"noninteracting", "overlapping", and "nonoverlapping") which
were incorrectly ignoring tiles outside the search area.
Otherwise they will miss areas that pass outside of the the
search area and return back inside somewhere else.
2025-12-01 15:16:14 -05:00
R. Timothy Edwards 22a230edc9 Found a mistake in the original edit for time stamps from two
commits back, and fixed it.  Also found that the version was
changed between today's first two commits, which it should not
have been, so dialed it back.
2025-11-29 15:49:17 -05:00
R. Timothy Edwards 7f1217596e Missed one additional place in the last commit where timestamps
need to be predecated on the read/write status of cells.
2025-11-29 15:01:21 -05:00
R. Timothy Edwards ff718c3ecf Got rid of one problem with timestamps, which was the requirement
to force an update on a child cell to match the timestamp of the
parent.  This is no longer done on read-only cells, although it
probably ought to be applied to all cells.  A timestamp should
change when a cell has been modified, but a parent cell should never
force a child cell to update its timestamp if the child cell has
not been modified.  The main problem is that "drc check" runs checks
on all child cells, and they then are marked as modified without
consideration of whether the child's DRC status changed.  A better
solution would be to avoid unnecessary updates by detecting a
change in DRC results, but for now, just disabling updates on
read-only cells (which can't be updated anyway) should suffice.
2025-11-29 13:24:23 -05:00
R. Timothy Edwards 98aa2f760a Corrected an error from a recent commit: An attempt to add array
checks when checking for exactly overlapping instances of the same
cell def was faulty and resulted in magic no longer detecting when
unarrayed instances exactly overlap.  Now both conditions (arrayed
and not arrayed) should be handled correctly.
2025-11-25 12:57:46 -05:00
R. Timothy Edwards 441d933148 Updated version to go along with the merge of pull request #473
from Sylvain Munaut.
2025-11-23 17:06:56 -05:00
Sylvain Munaut 9d3fb61cf3 defRead: Accept usename longer than 511 char
The previous code always read in a defined size buffer and any
name longer gets cut which causes issue during extraction because
any collision on the truncated name causes components to get "lost".

So here instead we keep a local stack buffer of 512 byte and use it
if possible, but for longer string we allocate some space on the heap
temporarily.

Some later error processing had to be refactored a bit to make sure
we can always clean-up after ourselves once we're done with the
buffer.

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2025-11-23 20:14:21 +01:00
R. Timothy Edwards a1fb779314 Added a LEF section to nmos.tech, provided by Dave in fossi-chat.org. 2025-11-19 17:49:43 -05:00
R. Timothy Edwards abd3975997 Corrected the (very old) "nmos.tech" file, which had GDS layer
assignments for output but not for input.  Also, one layer was
given two different GDS numbers for GDS output, which was
incorrect.
2025-11-19 17:42:40 -05:00
R. Timothy Edwards 227f264838 Fixed the error that causes problems with the tile allocation.
The error was in selStretchEraseFunc2() which was calling
DBErase().  But DBErase() can call DBSrPaintArea() and thereby
start another search of the same plane while the plane is
already in a search.  This is absolutely invalid.  However, it
is simple just to use selStretchEraseFunc2() to collect a mask
of the types that need to be erased and pass that back to the
caller, and apply DBErase() to each type in the mask, outside
of the DBSrPaintArea() search.  With this fix, the tile
allocation is no longer causing problems, and the code to add
tiles deallocated by TiJoinX and TiJoinY to the free tile list
has been uncommented again.
2025-11-09 12:52:03 -05:00
R. Timothy Edwards c87e5baff4 Rolling back part of the last commit; the correction to the tile
allocation fixes the issue with memory being grabbed constantly
and never released, but re-surfaces an error with tiles being
used after being freed.  This is assumed to be a long-standing
bug that has not been found yet.  Meanwhile, the error that uses
up excess memory is better than the error that causes layouts to
get completely screwed up.
2025-11-08 17:24:09 -05:00
R. Timothy Edwards 957d7edd64 A number of things in one commit:
1) Added a "*showmem" "wizard" command to get a dump of all memory
   being used by tiles in the database.
2) Made a slight correction to the way magic detects exact overlap
   of instances of the same cell.  This probably does not make any
   actual difference in practice.
3) Corrected an uninitialized variable in dbReComputeBboxFunc().
4) Changes DBSrCellPlaneArea() to use a static BPEnum variable, so
   that it does not waste time allocating and freeing memory for
   the same thing over and over again.
5) Corrected a memory leak in the tech file "extract" section that
   loses memory every time the extraction style is changed.
6) Corrected the tile join routines to fix a bad memory leak in the
   tile allocation and recovery---a fix which was mentioned in issue
   #414 but which had not yet been implemented.  This has now been
   tested and confirmed to work.
2025-11-07 11:00:22 -05:00
R. Timothy Edwards 969137d1e2 Corrected an unfortunate error from the previous commit due to
missing copying one line with a conditional.  The error results
in "bloat-all" DRC checks reporting false positive errors.  This
commit fixes that error.
2025-11-03 15:06:54 -05:00
R. Timothy Edwards f3adea8c65 Made a few corrections to recent code additions. Also added
more points to accept interrupts during DRC checks, and
modified the tech file parser to allow the full syntax for
magic layers that is allowed elsewhere (e.g., "(*ndiff,poly)/a")
(this applies to magic layers, not GDS layers).  Fixed a
clipping error in the bloat-all function which was causing
non-manhattan geometry to produce bad results, which would
cause false-positive DRC errors when used in a CIF-DRC rule.
2025-10-31 17:37:02 -04:00
R. Timothy Edwards 246c0ea7a4 Extended the "maxwidth" DRC rule to take an optional set of layers
that exclude the maxwidth rule from taking effect.  This is
especially useful for implementing a maxwidth rule on top metal
that does not apply to pads, using the passivation cut layer to
prevent the maxwidth rule from being applied.
2025-10-30 16:39:54 -04:00
R. Timothy Edwards 47778971ee And one more fix to the method, for which I added a variation of
DBNMSrPaintPlane() where if "tile" is non-NULL then "plane" can be
NULL;  the hint tile does not get set but the routine can be called
without knowing the plane other than that the tile is in it somewhere.
2025-10-30 13:18:12 -04:00
R. Timothy Edwards cccd79ab0d One correction to the last commit---The additional check is not
limited to the DRC_REVERSE case but must be done in both the
forward and reverse cases.
2025-10-30 12:37:00 -04:00
R. Timothy Edwards 51b9846120 Made a correction to the DRC error checking on a non-Manhattan
edge.  This was catching geometry unrelated to the error when doing
a spacing check between geometry on different planes.  In the
reverse-edge case, magic needed to run an additional search over
the area on the other side of the original edge that triggered
the rule to effectively clip that corner of the triangle from the
search area.
2025-10-30 12:07:29 -04:00
R. Timothy Edwards 1afd48e840 Corrected an error in which an invalid client name passed to the
"macro" command will crash magic.  This will happen if, for
example, magic is compiled without OpenGL support, in which case
the "wind3d" client does not exist, and parsing the default
macros from the system .magicrc file will cause an immediate
crash.
2025-10-29 09:32:03 -04:00
R. Timothy Edwards 99a5a28a3e Added a drc check to the gencell change procedure, as it appears
that otherwise DRC is not re-checked after a gencell update.  It
is not clear to me why checks are not done otherwise.
2025-10-28 15:10:03 -04:00
R. Timothy Edwards 0ac4d3a465 Found a way to work around the problem of having subcell DRC
errors show up as "See error definition in subcell", which has
been the case since I modified the code to prevent showing DRC
errors in subcells that have been resolved by the hierarchy
above them.  DRC errors are now intelligently searched
downward in the heirarchy when enumerated for "drc why".
Also changed the DRC check tile definition to offset such that
there is a tile centered on the origin, instead of the origin
being between four tiles.  Since most layouts are subcells and
most subcells are small relative to the DRC check tile area,
and most subcells are placed near the origin, then most subcells
will appear in only one tile, which speeds up the DRC process
somewhat.
2025-10-23 17:11:44 -04:00
R. Timothy Edwards 42aa06f8f5 Corrected what seems to be a long-standing error in which
DRCCheckThis() is called in order of top to bottom of the hierarchy
when called from drcCheckFunc() although it was changed to order
DRCPendingRoot from bottom to top.  drcCheckFunc() then does it
backwards.  Fixing this appears to have resolved some weird errors
with DRC errors not showing up when doing "drc check" (initially)
and DRC errors disappearing when making changes to a generated
cell.  Appears to be okay now.
2025-10-22 17:27:00 -04:00
R. Timothy Edwards 4d2912a406 Corrected the return value of spcWriteValue() (recently added)
from "bool" to "void" (does not return a value).
2025-10-21 09:15:05 -04:00
R. Timothy Edwards b668b02a1f Corrected a problem in which "cellname delete" never cleared the
cell name from the cell name hash table.  So when "cellname rename"
was changed recently to prevent changing the name of a cell that
already exists, the suggested recipe for R-C extraction no longer
works:  "load x; flatten y; load y; cellname delete x; cellname
rename y x".  Solved by adding a HashRemove() function to the
cell deletion routine.  Thanks to Egor Lukyachenko for reporting
the issue (Github issue tracker #467).
2025-10-20 11:03:03 -04:00
R. Timothy Edwards 6b8f5d1d67 Modified the toolkit behavior so that a default callback to update
the dialog (and run limit checks) is installed by default on
checkboxes and selection menus, as it is already done for entry
boxes.  Otherwise it is possible to make a selection (like changing
a device type) that invalidates the existing values, but if Apply
is hit immediately afterward, then no checks will be run and the
values may be used as-is even if invalid.  This does not prohibit
the use of "add_dependency" to change the callback behavior.
2025-10-16 17:08:15 -04:00
R. Timothy Edwards c977e4cf76 Corrected an error introduced yesterday by a hasty fix, which
ended up breaking the "extresist" function by failing to parse
the comment line of a .sim file.  This is now fixed.
2025-10-15 10:00:02 -04:00
R. Timothy Edwards 9327e319da Corrected ext2sim to handle the new "dsubcircuit" device type,
added in a recent commit.  The extension was handled by
"ext2spice" but "ext2sim" was missed.  Without it, "extresist"
will fail for any circuit containing a device defined in the
tech file extract section with "dsubcircuit".
2025-10-15 08:31:58 -04:00
R. Timothy Edwards 0e84616af8 Corrected an error that allows a cell to be renamed with the name
of an existing cell, which does not appear to be a fatal problem,
but must be causing a memory leak.  Also:  Corrected an error in
extresist when reading .sim files, in code that is slated to be
overhauled, so this is just a patch to avoid a crash condition.
2025-10-14 10:36:07 -04:00
R. Timothy Edwards c42db8e71b Modified the key input redirection so that it captures and
handles Control-u in the same way that tkcon does, so that when
typing via redirection into the console, Control-u will delete
the entire command back to the prompt. (See github issue #456.)
2025-10-10 10:39:40 -04:00
R. Timothy Edwards 27c423c2ed Substantially revised the "macro" command callback functions and
the "tool" implementation.  Previously, the "tool" implementation
would overwrite the button bindings for the mouse.  The problem
with that is that if the user customizes one or more of the
bindings, such as using the mouse wheel for zooming instead of
panning, then the custom macro gets obliterated when the tool
changes.  The reimplementation creates multiple macro sets which
are unique to each tool.  The "enable_tools" function sets up
the initial unique default bindings for each tool.  The user
can then customize the bindings for any tool, and the
implementation no longer requires the constant changing of key
bindings.  Note that the new implementation is slightly less
efficient because the macro tables are found by string hash
based on the name of the tool or client type, not the integer
client ID.  The reduction in efficiency is balanced by the
increased flexibility of the macros.
2025-10-09 15:43:54 -04:00
Darryl L. Miles 53e7dfe04c ext2spice.c: ifdef for !MAGIC_WRAPPER build 2025-10-08 20:56:41 -04:00
R. Timothy Edwards 9ca81f8ea6 Modified the "tag" command to add an optional subcommand "add" or
"replace" as the 2nd argument.  This allows a simpler 'tag add
<command> <value>' than the existing awkward 'tag <command>
"[tag <command>]; <value>'.  Using "add" also helps avoid
mistakes like one that was in the code for a long time which
overwrites one of the helper window callbacks.  With this done,
added some additional callbacks to the "library manager" to
update when a new file is created by "select save" or "writeall".
Also added "Refresh" buttons to these windows, just in case.
Implemented a zoom function on the mouse scroll wheel when the
Control key is pressed.  This is a stop-gap for a problem with
overriding button bindings that re-establish themselves when the
tool (box, wiring, etc.) changes.  That needs to have a more
comprehensive solution (such as tool-specific bindings).
2025-10-08 17:11:27 -04:00
R. Timothy Edwards d822353e85 One additional fix, since the previous fix needed to be made in
both ext2spice.c AND ext2hier.c.
2025-10-08 10:08:29 -04:00
R. Timothy Edwards 4951f013d5 Corrected the output of the new "dsubcircuit" device which was
generating output for one of the device nodes twice in the
netlist.
2025-10-08 10:04:38 -04:00
R. Timothy Edwards d3a0228958 Added a new device type "dsubcircuit" which basically behaves like
"csubcircuit" but swaps the first two pins (with the device
identifier layer becoming the 2nd pin and the other terminal the
first), which is needed for n-type diodes modeled as subcircuits
where the subcircuit pin order matches the order of pins for a
SPICE n-type diode component.  Previously "msubcircuit" was used
for this purpose, but will calculate the wrong L and W.  While
use of L and W for diodes is rare, this device type also works for
reversed capacitors (where the bottom or non-identifying layer
terminal is in the first pin position of the subcircuit).
2025-10-07 16:45:22 -04:00
R. Timothy Edwards 656d27b17a Added a new "devresist" type "terminal" to account for resistor
terminal resistance, for cases where the resistor value is
estimated and output along with (or instead of) the physical
length and width or area and perimeter.  Corrected the "area"
and "perimeter" type handling so that they combine in parallel,
not in series (note that "perimeter" resistance is just an area
resistance with the depth of the material factored in).
2025-10-07 12:12:33 -04:00
R. Timothy Edwards 3631892cfa One more minor change to the behavior just implemented: A value
for a resistor or capacitor is optional but is valid SPICE and not
just limited to CDL format, so it is now allowed to add "r=" at
the end of a resistor or capacitor component (not subcircuit) to
generate the optional component value.
2025-10-06 20:37:30 -04:00
R. Timothy Edwards 8c323803b7 Additional modification to write out a resistor or capacitor value
as-is, without a parameter name and before any device model name or
substrate pin, according to CDL syntax, if the parameter has been
specified without a parameter name (e.g., "r=" instead of "r=r").
Corrected an error in the extract code which put the substrate node
name in front of parameters instead of after.  This was previously
unexercised because only in CDL format does a resistor or capacitor
model have parameters listed by name.
2025-10-06 17:42:34 -04:00
R. Timothy Edwards acdfb256a1 Made a change to CDL format output to place the substrate parameter
in front of the device name, which is a very inconsistent way to
make the syntax, but whatever.
2025-10-06 16:40:19 -04:00
R. Timothy Edwards 5e74ecf9fa Added code to avoid a segfault if a resistor or capacitor is
specified without a list of substrate connection types, but
the "s=" parameter is used, resulting in an attempt to access a
substrate node that does not exist.
2025-10-06 14:14:05 -04:00
R. Timothy Edwards d6d8620a7c Added new statements "connect" and "disconnect" to the extract
section of the tech file, which can be used to alter the layer
connectivity tables from the default.  This can be used, for
example, to disconnect substrate and well from taps, to
generate a netlist that checks for soft-connect errors.
2025-10-06 11:50:38 -04:00
R. Timothy Edwards a2390167e6 Updated the version to go along with the merge of pull request #455
from Darryl Miles.
2025-10-04 20:50:51 -04:00
Darryl L. Miles 3cfc24f4b9 AppImage: AppRun use #!/usr/bin/env bash
There are Linux systems without bash installed at /bin/sh or it is
in a non-standard location.
2025-10-04 20:50:31 -04:00
Darryl L. Miles 7e12bec49d txInput.c: comment #endif markers 2025-10-04 20:50:31 -04:00
Darryl L. Miles 5f1f92f30d GHA: update canary-matrix.yml
Removes ubuntu-20.04 config (no longer available on GitHub CI)
added clang-19 and gcc-13
removed no_gc_gu, as all 'gl' (GL) options require 'gu' (GLU)
added build for --enable-readline-bundled
added X11+Cairo
2025-10-04 20:50:31 -04:00
Darryl L. Miles 15faa19346 configure: autoconf regen (2.69) --enable-readline-bundled GR_SRCS 2025-10-04 20:50:31 -04:00
Darryl L. Miles af7b6bf119 graphics: minor change to Makefile and configure
This splits and groups DEPSRCS better so errors are not seen trying to
include files that are not present with no intention to build that
source file.
2025-10-04 20:50:31 -04:00
Darryl L. Miles 8b0616eaf5 readline: add configure --enable-readline-bundled option
Cleanup autoconf handling, should always work as expected.
Use of --enable-readline-bundled when readline is needed will use
copy in subdir.
2025-10-04 20:50:31 -04:00
Darryl L. Miles 2b62123459 SimRsim.c: removal of pre-POSIX.1-2001 select() interface ifdefs
POSIX.1-2001 introduced fd_set for use with select() and all current
systems support POSIX.
2025-10-04 20:50:31 -04:00
Darryl L. Miles 2259ef626d SimRsim.c: EMSCRIPTEN fix for select/fd_set
The compiler has started to error on casting int* to fd_set*
Since WASM build has presense of fd_set then the ifdef have been
switched away from the legacy (pre 2000) method.
2025-10-04 20:50:31 -04:00
Darryl L. Miles 3c9987f460 CmdFI.c: CmdGoto() correct printf output
non-tktcl build check
2025-10-04 20:50:31 -04:00
Darryl L. Miles f4212d8e0e graphics: cleanup various warnings 2025-10-04 20:50:31 -04:00
Darryl L. Miles a16c667290 txInput.c: USE_READLINE constify rl_completion_function
There is a use case of fully .rodata data table of strings but also
a dynamic version built at runtime.
2025-10-04 20:50:31 -04:00
Darryl L. Miles 6e2babd141 txInput.c: constify localvars
non-tktcl build check
2025-10-04 20:50:31 -04:00
Darryl L. Miles b80279c6db grOGL1.c: HashLookOnly() using X11 Window type a key on LLP64 needs cast 2025-10-04 20:50:31 -04:00
Darryl L. Miles 722209b1ae parser.c: ParsSplit() constify (const char **remainder) 2025-10-04 20:50:31 -04:00
Darryl L. Miles 692c0f2339 grX11su3.c: warning for ClientData compare
MAGIC_WRAPPER build option
2025-10-04 20:50:31 -04:00
Darryl L. Miles dbdec3aa17 readline/Makefile: lib target (for no-tktcl build option) 2025-10-04 20:50:31 -04:00
Darryl L. Miles f7d2debb98 txOutput.c: $PAGER handling constify 2025-10-04 20:50:31 -04:00
Darryl L. Miles 0f047b89ce txMain.c: readline needs function shim for prototype difference TxGetChar
USE_READLINE build option
2025-10-04 20:50:31 -04:00
Darryl L. Miles 3b57ae1179 txMain.c: MAGIC_WRAPPER constify fix 2025-10-04 20:50:31 -04:00
Darryl L. Miles dc45242d46 database: DBTypeLongNameTbl() constify data (const char*) 2025-10-04 20:50:31 -04:00
Darryl L. Miles 6d8c3eee1a database: DBTechAddPlane() constify API (const char*) 2025-10-04 20:50:31 -04:00
Darryl L. Miles c8fe30398b database: DBTechInitPlane() consumer (DBPlaneLongNameTbl constify) 2025-10-04 20:50:31 -04:00
Darryl L. Miles 5093182f4a database: DBPlaneShortName() return const char * 2025-10-04 20:50:31 -04:00
Darryl L. Miles 4864a80179 database: DBTypeShortName() return const char * 2025-10-04 20:50:31 -04:00
Darryl L. Miles 70054ccde2 EFread.c: ANSI prototype efReadDef() 2025-10-04 20:50:31 -04:00
Darryl L. Miles c007d8077c EFbuild.c: ANSI prototype efBuildDevNode() 2025-10-04 20:50:31 -04:00
Darryl L. Miles da216195b3 SimSelect.c: fix theoretical potential to write to .rodata string
We make a copy of readonly string on function entry and use that instead.
strrchr() is a bit of an annoying API, takes const char* but returns char*
but it is the same string.  One for static analysis or C++.

SimSelectArea() argument unused.
2025-10-04 20:50:31 -04:00
Darryl L. Miles 5fe586100b extflat: ANSI prototype efBuildDevice() and constify (const Rect*) 2025-10-04 20:50:31 -04:00
Darryl L. Miles c7ef7d743a CmdRS.c: SimGetNodeCommand() returns (const char *) now 2025-10-04 20:50:31 -04:00
Darryl L. Miles df7b9079bd CmdFindLabel: fix off-by-one error with: findlabel -glob name
Thanks @d-m-bailey Mitch Bailey for reporting
2025-10-04 20:50:31 -04:00
Darryl L. Miles cfd1d567bd commands: Various fixes for TxPrintf() with !MAGIC_WRAPPER
!MAGIC_WRAPPER build for WASM exposes
2025-10-04 20:50:31 -04:00
Darryl L. Miles b1424bfaf3 plow: add ANSI prototypes plowMergeBottom() plowMergeTop()
This exposes the incorrect call sites, that are also fixed here.
2025-10-04 20:50:31 -04:00
Darryl L. Miles aef23fd5f3 plotRutils.c: use #include <math.h> 2025-10-04 20:50:31 -04:00
Darryl L. Miles 1dfe1ed645 SimSelect.c: constify (const char*) TLE.tl_nodeName TLE.tl_simLabel 2025-10-04 20:50:31 -04:00
Darryl L. Miles 9c5cf1a567 magic.h: DLONG_PREFIX add other Linux 64bit ifdefs 2025-10-04 20:50:31 -04:00
Darryl L. Miles 55931e8811 GHA: .github/workflows/main-aarch64.yml 2025-10-04 20:50:31 -04:00
R. Timothy Edwards bb131f14d0 One additional modification to output the message about duplicate
cells as a "note" if "gds noduplicates" has been set, and a
"warning" otherwise.  This makes error handling of magic's
output a bit easier.
2025-10-01 15:38:41 -04:00
R. Timothy Edwards 78f7d22796 A number of changes:
1) Corrected spurious error messages about cells already existing
   in GDS when using "flatten" or "flatglob".
2) Fixed handling of resistance as a subcircuit parameter
3) Added area and perimeter resistance for a device;  this is done
   through the "devresist" statement in the tech file, which is an
   extension of the original "fetresist" statement.  Where "fetresist"
   only supported type "linear", "devresist" supports types "area"
   and "perimeter".
4) Support for CDL syntax, including generating subcircuit-like
   parameters for components starting with SPICE-standard prefixes
   like M, R, C, etc., adding "/" between pins and subcircuit name,
   and saving the file as ".cdl" instead of ".spice".
5) Estimated L and W for devices whose geometry is complex and do not
   reduce to a simple rectangle.  L and W are estimated as the square
   root of the area.
6) Changed the method of extracting L and W for diodes to use the same
   method as capacitors.  Note that diodes are not usually specified
   by L and W, but if they are, this will produce the right result.
7) Corrected the reported filename and line number when printing error
   messages related to errors inside a technology file, when the
   technology file uses "include" to combine multiple files.
2025-10-01 15:17:49 -04:00
R. Timothy Edwards b1c7b52ed2 Modified "gds flatglob" to have the value "*_CDNS_*" by default,
since this is a common artifact of foundry cells and almost
always incompatible with magic.  Modified the "port" command to
allow "port make <index>" on a label where other labels of the
same text already have the same index.  Removed deprecated
documentation and added some missing documentation, such as an
explanation of the "ext2spice subcircuit auto" option.
2025-09-26 09:18:43 -04:00
R. Timothy Edwards 5de118b762 Corrected the greatest common factor routine that is run when
doing "save", which was missing checks on properties representing
coordinates (e.g., FIXED_BBOX) resulting in those values
potentially getting truncated by scaling the output to an
incompatible common factor.  Thanks to Sylvain Munaut for finding
the issue!
2025-09-17 12:20:13 -04:00
R. Timothy Edwards 00e3bbd12a Corrected the tech loader, which was failing to set the file
prefix when doing a reentrant load, causing include files to not
be found.  Fixed a divide-by-zero issue that occurs when some
tech file sections are not loaded to the abovementioned error.
2025-09-11 10:51:14 -04:00
R. Timothy Edwards 0022c502c8 Correction to dbReComputeBboxFunc() to fix a potential issue with
an uninitialized bounding box value.
2025-09-10 16:54:25 -04:00
R. Timothy Edwards 741216d6f3 Added a new command "archive" that works roughly like the "crash"
command, but with some critical differences, since the "crash"
command is designed for crash backups.  "crash" will save in a
temp file and removes the file after a successful recovery.
"archive" can be used at any time to make a complete snapshot of
a layout in a single file, or to read back that snapshot.
There is a "writeall" option that will make a snapshot including
layout of all read-only (PDK) cells.
2025-09-10 12:40:40 -04:00
279 changed files with 15929 additions and 8836 deletions

View File

@ -14,35 +14,33 @@ jobs:
matrix:
os: [ubuntu-24.04, ubuntu-22.04]
# Configure Options
pkgs: [all, none, no_tk_tcl_rl, no_rl, no_zlib, no_gc_gl_gu, no_gc_gu]
# X11 OGL CAIRO
pkgs: [all, none, no_tk_tcl_rl, no_tk_tcl_brl, no_zlib, no_gc_gl_gu, no_gc, no_gl_gu]
# Toolchain
# ubuntu-20.04 [gcc-9] gcc-10
# ubuntu-22.04 [gcc-11] gcc-12
# ubuntu-24.04 [gcc-13] gcc-14
tc: [default, gcc-10, gcc-12, gcc-14, clang-17, clang-18]
# ubuntu-20.04 [gcc-9, clang-10]
# ubuntu-22.04 [gcc-11, clang-14]
# ubuntu-24.04 [gcc-13, clang-18]
tc: [default, gcc-10, gcc-11, gcc-12, gcc-13, gcc-14, clang-14, clang-15, clang-17, clang-18, clang-19]
exclude:
- os: ubuntu-20.04
tc: gcc-12
- os: ubuntu-20.04
tc: gcc-14
- os: ubuntu-20.04
tc: clang-17
- os: ubuntu-20.04
tc: clang-18
- os: ubuntu-22.04
tc: gcc-10
tc: gcc-13
- os: ubuntu-22.04
tc: gcc-14
- os: ubuntu-22.04
tc: clang-17
- os: ubuntu-22.04
- os: ubuntu-22.04 # some sources show this as present but not found
tc: clang-18
- os: ubuntu-22.04
tc: clang-19
- os: ubuntu-24.04
tc: gcc-10
- os: ubuntu-24.04
tc: gcc-12
tc: gcc-11
- os: ubuntu-24.04
tc: clang-14
- os: ubuntu-24.04
tc: clang-15
fail-fast: false
runs-on: ${{ matrix.os }}
steps:
@ -69,16 +67,19 @@ jobs:
# z no.*_zl zlib1g-dev
# n no.*_nc libncurses-dev
# r no.*_rl libreadline-dev
# R no.*_brl --enable-readline-bundled
# c no.*_tcl tcl-dev
# k no.*_tk tk-dev
# C no.*_gc libcairo-dev
# L no.*_gl libgl-dev
# U no.*_gu libglu1-mesa-dev
# U no.*_gu libglu1-mesa-dev # GLU requires GL
# X no.*_gx libx11-dev
if echo -n "$MATRIX_PKGS" | grep -q "^no.*_zl"; then
pkgs=$(echo -n "$pkgs" | sed -e 's#z##'); fi
if echo -n "$MATRIX_PKGS" | grep -q "^no.*_nc"; then
pkgs=$(echo -n "$pkgs" | sed -e 's#n##'); fi
if echo -n "$MATRIX_PKGS" | grep -q "^no.*_brl"; then
pkgs=$(echo -n "$pkgs" | sed -e 's#r#R#'); fi # replace
if echo -n "$MATRIX_PKGS" | grep -q "^no.*_rl"; then
pkgs=$(echo -n "$pkgs" | sed -e 's#r##'); fi
if echo -n "$MATRIX_PKGS" | grep -q "^no.*_tcl"; then
@ -111,6 +112,8 @@ jobs:
_configure_args=()
if echo -n "$MATRIX_PKGS" | grep -q "^no.*_zl"; then
_configure_args+=(--disable-compression); fi
if echo -n "$MATRIX_PKGS" | grep -q "^no.*_brl"; then
_configure_args+=(--enable-readline-bundled); fi
if echo -n "$MATRIX_PKGS" | grep -q "^no.*_rl"; then
_configure_args+=(--disable-readline); fi
if echo -n "$MATRIX_PKGS" | grep -q "^no.*_tcl"; then
@ -135,6 +138,8 @@ jobs:
echo "BUILD_GCC_VERSION=$BUILD_GCC_VERSION" >> $GITHUB_ENV
echo "BUILD_CLANG_VERSION=$BUILD_CLANG_VERSION" >> $GITHUB_ENV
sudo apt-get update
if [ -n "$BUILD_GCC_VERSION" ]
then
GCCV=$BUILD_GCC_VERSION

61
.github/workflows/main-aarch64.yml vendored Normal file
View File

@ -0,0 +1,61 @@
# This is a basic workflow to help you get started with Actions
name: CI-aarch64
# Controls when the workflow will run
on:
push:
pull_request:
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
simple_build_linux_arm:
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
- name: Get Dependencies
run: |
sudo apt-get update
sudo apt-get install -y tcl-dev tk-dev libcairo-dev
- name: Build
run: |
./configure
make database/database.h
make -j$(nproc)
simple_build_wasm_arm:
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
- name: Get Dependencies
run: |
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
- name: Emscripten Diagnostic
run: |
source ./emsdk/emsdk_env.sh
echo "===== gcc -dM -E - ====="
echo | gcc -dM -E - | sort
echo "===== g++ -dM -E - ====="
echo | g++ -dM -E - | sort
echo "===== emcc -dM -E - ====="
echo | emcc -dM -E - | sort
echo "===== em++ -dM -E - ====="
echo | em++ -dM -E - | sort
- name: Build
run: |
source ./emsdk/emsdk_env.sh
# The --without and --disable in these build options is due to no WASM library being available for that feature
CFLAGS="--std=c17 -D_DEFAULT_SOURCE=1 -DEMSCRIPTEN=1 -g" emconfigure ./configure --without-cairo --without-opengl --without-x --without-tk --without-tcl --disable-readline --disable-compression --target=asmjs-unknown-emscripten
echo "===== defs.mak ====="
cat defs.mak
echo "===== defs.mak ====="
emmake make
- name: archive wasm bundle
uses: actions/upload-artifact@v4
with:
name: magic-wasm-bundle-arm
path: |
${{ github.workspace }}/magic/magic.wasm

View File

@ -10,8 +10,8 @@ on:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
simple_build_macos13:
runs-on: macos-13
simple_build_macos15:
runs-on: macos-15-intel # only and last supported intel MacOS
timeout-minutes: 45 # x86_64 seems non-SSD based (slower)
steps:
- name: Checkout
@ -235,10 +235,10 @@ jobs:
cp *.mak dist/BUILD-INFO/
cp *.LOG dist/BUILD-INFO/
- name: Upload archive magic-macos13
- name: Upload archive magic-macos15
uses: actions/upload-artifact@v4
with:
name: magic-macos13
name: magic-macos15
path: |
${{ github.workspace }}/dist

View File

@ -10,19 +10,6 @@ on:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
vezzal:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- name: Pulling the docker image
run: docker pull vezzal/vezzal:v1
- name: Start the container with the docker image
run: docker run -id --name test_magic vezzal/vezzal:v1 bash | exit
- name: Run the testing on the container and send the mail
run: docker exec test_magic /vezzal/test_magic.sh "lankasaicharan123@gmail.com,tim@opencircuitdesign.com" ${{secrets.MAILING_KEY}}
simple_build_linux:
runs-on: ubuntu-22.04
steps:
@ -45,10 +32,22 @@ jobs:
cd emsdk
./emsdk install latest
./emsdk activate latest
- name: Emscripten Diagnostic
run: |
source ./emsdk/emsdk_env.sh
echo "===== gcc -dM -E - ====="
echo | gcc -dM -E - | sort
echo "===== g++ -dM -E - ====="
echo | g++ -dM -E - | sort
echo "===== emcc -dM -E - ====="
echo | emcc -dM -E - | sort
echo "===== em++ -dM -E - ====="
echo | em++ -dM -E - | sort
- name: Build
run: |
source ./emsdk/emsdk_env.sh
emconfigure ./configure --without-cairo --without-opengl --without-x --disable-readline --disable-compression --target=asmjs-unknown-emscripten
# The --without and --disable in these build options is due to no WASM library being available for that feature
CFLAGS="--std=c17 -D_DEFAULT_SOURCE=1 -DEMSCRIPTEN=1 -g" emconfigure ./configure --without-cairo --without-opengl --without-x --without-tk --without-tcl --disable-readline --disable-compression --target=asmjs-unknown-emscripten
echo "===== defs.mak ====="
cat defs.mak
echo "===== defs.mak ====="

View File

@ -58,13 +58,15 @@ LIBS_SUBDIR := $(shell for i in ${MODULES}; do echo "$${i}/lib$${i}.a"; done)
${MODULES_SUBDIR}: FORCE
@${MAKE} -C $(dir $@) module
.PHONY: modules
modules: database/database.h depend ${MODULES_SUBDIR}
${LIBS_SUBDIR}: FORCE
@${MAKE} -C $(dir $@) lib
# Force the tiles/utils modules to exist first for libdatabase.a
libs: database/database.h tiles/libtiles.o utils/libutils.o depend ${LIBS_SUBDIR}
.PHONY: libs
libs: database/database.h depend tiles/libtiles.o utils/libutils.o ${LIBS_SUBDIR}
#
# extcheck - utility tool

View File

@ -1 +1 @@
8.3.549
8.3.637

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
export CURDIR=$(dirname $(readlink -f "${0}"))
export PATH="${CURDIR}/bin":$PATH

View File

@ -93,7 +93,7 @@ static BinArray *bpBinArrayNew(int dx, /* x diameter of bins */
/* allocate array */
size = sizeof(BinArray) + numBins*(sizeof(void *));
new = (BinArray *)callocMagic(size);
new = (BinArray *)callocMagic(1, size);
/* initial */
new->ba_bbox = *bbox;

View File

@ -53,6 +53,7 @@ int calmaNonManhattan;
int CalmaFlattenLimit = 10;
int NameConvertErrors = 0;
bool CalmaRewound = FALSE;
bool CalmaRecordPaths = FALSE;
TileTypeBitMask *CalmaMaskHints = NULL;
extern HashTable calmaDefInitHash;
@ -245,7 +246,9 @@ calmaExact(void)
int pNum;
Plane *newplane;
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 *));
@ -387,6 +390,15 @@ calmaParseStructure(
he = HashFind(&calmaDefInitHash, strname);
if ((def = (CellDef *)HashGetValue(he)) != NULL)
{
if (def->cd_flags & CDPRELOADED)
{
/* Cell definition was read ahead due to option "flatten" */
/* or "flatglob". Do not complain about seeing it again. */
def->cd_flags &= ~CDPRELOADED;
calmaNextCell();
return TRUE;
}
if (def->cd_flags & CDPROCESSEDGDS)
{
/* If cell definition was marked as processed, then skip */
@ -396,6 +408,7 @@ calmaParseStructure(
if (!CalmaPostOrder && !CalmaRewound)
{
cifReadCellDef = def;
CalmaReadError("Cell \"%s\" was already defined in this file.\n",
strname);
CalmaReadError("Ignoring duplicate definition\n");
@ -407,6 +420,7 @@ calmaParseStructure(
{
char *newname;
cifReadCellDef = def;
CalmaReadError("Cell \"%s\" was already defined in this file.\n",
strname);
newname = (char *)mallocMagic(strlen(strname) + 20);
@ -492,28 +506,33 @@ calmaParseStructure(
if (CalmaReadOnly || predefined)
{
PropertyRecord *proprec;
char cstring[1024];
/* Writing the file position into a string is slow, but */
/* it prevents requiring special handling when printing */
/* out the properties. */
char *fpcopy = (char *)mallocMagic(20);
char *fncopy;
/* Substitute variable for PDK path or ~ for home directory */
/* the same way that cell references are handled in .mag files. */
DBPathSubstitute(filename, cstring, cifReadCellDef);
fncopy = StrDup(NULL, cstring);
sprintf(fpcopy, "%"DLONG_PREFIX"d", (dlong) filepos);
DBPropPut(cifReadCellDef, "GDS_START", (ClientData)fpcopy);
fpcopy = (char *)mallocMagic(20);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
proprec->prop_type = PROPERTY_TYPE_DOUBLE;
proprec->prop_len = 1;
proprec->prop_value.prop_double[0] = filepos;
DBPropPut(cifReadCellDef, "GDS_START", (ClientData)proprec);
filepos = FTELL(calmaInputFile);
sprintf(fpcopy, "%"DLONG_PREFIX"d", (dlong) filepos);
DBPropPut(cifReadCellDef, "GDS_END", (ClientData)fpcopy);
DBPropPut(cifReadCellDef, "GDS_FILE", (ClientData)fncopy);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
proprec->prop_type = PROPERTY_TYPE_DOUBLE;
proprec->prop_len = 1;
proprec->prop_value.prop_double[0] = filepos;
DBPropPut(cifReadCellDef, "GDS_END", (ClientData)proprec);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) - 7 +
strlen(cstring));
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = 1;
strcpy(proprec->prop_value.prop_string, cstring);
DBPropPut(cifReadCellDef, "GDS_FILE", (ClientData)proprec);
if (predefined)
{
@ -740,6 +759,7 @@ calmaParseElement(
int
calmaEnumFunc(
Tile *tile,
TileType dinfo,
int *plane)
{
return 1;
@ -769,20 +789,22 @@ calmaElementSref(
char *filename)
{
int nbytes, rtype, cols, rows, nref, n, i, savescale;
int xlo, ylo, xhi, yhi, xsep, ysep;
bool madeinst = FALSE;
int xlo, ylo, xhi, yhi, xsep, ysep, angle;
bool madeinst = FALSE, rotated = FALSE;
char *sname = NULL;
bool isArray = FALSE;
bool dolookahead = FALSE;
Transform trans, tinv;
Point refarray[3], refunscaled[3], p;
CellUse *use;
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;
int propAttrType;
/* Forward reference */
int gdsCopyPaintFunc(Tile *tile, TileType dinfo, GDSCopyRec *gdsCopyRec);
int gdsHasUses(CellUse *use, ClientData clientdata);
/* Skip CALMA_ELFLAGS, CALMA_PLEX */
calmaSkipSet(calmaElementIgnore);
@ -798,7 +820,38 @@ calmaElementSref(
*/
def = calmaLookCell(sname);
if (!def && (CalmaPostOrder || CalmaFlattenUses || (CalmaFlattenUsesByName != NULL)))
/*
* If the "flatten" option is set, then we always have to seek
* ahead and read the structure in order to determine if it
* meets the requirement of being flattened or not. If the
* "flatglob" option is set, then we need to read ahead and
* read the cell definition so that it can be flatten. This
* requires pattern-matching the cell def.
*/
dolookahead = (CalmaPostOrder || CalmaFlattenUses) ? TRUE : FALSE;
if ((!dolookahead) && (CalmaFlattenUsesByName != NULL))
{
char *pattern;
i = 0;
while (TRUE)
{
pattern = CalmaFlattenUsesByName[i];
if (pattern == NULL) break;
i++;
/* Check pattern against strname */
if (Match(pattern, sname))
{
dolookahead = TRUE;
break;
}
}
}
if (!def && dolookahead)
{
/* Force the GDS parser to read the cell definition in
* post-order. If cellname "sname" is not defined before
@ -832,6 +885,7 @@ calmaElementSref(
FSEEK(calmaInputFile, originalFilePos, SEEK_SET);
cifReadCellDef = calmaLookCell(currentSname);
def = calmaLookCell(sname);
def->cd_flags |= CDPRELOADED;
cifCurReadPlanes = savePlanes;
calmaLayerHash = OrigCalmaLayerHash;
if (crsMultiplier != cifCurReadStyle->crs_multiplier)
@ -936,17 +990,73 @@ calmaElementSref(
refarray[2].p_x = refarray[2].p_y = 0;
}
/* If the array is given an angle, then the meaning of rows and
* columns needs to be swapped for the purpose of ignoring
* X or Y values in the case of a 1-row or 1-column entry.
*/
angle = GeoTransAngle(&trans, 0);
if ((angle == 90) || (angle == 270) || (angle == -90) || (angle == -270))
rotated = TRUE;
/* If this is a cell reference, then we scale to magic coordinates
* and place the cell in the magic database. However, if this is
* a cell to be flattened a la "gds flatten", then we keep the GDS
* coordinates, and don't scale to the magic database.
*
* NOTE: Scaling everything in the middle or reading array data
* and then retroactively adjusting the array data read earlier
* is problematic, and probably incorrect.
*/
for (n = 0; n < nref; n++)
{
savescale = calmaReadScale1;
/* If there is only one column, then X data in the 2nd or 3rd
* entry is irrelevant. If there is only one row, then Y data
* in the 2nd or 3rd entry is irrelevant. Prevent issues caused
* by incorrect/uninitialized data in these positions by ignoring
* them as needed.
*/
if ((n > 0) && ((!rotated && (rows == 1)) || (rotated && (cols == 1))))
{
calmaReadX(&refarray[n], 1);
calmaSkipBytes(4);
refarray[n].p_y = refarray[0].p_y;
}
else if ((n > 0) && ((!rotated && (cols == 1)) || (rotated && (rows == 1))))
{
calmaSkipBytes(4);
calmaReadY(&refarray[n], 1);
refarray[n].p_x = refarray[0].p_x;
}
else
calmaReadPoint(&refarray[n], 1);
if (savescale != calmaReadScale1)
{
/* Scale changed, so update previous points read */
int newscale = calmaReadScale1 / savescale;
for (i = 0; i < n; i++)
{
refarray[i].p_x *= newscale;
refarray[i].p_y *= newscale;
}
}
if (FEOF(calmaInputFile))
return -1;
}
for (n = 0; n < nref; n++)
refunscaled[n] = refarray[n]; // Save for CDFLATGDS cells
for (n = 0; n < nref; n++)
{
savescale = cifCurReadStyle->crs_scaleFactor;
calmaReadPoint(&refarray[n], 1);
refunscaled[n] = refarray[n]; // Save for CDFLATGDS cells
refarray[n].p_x = CIFScaleCoord(refarray[n].p_x, COORD_EXACT);
if (savescale != cifCurReadStyle->crs_scaleFactor)
{
@ -967,9 +1077,6 @@ calmaElementSref(
}
refarray[n].p_x *= (savescale / cifCurReadStyle->crs_scaleFactor);
}
if (FEOF(calmaInputFile))
return -1;
}
/* Skip remainder */
@ -1245,27 +1352,28 @@ gdsHasUses(
int
gdsCopyPaintFunc(
Tile *tile,
TileType dinfo,
GDSCopyRec *gdsCopyRec)
{
int pNum;
TileType dinfo;
TileType newdinfo;
Rect sourceRect, targetRect;
Transform *trans = gdsCopyRec->trans;
Plane *plane = gdsCopyRec->plane;
dinfo = TiGetTypeExact(tile);
newdinfo = TiGetTypeExact(tile) | dinfo;
if (trans)
{
TiToRect(tile, &sourceRect);
GeoTransRect(trans, &sourceRect, &targetRect);
if (IsSplit(tile))
dinfo = DBTransformDiagonal(TiGetTypeExact(tile), trans);
newdinfo = DBTransformDiagonal(TiGetTypeExact(tile) | dinfo, trans);
}
else
TiToRect(tile, &targetRect);
DBNMPaintPlane(plane, dinfo, &targetRect, CIFPaintTable,
DBNMPaintPlane(plane, newdinfo, &targetRect, CIFPaintTable,
(PaintUndoInfo *)NULL);
return 0;
@ -1384,13 +1492,18 @@ calmaFindCell(
}
else
{
TxPrintf("Warning: cell %s already existed before reading GDS!\n",
name);
if (CalmaNoDuplicates)
{
TxPrintf("Note: cell %s already existed before reading GDS.\n",
name);
if (predefined) *predefined = TRUE;
TxPrintf("Using pre-existing cell definition\n");
}
else
{
TxPrintf("Warning: cell %s already existed before reading GDS!\n",
name);
}
if (was_called) *was_called = TRUE;
}
HashSetValue(h, def);

View File

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

View File

@ -613,20 +613,23 @@ CalmaTechInit(void)
ASSERT(sizeof(FourByteInt)==4, "definition in calmaInt.h");
ASSERT(sizeof(TwoByteInt)==2, "definition in calmaInt.h");
/* NOTE: Enable the code below when CalmaContactArrays */
/* behaves like the non-arrayed function and can be enabled */
/* by default. */
#if 0
/* NOTE: Add "$$*$$" to the default "flatglob" value */
/* when CalmaContactArrays behaves like the non-arrayed */
/* function and can be enabled by default. */
/* Initialize CalmaFlattenByName to have one entry for */
/* "$$*$$" to match the name style used by the contact */
/* array cell generation. This can be overridden by the */
/* "gds flatglob none" command option. */
/* "*_CDNS_*" to match the name style used by many foundry */
/* cells and which corresponds to pcells that often split */
/* layers between cells in ways that magic can't cope with; */
/* and whose original parameterized functions cannot be */
/* recovered by magic anyway. When necessary, this default */
/* can be overridden by the "gds flatglob none" command */
/* option. */
if (CalmaFlattenUsesByName == (char **)NULL)
{
CalmaFlattenUsesByName = (char **)mallocMagic(2 * sizeof(char *));
*CalmaFlattenUsesByName = StrDup((char **)NULL, "$$*$$");
*CalmaFlattenUsesByName = StrDup((char **)NULL, "*_CDNS_*");
*(CalmaFlattenUsesByName + 1) = NULL;
}
#endif
}

View File

@ -97,10 +97,10 @@ typedef struct {
/* Forward declarations */
extern int calmaWriteInitFunc(CellDef *def);
extern int calmaWritePaintFunc(Tile *tile, calmaOutputStruct *cos);
extern int calmaMergePaintFunc(Tile *tile, calmaOutputStruct *cos);
extern int calmaWritePaintFunc(Tile *tile, TileType dinfo, calmaOutputStruct *cos);
extern int calmaMergePaintFunc(Tile *tile, TileType dinfo, calmaOutputStruct *cos);
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 calmaDelContacts(void);
extern void calmaOutFunc(CellDef *def, FILE *f, const Rect *cliprect);
@ -528,7 +528,7 @@ calmaDumpStructure(
/* Is view abstract? */
DBPropGet(edef, "LEFview", &isAbstract);
chklibname = (char *)DBPropGet(edef, "GDS_FILE", &isReadOnly);
chklibname = DBPropGetString(edef, "GDS_FILE", &isReadOnly);
if (isAbstract && isReadOnly)
{
@ -738,7 +738,7 @@ calmaFullDump(
* names in the GDS file do not shadow any names in the database.
*/
viewopts = (char *)DBPropGet(def, "LEFview", &isAbstract);
viewopts = DBPropGetString(def, "LEFview", &isAbstract);
if ((!isAbstract) || (strcasecmp(viewopts, "no_prefix")))
{
/* Generate a SHORT name for this cell (else it is easy to run into the
@ -918,7 +918,7 @@ calmaProcessDef(
DBPropGet(def, "GDS_END", &hasGDSEnd);
DBPropGet(def, "CIFhier", &needHier);
filename = (char *)DBPropGet(def, "GDS_FILE", &isReadOnly);
filename = DBPropGetString(def, "GDS_FILE", &isReadOnly);
/* When used with "calma addendum true", don't output the read-only */
/* cells. This makes the library incomplete and dependent on the */
@ -1033,13 +1033,12 @@ calmaProcessDef(
}
else
{
offptr = (char *)DBPropGet(def, "GDS_END", NULL);
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
cval = DBPropGetDouble(def, "GDS_END", NULL);
cellend = (off_t)cval;
offptr = (char *)DBPropGet(def, "GDS_BEGIN", &oldStyle);
cval = DBPropGetDouble(def, "GDS_BEGIN", &oldStyle);
if (!oldStyle)
{
offptr = (char *)DBPropGet(def, "GDS_START", NULL);
cval = DBPropGetDouble(def, "GDS_START", NULL);
/* Write our own header and string name, to ensure */
/* that the magic cell name and GDS name match. */
@ -1056,7 +1055,6 @@ calmaProcessDef(
calmaOutStructName(CALMA_STRNAME, def, outf);
}
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
cellstart = (off_t)cval;
/* GDS_START has been defined as the start of data after the cell */
@ -1263,7 +1261,7 @@ calmaOutFunc(
int dbunits;
calmaOutputStruct cos;
bool propfound;
char *propvalue;
PropertyRecord *proprec;
cos.f = f;
cos.area = (cliprect == &TiPlaneRect) ? NULL : cliprect;
@ -1323,14 +1321,20 @@ calmaOutFunc(
/* Include any fixed bounding box as part of the area to process, */
/* in case the fixed bounding box is larger than the geometry. */
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &propfound);
proprec = DBPropGet(def, "FIXED_BBOX", &propfound);
if (propfound)
{
Rect bbox;
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) == 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
GeoInclude(&bbox, &bigArea);
}
}
CIFErrorDef = def;
@ -1400,8 +1404,10 @@ calmaOutFunc(
{
pllist[i].pl_label = ll->ll_label;
pllist[i].pl_port = (unsigned int)ll->ll_attr;
freeMagic(ll);
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, ll);
ll = ll->ll_next;
freeMagic1_end(&mm1);
i++;
}
@ -2422,19 +2428,27 @@ calmaProcessBoundary(
/* Free the LinkedBoundary list */
lbref = listtop;
while (lbref->lb_next != listtop)
{
freeMagic(lbref);
lbref = lbref->lb_next;
free_magic1_t mm1 = freeMagic1_init();
lbref = listtop;
while (lbref->lb_next != listtop)
{
freeMagic1(&mm1, lbref);
lbref = lbref->lb_next;
}
freeMagic1(&mm1, lbref);
freeMagic1_end(&mm1);
}
freeMagic(lbref);
}
/* Free the BoundaryTop list */
for (bounds = blist; bounds != NULL; bounds = bounds->bt_next)
freeMagic(bounds);
{
free_magic1_t mm1 = freeMagic1_init();
for (bounds = blist; bounds != NULL; bounds = bounds->bt_next)
freeMagic1(&mm1, bounds);
freeMagic1_end(&mm1);
}
}
/*
@ -2454,6 +2468,7 @@ calmaProcessBoundary(
int
calmaMergePaintFunc(
Tile *tile, /* Tile to be written out. */
TileType dinfo, /* Split tile information (unused) */
calmaOutputStruct *cos) /* Information needed by algorithm */
{
FILE *f = cos->f;
@ -2484,11 +2499,10 @@ calmaMergePaintFunc(
split_type = -1;
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 */
/* I assume it is okay to just check which side is TT_SPACE */
/* split_type = (SplitSide(t) << 1) | SplitDirection(t); */
split_type = SplitDirection(t);
if (TiGetLeftType(t) == TT_SPACE) split_type |= 2;
num_points = 2;
@ -2500,8 +2514,10 @@ calmaMergePaintFunc(
lb = edge;
while (lb->lb_next != edge) lb = lb->lb_next;
lb->lb_next = edge->lb_next;
freeMagic(edge);
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, edge);
edge = edge->lb_next;
freeMagic1_end(&mm1);
}
}
else
@ -2709,7 +2725,9 @@ right_search:
done_searches:
if (intedges == 0)
{
calmaWritePaintFunc(t, cos);
calmaWritePaintFunc(t,
(split_type & 2) ? (TileType)TT_SIDE : (TileType)0,
cos);
/* Although calmaWritePaintFunc is called only on isolated */
/* tiles, we may have expanded it. This could use a LOT of */
@ -2720,11 +2738,13 @@ done_searches:
if (num_points != 4)
{
free_magic1_t mm1 = freeMagic1_init();
for (i = 0; i < num_points; i++)
{
freeMagic(edge);
freeMagic1(&mm1, edge);
edge = edge->lb_next;
}
freeMagic1_end(&mm1);
edge = NULL;
}
if (!StackEmpty(SegStack))
@ -2777,6 +2797,7 @@ done_searches:
int
calmaWritePaintFunc(
Tile *tile, /* Tile to be written out. */
TileType dinfo, /* Split tile information */
calmaOutputStruct *cos) /* File for output and clipping area */
{
FILE *f = cos->f;
@ -2812,7 +2833,7 @@ calmaWritePaintFunc(
/* Coordinates */
calmaOutRH(36, CALMA_XY, CALMA_I4, f);
switch ((SplitSide(tile) << 1) | SplitDirection(tile))
switch (((dinfo & TT_SIDE) ? 2 : 0) | SplitDirection(tile))
{
case 0x0:
calmaOutI4(r.r_xbot, f); calmaOutI4(r.r_ybot, f);
@ -3053,6 +3074,7 @@ calmaWriteLabelFunc(
int
calmaPaintLabelFunc(
Tile *tile, /* Tile contains area for label. */
TileType dinfo, /* Split tile information (unused) */
calmaOutputStruct *cos) /* File for output and clipping area */
{
FILE *f = cos->f;

View File

@ -107,10 +107,10 @@ typedef struct {
} calmaOutputStructZ;
/* Forward declarations */
extern int calmaWritePaintFuncZ(Tile *tile, calmaOutputStructZ *cos);
extern int calmaMergePaintFuncZ(Tile *tile, calmaOutputStructZ *cos);
extern int calmaWritePaintFuncZ(Tile *tile, TileType dinfo, calmaOutputStructZ *cos);
extern int calmaMergePaintFuncZ(Tile *tile, TileType dinfo, calmaOutputStructZ *cos);
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 calmaOutFuncZ(CellDef *def, gzFile f, const Rect *cliprect);
extern void calmaOutStructNameZ(int type, CellDef *def, gzFile f);
@ -508,7 +508,7 @@ calmaDumpStructureZ(
/* Is view abstract? */
DBPropGet(edef, "LEFview", &isAbstract);
chklibname = (char *)DBPropGet(edef, "GDS_FILE", &isReadOnly);
chklibname = DBPropGetString(edef, "GDS_FILE", &isReadOnly);
if (isAbstract && isReadOnly)
{
@ -716,7 +716,7 @@ calmaFullDumpZ(
* names in the GDS file do not shadow any names in the database.
*/
viewopts = (char *)DBPropGet(def, "LEFview", &isAbstract);
viewopts = DBPropGetString(def, "LEFview", &isAbstract);
if ((!isAbstract) || (strcasecmp(viewopts, "no_prefix")))
{
/* Generate a SHORT name for this cell (else it is easy to run into the
@ -870,7 +870,7 @@ calmaProcessDefZ(
DBPropGet(def, "GDS_START", &hasContent);
DBPropGet(def, "GDS_END", &hasGDSEnd);
DBPropGet(def, "CIFhier", &needHier);
filename = (char *)DBPropGet(def, "GDS_FILE", &isReadOnly);
filename = DBPropGetString(def, "GDS_FILE", &isReadOnly);
/* When used with "calma addendum true", don't output the read-only */
/* cells. This makes the library incomplete and dependent on the */
@ -985,13 +985,12 @@ calmaProcessDefZ(
}
else
{
offptr = (char *)DBPropGet(def, "GDS_END", NULL);
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
cval = DBPropGetDouble(def, "GDS_END", NULL);
cellend = (z_off_t)cval;
offptr = (char *)DBPropGet(def, "GDS_BEGIN", &oldStyle);
cval = DBPropGetDouble(def, "GDS_BEGIN", &oldStyle);
if (!oldStyle)
{
offptr = (char *)DBPropGet(def, "GDS_START", NULL);
cval = DBPropGetDouble(def, "GDS_START", NULL);
/* Write our own header and string name, to ensure */
/* that the magic cell name and GDS name match. */
@ -1008,7 +1007,6 @@ calmaProcessDefZ(
calmaOutStructNameZ(CALMA_STRNAME, def, outf);
}
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
cellstart = (z_off_t)cval;
/* GDS_START has been defined as the start of data after the cell */
@ -1186,6 +1184,7 @@ calmaOutFuncZ(
int dbunits;
calmaOutputStructZ cos;
bool propfound;
PropertyRecord *proprec;
char *propvalue;
extern int compport(const void *one, const void *two); /* Forward declaration */
@ -1247,14 +1246,20 @@ calmaOutFuncZ(
/* Include any fixed bounding box as part of the area to process, */
/* in case the fixed bounding box is larger than the geometry. */
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &propfound);
proprec = DBPropGet(def, "FIXED_BBOX", &propfound);
if (propfound)
{
Rect bbox;
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) == 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
GeoInclude(&bbox, &bigArea);
}
}
CIFErrorDef = def;
@ -1324,8 +1329,10 @@ calmaOutFuncZ(
{
pllist[i].pl_label = ll->ll_label;
pllist[i].pl_port = (unsigned int)ll->ll_attr;
freeMagic(ll);
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, ll);
ll = ll->ll_next;
freeMagic1_end(&mm1);
i++;
}
@ -1857,19 +1864,27 @@ calmaProcessBoundaryZ(
/* Free the LinkedBoundary list */
lbref = listtop;
while (lbref->lb_next != listtop)
{
freeMagic(lbref);
lbref = lbref->lb_next;
free_magic1_t mm1 = freeMagic1_init();
lbref = listtop;
while (lbref->lb_next != listtop)
{
freeMagic1(&mm1, lbref);
lbref = lbref->lb_next;
}
freeMagic1(&mm1, lbref);
freeMagic1_end(&mm1);
}
freeMagic(lbref);
}
/* Free the BoundaryTop list */
for (bounds = blist; bounds != NULL; bounds = bounds->bt_next)
freeMagic(bounds);
{
free_magic1_t mm1 = freeMagic1_init();
for (bounds = blist; bounds != NULL; bounds = bounds->bt_next)
freeMagic1(&mm1, bounds);
freeMagic1_end(&mm1);
}
}
/*
@ -1889,6 +1904,7 @@ calmaProcessBoundaryZ(
int
calmaMergePaintFuncZ(
Tile *tile, /* Tile to be written out. */
TileType dinfo, /* Split tile information (unused) */
calmaOutputStructZ *cos) /* Information needed by algorithm */
{
gzFile f = cos->f;
@ -1919,11 +1935,10 @@ calmaMergePaintFuncZ(
split_type = -1;
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 */
/* I assume it is okay to just check which side is TT_SPACE */
/* split_type = (SplitSide(t) << 1) | SplitDirection(t); */
split_type = SplitDirection(t);
if (TiGetLeftType(t) == TT_SPACE) split_type |= 2;
num_points = 2;
@ -1935,8 +1950,10 @@ calmaMergePaintFuncZ(
lb = edge;
while (lb->lb_next != edge) lb = lb->lb_next;
lb->lb_next = edge->lb_next;
freeMagic(edge);
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, edge);
edge = edge->lb_next;
freeMagic1_end(&mm1);
}
}
else
@ -2144,7 +2161,9 @@ right_search:
done_searches:
if (intedges == 0)
{
calmaWritePaintFuncZ(t, cos);
calmaWritePaintFuncZ(t,
(split_type & 2) ? (TileType)TT_SIDE : (TileType)0,
cos);
/* Although calmaWritePaintFunc is called only on isolated */
/* tiles, we may have expanded it. This could use a LOT of */
@ -2155,11 +2174,13 @@ done_searches:
if (num_points != 4)
{
free_magic1_t mm1 = freeMagic1_init();
for (i = 0; i < num_points; i++)
{
freeMagic(edge);
freeMagic1(&mm1, edge);
edge = edge->lb_next;
}
freeMagic1_end(&mm1);
edge = NULL;
}
if (!StackEmpty(SegStack))
@ -2212,6 +2233,7 @@ done_searches:
int
calmaWritePaintFuncZ(
Tile *tile, /* Tile to be written out. */
TileType dinfo, /* Split tile information */
calmaOutputStructZ *cos) /* File for output and clipping area */
{
gzFile f = cos->f;
@ -2247,7 +2269,7 @@ calmaWritePaintFuncZ(
/* Coordinates */
calmaOutRHZ(36, CALMA_XY, CALMA_I4, f);
switch ((SplitSide(tile) << 1) | SplitDirection(tile))
switch (((dinfo & TT_SIDE) ? 2 : 0) | SplitDirection(tile))
{
case 0x0:
calmaOutI4Z(r.r_xbot, f); calmaOutI4Z(r.r_ybot, f);
@ -2488,6 +2510,7 @@ calmaWriteLabelFuncZ(
int
calmaPaintLabelFuncZ(
Tile *tile, /* Tile contains area for label. */
TileType dinfo, /* Split tile information (unused) */
calmaOutputStructZ *cos) /* File for output and clipping area */
{
gzFile f = cos->f;

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -209,52 +209,41 @@ typedef struct _maskHintsData
{
Transform *mh_trans;
CellDef *mh_def;
Plane *mh_plane;
} MaskHintsData;
/*
* ----------------------------------------------------------------------------
*
* cifMaskHints --
* cifCopyMaskHintFunc --
*
* Copy a mask hint into a target cell by adding it to the
* property list of the target cell. If the target cell already
* has the same mask hint key, then the mask hint value is
* appended to the property in the target cell def.
* Callback function used by cifFlatMaskHints. Transforms a tile
* from the original plane and paints it into the target plane,
* both of which are properties.
*
* Returns:
* 0 to keep the search going.
* Results:
* Zero to keep the search going.
*
* Side effects:
* Modifies properties of the target cell def.
* Paints geometry into the target plane.
*
* ----------------------------------------------------------------------------
*/
/* DEPRECATED */
int
cifMaskHints(
char *name,
char *value,
CellDef *targetDef)
cifCopyMaskHintFunc(Tile *tile,
TileType dinfo,
ClientData cdata)
{
char *propvalue, *newval;
bool propfound;
MaskHintsData *mhd = (MaskHintsData *)cdata;
Rect r, newr;
if (!strncmp(name, "MASKHINTS_", 10))
{
/* Check if name exists already in the flattened cell */
propvalue = (char *)DBPropGet(targetDef, name, &propfound);
if (propfound)
{
/* Append value to the property */
newval = mallocMagic(strlen(value) + strlen(propvalue) + 2);
sprintf(newval, "%s %s", propvalue, value);
}
else
newval = StrDup((char **)NULL, value);
TiToRect(tile, &r);
/* Transform tile area to coordinates of mhd->mh_plane and paint */
GeoTransRect(mhd->mh_trans, &r, &newr);
DBPaintPlane(mhd->mh_plane, &newr, CIFPaintTable, (PaintUndoInfo *)NULL);
DBPropPut(targetDef, name, newval);
}
return 0;
}
@ -264,8 +253,8 @@ cifMaskHints(
* cifFlatMaskHints --
*
* Copy a mask hint into a flattened cell by transforming it into the
* coordinate system of the flattened cell, and adding it to the
* property list of the flattened cell.
* coordinate system of the flattened cell, and painting it into the
* property plane of the flattened cell.
*
* Returns:
* 0 to keep the search going.
@ -279,67 +268,40 @@ cifMaskHints(
int
cifFlatMaskHints(
char *name,
char *value,
PropertyRecord *proprec,
MaskHintsData *mhd)
{
Rect r, newr;
char *vptr, *newval, *lastval, *propvalue;
bool propfound;
int lastlen, numvals;
int i, lastlen, numvals;
PropertyRecord *newproprec, *oldproprec;
Plane *plane;
if (!strncmp(name, "MASKHINTS_", 10))
{
newval = (char *)NULL;
vptr = value;
while (*vptr != '\0')
{
numvals = sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
&r.r_xtop, &r.r_ytop);
if (numvals == 4)
{
/* Transform rectangle to top level coordinates */
GeoTransRect(mhd->mh_trans, &r, &newr);
lastval = newval;
lastlen = (lastval) ? strlen(lastval) : 0;
newval = mallocMagic(40 + lastlen);
if (lastval)
strcpy(newval, lastval);
else
*newval = '\0';
sprintf(newval + lastlen, "%s%d %d %d %d", (lastval) ? " " : "",
newr.r_xbot, newr.r_ybot, newr.r_xtop, newr.r_ytop);
if (lastval) freeMagic(lastval);
/* Parse through the four values and check if there's more */
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
}
else
{
TxError("MASKHINTS_%s: Expected 4 values, found only %d\n",
name + 10, numvals);
break;
}
}
/* Check if name exists already in the flattened cell */
propvalue = (char *)DBPropGet(mhd->mh_def, name, &propfound);
oldproprec = (PropertyRecord *)DBPropGet(mhd->mh_def, name, &propfound);
if (propfound)
{
/* Append newval to the property */
lastval = newval;
newval = mallocMagic(strlen(lastval) + strlen(propvalue) + 2);
sprintf(newval, "%s %s", propvalue, lastval);
freeMagic(lastval);
ASSERT(oldproprec->prop_value.prop_type == PROPERTY_TYPE_PLANE,
"cifFlatMaskHints");
plane = oldproprec->prop_value.prop_plane;
}
DBPropPut(mhd->mh_def, name, newval);
else
{
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
newproprec->prop_len = 0; /* (unused) */
newproprec->prop_type = PROPERTY_TYPE_PLANE;
plane = DBNewPlane((ClientData)TT_SPACE);
newproprec->prop_value.prop_plane = plane;
DBPropPut(mhd->mh_def, name, newproprec);
}
mhd->mh_plane = plane;
DBSrPaintArea((Tile *)NULL, proprec->prop_value.prop_plane,
&TiPlaneRect, &CIFSolidBits,
cifCopyMaskHintFunc, (ClientData)mhd);
}
return 0;
}
@ -350,9 +312,10 @@ cifFlatMaskHints(
* CIFCopyMaskHints --
*
* Callback function to copy mask hints from one cell into another.
* (Occasionally called as a standalone function, not as a callback.)
*
* Results:
* None.
* Return 0 to keep the search going.
*
* Side effects:
* May modify properties in the target cell.
@ -360,7 +323,7 @@ cifFlatMaskHints(
* ----------------------------------------------------------------------------
*/
void
int
CIFCopyMaskHints(
SearchContext *scx,
CellDef *targetDef)
@ -370,38 +333,9 @@ CIFCopyMaskHints(
CellDef *sourceDef = scx->scx_use->cu_def;
mhd.mh_trans = &scx->scx_trans;
mhd.mh_def = targetDef;
mhd.mh_plane = (Plane *)NULL;
DBPropEnum(sourceDef, cifFlatMaskHints, &mhd);
}
/*
* ----------------------------------------------------------------------------
*
* cifHierCopyMaskHints --
*
* Callback function to copy mask hints from a subcell into a flattened
* cell, which is passed in the clientData record.
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* May modify properties in the flattened cell.
*
* ----------------------------------------------------------------------------
*/
int
cifHierCopyMaskHints(
SearchContext *scx,
ClientData clientData)
{
MaskHintsData mhd;
mhd.mh_trans = &scx->scx_trans;
mhd.mh_def = (CellDef *)clientData;
DBPropEnum(scx->scx_use->cu_def, cifFlatMaskHints, &mhd);
return 0;
}
@ -433,15 +367,16 @@ cifHierCopyMaskHints(
int
cifHierCopyFunc(
Tile *tile, /* Pointer to tile to copy. */
TileType dinfo, /* Split tile information */
TreeContext *cxp) /* Describes context of search, including
* transform and client data.
*/
{
TileType type = TiGetTypeExact(tile);
TileType type = TiGetTypeExact(tile) | dinfo;
Rect sourceRect, targetRect;
int pNum;
CellDef *def = (CellDef *) cxp->tc_filter->tf_arg;
int dinfo = 0;
TileType newdinfo = 0;
/* Ignore tiles in vendor GDS, unless this is specifically */
/* overridden by the "see-vendor" option. */
@ -457,8 +392,8 @@ cifHierCopyFunc(
if (IsSplit(tile))
{
dinfo = DBTransformDiagonal(type, &cxp->tc_scx->scx_trans);
type = (SplitSide(tile)) ? SplitRightType(tile) :
newdinfo = DBTransformDiagonal(type, &cxp->tc_scx->scx_trans);
type = (dinfo & TT_SIDE) ? SplitRightType(tile) :
SplitLeftType(tile);
}
@ -473,7 +408,7 @@ cifHierCopyFunc(
{
if (DBPaintOnPlane(type, pNum))
{
DBNMPaintPlane(def->cd_planes[pNum], dinfo, &targetRect,
DBNMPaintPlane(def->cd_planes[pNum], newdinfo, &targetRect,
DBStdPaintTbl(type, pNum), (PaintUndoInfo *) NULL);
}
}
@ -525,7 +460,7 @@ cifHierCellFunc(
/* Flatten mask hints in the area of interest */
CIFCopyMaskHints(scx, CIFComponentDef);
DBTreeSrCells(&newscx, 0, cifHierCopyMaskHints,
DBTreeSrCells(&newscx, 0, CIFCopyMaskHints,
(ClientData)CIFComponentDef);
/* Set CIFErrorDef to NULL to ignore errors here... these will
@ -562,9 +497,11 @@ cifHierCellFunc(
int
cifHierErrorFunc(
Tile *tile, /* Tile that covers area it shouldn't. */
TileType dinfo, /* Split tile information */
Rect *checkArea) /* Intersection of this and tile is error. */
{
Rect area;
bool side = (dinfo & TT_SIDE) ? TRUE : FALSE;
TiToRect(tile, &area);
@ -572,8 +509,8 @@ cifHierErrorFunc(
* space bounds the checkArea.
*/
if (IsSplit(tile))
if (((area.r_xbot == checkArea->r_xbot) && !SplitSide(tile)) ||
((area.r_xtop == checkArea->r_xtop) && SplitSide(tile)))
if (((area.r_xbot == checkArea->r_xbot) && !side) ||
((area.r_xtop == checkArea->r_xtop) && side))
return 0;
GeoClip(&area, checkArea);
@ -604,6 +541,7 @@ cifHierErrorFunc(
int
cifHierCheckFunc(
Tile *tile, /* Tile containing CIF. */
TileType dinfo, /* Split tile information */
Plane *plane) /* Plane to check against and modify. */
{
Rect area;
@ -612,10 +550,10 @@ cifHierCheckFunc(
if (IsSplit(tile))
{
DBSrPaintNMArea((Tile *)NULL, plane, TiGetTypeExact(tile),
DBSrPaintNMArea((Tile *)NULL, plane, TiGetTypeExact(tile) | dinfo,
&area, &DBSpaceBits, cifHierErrorFunc, (ClientData) &area);
DBNMPaintPlane(plane, TiGetTypeExact(tile), &area, CIFEraseTable,
DBNMPaintPlane(plane, TiGetTypeExact(tile) | dinfo, &area, CIFEraseTable,
(PaintUndoInfo *) NULL);
}
else
@ -651,6 +589,7 @@ cifHierCheckFunc(
int
cifHierTempCheckFunc(
Tile *tile, /* Tile containing CIF. */
TileType dinfo, /* Information about split tiles */
Plane *plane) /* Plane to check against and modify. */
{
Rect area;
@ -658,7 +597,7 @@ cifHierTempCheckFunc(
TiToRect(tile, &area);
if (IsSplit(tile))
DBNMPaintPlane(plane, TiGetTypeExact(tile), &area, CIFEraseTable,
DBNMPaintPlane(plane, TiGetTypeExact(tile) | dinfo, &area, CIFEraseTable,
(PaintUndoInfo *) NULL);
else
DBPaintPlane(plane, &area, CIFEraseTable, (PaintUndoInfo *) NULL);
@ -686,6 +625,7 @@ cifHierTempCheckFunc(
int
cifHierPaintFunc(
Tile *tile,
TileType dinfo, /* Information about split tiles */
Plane *plane) /* Plane in which to paint CIF over tile's
* area.
*/
@ -693,9 +633,9 @@ cifHierPaintFunc(
Rect 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))
DBNMPaintPlane(plane, TiGetTypeExact(tile), &area, CIFPaintTable,
DBNMPaintPlane(plane, TiGetTypeExact(tile) | dinfo, &area, CIFPaintTable,
(PaintUndoInfo *) NULL);
else
DBPaintPlane(plane, &area, CIFPaintTable, (PaintUndoInfo *) NULL);
@ -848,7 +788,7 @@ CIFGenSubcells(
cifHierCopyFunc, (ClientData) CIFTotalDef);
/* Flatten mask hints in the area of interest */
CIFCopyMaskHints(&scx, CIFTotalDef);
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFTotalDef);
CIFErrorDef = def;
@ -1026,14 +966,14 @@ cifHierElementFunc(
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
cifHierCopyFunc, (ClientData) CIFTotalDef);
CIFCopyMaskHints(&scx, CIFTotalDef);
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFTotalDef);
DBCellClearDef(CIFComponentDef);
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef);
CIFCopyMaskHints(&scx, CIFComponentDef);
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
(ClientData)CIFComponentDef);
CIFErrorDef = (CellDef *) NULL;
@ -1067,6 +1007,7 @@ cifHierElementFunc(
int
cifGrowSliver(
Tile *tile,
TileType dinfo, /* Split tile information, needs to be handled */
Rect *area)
{
int height, width, expand_up, expand_side;
@ -1127,22 +1068,24 @@ cifGrowSliver(
int
cifHierPaintArrayFunc(
Tile *tile)
Tile *tile,
TileType dinfo,
ClientData clientdata) /* (unused) */
{
Rect area;
int i, j, xbot, xtop;
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;
xtop = area.r_xtop;
for (i=0; i<cifHierYCount; i++)
{
for (j=0; j<cifHierXCount; j++)
for (j = 0; j < cifHierXCount; j++)
{
DBPaintPlane(cifHierCurPlane, &area, CIFPaintTable,
(PaintUndoInfo *) NULL);
CIFTileOps += 1;
DBNMPaintPlane(cifHierCurPlane, TiGetTypeExact(tile) | dinfo,
&area, CIFPaintTable, (PaintUndoInfo *) NULL);
CIFTileOps++;
area.r_xbot += 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_BRIDGELIM - Added 27/07/20---Bridge across catecorner gaps, but with limiting layers
* CIFOP_MASKHINTS - Added 12/14/20---Add geometry from cell properties, if any.
* CIFOP_NOTSQUARE - Added 2/26/26---Keep only geometry which is not square.
* CIFOP_TAGGED - Added 3/11/26---Find geometry attached to the given text label
*/
#define CIFOP_AND 1
@ -172,6 +174,8 @@ typedef struct cifop
#define CIFOP_BRIDGE 23
#define CIFOP_BRIDGELIM 24
#define CIFOP_MASKHINTS 25
#define CIFOP_NOTSQUARE 26
#define CIFOP_TAGGED 27
/* Definitions of bit fields used in the value of co_client for CIFOP_INTERACT */
#define CIFOP_INT_NOT 0x1 /* Inverted sense (not interacting) */
@ -335,10 +339,9 @@ extern void CIFClearPlanes(Plane **planes);
extern Plane *CIFGenLayer(CIFOp *op, const Rect *area, CellDef *cellDef, CellDef *origDef, Plane *temps[],
bool hier, ClientData clientdata);
extern void CIFInitCells(void);
extern int cifHierCopyFunc(Tile *tile, TreeContext *cxp);
extern int cifHierCopyMaskHints(SearchContext *scx, ClientData clientData);
extern int cifHierCopyFunc(Tile *tile, TileType dinfo, TreeContext *cxp);
extern void CIFLoadStyle(char *stylename);
extern void CIFCopyMaskHints(SearchContext *scx, CellDef *targetDef);
extern int CIFCopyMaskHints(SearchContext *scx, CellDef *targetDef);
/* C99 compat */
extern void CIFCoverageLayer(CellDef *rootDef, Rect *area, char *layer, bool dolist);
@ -346,7 +349,7 @@ extern bool CIFWriteFlat(CellDef *rootDef, FILE *f);
extern void CIFScalePlanes(int scalen, int scaled, Plane **planearray);
extern void CIFInputRescale(int n, int d);
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 cifSquareFunc(Rect *area, CIFOp *op, int *rows, int *columns, Rect *cut);
extern int cifSquareGridFunc(Rect *area, CIFOp *op, int *rows, int *columns, Rect *cut);
@ -367,6 +370,9 @@ extern CellUse *CIFDummyUse; /* Used to dummy up a CellUse for a
* def.
*/
extern Plane *CIFTotalPlanes[]; /* Exported for diagnostics */
extern Plane *CIFComponentPlanes[]; /* Exported for diagnostics */
/* Valid values of CIFWarningLevel (see cif.h) */
typedef enum {CIF_WARN_DEFAULT, CIF_WARN_NONE, CIF_WARN_ALIGN,

View File

@ -505,6 +505,7 @@ CIFParseStart(void)
int cifCheckPaintFunc(
Tile *tile,
TileType dinfo,
ClientData clientData)
{
return 1;
@ -515,27 +516,28 @@ int cifCheckPaintFunc(
int
cifCopyPaintFunc(
Tile *tile,
TileType dinfo,
CIFCopyRec *cifCopyRec)
{
int pNum;
TileType dinfo;
TileType newdinfo;
Rect sourceRect, targetRect;
Transform *trans = cifCopyRec->trans;
Plane *plane = cifCopyRec->plane;
dinfo = TiGetTypeExact(tile);
newdinfo = TiGetTypeExact(tile) | dinfo;
if (trans)
{
TiToRect(tile, &sourceRect);
GeoTransRect(trans, &sourceRect, &targetRect);
if (IsSplit(tile))
dinfo = DBTransformDiagonal(TiGetTypeExact(tile), trans);
newdinfo = DBTransformDiagonal(TiGetTypeExact(tile) | dinfo, trans);
}
else
TiToRect(tile, &targetRect);
DBNMPaintPlane(plane, dinfo, &targetRect, CIFPaintTable,
DBNMPaintPlane(plane, newdinfo, &targetRect, CIFPaintTable,
(PaintUndoInfo *)NULL);
return 0;
@ -561,6 +563,7 @@ cifCopyPaintFunc(
int
cifMaskHintFunc(
Tile *tile,
TileType dinfo, /* Unused, do not support non-manhattan hints */
LinkedRect **lrecp)
{
Rect r;
@ -597,8 +600,9 @@ int
CIFPaintCurrent(
int filetype)
{
extern int cifMakeBoundaryFunc(Tile *tile, ClientData clientdata); /* Forward declaration. */
extern int cifPaintCurrentFunc(Tile *tile, TileType type); /* Forward declaration. */
/* Forward declarations. */
extern int cifMakeBoundaryFunc(Tile *tile, TileType dinfo, ClientData clientdata);
extern int cifPaintCurrentFunc(Tile *tile, TileType dinfo, TileType type);
Plane *plane, *swapplane;
int i;
@ -609,7 +613,7 @@ CIFPaintCurrent(
CIFOp *op;
plane = CIFGenLayer(cifCurReadStyle->crs_layers[i]->crl_ops,
&TiPlaneRect, (CellDef *)NULL, (CellDef *)NULL,
&TiPlaneRect, cifReadCellDef, cifReadCellDef,
cifCurReadPlanes, FALSE, (ClientData)NULL);
/* Generate a paint/erase table, then paint from the CIF
@ -684,6 +688,8 @@ CIFPaintCurrent(
}
else if (op == NULL)
{
LinkedRect *lrec = NULL, *lsrch;
/* Handle boundary layer */
op = cifCurReadStyle->crs_layers[i]->crl_ops;
@ -698,6 +704,102 @@ CIFPaintCurrent(
(ClientData)NULL) == 1))
DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect,
&CIFSolidBits, cifMakeBoundaryFunc, INT2CD(filetype));
/* Handle mask-hints input operator */
op = cifCurReadStyle->crs_layers[i]->crl_ops;
while (op)
{
if (op->co_opcode == CIFOP_MASKHINTS) break;
op = op->co_next;
}
if (op && (DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect,
&DBAllButSpaceBits, cifCheckPaintFunc,
(ClientData)NULL) == 1))
{
/* (To do: remove the linked Rects and paint directly
* into the plane in cifMaskHintFunc())
*/
DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect,
&CIFSolidBits, cifMaskHintFunc,
(ClientData)&lrec);
if (lrec != NULL)
{
PropertyRecord *proprec, *proporig;
char *propname, *layername;
int proplen, i, savescale;
bool origfound = FALSE;
Plane *plane;
layername = (char *)op->co_client;
propname = (char *)mallocMagic(11 + strlen(layername));
sprintf(propname, "MASKHINTS_%s", layername);
/* If there is already a mask hint plane for this layer,
* then add to it; otherwise, create a new plane.
*/
proprec = DBPropGet(cifReadCellDef, layername, &origfound);
if (origfound)
plane = proprec->prop_value.prop_plane;
else
{
proprec = (PropertyRecord *)mallocMagic(
sizeof(PropertyRecord));
proprec->prop_type = PROPERTY_TYPE_PLANE;
proprec->prop_len = 0; /* (unused) */
plane = DBNewPlane((ClientData)TT_SPACE);
proprec->prop_value.prop_plane = plane;
DBPropPut(cifReadCellDef, propname, proprec);
}
while (lrec != NULL)
{
lrec->r_r.r_xtop =
CIFScaleCoord(lrec->r_r.r_xtop, COORD_EXACT);
savescale = cifCurReadStyle->crs_scaleFactor;
lrec->r_r.r_ytop =
CIFScaleCoord(lrec->r_r.r_ytop, COORD_EXACT);
if (savescale != cifCurReadStyle->crs_scaleFactor)
{
lrec->r_r.r_xtop *=
(savescale / cifCurReadStyle->crs_scaleFactor);
savescale = cifCurReadStyle->crs_scaleFactor;
}
lrec->r_r.r_xbot =
CIFScaleCoord(lrec->r_r.r_xbot, COORD_EXACT);
if (savescale != cifCurReadStyle->crs_scaleFactor)
{
lrec->r_r.r_xtop *=
(savescale / cifCurReadStyle->crs_scaleFactor);
lrec->r_r.r_ytop *=
(savescale / cifCurReadStyle->crs_scaleFactor);
savescale = cifCurReadStyle->crs_scaleFactor;
}
lrec->r_r.r_ybot =
CIFScaleCoord(lrec->r_r.r_ybot, COORD_EXACT);
if (savescale != cifCurReadStyle->crs_scaleFactor)
{
lrec->r_r.r_xtop *=
(savescale / cifCurReadStyle->crs_scaleFactor);
lrec->r_r.r_ytop *=
(savescale / cifCurReadStyle->crs_scaleFactor);
lrec->r_r.r_xbot *=
(savescale / cifCurReadStyle->crs_scaleFactor);
}
DBPaintPlane(plane, &lrec->r_r, CIFPaintTable,
(PaintUndoInfo *)NULL);
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, lrec);
lrec = lrec->r_next;
freeMagic1_end(&mm1);
}
freeMagic(propname);
}
}
}
/* Swap planes */
@ -786,9 +888,7 @@ CIFPaintCurrent(
for (i = 0; i < cifNReadLayers; i++)
{
LinkedRect *lrec = NULL;
char *propstr = NULL;
char locstr[512];
LinkedRect *lrec = NULL, *lsrch;
Plane *tempp;
if (!TTMaskHasType(CalmaMaskHints, i)) continue;
@ -813,51 +913,55 @@ CIFPaintCurrent(
(CellDef *)NULL, CIFPlanes, FALSE, (ClientData)NULL);
/* Scan the resulting plane and generate linked Rect structures for
* each shape found.
* each shape found. (To do: Remove the linked Rects and paint
* directly into the plane in cifMaskHintFunc(), which is more
* efficient but not hugely so.)
*/
DBSrPaintArea((Tile *)NULL, presult, &TiPlaneRect, &CIFSolidBits,
cifMaskHintFunc, (ClientData)&lrec);
if (lrec != NULL)
{
PropertyRecord *proprec;
bool propfound;
char *propname;
Plane *plane;
propname = (char *)mallocMagic(11 + strlen(cifReadLayers[i]));
sprintf(propname, "MASKHINTS_%s", cifReadLayers[i]);
propstr = (char *)NULL;
/* Turn all linked Rects into a mask-hints property in the
* target cell.
/* Paint all linked Rects into a mask-hints property plane
* in the target cell.
*/
proprec = DBPropGet(cifReadCellDef, propname, &propfound);
if (!propfound)
{
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
proprec->prop_type = PROPERTY_TYPE_PLANE;
proprec->prop_len = 0; /* (unused) */
plane = DBNewPlane((ClientData)TT_SPACE);
proprec->prop_value.prop_plane = plane;
DBPropPut(cifReadCellDef, propname, proprec);
}
else
plane = proprec->prop_value.prop_plane;
while (lrec != NULL)
{
char *newstr;
sprintf(locstr, "%d %d %d %d",
lrec->r_r.r_xbot / CIFCurStyle->cs_scaleFactor,
lrec->r_r.r_ybot / CIFCurStyle->cs_scaleFactor,
lrec->r_r.r_xtop / CIFCurStyle->cs_scaleFactor,
lrec->r_r.r_ytop / CIFCurStyle->cs_scaleFactor);
if (propstr == NULL)
{
newstr = (char *)mallocMagic(strlen(locstr) + 1);
sprintf(newstr, "%s", locstr);
}
else
{
newstr = (char *)mallocMagic(strlen(locstr)
+ strlen(propstr) + 2);
sprintf(newstr, "%s %s", propstr, locstr);
freeMagic(propstr);
}
propstr = newstr;
freeMagic(lrec);
lrec->r_r.r_xbot /= CIFCurStyle->cs_scaleFactor;
lrec->r_r.r_ybot /= CIFCurStyle->cs_scaleFactor;
lrec->r_r.r_xtop /= CIFCurStyle->cs_scaleFactor;
lrec->r_r.r_ytop /= CIFCurStyle->cs_scaleFactor;
DBPaintPlane(plane, &lrec->r_r, CIFPaintTable,
(PaintUndoInfo *)NULL);
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, lrec);
lrec = lrec->r_next;
}
/* NOTE: propstr is transferred to the CellDef and should
* not be free'd here.
*/
DBPropPut(cifReadCellDef, propname, propstr);
freeMagic1_end(&mm1);
}
freeMagic(propname);
}
@ -889,12 +993,14 @@ CIFPaintCurrent(
int
cifMakeBoundaryFunc(
Tile *tile, /* Tile of CIF information. */
TileType dinfo, /* Split tile information (unused) */
ClientData clientdata) /* Pass the file type (CIF or CALMA) */
{
/* It is assumed that there is one rectangle for the boundary. */
/* If there are multiple rectangles defined with the boundary */
/* layer, then the last one defines the FIXED_BBOX property. */
PropertyRecord *proprec;
Rect area;
char propertyvalue[128], *storedvalue;
int savescale;
@ -926,19 +1032,24 @@ cifMakeBoundaryFunc(
if (cifReadCellDef->cd_flags & CDFIXEDBBOX)
{
char *propvalue;
PropertyRecord *proprec;
bool found;
/* Only flag a warning if the redefined boundary was */
/* different from the original. */
propvalue = (char *)DBPropGet(cifReadCellDef, "FIXED_BBOX", &found);
proprec = DBPropGet(cifReadCellDef, "FIXED_BBOX", &found);
if (found)
{
Rect bbox;
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) == 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
if ((bbox.r_xbot != area.r_xbot) ||
(bbox.r_ybot != area.r_ybot) ||
(bbox.r_xtop != area.r_xtop) ||
@ -955,10 +1066,15 @@ cifMakeBoundaryFunc(
}
}
sprintf(propertyvalue, "%d %d %d %d",
area.r_xbot, area.r_ybot, area.r_xtop, area.r_ytop);
storedvalue = StrDup((char **)NULL, propertyvalue);
DBPropPut(cifReadCellDef, "FIXED_BBOX", storedvalue);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) + 2 * sizeof(int));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = 4;
proprec->prop_value.prop_integer[0] = area.r_xbot;
proprec->prop_value.prop_integer[1] = area.r_ybot;
proprec->prop_value.prop_integer[2] = area.r_xtop;
proprec->prop_value.prop_integer[3] = area.r_ytop;
DBPropPut(cifReadCellDef, "FIXED_BBOX", proprec);
cifReadCellDef->cd_flags |= CDFIXEDBBOX;
return 0;
}
@ -968,6 +1084,7 @@ cifMakeBoundaryFunc(
int
cifPaintCurrentFunc(
Tile *tile, /* Tile of CIF information. */
TileType dinfo, /* Split tile information */
TileType type) /* Magic type to be painted. */
{
Rect area;
@ -1017,7 +1134,7 @@ cifPaintCurrentFunc(
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; 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);
}
@ -1669,8 +1786,8 @@ CIFReadCellCleanup(
}
/* Do geometrical processing on the top-level cell. */
if (filetype == FILE_CIF) CIFPaintCurrent(filetype);
CIFPaintCurrent(FILE_CIF);
DBAdjustLabels(EditCellUse->cu_def, &TiPlaneRect);
DBReComputeBbox(EditCellUse->cu_def);
DBWAreaChanged(EditCellUse->cu_def, &EditCellUse->cu_def->cd_bbox,

View File

@ -244,40 +244,61 @@ CIFPropRecordPath(
{
extern float CIFGetOutputScale(int convert);
CIFPath *pathp;
char *pathstr, *sptr;
int components;
float x, y, oscale, mult;
char *namestr = NULL;
int components, i, x, y, mult, pathnum;
PropertyRecord *proprec;
bool propfound;
oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */
if (oscale == 0.0) oscale = 1.0;
mult = (iswire == TRUE) ? 0.5 : 1.0;
/* If "name" is a property, then append a suffix to it to ensure uniqueness */
DBPropGet(def, propname, &propfound);
if (propfound)
{
pathnum = 0;
namestr = mallocMagic(strlen(propname) + 10);
while (propfound)
{
sprintf(namestr, "%s_%d", propname, pathnum);
DBPropGet(def, namestr, &propfound);
pathnum++;
}
}
pathp = pathheadp;
components = 0;
mult = (iswire == TRUE) ? 1 : 0;
/* Count the number of components in the path */
pathp = pathheadp;
components = 0;
while (pathp != NULL)
{
pathp = pathp->cifp_next;
components++;
pathp = pathp->cifp_next;
}
/* Allocate enough space to hold 2 * N points at "infinity" */
pathstr = (char *)mallocMagic(components * 40);
/* Allocate enough space to hold 2 * N points. */
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
((components - 1) * 2) * sizeof(int));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = components * 2;
pathp = pathheadp;
sptr = pathstr;
i = 0;
while (pathp != NULL)
{
x = (float)pathp->cifp_x * oscale * mult;
y = (float)pathp->cifp_y * oscale * mult;
sprintf(sptr, "%.3f %.3f ", x, y);
sptr = sptr + strlen(sptr);
x = pathp->cifp_x >> mult;
y = pathp->cifp_y >> mult;
proprec->prop_value.prop_integer[i] = x;
proprec->prop_value.prop_integer[i + 1] = y;
i += 2;
pathp = pathp->cifp_next;
}
/* Reallocate pathstr to be no larger than needed to hold the path contents */
StrDup(&pathstr, pathstr);
DBPropPut(def, propname, (ClientData)pathstr);
if (namestr)
{
DBPropPut(def, namestr, proprec);
freeMagic(namestr);
}
else
DBPropPut(def, propname, proprec);
}
/*
@ -338,18 +359,20 @@ CIFPaintWirePath(
pathp = pathheadp->cifp_next;
if (pathp != NULL)
{
free_magic1_t mm1 = freeMagic1_init();
while (pathp->cifp_next != NULL)
{
if (pathp->cifp_next->cifp_x == pathp->cifp_x &&
pathp->cifp_next->cifp_y == pathp->cifp_y)
{
previousp->cifp_next = pathp->cifp_next;
freeMagic(pathp);
freeMagic1(&mm1, pathp);
}
else
previousp = pathp;
pathp = pathp->cifp_next;
}
freeMagic1_end(&mm1);
}
previousp = pathheadp;
@ -486,11 +509,13 @@ CIFPaintWirePath(
rectp = CIFPolyToRects(polypath, plane, ptable, ui, FALSE);
CIFFreePath(polypath);
free_magic1_t mm1 = freeMagic1_init();
for (; rectp != NULL ; rectp = rectp->r_next)
{
DBPaintPlane(plane, &rectp->r_r, ptable, ui);
freeMagic((char *) rectp);
freeMagic1(&mm1, (char *) rectp);
}
freeMagic1_end(&mm1);
polypath = NULL;
}
else
@ -588,11 +613,13 @@ PaintPolygon(
rectlist = CIFPolyToRects(cifpath, plane, ptable, ui, FALSE);
CIFFreePath(cifpath);
free_magic1_t mm1 = freeMagic1_init();
for (rectp = rectlist; rectp != NULL ; rectp = rectp->r_next)
{
DBPaintPlane(plane, &rectp->r_r, ptable, ui);
if (!keep) freeMagic((char *) rectp);
if (!keep) freeMagic1(&mm1, (char *) rectp);
}
freeMagic1_end(&mm1);
return (keep) ? rectlist : (LinkedRect *)NULL;
}
@ -821,11 +848,13 @@ CIFParsePoly(void)
CIFSkipToSemi();
return FALSE;
}
free_magic1_t mm1 = freeMagic1_init();
for (; rectp != NULL ; rectp = rectp->r_next)
{
DBPaintPlane(cifReadPlane, &rectp->r_r, CIFPaintTable,
(PaintUndoInfo *) NULL);
freeMagic((char *) rectp);
freeMagic1(&mm1, (char *) rectp);
}
freeMagic1_end(&mm1);
return TRUE;
}

View File

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

View File

@ -1338,11 +1338,13 @@ void
CIFFreePath(
CIFPath *path) /* Path to be freed. */
{
free_magic1_t mm1 = freeMagic1_init();
while (path != NULL)
{
freeMagic((char *) path);
freeMagic1(&mm1, (char *) path);
path = path->cifp_next;
}
freeMagic1_end(&mm1);
}
/*

View File

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

View File

@ -100,6 +100,7 @@ cifTechFreeStyle(void)
layer = CIFCurStyle->cs_layers[i];
if (layer != NULL)
{
free_magic1_t mm1 = freeMagic1_init();
for (op = layer->cl_ops; op != NULL; op = op->co_next)
{
if (op->co_client != (ClientData)NULL)
@ -120,8 +121,9 @@ cifTechFreeStyle(void)
break;
}
}
freeMagic((char *)op);
freeMagic1(&mm1, (char *)op);
}
freeMagic1_end(&mm1);
freeMagic((char *)layer);
}
}
@ -234,7 +236,7 @@ cifParseLayers(
*/
{
TileTypeBitMask curCifMask, curPaintMask;
char curLayer[40], *p, *cp;
char curLayer[512], *p, *cp;
TileType paintType;
int i;
bool allResidues;
@ -246,6 +248,10 @@ cifParseLayers(
{
p = curLayer;
if (*string == '(')
while ((*string != ')') && (*string != 0))
*p++ = *string++;
if (*string == '*')
{
allResidues = TRUE;
@ -263,7 +269,22 @@ cifParseLayers(
if (paintMask != NULL)
{
paintType = DBTechNameTypes(curLayer, &curPaintMask);
if (*curLayer == '(')
{
TileType t;
/* Layer groups with parentheses can only be paint types,
* and will be parsed accordingly. Residues will be
* handled within the group. Set paintType to -3, which
* is flagged and handled below.
*/
DBTechNoisyNameMask(curLayer, &curPaintMask);
paintType = -3;
allResidues = FALSE;
}
else
paintType = DBTechNameTypes(curLayer, &curPaintMask);
if (paintType >= 0) goto okpaint;
}
else paintType = -2;
@ -299,7 +320,7 @@ okpaint:
TechError("Ambiguous layer (type) \"%s\".\n", curLayer);
continue;
}
if (paintType >= 0)
if ((paintType >= 0) || (paintType == -3))
{
if (paintType == TT_SPACE && spaceOK ==0)
TechError("\"Space\" layer not permitted in CIF rules.\n");
@ -369,11 +390,13 @@ CIFTechInit(void)
/* forget the list of styles */
free_magic1_t mm1 = freeMagic1_init();
for (style = CIFStyleList; style != NULL; style = style->cs_next)
{
freeMagic(style->cs_name);
freeMagic(style);
freeMagic1(&mm1, style);
}
freeMagic1_end(&mm1);
CIFStyleList = NULL;
}
@ -794,7 +817,7 @@ CIFTechLine(
else
{
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;
return TRUE;
@ -1084,6 +1107,8 @@ CIFTechLine(
newOp->co_opcode = CIFOP_BBOX;
else if (strcmp(argv[0], "net") == 0)
newOp->co_opcode = CIFOP_NET;
else if (strcmp(argv[0], "tagged") == 0)
newOp->co_opcode = CIFOP_TAGGED;
else if (strcmp(argv[0], "maxrect") == 0)
newOp->co_opcode = CIFOP_MAXRECT;
else if (strcmp(argv[0], "boundary") == 0)
@ -1094,6 +1119,8 @@ CIFTechLine(
newOp->co_opcode = CIFOP_CLOSE;
else if (strcmp(argv[0], "orthogonal") == 0)
newOp->co_opcode = CIFOP_MANHATTAN;
else if (strcmp(argv[0], "not-square") == 0)
newOp->co_opcode = CIFOP_NOTSQUARE;
else if (strcmp(argv[0], "bridge") == 0)
newOp->co_opcode = CIFOP_BRIDGE;
else if (strcmp(argv[0], "bridge-lim") == 0)
@ -1332,6 +1359,7 @@ bloatCheck:
bloatDone: break;
case CIFOP_NET:
case CIFOP_TAGGED:
if (argc != 3) goto wrongNumArgs;
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
cifParseLayers(argv[2], CIFCurStyle, &newOp->co_paintMask,
@ -1646,12 +1674,12 @@ cifComputeRadii(
for (op = layer->cl_ops; op != NULL; op = op->co_next)
{
/* BBOX, NET, and MASKHINTS operators should never be used */
/* hierarchically so ignore any grow/shrink operators that */
/* BBOX, NET, TAGGED, and MASKHINTS operators should never be */
/* used hierarchically so ignore any grow/shrink operators that */
/* come after them. */
if (op->co_opcode == CIFOP_BBOX || op->co_opcode == CIFOP_NET ||
op->co_opcode == CIFOP_MASKHINTS)
op->co_opcode == CIFOP_TAGGED || op->co_opcode == CIFOP_MASKHINTS)
break;
/* If CIF layers are used, switch to the max of current
@ -1758,7 +1786,8 @@ cifComputeHalo(
if (maxGrow > maxShrink)
style->cs_radius = 2*maxGrow;
else style->cs_radius = 2*maxShrink;
style->cs_radius /= style->cs_scaleFactor;
if (style->cs_scaleFactor > 0)
style->cs_radius /= style->cs_scaleFactor;
style->cs_radius++;
/* TxPrintf("Radius for %s CIF is %d.\n",
@ -1962,8 +1991,8 @@ CIFTechFinal(void)
/* Presence of op->co_opcode in CIFOP_OR indicates a copy */
/* of the SquaresData pointer from a following operator. */
/* CIFOP_BBOX and CIFOP_MAXRECT uses the co_client field */
/* as a flag field, while CIFOP_NET and CIFOP_MASKHINTS */
/* uses it for a string. */
/* as a flag field, while CIFOP_NET, CIFOP_MASKHINTS, and */
/* CIFOP_TAGGED use it for a string. */
else
{
switch (op->co_opcode)
@ -1975,6 +2004,7 @@ CIFTechFinal(void)
case CIFOP_MAXRECT:
case CIFOP_MANHATTAN:
case CIFOP_NET:
case CIFOP_TAGGED:
break;
case CIFOP_BRIDGELIM:
case CIFOP_BRIDGE:
@ -2510,6 +2540,7 @@ CIFTechOutputScale(
case CIFOP_MAXRECT:
case CIFOP_MANHATTAN:
case CIFOP_NET:
case CIFOP_TAGGED:
case CIFOP_INTERACT:
break;
case CIFOP_BRIDGELIM:
@ -2625,8 +2656,8 @@ CIFTechOutputScale(
default:
/* op->co_opcode in CIFOP_OR is a pointer copy, */
/* in CIFOP_BBOX and CIFOP_MAXRECT is a flag, */
/* and in CIFOP_NET and CIFOP_MASKHINTS is a */
/* string. */
/* and in CIFOP_NET, CIFOP_MASKHINTS, and */
/* CIFOP_TAGGED is a string. */
break;
}
}

View File

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

View File

@ -81,6 +81,70 @@ CmdAddPath(
PaAppend(&Path, cmd->tx_argv[1]);
}
/*
* ----------------------------------------------------------------------------
*
* CmdArchive --
*
* Save an entire database to a "crash recovery"-type archive file, or
* load a database from a "crash recovery"-type archive file. Option
* "writeall" writes everything, including read-only PDK cells, while
* "readref" does not dereference and will prefer files found in the
* search path over content in the archive.
*
*
* Usage:
* archive write|writeall|read|readref file
*
* Results:
* None.
*
* Side effects:
* Writes a single file with the contents of the entire database,
* or loads the database with multiple cells from the file.
*
* ----------------------------------------------------------------------------
*/
void
CmdArchive(
MagWindow *w,
TxCommand *cmd)
{
int option = -1;
char *filename = NULL;
static const char * const cmdArchiveOpt[] = {"write", "writeall",
"read", "readref", 0};
if (cmd->tx_argc != 3)
TxError("Usage: %s write|writeall|read|readref filename\n", cmd->tx_argv[0]);
else
{
option = Lookup(cmd->tx_argv[1], cmdArchiveOpt);
if (option < 0)
{
TxError("Usage: %s write|writeall|read|readref filename\n", cmd->tx_argv[0]);
return;
}
}
filename = cmd->tx_argv[2];
switch(option) {
case 0: /* write */
DBWriteBackup(filename, TRUE, FALSE);
break;
case 1: /* writeall */
DBWriteBackup(filename, TRUE, TRUE);
break;
case 2: /* read */
DBReadBackup(filename, TRUE, TRUE);
break;
case 3: /* readref */
DBReadBackup(filename, TRUE, FALSE);
break;
}
}
/* Linked-list structure for returning information about arrayed cells */
@ -274,14 +338,17 @@ CmdArray(
case ARRAY_WIDTH:
if (locargc == 2)
{
char *xsepvalue;
for (la = lahead; la != NULL; la = la->ar_next)
{
xsepvalue = DBWPrintValue(la->arrayInfo.ar_xsep,
w, TRUE);
#ifdef MAGIC_WRAPPER
if (doList)
{
tobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewIntObj(la->arrayInfo.ar_xsep));
Tcl_NewStringObj(xsepvalue, -1));
Tcl_SetObjResult(magicinterp, tobj);
}
else
@ -291,7 +358,7 @@ CmdArray(
TxPrintf("Cell use \"%s\":", la->cellUse->cu_id);
else
TxPrintf("Cell \"%s\":", la->cellUse->cu_def->cd_name);
TxPrintf("x separation %d\n", la->arrayInfo.ar_xsep);
TxPrintf("x separation %s\n", xsepvalue);
#ifdef MAGIC_WRAPPER
}
#endif
@ -310,14 +377,17 @@ CmdArray(
case ARRAY_HEIGHT:
if (locargc == 2)
{
char *ysepvalue;
for (la = lahead; la != NULL; la = la->ar_next)
{
ysepvalue = DBWPrintValue(la->arrayInfo.ar_ysep,
w, FALSE);
#ifdef MAGIC_WRAPPER
if (doList)
{
tobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewIntObj(la->arrayInfo.ar_ysep));
Tcl_NewStringObj(ysepvalue, -1));
Tcl_SetObjResult(magicinterp, tobj);
}
else
@ -327,7 +397,7 @@ CmdArray(
TxPrintf("Cell use \"%s\":", la->cellUse->cu_id);
else
TxPrintf("Cell \"%s\":", la->cellUse->cu_def->cd_name);
TxPrintf("y separation %d\n", la->arrayInfo.ar_ysep);
TxPrintf("y separation %s\n", ysepvalue);
#ifdef MAGIC_WRAPPER
}
#endif
@ -346,16 +416,21 @@ CmdArray(
case ARRAY_PITCH:
if (locargc == 2)
{
char *xpitch, *ypitch;
for (la = lahead; la != NULL; la = la->ar_next)
{
xpitch = DBWPrintValue(la->arrayInfo.ar_xsep,
w, TRUE);
ypitch = DBWPrintValue(la->arrayInfo.ar_ysep,
w, FALSE);
#ifdef MAGIC_WRAPPER
if (doList)
{
tobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewIntObj(la->arrayInfo.ar_xsep));
Tcl_NewStringObj(xpitch, -1));
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewIntObj(la->arrayInfo.ar_ysep));
Tcl_NewStringObj(ypitch, -1));
Tcl_SetObjResult(magicinterp, tobj);
}
else
@ -365,8 +440,8 @@ CmdArray(
TxPrintf("Cell use \"%s\":", la->cellUse->cu_id);
else
TxPrintf("Cell \"%s\":", la->cellUse->cu_def->cd_name);
TxPrintf("x separation %d ", la->arrayInfo.ar_xsep);
TxPrintf("y separation %d\n", la->arrayInfo.ar_ysep);
TxPrintf("x separation %s ", xpitch);
TxPrintf("y separation %s\n", ypitch);
#ifdef MAGIC_WRAPPER
}
#endif
@ -386,16 +461,21 @@ CmdArray(
case ARRAY_POSITION:
if (locargc == 2)
{
char *xpos, *ypos;
for (la = lahead; la != NULL; la = la->ar_next)
{
xpos = DBWPrintValue(la->cellUse->cu_bbox.r_xbot,
w, TRUE);
ypos = DBWPrintValue(la->cellUse->cu_bbox.r_ybot,
w, FALSE);
#ifdef MAGIC_WRAPPER
if (doList)
{
tobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewIntObj(la->cellUse->cu_bbox.r_xbot));
Tcl_NewStringObj(xpos, -1));
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewIntObj(la->cellUse->cu_bbox.r_ybot));
Tcl_NewStringObj(ypos, -1));
Tcl_SetObjResult(magicinterp, tobj);
}
else
@ -405,8 +485,8 @@ CmdArray(
TxPrintf("Cell use \"%s\":", la->cellUse->cu_id);
else
TxPrintf("Cell \"%s\":", la->cellUse->cu_def->cd_name);
TxPrintf("x=%d ", la->cellUse->cu_bbox.r_xbot);
TxPrintf("y=%d\n", la->cellUse->cu_bbox.r_ybot);
TxPrintf("x=%s ", xpos);
TxPrintf("y=%s\n", ypos);
#ifdef MAGIC_WRAPPER
}
#endif
@ -466,11 +546,15 @@ badusage:
}
freelist:
la = lahead;
while (la != NULL)
{
freeMagic((char *)la);
la = la->ar_next;
la = lahead;
while (la != NULL)
{
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, (char *)la);
la = la->ar_next;
freeMagic1_end(&mm1);
}
}
return;
}
@ -695,8 +779,8 @@ CmdBox(
break;
case BOX_EXISTS:
#ifdef MAGIC_WRAPPER
Tcl_SetResult(magicinterp, ToolGetBox(NULL, NULL) ? "1" : "0",
NULL);
Tcl_SetObjResult(magicinterp,
Tcl_NewBooleanObj(ToolGetBox(NULL, NULL) ? TRUE : FALSE));
#else
TxPrintf("%s\n", ToolGetBox(NULL, NULL) ? "True" : "False");
#endif
@ -806,13 +890,16 @@ CmdBox(
TxRebuildCommand(cmd);
return;
}
else if (DBWSnapToGrid != DBW_SNAP_USER)
else if (DBWUnits != DBW_UNITS_USER)
{
distancex = cmdParseCoord(w, cmd->tx_argv[3], TRUE, FALSE);
distancey = distancex;
}
else
{
/* For user units, the distance may be different in the X and Y
* directions for a given value.
*/
switch (direction)
{
case GEO_EAST: case GEO_WEST:
@ -840,15 +927,14 @@ CmdBox(
case BOX_WIDTH:
if (argc == 2)
{
char *boxvalues;
boxvalues = DBWPrintValue(boxptr->r_xtop - boxptr->r_xbot,
w, TRUE);
#ifdef MAGIC_WRAPPER
char *boxvalues = (char *)Tcl_Alloc(50);
sprintf(boxvalues, "%d",
boxptr->r_xtop - boxptr->r_xbot);
Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC);
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(boxvalues, -1));
#else
TxPrintf("%s box width is %d\n",
(refEdit) ? "Edit" : "Root",
boxptr->r_xtop - boxptr->r_xbot);
TxPrintf("%s box width is %s\n", (refEdit) ? "Edit" : "Root",
boxvalues);
#endif
return;
}
@ -860,15 +946,14 @@ CmdBox(
case BOX_HEIGHT:
if (argc == 2)
{
char *boxvalues;
boxvalues = DBWPrintValue(boxptr->r_ytop - boxptr->r_ybot,
w, FALSE);
#ifdef MAGIC_WRAPPER
char *boxvalues = (char *)Tcl_Alloc(50);
sprintf(boxvalues, "%d",
boxptr->r_ytop - boxptr->r_ybot);
Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC);
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(boxvalues, -1));
#else
TxPrintf("%s box height is %d\n",
(refEdit) ? "Edit" : "Root",
boxptr->r_ytop - boxptr->r_ybot);
TxPrintf("%s box height is %s\n", (refEdit) ? "Edit" : "Root",
boxvalues);
#endif
return;
}
@ -881,16 +966,24 @@ CmdBox(
if (argc == 2)
{
#ifdef MAGIC_WRAPPER
char *boxvalues = (char *)Tcl_Alloc(50);
sprintf(boxvalues, "%d %d",
boxptr->r_xtop - boxptr->r_xbot,
boxptr->r_ytop - boxptr->r_ybot);
Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC);
Tcl_Obj *tobj;
#endif
char *boxvaluex, *boxvaluey;
boxvaluex = DBWPrintValue(boxptr->r_xtop - boxptr->r_xbot,
w, TRUE);
boxvaluey = DBWPrintValue(boxptr->r_ytop - boxptr->r_ybot,
w, FALSE);
#ifdef MAGIC_WRAPPER
tobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(boxvaluex, -1));
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(boxvaluey, -1));
Tcl_SetObjResult(magicinterp, tobj);
#else
TxPrintf("%s box size is %d x %d\n",
TxPrintf("%s box size is %s x %s\n",
(refEdit) ? "Edit" : "Root",
boxptr->r_xtop - boxptr->r_xbot,
boxptr->r_ytop - boxptr->r_ybot);
boxvaluex, boxvaluey);
#endif
return;
}
@ -905,14 +998,22 @@ CmdBox(
if (argc == 2)
{
#ifdef MAGIC_WRAPPER
char *boxvalues = (char *)Tcl_Alloc(50);
sprintf(boxvalues, "%d %d",
boxptr->r_xbot, boxptr->r_ybot);
Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC);
Tcl_Obj *tobj;
#endif
char *boxvaluex, *boxvaluey;
boxvaluex = DBWPrintValue(boxptr->r_xbot, w, TRUE);
boxvaluey = DBWPrintValue(boxptr->r_ybot, w, FALSE);
#ifdef MAGIC_WRAPPER
tobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(boxvaluex, -1));
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(boxvaluey, -1));
Tcl_SetObjResult(magicinterp, tobj);
#else
TxPrintf("%s box lower-left corner at (%d, %d)\n",
TxPrintf("%s box lower-left corner at (%s, %s)\n",
(refEdit) ? "Edit" : "Root",
boxptr->r_xbot, boxptr->r_ybot);
boxvaluex, boxvaluey);
#endif
return;
}
@ -944,16 +1045,31 @@ CmdBox(
if (argc == 2)
{
#ifdef MAGIC_WRAPPER
char *boxvalues = (char *)Tcl_Alloc(50);
sprintf(boxvalues, "%d %d %d %d",
boxptr->r_xbot, boxptr->r_ybot,
boxptr->r_xtop, boxptr->r_ytop);
Tcl_SetResult(magicinterp, boxvalues, TCL_DYNAMIC);
Tcl_Obj *tobj;
#endif
char *boxvaluellx, *boxvaluelly;
char *boxvalueurx, *boxvalueury;
boxvaluellx = DBWPrintValue(boxptr->r_xbot, w, TRUE);
boxvaluelly = DBWPrintValue(boxptr->r_ybot, w, FALSE);
boxvalueurx = DBWPrintValue(boxptr->r_xtop, w, TRUE);
boxvalueury = DBWPrintValue(boxptr->r_ytop, w, FALSE);
#ifdef MAGIC_WRAPPER
tobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(boxvaluellx, -1));
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(boxvaluelly, -1));
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(boxvalueurx, -1));
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(boxvalueury, -1));
Tcl_SetObjResult(magicinterp, tobj);
#else
TxPrintf("%s box coordinates (%d, %d) to (%d, %d)\n",
TxPrintf("%s box coordinates (%s, %s) to (%s, %s)\n",
(refEdit) ? "Edit" : "Root",
boxptr->r_xbot, boxptr->r_ybot,
boxptr->r_xtop, boxptr->r_ytop);
boxvaluellx, boxvaluelly, boxvalueurx, boxvalueury);
#endif
return;
}

View File

@ -117,12 +117,13 @@ bool cmdDumpParseArgs(char *cmdName, MagWindow *w, TxCommand *cmd, CellUse *dumm
#define CALMA_READ 19
#define CALMA_READONLY 20
#define CALMA_RESCALE 21
#define CALMA_WARNING 22
#define CALMA_WRITE 23
#define CALMA_POLYS 24
#define CALMA_PATHS 25
#define CALMA_UNDEFINED 26
#define CALMA_UNIQUE 27
#define CALMA_SAVEPATHS 22
#define CALMA_WARNING 23
#define CALMA_WRITE 24
#define CALMA_POLYS 25
#define CALMA_PATHS 26
#define CALMA_UNDEFINED 27
#define CALMA_UNIQUE 28
#define CALMA_WARN_HELP CIF_WARN_END /* undefined by CIF module */
@ -175,6 +176,7 @@ CmdCalma(
" into edit cell",
"readonly [yes|no] set cell as read-only and generate output from GDS file",
"rescale [yes|no] allow or disallow internal grid subdivision",
"savepaths [yes|no] save path centerlines as cell properties",
"warning [option] set warning information level",
"write file output Calma GDS-II format to \"file\"\n"
" for the window's root cell",
@ -431,7 +433,7 @@ CmdCalma(
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewDoubleObj((double)CalmaMagScale));
#else
TxPrintf("Text magnification 1.0 = %g microns.\n");
TxPrintf("Text magnification 1.0 = %g microns.\n", (double)CalmaMagScale);
#endif
return;
}
@ -738,13 +740,34 @@ CmdCalma(
CalmaSubcellPolygons = (unsigned char)option;
return;
case CALMA_SAVEPATHS:
if (cmd->tx_argc == 2)
{
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(CalmaRecordPaths));
#else
TxPrintf("Paths in GDS cells read from input file are%s recorded"
" as cell properties.\n",
(CalmaRecordPaths) ? " " : " not");
#endif
return;
}
else if (cmd->tx_argc != 3)
goto wrongNumArgs;
option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo);
if (option < 0)
goto wrongNumArgs;
CalmaRecordPaths = (option < 4) ? FALSE : TRUE;
return;
case CALMA_NO_DUP:
if (cmd->tx_argc == 2)
{
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(CalmaNoDuplicates));
#else
TxPrintf("Cell defs that exist before reading GDS will not be paresd.\n",
TxPrintf("Cell defs that exist before reading GDS will %sbe parsed.\n",
(CalmaNoDuplicates) ? "not " : "");
#endif
return;
@ -764,7 +787,7 @@ CmdCalma(
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(CalmaUnique));
#else
TxPrintf("Cell defs that exist before reading GDS will be renamed.\n",
TxPrintf("Cell defs that exist before reading GDS will %sbe renamed.\n",
(CalmaUnique) ? "not " : "");
#endif
return;
@ -1300,7 +1323,7 @@ CmdCellname(
if (cellDef == (CellDef *) NULL)
TxError("Unknown cell %s\n", cellname);
else
CmdDoProperty(cellDef, cmd, 3 + ((dolist) ? 1 : 0));
CmdDoProperty(cellDef, w, cmd, 3 + ((dolist) ? 1 : 0));
break;
case IDX_DELETE:
@ -2396,8 +2419,10 @@ CmdContact(
CCStruct ccs;
Rect area;
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);
if ((w == (MagWindow *) NULL) || (w->w_client != DBWclientID))
@ -2455,6 +2480,7 @@ CmdContact(
rmask = DBResidueMask(type);
free_magic1_t mm1 = freeMagic1_init();
while (lr != NULL)
{
GeoClip(&lr->r_r, &area);
@ -2465,9 +2491,10 @@ CmdContact(
if (TTMaskHasType(rmask, rtype))
DBPaint(EditCellUse->cu_def, &lr->r_r, rtype);
freeMagic(lr);
freeMagic1(&mm1, lr);
lr = lr->r_next;
}
freeMagic1_end(&mm1);
/* Refresh the layout drawing */
DBWAreaChanged(EditCellUse->cu_def, &area, DBW_ALLWINDOWS, &smask);
@ -2504,14 +2531,16 @@ CmdContact(
DBSrPaintArea((Tile *) NULL, EditCellUse->cu_def->cd_planes[DBPlane(rtype)],
&area, &smask, cmdContactFunc, (ClientData) &ccs);
free_magic1_t mm1 = freeMagic1_init();
while (ccs.lhead != NULL)
{
TTMaskSetOnlyType(&smask, type);
TTMaskAndMask(&smask, &DBActiveLayerBits);
DBPaintMask(EditCellUse->cu_def, &ccs.lhead->r_r, &smask);
freeMagic(ccs.lhead);
freeMagic1(&mm1, ccs.lhead);
ccs.lhead = ccs.lhead->r_next;
}
freeMagic1_end(&mm1);
/* Refresh the layout drawing */
DBWAreaChanged(EditCellUse->cu_def, &area, DBW_ALLWINDOWS, &smask);
@ -2527,11 +2556,14 @@ CmdContact(
int
cmdContactFunc(
Tile *tile,
TileType dinfo,
CCStruct *ccs)
{
TileType stype;
TileTypeBitMask smask;
int cmdContactFunc2(Tile *tile, CCStruct *ccs); /* Forward declaration */
/* Forward declaration */
int cmdContactFunc2(Tile *tile, TileType dinfo, CCStruct *ccs);
TiToRect(tile, &ccs->area);
GeoClip(&ccs->area, &ccs->clip);
@ -2541,14 +2573,16 @@ cmdContactFunc(
break;
TTMaskSetOnlyType(&smask, stype);
DBSrPaintArea((Tile *) NULL, ccs->rootDef->cd_planes[DBPlane(stype)],
&ccs->area, &smask, cmdContactFunc2, (ClientData)ccs);
DBSrPaintNMArea((Tile *)NULL, ccs->rootDef->cd_planes[DBPlane(stype)],
TiGetTypeExact(tile) | dinfo, &ccs->area, &smask,
cmdContactFunc2, (ClientData)ccs);
return 0;
}
int
cmdContactFunc2(
Tile *tile,
TileType dinfo, /* (unused) */
CCStruct *ccs)
{
LinkedRect *newlr;
@ -2571,6 +2605,7 @@ cmdContactFunc2(
int
cmdContactEraseFunc(
Tile *tile,
TileType dinfo, /* (unused) */
LinkedRect **lr)
{
LinkedRect *newlr;
@ -2824,14 +2859,15 @@ CmdCorner(
TileTypeBitMask maskBits;
Rect editBox;
SearchContext scx;
extern int cmdCornerFunc(Tile *tile, TreeContext *cxp);
bool hasErr = FALSE;
int locargc = cmd->tx_argc;
extern int cmdBevelFunc(Tile *tile, TreeContext *cxp);
bool dobevel = FALSE;
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)
{
TxError("Usage: %s direction1 direction2 [layers]\n",
@ -2952,14 +2988,22 @@ CmdCorner(
rectp = CIFPolyToRects(cmdPathList.pathlist->pathhead, plane,
resultTbl, &ui, FALSE);
for (; rectp != NULL; rectp = rectp->r_next)
{
DBPaintPlane(plane, &rectp->r_r, resultTbl, &ui);
freeMagic((char *)rectp);
free_magic1_t mm1 = freeMagic1_init();
for (; rectp != NULL; rectp = rectp->r_next)
{
DBPaintPlane(plane, &rectp->r_r, resultTbl, &ui);
freeMagic1(&mm1, (char *)rectp);
}
freeMagic1_end(&mm1);
}
CIFFreePath(cmdPathList.pathlist->pathhead);
freeMagic((char *)cmdPathList.pathlist);
cmdPathList.pathlist = cmdPathList.pathlist->cpl_next;
{
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, (char *)cmdPathList.pathlist);
cmdPathList.pathlist = cmdPathList.pathlist->cpl_next;
freeMagic1_end(&mm1);
}
}
}
else
@ -2977,14 +3021,16 @@ CmdCorner(
/* Now that we've got all the material, scan over the list
* painting the material and freeing up the entries on the list.
*/
free_magic1_t mm1 = freeMagic1_init();
while (cmdCornerList != NULL)
{
DBPaint(EditCellUse->cu_def, &cmdCornerList->cca_area,
cmdCornerList->cca_type);
freeMagic((char *) cmdCornerList);
freeMagic1(&mm1, (char *) cmdCornerList);
cmdCornerList = cmdCornerList->cca_next;
}
}
freeMagic1_end(&mm1);
}
SelectClear();
DBAdjustLabels(EditCellUse->cu_def, &editBox);
@ -3016,6 +3062,7 @@ CmdCorner(
int
cmdCornerFunc(
Tile *tile, /* Tile to fill with. */
TileType dinfo, /* Split tile information (unused) */
TreeContext *cxp) /* Describes state of search. */
{
Rect r1, r2, r3;
@ -3182,6 +3229,7 @@ AddNewPoint(
int
cmdBevelFunc(
Tile *tile, /* Tile to fill with. */
TileType dinfo, /* Split tile information (unused) */
TreeContext *cxp) /* Describes state of search. */
{
Rect r1, r2, r3;
@ -3643,8 +3691,10 @@ cmdBevelFunc(
GeoClip(&r3, &cmdCornerRootBox);
if (GEO_RECTNULL(&r2) || GEO_RECTNULL(&r3))
{
free_magic1_t mm1 = freeMagic1_init();
for (pptr = pathhead; pptr != NULL; pptr = pptr->cifp_next)
freeMagic((char *)pptr);
freeMagic1(&mm1, (char *)pptr);
freeMagic1_end(&mm1);
return 0;
}
@ -3678,7 +3728,7 @@ cmdBevelFunc(
* Save cells to or recover cells from a crash backup file
*
* Usage:
* crash save|recover [file]
* crash save|recover|archive|read [file]
*
* Results:
* None.
@ -3713,7 +3763,7 @@ CmdCrash(
switch(option) {
case 0: /* save */
DBWriteBackup(filename);
DBWriteBackup(filename, FALSE, FALSE);
break;
case 1: /* recover */
DBFileRecovery(filename);
@ -4154,6 +4204,7 @@ CmdDrc(
rootUse = (CellUse *) window->w_surfaceID;
dcl = DRCCount(rootUse, &rootArea, doforall);
free_magic1_t mm1 = freeMagic1_init();
while (dcl != NULL)
{
if (count_total >= 0)
@ -4183,9 +4234,10 @@ CmdDrc(
}
#endif
}
freeMagic((char *)dcl);
freeMagic1(&mm1, (char *)dcl);
dcl = dcl->dcl_next;
}
freeMagic1_end(&mm1);
#ifdef MAGIC_WRAPPER
if ((count_total >= 0) || (!dolist))
@ -4308,6 +4360,8 @@ CmdDrc(
#endif
TxPrintf("Error area #%d:\n", result);
if (DRCWhy(dolist, rootUse, &area, findonly)) break;
/* Check for interrupt or this will go into an infinite loop */
else if (SigInterruptPending) break;
drc_nth++;
}
else if (result < 0)
@ -4334,12 +4388,14 @@ CmdDrc(
}
if (findonly)
{
free_magic1_t mm1 = freeMagic1_init();
/* Delete temporary rules */
while (DRCIgnoreRules != NULL)
{
freeMagic(DRCIgnoreRules);
freeMagic1(&mm1, DRCIgnoreRules);
DRCIgnoreRules = DRCIgnoreRules->li_next;
}
freeMagic1_end(&mm1);
/* Replace temporary set of rules */
DRCIgnoreRules = DRCSaveRules;
}
@ -4422,8 +4478,10 @@ CmdDrc(
{
while (DRCIgnoreRules != NULL)
{
freeMagic(DRCIgnoreRules);
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, DRCIgnoreRules);
DRCIgnoreRules = DRCIgnoreRules->li_next;
freeMagic1_end(&mm1);
}
}
else
@ -4561,6 +4619,7 @@ CmdDrc(
int
cmdDropPaintCell(
Tile *tile,
TileType dinfo,
TreeContext *cxp)
{
CellDef *cellDef = cxp->tc_scx->scx_use->cu_def;
@ -4569,7 +4628,7 @@ cmdDropPaintCell(
TileType type;
Rect area;
if (SplitSide(tile))
if (dinfo & TT_SIDE)
type = SplitRightType(tile);
else
type = SplitLeftType(tile);
@ -4602,6 +4661,7 @@ cmdDropPaintCell(
int
cmdDropFunc(
Tile *tile,
TileType dinfo,
ClientData clientData)
{
TileTypeBitMask tMask, *lMask = (TileTypeBitMask *)clientData;
@ -4612,7 +4672,7 @@ cmdDropFunc(
scx.scx_use = EditCellUse;
scx.scx_trans = GeoIdentityTransform;
if (SplitSide(tile))
if (dinfo & TT_SIDE)
type = SplitRightType(tile);
else
type = SplitLeftType(tile);
@ -4954,15 +5014,20 @@ cmdDumpParseArgs(
bbox = def->cd_bbox;
if (def->cd_flags & CDFIXEDBBOX)
{
char *propvalue;
PropertyRecord *proprec;
bool found;
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &found);
proprec = DBPropGet(def, "FIXED_BBOX", &found);
if (found)
{
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) != 4)
bbox = def->cd_bbox;
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
}
}
}

View File

@ -781,39 +781,82 @@ cmdEraseCellsFunc(
* Implement the "expand" command.
*
* Usage:
* expand
* expand toggle
* expand [selection|surround|overlap|all] [toggle]
*
* "selection" expands cells in the selection. All other options
* expand cells in the layout. "all" expands all cells in the
* layout. "surround" expands cells which the cursor box
* surrounds completely, and "overlap" expands cells which the
* cursor box overlaps.
*
* If "toggle" is specified, flips the expanded/unexpanded status.
* Cells which were expanded are unexpanded, and cells which were
* unexpanded are expanded.
*
* For backwards compatibility:
* "expand" alone implements "expand overlap".
* "expand toggle" implements "expand selection toggle".
*
* Also see: CmdUnexpand
*
* Results:
* None.
*
* Side effects:
* If "toggle" is specified, flips the expanded/unexpanded status
* of all selected cells. Otherwise, aren't any unexpanded cells
* left under the box. May read cells in from disk, and updates
* bounding boxes that have changed.
* Expansion state of cells is changed. May read cells in from
* disk, and update bounding boxes that have changed.
*
* ----------------------------------------------------------------------------
*/
#define EXPAND_SELECTION 0
#define EXPAND_SURROUND 1
#define EXPAND_OVERLAP 2
#define EXPAND_ALL 3
#define EXPAND_HELP 4
void
CmdExpand(
MagWindow *w,
TxCommand *cmd)
{
int windowMask, boxMask, d;
int windowMask, boxMask, d, option;
bool doToggle = FALSE;
const char * const *msg;
Rect rootRect;
CellUse *rootBoxUse;
CellDef *rootBoxDef;
int cmdExpandFunc(CellUse *use, int windowMask); /* Forward reference. */
if (cmd->tx_argc > 2 || (cmd->tx_argc == 2
&& (strncmp(cmd->tx_argv[1], "toggle", strlen(cmd->tx_argv[1])) != 0)))
static const char * const cmdExpandOption[] = {
"selection expand cell instances in the selection",
"surround expand cell instances which the cursor box surrounds",
"overlap expand cell instances which the cursor box overlaps",
"all expand all cell instances",
NULL
};
if (cmd->tx_argc > 1)
{
TxError("Usage: %s or %s toggle\n", cmd->tx_argv[0], cmd->tx_argv[0]);
return;
if (!strncmp(cmd->tx_argv[cmd->tx_argc - 1], "toggle",
strlen(cmd->tx_argv[cmd->tx_argc - 1])))
{
doToggle = TRUE;
cmd->tx_argc--;
}
}
if (cmd->tx_argc > 1)
{
option = Lookup(cmd->tx_argv[1], cmdExpandOption);
if (option < 0) option = EXPAND_HELP;
}
else
option = EXPAND_OVERLAP;
if (option == EXPAND_HELP) goto badusage;
windCheckOnlyWindow(&w, DBWclientID);
if (w == (MagWindow *) NULL)
{
@ -844,23 +887,95 @@ CmdExpand(
WindScale(d, 1);
TxPrintf("expand: rescaled by %d\n", d);
d = DBLambda[1];
if (cmd->tx_argc == 2) break; /* Don't toggle twice */
if (doToggle) break; /* Don't toggle twice */
}
(void) ToolGetBoxWindow(&rootRect, &boxMask);
if (cmd->tx_argc == 2)
SelectExpand(windowMask);
else
if (option != EXPAND_SELECTION)
{
if ((boxMask & windowMask) != windowMask)
{
TxError("The box isn't in the same window as the cursor.\n");
return;
}
DBExpandAll(rootBoxUse, &rootRect, windowMask,
TRUE, cmdExpandFunc, (ClientData)(pointertype) windowMask);
}
switch (option)
{
case EXPAND_SELECTION:
SelectExpand(windowMask,
(doToggle) ? DB_EXPAND_TOGGLE : DB_EXPAND,
(Rect *)NULL, FALSE);
break;
case EXPAND_OVERLAP:
if (doToggle)
{
DBExpandAll(rootBoxUse, &rootRect, windowMask,
DB_EXPAND_TOGGLE | DB_EXPAND_OVERLAP,
cmdExpandFunc, (ClientData)(pointertype)windowMask);
SelectExpand(windowMask,
DB_EXPAND_TOGGLE | DB_EXPAND_OVERLAP,
&rootRect, FALSE);
}
else
{
DBExpandAll(rootBoxUse, &rootRect, windowMask,
DB_EXPAND | DB_EXPAND_OVERLAP,
cmdExpandFunc, (ClientData)(pointertype)windowMask);
SelectExpand(windowMask,
DB_EXPAND | DB_EXPAND_OVERLAP,
&rootRect, FALSE);
}
break;
case EXPAND_SURROUND:
if (doToggle)
{
DBExpandAll(rootBoxUse, &rootRect, windowMask,
DB_EXPAND_TOGGLE | DB_EXPAND_SURROUND,
cmdExpandFunc, (ClientData)(pointertype)windowMask);
SelectExpand(windowMask,
DB_EXPAND_TOGGLE | DB_EXPAND_SURROUND,
&rootRect, TRUE);
}
else
{
DBExpandAll(rootBoxUse, &rootRect, windowMask,
DB_EXPAND | DB_EXPAND_SURROUND,
cmdExpandFunc, (ClientData)(pointertype)windowMask);
SelectExpand(windowMask,
DB_EXPAND | DB_EXPAND_SURROUND,
&rootRect, TRUE);
}
break;
case EXPAND_ALL:
if (doToggle)
{
DBExpandAll(rootBoxUse, &TiPlaneRect, windowMask,
DB_EXPAND | DB_EXPAND_OVERLAP,
cmdExpandFunc, (ClientData)(pointertype)windowMask);
SelectExpand(windowMask,
DB_EXPAND | DB_EXPAND_OVERLAP,
(Rect *)NULL, FALSE);
}
else
{
DBExpandAll(rootBoxUse, &TiPlaneRect, windowMask,
DB_EXPAND | DB_EXPAND_OVERLAP,
cmdExpandFunc, (ClientData)(pointertype)windowMask);
SelectExpand(windowMask,
DB_EXPAND | DB_EXPAND_OVERLAP,
(Rect *)NULL, FALSE);
}
break;
}
} while (d != DBLambda[1]);
return;
badusage:
for (msg = &(cmdExpandOption[0]); *msg != NULL; msg++)
TxPrintf(" %s\n", *msg);
TxPrintf(" toggle Toggle the visibility of cell instances.\n");
}
/* This function is called for each cell whose expansion status changed.
@ -925,11 +1040,14 @@ cmdExpandFunc(
#define DOALL 1
#define DOCAPACITANCE 2
#define DOCOUPLING 3
#define DOLENGTH 4
#define DOLOCAL 5
#define DORESISTANCE 6
#define DOLABELCHECK 7
#define DOALIASES 8
#define DOEXTRESIST 4
#define DOLENGTH 5
#define DOLOCAL 6
#define DORESISTANCE 7
#define DOLABELCHECK 8
#define DOALIASES 9
#define DOUNIQUE 10
#define DOEXTRESIST2 11
#define LENCLEAR 0
#define LENDRIVER 1
@ -972,11 +1090,14 @@ CmdExtract(
"all all options",
"capacitance extract substrate capacitance",
"coupling extract coupling capacitance",
"extresist extract resistance",
"length compute driver-receiver pathlengths",
"local put all generated files in the current directory",
"resistance estimate resistance",
"lumped estimate lumped resistance",
"labelcheck check for connections through sticky labels",
"aliases output all net name aliases",
"unique ensure unique node names during extraction",
"resistance extract resistance (same as \"do extresist\")",
NULL
};
static const char * const cmdExtLength[] =
@ -1120,12 +1241,13 @@ CmdExtract(
}
else if (argc == 2)
{
char *halodisp;
halodisp = DBWPrintValue(ExtCurStyle->exts_sideCoupleHalo,
w, TRUE);
#ifdef MAGIC_WRAPPER
Tcl_Obj *tobj;
tobj = Tcl_NewIntObj(ExtCurStyle->exts_sideCoupleHalo);
Tcl_SetObjResult(magicinterp, tobj);
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(halodisp, -1));
#else
TxPrintf("Side overlap halo is %d\n", ExtCurStyle->exts_sideCoupleHalo);
TxPrintf("Side overlap halo is %s\n", halodisp);
#endif
return;
}
@ -1150,12 +1272,12 @@ CmdExtract(
}
else if (argc == 2)
{
char *stepdisp;
stepdisp = DBWPrintValue(ExtCurStyle->exts_stepSize, w, TRUE);
#ifdef MAGIC_WRAPPER
Tcl_Obj *tobj;
tobj = Tcl_NewIntObj(ExtCurStyle->exts_stepSize);
Tcl_SetObjResult(magicinterp, tobj);
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(stepdisp, -1));
#else
TxPrintf("Extraction step size is %d\n", ExtCurStyle->exts_stepSize);
TxPrintf("Extraction step size is %s\n", stepdisp);
#endif
return;
}
@ -1277,9 +1399,11 @@ CmdExtract(
TxPrintf("%s capacitance\n", OPTSET(EXT_DOCAPACITANCE));
TxPrintf("%s coupling\n", OPTSET(EXT_DOCOUPLING));
TxPrintf("%s length\n", OPTSET(EXT_DOLENGTH));
TxPrintf("%s resistance\n", OPTSET(EXT_DORESISTANCE));
TxPrintf("%s lumped R\n", OPTSET(EXT_DORESISTANCE));
TxPrintf("%s label check\n", OPTSET(EXT_DOLABELCHECK));
TxPrintf("%s aliases\n", OPTSET(EXT_DOALIASES));
TxPrintf("%s unique\n", OPTSET(EXT_DOUNIQUE));
TxPrintf("%s resistance (extresist)\n", OPTSET(EXT_DOEXTRESIST));
return;
#undef OPTSET
}
@ -1309,6 +1433,9 @@ CmdExtract(
case DORESISTANCE: option = EXT_DORESISTANCE; break;
case DOLABELCHECK: option = EXT_DOLABELCHECK; break;
case DOALIASES: option = EXT_DOALIASES; break;
case DOUNIQUE: option = EXT_DOUNIQUE; break;
case DOEXTRESIST:
case DOEXTRESIST2: option = EXT_DOEXTRESIST; break;
case DOLOCAL:
/* "extract do local" and "extract no local" are kept for
* backwards compatibility, but now effectively implement

View File

@ -102,15 +102,17 @@ struct cmdFPArg
int
feedPolyFunc(
Tile *tile,
TileType dinfo,
struct cmdFPArg *arg)
{
Rect area;
TiToRect(tile, &area);
/* (NOTE: Preserve information about the geometry of a diagonal tile) */
DBWFeedbackAdd(&area, arg->text, arg->def, FEEDMAGNIFY,
arg->style |
(TiGetTypeExact(tile) & (TT_DIAGONAL | TT_DIRECTION | TT_SIDE)));
/* (preserve information about the geometry of a diagonal tile) */
((TiGetTypeExact(tile) | dinfo) &
(TT_DIAGONAL | TT_DIRECTION | TT_SIDE)));
return 0;
}
@ -507,13 +509,15 @@ struct cmdFillArea *cmdFillList; /* List of areas to fill. */
void
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. */
{
TileTypeBitMask maskBits;
Rect editBox;
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)
{
@ -581,13 +585,15 @@ CmdFill(
/* Now that we've got all the material, scan over the list
* painting the material and freeing up the entries on the list.
*/
free_magic1_t mm1 = freeMagic1_init();
while (cmdFillList != NULL)
{
DBPaint(EditCellUse->cu_def, &cmdFillList->cfa_area,
cmdFillList->cfa_type);
freeMagic((char *) cmdFillList);
freeMagic1(&mm1, (char *) cmdFillList);
cmdFillList = cmdFillList->cfa_next;
}
freeMagic1_end(&mm1);
SelectClear();
DBAdjustLabels(EditCellUse->cu_def, &editBox);
@ -601,11 +607,16 @@ CmdFill(
* paint here it may mess up the search. Instead, the procedures
* save areas on a list. The list is post-processed to paint the
* 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
cmdFillFunc(
Tile *tile, /* Tile to fill with. */
TileType dinfo, /* Split tile information (unused) */
TreeContext *cxp) /* Describes state of search. */
{
Rect r1, r2;
@ -841,7 +852,7 @@ CmdFindLabel(
return;
};
labname = cmd->tx_argv[1 + (doglob) ? 1 : 0];
labname = cmd->tx_argv[1 + ((doglob) ? 1 : 0)];
labUse = EditCellUse;
if (labUse == NULL) labUse = (CellUse *)w->w_surfaceID;
@ -1208,7 +1219,7 @@ CmdGetnode(
TxError("Put the cursor in a layout window\n");
return;
}
if( is_fast == TRUE )
if (is_fast == TRUE)
{
SimRecomputeSel = TRUE;
SimGetsnode();
@ -1216,7 +1227,8 @@ CmdGetnode(
else
SimGetnode();
if (SimGetnodeAlias) { /* "erase" the hash table */
if (SimGetnodeAlias) /* "erase" the hash table */
{
HashKill(&SimGNAliasTbl);
HashInit(&SimGNAliasTbl, 120, STRINGS);
}
@ -1602,7 +1614,7 @@ CmdFindNetProc(
int pnum, xpos, ypos;
char *xstr, *ystr;
bool locvalid = FALSE, usefound = TRUE;
TileType ttype;
TileType ttype, dinfo = (TileType)0;
scx.scx_use = use;
scx.scx_trans = GeoIdentityTransform;
@ -1640,6 +1652,7 @@ CmdFindNetProc(
if ((xstr = strchr(s, '_')) != NULL)
{
char *hashpos;
bool isNeg = FALSE;
/* The characters up to the leading '_' should match one of the */
@ -1683,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;
}
}
@ -1705,17 +1729,23 @@ checklocal:
if (locvalid == TRUE)
{
int findTile(Tile *tile, TileType *rtype);
int findTile(Tile *tile, TileType dinfo, TileAndDinfo *tad);
CellDef *targetdef = use->cu_def;
Plane *plane = targetdef->cd_planes[pnum];
ttype = TT_SPACE; /* revert to space in case of failure */
TileAndDinfo tad;
/* 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,
(ClientData) &ttype);
(ClientData) &tad);
ttype = tad.tad_dinfo & TT_LEFTMASK;
}
else
{
@ -1783,7 +1813,7 @@ CmdGoto(
MagWindow *w,
TxCommand *cmd)
{
char *s, *nodename = cmd->tx_argv[1];
char *nodename = cmd->tx_argv[1];
Rect rect;
CellUse *use;
int locargc;
@ -1824,9 +1854,9 @@ CmdGoto(
/* are multiple layers drawn at the indicated point. */
#ifdef MAGIC_WRAPPER
Tcl_SetResult(magicinterp, DBTypeLongName(ttype), NULL);
Tcl_SetResult(magicinterp, (char*)DBTypeLongName(ttype), NULL); /* Tcl treats as const */
#else
TxPrintf("node %s is type %s\n", s, DBTypeLongName(ttype));
TxPrintf("node %s is type %s\n", nodename, DBTypeLongName(ttype));
#endif
}
@ -1839,20 +1869,31 @@ CmdGoto(
int
findTile(
Tile *tile,
TileType *rtype)
TileType dinfo, /* (unused) */
TileAndDinfo *tad)
{
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 (SplitSide(tile))
if (tad->tad_dinfo & TT_SIDE)
ttype = SplitRightType(tile);
else
ttype = SplitLeftType(tile);
}
else
ttype = TiGetTypeExact(tile);
*rtype = ttype;
/* Leave the tile type in tad_dinfo before returning */
tad->tad_dinfo = ttype;
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 "select/select.h"
#include "netmenu/netmenu.h"
/* C99 compat */
#include "cif/cif.h"
#include "cif/CIFint.h"
/* Forward declarations */
@ -518,14 +517,14 @@ CmdLoad(
DBExpandAll(topuse, &(topuse->cu_bbox),
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
TRUE, keepGoing, NULL);
DB_EXPAND, keepGoing, NULL);
DBExpandAll(topuse, &(topuse->cu_bbox),
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
FALSE, keepGoing, NULL);
DB_UNEXPAND, keepGoing, NULL);
DBExpand(topuse,
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
TRUE);
DB_EXPAND);
/* We don't want to save and restore DBLambda, because */
/* loading the file may change their values. Instead, we */
@ -2176,11 +2175,15 @@ parseindex:
{
if ((int)sl->lab_port == idx)
{
TxError("Port index %d is already used by port %s.\n"
"Use command \"port index %d\" to force "
"equivalence after defining the port.\n",
idx, sl->lab_text, idx);
return;
/* This is only an error if port name doesn't match */
if (strcmp(sl->lab_text, lab->lab_text))
{
TxError("Port index %d is already used by port %s.\n"
"Use command \"port index %d\" to force "
"equivalence after defining the port.\n",
idx, sl->lab_text, idx);
return;
}
}
}
}
@ -2292,6 +2295,8 @@ parsepositions:
editDef->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
}
#define PROPERTY_TYPE_COMPAT 4 /* Last entry in cmdPropertyType */
/*
* ----------------------------------------------------------------------------
*
@ -2315,47 +2320,448 @@ parsepositions:
void
CmdDoProperty(
CellDef *def,
MagWindow *w,
TxCommand *cmd,
int argstart)
{
int printPropertiesFunc();
PropertyRecord *proprec;
char *value;
bool propfound;
bool propfound, dolist;
int proptype, proplen, propvalue, i;
dlong dvalue;
int locargc = cmd->tx_argc - argstart + 1;
#ifdef MAGIC_WRAPPER
Tcl_Obj *tobj;
#endif
/* Forward declarations */
int printPropertiesFunc();
int printPlanePropFunc();
/* These should match the property codes in database.h.in, except
* for "compat" which must come at the end.
*/
static const char * const cmdPropertyType[] = {
"string", "integer", "dimension", "double", "plane", "compat", NULL
};
/* If the first keyword is "list", then set dolist and increment
* the starting argument position.
*/
dolist = FALSE;
if (locargc > 1)
{
if (!strcmp(cmd->tx_argv[argstart], "list"))
{
dolist = TRUE;
locargc--;
argstart++;
}
}
/* If a property type is given, parse it and then strip it from
* the arguments list.
*/
if (locargc > 1)
{
proptype = Lookup(cmd->tx_argv[argstart], cmdPropertyType);
if (proptype >= 0)
{
if (proptype != PROPERTY_TYPE_COMPAT)
{
locargc--;
argstart++;
}
}
else
proptype = PROPERTY_TYPE_STRING; /* default */
}
else
proptype = PROPERTY_TYPE_STRING; /* default */
if (locargc == 1)
{
#ifdef MAGIC_WRAPPER
Tcl_Obj *tobj;
/* Create an empty list for the interpreter result; the
* printPropertiesFunc() function will append values to it.
*/
tobj = Tcl_NewListObj(0, NULL);
Tcl_SetObjResult(magicinterp, tobj);
#endif
/* print all properties and their values */
DBPropEnum(def, printPropertiesFunc, NULL);
DBPropEnum(def, printPropertiesFunc, (ClientData)w);
}
else if (locargc == 2)
{
/* print the value of the indicated property */
value = (char *)DBPropGet(def, cmd->tx_argv[argstart], &propfound);
if (propfound)
/* If the property type was "compat", then give the state of the
* compatibility flag and return.
*/
if (proptype == PROPERTY_TYPE_COMPAT)
{
#ifdef MAGIC_WRAPPER
Tcl_SetResult(magicinterp, value, NULL);
Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(DBPropCompat));
#else
TxPrintf("%s", value);
TxPrintf("%s\n", (DBPropCompat == TRUE) ? "True" : "False");
#endif
return;
}
/* Print the value of the indicated property */
proprec = (PropertyRecord *)DBPropGet(def, cmd->tx_argv[argstart], &propfound);
if (propfound)
{
proptype = proprec->prop_type;
#ifdef MAGIC_WRAPPER
switch (proptype)
{
case PROPERTY_TYPE_STRING:
Tcl_SetResult(magicinterp, proprec->prop_value.prop_string, NULL);
break;
case PROPERTY_TYPE_INTEGER:
if (proprec->prop_len == 1)
Tcl_SetObjResult(magicinterp,
Tcl_NewIntObj(proprec->prop_value.prop_integer[0]));
else
{
tobj = Tcl_NewListObj(0, NULL);
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewIntObj(
proprec->prop_value.prop_integer[i]));
Tcl_SetObjResult(magicinterp, tobj);
}
break;
case PROPERTY_TYPE_DIMENSION:
if (proprec->prop_len == 1)
Tcl_SetResult(magicinterp,
DBWPrintValue(proprec->prop_value.prop_integer[0],
w, TRUE), NULL);
else
{
tobj = Tcl_NewListObj(0, NULL);
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(DBWPrintValue(
proprec->prop_value.prop_integer[i], w,
((i % 2) == 0) ? TRUE : FALSE), -1));
Tcl_SetObjResult(magicinterp, tobj);
}
break;
case PROPERTY_TYPE_PLANE:
tobj = Tcl_NewListObj(0, NULL);
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
proprec->prop_value.prop_plane,
&TiPlaneRect, &CIFSolidBits, printPlanePropFunc,
(ClientData)tobj);
Tcl_SetObjResult(magicinterp, tobj);
break;
case PROPERTY_TYPE_DOUBLE:
if (proprec->prop_len == 1)
Tcl_SetObjResult(magicinterp,
Tcl_NewWideIntObj((Tcl_WideInt)
proprec->prop_value.prop_double[0]));
else
{
tobj = Tcl_NewListObj(0, NULL);
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewWideIntObj((Tcl_WideInt)
proprec->prop_value.prop_double[i]));
Tcl_SetObjResult(magicinterp, tobj);
}
break;
}
#else
switch (proptype)
{
case PROPERTY_TYPE_STRING:
TxPrintf("%s\n", proprec->prop_value.prop_string);
break;
case PROPERTY_TYPE_INTEGER:
for (i = 0; i < proprec->prop_len; i++)
TxPrintf("%d ", proprec->prop_value.prop_integer[i]);
TxPrintf("\n");
break;
case PROPERTY_TYPE_DIMENSION:
for (i = 0; i < proprec->prop_len; i++)
TxPrintf("%s ", DBWPrintValue(
proprec->prop_value.prop_integer[i], w,
((i % 2) == 0) ? TRUE : FALSE));
TxPrintf("\n");
break;
case PROPERTY_TYPE_PLANE:
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
proprec->prop_value.prop_plane,
&TiPlaneRect, &CIFSolidBits, printPlanePropFunc,
(ClientData)NULL);
TxPrintf("\n");
break;
case PROPERTY_TYPE_DOUBLE:
for (i = 0; i < proprec->prop_len; i++)
TxPrintf( "%"DLONG_PREFIX"d",
proprec->prop_value.prop_double[i]);
TxPrintf("\n");
break;
}
#endif
}
else {
#ifdef MAGIC_WRAPPER
/* If the command was "cellname list property ...", then */
/* just return NULL if the property was not found. */
if (strcmp(cmd->tx_argv[1], "list"))
if (!dolist)
#endif
TxError("Property name \"%s\" is not defined\n", cmd->tx_argv[1]);
TxError("Property name \"%s\" is not defined\n", cmd->tx_argv[argstart]);
}
}
else if (locargc == 3)
else if (locargc >= 3)
{
/* If the property type was "compat", then set the state of the
* compatibility flag and return.
*/
if (proptype == PROPERTY_TYPE_COMPAT)
{
int idx;
static const char * const cmdPropYesNo[] = {
"disable", "no", "false", "off", "0",
"enable", "yes", "true", "on", "1", 0 };
idx = Lookup(cmd->tx_argv[2], cmdPropYesNo);
if (idx < 0)
{
TxError("Unknown property compat option \"%s\"\n", cmd->tx_argv[2]);
return;
}
DBPropCompat = (idx <= 4) ? FALSE : TRUE;
return;
}
/* Catch the following known reserved keywords and cast them to the
* expected property type. If any property type was already given
* to the command, it is overridden. This ensures that the reserved
* keyword functions work correctly.
*
* GDS_START, GDS_END: PROPERTY_TYPE_DOUBLE
* MASKHINTS_*: PROPERTY_TYPE_PLANE
* FIXED_BBOX: PROPERTY_TYPE_DIMENSION
*/
if (!strcmp(cmd->tx_argv[argstart], "GDS_START"))
proptype = PROPERTY_TYPE_DOUBLE;
else if (!strcmp(cmd->tx_argv[argstart], "GDS_END"))
proptype = PROPERTY_TYPE_DOUBLE;
else if (!strcmp(cmd->tx_argv[argstart], "GDS_FILE"))
proptype = PROPERTY_TYPE_STRING;
else if (!strcmp(cmd->tx_argv[argstart], "FIXED_BBOX"))
proptype = PROPERTY_TYPE_DIMENSION;
else if (!strcmp(cmd->tx_argv[argstart], "OBS_BBOX"))
proptype = PROPERTY_TYPE_DIMENSION;
else if (!strncmp(cmd->tx_argv[argstart], "MASKHINTS_", 10))
proptype = PROPERTY_TYPE_PLANE;
if (strlen(cmd->tx_argv[argstart + 1]) == 0)
DBPropPut(def, cmd->tx_argv[argstart], NULL);
else
{
value = StrDup((char **)NULL, cmd->tx_argv[argstart + 1]);
DBPropPut(def, cmd->tx_argv[argstart], value);
if (proptype == PROPERTY_TYPE_STRING)
{
proplen = strlen(cmd->tx_argv[argstart + 1]);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) -
7 + proplen);
proprec->prop_type = proptype;
proprec->prop_len = proplen;
strcpy(proprec->prop_value.prop_string, cmd->tx_argv[argstart + 1]);
}
else /* All non-string properties */
{
Plane *plane;
Rect r;
/* Two choices: If locargc == 3 then all values are in one
* argument. If locargc > 3, then parse each argument as a
* separate value.
*/
if (locargc > 3)
{
proplen = locargc - 2;
if (proptype == PROPERTY_TYPE_DOUBLE)
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(proplen - 1)*sizeof(dlong));
else if (proptype == PROPERTY_TYPE_PLANE)
{
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
plane = DBNewPlane((ClientData)TT_SPACE);
proprec->prop_value.prop_plane = plane;
}
else
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(proplen - 2)*sizeof(int));
proprec->prop_type = proptype;
proprec->prop_len = proplen;
for (i = 1; i < locargc - 1; i++)
{
if (proptype == PROPERTY_TYPE_INTEGER)
{
if (sscanf(cmd->tx_argv[argstart + i], "%d",
&propvalue) == 1)
proprec->prop_value.prop_integer[i - 1] = propvalue;
else
{
TxError("Unable to parse value \"%s\" as an integer\n",
cmd->tx_argv[argstart + i]);
proprec->prop_value.prop_integer[i - 1] = 0;
}
}
else if (proptype == PROPERTY_TYPE_DOUBLE)
{
if (sscanf(cmd->tx_argv[argstart + i], "%"DLONG_PREFIX"d",
&dvalue) == 1)
proprec->prop_value.prop_double[i - 1] = dvalue;
else
{
TxError("Unable to parse value \"%s\" as an integer\n",
cmd->tx_argv[argstart + i]);
proprec->prop_value.prop_double[i - 1] = 0;
}
}
else if (proptype == PROPERTY_TYPE_PLANE)
{
propvalue = cmdParseCoord(w, cmd->tx_argv[argstart + i],
FALSE, ((i % 2) == 0) ? FALSE : TRUE);
switch ((i - 1) % 4)
{
case 0:
r.r_xbot = propvalue;
break;
case 1:
r.r_ybot = propvalue;
break;
case 2:
r.r_xtop = propvalue;
break;
case 3:
r.r_ytop = propvalue;
DBPaintPlane(plane, &r, CIFPaintTable,
(PaintUndoInfo *)NULL);
break;
}
}
else /* PROPERTY_TYPE_DIMENSION */
{
propvalue = cmdParseCoord(w, cmd->tx_argv[argstart + i],
FALSE, ((i % 2) == 0) ? FALSE : TRUE);
proprec->prop_value.prop_integer[i - 1] = propvalue;
}
}
}
else
{
/* Make two passes through the argument string, once to get
* the valid number of arguments, then again to parse the
* values, once the property record has been allocated
*/
if (proptype == PROPERTY_TYPE_PLANE)
{
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
plane = DBNewPlane((ClientData)TT_SPACE);
proprec->prop_value.prop_plane = plane;
}
else
{
value = cmd->tx_argv[argstart + 1];
for (proplen = 0; *value != '\0'; )
{
if (isspace(*value) && (*value != '\0')) value++;
if (!isspace(*value))
{
proplen++;
while (!isspace(*value) && (*value != '\0')) value++;
}
}
if (proplen > 0)
proprec = (PropertyRecord *)mallocMagic(
sizeof(PropertyRecord) +
(proplen - 2) * sizeof(int));
}
proprec->prop_type = proptype;
proprec->prop_len = proplen;
/* Second pass */
value = cmd->tx_argv[argstart + 1];
for (proplen = 0; proplen < proprec->prop_len; proplen++)
{
if (isspace(*value) && (*value != '\0')) value++;
if (!isspace(*value))
{
char *spptr, spchar;
/* cmdParseCoord() can only handle one value at a
* time, so look ahead and null out the next space
* character if there is one.
*/
spptr = value + 1;
while (!isspace(*spptr) && (*spptr != '\0')) spptr++;
spchar = *spptr;
*spptr = '\0';
if (proptype == PROPERTY_TYPE_INTEGER)
{
if (sscanf(value, "%d", &propvalue) != 1)
{
TxError("Unable to parse integer "
"value from \"%s\"\n",
value);
propvalue = 0;
}
proprec->prop_value.prop_integer[proplen] = propvalue;
}
else if (proptype == PROPERTY_TYPE_DOUBLE)
{
if (sscanf(value, "%"DLONG_PREFIX"d", &dvalue) != 1)
{
TxError("Unable to parse integer "
"value from \"%s\"\n",
value);
propvalue = 0;
}
proprec->prop_value.prop_double[proplen] = dvalue;
}
else if (proptype == PROPERTY_TYPE_PLANE)
{
propvalue = cmdParseCoord(w, value, FALSE,
((proplen % 2) == 0) ? TRUE : FALSE);
switch (proplen % 4)
{
case 0:
r.r_xbot = propvalue;
break;
case 1:
r.r_ybot = propvalue;
break;
case 2:
r.r_xtop = propvalue;
break;
case 3:
r.r_ytop = propvalue;
DBPaintPlane(plane, &r, CIFPaintTable,
(PaintUndoInfo *)NULL);
break;
}
}
else /* PROPERTY_TYPE_DIMENSION */
{
propvalue = cmdParseCoord(w, value, FALSE,
((proplen % 2) == 0) ? TRUE : FALSE);
proprec->prop_value.prop_integer[proplen] = propvalue;
}
*spptr = spchar;
while (!isspace(*value) && (*value != '\0')) value++;
}
}
}
}
DBPropPut(def, cmd->tx_argv[argstart], proprec);
}
def->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
}
@ -2376,10 +2782,14 @@ CmdDoProperty(
* defined in database/DBprop.c.
*
* Usage:
* property [name] [value]
* property [string|integer|dimension] [name] [value]
*
* "name" is a unique string tag for the property, and "value" is its
* string value.
* If the first argument is present, it must be one of the known
* keywords, and determines the form in which "value" is interpreted and
* stored. "name" is a unique string tag for the property. "value" is
* the value of the property, which is either a string, integer, or a
* list of integers. The difference between an "integer" and a "dimension"
* is that all values which are dimensions are scaled with internal units.
*
* Results:
* None.
@ -2406,9 +2816,62 @@ CmdProperty(
else
def = ((CellUse *) w->w_surfaceID)->cu_def;
CmdDoProperty(def, cmd, 1);
CmdDoProperty(def, w, cmd, 1);
}
/*
* ----------------------------------------------------------------------------
* Callback function for printing values from a Plane property
* ----------------------------------------------------------------------------
*/
#ifdef MAGIC_WRAPPER
int
printPlanePropFunc(
Tile *tile,
TileType dinfo,
Tcl_Obj *lobj)
{
Rect r;
MagWindow *w;
TiToRect(tile, &r);
windCheckOnlyWindow(&w, DBWclientID);
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(DBWPrintValue(r.r_xbot, w, TRUE), -1));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(DBWPrintValue(r.r_ybot, w, FALSE), -1));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(DBWPrintValue(r.r_xtop, w, TRUE), -1));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(DBWPrintValue(r.r_ytop, w, FALSE), -1));
return 0;
}
#else
int
printPlanePropFunc(
Tile *tile,
TileType dinfo,
ClientData cdata) /* (unused) */
{
Rect r;
MagWindow *w;
TiToRect(tile, &r);
windCheckOnlyWindow(&w, DBWclientID);
TxPrintf("%s ", DBWPrintValue(r.r_xbot, w, TRUE));
TxPrintf("%s ", DBWPrintValue(r.r_ybot, w, FALSE));
TxPrintf("%s ", DBWPrintValue(r.r_xtop, w, TRUE));
TxPrintf("%s ", DBWPrintValue(r.r_ytop, w, FALSE));
return 0;
}
#endif
/*
* ----------------------------------------------------------------------------
* Callback function for printing a single property key:value pair
@ -2418,27 +2881,84 @@ CmdProperty(
int
printPropertiesFunc(
const char *name,
ClientData value,
ClientData cdata) /* not used */
PropertyRecord *proprec,
MagWindow *w)
{
#ifdef MAGIC_WRAPPER
char *keyvalue;
int i;
if (value == NULL)
#ifdef MAGIC_WRAPPER
Tcl_Obj *tobj, *lobj;
tobj = Tcl_GetObjResult(magicinterp);
lobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_NewStringObj(name, -1));
switch (proprec->prop_type)
{
keyvalue = (char *)mallocMagic(strlen(name) + 4);
sprintf(keyvalue, "%s {}", name);
case PROPERTY_TYPE_STRING:
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(proprec->prop_value.prop_string, -1));
break;
case PROPERTY_TYPE_INTEGER:
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(proprec->prop_value.prop_integer[i]));
break;
case PROPERTY_TYPE_DIMENSION:
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(
DBWPrintValue(proprec->prop_value.prop_integer[i],
w, ((i % 2) == 0) ? TRUE : FALSE), -1));
break;
case PROPERTY_TYPE_PLANE:
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
proprec->prop_value.prop_plane,
&TiPlaneRect, &CIFSolidBits, printPlanePropFunc,
(ClientData)lobj);
break;
case PROPERTY_TYPE_DOUBLE:
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewWideIntObj(proprec->prop_value.prop_double[i]));
break;
}
else
{
keyvalue = (char *)mallocMagic(strlen(name) + strlen((char *)value) + 2);
sprintf(keyvalue, "%s %s", name, (char *)value);
}
Tcl_AppendElement(magicinterp, keyvalue);
freeMagic(keyvalue);
Tcl_ListObjAppendElement(magicinterp, tobj, lobj);
Tcl_SetObjResult(magicinterp, tobj);
#else
TxPrintf("%s = %s\n", name, value);
switch (proprec->prop_type)
{
case PROPERTY_TYPE_STRING:
TxPrintf("%s = %s\n", name, (const char *)proprec->prop_value.prop_string);
break;
case PROPERTY_TYPE_INTEGER:
TxPrintf("%s = ", name);
for (i = 0; i < proprec->prop_len; i++)
TxPrintf("%d ", proprec->prop_value.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_value.prop_double[i]);
TxPrintf("\n");
break;
}
#endif
return 0; /* keep the search alive */

View File

@ -99,7 +99,7 @@ CmdRandom(
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(random()));
#else
TxPrintf("%d", random());
TxPrintf("%ld", random());
#endif
}
else if ((cmd->tx_argc >= 2) && (!strcmp(cmd->tx_argv[1], "seed")))
@ -1084,25 +1084,33 @@ CmdSelect(
*/
case SEL_BBOX:
{
char *selllx, *sellly, *selurx, *selury;
GeoTransRect(&SelectUse->cu_transform, &SelectDef->cd_bbox, &selarea);
selllx = DBWPrintValue(selarea.r_xbot, w, TRUE);
sellly = DBWPrintValue(selarea.r_ybot, w, FALSE);
selurx = DBWPrintValue(selarea.r_xtop, w, TRUE);
selury = DBWPrintValue(selarea.r_ytop, w, FALSE);
#ifdef MAGIC_WRAPPER
lobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(selarea.r_xbot));
Tcl_NewStringObj(selllx, -1));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(selarea.r_ybot));
Tcl_NewStringObj(sellly, -1));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(selarea.r_xtop));
Tcl_NewStringObj(selurx, -1));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(selarea.r_ytop));
Tcl_NewStringObj(selury, -1));
Tcl_SetObjResult(magicinterp, lobj);
#else
TxPrintf("Select bounding box: %d %d %d %d\n",
selarea.r_xbot, selarea.r_ybot,
selarea.r_xtop, selarea.r_ytop);
TxPrintf("Select bounding box: %s %s %s %s\n",
selllx, sellly, selurx, selury);
#endif
return;
}
/*--------------------------------------------------------------------
* Make a copy of the selection at its present loction but do not
@ -1256,15 +1264,17 @@ CmdSelect(
/* of rlist) */
SelectClear();
free_magic1_t mm1 = freeMagic1_init();
while (rlist != NULL)
{
/* Paint rlist back into SelectDef */
DBPaint(SelectDef, &rlist->r_r, rlist->r_type);
/* cleanup as we go */
freeMagic(rlist);
freeMagic1(&mm1, rlist);
rlist = rlist->r_next;
}
freeMagic1_end(&mm1);
/* Force erase and redraw of the selection */
DBReComputeBbox(SelectDef);
@ -1791,13 +1801,18 @@ cmdLabelSizeFunc(
if (value == NULL)
{
char *labsize;
MagWindow *w;
windCheckOnlyWindow(&w, DBWclientID);
labsize = DBWPrintValue(label->lab_size / 8, w, FALSE);
#ifdef MAGIC_WRAPPER
lobj = Tcl_GetObjResult(magicinterp);
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewDoubleObj((double)label->lab_size / 8.0));
Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_NewStringObj(labsize, -1));
Tcl_SetObjResult(magicinterp, lobj);
#else
TxPrintf("%g\n", (double)label->lab_size / 8.0);
TxPrintf("%s\n", labsize);
#endif
}
else if (label->lab_size != *value)
@ -1942,18 +1957,22 @@ cmdLabelOffsetFunc(
if (point == NULL)
{
char *laboffx, *laboffy;
MagWindow *w;
windCheckOnlyWindow(&w, DBWclientID);
laboffx = DBWPrintValue(label->lab_offset.p_x / 8, w, TRUE);
laboffy = DBWPrintValue(label->lab_offset.p_x / 8, w, FALSE);
#ifdef MAGIC_WRAPPER
lobj = Tcl_GetObjResult(magicinterp);
pobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
Tcl_ListObjAppendElement(magicinterp, pobj,
Tcl_NewDoubleObj((double)label->lab_offset.p_x / 8.0));
Tcl_ListObjAppendElement(magicinterp, pobj,
Tcl_NewDoubleObj((double)label->lab_offset.p_y / 8.0));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(laboffx, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(laboffy, -1));
Tcl_SetObjResult(magicinterp, lobj);
#else
TxPrintf("%g %g\n", (double)(label->lab_offset.p_x) / 8.0,
(double)(label->lab_offset.p_y) / 8.0);
TxPrintf("%s %s\n", laboffx, laboffy);
#endif
}
else if (!GEO_SAMEPOINT(label->lab_offset, *point))
@ -1983,23 +2002,25 @@ cmdLabelRectFunc(
if (rect == NULL)
{
char *labllx, *lablly, *laburx, *labury;
/* Note: Ideally, the MagWindow pointer should be passed to this function */
labllx = DBWPrintValue(label->lab_rect.r_xbot, (MagWindow *)NULL, TRUE);
lablly = DBWPrintValue(label->lab_rect.r_ybot, (MagWindow *)NULL, FALSE);
laburx = DBWPrintValue(label->lab_rect.r_xtop, (MagWindow *)NULL, TRUE);
labury = DBWPrintValue(label->lab_rect.r_ytop, (MagWindow *)NULL, FALSE);
#ifdef MAGIC_WRAPPER
lobj = Tcl_GetObjResult(magicinterp);
pobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
Tcl_ListObjAppendElement(magicinterp, pobj,
Tcl_NewIntObj((double)label->lab_rect.r_xbot));
Tcl_ListObjAppendElement(magicinterp, pobj,
Tcl_NewIntObj((double)label->lab_rect.r_ybot));
Tcl_ListObjAppendElement(magicinterp, pobj,
Tcl_NewIntObj((double)label->lab_rect.r_xtop));
Tcl_ListObjAppendElement(magicinterp, pobj,
Tcl_NewIntObj((double)label->lab_rect.r_ytop));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(labllx, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(lablly, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(laburx, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(labury, -1));
Tcl_SetObjResult(magicinterp, lobj);
#else
TxPrintf("%d %d %d %d\n",
label->lab_rect.r_xbot, label->lab_rect.r_ybot,
label->lab_rect.r_xtop, label->lab_rect.r_ytop);
TxPrintf("%s %s %s %s\n", labllx, lablly, laburx,labury);
#endif
}
else if (!GEO_SAMERECT(label->lab_rect, *rect))
@ -2200,9 +2221,13 @@ CmdSetLabel(
}
else if (EditCellUse)
{
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelTextFunc, (locargc == 3) ?
(ClientData)cmd->tx_argv[argstart + 1] : (ClientData)NULL);
if (locargc == 2)
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelTextFunc, (ClientData)NULL);
else
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelTextFunc,
(ClientData)cmd->tx_argv[argstart + 1]);
}
break;
@ -2268,9 +2293,12 @@ CmdSetLabel(
}
else if (EditCellUse)
{
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelFontFunc, (locargc == 3) ?
(ClientData)&font : (ClientData)NULL);
if (locargc == 2)
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelFontFunc, (ClientData)NULL);
else
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelFontFunc, (ClientData)&font);
}
}
break;
@ -2298,9 +2326,12 @@ CmdSetLabel(
}
else if (EditCellUse)
{
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelJustFunc, (locargc == 3) ?
(ClientData)&pos : (ClientData)NULL);
if (locargc == 2)
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelJustFunc, (ClientData)NULL);
else
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelJustFunc, (ClientData)&pos);
}
break;
@ -2315,11 +2346,13 @@ CmdSetLabel(
{
if (locargc == 2)
{
char *labsize;
labsize = DBWPrintValue(DefaultLabel->lab_size, w, FALSE);
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp,
Tcl_NewIntObj(DefaultLabel->lab_size));
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(labsize, -1));
#else
TxPrintf("%d\n", DefaultLabel->lab_size);
TxPrintf("%s\n", labsize);
#endif
}
else
@ -2327,9 +2360,12 @@ CmdSetLabel(
}
else if (EditCellUse)
{
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelSizeFunc, (locargc == 3) ?
(ClientData)&size : (ClientData)NULL);
if (locargc == 2)
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelSizeFunc, (ClientData)NULL);
else
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelSizeFunc, (ClientData)&size);
}
break;
@ -2358,16 +2394,20 @@ CmdSetLabel(
{
if (locargc == 2)
{
char *laboffx, *laboffy;
laboffx = DBWPrintValue(DefaultLabel->lab_offset.p_x, w,
TRUE);
laboffy = DBWPrintValue(DefaultLabel->lab_offset.p_y, w,
FALSE);
#ifdef MAGIC_WRAPPER
lobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(DefaultLabel->lab_offset.p_x));
Tcl_NewStringObj(laboffx, -1));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(DefaultLabel->lab_offset.p_y));
Tcl_NewStringObj(laboffy, -1));
Tcl_SetObjResult(magicinterp, lobj);
#else
TxPrintf("%d %d\n", DefaultLabel->lab_offset.p_x,
DefaultLabel->lab_offset.p_y);
TxPrintf("%s %s\n", laboffx, laboffy);
#endif
}
else
@ -2375,9 +2415,12 @@ CmdSetLabel(
}
else if (EditCellUse)
{
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelOffsetFunc, (locargc != 2) ?
(ClientData)&offset : (ClientData)NULL);
if (locargc == 2)
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelOffsetFunc, (ClientData)NULL);
else
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelOffsetFunc, (ClientData)&offset);
}
break;
@ -2441,10 +2484,12 @@ CmdSetLabel(
rect.r_ytop = cmdScaleCoord(w, cmd->tx_argv[argstart + 4],
TRUE, FALSE, 1);
}
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelRectFunc,
((locargc == 6) || (locargc == 3)) ?
(ClientData)&rect : (ClientData)NULL);
if ((locargc == 3) || (locargc == 6))
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelRectFunc, (ClientData)&rect);
else
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelRectFunc, (ClientData)NULL);
}
break;
@ -2470,9 +2515,12 @@ CmdSetLabel(
}
else if (EditCellUse)
{
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelRotateFunc, (locargc == 3) ?
(ClientData)&rotate : (ClientData)NULL);
if (locargc == 2)
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelRotateFunc, (ClientData)NULL);
else
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelRotateFunc, (ClientData)&rotate);
}
break;
@ -2504,9 +2552,12 @@ CmdSetLabel(
}
else if (EditCellUse)
{
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelStickyFunc, (locargc == 3) ?
(ClientData)&flags : (ClientData)NULL);
if (locargc == 2)
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelStickyFunc, (ClientData)NULL);
else
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelStickyFunc, (ClientData)&flags);
}
break;
@ -2534,7 +2585,7 @@ CmdSetLabel(
else
#ifdef MAGIC_WRAPPER
Tcl_SetResult(magicinterp,
DBTypeLongNameTbl[DefaultLabel->lab_type],
(char*)DBTypeLongNameTbl[DefaultLabel->lab_type], /* Tcl treats as const */
TCL_VOLATILE);
#else
TxPrintf("%s\n", DBTypeLongNameTbl[DefaultLabel->lab_type]);
@ -2545,9 +2596,12 @@ CmdSetLabel(
}
else if (EditCellUse)
{
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelLayerFunc, (locargc == 3) ?
(ClientData)&ttype : (ClientData)NULL);
if (locargc == 2)
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelLayerFunc, (ClientData)NULL);
else
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelLayerFunc, (ClientData)&ttype);
}
break;
@ -2784,7 +2838,7 @@ CmdSimCmd(
{
static char cmdbuf[200];
char *strptr;
char *nodeCmd;
const char *nodeCmd;
int i;
if (!SimRsimRunning) {
@ -2882,16 +2936,39 @@ CmdSnap(
TxPrintf("Usage: snap [internal | lambda | user]\n");
return;
}
/* Backwards compatibility: Use of "snap" to set units display and
* parsing has been deprecated as of February 2026. However, as this
* is rather disruptive to existing scripts which use "snap" to change
* the parsing of units, then the following measure is being taken
* (for now, anyway): If DBWUnits is set to DBW_UNITS_DEFAULT, then
* "snap internal" will set DBWUnits as well as DBWSnapToGrid. If
* DBWUnits is changed first (e.g., "units internal"), then "snap" will
* affect only the snap grid. The older usage will be accompanied by a
* warning message. Note that backwards compatibility is being kept
* only in the case of "snap internal", which was commonly used in
* scripts to make sure that all units were interpreted as internal
* units.
*/
if ((DBWUnits == DBW_UNITS_DEFAULT) && (n == SNAP_INTERNAL))
{
DBWUnits = DBW_UNITS_INTERNAL;
TxError("Warning: snap setting is also changing units. This usage "
"is deprecated\nand may be removed in the future. Use "
"\"units\" to change units, and\nchange units before "
"setting snap to keep this message from appearing.\n");
}
switch (n)
{
case SNAP_OFF: case SNAP_INTERNAL:
DBWSnapToGrid = DBW_SNAP_INTERNAL;
DBWSnapToGrid = DBW_UNITS_INTERNAL;
return;
case SNAP_LAMBDA:
DBWSnapToGrid = DBW_SNAP_LAMBDA;
DBWSnapToGrid = DBW_UNITS_LAMBDA;
return;
case SNAP_GRID: case SNAP_USER: case SNAP_ON:
DBWSnapToGrid = DBW_SNAP_USER;
DBWSnapToGrid = DBW_UNITS_USER;
return;
}
@ -2899,21 +2976,19 @@ printit:
if (n == SNAP_LIST) /* list */
#ifdef MAGIC_WRAPPER
Tcl_SetResult(magicinterp,
(DBWSnapToGrid == DBW_SNAP_INTERNAL) ? "internal" :
((DBWSnapToGrid == DBW_SNAP_LAMBDA) ? "lambda" : "user"),
(DBWSnapToGrid == DBW_UNITS_INTERNAL) ? "internal" :
((DBWSnapToGrid == DBW_UNITS_LAMBDA) ? "lambda" : "user"),
TCL_VOLATILE);
#else
TxPrintf("%s\n", (DBWSnapToGrid == DBW_SNAP_INTERNAL) ? "internal" :
((DBWSnapToGrid == DBW_SNAP_LAMBDA) ? "lambda" : "user"));
TxPrintf("%s\n", (DBWSnapToGrid == DBW_UNITS_INTERNAL) ? "internal" :
((DBWSnapToGrid == DBW_UNITS_LAMBDA) ? "lambda" : "user"));
#endif
else
TxPrintf("Box is aligned to %s grid\n",
(DBWSnapToGrid == DBW_SNAP_INTERNAL) ? "internal" :
((DBWSnapToGrid == DBW_SNAP_LAMBDA) ? "lambda" : "user"));
(DBWSnapToGrid == DBW_UNITS_INTERNAL) ? "internal" :
((DBWSnapToGrid == DBW_UNITS_LAMBDA) ? "lambda" : "user"));
}
/*
* ----------------------------------------------------------------------------
*

View File

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

View File

@ -61,7 +61,9 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
int
existFunc(
Tile *tile)
Tile *tile, /* (unused) */
TileType dinfo, /* (unused) */
ClientData clientdata) /* (unused) */
{
return 1;
}
@ -453,15 +455,18 @@ CmdTech(
}
if (!strncmp(cmd->tx_argv[2], "width", 5))
{
char *techwidth;
tresult = DRCGetDefaultLayerWidth(t1);
techwidth = DBWPrintValue(tresult, w, TRUE);
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult));
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techwidth, -1));
#else
TxPrintf("Minimum width is %d\n", tresult);
TxPrintf("Minimum width is %s\n", techwidth);
#endif
}
else if (!strncmp(cmd->tx_argv[2], "spac", 4))
{
char *techspace;
if (cmd->tx_argc >= 5)
{
t2 = DBTechNoisyNameType(cmd->tx_argv[4]);
@ -473,14 +478,16 @@ CmdTech(
else
t2 = t1;
tresult = DRCGetDefaultLayerSpacing(t1, t2);
techspace = DBWPrintValue(tresult, w, TRUE);
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult));
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techspace, -1));
#else
TxPrintf("Minimum spacing is %d\n", tresult);
TxPrintf("Minimum spacing is %s\n", techspace);
#endif
}
else if (!strncmp(cmd->tx_argv[2], "surr", 4))
{
char *techsurround;
if (cmd->tx_argc >= 5)
{
t2 = DBTechNoisyNameType(cmd->tx_argv[4]);
@ -496,14 +503,17 @@ CmdTech(
}
tresult = DRCGetDefaultLayerSurround(t1, t2);
techsurround = DBWPrintValue(tresult, w, TRUE);
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult));
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techsurround, -1));
#else
TxPrintf("Minimum surround is %d\n", tresult);
TxPrintf("Minimum surround is %s\n", techsurround);
#endif
}
else if (!strncmp(cmd->tx_argv[2], "direc", 5))
{
char *techdirec;
if (cmd->tx_argc >= 5)
{
t2 = DBTechNoisyNameType(cmd->tx_argv[4]);
@ -519,10 +529,11 @@ CmdTech(
}
tresult = DRCGetDirectionalLayerSurround(t1, t2);
techdirec = DBWPrintValue(tresult, w, TRUE);
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(tresult));
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(techdirec, -1));
#else
TxPrintf("Minimum surround (in one orientation) is %d\n", tresult);
TxPrintf("Minimum surround (in one orientation) is %s\n", techdirec);
#endif
}
}
@ -671,6 +682,15 @@ CmdTool(
if (strcmp(cmd->tx_argv[1], "info") == 0)
DBWPrintButtonDoc();
else if (strcmp(cmd->tx_argv[1], "type") == 0)
{
char *toolType = DBWGetButtonHandler();
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(toolType, -1));
#else
TxPrintf("Current tool is \"%s\".\n", toolType);
#endif /* MAGIC_WRAPPER */
}
else (void) DBWChangeButtonHandler(cmd->tx_argv[1]);
}
@ -682,32 +702,62 @@ CmdTool(
* Implement the "unexpand" command.
*
* Usage:
* unexpand
* unexpand [selection|surround|overlap|all]
*
* "selection" unexpands (hides) cells in the selection. All
* other options unexpand cells in the layout. "all" unexpands
* all cells in the layout. "surround" unexpannds cells which
* the cursor box surrounds completely, and "overlap" unexpands
* cells which the cursor box overlaps.
*
* For backwards compatibility:
* "unexpand" alone implements "unexpand surround".
*
* Also see: CmdExpand
*
* Results:
* None.
*
* Side effects:
* Unexpands all cells under the box that don't completely
* contain the box.
* Changes the expansion state of cells.
*
* ----------------------------------------------------------------------------
*/
#define UNEXPAND_SELECTION 0
#define UNEXPAND_SURROUND 1
#define UNEXPAND_OVERLAP 2
#define UNEXPAND_ALL 3
#define UNEXPAND_HELP 4
void
CmdUnexpand(
MagWindow *w,
TxCommand *cmd)
{
int windowMask, boxMask;
int windowMask, boxMask, option;
const char * const *msg;
Rect rootRect;
int cmdUnexpandFunc(CellUse *use, int windowMask); /* Forward reference. */
if (cmd->tx_argc != 1)
static const char * const cmdUnexpandOption[] = {
"selection expand cell instances in the selection",
"surround expand cell instances which the cursor box surrounds",
"overlap expand cell instances which the cursor box overlaps",
"all expand all cell instances",
NULL
};
if (cmd->tx_argc > 1)
{
TxError("Usage: %s\n", cmd->tx_argv[0]);
return;
option = Lookup(cmd->tx_argv[1], cmdUnexpandOption);
if (option < 0) option = UNEXPAND_HELP;
}
else
option = UNEXPAND_SURROUND;
if (option == UNEXPAND_HELP) goto badusage;
windCheckOnlyWindow(&w, DBWclientID);
if (w == (MagWindow *) NULL)
@ -723,8 +773,42 @@ CmdUnexpand(
TxError("The box isn't in the same window as the cursor.\n");
return;
}
DBExpandAll(((CellUse *) w->w_surfaceID), &rootRect, windowMask,
FALSE, cmdUnexpandFunc, (ClientData)(pointertype) windowMask);
switch (option)
{
case UNEXPAND_SELECTION:
SelectExpand(windowMask, DB_UNEXPAND, (Rect *)NULL, FALSE);
break;
case UNEXPAND_OVERLAP:
DBExpandAll(((CellUse *)w->w_surfaceID), &rootRect, windowMask,
DB_UNEXPAND | DB_EXPAND_OVERLAP,
cmdUnexpandFunc, (ClientData)(pointertype)windowMask);
SelectExpand(windowMask,
DB_UNEXPAND | DB_EXPAND_OVERLAP,
&rootRect, FALSE);
break;
case UNEXPAND_SURROUND:
DBExpandAll(((CellUse *)w->w_surfaceID), &rootRect, windowMask,
DB_UNEXPAND | DB_EXPAND_SURROUND,
cmdUnexpandFunc, (ClientData)(pointertype)windowMask);
SelectExpand(windowMask,
DB_UNEXPAND | DB_EXPAND_SURROUND,
&rootRect, TRUE);
break;
case UNEXPAND_ALL:
DBExpandAll(((CellUse *)w->w_surfaceID), &TiPlaneRect, windowMask,
DB_UNEXPAND | DB_EXPAND_OVERLAP,
cmdUnexpandFunc, (ClientData)(pointertype)windowMask);
SelectExpand(windowMask,
DB_UNEXPAND | DB_EXPAND_OVERLAP,
(Rect *)NULL);
break;
}
return;
badusage:
for (msg = &(cmdUnexpandOption[0]); *msg != NULL; msg++)
TxPrintf(" %s\n", *msg);
}
/* This function is called for each cell whose expansion status changed.
@ -743,6 +827,182 @@ cmdUnexpandFunc(
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* CmdUnits --
*
* Implement the "units" command.
*
* Usage:
* units [value] [print|noprint]
*
* where "value" may be one of "default", "internal", "lambda",
* "user" (equivalently "grid"), or "microns".
*
* Results:
* None.
*
* Side effects:
* The global variable DBWUnits may be changed, which changes the
* behavior of magic when interpreting un-suffixed values or
* displaying values.
*
* Notes:
* The units behavior was previously dependent on what command was
* issued, with results usually being given in internal units, and
* with un-suffixed values following the snap behavior. Backwards-
* compatible behavior is used on startup or at any time by setting
* the units to "default". Otherwise, unit display follows the
* given "units" setting.
*
* ----------------------------------------------------------------------------
*/
#define UNITS_DEFAULT 0
#define UNITS_INTERNAL 1
#define UNITS_LAMBDA 2
#define UNITS_GRID 3
#define UNITS_USER 4
#define UNITS_MICRONS 5
#define UNITS_LIST 6
#define UNITS_PRINT 7
#define UNITS_NOPRINT 8
void
CmdUnits(
MagWindow *w,
TxCommand *cmd)
{
static const char * const names[] = { "default", "internal", "lambda",
"grid", "user", "microns", "list", "print", "noprint", 0 };
int idx, n = UNITS_LIST, n2, saveflag;
DBWclientRec *crec;
if (cmd->tx_argc >= 2)
{
n = Lookup(cmd->tx_argv[1], names);
if (n < 0)
{
TxPrintf("Usage: units [default | internal | lambda | microns"
" | user] [print]\n");
return;
}
if (DBWUnits != DBW_UNITS_DEFAULT)
saveflag = DBWUnits & DBW_UNITS_PRINT_FLAG;
else
saveflag = -1;
switch (n)
{
case UNITS_DEFAULT:
DBWUnits = DBW_UNITS_DEFAULT;
break;
case UNITS_INTERNAL:
DBWUnits = DBW_UNITS_INTERNAL;
break;
case UNITS_LAMBDA:
DBWUnits = DBW_UNITS_LAMBDA;
break;
case UNITS_USER:
case UNITS_GRID:
DBWUnits = DBW_UNITS_USER;
break;
case UNITS_MICRONS:
DBWUnits = DBW_UNITS_MICRONS;
break;
case UNITS_PRINT:
saveflag = DBW_UNITS_PRINT_FLAG;
break;
case UNITS_NOPRINT:
saveflag = 0;
break;
}
if (n < 0)
{
TxError("Unrecognized units option %s\n.", cmd->tx_argv[1]);
return;
}
if (n != UNITS_LIST)
{
if ((cmd->tx_argc == 3) && (n != UNITS_DEFAULT))
{
n2 = Lookup(cmd->tx_argv[2], names);
switch (n2)
{
case UNITS_PRINT:
DBWUnits |= DBW_UNITS_PRINT_FLAG;
break;
case UNITS_NOPRINT:
DBWUnits &= DBW_UNITS_TYPE_MASK;
break;
default:
TxError("Unrecognized units option %s\n.", cmd->tx_argv[2]);
break;
}
}
else if ((n != UNITS_DEFAULT) && (saveflag != -1))
{
/* Preserve the previous value of the print/noprint flag */
DBWUnits &= DBW_UNITS_TYPE_MASK;
DBWUnits |= saveflag;
}
return;
}
}
if (DBWUnits == DBW_UNITS_DEFAULT)
idx = UNITS_DEFAULT;
else
switch (DBWUnits & DBW_UNITS_TYPE_MASK)
{
case DBW_UNITS_INTERNAL:
idx = UNITS_INTERNAL;
break;
case DBW_UNITS_LAMBDA:
idx = UNITS_LAMBDA;
break;
case DBW_UNITS_USER:
idx = UNITS_USER;
break;
case DBW_UNITS_MICRONS:
idx = UNITS_MICRONS;
break;
}
if (n == UNITS_LIST) /* list */
{
#ifdef MAGIC_WRAPPER
Tcl_Obj *tobj;
tobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj((char *)names[idx], -1));
if (idx != UNITS_DEFAULT)
{
if (DBWUnits & DBW_UNITS_PRINT_FLAG)
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj("print", 5));
else
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj("noprint", 7));
}
Tcl_SetObjResult(magicinterp, tobj);
#else
TxPrintf("%s", names[idx]);
if (idx != UNITS_DEFAULT)
if (DBWUnits & DBW_UNITS_PRINT_FLAG)
TxPrintf(" print");
TxPrintf("\n");
#endif
}
else if (idx == UNITS_DEFAULT)
TxPrintf("Reported units follow the snap setting.\n");
else if (DBWUnits & DBW_UNITS_PRINT_FLAG)
TxPrintf("Values are reported as %s, along with the units.\n", names[idx]);
else
TxPrintf("Values are reported as %s\n", names[idx]);
}
/*
* ----------------------------------------------------------------------------
*
@ -830,7 +1090,8 @@ struct linked_id {
int
cmdWhatPrintCell(
Tile *tile,
Tile *tile, /* (unused) */
TileType dinfo, /* (unused) */
TreeContext *cxp)
{
struct linked_id **lid = (struct linked_id **)cxp->tc_filter->tf_arg;
@ -885,6 +1146,7 @@ static LabelStore *labelBlockTop, *labelEntry;
int
cmdFindWhatTileFunc(
Tile *tile,
TileType dinfo,
ClientData clientData)
{
struct linked_id **lid = (struct linked_id **)clientData;
@ -896,7 +1158,7 @@ cmdFindWhatTileFunc(
scx.scx_use = EditCellUse;
scx.scx_trans = GeoIdentityTransform;
if (SplitSide(tile))
if (dinfo & TT_SIDE)
type = SplitRightType(tile);
else
type = SplitLeftType(tile);
@ -1094,11 +1356,13 @@ CmdWhat(
}
#endif
while (lid != NULL)
{
freeMagic(lid);
free_magic1_t mm1 = freeMagic1_init();
while (lid != NULL)
{
freeMagic1(&mm1, lid);
lid = lid->lid_next;
}
freeMagic1_end(&mm1);
#ifdef MAGIC_WRAPPER
if (doListAll)
Tcl_ListObjAppendElement(magicinterp, paintobj,
@ -1681,18 +1945,20 @@ CmdWire(
case VALUES:
if (locargc == 2)
{
char *wdisp;
width = WireGetWidth();
type = WireGetType();
wdisp = DBWPrintValue(width, w, TRUE);
#ifdef MAGIC_WRAPPER
lobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(width));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(DBTypeLongNameTbl[type], -1));
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(wdisp, -1));
Tcl_SetObjResult(magicinterp, lobj);
#else
TxPrintf("Wire layer %s, width %d\n",
DBTypeLongNameTbl[type], width);
TxPrintf("Wire layer %s, width %s\n",
DBTypeLongNameTbl[type], wdisp);
#endif
}
break;
@ -1717,12 +1983,14 @@ CmdWire(
case WIDTH:
if (locargc == 2)
{
char *wdisp;
width = WireGetWidth();
wdisp = DBWPrintValue(width, w, TRUE);
#ifdef MAGIC_WRAPPER
lobj = Tcl_NewIntObj(width);
lobj = Tcl_NewStringObj(wdisp, -1);
Tcl_SetObjResult(magicinterp, lobj);
#else
TxPrintf("Wire width is %d\n", width);
TxPrintf("Wire width is %s\n", wdisp);
#endif
}
else if (locargc != 3)

View File

@ -47,6 +47,10 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
#include "utils/utils.h"
#include "textio/txcommands.h"
/* For diagnostics */
#include "cif/CIFint.h"
#include "database/databaseInt.h"
/* C99 compat */
#include "extract/extract.h"
@ -189,6 +193,234 @@ CmdExtractTest(
}
#endif
/*
* ----------------------------------------------------------------------------
*
* tileCountProc --
*
* Routine to count tiles.
*
* Return:
* 0 to keep the search going
*
* Side effects:
* Keeps count in clientData
*
* ----------------------------------------------------------------------------
*/
int
tileCountProc(
Tile *tile, /* (unused) */
TileType dinfo, /* (unused) */
int *tcount)
{
(*tcount)++;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* showMem --
* CmdShowmem --
*
* Usage:
*
* showmem [outfile]
*
* Display all the (principle) internal memory usage for tiles, including
* all cell defs, and all CIF generated planes.
*
* Results:
* None.
*
* Side effects:
* May write to a disk file.
*
* ----------------------------------------------------------------------------
*/
void
showMem(
FILE *outf, /* File to which information is to be output */
bool verbose) /* If TRUE, output detailed erase table */
{
int ttotal, ttotal1, ttotal2;
int i;
Plane *plane;
CellDef *def;
int pNum;
HashSearch hs;
HashEntry *entry;
fprintf(outf, "Tile memory usage summary\n");
fprintf(outf, "Technology %s\n", DBTechName);
/* Search every cell def (including internal ones), count tiles,
* and add up the tile memory usage on every plane.
*/
/* Search the CIFPlanes and count tiles. */
/* CIFPlanes, CIFTotalPlanes, CIFComponentPlanes */
ttotal2 = 0;
if (CIFCurStyle != NULL)
{
fprintf(outf, "\nCIFPlanes:\n");
ttotal1 = 0;
for (i = 0; i < MAXCIFLAYERS; i++)
{
plane = CIFPlanes[i];
if (plane != NULL)
{
ttotal = 0;
DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect,
&DBAllTypeBits, tileCountProc, &ttotal);
ttotal1 += ttotal;
if (CIFCurStyle->cs_layers[i])
fprintf(outf, " layer %s: %ld\n",
CIFCurStyle->cs_layers[i]->cl_name,
(long)ttotal * (long)sizeof(Tile));
else
fprintf(outf, " layer %d: %d\n", i,
(long)ttotal * (long)sizeof(Tile));
}
}
fprintf(outf, " Subtotal: %ld bytes\n",
(long)ttotal1 * (long)sizeof(Tile));
ttotal2 += ttotal1;
fprintf(outf, "\nCIFTotalPlanes\n");
ttotal1 = 0;
for (i = 0; i < MAXCIFLAYERS; i++)
{
plane = CIFTotalPlanes[i];
if (plane != NULL)
{
ttotal = 0;
DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect,
&DBAllTypeBits, tileCountProc, &ttotal);
ttotal1 += ttotal;
if (CIFCurStyle->cs_layers[i])
fprintf(outf, " layer %s: %ld\n",
CIFCurStyle->cs_layers[i]->cl_name,
(long)ttotal * (long)sizeof(Tile));
else
fprintf(outf, " layer %d: %d\n", i,
(long)ttotal * (long)sizeof(Tile));
}
}
fprintf(outf, " Subtotal: %ld bytes\n",
(long)ttotal1 * (long)sizeof(Tile));
ttotal2 += ttotal1;
fprintf(outf, "\nCIFComponentPlanes\n");
ttotal1 = 0;
for (i = 0; i < MAXCIFLAYERS; i++)
{
plane = CIFComponentPlanes[i];
if (plane != NULL)
{
ttotal = 0;
DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect,
&DBAllTypeBits, tileCountProc, &ttotal);
ttotal1 += ttotal;
if (CIFCurStyle->cs_layers[i])
fprintf(outf, " layer %s: %ld bytes\n",
CIFCurStyle->cs_layers[i]->cl_name,
(long)ttotal * (long)sizeof(Tile));
else
fprintf(outf, " layer %d: %ld bytes\n", i,
(long)ttotal * (long)sizeof(Tile));
}
}
fprintf(outf, " Subtotal: %ld bytes\n",
(long)ttotal1 * (long)sizeof(Tile));
ttotal2 += ttotal1;
}
else
{
fprintf(outf, "CIF planes: No memory usage\n");
}
HashStartSearch(&hs);
while ((entry = HashNext(&dbCellDefTable, &hs)) != NULL)
{
def = (CellDef *)HashGetValue(entry);
if (def != (CellDef *)NULL)
{
fprintf(outf, "\nCell def %s\n", def->cd_name);
ttotal1 = 0;
for (pNum = 0; pNum < DBNumPlanes; pNum++)
{
plane = def->cd_planes[pNum];
if (plane != NULL)
{
ttotal = 0;
DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect,
&DBAllTypeBits, tileCountProc, &ttotal);
fprintf(outf, " plane %s: %ld bytes\n",
DBPlaneLongNameTbl[pNum],
(long)ttotal * (long)sizeof(Tile));
ttotal1 += ttotal;
}
}
fprintf(outf, " Subtotal: %ld bytes\n",
(long)ttotal1 * (long)sizeof(Tile));
ttotal2 += ttotal1;
}
}
fprintf(outf, " Grand total: %ld bytes\n",
(long)ttotal2 * (long)sizeof(Tile));
}
void
CmdShowmem(
MagWindow *w,
TxCommand *cmd)
{
FILE *outf;
bool verbose;
char **av;
int ac;
if (cmd->tx_argc > 3)
{
TxError("Usage: showmem [-v] [file]\n");
return;
}
verbose = FALSE;
av = &cmd->tx_argv[1];
ac = cmd->tx_argc - 1;
outf = stdout;
if (ac > 0 && strcmp(av[0], "-v") == 0)
{
verbose = TRUE;
av++, ac--;
}
if (ac > 0)
{
outf = fopen(av[0], "w");
if (outf == (FILE *) NULL)
{
perror(av[0]);
TxError("Nothing written\n");
return;
}
}
showMem(outf, verbose);
if (outf != stdout)
(void) fclose(outf);
}
/*
* ----------------------------------------------------------------------------
@ -232,7 +464,7 @@ showTech(
fprintf(outf, "\n");
fprintf(outf, "Types:\n");
for (i = 0; i < DBNumTypes; i++) {
int pl ; char *spl ;
int pl ; const char *spl ;
pl = DBPlane(i);
spl = ( pl <= 0 || pl > DBNumPlanes ) ? "??" : DBPlaneLongName(pl);
@ -569,11 +801,13 @@ cmdStatsCount(
CellDef *def,
struct countClient *cc)
{
int cmdStatsCountTile(Tile *tile, struct cellInfo *ci);
int pNum;
struct cellInfo *ci;
TileType t;
/* Forward declaration */
int cmdStatsCountTile(Tile *tile, TileType dinfo, struct cellInfo *ci);
if (def->cd_client)
return (1);
@ -598,6 +832,7 @@ cmdStatsCount(
int
cmdStatsCountTile(
Tile *tile,
TileType dinfo, /* (unused) */
struct cellInfo *ci)
{
TileType type = TiGetType(tile);
@ -868,17 +1103,18 @@ CmdTsearch(
MagWindow *w,
TxCommand *cmd)
{
int cmdTsrFunc(Tile *tp);
char *RunStats(int flags, struct tms *lastt, struct tms *deltat);
char *rstatp;
static TileTypeBitMask mask;
static struct tms tlast, tdelta;
Rect rtool, rsearch;
/**** Rect *ebox; ****/
Plane *plane;
int i, pNum, count;
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)
{
TxError("Usage: tsearch plane count [mask [new|mayo]]\n");
@ -978,10 +1214,12 @@ CmdTsearch(
int
cmdTsrFunc(
Tile *tp)
Tile *tp,
TileType dinfo, /* (unused) */
ClientData clientdata) /* (unused) */
{
if (cmdTsearchDebug)
TxPrintf("%lx\n", (intmax_t) tp);
TxPrintf("%lx\n", (intptr_t) tp);
numTilesFound++;
return 0;
}
@ -1047,7 +1285,7 @@ CmdWatch(
pNum = DBTechNamePlane(cmd->tx_argv[1]);
if (pNum < 0)
{
char *cp;
const char *cp;
TxError("Unrecognized plane: %s. Legal names are:\n",
cmd->tx_argv[1]);
for(pNum=0; pNum < PL_MAXTYPES; pNum++) {

View File

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

View File

@ -108,16 +108,55 @@ DBCellFindDup(use, parent)
"DBCellFindDup");
while ((dupUse = BPEnumNext(&bpe)))
if (dupUse->cu_def == use->cu_def)
{
bool transMatch, arrayMatch, notXarray, notYarray;
/* Transforms must be equal---Aligned bounding boxes are
* an insufficient measure of exact overlap.
* an insufficient measure of exact overlap. Also, array
* counts and separation must match for arrayed devices
*/
if ((dupUse->cu_transform.t_a == use->cu_transform.t_a) &&
transMatch = ((dupUse->cu_transform.t_a == use->cu_transform.t_a) &&
(dupUse->cu_transform.t_b == use->cu_transform.t_b) &&
(dupUse->cu_transform.t_c == use->cu_transform.t_c) &&
(dupUse->cu_transform.t_d == use->cu_transform.t_d) &&
(dupUse->cu_transform.t_e == use->cu_transform.t_e) &&
(dupUse->cu_transform.t_f == use->cu_transform.t_f))
(dupUse->cu_transform.t_f == use->cu_transform.t_f));
/* First check if both use and dupUse are not arrays. */
notXarray = (dupUse->cu_xhi == dupUse->cu_xlo) &&
(use->cu_xhi == use->cu_xlo);
notYarray = (dupUse->cu_yhi == dupUse->cu_ylo) &&
(use->cu_yhi == use->cu_ylo);
arrayMatch = (notXarray && notYarray);
/* If they are arrays, then the array parameters must match. */
if (!notXarray && notYarray)
{
arrayMatch = ((dupUse->cu_xhi - dupUse->cu_xlo) ==
(use->cu_xhi - use->cu_xlo)) &&
(dupUse->cu_xsep == use->cu_xsep);
}
else if (!notYarray && notXarray)
{
arrayMatch = ((dupUse->cu_yhi - dupUse->cu_ylo) ==
(use->cu_yhi - use->cu_ylo)) &&
(dupUse->cu_ysep == use->cu_ysep);
}
else if (!notYarray && !notXarray)
{
arrayMatch = (((dupUse->cu_xhi - dupUse->cu_xlo) ==
(use->cu_xhi - use->cu_xlo)) &&
(dupUse->cu_xsep == use->cu_xsep)) &&
(((dupUse->cu_yhi - dupUse->cu_ylo) ==
(use->cu_yhi - use->cu_ylo)) &&
(dupUse->cu_ysep == use->cu_ysep));
}
if (transMatch && arrayMatch)
break;
}
BPEnumTerm(&bpe);
return dupUse;

View File

@ -619,8 +619,9 @@ dbReComputeBboxFunc(cellDef, boundProc, recurseProc)
/*
* Include area of subcells separately
*/
if ((foundAny = DBBoundCellPlane(cellDef, &extended, &rect)) > 0)
area = rect;
if (!((foundAny = DBBoundCellPlane(cellDef, &extended, &rect)) > 0))
extended = GeoNullRect;
area = rect;
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
if (pNum != PL_DRC_CHECK)

View File

@ -37,9 +37,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "commands/commands.h"
/* C99 compat */
#include "graphics/graphics.h"
#include "cif/CIFint.h"
/*
* The following variable points to the tables currently used for
@ -357,9 +356,43 @@ DBCellCheckCopyAllPaint(scx, mask, xMask, targetUse, func)
struct propUseDefStruct {
CellDef *puds_source;
CellDef *puds_dest;
Plane *puds_plane; /* Mask hint plane in dest */
Transform *puds_trans; /* Transform from source use to dest */
Rect *puds_area; /* Clip area in source coordinates */
};
/*
*-----------------------------------------------------------------------------
*
* dbCopyMaskHintPlaneFunc --
*
* Translate tiles from a child mask-hint property plane into the
* coordinate system of the parent, and paint the mask-hint area
* into the mask-hint property plane of the parent.
*
*-----------------------------------------------------------------------------
*/
int
dbCopyMaskHintPlaneFunc(Tile *tile,
TileType dinfo,
struct propUseDefStruct *puds)
{
Transform *trans = puds->puds_trans;
Rect *clip = puds->puds_area;
Rect r, rnew;
Plane *plane = puds->puds_plane;
TiToRect(tile, &r);
GeoClip(&r, clip);
if (!GEO_RECTNULL(&r))
{
GeoTransRect(trans, &r, &rnew);
DBPaintPlane(plane, &rnew, CIFPaintTable, (PaintUndoInfo *)NULL);
}
return 0;
}
/*
*-----------------------------------------------------------------------------
*
@ -380,63 +413,52 @@ struct propUseDefStruct {
*/
int
dbCopyMaskHintsFunc(key, value, puds)
dbCopyMaskHintsFunc(key, proprec, puds)
char *key;
ClientData value;
PropertyRecord *proprec;
struct propUseDefStruct *puds;
{
CellDef *dest = puds->puds_dest;
Transform *trans = puds->puds_trans;
char *propstr = (char *)value;
Rect *clip = puds->puds_area;
PropertyRecord *parentproprec, *newproprec;
char *parentprop, *newvalue, *vptr;
Rect r, rnew;
bool propfound;
int i, j;
if (!strncmp(key, "MASKHINTS_", 10))
{
char *vptr, *lastval;
int lastlen;
Plane *plane;
/* Append to existing mask hint (if any) */
parentprop = (char *)DBPropGet(dest, key, &propfound);
newvalue = (propfound) ? StrDup((char **)NULL, parentprop) : (char *)NULL;
ASSERT(proprec->prop_type == PROPERTY_TYPE_PLANE, "dbCopyMaskHintsFunc");
vptr = propstr;
while (*vptr != '\0')
/* Get the existing mask hint plane in the parent cell, and
* create it if it does not already exist.
*/
parentproprec = (PropertyRecord *)DBPropGet(dest, key, &propfound);
if (propfound)
plane = parentproprec->prop_value.prop_plane;
else
{
if (sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
&r.r_xtop, &r.r_ytop) == 4)
{
GeoTransRect(trans, &r, &rnew);
lastval = newvalue;
lastlen = (lastval) ? strlen(lastval) : 0;
newvalue = mallocMagic(40 + lastlen);
if (lastval)
strcpy(newvalue, lastval);
else
*newvalue = '\0';
sprintf(newvalue + lastlen, "%s%d %d %d %d", (lastval) ? " " : "",
rnew.r_xbot, rnew.r_ybot, rnew.r_xtop, rnew.r_ytop);
if (lastval) freeMagic(lastval);
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
}
else break;
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
newproprec->prop_type = PROPERTY_TYPE_PLANE;
newproprec->prop_len = 0;
plane = DBNewPlane((ClientData)TT_SPACE);
newproprec->prop_value.prop_plane = plane;
DBPropPut(dest, key, newproprec);
}
if (newvalue)
DBPropPut(dest, key, newvalue);
}
puds->puds_plane = plane;
/* Copy the properties from child to parent */
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
proprec->prop_value.prop_plane,
clip, &CIFSolidBits, dbCopyMaskHintPlaneFunc,
(ClientData)puds);
}
return 0;
}
@ -468,6 +490,7 @@ DBCellCopyMaskHints(child, parent, transform)
puds.puds_source = child->cu_def;
puds.puds_dest = parent;
puds.puds_trans = transform;
puds.puds_area = (Rect *)&TiPlaneRect;
DBPropEnum(child->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
}
@ -501,6 +524,7 @@ dbFlatCopyMaskHintsFunc(scx, def)
puds.puds_source = scx->scx_use->cu_def;
puds.puds_dest = def;
puds.puds_trans = &scx->scx_trans;
puds.puds_area = &scx->scx_area;
DBPropEnum(use->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
@ -967,14 +991,15 @@ DBCellGenerateSimpleSubstrate(scx, subType, notSubMask, targetDef)
*/
int
dbEraseSubFunc(tile, cxp)
dbEraseSubFunc(tile, dinfo, cxp)
Tile *tile; /* Pointer to source tile with shield type */
TileType dinfo; /* Split tile information */
TreeContext *cxp; /* Context from DBTreeSrTiles */
{
SearchContext *scx;
Rect sourceRect, targetRect;
int pNum;
TileType dinfo, loctype, subType;
TileType newdinfo, loctype, subType;
Plane *plane;
struct dbCopySubData *csd; /* Client data */
@ -983,13 +1008,14 @@ dbEraseSubFunc(tile, cxp)
plane = csd->csd_plane;
pNum = csd->csd_pNum;
subType = csd->csd_subtype;
dinfo = TiGetTypeExact(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;
dinfo = DBTransformDiagonal(dinfo, &scx->scx_trans);
newdinfo = DBTransformDiagonal(TiGetTypeExact(tile) | dinfo, &scx->scx_trans);
}
else
newdinfo = (TileType)0;
/* Construct the rect for the tile */
TITORECT(tile, &sourceRect);
@ -999,7 +1025,7 @@ dbEraseSubFunc(tile, cxp)
csd->csd_modified = TRUE;
return DBNMPaintPlane(plane, dinfo, &targetRect, DBStdEraseTbl(subType, pNum),
return DBNMPaintPlane(plane, newdinfo, &targetRect, DBStdEraseTbl(subType, pNum),
(PaintUndoInfo *)NULL);
}
@ -1011,14 +1037,15 @@ dbEraseSubFunc(tile, cxp)
*/
int
dbPaintSubFunc(tile, cxp)
dbPaintSubFunc(tile, dinfo, cxp)
Tile *tile; /* Pointer to source tile with shield type */
TileType dinfo; /* Split tile information */
TreeContext *cxp; /* Context from DBTreeSrTiles */
{
SearchContext *scx;
Rect sourceRect, targetRect;
int pNum;
TileType dinfo, loctype, subType;
TileType newdinfo, loctype, subType;
Plane *plane;
struct dbCopySubData *csd; /* Client data */
@ -1027,13 +1054,14 @@ dbPaintSubFunc(tile, cxp)
plane = csd->csd_plane;
pNum = csd->csd_pNum;
subType = csd->csd_subtype;
dinfo = TiGetTypeExact(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;
dinfo = DBTransformDiagonal(dinfo, &scx->scx_trans);
newdinfo = DBTransformDiagonal(TiGetTypeExact(tile) | dinfo, &scx->scx_trans);
}
else
newdinfo = (TileType)0;
/* Construct the rect for the tile */
TITORECT(tile, &sourceRect);
@ -1043,7 +1071,7 @@ dbPaintSubFunc(tile, cxp)
csd->csd_modified = TRUE;
return DBNMPaintPlane(plane, dinfo, &targetRect, DBStdPaintTbl(subType, pNum),
return DBNMPaintPlane(plane, newdinfo, &targetRect, DBStdPaintTbl(subType, pNum),
(PaintUndoInfo *)NULL);
}
@ -1056,14 +1084,15 @@ dbPaintSubFunc(tile, cxp)
*/
int
dbEraseNonSub(tile, cxp)
dbEraseNonSub(tile, dinfo, cxp)
Tile *tile; /* Pointer to tile to erase from target */
TileType dinfo; /* Split tile information */
TreeContext *cxp; /* Context from DBTreeSrTiles */
{
SearchContext *scx;
Rect sourceRect, targetRect;
Plane *plane; /* Plane of target data */
TileType dinfo, loctype, subType;
TileType newdinfo, loctype, subType;
struct dbCopySubData *csd;
int pNum;
@ -1074,13 +1103,14 @@ dbEraseNonSub(tile, cxp)
scx = cxp->tc_scx;
dinfo = TiGetTypeExact(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;
dinfo = DBTransformDiagonal(dinfo, &scx->scx_trans);
newdinfo = DBTransformDiagonal(TiGetTypeExact(tile) | dinfo, &scx->scx_trans);
}
else
newdinfo = (TileType)0;
/* Construct the rect for the tile */
TITORECT(tile, &sourceRect);
@ -1089,7 +1119,7 @@ dbEraseNonSub(tile, cxp)
GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect);
/* 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);
}
@ -1101,8 +1131,9 @@ dbEraseNonSub(tile, cxp)
*/
int
dbCopySubFunc(tile, csd)
dbCopySubFunc(tile, dinfo, csd)
Tile *tile; /* Pointer to tile to erase from target */
TileType dinfo; /* Split tile information */
struct dbCopySubData *csd; /* Client data */
{
Rect rect;
@ -1112,10 +1143,10 @@ dbCopySubFunc(tile, csd)
plane = csd->csd_plane;
pNum = csd->csd_pNum;
type = TiGetTypeExact(tile);
type = TiGetTypeExact(tile) | dinfo;
if (IsSplit(tile))
{
loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
loctype = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
if (loctype == TT_SPACE) return 0;
}
else
@ -1436,8 +1467,9 @@ DBCellCopyLabels(scx, mask, xMask, targetUse, pArea)
***/
int
dbCopyManhattanPaint(tile, cxp)
Tile *tile; /* Pointer to tile to copy */
dbCopyManhattanPaint(tile, dinfo, cxp)
Tile *tile; /* Pointer to tile to copy */
TileType dinfo; /* Split tile information */
TreeContext *cxp; /* Context from DBTreeSrTiles */
{
SearchContext *scx = cxp->tc_scx;
@ -1483,8 +1515,9 @@ dbCopyManhattanPaint(tile, cxp)
***/
int
dbCopyAllPaint(tile, cxp)
Tile *tile; /* Pointer to tile to copy */
dbCopyAllPaint(tile, dinfo, cxp)
Tile *tile; /* Pointer to tile to copy */
TileType dinfo; /* Split tile information */
TreeContext *cxp; /* Context from DBTreeSrTiles */
{
SearchContext *scx = cxp->tc_scx;
@ -1492,7 +1525,7 @@ dbCopyAllPaint(tile, cxp)
Rect sourceRect, targetRect;
PaintUndoInfo ui;
CellDef *def;
TileType type = TiGetTypeExact(tile);
TileType type = TiGetTypeExact(tile) | dinfo;
int pNum = cxp->tc_plane;
int result;
TileTypeBitMask *typeMask;
@ -1505,13 +1538,13 @@ dbCopyAllPaint(tile, cxp)
*/
bool splittile = FALSE;
TileType dinfo = 0;
TileType newdinfo = 0;
if (IsSplit(tile))
{
splittile = TRUE;
dinfo = DBTransformDiagonal(type, &scx->scx_trans);
type = (SplitSide(tile)) ? SplitRightType(tile) :
newdinfo = DBTransformDiagonal(type, &scx->scx_trans);
type = (dinfo & TT_SIDE) ? SplitRightType(tile) :
SplitLeftType(tile);
}
@ -1571,7 +1604,7 @@ dbCopyAllPaint(tile, cxp)
Rect rrect, orect;
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)
return(0);
@ -1600,7 +1633,7 @@ dbCopyAllPaint(tile, cxp)
rrect.r_ybot = points[0].p_y;
rrect.r_ytop = points[2].p_y;
GeoCanonicalRect(&rrect, &targetRect);
dinfo = 0;
newdinfo = 0;
}
else if (np >= 4) /* Process extra rectangles in the area */
{
@ -1657,7 +1690,7 @@ topbottom:
splitdone:
result = (*dbCurPaintPlane)(def, pNum, dinfo | type, &targetRect, &ui);
result = (*dbCurPaintPlane)(def, pNum, newdinfo | type, &targetRect, &ui);
if ((result != 0) && (arg->caa_func != NULL))
{
/* result == 1 used exclusively for DRC off-grid error flagging */

View File

@ -117,6 +117,14 @@ DBCellRename(cellname, newname, doforce)
return FALSE;
}
/* Cannot rename a cell with the name of an existing cell */
entry = HashLookOnly(&dbCellDefTable, newname);
if (entry != NULL)
{
TxError("Cannot rename; cell \"%s\" already exists!\n", newname);
return FALSE;
}
/* Disallow renaming if the cell has the READONLY flag set, */
/* because the cellname must match the name in the GDS */
/* file referenced. */
@ -144,10 +152,9 @@ DBCellRename(cellname, newname, doforce)
if (doforce && ((celldef->cd_flags & CDVENDORGDS) == CDVENDORGDS))
{
char *chkgdsfile;
bool isReadOnly;
chkgdsfile = (char *)DBPropGet(celldef, "GDS_FILE", &isReadOnly);
DBPropGet(celldef, "GDS_FILE", &isReadOnly);
/* Note that clearing GDS_FILE will also clear CDVENDORGDS flag */
if (isReadOnly) DBPropPut(celldef, "GDS_FILE", NULL);
@ -312,6 +319,7 @@ DBCellDelete(cellname, force)
/* use. If so, load the window with (UNNAMED). */
UndoDisable();
free_magic1_t mm1 = freeMagic1_init();
for (celluse = celldef->cd_parents; celluse != (CellUse *) NULL;
celluse = celluse->cu_nextuse)
{
@ -320,8 +328,9 @@ DBCellDelete(cellname, force)
WindUnload(celluse);
freeMagic(celluse->cu_id);
}
freeMagic((char *)celluse);
freeMagic1(&mm1, (char *)celluse);
}
freeMagic1_end(&mm1);
celldef->cd_parents = (CellUse *)NULL;
DBWResetBox(celldef);
@ -1610,7 +1619,9 @@ dbAbutmentUseFunc(selUse, use, transform, data)
{
Rect bbox, refbox;
Transform *trans;
PropertyRecord *proprec;
char *propvalue;
char *refllx, *reflly, *refurx, *refury;
bool found;
bool *dolist = (bool *)data;
@ -1632,32 +1643,47 @@ dbAbutmentUseFunc(selUse, use, transform, data)
}
trans = &use->cu_transform;
propvalue = (char *)DBPropGet(use->cu_def, "FIXED_BBOX", &found);
proprec = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
if (!found)
bbox = use->cu_def->cd_bbox;
else
{
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) != 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
}
else
{
TxError("Unable to parse the cell's FIXED_BBOX property; using "
"the instance bounding box instead.\n");
bbox = use->cu_def->cd_bbox;
}
}
GeoTransRect(trans, &bbox, &refbox);
/* NOTE: Ideally, the MagWindow pointer should get passed to this routine */
refllx = DBWPrintValue(refbox.r_xbot, (MagWindow *)NULL, TRUE);
reflly = DBWPrintValue(refbox.r_ybot, (MagWindow *)NULL, FALSE);
refurx = DBWPrintValue(refbox.r_xtop, (MagWindow *)NULL, TRUE);
refury = DBWPrintValue(refbox.r_ytop, (MagWindow *)NULL, FALSE);
#ifdef MAGIC_WRAPPER
if (*dolist)
{
pobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_xbot));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_ybot));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_xtop));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_ytop));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(refllx, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(reflly, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(refurx, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(refury, -1));
Tcl_SetObjResult(magicinterp, pobj);
}
else
#endif
TxPrintf("Abutment box: %d %d %d %d\n", refbox.r_xbot, refbox.r_ybot,
refbox.r_xtop, refbox.r_ytop);
TxPrintf("Abutment box: %s %s %s %s\n", refllx, reflly, refurx, refury);
return 0;
}
@ -1936,6 +1962,7 @@ DBCellDeleteDef(cellDef)
entry = HashFind(&dbCellDefTable, cellDef->cd_name);
ASSERT(HashGetValue(entry) == (ClientData) cellDef, "DBCellDeleteDef");
HashSetValue(entry, (ClientData) NULL);
HashRemove(&dbCellDefTable, cellDef->cd_name);
if (cellDef->cd_props)
DBPropClearAll(cellDef);
@ -1997,8 +2024,10 @@ DBCellDefFree(cellDef)
cellDef->cd_planes[pNum] = (Plane *) NULL;
}
free_magic1_t mm1 = freeMagic1_init();
for (lab = cellDef->cd_labels; lab; lab = lab->lab_next)
freeMagic((char *) lab);
freeMagic1(&mm1, (char *) lab);
freeMagic1_end(&mm1);
SigEnableInterrupts();
HashKill(&cellDef->cd_idHash);

View File

@ -85,11 +85,13 @@ struct seeTypesArg
int
DBSrCellPlaneArea(BPlane *plane, const Rect *rect, int (*func)(), ClientData arg)
{
BPEnum sbpe;
BPEnum *bpe;
CellUse *use;
int rval = 0;
bpe = (BPEnum *)mallocMagic(sizeof(BPEnum));
/* bpe = (BPEnum *)mallocMagic(sizeof(BPEnum)); */
bpe = &sbpe;
BPEnumInit(bpe, plane, rect, BPE_OVERLAP, "DBSrCellPlaneArea");
while ((use = BPEnumNext(bpe)))
@ -102,7 +104,7 @@ DBSrCellPlaneArea(BPlane *plane, const Rect *rect, int (*func)(), ClientData arg
}
BPEnumTerm(bpe);
freeMagic(bpe);
/* freeMagic(bpe); */
return rval;
}
@ -118,6 +120,7 @@ DBSrCellPlaneArea(BPlane *plane, const Rect *rect, int (*func)(), ClientData arg
* int
* func(tile, cxp)
* Tile *tile;
* TileType dinfo;
* TreeContext *cxp;
* {
* }
@ -414,6 +417,7 @@ dbCellUniqueTileSrFunc(scx, fp)
* int
* func(tile, cxp)
* Tile *tile;
* TileType dinfo;
* TreeContext *cxp;
* {
* }
@ -584,6 +588,25 @@ DBTreeSrLabels(scx, mask, xMask, tpath, flags, func, cdarg)
if (!DBCellRead(def, TRUE, TRUE, NULL))
return 0;
if (flags & TF_LABEL_REVERSE_SEARCH)
{
/* Search children first */
filter.tf_func = func;
filter.tf_arg = cdarg;
filter.tf_mask = mask;
filter.tf_xmask = xMask;
filter.tf_tpath = tpath;
filter.tf_flags = flags;
scx2 = *scx;
if (scx2.scx_area.r_xbot > TiPlaneRect.r_xbot) scx2.scx_area.r_xbot -= 1;
if (scx2.scx_area.r_ybot > TiPlaneRect.r_ybot) scx2.scx_area.r_ybot -= 1;
if (scx2.scx_area.r_xtop < TiPlaneRect.r_xtop) scx2.scx_area.r_xtop += 1;
if (scx2.scx_area.r_ytop < TiPlaneRect.r_ytop) scx2.scx_area.r_ytop += 1;
if (DBCellSrArea(&scx2, dbCellLabelSrFunc, (ClientData) &filter))
return 1;
}
for (lab = def->cd_labels; lab; lab = lab->lab_next)
{
if (SigInterruptPending) break;
@ -636,6 +659,8 @@ DBTreeSrLabels(scx, mask, xMask, tpath, flags, func, cdarg)
return (1);
}
if (flags & TF_LABEL_REVERSE_SEARCH) return 0; /* children already searched */
filter.tf_func = func;
filter.tf_arg = cdarg;
filter.tf_mask = mask;
@ -707,6 +732,16 @@ dbCellLabelSrFunc(scx, fp)
}
}
/* If fp->tf_flags has TF_LABEL_REVERSE_SEARCH, then search child
* uses first, then the parent. This is for display, so that if
* a child cell and parent cell have overlapping labels, the parent
* label is the one on top.
*/
if (fp->tf_flags & TF_LABEL_REVERSE_SEARCH)
if (DBCellSrArea(scx, dbCellLabelSrFunc, (ClientData) fp))
result = 1;
/* Apply the function first to any of the labels in this def. */
result = 0;
@ -728,9 +763,11 @@ dbCellLabelSrFunc(scx, fp)
}
}
/* Now visit each child use recursively */
if (DBCellSrArea(scx, dbCellLabelSrFunc, (ClientData) fp))
result = 1;
/* Now visit each child use recursively, if not doing a reverse search */
if (!(fp->tf_flags & TF_LABEL_REVERSE_SEARCH))
if (DBCellSrArea(scx, dbCellLabelSrFunc, (ClientData) fp))
result = 1;
cleanup:
/* Remove the trailing pathname component from the TerminalPath */
@ -912,8 +949,9 @@ DBSeeTypesAll(rootUse, rootRect, xMask, mask)
*/
int
dbSeeTypesAllSrFunc(tile, cxp)
dbSeeTypesAllSrFunc(tile, dinfo, cxp)
Tile *tile;
TileType dinfo;
TreeContext *cxp;
{
Rect tileRect;
@ -924,7 +962,7 @@ dbSeeTypesAllSrFunc(tile, cxp)
if (GEO_OVERLAP((&tileRect), area))
{
if (IsSplit(tile))
TTMaskSetType(mask, SplitSide(tile) ?
TTMaskSetType(mask, (dinfo & TT_SIDE) ?
SplitRightType(tile) : SplitLeftType(tile));
else
TTMaskSetType(mask, TiGetType(tile));
@ -1514,13 +1552,14 @@ DBScaleEverything(scalen, scaled)
}
/* Free the linked CellDef list */
free_magic1_t mm1 = freeMagic1_init();
lcd = lhead;
while (lcd != NULL)
{
freeMagic((char *)lcd);
freeMagic1(&mm1, (char *)lcd);
lcd = lcd->cd_next;
}
freeMagic1_end(&mm1);
/* Scale all elements */
DBWScaleElements(scalen, scaled);
@ -1604,8 +1643,9 @@ dbScalePlane(oldplane, newplane, pnum, scalen, scaled, doCIF)
*/
int
dbTileScaleFunc(tile, scvals)
dbTileScaleFunc(tile, dinfo, scvals)
Tile *tile;
TileType dinfo;
struct scaleArg *scvals;
{
TileType type;
@ -1628,10 +1668,10 @@ dbTileScaleFunc(tile, scvals)
return 0;
}
type = TiGetTypeExact(tile);
type = TiGetTypeExact(tile) | dinfo;
exact = type;
if (IsSplit(tile))
type = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
DBNMPaintPlane(scvals->ptarget, exact, &targetRect,
(
#ifdef CIF_MODULE
@ -1686,8 +1726,9 @@ dbMovePlane(oldplane, newplane, pnum, origx, origy)
*/
int
dbTileMoveFunc(tile, mvvals)
dbTileMoveFunc(tile, dinfo, mvvals)
Tile *tile;
TileType dinfo;
struct moveArg *mvvals;
{
TileType type;
@ -1700,12 +1741,12 @@ dbTileMoveFunc(tile, mvvals)
DBMovePoint(&targetRect.r_ll, mvvals->origx, mvvals->origy);
DBMovePoint(&targetRect.r_ur, mvvals->origx, mvvals->origy);
type = TiGetTypeExact(tile);
type = TiGetTypeExact(tile) | dinfo;
exact = type;
if (IsSplit(tile))
type = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
DBNMPaintPlane(mvvals->ptarget, exact, &targetRect,
DBStdPaintTbl(type, mvvals->pnum),
(mvvals->pnum < 0) ? CIFPaintTable : DBStdPaintTbl(type, mvvals->pnum),
(PaintUndoInfo *)NULL);
return 0;
}
@ -1767,12 +1808,14 @@ DBSrCellUses(cellDef, func, arg)
}
/* Free this linked cellUse structure */
free_magic1_t mm1 = freeMagic1_init();
lu = luhead;
while (lu != NULL)
{
freeMagic((char *)lu);
freeMagic1(&mm1, (char *)lu);
lu = lu->cu_next;
}
freeMagic1_end(&mm1);
return retval;
}
@ -1796,84 +1839,48 @@ typedef struct _cellpropstruct {
* ----------------------------------------------------------------------------
*/
int dbScaleProp(name, value, cps)
int dbScaleProp(name, proprec, cps)
char *name;
char *value;
PropertyRecord *proprec;
CellPropStruct *cps;
{
int scalen, scaled;
char *newvalue, *vptr;
Rect r;
int i, scalen, scaled;
Point p;
if ((strlen(name) > 5) && !strncmp(name + strlen(name) - 5, "_BBOX", 5))
/* Only "dimension" and "plane" type properties get scaled */
if (proprec->prop_type == PROPERTY_TYPE_PLANE)
{
if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
&r.r_xtop, &r.r_ytop) == 4)
{
/* Scale numerator held in point X value, */
/* scale denominator held in point Y value */
scalen = cps->cps_point.p_x;
scaled = cps->cps_point.p_y;
DBScalePoint(&r.r_ll, scalen, scaled);
DBScalePoint(&r.r_ur, scalen, scaled);
newvalue = (char *)mallocMagic(40);
sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot,
r.r_xtop, r.r_ytop);
DBPropPut(cps->cps_def, name, newvalue);
}
Plane *newplane;
newplane = DBNewPlane((ClientData)TT_SPACE);
DBClearPaintPlane(newplane);
/* Plane index is unused; arbitrarily substitute -1 */
dbScalePlane(proprec->prop_value.prop_plane, newplane, -1,
scalen, scaled, TRUE);
DBFreePaintPlane(proprec->prop_value.prop_plane);
TiFreePlane(proprec->prop_value.prop_plane);
proprec->prop_value.prop_plane = newplane;
return 0;
}
else if (!strncmp(name, "MASKHINTS_", 10))
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
/* Scale numerator held in point X value, */
/* scale denominator held in point Y value */
scalen = cps->cps_point.p_x;
scaled = cps->cps_point.p_y;
for (i = 0; i < proprec->prop_len; i += 2)
{
char *vptr, *lastval;
int lastlen;
if ((i + 1) >= proprec->prop_len) break;
newvalue = (char *)NULL;
vptr = value;
while (*vptr != '\0')
{
if (sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
&r.r_xtop, &r.r_ytop) == 4)
{
/* Scale numerator held in point X value, */
/* scale denominator held in point Y value */
scalen = cps->cps_point.p_x;
scaled = cps->cps_point.p_y;
DBScalePoint(&r.r_ll, scalen, scaled);
DBScalePoint(&r.r_ur, scalen, scaled);
lastval = newvalue;
lastlen = (lastval) ? strlen(lastval) : 0;
newvalue = mallocMagic(40 + lastlen);
if (lastval)
strcpy(newvalue, lastval);
else
*newvalue = '\0';
sprintf(newvalue + lastlen, "%s%d %d %d %d", (lastval) ? " " : "",
r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
if (lastval) freeMagic(lastval);
/* Parse through the four values and check if there's more */
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
}
else break;
}
if (newvalue)
DBPropPut(cps->cps_def, name, newvalue);
p.p_x = proprec->prop_value.prop_integer[i];
p.p_y = proprec->prop_value.prop_integer[i + 1];
DBScalePoint(&p, scalen, scaled);
proprec->prop_value.prop_integer[i] = p.p_x;
proprec->prop_value.prop_integer[i + 1] = p.p_y;
}
return 0; /* Keep enumerating through properties */
}
@ -1889,33 +1896,47 @@ int dbScaleProp(name, value, cps)
* ----------------------------------------------------------------------------
*/
int dbMoveProp(name, value, cps)
int dbMoveProp(name, proprec, cps)
char *name;
char *value;
PropertyRecord *proprec;
CellPropStruct *cps;
{
int origx, origy;
int i, origx, origy;
char *newvalue;
Rect r;
Point p;
if (((strlen(name) > 5) && !strncmp(name + strlen(name) - 5, "_BBOX", 5))
|| !strncmp(name, "MASKHINTS_", 10))
/* Only "dimension" and "plane" type properties get scaled */
if (proprec->prop_type == PROPERTY_TYPE_PLANE)
{
if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
&r.r_xtop, &r.r_ytop) == 4)
{
origx = cps->cps_point.p_x;
origy = cps->cps_point.p_y;
Plane *newplane;
DBMovePoint(&r.r_ll, origx, origy);
DBMovePoint(&r.r_ur, origx, origy);
newvalue = (char *)mallocMagic(40);
sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot,
r.r_xtop, r.r_ytop);
DBPropPut(cps->cps_def, name, newvalue);
}
newplane = DBNewPlane((ClientData) TT_SPACE);
DBClearPaintPlane(newplane);
/* Use plane index -1 to indicate use of CIFPaintTable */
dbMovePlane(proprec->prop_value.prop_plane, newplane, -1, origx, origy);
DBFreePaintPlane(proprec->prop_value.prop_plane);
TiFreePlane(proprec->prop_value.prop_plane);
proprec->prop_value.prop_plane = newplane;
return 0;
}
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
origx = cps->cps_point.p_x;
origy = cps->cps_point.p_y;
for (i = 0; i < proprec->prop_len; i += 2)
{
if ((i + 1) >= proprec->prop_len) break;
p.p_x = proprec->prop_value.prop_integer[i];
p.p_y = proprec->prop_value.prop_integer[i + 1];
DBMovePoint(&p, origx, origy);
proprec->prop_value.prop_integer[i] = p.p_x;
proprec->prop_value.prop_integer[i + 1] = p.p_y;
}
return 0; /* Keep enumerating through properties */
}
@ -2000,12 +2021,14 @@ dbScaleCell(cellDef, scalen, scaled)
BPFree(cellPlaneOrig);
/* Free this linked cellUse structure */
free_magic1_t mm1 = freeMagic1_init();
lu = luhead;
while (lu != NULL)
{
freeMagic((char *)lu);
freeMagic1(&mm1, (char *)lu);
lu = lu->cu_next;
}
freeMagic1_end(&mm1);
/* Scale all of the paint tiles in this cell by creating a new plane */
/* and copying all tiles into the new plane at scaled dimensions. */
@ -2208,12 +2231,14 @@ DBMoveCell(cellDef, origx, origy)
BPFree(cellPlaneOrig);
/* Free this linked cellUse structure */
free_magic1_t mm1 = freeMagic1_init();
lu = luhead;
while (lu != NULL)
{
freeMagic((char *)lu);
freeMagic1(&mm1, (char *)lu);
lu = lu->cu_next;
}
freeMagic1_end(&mm1);
/* Move all of the paint tiles in this cell by creating a new plane */
/* and copying all tiles into the new plane at the new position. */

View File

@ -218,8 +218,10 @@ DBCellClearDef(cellDef)
cellDef->cd_bbox.r_xtop = cellDef->cd_bbox.r_ytop = 1;
cellDef->cd_extended.r_xbot = cellDef->cd_extended.r_ybot = 0;
cellDef->cd_extended.r_xtop = cellDef->cd_extended.r_ytop = 1;
free_magic1_t mm1 = freeMagic1_init();
for (lab = cellDef->cd_labels; lab; lab = lab->lab_next)
freeMagic((char *) lab);
freeMagic1(&mm1, (char *) lab);
freeMagic1_end(&mm1);
cellDef->cd_labels = (Label *) NULL;
cellDef->cd_lastLabel = (Label *) NULL;

View File

@ -128,85 +128,6 @@ DBInvTransformDiagonal(oldtype, trans)
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;
int startPlane, result;
Tile *startTile; /* Starting tile for search. */
TileAndDinfo start_tad; /* Starting tile and split information */
result = 0;
csa.csa_def = def;
@ -287,17 +208,18 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
* 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++)
{
csa.csa_pNum = startPlane;
if (DBSrPaintArea((Tile *) NULL,
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 */
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. */
@ -306,7 +228,8 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
csa.csa_clientDefault = CLIENTDEFAULT;
csa.csa_clear = FALSE;
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.
* Don't allow any interruptions.
@ -315,7 +238,7 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
SigDisableInterrupts();
csa.csa_clientFunc = NULL;
csa.csa_clear = TRUE;
(void) dbSrConnectFunc(startTile, PTR2CD(&csa));
(void) dbSrConnectFunc(start_tad.tad_tile, start_tad.tad_dinfo, PTR2CD(&csa));
SigEnableInterrupts();
return result;
@ -325,11 +248,12 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
int
dbSrConnectStartFunc(
Tile *tile, /* This will be the starting tile. */
ClientData cdata) /* We store tile's address here. */
/* (Tile **pTile) */
TileType dinfo, /* (unused) */
ClientData cdata) /* We store tile and split info here. */
{
Tile **pTile = (Tile **)CD2PTR(cdata);
*pTile = tile;
TileAndDinfo *tad = (TileAndDinfo *)CD2PTR(cdata);
tad->tad_tile = tile;
tad->tad_dinfo = dinfo;
return 1;
}
@ -367,7 +291,7 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
{
struct conSrArg csa;
int startPlane, result;
Tile *startTile; /* Starting tile for search. */
TileAndDinfo tad;
result = 0;
csa.csa_def = def;
@ -378,17 +302,18 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
* the tile address and returns.
*/
startTile = NULL;
tad.tad_tile = NULL;
tad.tad_next = NULL; /* unused */
for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++)
{
csa.csa_pNum = startPlane;
if (DBSrPaintArea((Tile *) NULL,
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 */
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. */
@ -397,7 +322,7 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
csa.csa_clientDefault = CLIENTDEFAULT;
csa.csa_clear = FALSE;
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;
}
@ -420,12 +345,15 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
*/
int
dbcFindTileFunc(tile, arg)
dbcFindTileFunc(tile, dinfo, arg)
Tile *tile;
TileType dinfo;
ClientData arg;
{
Tile **tptr = (Tile **)arg;
*tptr = tile;
TileAndDinfo *tad = (TileAndDinfo *)arg;
tad->tad_tile = tile;
tad->tad_dinfo = dinfo;
return 1;
}
@ -465,6 +393,7 @@ dbcFindTileFunc(tile, arg)
int
dbSrConnectFunc(
Tile *tile, /* Tile that is connected. */
TileType dinfo, /* Split tile information */
ClientData cdata) /* Contains information about the search. */
/* (struct conSrArg *csa) */
{
@ -484,11 +413,13 @@ dbSrConnectFunc(
/* Drop the first entry on the stack */
pNum = csa->csa_pNum;
STACKPUSH(INT2CD(tile), dbConnectStack);
STACKPUSH(INT2CD(dinfo), dbConnectStack);
STACKPUSH(INT2CD(pNum), dbConnectStack);
while (!StackEmpty(dbConnectStack))
{
pNum = (int)CD2INT(STACKPOP(dbConnectStack));
dinfo = (int)CD2INT(STACKPOP(dbConnectStack));
tile = (Tile *)CD2INT(STACKPOP(dbConnectStack));
if (result == 1) continue;
@ -522,7 +453,7 @@ dbSrConnectFunc(
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;
continue;
@ -536,7 +467,7 @@ dbSrConnectFunc(
if (IsSplit(tile))
{
if (SplitSide(tile))
if (dinfo & TT_SIDE)
loctype = SplitRightType(tile);
else
loctype = SplitLeftType(tile);
@ -547,7 +478,7 @@ dbSrConnectFunc(
/* 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))
{
@ -564,9 +495,11 @@ dbSrConnectFunc(
if (t2->ti_client == csa->csa_clientDefault) 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);
if (IsSplit(t2))
STACKPUSH(INT2CD((TileType)TT_SIDE), dbConnectStack);
else
STACKPUSH(INT2CD(0), dbConnectStack);
STACKPUSH(INT2CD(pNum), dbConnectStack);
}
}
@ -574,7 +507,7 @@ dbSrConnectFunc(
/* Bottom side: */
bottomside:
if (IsSplit(tile) && (!(SplitSide(tile) ^ SplitDirection(tile))))
if (IsSplit(tile) && ((!((dinfo & TT_SIDE) ? 1 : 0)) ^ SplitDirection(tile)))
goto rightside;
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;
}
else if (t2->ti_client == (ClientData) 1) continue;
STACKPUSH(INT2CD(t2), dbConnectStack);
if (IsSplit(t2))
{
if (SplitDirection(t2))
/* bit set */
TiSetBody(t2, INT2CD(CD2INT(t2->ti_body) | TT_SIDE));
STACKPUSH(INT2CD((TileType)TT_SIDE), dbConnectStack);
else
/* 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);
}
}
@ -609,7 +543,7 @@ bottomside:
/* Right side: */
rightside:
if (IsSplit(tile) && !SplitSide(tile)) goto topside;
if (IsSplit(tile) && !(dinfo & TT_SIDE)) goto topside;
for (t2 = TR(tile); ; t2 = LB(t2))
{
@ -626,9 +560,8 @@ rightside:
if (t2->ti_client == csa->csa_clientDefault) 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(0), dbConnectStack);
STACKPUSH(INT2CD(pNum), dbConnectStack);
}
nextRight: if (BOTTOM(t2) <= tileArea.r_ybot) break;
@ -637,7 +570,8 @@ rightside:
/* Top side: */
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))
{
@ -654,16 +588,18 @@ topside:
if (t2->ti_client == csa->csa_clientDefault) goto nextTop;
}
else if (t2->ti_client == (ClientData) 1) goto nextTop;
STACKPUSH(INT2CD(t2), dbConnectStack);
if (IsSplit(t2))
{
if (SplitDirection(t2))
/* bit clear */
TiSetBody(t2, INT2CD(CD2INT(t2->ti_body) & ~TT_SIDE));
STACKPUSH(INT2CD(0), dbConnectStack);
else
/* 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);
}
nextTop: if (LEFT(t2) <= tileArea.r_xbot) break;
@ -682,6 +618,7 @@ donesides:
{
Rect newArea;
GEO_EXPAND(&tileArea, 1, &newArea);
TileAndDinfo tad;
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
{
@ -689,18 +626,20 @@ donesides:
if (IsSplit(tile))
{
if (DBSrPaintNMArea((Tile *) NULL, csa->csa_def->cd_planes[i],
TiGetTypeExact(tile), &newArea, connectMask,
dbcFindTileFunc, (ClientData)&t2) != 0)
TiGetTypeExact(tile) | dinfo, &newArea, connectMask,
dbcFindTileFunc, (ClientData)&tad) != 0)
{
STACKPUSH(INT2CD(t2), dbConnectStack);
STACKPUSH(PTR2CD(tad.tad_tile), dbConnectStack);
STACKPUSH(INT2CD(tad.tad_dinfo), dbConnectStack);
STACKPUSH(INT2CD(i), dbConnectStack);
}
}
else if (DBSrPaintArea((Tile *) NULL, csa->csa_def->cd_planes[i],
&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);
}
}
@ -734,9 +673,10 @@ donesides:
/** @typedef cb_database_srpaintnmarea_t */
/** @typedef cb_database_srpaintarea_t */
int
dbcUnconnectFunc(tile, clientData)
dbcUnconnectFunc(tile, dinfo, clientData)
Tile *tile; /* Current tile */
ClientData clientData; /* Unused. */
TileType dinfo; /* Split tile information, unused */
ClientData clientData; /* Unused. */
{
return 1;
@ -828,6 +768,7 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
CellDef *orig_def = scx->scx_use->cu_def;
Label *slab;
int lidx = lab->lab_port;
bool foundOne;
const TileTypeBitMask *connectMask;
/* Check for equivalent ports. For any found, call */
@ -839,6 +780,7 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
/* are more equivalent ports, they will be found when */
/* processing this label's area. */
foundOne = FALSE;
for (slab = orig_def->cd_labels; slab != NULL; slab = slab->lab_next)
if ((slab->lab_flags & PORT_DIR_MASK) && (slab != lab))
if (slab->lab_port == lidx)
@ -899,6 +841,20 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
csa2->csa2_list[csa2->csa2_top].connectMask = connectMask;
csa2->csa2_list[csa2->csa2_top].dinfo = 0;
#if 0
/* This warning is useful but currently is generating
* multiple messages per instance and so its more of
* an annoyance than an aid.
*/
if (foundOne == FALSE)
TxError("Warning: Port %s at location (%d %d) connects"
" a net across multiple disconnected areas!\n",
lab->lab_text, lab->lab_rect.r_xbot,
lab->lab_rect.r_ybot);
#endif
foundOne = TRUE;
/* See above: Process only one equivalent port at a time */
break;
}
@ -933,8 +889,9 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2)
*/
int
dbcConnectFunc(tile, cx)
dbcConnectFunc(tile, dinfo, cx)
Tile *tile; /* Tile found. */
TileType dinfo; /* Split tile information */
TreeContext *cx; /* Describes context of search. The client
* data is a pointer to a conSrArg2 record
* containing various required information.
@ -947,8 +904,8 @@ dbcConnectFunc(tile, cx)
Rect *srArea;
SearchContext *scx = cx->tc_scx;
SearchContext scx2;
TileType loctype = TiGetTypeExact(tile);
TileType dinfo = 0;
TileType loctype = TiGetTypeExact(tile) | dinfo;
TileType newdinfo = 0;
int retval, i, pNum = cx->tc_plane;
CellDef *def;
@ -980,8 +937,8 @@ dbcConnectFunc(tile, cx)
if (IsSplit(tile))
{
dinfo = DBTransformDiagonal(loctype, &scx->scx_trans);
loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
newdinfo = DBTransformDiagonal(loctype, &scx->scx_trans);
loctype = ((dinfo & TT_SIDE)) ? SplitRightType(tile) : SplitLeftType(tile);
}
/* See if the destination cell contains stuff over the whole
@ -1019,7 +976,7 @@ dbcConnectFunc(tile, cx)
def = csa2->csa2_use->cu_def;
retval = 1;
if (DBSrPaintNMArea((Tile *) NULL, def->cd_planes[pNum],
dinfo, &newarea, &notConnectMask, dbcUnconnectFunc,
newdinfo, &newarea, &notConnectMask, dbcUnconnectFunc,
(ClientData) NULL) == 0)
retval = 0;
@ -1028,7 +985,7 @@ dbcConnectFunc(tile, cx)
* the storage for the current list element.
*/
DBNMPaintPlane(def->cd_planes[pNum], dinfo,
DBNMPaintPlane(def->cd_planes[pNum], newdinfo,
&newarea, DBStdPaintTbl(loctype, pNum),
(PaintUndoInfo *) NULL);
@ -1045,14 +1002,14 @@ dbcConnectFunc(tile, cx)
/* 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;
else /* left */
newarea.r_xbot -= 1;
if (((dinfo & TT_SIDE) >> 1)
== (dinfo & TT_DIRECTION)) /* top */
if (((newdinfo & TT_SIDE) >> 1)
== (newdinfo & TT_DIRECTION)) /* top */
newarea.r_ytop += 1;
else /* bottom */
newarea.r_ybot -= 1;
@ -1092,7 +1049,7 @@ dbcConnectFunc(tile, cx)
csa2->csa2_list[csa2->csa2_top].area = newarea;
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;
}
@ -1247,7 +1204,8 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse)
if (DBTreeSrLabels(scx, newmask, xMask, &tpath, searchtype,
dbcConnectLabelFunc, (ClientData) &csa2) != 0)
{
TxError("Connection search hit memory limit and stopped.\n");
TxError("Connection search was interrupted or hit "
"memory limit and stopped.\n");
break;
}
}

View File

@ -39,6 +39,7 @@ struct expandArg
{
bool ea_deref; /* TRUE if root def dereference flag is set */
int ea_xmask; /* Expand mask. */
int ea_type; /* Expand, unexpand, or toggle */
int (*ea_func)(); /* Function to call for each cell whose
* status is changed.
*/
@ -67,15 +68,22 @@ struct expandArg
*/
void
DBExpand(cellUse, expandMask, expandFlag)
DBExpand(cellUse, expandMask, expandType)
CellUse *cellUse;
int expandMask;
bool expandFlag;
int expandType;
{
CellDef *def;
if (DBDescendSubcell(cellUse, expandMask) == expandFlag)
return;
bool expandFlag, expandTest;
expandTest = DBDescendSubcell(cellUse, expandMask);
if ((expandType & DB_EXPAND_MASK) == DB_EXPAND_TOGGLE)
expandFlag = expandTest;
else
{
expandFlag = ((expandType & DB_EXPAND_MASK) == DB_EXPAND) ? TRUE : FALSE;
if (expandFlag == expandTest) return;
}
if (expandFlag)
{
@ -130,17 +138,17 @@ DBExpand(cellUse, expandMask, expandFlag)
*/
void
DBExpandAll(rootUse, rootRect, expandMask, expandFlag, func, cdarg)
DBExpandAll(rootUse, rootRect, expandMask, expandType, func, cdarg)
CellUse *rootUse; /* Root cell use from which search begins */
Rect *rootRect; /* Area to be expanded, in root coordinates */
int expandMask; /* Window mask in which cell is to be expanded */
bool expandFlag; /* TRUE => expand, FALSE => unexpand */
int expandType; /* DB_EXPAND, DB_UNEXPAND, DB_EXPAND_TOGGLE */
int (*func)(); /* Function to call for each cell whose expansion
* status is modified. NULL means don't call anyone.
*/
ClientData cdarg; /* Argument to pass to func. */
{
int dbExpandFunc(), dbUnexpandFunc();
int dbExpandFunc();
SearchContext scontext;
struct expandArg arg;
@ -148,29 +156,26 @@ DBExpandAll(rootUse, rootRect, expandMask, expandFlag, func, cdarg)
(void) DBCellRead(rootUse->cu_def, TRUE, TRUE, NULL);
/*
* Walk through the area and set the expansion state
* appropriately.
* Walk through the area and set the expansion state appropriately.
*/
arg.ea_xmask = expandMask;
arg.ea_func = func;
arg.ea_arg = cdarg;
arg.ea_type = expandType;
arg.ea_deref = (rootUse->cu_def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
scontext.scx_use = rootUse;
scontext.scx_trans = GeoIdentityTransform;
scontext.scx_area = *rootRect;
if (expandFlag)
DBCellSrArea(&scontext, dbExpandFunc, (ClientData) &arg);
else
DBCellSrArea(&scontext, dbUnexpandFunc, (ClientData) &arg);
DBCellSrArea(&scontext, dbExpandFunc, (ClientData) &arg);
}
/*
* dbExpandFunc --
*
* Filter function called by DBCellSrArea on behalf of DBExpandAll above
* when cells are being expanded.
* when cells are being expanded, unexpanded, or toggled.
*/
int
@ -184,68 +189,55 @@ dbExpandFunc(scx, arg)
{
CellUse *childUse = scx->scx_use;
int n = DBLambda[1];
int expandTest;
int expandType = (arg->ea_type & DB_EXPAND_MASK);
int expandSurround = (arg->ea_type & DB_EXPAND_SURROUND_MASK);
bool surround;
expandTest = DBDescendSubcell(childUse, arg->ea_xmask);
/*
* Change the expansion status of this cell if necessary. Call the
* client's function if the expansion status has changed.
*/
if (!DBDescendSubcell(childUse, arg->ea_xmask))
if (!expandTest && ((expandType == DB_EXPAND) || (expandType == DB_EXPAND_TOGGLE)))
{
/* If the cell is unavailable, then don't expand it.
*/
if ((childUse->cu_def->cd_flags & CDAVAILABLE) == 0)
surround = (!GEO_SURROUND(&childUse->cu_def->cd_bbox, &scx->scx_area)
|| GEO_SURROUND(&scx->scx_area, &childUse->cu_def->cd_bbox));
if (surround || (expandSurround == DB_EXPAND_OVERLAP))
{
/* If the parent is dereferenced, then the child should be, too */
if (arg->ea_deref) childUse->cu_def->cd_flags |= CDDEREFERENCE;
if(!DBCellRead(childUse->cu_def, TRUE, TRUE, NULL))
/* If the cell is unavailable, then don't expand it.
*/
if ((childUse->cu_def->cd_flags & CDAVAILABLE) == 0)
{
TxError("Cell %s is unavailable. It could not be expanded.\n",
childUse->cu_def->cd_name);
return 2;
/* If the parent is dereferenced, then the child should be, too */
if (arg->ea_deref) childUse->cu_def->cd_flags |= CDDEREFERENCE;
if (!DBCellRead(childUse->cu_def, TRUE, TRUE, NULL))
{
TxError("Cell %s is unavailable. It could not be expanded.\n",
childUse->cu_def->cd_name);
return 2;
}
}
childUse->cu_expandMask |= arg->ea_xmask;
expandTest = TRUE;
if (arg->ea_func != NULL)
{
if ((*arg->ea_func)(childUse, arg->ea_arg) != 0) return 1;
}
}
childUse->cu_expandMask |= arg->ea_xmask;
if (arg->ea_func != NULL)
{
if ((*arg->ea_func)(childUse, arg->ea_arg) != 0) return 1;
}
}
if (DBCellSrArea(scx, dbExpandFunc, (ClientData) arg))
return 1;
return 2;
}
/*
* dbUnexpandFunc --
*
* Filter function called by DBCellSrArea on behalf of DBExpandAll above
* when cells are being unexpanded.
*/
int
dbUnexpandFunc(scx, arg)
SearchContext *scx; /* Pointer to search context containing
* child use, search area in coor-
* dinates of the child use, and
* transform back to "root".
*/
struct expandArg *arg; /* Client data from caller */
{
CellUse *childUse = scx->scx_use;
/*
* Change the expansion status of this cell if necessary.
*/
if (DBDescendSubcell(childUse, arg->ea_xmask))
else if (expandTest && ((expandType == DB_UNEXPAND) ||
(expandType == DB_EXPAND_TOGGLE)))
{
if (!GEO_SURROUND(&childUse->cu_def->cd_bbox, &scx->scx_area)
|| GEO_SURROUND(&scx->scx_area, &childUse->cu_def->cd_bbox))
surround = (!GEO_SURROUND(&childUse->cu_def->cd_bbox, &scx->scx_area)
|| GEO_SURROUND(&scx->scx_area, &childUse->cu_def->cd_bbox));
if (surround || (expandSurround == DB_EXPAND_OVERLAP))
{
childUse->cu_expandMask &= ~arg->ea_xmask;
expandTest = FALSE;
/* Call the client's function, if there is one. */
@ -256,11 +248,7 @@ dbUnexpandFunc(scx, arg)
}
}
/* Don't recursively search things that aren't already expanded. */
else return 2;
if (DBCellSrArea(scx, dbUnexpandFunc, (ClientData) arg))
if (DBCellSrArea(scx, dbExpandFunc, (ClientData) arg))
return 1;
return 2;
}

File diff suppressed because it is too large Load Diff

View File

@ -280,6 +280,7 @@ DBEraseGlobLabel(cellDef, area, mask, areaReturn, globmatch)
bool erasedAny = FALSE;
TileType newType;
free_magic1_t mm1 = freeMagic1_init();
labPrev = NULL;
lab = cellDef->cd_labels;
while (lab != NULL)
@ -313,7 +314,7 @@ DBEraseGlobLabel(cellDef, area, mask, areaReturn, globmatch)
if ((lab->lab_font >= 0) && areaReturn)
GeoInclude(&lab->lab_bbox, areaReturn);
freeMagic((char *) lab);
freeMagic1(&mm1, (char *) lab);
lab = lab->lab_next;
erasedAny = TRUE;
continue;
@ -321,6 +322,7 @@ DBEraseGlobLabel(cellDef, area, mask, areaReturn, globmatch)
nextLab: labPrev = lab;
lab = lab->lab_next;
}
freeMagic1_end(&mm1);
if (erasedAny)
cellDef->cd_flags |= CDMODIFIED|CDGETNEWSTAMP;
@ -442,6 +444,7 @@ DBEraseLabelsByContent(def, rect, type, text)
{
Label *lab, *labPrev;
free_magic1_t mm1 = freeMagic1_init();
for (labPrev = NULL, lab = def->cd_labels;
lab != NULL;
labPrev = lab, lab = lab->lab_next)
@ -457,7 +460,7 @@ DBEraseLabelsByContent(def, rect, type, text)
else labPrev->lab_next = lab->lab_next;
if (def->cd_lastLabel == lab)
def->cd_lastLabel = labPrev;
freeMagic((char *) lab);
freeMagic1(&mm1, (char *) lab);
/* Don't iterate through loop, since this will skip a label:
* just go back to top. This is tricky!
@ -467,6 +470,7 @@ DBEraseLabelsByContent(def, rect, type, text)
if (lab == NULL) break;
else goto nextCheck;
}
freeMagic1_end(&mm1);
}
/*
@ -495,6 +499,7 @@ DBRemoveLabel(def, refLab)
{
Label *lab, *labPrev;
free_magic1_t mm1 = freeMagic1_init();
for (labPrev = NULL, lab = def->cd_labels;
lab != NULL;
labPrev = lab, lab = lab->lab_next)
@ -508,7 +513,7 @@ DBRemoveLabel(def, refLab)
else labPrev->lab_next = lab->lab_next;
if (def->cd_lastLabel == lab)
def->cd_lastLabel = labPrev;
freeMagic((char *) lab);
freeMagic1(&mm1, (char *) lab);
/* Don't iterate through loop, since this will skip a label:
* just go back to top. This is tricky!
@ -518,6 +523,7 @@ DBRemoveLabel(def, refLab)
if (lab == NULL) break;
else goto nextCheck;
}
freeMagic1_end(&mm1);
}
/*
@ -577,8 +583,9 @@ DBReOrientLabel(cellDef, area, newPos)
*/
int
dbGetLabelArea(tile, area)
dbGetLabelArea(tile, dinfo, area)
Tile *tile; /* Tile found. */
TileType dinfo; /* Split tile information (unused) */
Rect *area; /* Area to be modified. */
{
Rect r;
@ -760,8 +767,10 @@ DBAdjustLabelsNew(def, area)
def->cd_lastLabel = labPrev;
DBUndoEraseLabel(def, lab);
DBWLabelChanged(def, lab, DBW_ALLWINDOWS);
freeMagic((char *) lab);
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, (char *) lab);
lab = lab->lab_next;
freeMagic1_end(&mm1);
modified = TRUE;
continue;
}
@ -1077,14 +1086,15 @@ DBPickLabelLayer(def, lab, doCalma)
*/
int
dbPickFunc1(tile, mask)
dbPickFunc1(tile, dinfo, mask)
Tile *tile; /* Tile found. */
TileType dinfo; /* Split tile information */
TileTypeBitMask *mask; /* Mask to be modified. */
{
TileType type;
if (IsSplit(tile))
type = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
else
type = TiGetType(tile);
@ -1103,15 +1113,16 @@ dbPickFunc1(tile, mask)
*/
int
dbPickFunc2(tile, mask)
dbPickFunc2(tile, dinfo, mask)
Tile *tile; /* Tile found. */
TileType dinfo; /* Split tile information */
TileTypeBitMask *mask; /* Mask to be modified. */
{
TileType type;
TileTypeBitMask tmp, *rMask;
if (IsSplit(tile))
type = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
else
type = TiGetType(tile);
@ -1744,8 +1755,10 @@ DBLoadFont(fontfile, scale)
}
/* Remove the pointlist */
free_magic1_t mm1 = freeMagic1_init();
for (newPath = pathStart; newPath != NULL; newPath = newPath->fp_next)
freeMagic(newPath);
freeMagic1(&mm1, newPath);
freeMagic1_end(&mm1);
pathStart = NULL;
}
else

View File

@ -487,8 +487,6 @@ enumerate:
newType = (method == (unsigned char)PAINT_XOR) ?
*resultTbl : resultTbl[oldType];
if (mergeFlags & MRG_RIGHT)
tile = TiNMMergeRight(tile, plane); // was commented out?
if (mergeFlags & MRG_LEFT)
TiNMMergeLeft(LB(newtile), plane);
}
@ -496,8 +494,6 @@ enumerate:
{
if (mergeFlags & MRG_LEFT)
TiNMMergeLeft(newtile, plane);
if (mergeFlags & MRG_RIGHT)
TiNMMergeRight(LB(tile), plane); // was commented out?
}
}
else
@ -1439,10 +1435,6 @@ DBDiagonalProc(oldtype, dinfo)
else
return -1;
/* For purposes of "undo" recording, record which side we just painted */
if (dinfo->side)
newtype |= TT_SIDE;
return newtype;
}
@ -1796,12 +1788,14 @@ nextrect:
lr = lr->r_next;
}
free_magic1_t mm1 = freeMagic1_init();
lr = lhead;
while (lr != NULL)
{
freeMagic((char *) lr);
freeMagic1(&mm1, (char *) lr);
lr = lr->r_next;
}
freeMagic1_end(&mm1);
}
else
result = DBPaintPlane0(plane, area, resultTbl, undo, (method == PAINT_MARK) ?
@ -1822,14 +1816,15 @@ nextrect:
*/
int
dbNMEnumFunc(tile, arg)
dbNMEnumFunc(tile, dinfo, arg)
Tile *tile;
TileType dinfo;
LinkedRect **arg;
{
LinkedRect *lr;
/* 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));
TiToRect(tile, &lr->r_r);

View File

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

View File

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

View File

@ -327,11 +327,11 @@ DBTechNoisyNamePlane(planename)
* ----------------------------------------------------------------------------
*/
char *
DBTypeShortName(type)
TileType type;
const char *
DBTypeShortName(
TileType type)
{
NameList *tbl;
const NameList *tbl;
for (tbl = dbTypeNameLists.sn_next;
tbl != &dbTypeNameLists;
@ -347,11 +347,11 @@ DBTypeShortName(type)
return ("???");
}
char *
DBPlaneShortName(pNum)
int pNum;
const char *
DBPlaneShortName(
int pNum)
{
NameList *tbl;
const NameList *tbl;
for (tbl = dbPlaneNameLists.sn_next;
tbl != &dbPlaneNameLists;

View File

@ -38,14 +38,14 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
/* Types and their names */
int DBNumTypes;
char *DBTypeLongNameTbl[NT];
const char *DBTypeLongNameTbl[NT];
int DBTypePlaneTbl[NT]; /* Normally accessed as macro "DBPlane(x)" */
NameList dbTypeNameLists = {NULL, NULL, NULL, (ClientData)0, FALSE};
HashTable DBTypeAliasTable;
/* Planes and their names */
int DBNumPlanes;
char *DBPlaneLongNameTbl[PL_MAXTYPES];
const char *DBPlaneLongNameTbl[PL_MAXTYPES];
NameList dbPlaneNameLists = {NULL, NULL, NULL, (ClientData)0, FALSE};
@ -116,22 +116,24 @@ NameList *dbTechNameAddOne();
*/
void
DBTechInitPlane()
DBTechInitPlane(void)
{
DefaultPlane *dpp;
char *cp;
const char *cp;
/* Clear out any old information */
if (dbPlaneNameLists.sn_next != NULL)
{
NameList *tbl;
free_magic1_t mm1 = freeMagic1_init();
for (tbl = dbPlaneNameLists.sn_next; tbl != &dbPlaneNameLists;
tbl = tbl->sn_next)
{
freeMagic(tbl->sn_name);
freeMagic(tbl);
freeMagic1(&mm1, tbl);
}
freeMagic1_end(&mm1);
}
/* Tables of short names */
@ -205,12 +207,14 @@ DBTechInitType()
{
NameList *tbl;
free_magic1_t mm1 = freeMagic1_init();
for (tbl = dbTypeNameLists.sn_next; tbl != &dbTypeNameLists;
tbl = tbl->sn_next)
{
freeMagic(tbl->sn_name);
freeMagic(tbl);
freeMagic1(&mm1, tbl);
}
freeMagic1_end(&mm1);
}
/* Tables of short names */
@ -264,12 +268,12 @@ DBTechInitType()
/*ARGSUSED*/
bool
DBTechAddPlane(sectionName, argc, argv)
char *sectionName;
int argc;
char *argv[];
DBTechAddPlane(
const char *sectionName,
int argc,
char *argv[])
{
char *cp;
const char *cp;
if (DBNumPlanes >= PL_MAXTYPES)
{

View File

@ -44,6 +44,296 @@ struct dbCheck
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
* func(tile, cdata)
* Tile *tile;
* TileType dinfo;
* ClientData cdata;
* {
* }
@ -92,7 +383,7 @@ DBSrPaintNMArea(hintTile, plane, ttype, rect, mask, func, arg)
* provide a hint tile in case hintTile == NULL.
* The hint tile in the plane is updated to be
* the last tile visited in the area
* enumeration.
* enumeration, if plane is non-NULL.
*/
TileType ttype; /* Information about the non-manhattan area to
* search; zero if area is manhattan.
@ -129,7 +420,7 @@ DBSrPaintNMArea(hintTile, plane, ttype, rect, mask, func, arg)
{
/* Each iteration enumerates another tile */
nm_enum:
PlaneSetHint(plane, tp);
if (plane != (Plane *)NULL) PlaneSetHint(plane, tp);
if (SigInterruptPending)
return (1);
@ -137,147 +428,26 @@ nm_enum:
/* the tile enumeration if it is not. */
/* 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 (!TTMaskHasType(mask, SplitLeftType(tp)))
ignore_sides |= IGNORE_LEFT;
if (!TTMaskHasType(mask, SplitRightType(tp)))
ignore_sides |= IGNORE_RIGHT;
TileType tpdi = TiGetTypeExact(tp);
tpt = TiGetTypeExact(tp);
if ((tpt & TT_DIRECTION) == (ttype & TT_DIRECTION))
{
f3 = (LEFT(tp) > MINFINITY + 2) ?
((dlong)(rect->r_xtop - LEFT(tp)) * rheight) : DLONG_MAX;
f4 = (RIGHT(tp) < INFINITY - 2) ?
((dlong)(RIGHT(tp) - rect->r_xbot) * rheight) : DLONG_MAX;
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);
}
}
if (TTMaskHasType(mask, SplitLeftType(tp)))
if (DBTestNMInteract(rect, ttype, tp, tpdi, TRUE))
if ((*func)(tp, (TileType)TT_DIAGONAL, arg))
return 1;
if (TTMaskHasType(mask, SplitRightType(tp)))
if (DBTestNMInteract(rect, ttype, tp, tpdi | TT_SIDE, TRUE))
if ((*func)(tp, (TileType)TT_DIAGONAL | TT_SIDE, arg))
return 1;
}
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:
tpnew = TR(tp);
@ -325,6 +495,7 @@ enum_next:
* int
* func(tile, cdata)
* Tile *tile;
* TileType dinfo;
* ClientData cdata;
* {
* }
@ -416,9 +587,7 @@ enumerate:
(dlong)(rect->r_xbot - LEFT(tp)) * theight : DLONG_MIN;
if (SplitDirection(tp) ? (f1 > f4) : (f2 > f4))
{
TiSetBody(tp, INT2CD((TileType)CD2INT(TiGetBody(tp))
& ~TT_SIDE)); /* bit clear */
if ((*func)(tp, arg)) return (1);
if ((*func)(tp, (TileType)TT_DIAGONAL, arg)) return (1);
}
}
@ -429,14 +598,12 @@ enumerate:
(dlong)(RIGHT(tp) - rect->r_xtop) * theight : DLONG_MIN;
if (SplitDirection(tp) ? (f2 > f3) : (f1 > f3))
{
TiSetBody(tp, INT2CD((TileType)CD2INT(TiGetBody(tp))
| TT_SIDE)); /* bit set */
if ((*func)(tp, arg)) return (1);
if ((*func)(tp, (TileType)TT_DIAGONAL | TT_SIDE, arg)) return (1);
}
}
}
else
if (TTMaskHasType(mask, TiGetType(tp)) && (*func)(tp, arg))
if (TTMaskHasType(mask, TiGetType(tp)) && (*func)(tp, (TileType)0, arg))
return (1);
tpnew = TR(tp);
@ -485,6 +652,7 @@ enumerate:
* int
* func(tile, cdata)
* Tile *tile;
* TileType dinfo;
* ClientData cdata;
* {
* }
@ -576,9 +744,7 @@ enumerate:
(dlong)(rect->r_xbot - LEFT(tp)) * (dlong)theight : DLONG_MIN;
if (SplitDirection(tp) ? (f1 > f4) : (f2 > f4))
{
TiSetBody(tp, INT2CD((TileType)CD2INT(TiGetBody(tp))
& ~TT_SIDE)); /* bit clear */
if ((tp->ti_client == client) && (*func)(tp, arg))
if ((tp->ti_client == client) && (*func)(tp, (TileType)TT_DIAGONAL, arg))
return (1);
}
}
@ -590,16 +756,15 @@ enumerate:
(dlong)(RIGHT(tp) - rect->r_xtop) * (dlong)theight : DLONG_MIN;
if (SplitDirection(tp) ? (f2 > f3) : (f1 > f3))
{
TiSetBody(tp, INT2CD((TileType)CD2INT(TiGetBody(tp))
| TT_SIDE)); /* bit set */
if ((tp->ti_client == client) && (*func)(tp, arg))
if ((tp->ti_client == client) && (*func)(tp, (TileType)TT_DIAGONAL
| TT_SIDE, arg))
return (1);
}
}
}
else
if (TTMaskHasType(mask, TiGetType(tp)) && tp->ti_client == client
&& (*func)(tp, arg))
&& (*func)(tp, (TileType)0, arg))
return (1);
tpnew = TR(tp);
@ -665,7 +830,7 @@ DBResetTilePlane(plane, cdata)
/* Each iteration visits another tile on the LHS of the search area */
while (TOP(tp) > rect->r_ybot)
{
/* Each iteration frees another tile */
/* Each iteration resets another tile */
enumerate:
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
dbCheckMaxHFunc(tile, dbc)
dbCheckMaxHFunc(tile, dinfo, dbc)
Tile *tile;
TileType dinfo; /* (unused) */
struct dbCheck *dbc;
{
Tile *tp;
@ -1010,8 +1258,9 @@ DBCheckMaxVStrips(plane, area, proc, cdata)
*/
int
dbCheckMaxVFunc(tile, dbc)
dbCheckMaxVFunc(tile, dinfo, dbc)
Tile *tile;
TileType dinfo; /* (unused) */
struct dbCheck *dbc;
{
Tile *tp;

View File

@ -137,8 +137,10 @@ DBFixMismatch()
cellDef = mismatch->mm_cellDef;
oldArea = mismatch->mm_oldArea;
freeMagic((char *) mismatch);
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, (char *) mismatch);
mismatch = mismatch->mm_next;
freeMagic1_end(&mm1);
if (cellDef->cd_flags & CDPROCESSED) continue;
(void) DBCellRead(cellDef, TRUE, TRUE, NULL);
@ -182,13 +184,15 @@ DBFixMismatch()
}
SigEnableInterrupts();
TxPrintf("Timestamp mismatches found in these cells: ");
free_magic1_t mm1 = freeMagic1_init();
while (cl != NULL)
{
TxPrintf("%s", cl->cl_cell->cd_name);
if (cl->cl_next != NULL) TxPrintf(", ");
freeMagic(cl);
freeMagic1(&mm1, cl);
cl = cl->cl_next;
}
freeMagic1_end(&mm1);
TxPrintf(".\n");
TxFlush();
if (redisplay) WindAreaChanged((MagWindow *) NULL, (Rect *) NULL);
@ -227,7 +231,7 @@ DBUpdateStamps(def)
else if (def->cd_flags & CDGETNEWSTAMP)
{
if (def->cd_flags & CDFIXEDSTAMP)
if (def->cd_flags & (CDNOEDIT | CDFIXEDSTAMP))
def->cd_flags &= ~CDGETNEWSTAMP;
else
dbStampFunc(def);
@ -247,6 +251,26 @@ dbStampFunc(cellDef)
if (cellDef->cd_timestamp == timestamp) return 0;
/* Non-editable cells should not try to update timestamps, as the
* new timestamp cannot be written back to the file. This is
* basically a hack solution for the problem that running DRC on
* all cells causes all cells, including non-editable ones, to be
* marked as modified, even if there were no DRC changes in the
* cell. It is possible to get into trouble this way by modifying
* a cell and then marking it as non-editable
*/
if (cellDef->cd_flags & CDNOEDIT)
{
cellDef->cd_flags &= ~CDGETNEWSTAMP;
return 0;
}
/*
* Do not force a non-edit cell or a cell with a fixed timestamp
* to update its timestamp, as it cannot or should not. Just clear
* any flag suggesting that it needs a new timestamp.
*/
if (!(cellDef->cd_flags & CDFIXEDSTAMP))
cellDef->cd_timestamp = timestamp;

View File

@ -303,9 +303,14 @@ typedef struct label
#define PORT_SHAPE_RING 0x1000 /* Port is a ring shape */
#define PORT_SHAPE_THRU 0x1800 /* Port is a feedthrough shape */
#define PORT_VISITED 0x2000 /* Bit for checking if a port */
#define LABEL_STICKY 0x2000 /* Label does not change layers */
#define LABEL_UNIQUE 0x4000 /* Temporary unique label */
/* The last two flags are never used at the same time and so can share
* a flag bit.
*/
#define PORT_VISITED 0x8000 /* Bit for checking if a port */
/* has been previously visited. */
#define LABEL_STICKY 0x4000 /* Label does not change layers */
#define LABEL_GENERATE 0x8000 /* Auto-generated label */
/*
@ -403,6 +408,9 @@ typedef struct celldef
* is added to the magic database. The flag is used to identify
* whether the cell has been processed when forcing the GDS
* stream data to be read in post-order.
* CDPRELOADED is similar to CDPROCESSEDGDS but is used in cases
* other than forced post-order reading, such as flattening
* or flatten-by-name.
* CDVENDORGDS indicates that the cell was read from a GDS stream
* with the option "gds readonly true".
* CDVISITED indicates that at least one instance of the cell was
@ -434,12 +442,13 @@ typedef struct celldef
#define CDFLATGDS 0x00400
#define CDFLATTENED 0x00800
#define CDPROCESSEDGDS 0x01000
#define CDVENDORGDS 0x02000
#define CDVISITED 0x04000
#define CDDEREFERENCE 0x08000
#define CDFIXEDSTAMP 0x10000
#define CDNOEXTRACT 0x20000
#define CDDONTUSE 0x40000
#define CDPRELOADED 0x02000
#define CDVENDORGDS 0x04000
#define CDVISITED 0x08000
#define CDDEREFERENCE 0x10000
#define CDFIXEDSTAMP 0x20000
#define CDNOEXTRACT 0x40000
#define CDDONTUSE 0x80000
#include "database/arrayinfo.h" /* ArrayInfo */
@ -547,6 +556,18 @@ typedef struct diag_info
bool side;
} 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. */
/* Used in selOps.c but also passed back to CmdRS.c for select command. */
@ -630,6 +651,7 @@ typedef struct treeFilter
#define TF_LABEL_ATTACH_NOT_SE 0x10 /* Same as above, ignore tile SE corner */
#define TF_LABEL_ATTACH_NOT_SW 0x20 /* Same as above, ignore tile SW corner */
#define TF_LABEL_ATTACH_CORNER 0x3C /* Mask of the four types above */
#define TF_LABEL_REVERSE_SEARCH 0x40 /* Search children before parent */
/* To do: Make the tpath entries dynamically allocated */
#define FLATTERMSIZE 4096 /* Used for generating flattened labels */
@ -683,6 +705,25 @@ struct conSrArg2
#define CSA2_LIST_SIZE 65536 /* Number of entries per list */
/* ------------------------ Properties ------------------------------ */
/* Note that the property record is a single allocated block large enough
* to hold the string or integer list, and can be freed as a single block.
* The array bounds, like those of lab_text for labels, are placeholders.
*/
typedef struct
{
int prop_type; /* See codes below; e.g., PROPERTY_TYPE_STRING */
int prop_len; /* String length or number of values */
union {
char prop_string[8]; /* For PROPERTY_TYPE_STRING */
int prop_integer[2]; /* For PROPERTY_TYPE_INTEGER or _DIMENSION */
dlong prop_double[1]; /* For PROPERTY_TYPE_DOUBLE */
Plane *prop_plane; /* For PROPERTY_TYPE_PLANE */
} prop_value;
} PropertyRecord;
/* -------------- Undo information passed to DBPaintPlane ------------- */
typedef struct
@ -715,6 +756,14 @@ typedef struct
#define PAINT_MARK 1 /* Mark tiles that are painted */
#define PAINT_XOR 2 /* Use with XOR function to prevent double-painting */
/* ---------------------- Codes for properties -------------------------*/
#define PROPERTY_TYPE_STRING 0 /* ASCII string property */
#define PROPERTY_TYPE_INTEGER 1 /* Fixed integer property */
#define PROPERTY_TYPE_DIMENSION 2 /* Integer property that scales with units */
#define PROPERTY_TYPE_DOUBLE 3 /* Double-long integer (for file positions) */
#define PROPERTY_TYPE_PLANE 4 /* A tile plane structure */
/* -------------------- Exported procedure headers -------------------- */
/* Painting/erasing */
@ -769,7 +818,7 @@ extern void DBTechInit();
extern bool DBTechSetTech();
extern void DBTechInitVersion();
extern bool DBTechSetVersion();
extern bool DBTechAddPlane();
extern bool DBTechAddPlane(const char *sectionName, int argc, char *argv[]);
extern bool DBTechAddType();
extern bool DBTechAddAlias();
extern void DBTechFinalType();
@ -781,7 +830,7 @@ extern int DBTechNamePlane(), DBTechNoisyNamePlane();
extern PlaneMask DBTechNameMask(), DBTechNoisyNameMask();
extern PlaneMask DBTechTypesToPlanes();
extern bool DBTechTypesOnPlane();
extern void DBTechInitPlane();
extern void DBTechInitPlane(void);
extern void DBTypeInit();
extern void DBTechInitType();
extern void DBTechInitCompose();
@ -900,7 +949,9 @@ extern void DBFreePaintPlane();
/* Cell properties */
extern void DBPropPut();
extern ClientData DBPropGet();
extern PropertyRecord *DBPropGet();
extern char *DBPropGetString();
extern dlong DBPropGetDouble();
extern int DBPropEnum();
extern void DBPropClearAll();
@ -916,9 +967,10 @@ extern int DBArraySr();
extern bool DBNearestLabel();
extern int DBSrLabelLoc();
extern TileType DBTransformDiagonal();
extern int dbcUnconnectFunc(Tile *tile, ClientData clientData); /* (notused) */
extern int dbSrConnectFunc(Tile *tile, ClientData clientData); /* (struct conSrArg *csa) */
extern int dbSrConnectStartFunc(Tile *tile, ClientData clientData); /* cb_database_srpaintarea_t (Tile **pTile) */
extern bool DBTestNMInteract(Rect *rect1, TileType tt1, Tile *t2, TileType di2, bool overlap_only);
extern int dbcUnconnectFunc(Tile *tile, TileType dinfo, ClientData clientData); /* (notused) */
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 */
extern void DBEraseValid();
@ -965,10 +1017,10 @@ extern int dbIsPrimary();
extern void dbTechMatchResidues();
extern void DBUndoInit();
extern void DBResetTilePlane();
extern void DBResetTilePlaneSpecial();
extern void DBNewYank();
extern int DBSrPaintClient();
extern int DBSrConnect();
extern int DBSrConnectOnePlane();
extern char *dbFgets();
extern void DBAdjustLabelsNew();
extern bool DBScaleValue();
@ -997,6 +1049,7 @@ extern int DBLambda[2];
/* -------------------- Exported magic file suffix -------------------- */
extern char *DBSuffix; /* Suffix appended to all Magic cell names */
extern bool DBPropCompat; /* Backwards-compatible properties */
/* -------------------- User Interface Stuff -------------------------- */
@ -1009,6 +1062,19 @@ extern unsigned char DBVerbose; /* If 0, don't print any messages */
#define DB_VERBOSE_WARN 2
#define DB_VERBOSE_ALL 3
/* ---------- Definitions for expanding/unexpanding cells --------------*/
/* Selection expansion flags */
#define DB_EXPAND_MASK 3 /* 1 = expand, 0 = unexpand, 2 = toggle */
#define DB_EXPAND_SURROUND_MASK 4 /* 1 = surround, 0 = touch */
/* Selection expansion values */
#define DB_EXPAND 0
#define DB_UNEXPAND 1
#define DB_EXPAND_TOGGLE 2
#define DB_EXPAND_SURROUND 4
#define DB_EXPAND_OVERLAP 0
/* ------------------ Exported technology variables ------------------- */
/***
@ -1055,10 +1121,10 @@ extern int DBNumPlanes;
extern HashTable DBTypeAliasTable;
/* Gives the official long name of each plane: */
extern char *DBPlaneLongNameTbl[NP];
extern const char *DBPlaneLongNameTbl[NP];
/* Gives a short name for each plane: */
extern char *DBPlaneShortName();
extern const char *DBPlaneShortName();
/* Gives for each plane a mask of all tile types stored in that plane: */
extern TileTypeBitMask DBPlaneTypes[NP];
@ -1117,10 +1183,10 @@ extern int DBTypePlaneTbl[TT_MAXTYPES];
extern PlaneMask DBTypePlaneMaskTbl[TT_MAXTYPES];
/* Gives the long name for each tile type: */
extern char *DBTypeLongNameTbl[TT_MAXTYPES];
extern const char *DBTypeLongNameTbl[TT_MAXTYPES];
/* Gives a short name for a tile type: */
extern char *DBTypeShortName();
extern const char *DBTypeShortName(TileType type);
/*
* The following give masks of all planes that may be affected

View File

@ -194,6 +194,8 @@ typedef struct
extern int dbNumSavedRules;
extern Rule dbSavedRules[];
extern HashTable dbCellDefTable; /* Exported for diagnostics */
/* -------------------- Internal procedure headers -------------------- */
extern void DBUndoPutLabel();

View File

@ -27,6 +27,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include <stdio.h>
#include <string.h>
#include "tcltk/tclmagic.h"
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
@ -130,8 +131,11 @@ DBWAddButtonHandler(
for (i = 0; i < MAXBUTTONHANDLERS; i++)
{
if (dbwButtonHandlers[i] != NULL) continue;
(void) StrDup(&dbwButtonHandlers[i], name);
(void) StrDup(&dbwButtonDoc[i], doc);
StrDup(&dbwButtonHandlers[i], name);
if (doc != NULL)
StrDup(&dbwButtonDoc[i], doc);
else
dbwButtonDoc[i] = (char *)NULL;
dbwButtonProcs[i] = proc;
dbwButtonCursors[i] = cursor;
return;
@ -240,6 +244,69 @@ DBWChangeButtonHandler(name)
return oldName;
}
/*
* ----------------------------------------------------------------------------
*
* DBWGetButtonHandler --
*
* Return the name of the current button handler. This does the same
* thing as DBWChangeButtonHandler(name) with an invalid name, but
* without printing the error messages. However, if magic is running
* with the Tcl interpreter wrapper, then return the string value of
* $Opts(tool), if it exists.
*
* Results:
* A pointer to the name of the current button handler.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
char *
DBWGetButtonHandler()
{
#ifdef MAGIC_WRAPPER
char *toolName;
toolName = (char *)Tcl_GetVar2(magicinterp, "Opts", "tool", TCL_GLOBAL_ONLY);
if (toolName != NULL) return toolName;
#endif
return dbwButtonHandlers[dbwButtonCurrentIndex];
}
/*
* ----------------------------------------------------------------------------
*
* DBWButtonHandlerIndex()
*
* Given a string, return the index of the button handler. If the
* string does not correspond to any button handler name, then
* return -1.
*
* Results:
* Index of button handler, if it exists; -1 otherwise.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
DBWButtonHandlerIndex(char *toolName)
{
int i;
for (i = 0; i < MAXBUTTONHANDLERS; i++)
{
if (dbwButtonHandlers[i] == NULL) return -1;
else if (!strcmp(toolName, dbwButtonHandlers[i])) return i;
}
return -1;
}
/*
* ----------------------------------------------------------------------------
*
@ -261,7 +328,10 @@ DBWChangeButtonHandler(name)
void
DBWPrintButtonDoc()
{
TxPrintf("%s", dbwButtonDoc[dbwButtonCurrentIndex]);
if (dbwButtonDoc[dbwButtonCurrentIndex])
TxPrintf("%s", dbwButtonDoc[dbwButtonCurrentIndex]);
else
TxPrintf("(no usage information)\n");
}

View File

@ -38,7 +38,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
* Standard DBWind command set
*/
extern void CmdAddPath(), CmdAntennaCheck(), CmdArray();
extern void CmdAddPath(), CmdAntennaCheck(), CmdArchive(), CmdArray();
extern void CmdBox(), CmdCellname(), CmdClockwise();
extern void CmdContact(), CmdCopy(), CmdCorner();
extern void CmdCrash(), CmdCrosshair();
@ -54,7 +54,7 @@ extern void CmdRandom(), CmdSave(), CmdScaleGrid(), CmdSee();
extern void CmdSelect(), CmdSetLabel(), CmdSideways();
extern void CmdShell(), CmdSnap();
extern void CmdStretch(), CmdStraighten();
extern void CmdTech(), CmdTool(), CmdUnexpand();
extern void CmdTech(), CmdTool(), CmdUnexpand(), CmdUnits();
extern void CmdUpsidedown(), CmdWhat(), CmdWire(), CmdWriteall();
extern void CmdGoto(), CmdFlatten(), CmdXload(), CmdXor();
@ -75,6 +75,7 @@ extern void CmdExtResis();
extern void CmdPsearch();
extern void CmdPlowTest();
extern void CmdShowtech();
extern void CmdShowmem();
extern void CmdTilestats();
extern void CmdTsearch();
extern void CmdWatch();
@ -208,6 +209,9 @@ DBWInitCommands()
WindAddCommand(DBWclientID,
"*psearch plane count invoke point search over box area",
CmdPsearch, FALSE);
WindAddCommand(DBWclientID,
"*showmem [file] print internal memory usage",
CmdShowmem, FALSE);
WindAddCommand(DBWclientID,
"*showtech [file] print internal technology tables",
CmdShowtech, FALSE);
@ -228,6 +232,10 @@ DBWInitCommands()
"antennacheck [path] check for antenna violations",
CmdAntennaCheck, FALSE);
#endif
WindAddCommand(DBWclientID,
"archive write|read file\n"
" write or read the archive file \"file\".",
CmdArchive, FALSE);
WindAddCommand(DBWclientID,
"array xsize ysize OR\n"
"array xlo xhi ylo yhi\n"
@ -466,6 +474,9 @@ DBWInitCommands()
WindAddCommand(DBWclientID,
"unexpand unexpand subcells under box",
CmdUnexpand, FALSE);
WindAddCommand(DBWclientID,
"units [type] set type of units parsed and displayed",
CmdUnits, FALSE);
WindAddCommand(DBWclientID,
"upsidedown flip selection and box upside down",
CmdUpsidedown, FALSE);

View File

@ -421,7 +421,8 @@ DBWredisplay(w, rootArea, clipArea)
/* Set style information beforehand */
GrSetStuff(STYLE_LABEL);
(void) DBTreeSrLabels(&scontext, &DBAllTypeBits, bitMask,
(TerminalPath *) NULL, TF_LABEL_DISPLAY | TF_LABEL_ATTACH,
(TerminalPath *) NULL,
TF_LABEL_DISPLAY | TF_LABEL_ATTACH | TF_LABEL_REVERSE_SEARCH,
dbwLabelFunc, (ClientData)(&crec->dbw_visibleLayers));
GrClipTo(&rootClip);
}
@ -571,8 +572,9 @@ DBWredisplay(w, rootArea, clipArea)
*/
int
dbwPaintFunc(tile, cxp)
Tile *tile; /* Tile to be redisplayed. */
dbwPaintFunc(tile, dinfo, cxp)
Tile *tile; /* Tile to be redisplayed. */
TileType dinfo; /* Split tile information */
TreeContext *cxp; /* From DBTreeSrTiles */
{
SearchContext *scx = cxp->tc_scx;
@ -652,7 +654,7 @@ dbwPaintFunc(tile, cxp)
/* whether to render the outline with a fast rectangle- */
/* drawing routine or to render it segment by segment. */
GrBox(dbwWindow, &scx->scx_trans, tile);
GrBox(dbwWindow, &scx->scx_trans, tile, dinfo);
return 0;
}
@ -1075,8 +1077,10 @@ dbwBBoxFunc(scx)
*/
int
dbwTileFunc(tile)
dbwTileFunc(tile, dinfo, clientdata)
Tile *tile; /* A tile to be redisplayed. */
TileType dinfo; /* Split tile information (unused) */
ClientData clientdata; /* (unused) */
{
Rect r, r2;
int xoffset, yoffset;
@ -1113,7 +1117,7 @@ dbwTileFunc(tile)
if (dbwSeeTypes)
{
(void) sprintf(string, "%s",DBTypeShortName(TiGetType(tile)));
(void) sprintf(string, "%s", DBTypeShortName(TiGetType(tile)));
}
else
{
@ -1129,7 +1133,7 @@ dbwTileFunc(tile)
#define XYOFFSET 12
for (i=0; i<4; i++)
for (i = 0; i < 4; i++)
{
xoffset = 0;
yoffset = 0;
@ -1172,13 +1176,13 @@ dbwTileFunc(tile)
yoffset = temp;
}
if ( (dbwWatchTrans.t_a < 0) || (dbwWatchTrans.t_b < 0) )
if ((dbwWatchTrans.t_a < 0) || (dbwWatchTrans.t_b < 0))
{
/* mirror in x */
xoffset = -xoffset;
}
if ( (dbwWatchTrans.t_d < 0) || (dbwWatchTrans.t_e < 0) )
if ((dbwWatchTrans.t_d < 0) || (dbwWatchTrans.t_e < 0))
{
/* mirror in y */
yoffset = -yoffset;

View File

@ -588,10 +588,12 @@ DBWElementDelete(MagWindow *w, char *name)
if (elem->flags & DBW_ELEMENT_PERSISTENT)
elem->rootDef->cd_flags |= CDMODIFIED;
free_magic1_t mm1 = freeMagic1_init();
for (stylePtr = elem->stylelist; stylePtr != NULL; stylePtr = stylePtr->next)
{
freeMagic(stylePtr);
freeMagic1(&mm1, stylePtr);
}
freeMagic1_end(&mm1);
if (elem->type == ELEMENT_TEXT)
freeMagic(elem->text);
@ -1156,8 +1158,10 @@ DBWElementStyle(MagWindow *w, char *ename, int style, bool add)
(elem->stylelist->style == style))
{
dbwElementUndraw(w, elem);
freeMagic(elem->stylelist);
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, elem->stylelist);
elem->stylelist = elem->stylelist->next;
freeMagic1_end(&mm1);
if (elem->stylelist == NULL)
TxPrintf("Warning: Element %s has no styles!\n", ename);
}
@ -1169,8 +1173,10 @@ DBWElementStyle(MagWindow *w, char *ename, int style, bool add)
else if (sptr->next != NULL)
{
dbwElementUndraw(w, elem);
freeMagic(sptr->next);
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, sptr->next);
sptr->next = sptr->next->next;
freeMagic1_end(&mm1);
}
}
/* mark element's cell as having been modified */
@ -1279,8 +1285,10 @@ DBWElementClearDef(cellDef)
if (!elem) continue;
if (elem->rootDef != cellDef) continue;
free_magic1_t mm1 = freeMagic1_init();
for (stylePtr = elem->stylelist; stylePtr != NULL; stylePtr = stylePtr->next)
freeMagic(stylePtr);
freeMagic1(&mm1, stylePtr);
freeMagic1_end(&mm1);
if (elem->type == ELEMENT_TEXT)
freeMagic(elem->text);

View File

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

View File

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

View File

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

View File

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

View File

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

67
doc/html/archive.html Normal file
View File

@ -0,0 +1,67 @@
<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>archive</H2>
<HR>
Handle archive files
<HR>
<H3>Usage:</H3>
<BLOCKQUOTE>
<B>archive write</B> | <B>read</B> <I>filename</I> <BR><BR>
</BLOCKQUOTE>
<H3>Summary:</H3>
<BLOCKQUOTE>
The <B>archive</B> command handles archive files. The exact
operation depends on the option, and are outlined below:
<DL>
<DT> <B>archive write</B> <I>filename</I>
<DD> creates and writes to the file <I>filename</I> a copy of
the contents of all database cells. <P>
<DT> <B>archive read</B> <I>filename</I>
<DD> recovers the database from the contents of the saved archive
file <I>filename</I>. <P>
</DL>
</BLOCKQUOTE>
Archive files use the same format as crash recovery files, which is a
single file containing all database files with additional metadata
about the original location of each file.
<H3>Implementation Notes:</H3>
<BLOCKQUOTE>
<B>archive</B> is implemented as a built-in command in <B>magic</B>.
</BLOCKQUOTE>
<H3>See Also:</H3>
<BLOCKQUOTE>
<A HREF=crash.html><B>crash</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> January 12, 2021 at 10:10am <P>
</BODY>
</HTML>

View File

@ -71,12 +71,15 @@ Operations on cell definitions.
<DT> <B>rename</B> <I>name newname</I>
<DD> Change the name of the cell definition <I>name</I> to
<I>newname</I>.
<DT> <B>delete</B> <I>name</I>
<DT> <B>delete</B> <I>name</I> [<B>-noprompt</B>]
<DD> Delete the cell definition with name <I>name</I>. If cell
<I>name</I> is a descendent of another cell, the command
will be prohibited. If the cell <I>name</I> is currently
the topmost cell in the window, the window will be loaded
with default cell "(UNNAMED)".
with default cell "(UNNAMED)". If option <B>-noprompt</B>
is specified, then the actions specified above happen
immediately. Otherwise, a dialog box will be raised
asking for confirmation to delete the cell.
<DT> <B>dereference</B> <I>name</I>
<DD> Perform a flush of the cell (per the "<B>flush</B>" command),
first removing any file path associated with the cell, so

View File

@ -334,23 +334,23 @@
</TR>
<TR>
<TD> <A HREF=undo.html> <B>undo</B></A> </TD>
<TD> <A HREF=units.html> <B>units</B></A> </TD>
<TD> <A HREF=updatedisplay.html> <B>updatedisplay</B></A> </TD>
<TD> <A HREF=version.html> <B>version</B></A> </TD>
</TR>
<TR>
<TD> <A HREF=version.html> <B>version</B></A> </TD>
<TD> <A HREF=view.html> <B>view</B></A> </TD>
<TD> <A HREF=windowborder.html> <B>windowborder</B></A> </TD>
<TD> <A HREF=windowcaption.html> <B>windowcaption</B></A> </TD>
</TR>
<TR>
<TD> <A HREF=windowcaption.html> <B>windowcaption</B></A> </TD>
<TD> <A HREF=windownames.html> <B>windownames</B></A> </TD>
<TD> <A HREF=windowscrollbars.html> <B>windowscrollbars</B></A> </TD>
<TD> <A HREF=xview.html> <B>xview</B></A> </TD>
</TR>
<TR>
<TD> <A HREF=xview.html> <B>xview</B></A> </TD>
<TD> <A HREF=zoom.html> <B>zoom</B></A> </TD>
<TD> <A HREF=tk_path_name.html> <I>tk_path_name</I></A> </TD>
<TD> </TD>
</TR>
</TBODY>
</TABLE>
@ -362,184 +362,189 @@
cellpadding="5" bgcolor="#ccccff">
<TBODY>
<TR>
<TD> <A HREF=addcommandentry.html><B>addcommandentry</B></A><TD>
<TD> <A HREF=addpath.html> <B>addpath</B></A><TD>
<TD> <A HREF=antennacheck.html> <B>antennacheck</B></A><TD>
<TD> <A HREF=addcommandentry.html><B>addcommandentry</B></A></TD>
<TD> <A HREF=addpath.html> <B>addpath</B></A></TD>
<TD> <A HREF=antennacheck.html> <B>antennacheck</B></A></TD>
</TR>
<TR>
<TD> <A HREF=array.html> <B>array</B></A><TD>
<TD> <A HREF=box.html> <B>box</B></A><TD>
<TD> <A HREF=calma.html> <B>calma</B></A><TD>
<TD> <A HREF=archive.html> <B>array</B></A></TD>
<TD> <A HREF=array.html> <B>array</B></A></TD>
<TD> <A HREF=box.html> <B>box</B></A></TD>
</TR>
<TR>
<TD> <A HREF=caption.html> <B>caption</B></A><TD>
<TD> <A HREF=cellmanager.html> <B>cellmanager</B></A><TD>
<TD> <A HREF=cellname.html> <B>cellname</B></A><TD>
<TD> <A HREF=calma.html> <B>calma</B></A></TD>
<TD> <A HREF=caption.html> <B>caption</B></A></TD>
<TD> <A HREF=cellmanager.html> <B>cellmanager</B></A></TD>
</TR>
<TR>
<TD> <A HREF=cellsearch.html> <B>cellsearch</B></A><TD>
<TD> <A HREF=channels.html> <B>channels</B></A><TD>
<TD> <A HREF=cif.html> <B>cif</B></A><TD>
<TD> <A HREF=cellname.html> <B>cellname</B></A></TD>
<TD> <A HREF=cellsearch.html> <B>cellsearch</B></A></TD>
<TD> <A HREF=channels.html> <B>channels</B></A></TD>
</TR>
<TR>
<TD> <A HREF=clockwise.html> <B>clockwise</B></A><TD>
<TD> <A HREF=closewrapper.html> <B>closewrapper</B></A><TD>
<TD> <A HREF=contact.html> <B>contact</B></A><TD>
<TD> <A HREF=cif.html> <B>cif</B></A></TD>
<TD> <A HREF=clockwise.html> <B>clockwise</B></A></TD>
<TD> <A HREF=closewrapper.html> <B>closewrapper</B></A></TD>
</TR>
<TR>
<TD> <A HREF=copy.html> <B>copy</B></A><TD>
<TD> <A HREF=corner.html> <B>corner</B></A><TD>
<TD> <A HREF=crash.html> <B>crash</B></A><TD>
<TD> <A HREF=contact.html> <B>contact</B></A></TD>
<TD> <A HREF=copy.html> <B>copy</B></A></TD>
<TD> <A HREF=corner.html> <B>corner</B></A></TD>
</TR>
<TR>
<TD> <A HREF=crashbackups.html> <B>crashbackups</B></A><TD>
<TD> <A HREF=crosshair.html> <B>crosshair</B></A><TD>
<TD> <A HREF=def.html> <B>def</B></A><TD>
<TD> <A HREF=crash.html> <B>crash</B></A></TD>
<TD> <A HREF=crashbackups.html> <B>crashbackups</B></A></TD>
<TD> <A HREF=crosshair.html> <B>crosshair</B></A></TD>
</TR>
<TR>
<TD> <A HREF=delete.html> <B>delete</B></A><TD>
<TD> <A HREF=deletecommandentry.html> <B>deletecommandentry</B></A><TD>
<TD> <A HREF=down.html> <B>down</B></A><TD>
<TD> <A HREF=def.html> <B>def</B></A></TD>
<TD> <A HREF=delete.html> <B>delete</B></A></TD>
<TD> <A HREF=deletecommandentry.html> <B>deletecommandentry</B></A></TD>
</TR>
<TR>
<TD> <A HREF=drc.html> <B>drc</B></A><TD>
<TD> <A HREF=dump.html> <B>dump</B></A><TD>
<TD> <A HREF=edit.html> <B>edit</B></A><TD>
<TD> <A HREF=down.html> <B>down</B></A></TD>
<TD> <A HREF=drc.html> <B>drc</B></A></TD>
<TD> <A HREF=dump.html> <B>dump</B></A></TD>
</TR>
<TR>
<TD> <A HREF=element.html> <B>element</B></A><TD>
<TD> <A HREF=erase.html> <B>erase</B></A><TD>
<TD> <A HREF=expand.html> <B>expand</B></A><TD>
<TD> <A HREF=edit.html> <B>edit</B></A></TD>
<TD> <A HREF=element.html> <B>element</B></A></TD>
<TD> <A HREF=erase.html> <B>erase</B></A></TD>
</TR>
<TR>
<TD> <A HREF=ext.html> <B>ext</B></A><TD>
<TD> <A HREF=ext2sim.html> <B>ext2sim</B></A><TD>
<TD> <A HREF=ext2spice.html> <B>ext2spice</B></A><TD>
<TD> <A HREF=expand.html> <B>expand</B></A></TD>
<TD> <A HREF=ext.html> <B>ext</B></A></TD>
<TD> <A HREF=ext2sim.html> <B>ext2sim</B></A></TD>
</TR>
<TR>
<TD> <A HREF=extract.html> <B>extract</B></A><TD>
<TD> <A HREF=extresist.html> <B>extresist</B></A><TD>
<TD> <A HREF=ext2sim.html> <B>exttosim</B></A><TD>
<TD> <A HREF=ext2spice.html> <B>ext2spice</B></A></TD>
<TD> <A HREF=extract.html> <B>extract</B></A></TD>
<TD> <A HREF=extresist.html> <B>extresist</B></A></TD>
</TR>
<TR>
<TD> <A HREF=ext2spice.html> <B>exttospice</B></A><TD>
<TD> <A HREF=feedback.html> <B>feedback</B></A><TD>
<TD> <A HREF=fill.html> <B>fill</B></A><TD>
<TD> <A HREF=ext2sim.html> <B>exttosim</B></A></TD>
<TD> <A HREF=ext2spice.html> <B>exttospice</B></A></TD>
<TD> <A HREF=feedback.html> <B>feedback</B></A></TD>
</TR>
<TR>
<TD> <A HREF=findbox.html> <B>findbox</B></A><TD>
<TD> <A HREF=findlabel.html> <B>findlabel</B></A><TD>
<TD> <A HREF=flatten.html> <B>flatten</B></A><TD>
<TD> <A HREF=fill.html> <B>fill</B></A></TD>
<TD> <A HREF=findbox.html> <B>findbox</B></A></TD>
<TD> <A HREF=findlabel.html> <B>findlabel</B></A></TD>
</TR>
<TR>
<TD> <A HREF=flush.html> <B>flush</B></A><TD>
<TD> <A HREF=garoute.html> <B>garoute</B></A><TD>
<TD> <A HREF=gds.html> <B>gds</B></A><TD>
<TD> <A HREF=flatten.html> <B>flatten</B></A></TD>
<TD> <A HREF=flush.html> <B>flush</B></A></TD>
<TD> <A HREF=garoute.html> <B>garoute</B></A></TD>
</TR>
<TR>
<TD> <A HREF=get.html> <B>get</B></A><TD>
<TD> <A HREF=getcell.html> <B>getcell</B></A><TD>
<TD> <A HREF=getnode.html> <B>getnode</B></A><TD>
<TD> <A HREF=gds.html> <B>gds</B></A></TD>
<TD> <A HREF=get.html> <B>get</B></A></TD>
<TD> <A HREF=getcell.html> <B>getcell</B></A></TD>
</TR>
<TR>
<TD> <A HREF=goto.html> <B>goto</B></A><TD>
<TD> <A HREF=grid.html> <B>grid</B></A><TD>
<TD> <A HREF=help.html> <B>help</B></A><TD>
<TD> <A HREF=getnode.html> <B>getnode</B></A></TD>
<TD> <A HREF=goto.html> <B>goto</B></A></TD>
<TD> <A HREF=grid.html> <B>grid</B></A></TD>
</TR>
<TR>
<TD> <A HREF=identify.html> <B>identify</B></A><TD>
<TD> <A HREF=initialize.html> <B>initialize</B></A><TD>
<TD> <A HREF=instance.html> <B>instance</B></A><TD>
<TD> <A HREF=help.html> <B>help</B></A></TD>
<TD> <A HREF=identify.html> <B>identify</B></A></TD>
<TD> <A HREF=initialize.html> <B>initialize</B></A></TD>
</TR>
<TR>
<TD> <A HREF=iroute.html> <B>iroute</B></A><TD>
<TD> <A HREF=irsim.html> <B>irsim</B></A><TD>
<TD> <A HREF=label.html> <B>label</B></A><TD>
<TD> <A HREF=instance.html> <B>instance</B></A></TD>
<TD> <A HREF=iroute.html> <B>iroute</B></A></TD>
<TD> <A HREF=irsim.html> <B>irsim</B></A></TD>
</TR>
<TR>
<TD> <A HREF=lef.html> <B>lef</B></A><TD>
<TD> <A HREF=load.html> <B>load</B></A><TD>
<TD> <A HREF=maketoolbar.html> <B>maketoolbar</B></A><TD>
<TD> <A HREF=label.html> <B>label</B></A></TD>
<TD> <A HREF=lef.html> <B>lef</B></A></TD>
<TD> <A HREF=load.html> <B>load</B></A></TD>
</TR>
<TR>
<TD> <A HREF=move.html> <B>move</B></A><TD>
<TD> <A HREF=measure.html> <B>measure</B></A><TD>
<TD> <A HREF=openwrapper.html> <B>openwrapper</B></A><TD>
<TD> <A HREF=maketoolbar.html> <B>maketoolbar</B></A></TD>
<TD> <A HREF=move.html> <B>move</B></A></TD>
<TD> <A HREF=measure.html> <B>measure</B></A></TD>
</TR>
<TR>
<TD> <A HREF=paint.html> <B>paint</B></A><TD>
<TD> <A HREF=path.html> <B>path</B></A><TD>
<TD> <A HREF=peekbox.html> <B>peekbox</B></A><TD>
<TD> <A HREF=openwrapper.html> <B>openwrapper</B></A></TD>
<TD> <A HREF=paint.html> <B>paint</B></A></TD>
<TD> <A HREF=path.html> <B>path</B></A></TD>
</TR>
<TR>
<TD> <A HREF=plot.html> <B>plot</B></A><TD>
<TD> <A HREF=plow.html> <B>plow</B></A><TD>
<TD> <A HREF=polygon.html> <B>polygon</B></A><TD>
<TD> <A HREF=peekbox.html> <B>peekbox</B></A></TD>
<TD> <A HREF=plot.html> <B>plot</B></A></TD>
<TD> <A HREF=plow.html> <B>plow</B></A></TD>
</TR>
<TR>
<TD> <A HREF=popbox.html> <B>popbox</B></A><TD>
<TD> <A HREF=popstack.html> <B>popstack</B></A><TD>
<TD> <A HREF=port.html> <B>port</B></A><TD>
<TD> <A HREF=polygon.html> <B>polygon</B></A></TD>
<TD> <A HREF=popbox.html> <B>popbox</B></A></TD>
<TD> <A HREF=popstack.html> <B>popstack</B></A></TD>
</TR>
<TR>
<TD> <A HREF=promptload.html> <B>promptload</B></A><TD>
<TD> <A HREF=promptsave.html> <B>promptsave</B></A><TD>
<TD> <A HREF=property.html> <B>property</B></A><TD>
<TD> <A HREF=port.html> <B>port</B></A></TD>
<TD> <A HREF=promptload.html> <B>promptload</B></A></TD>
<TD> <A HREF=promptsave.html> <B>promptsave</B></A></TD>
</TR>
<TR>
<TD> <A HREF=pushbox.html> <B>pushbox</B></A><TD>
<TD> <A HREF=pushstack.html> <B>pushstack</B></A><TD>
<TD> <A HREF=render3d.html> <B>render3d</B></A><TD>
<TD> <A HREF=property.html> <B>property</B></A></TD>
<TD> <A HREF=pushbox.html> <B>pushbox</B></A></TD>
<TD> <A HREF=pushstack.html> <B>pushstack</B></A></TD>
</TR>
<TR>
<TD> <A HREF=resumeall.html> <B>resumeall</B></A><TD>
<TD> <A HREF=rotate.html> <B>rotate</B></A><TD>
<TD> <A HREF=route.html> <B>route</B></A><TD>
<TD> <A HREF=render3d.html> <B>render3d</B></A></TD>
<TD> <A HREF=resumeall.html> <B>resumeall</B></A></TD>
<TD> <A HREF=rotate.html> <B>rotate</B></A></TD>
</TR>
<TR>
<TD> <A HREF=save.html> <B>save</B></A><TD>
<TD> <A HREF=scalegrid.html> <B>scalegrid</B></A><TD>
<TD> <A HREF=search.html> <B>search</B></A><TD>
<TD> <A HREF=route.html> <B>route</B></A></TD>
<TD> <A HREF=save.html> <B>save</B></A></TD>
<TD> <A HREF=scalegrid.html> <B>scalegrid</B></A></TD>
</TR>
<TR>
<TD> <A HREF=see.html> <B>see</B></A><TD>
<TD> <A HREF=select.html> <B>select</B></A><TD>
<TD> <A HREF=setlabel.html> <B>setlabel</B> <I>(version 8.0)</I></A><TD>
<TD> <A HREF=search.html> <B>search</B></A></TD>
<TD> <A HREF=see.html> <B>see</B></A></TD>
<TD> <A HREF=select.html> <B>select</B></A></TD>
</TR>
<TR>
<TD> <A HREF=shell.html> <B>shell</B></A><TD>
<TD> <A HREF=sideways.html> <B>sideways</B></A><TD>
<TD> <A HREF=snap.html> <B>snap</B></A><TD>
<TD> <A HREF=setlabel.html> <B>setlabel</B> <I>(version 8.0)</I></A></TD>
<TD> <A HREF=shell.html> <B>shell</B></A></TD>
<TD> <A HREF=sideways.html> <B>sideways</B></A></TD>
</TR>
<TR>
<TD> <A HREF=spliterase.html> <B>spliterase</B></A><TD>
<TD> <A HREF=splitpaint.html> <B>splitpaint</B></A><TD>
<TD> <A HREF=startup.html> <B>startup</B></A><TD>
<TD> <A HREF=snap.html> <B>snap</B></A></TD>
<TD> <A HREF=spliterase.html> <B>spliterase</B></A></TD>
<TD> <A HREF=splitpaint.html> <B>splitpaint</B></A></TD>
</TR>
<TR>
<TD> <A HREF=straighten.html> <B>straighten</B></A><TD>
<TD> <A HREF=stretch.html> <B>stretch</B></A><TD>
<TD> <A HREF=suspendall.html> <B>suspendall</B></A><TD>
<TD> <A HREF=startup.html> <B>startup</B></A></TD>
<TD> <A HREF=straighten.html> <B>straighten</B></A></TD>
<TD> <A HREF=stretch.html> <B>stretch</B></A></TD>
</TR>
<TR>
<TD> <A HREF=tag.html> <B>tag</B></A><TD>
<TD> <A HREF=tech.html> <B>tech</B></A><TD>
<TD> <A HREF=techmanager.html> <B>techmanager</B></A><TD>
<TD> <A HREF=suspendall.html> <B>suspendall</B></A></TD>
<TD> <A HREF=tag.html> <B>tag</B></A></TD>
<TD> <A HREF=tech.html> <B>tech</B></A></TD>
</TR>
<TR>
<TD> <A HREF=tool.html> <B>tool</B> <I>(non-Tcl version)</I></A><TD>
<TD> <A HREF=changetool.html> <B>tool</B> <I>(Tcl version)</I></A><TD>
<TD> <A HREF=unexpand.html> <B>unexpand</B></A><TD>
<TD> <A HREF=techmanager.html> <B>techmanager</B></A></TD>
<TD> <A HREF=tool.html> <B>tool</B> <I>(non-Tcl version)</I></A></TD>
<TD> <A HREF=changetool.html> <B>tool</B> <I>(Tcl version)</I></A></TD>
</TR>
<TR>
<TD> <A HREF=unmeasure.html> <B>unmeasure</B></A><TD>
<TD> <A HREF=upsidedown.html> <B>upsidedown</B></A><TD>
<TD> <A HREF=what.html> <B>what</B></A><TD>
<TD> <A HREF=unexpand.html> <B>unexpand</B></A></TD>
<TD> <A HREF=unmeasure.html> <B>unmeasure</B></A></TD>
<TD> <A HREF=upsidedown.html> <B>upsidedown</B></A></TD>
</TR>
<TR>
<TD> <A HREF=wire.html> <B>wire</B></A><TD>
<TD> <A HREF=writeall.html> <B>writeall</B></A><TD>
<TD> <A HREF=xload.html> <B>xload</B></A><TD>
<TD> <A HREF=what.html> <B>what</B></A></TD>
<TD> <A HREF=wire.html> <B>wire</B></A></TD>
<TD> <A HREF=writeall.html> <B>writeall</B></A></TD>
</TR>
<TR>
<TD> <A HREF=xload.html> <B>xload</B></A></TD>
<TD> </TD>
<TD> </TD>
</TR>
</TBODY>
</TABLE>
@ -551,38 +556,38 @@
cellpadding="5" bgcolor="#ffcccc">
<TBODY>
<TR>
<TD> <A HREF=netlist/add.html><B>add</B></A><TD>
<TD> <A HREF=netlist/cleanup.html><B>cleanup</B></A><TD>
<TD> <A HREF=netlist/cull.html><B>cull</B></A><TD>
<TD> <A HREF=netlist/add.html><B>add</B></A></TD>
<TD> <A HREF=netlist/cleanup.html><B>cleanup</B></A></TD>
<TD> <A HREF=netlist/cull.html><B>cull</B></A></TD>
</TR>
<TR>
<TD> <A HREF=netlist/dnet.html><B>dnet</B></A><TD>
<TD> <A HREF=netlist/dterm.html><B>dterm</B></A><TD>
<TD> <A HREF=netlist/extract.html><B>extract</B></A><TD>
<TD> <A HREF=netlist/dnet.html><B>dnet</B></A></TD>
<TD> <A HREF=netlist/dterm.html><B>dterm</B></A></TD>
<TD> <A HREF=netlist/extract.html><B>extract</B></A></TD>
</TR>
<TR>
<TD> <A HREF=netlist/find.html><B>find</B></A><TD>
<TD> <A HREF=netlist/flush.html><B>flush</B></A><TD>
<TD> <A HREF=netlist/join.html><B>join</B></A><TD>
<TD> <A HREF=netlist/find.html><B>find</B></A></TD>
<TD> <A HREF=netlist/flush.html><B>flush</B></A></TD>
<TD> <A HREF=netlist/join.html><B>join</B></A></TD>
</TR>
<TR>
<TD> <A HREF=netlist/netlist.html><B>netlist</B></A><TD>
<TD> <A HREF=netlist/orient.html><B>orient</B></A><TD>
<TD> <A HREF=netlist/pushbutton.html><B>pushbutton</B></A><TD>
<TD> <A HREF=netlist/netlist.html><B>netlist</B></A></TD>
<TD> <A HREF=netlist/orient.html><B>orient</B></A></TD>
<TD> <A HREF=netlist/pushbutton.html><B>pushbutton</B></A></TD>
</TR>
<TR>
<TD> <A HREF=netlist/print.html><B>print</B></A><TD>
<TD> <A HREF=netlist/ripup.html><B>ripup</B></A><TD>
<TD> <A HREF=netlist/savenetlist.html><B>savenetlist</B></A><TD>
<TD> <A HREF=netlist/print.html><B>print</B></A></TD>
<TD> <A HREF=netlist/ripup.html><B>ripup</B></A></TD>
<TD> <A HREF=netlist/savenetlist.html><B>savenetlist</B></A></TD>
</TR>
<TR>
<TD> <A HREF=netlist/shownet.html><B>shownet</B></A><TD>
<TD> <A HREF=netlist/showterms.html><B>showterms</B></A><TD>
<TD> <A HREF=netlist/trace.html><B>trace</B></A><TD>
<TD> <A HREF=netlist/shownet.html><B>shownet</B></A></TD>
<TD> <A HREF=netlist/showterms.html><B>showterms</B></A></TD>
<TD> <A HREF=netlist/trace.html><B>trace</B></A></TD>
</TR>
<TR>
<TD> <A HREF=netlist/verify.html><B>verify</B></A><TD>
<TD> <A HREF=netlist/writeall.html><B>writeall</B></A><TD>
<TD> <A HREF=netlist/verify.html><B>verify</B></A></TD>
<TD> <A HREF=netlist/writeall.html><B>writeall</B></A></TD>
<TD></TD>
</TR>
</TBODY>
@ -595,24 +600,24 @@
cellpadding="5" bgcolor="#ccffcc">
<TBODY>
<TR>
<TD> <A HREF=wind3d/cif.html><B>cif</B></A><TD>
<TD> <A HREF=wind3d/closewindow.html><B>closewindow</B></A><TD>
<TD> <A HREF=wind3d/cutbox.html><B>cutbox</B></A><TD>
<TD> <A HREF=wind3d/cif.html><B>cif</B></A></TD>
<TD> <A HREF=wind3d/closewindow.html><B>closewindow</B></A></TD>
<TD> <A HREF=wind3d/cutbox.html><B>cutbox</B></A></TD>
</TR>
<TR>
<TD> <A HREF=wind3d/defaults.html><B>defaults</B></A><TD>
<TD> <A HREF=wind3d/help.html><B>help</B></A><TD>
<TD> <A HREF=wind3d/level.html><B>level</B></A><TD>
<TD> <A HREF=wind3d/defaults.html><B>defaults</B></A></TD>
<TD> <A HREF=wind3d/help.html><B>help</B></A></TD>
<TD> <A HREF=wind3d/level.html><B>level</B></A></TD>
</TR>
<TR>
<TD> <A HREF=wind3d/refresh.html><B>refresh</B></A><TD>
<TD> <A HREF=wind3d/render.html><B>render</B></A><TD>
<TD> <A HREF=wind3d/scroll.html><B>scroll</B></A><TD>
<TD> <A HREF=wind3d/refresh.html><B>refresh</B></A></TD>
<TD> <A HREF=wind3d/render.html><B>render</B></A></TD>
<TD> <A HREF=wind3d/scroll.html><B>scroll</B></A></TD>
</TR>
<TR>
<TD> <A HREF=wind3d/see.html><B>see</B></A><TD>
<TD> <A HREF=wind3d/view.html><B>view</B></A><TD>
<TD> <A HREF=wind3d/zoom.html><B>zoom</B></A><TD>
<TD> <A HREF=wind3d/see.html><B>see</B></A></TD>
<TD> <A HREF=wind3d/view.html><B>view</B></A></TD>
<TD> <A HREF=wind3d/zoom.html><B>zoom</B></A></TD>
</TR>
</TBODY>
</TABLE>
@ -624,12 +629,12 @@
cellpadding="5" bgcolor="#ffccff">
<TBODY>
<TR>
<TD> <A HREF=color/pushbutton.html><B>pushbutton</B></A><TD>
<TD> <A HREF=color/color.html><B>color</B></A><TD>
<TD> <A HREF=color/load.html><B>load</B></A><TD>
<TD> <A HREF=color/pushbutton.html><B>pushbutton</B></A></TD>
<TD> <A HREF=color/color.html><B>color</B></A></TD>
<TD> <A HREF=color/load.html><B>load</B></A></TD>
</TR>
<TR>
<TD> <A HREF=color/save.html><B>save</B></A><TD>
<TD> <A HREF=color/save.html><B>save</B></A></TD>
<TD></TD>
<TD></TD>
</TR>
@ -643,19 +648,19 @@
cellpadding="5" bgcolor="#ffffcc">
<TBODY>
<TR>
<TD> <A HREF=wizard/bypass.html><B>*bypass</B></A><TD>
<TD> <A HREF=wizard/coord.html><B>*coord</B></A><TD>
<TD> <A HREF=wizard/extract.html><B>*extract</B></A><TD>
<TD> <A HREF=wizard/bypass.html><B>*bypass</B></A></TD>
<TD> <A HREF=wizard/coord.html><B>*coord</B></A></TD>
<TD> <A HREF=wizard/extract.html><B>*extract</B></A></TD>
</TR>
<TR>
<TD> <A HREF=wizard/plow.html><B>*plow</B></A><TD>
<TD> <A HREF=wizard/psearch.html><B>*psearch</B></A><TD>
<TD> <A HREF=wizard/showtech.html><B>*showtech</B></A><TD>
<TD> <A HREF=wizard/plow.html><B>*plow</B></A></TD>
<TD> <A HREF=wizard/psearch.html><B>*psearch</B></A></TD>
<TD> <A HREF=wizard/showtech.html><B>*showtech</B></A></TD>
</TR>
<TR>
<TD> <A HREF=wizard/tilestats.html><B>*tilestats</B></A><TD>
<TD> <A HREF=wizard/tsearch.html><B>*tsearch</B></A><TD>
<TD> <A HREF=wizard/watch.html><B>*watch</B></A><TD>
<TD> <A HREF=wizard/tilestats.html><B>*tilestats</B></A></TD>
<TD> <A HREF=wizard/tsearch.html><B>*tsearch</B></A></TD>
<TD> <A HREF=wizard/watch.html><B>*watch</B></A></TD>
</TR>
</TBODY>
</TABLE>
@ -667,14 +672,14 @@
cellpadding="5" bgcolor="#cccccc">
<TBODY>
<TR>
<TD> <A HREF=wizard/crash.html><B>*crash</B></A><TD>
<TD> <A HREF=wizard/files.html><B>*files</B></A><TD>
<TD> <A HREF=wizard/grstats.html><B>*grstats</B></A><TD>
<TD> <A HREF=wizard/crash.html><B>*crash</B></A></TD>
<TD> <A HREF=wizard/files.html><B>*files</B></A></TD>
<TD> <A HREF=wizard/grstats.html><B>*grstats</B></A></TD>
</TR>
<TR>
<TD> <A HREF=wizard/pause.html><B>*pause</B></A><TD>
<TD> <A HREF=wizard/winddebug.html><B>*winddebug</B></A><TD>
<TD> <A HREF=wizard/winddump.html><B>*winddump</B></A><TD>
<TD> <A HREF=wizard/pause.html><B>*pause</B></A></TD>
<TD> <A HREF=wizard/winddebug.html><B>*winddebug</B></A></TD>
<TD> <A HREF=wizard/winddump.html><B>*winddump</B></A></TD>
</TR>
</TBODY>
</TABLE>

View File

@ -1,6 +1,7 @@
addcommandentry
addpath
antennacheck
archive
array
box
calma
@ -116,6 +117,7 @@ techmanager
tool
undo
unexpand
units
updatedisplay
upsidedown
version

View File

@ -26,7 +26,8 @@ expanded/unexpanded cells in the current selection.
<H3>Usage:</H3>
<BLOCKQUOTE>
<B>expand</B> [<B>toggle</B>] <BR><BR>
<B>expand</B> [<B>selection</B>|<B>surround</B>|<B>overlap</B>|<B>all</B>]
[<B>toggle</B>] <BR><BR>
</BLOCKQUOTE>
<H3>Shortcuts:</H3>
@ -38,14 +39,32 @@ expanded/unexpanded cells in the current selection.
<H3>Summary:</H3>
<BLOCKQUOTE>
The <B>expand</B> command expands the view of subcells to
display the contents of the subcells. Without arguments,
the <B>expand</B> command expands all unexpanded subcells that
touch or intersect the cursor box in the layout window. <P>
display the contents of the subcells.
Option <B>overlap</B> expands all unexpanded subcells that
overlap with the cursor box in the layout window. <P>
Option <B>surround</B> expands all unexpanded subcells that
are completely surrounded by the cursor box in the layout window. <P>
Option <B>all</B> expands all subcells in the layout window. <P>
Option <B>selection</B> operates on the current selection, not
relative to the cursor box, expanding all selected cells. <P>
Option <B>toggle</B> will expand a selected cell that is
unexpanded, or unexpand a cell that is already expanded.
<B>toggle</B> may be given as an additional option to any
of the other options above; however, the <B>toggle</B> option
must be the last option given to the command.<P>
With no arguments, the <B>expand</B> command behaves like
<B>expand overlap</B>, and the <B>expand toggle</B> command
with no additonal arguments behaves like
<B>expand selection toggle</B>, for backwards-compatible
behavior with earlier versions of magic which offered only
the <B>toggle</B> option.
Option <B>expand toggle</B> operates on the current selection,
not relative to the cursor box, and will expand a selected
cell that is unexpanded, or unexpand a cell that is already
expanded.
</BLOCKQUOTE>
<H3>Implementation Notes:</H3>

View File

@ -34,11 +34,15 @@ Convert extracted file(s) to a SPICE format file.
(see Summary, below).
<DT> <B>default</B>
<DD> Reset to default values
<DT> <B>format hspice</B>|<B>spice2</B>|<B>spice3</B>|<B>ngspice</B>
<DT> <B>format hspice</B>|<B>spice2</B>|<B>spice3</B>|<B>ngspice</B>|<B>cdl</B>
<DD> Set output format. <B>spice3</B> is the default,
for compatibility with <B>tclspice</B>. This is a
change from previous versions of magic, where the
default was <B>hspice</B>.
default was <B>hspice</B>. <B>ngspice</B> is set as
default by the <B>ext2spice lvs</B> option. <B>cdl</B>
format incorporates some common syntax used by CDL format
files, including placing a slash between a subcircuit's
pins and the subcircuit name.
<DT> <B>rthresh</B> [<I>value</I>]
<DD> Set resistance threshold value. Lumped resistances
below this value will not be written to the output. The
@ -46,7 +50,6 @@ Convert extracted file(s) to a SPICE format file.
to prohibit writing any lumped resistances to the output.
<DT> <B>cthresh</B> [<I>value</I>]
<DD> Set capacitance threshold value. The value is in femtofarads,
or may be the keyword <B>infinite</B> to prohibit writing
any parasitic capacitances to the output.
<DT> <B>merge</B> [<I>merge_option</I>]
<DD> Merge parallel devices/transistors. The valid merge options are:
@ -95,13 +98,18 @@ Convert extracted file(s) to a SPICE format file.
<B>subcircuit</B> is set to <B>off</B>, the top-level
circuit will be the top level of the netlist, and it
will have no associated subcircuit definition.
<DT> <B>subcircuit top</B> [<B>on</B>|<B>off</B>]
<DT> <B>subcircuit top</B> [<B>on</B>|<B>off</B>|<B>auto</B>]
<DD> This variant of the <B>subcircuit</B> option controls
whether or not ext2spice generates a .subckt wrapper
around the top-level circuit. If the top-level circuit
does not have defined ports, then no .subckt wrapper
will ever be generated, because ext2spice will not
be able to know which nets are the ports.
around the top-level circuit. If <B>on</B> is specified,
a ".subckt" wrapper will always be output, regardless of
whether or not ports are defined in the layout. If
<B>off</B>, no ".subckt" wrapper will be output, and
ports will be ignored (They will be regular nets in the
output netlist). If set to <B>auto</B>, magic will
check whether or not ports are defined in the layout,
and generate a ".subckt" wrapper only if ports have
been defined.
<DT> <B>subcircuit descend</B> [<B>on</B>|<B>off</B>]
<DD> When set to <B>off</B>, the <B>subcircuit descend</B>
option will not descend into any subcells below the
@ -230,7 +238,7 @@ Convert extracted file(s) to a SPICE format file.
class, and substrate node name for device type <I>device</I>.
Resistance classes are indexed by number and must match the
definition in the technology file's extract section.
<DT> <B>-f spice2</B>|<B>spice3</B>|<B>hspice</B>|<B>ngspice</B>
<DT> <B>-f spice2</B>|<B>spice3</B>|<B>hspice</B>|<B>ngspice</B>|<B>cdl</B>
<DD> Choose the output SPICE format for compatibility with
different versions of SPICE.
<DT> <B>-d</B>

View File

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

View File

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

View File

@ -1,161 +0,0 @@
<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.gif ALT="Magic VLSI Layout Tool Version 8.3">
<IMG SRC=graphics/magic_OGL_sm.gif ALIGN="top" ALT="*"> </H1>
<H2>ext2sim, exttosim</H2>
<HR>
Convert extracted file(s) to a ".sim" format file.
<HR>
<H3>Usage:</H3>
<BLOCKQUOTE>
<B>ext2sim</B> [<I>option</I>] <BR><BR>
<BLOCKQUOTE>
where <I>option</I> is one of the following:
<DL>
<DT> [<B>run</B>] [<I>runtime_options</I>]
<DD> Run exttosim on current cell, with command-line options
(see Summary, below).
<DT> <B>alias on</B>|<B>off</B>
<DD> Enable/disable alias (.al) file
<DT> <B>labels on</B>|<B>off</B>
<DD> Enable/disable labels (.nodes) file
<DT> <B>default</B>
<DD> Reset to default values
<DT> <B>format MIT</B>|<B>SU</B>|<B>LBL</B>
<DD> Set output format
<DT> <B>rthresh</B> [<I>value</I>]
<DD> Set resistance threshold value. Lumped resistances
below this value will not be written to the output. The
value is in ohms, or may be the keyword <B>infinite</B>
to prohibit writing any lumped resistances to the output.
<DT> <B>cthresh</B> [<I>value</I>]
<DD> Set capacitance threshold value. The value is in femtofarads,
or may be the keyword <B>infinite</B> to prohibit writing
any parasitic capacitances to the output.
<DT> <B>merge</B> [<I>merge_option</I>]
<DD> Merge parallel devices/transistors. The valid merge options are:
<BLOCKQUOTE>
<DL>
<DT><B>conservative</B>
<DD> Merge transistors and capacitors having the same device
type and node connections and having the same width and
length. Widths are summed in the final output for
transistors. Capacitor values are summed in the final
output.
<DT><B>aggressive</B>
<DD> Merge transistors having the same node
connections and having the same length. Widths
are summed in the final output. Merge any capacitors
having the same device type and node connections.
Capacitance is summed in the final output.
<DT><B>none</B>
<DD> Do not merge any devices.
</DL>
</BLOCKQUOTE>
<DT> <B>extresist on</B>|<B>off</B>
<DD> Incorporate output from the command <B>extresist</B> into
the final <TT>.sim</TT> file.
<DT> <B>help</B>
<DD> Print help information
</DL>
</BLOCKQUOTE>
</BLOCKQUOTE>
<H3>Summary:</H3>
<BLOCKQUOTE>
Without options, or with the option <B>run</B>,
the <B>ext2sim</B> command converts the hierarchical extracted
netlist information produced by the <B>extract</B> command in
a series of <TT>.ext</TT> files into a flattened representation
in the <TT>.sim</TT> format, used for switch-level simulation. <P>
<I>runtime_options</I> may be passed on the command line, and
represent the original command-line options passed to the
standalone version of ext2sim. A number of the original
command-line options have been deprecated in the Tcl-based
version, and some are duplicated by other <B>ext2sim</B> options.
Valid <I>runtime_options</I> are:
<BLOCKQUOTE>
<DL>
<DT> <B>-B</B>
<DD> Don't output transistor or node attributes in the .sim file.
This option will also disable the output of information such
as the area and perimeter of source and drain diffusion and
the FET substrate.
<DT> <B>-F</B>
<DD> Don't output nodes that aren't connected to devices (floating
nodes).
<DT> <B>-t</B><I>char</I>
<DD> Trim characters from node names when writing the output file.
<I>char</I> should be either "<B>#</B>" or "<B>!</B>". The
option may be used twice if both characters require trimming.
<DT> <B>-y</B> <I>num</I>
<DD> Select the precision for outputting capacitors. The default is
1 which means that the capacitors will be printed to a precision
of 0.1 fF.
<DT> <B>-J</B> <B>hier</B>|<B>flat</B>
<DD> Select the source/drain area and perimeter extraction algorithm.
If <B>hier</B> is selected then the areas and perimeters are
extracted only within each subcell. For each device in a
subcell the area and perimeter of its source and drain within
this subcell are output. If two or more devices share a
source/drain node then the total area and perimeter will be
output in only one of them and the other will have 0. If
<B>flat</B> is selected the same rules apply, only the scope
of search for area and perimeter is the whole netlist. In
general, <B>flat</B> (which is the default) will give accurate
results (it will take into account shared sources/drains).
</DL>
</BLOCKQUOTE>
With options, the command sets various parameters affecting the
output format and content. <P>
</BLOCKQUOTE>
<H3>Implementation Notes:</H3>
<BLOCKQUOTE>
<B>ext2sim</B> is implemented as a separate loadable Tcl package,
but one which depends on the presence of the standard "tclmagic"
package. <B>magic</B> is set up with a placeholder command for
<B>ext2sim</B>, and will automatically load the Tcl package when
this command is invoked. <P>
<B>exttosim</B> is an alias for <B>ext2sim</B>, to satisfy the
grammatically anal retentive.
</BLOCKQUOTE>
<H3>See Also:</H3>
<BLOCKQUOTE>
<A HREF=extract.html><B>extract</B></A> <BR>
<A HREF=extresist.html><B>extresist</B></A> <BR>
<A HREF=ext2spice.html><B>ext2spice</B></A> <BR>
<A HREF=irsim.html><B>irsim</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> October 12, 2005 at 9:40pm <P>
</BODY>
</HTML>

View File

@ -1,176 +0,0 @@
<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.gif ALT="Magic VLSI Layout Tool Version 8.3">
<IMG SRC=graphics/magic_OGL_sm.gif ALIGN="top" ALT="*"> </H1>
<H2>ext2spice, exttospice</H2>
<HR>
Convert extracted file(s) to a SPICE format file.
<HR>
<H3>Usage:</H3>
<BLOCKQUOTE>
<B>ext2spice</B> [<I>option</I>] <BR><BR>
<BLOCKQUOTE>
where <I>option</I> is one of the following:
<DL>
<DT> [<B>run</B>] [<I>runtime_options</I>]
<DD> Run <B>ext2spice</B> on current cell, with command-line options
(see Summary, below).
<DT> <B>default</B>
<DD> Reset to default values
<DT> <B>format hspice</B>|<B>spice2</B>|<B>spice3</B>
<DD> Set output format. <B>spice3</B> is the default,
for compatibility with <B>tclspice</B>. This is a
change from previous versions of magic, where the
default was <B>hspice</B>.
<DT> <B>rthresh</B> [<I>value</I>]
<DD> Set resistance threshold value. Lumped resistances
below this value will not be written to the output. The
value is in ohms, or may be the keyword <B>infinite</B>
to prohibit writing any lumped resistances to the output.
<DT> <B>cthresh</B> [<I>value</I>]
<DD> Set capacitance threshold value. The value is in femtofarads,
or may be the keyword <B>infinite</B> to prohibit writing
any parasitic capacitances to the output.
<DT> <B>merge</B> [<I>merge_option</I>]
<DD> Merge parallel devices/transistors. The valid merge options are:
<BLOCKQUOTE>
<DL>
<DT><B>conservative</B>
<DD> Merge transistors and capacitors having the same device
type and node connections and having the same width and
length. Widths are summed in the final output for
transistors. Capacitor values are summed in the final
output.
<DT><B>aggressive</B>
<DD> Merge transistors having the same node
connections and having the same length. Widths
are summed in the final output. Merge any capacitors
having the same device type and node connections.
Capacitance is summed in the final output.
<DT><B>none</B>
<DD> Do not merge any devices.
</DL>
</BLOCKQUOTE>
<DT> <B>extresist on</B>|<B>off</B>
<DD> Incorporate output from the command <B>extresist</B> into
the final SPICE file.
<DT> <B>resistor tee</B> [<B>on</B>|<B>off</B>]
<DD> Model resistor capacitance as a T-network. Each resistor
device is split into two, with all substrate and overlap
capacitance placed on the node between the two half-length
devices. Without this option, resistor devices lose all
parasitic capacitance information, and <B>ext2spice</B>
may produce warnings about unknown nodes. However, use of
this option may conflict with LVS (layout-vs.-schematic),
when only one resistor is expected per drawn device.
<DT> <B>subcircuits</B> [<B>on</B>|<B>off</B>]
<DD> When set to <B>on</B> (the default), standard cells become
subcircuit calls ("X") in the SPICE output. The contents
of the standard cells are not output, and it is assumed
that a pre-characterized SPICE deck exists modeling the
behavior of each standard cell definition. Standard cells
are defined by the use of the <B>port</B> method for
labeling input and output ports. When set to <B>off</B>,
ports are ignored, and the entire circuit hierarchy is
flattened down to the device level.
<DT> <B>help</B>
<DD> Print help information.
</DL>
</BLOCKQUOTE>
</BLOCKQUOTE>
<H3>Summary:</H3>
<BLOCKQUOTE>
Without options, or with the option <B>run</B>,
the <B>ext2spice</B> command converts the hierarchical extracted
netlist information produced by the <B>extract</B> command in
a series of <TT>.ext</TT> files into a flattened representation
in SPICE format, used for detailed analog simulation. <P>
<I>runtime_options</I> may be passed on the command line, and
represent the original command-line options passed to the
standalone version of ext2spice. A number of the original
command-line options have been deprecated in the Tcl-based
version, and some are duplicated by other <B>ext2spice</B> options.
Valid <I>runtime_options</I> are:
<BLOCKQUOTE>
<DL>
<DT> <B>-B</B>
<DD> Don't output transistor or node attributes in the SPICE file.
This option will also disable the output of information such
as the area and perimeter of source and drain diffusion and
the FET substrate.
<DT> <B>-F</B>
<DD> Don't output nodes that aren't connected to devices (floating
nodes).
<DT> <B>-t</B><I>char</I>
<DD> Trim characters from node names when writing the output file.
<I>char</I> should be either "<B>#</B>" or "<B>!</B>". The
option may be used twice if both characters require trimming.
<DT> <B>-y</B> <I>num</I>
<DD> Select the precision for outputting capacitors. The default is
1 which means that the capacitors will be printed to a precision
of 0.1 fF.
<DT> <B>-J</B> <B>hier</B>|<B>flat</B>
<DD> Select the source/drain area and perimeter extraction algorithm.
If <B>hier</B> is selected then the areas and perimeters are
extracted only within each subcell. For each device in a
subcell the area and perimeter of its source and drain within
this subcell are output. If two or more devices share a
source/drain node then the total area and perimeter will be
output in only one of them and the other will have 0. If
<B>flat</B> is selected the same rules apply, only the scope
of search for area and perimeter is the whole netlist. In
general, <B>flat</B> (which is the default) will give accurate
results (it will take into account shared sources/drains).
</DL>
</BLOCKQUOTE>
With options, the command sets various parameters affecting the
output format and content. <P>
</BLOCKQUOTE>
<H3>Implementation Notes:</H3>
<BLOCKQUOTE>
<B>ext2spice</B> is implemented as a separate loadable Tcl package,
but one which depends on the presence of the standard "tclmagic"
package. <B>magic</B> is set up with a placeholder command for
<B>ext2spice</B>, and will automatically load the Tcl package when
this command is invoked. <P>
<B>exttospice</B> is an alias for <B>ext2spice</B>, to satisfy the
grammatically anal retentive.
</BLOCKQUOTE>
<H3>See Also:</H3>
<BLOCKQUOTE>
<A HREF=extract.html><B>extract</B></A> <BR>
<A HREF=ext2sim.html><B>ext2sim</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> October 12, 2005 at 9:40pm <P>
</BODY>
</HTML>

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 893 B

After

Width:  |  Height:  |  Size: 991 B

View File

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

View File

@ -37,10 +37,10 @@ LEF-format input and output
<DT> <B>read</B> [<I>filename</I>] <B>-annotate</B>
<DD> Read a LEF file. Use any macros defined in the LEF file
to annotate existing layouts, and ignore all other macros.
<DT> <B>write</B> [<I>cell</I>] [<B>-tech</B>]
<DT> <B>write</B> [<I>filename</I>] [<B>-tech</B>]
[<B>-hide</B> [<I>distance</I>]] [<B>-toplayer</B>]
[<B>-pinonly</B> [<I>distance</I>]] [<B>-nomaster</B>]
<DD> Write LEF for the current or indicated cell.<BR>
<DD> Write LEF for the current cell to the file <I>filename</I>.<BR>
Option <B>-tech</B> writes the technology information (layer
mapping and rules) to the same file as the cell macro. <BR>
Option <B>-hide</B> generates an abstract view that has all

View File

@ -20,22 +20,64 @@
<H2>macro</H2>
<HR>
Define or print a macro called char
Define or print a key or button macro binding.
<HR>
<H3>Usage:</H3>
<BLOCKQUOTE>
<B>macro</B> [<I>window_type</I>] [<I>key</I> [<I>value</I>]] <BR><BR>
<B>macro</B> [<I>window_type</I>] [<I>option</I>] [<I>key</I> [<I>value</I>]]
<BR><BR>
<BLOCKQUOTE>
where <I>key</I> is the name of a valid key (see below), and
<I>value</I> is a <B>magic</B> command-line command. If
present, <I>window_type</I> must be one of the four window
types accepted by the <B>specialopen</B> command: <B>layout</B>,
<B>color</B>, <B>netlist</B>, and <B>wind3d</B>. If omitted,
the layout window is assumed by default, unless the command has
been called from inside a window (using the colon or semicolon
present, <I>window_type</I> must be one of the known valid window
types accepted by the <B>specialopen</B> command (<B>color</B>,
<B>netlist</B>, and <B>wind3d</B>), or a known layout tool
(<B>box</B>, <B>wiring</B>, <B>nettool</B>, or <B>pick</B>). If
omitted, the layout window is assumed by default, unless the command
has been called from inside a window (using the colon or semicolon
escape to the command-line), in which case that window type is
assumed.
assumed. <P>
In the non-Tcl version of magic, the <I>window_type</I> must be
one of the three valid window types listed above, or <B>layout</B>.
Tool button bindings are hard-coded, fixed, and unknown to the
macro handler. <P>
In the Tcl version of magic, tool types are generated by
procedure and can be modified or overridden. The four tools
listed above are the default tools known to magic. If no window
or tool type is given, then the current tool in the current
active layout window is assumed.<P>
<I>option</I> may be one of the following:
<DL>
<DT> <B>list</B> [<B>-reverse</B>]
<DD> The key bindings are returned in the form of a Tcl list
(Tcl version of magic only). The returned value is a
single list with alternating entries of the macro key and
the macro binding. In Tcl, this list can be treated as a
dictionary type of key:value pairs. With the <B>-reverse</B>
option, the keys and values are reversed, resulting in a
dictionary that can be searched or listed by function.
<DT> <B>help</B>
<DD> Curently, <B>macro help</B> is equivalent to <B>macro</B>
without arguments, and returns a full list of macro names
and their bindings.
<DT> <B>search</B> <I>text</I>
<DD> Return only results which match (all or in part) the string
<I>text</I>. For example, <B>macro search grid</B> will
return all key bindings that include the command <B>grid</B>.
<DT> <B>copy</B> <I>tool_name</I>
<DD> This is a method introduced to allow the interactive creation
of new tools, in the Tcl version of magic. Each tool is defined
specifically by its unique button and key bindings. Because
tools generally keep most of the same default bindings, the
<B>copy</B> option will copy all the existing bindings to the
new tool from the current tool. This can be followed by
switching to the new tool and replacing macros with ones
unique to the tool.
</DL>
</BLOCKQUOTE>
</BLOCKQUOTE>
@ -72,7 +114,6 @@ Define or print a macro called char
etc., the <B>macro</B> command accepts the abbreviated
forms <B>Button1</B>, and so forth. <P>
Finally, key modifiers may be prepended to the key name.
Valid key modifiers are <B>Shift_</B>, <B>Control_</B>,
<B>Alt_</B>, and <B>Meta_</B>, and may be coupled in any
@ -89,6 +130,7 @@ Define or print a macro called char
<H3>See Also:</H3>
<BLOCKQUOTE>
<A HREF=imacro.html><B>imacro</B></A> <BR>
<A HREF=toolchange.html><B>tool</B></A> (Tcl version) <BR>
</BLOCKQUOTE>
<P><IMG SRC=graphics/line1.gif><P>

View File

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

View File

@ -41,7 +41,15 @@ Save edit cell on disk
The <B>save</B> command differs from <B>writeall</B> in several
ways: <B>save</B> does not descend the hierarchy, and does not
prompt the user for an action.
prompt the user for an action. <P>
As of magic version 8.3.549, if <I>filename</I> ends with
"<B>.tcl</B>", then magic will save a script file containing
a sequence of magic command-line commands that completely
reproduces the file layout. The cell can then be regenerated
by sourcing the script. This is not a substitution for a
database (<B>.mag</B>) file, and magic will not normally
search for or source these type of script files itself. <P>
</BLOCKQUOTE>
<H3>Implementation Notes:</H3>

View File

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

View File

@ -25,7 +25,8 @@ Unexpand everything inside or touching the cursor box.
<H3>Usage:</H3>
<BLOCKQUOTE>
<B>unexpand</B> <BR><BR>
<B>unexpand</B> [<B>selection</B>|<B>surround</B>|<B>overlap</B>|<B>all</B>]
<BR><BR>
</BLOCKQUOTE>
<H3>Shortcuts:</H3>
@ -37,8 +38,23 @@ Unexpand everything inside or touching the cursor box.
<BLOCKQUOTE>
The <B>unexpand</B> command unexpands the view of subcells to
hide the contents of the subcells and show the bounding box
outline only. The <B>unexpand</B> command unexpands all subcells
that touch or intersect the cursor box in the layout window. <P>
outline only.
Option <B>overlap</B> unexpands all expanded subcells that
overlap with the cursor box in the layout window. <P>
Option <B>surround</B> unexpands all expanded subcells that
are completely surrounded by the cursor box in the layout window. <P>
Option <B>all</B> unexpands all subcells in the layout window. <P>
Option <B>selection</B> operates on the current selection, not
relative to the cursor box, unexpanding all selected cells. <P>
With no arguments, the <B>unexpand</B> command behaves like
<B>unexpand surround</B>, for backwards-compatible behavior with
earlier versions of magic which did not offer the options.
</BLOCKQUOTE>
<H3>Implementation Notes:</H3>

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

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

View File

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

View File

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

View File

@ -27,6 +27,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include <stdio.h>
#include <string.h> // for memcpy()
#include <math.h> // for sqrt() for diagonal check
#include "tcltk/tclmagic.h"
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
@ -36,6 +38,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/signals.h"
#include "utils/maxrect.h"
#include "utils/malloc.h"
#include "utils/undo.h"
#include "textio/textio.h"
#include "cif/CIFint.h"
int dbDRCDebug = 0;
@ -47,7 +52,7 @@ int dbDRCDebug = 0;
static DRCCookie drcOverlapCookie = {
0, 0, 0, 0,
{ {0} }, { {0} },
0, 0, 0,
0, DRC_EXCEPTION_NONE, 0, 0,
DRC_OVERLAP_TAG,
(DRCCookie *) NULL
};
@ -61,7 +66,33 @@ extern MaxRectsData *drcCanonicalMaxwidth();
/*
*-----------------------------------------------------------------------
*
* drcCifPointToSegment
* drcFoundOneFunc --
*
* Simple callback for a plane search on a mask-hint plane inside
* a DRC check area.
*
* Results:
* Return 1 always, indicating that a tile has been found in the
* DRC search area, and the search can end.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------
*/
int
drcFoundOneFunc(Tile *tile,
TileType dinfo,
ClientData cdata)
{
return 1;
}
/*
*-----------------------------------------------------------------------
*
* drcCifPointToSegment --
*
* Euclidean-distance point-to-segment distance (squared)
* calculation (borrowed from XCircuit)
@ -139,8 +170,9 @@ drcCifPointToSegment(px, py, s1x, s1y, s2x, s2y)
*/
int
areaCheck(tile, arg)
areaCheck(tile, dinfo, arg)
Tile *tile;
TileType dinfo;
struct drcClientData *arg;
{
Rect rect; /* Area where error is to be recorded. */
@ -194,7 +226,7 @@ areaCheck(tile, arg)
- arg->dCD_constraint->r_ytop + sdist) >= 0)
&& ((sqx * sqx + sqy * sqy) >= ssdist))
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,
arg->dCD_constraint->r_ytop - sdist,
@ -209,7 +241,7 @@ areaCheck(tile, arg)
- arg->dCD_constraint->r_ytop + sdist) >= 0)
&& ((sqx * sqx + sqy * sqy) >= ssdist))
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,
arg->dCD_constraint->r_ytop - sdist,
@ -225,7 +257,7 @@ areaCheck(tile, arg)
+ sdist - rect.r_ytop) >= 0)
&& ((sqx * sqx + sqy * sqy) >= ssdist))
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,
arg->dCD_constraint->r_ybot + sdist,
@ -241,7 +273,7 @@ areaCheck(tile, arg)
+ sdist - rect.r_ytop) >= 0)
&& ((sqx * sqx + sqy * sqy) >= ssdist))
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,
arg->dCD_constraint->r_ybot + sdist,
@ -287,16 +319,59 @@ areaCheck(tile, arg)
/*
* ----------------------------------------------------------------------------
*
* areaNMCheck ---
* areaNMReject ---
*
* Check for errors in triangular area of a tile
* Trivial callback function used by areaNMCheck to see if a tile
* found in the error area of a reverse non-manhattan check exists
* only on the other side of the original check boundary. If it
* is found in this search, return 1 to immediately stop the search.
*
* Results:
* Returns 1 if the tile indicated in the ClientData argument was
* found in the check area, otherwise return 0 to keep looking.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
areaNMCheck(tile, arg)
areaNMReject(tile, dinfo, arg)
Tile *tile;
TileType dinfo;
ClientData *arg;
{
Tile *checktile = (Tile *)arg;
if (tile == checktile)
return 1;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* areaNMCheck ---
*
* Check for errors in triangular area of a tile.
*
* Results:
* Return 0 always to keep the search going.
*
* Side effects:
* If the tile is not rejected due to being outside of the various
* clip areas, then call the function specified in the drcClientData
* argument.
*
* ----------------------------------------------------------------------------
*/
int
areaNMCheck(tile, dinfo, arg)
Tile *tile;
TileType dinfo;
struct drcClientData *arg;
{
Rect rect; /* Area where error is to be recorded. */
@ -320,6 +395,25 @@ areaNMCheck(tile, arg)
if ((rect.r_xbot >= rect.r_xtop) || (rect.r_ybot >= rect.r_ytop))
return 0;
if (arg->dCD_entries & TT_DIAGONAL)
{
TileTypeBitMask mask;
int dinfo = arg->dCD_entries;
/* In the DRC_REVERSE case, the area being searched extends
* behind the edge that triggered the DRC check, but any
* tile that is outside that edge should be ignored. This
* requires a separate check.
*/
TTMaskSetOnlyType(&mask, TiGetLeftType(tile));
TTMaskSetType(&mask, TiGetRightType(tile));
if (DBSrPaintNMArea((Tile *)tile, (Plane *)NULL,
TiGetTypeExact(tile) | dinfo, arg->dCD_rlist,
&mask, areaNMReject, (ClientData)tile) == 0)
return 0;
}
(*(arg->dCD_function))(arg->dCD_celldef, &rect, arg->dCD_cptr,
arg->dCD_clientData);
(*(arg->dCD_errors))++;
@ -404,12 +498,39 @@ DRCBasicCheck (celldef, checkRect, clipRect, function, cdata)
DBResetTilePlane(celldef->cd_planes[planeNum], DRC_UNPROCESSED);
(void) DBSrPaintArea ((Tile *) NULL, celldef->cd_planes[planeNum],
checkRect, &DBAllTypeBits, drcTile, (ClientData) &arg);
#ifdef MAGIC_WRAPPER
/* Execute pending Tcl events, so the DRC process doesn't block. */
/* WARNING: This code cannot be enabled until some method is
* worked out to determine if any event resulted in a change
* to the DRC check plane which would invalidate the current
* search. If so, the search must end immediately and the
* area being checked must be reinstated. The code was added
* to see how it speeds up the response time of magic when
* some of the DRC rules are compute-intensive. It speeds up
* performance enough that it is worthwhile to implement the
* method just mentioned.
*/
#if 0
UndoEnable();
while (Tcl_DoOneEvent(TCL_DONT_WAIT));
UndoDisable();
#endif
#endif
}
drcCifCheck(&arg);
if (arg.dCD_rlist != NULL) freeMagic(arg.dCD_rlist);
return (errors);
}
/* Expect that keeping around 3 MaxRectsData records should be sufficient
* to avoid recomputing drcCanonicalMaxwidth() multiple times. Note that
* if a PDK sets up multiple rules on an edge which all require running
* drcCanonicalMaxwidth(), then this cache size may need to be revisited.
*/
#define MAXRECTSCACHE 3
/*
* ----------------------------------------------------------------------------
*
@ -432,8 +553,9 @@ DRCBasicCheck (celldef, checkRect, clipRect, function, cdata)
*/
int
drcTile (tile, arg)
Tile *tile; /* Tile being examined */
drcTile (tile, dinfo, arg)
Tile *tile; /* Tile being examined */
TileType dinfo; /* Split tile information */
struct drcClientData *arg;
{
DRCCookie *cptr; /* Current design rule on list */
@ -446,6 +568,19 @@ drcTile (tile, arg)
int triggered;
int cdist, dist, ccdist, result;
/* Keep up to three MaxRectsData records to avoid doing the same
* expensive computation more than once.
*
* mrdcache[0] will be used for the tpleft tile, since it will never
* be reused. mrdcache[1] and mrdcache[2] will be used for the tile
* itself. Note that if more than 2 DRCCookie entries for the same
* edge require drcCanonicalMaxwidth(), then mrdcache[2] will be
* re-used so that at least mrdcache[1] is always a cache hit.
*/
static MaxRectsData *mrdcache[MAXRECTSCACHE] = {NULL, NULL, NULL};
DRCCookie *cptrcache;
arg->dCD_constraint = &errRect;
/*
@ -473,7 +608,7 @@ drcTile (tile, arg)
/* DRC searches only one direction on regular tiles, the split */
/* tiles are only processed for one of the two cases. */
if (IsSplit(tile) && !SplitSide(tile))
if (IsSplit(tile) && !(dinfo & TT_SIDE))
{
int deltax, deltay;
TileType tt, to;
@ -495,7 +630,7 @@ drcTile (tile, arg)
{
int deltax, deltay, w, h;
double r;
TileType dinfo, dsplit;
TileType newdinfo, dsplit;
/* Work to be done: Handle triggering rules for non-Manhattan */
/* edges; especially important for the wide-spacing rule. */
@ -545,7 +680,7 @@ drcTile (tile, arg)
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))
{
/* Forward case is behind the triangle */
@ -553,9 +688,23 @@ drcTile (tile, arg)
deltay = -deltay;
/* Split side changes in the reverse case */
dinfo |= TT_SIDE;
newdinfo |= TT_SIDE;
}
/* The area to check is bounded between the diagonals of
* tile and errRect (which is the tile area, offset).
* Pass errRect and newdinfo to areaNMCheck using the
* ClientData structure arg->dCD_rlist and arg->dCD_entries,
* which are not used by areaNMCheck.
*/
arg->dCD_rlist = (Rect *)mallocMagic(sizeof(Rect));
*(arg->dCD_rlist) = errRect;
arg->dCD_entries = newdinfo;
if (newdinfo & TT_SIDE)
arg->dCD_entries &= ~TT_SIDE;
else
arg->dCD_entries |= TT_SIDE;
/* errRect is the tile area offset by (deltax, deltay) */
errRect.r_xbot += deltax;
errRect.r_ybot += deltay;
@ -563,12 +712,18 @@ drcTile (tile, arg)
errRect.r_ytop += deltay;
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);
arg->dCD_entries = 0;
freeMagic(arg->dCD_rlist);
arg->dCD_rlist = (Rect *)NULL;
}
DRCstatEdges++;
}
cptrcache = NULL;
/*
* Check design rules along a vertical boundary between two tiles.
*
@ -644,6 +799,44 @@ drcTile (tile, arg)
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
cptr = cptr->drcc_next)
{
/* Handle rule exceptions and exemptions */
if (cptr->drcc_exception != DRC_EXCEPTION_NONE)
{
PropertyRecord *proprec;
bool propfound, isinside = FALSE;
char *name;
int idx = cptr->drcc_exception & ~DRC_EXCEPTION_MASK;
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 & DRC_EXCEPTION_MASK) == 0))
continue;
if (isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) != 0))
continue;
}
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
/* the code above for non-Manhattan shapes and do not */
/* need to be processed again. */
@ -686,12 +879,23 @@ drcTile (tile, arg)
if (cptr->drcc_flags & DRC_REVERSE)
{
mrd = drcCanonicalMaxwidth(tpleft, GEO_WEST, arg, cptr);
mrd = drcCanonicalMaxwidth(tpleft, GEO_WEST, arg, cptr,
&mrdcache[0]);
triggered = 0;
}
else if (firsttile)
else
{
mrd = drcCanonicalMaxwidth(tile, GEO_EAST, arg, cptr);
if (cptrcache == NULL)
{
mrd = drcCanonicalMaxwidth(tile, GEO_EAST, arg, cptr,
&mrdcache[1]);
cptrcache = cptr;
}
else if (cptrcache != cptr)
mrd = drcCanonicalMaxwidth(tile, GEO_EAST, arg, cptr,
&mrdcache[2]);
else
mrd = mrdcache[1];
triggered = 0;
}
if (!trigpending || (DRCCurStyle->DRCFlags
@ -982,6 +1186,8 @@ drcTile (tile, arg)
}
}
cptrcache = NULL;
/*
* Check design rules along a horizontal boundary between two tiles.
*
@ -1053,6 +1259,44 @@ drcTile (tile, arg)
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
cptr = cptr->drcc_next)
{
/* Handle rule exceptions and exemptions */
if (cptr->drcc_exception != DRC_EXCEPTION_NONE)
{
PropertyRecord *proprec;
bool propfound, isinside = FALSE;
char *name;
int idx = cptr->drcc_exception & ~DRC_EXCEPTION_MASK;
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_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 & DRC_EXCEPTION_MASK) == 0))
continue;
if (isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) != 0))
continue;
}
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
/* the code above for non-Manhattan shapes and do not */
/* need to be processed again. */
@ -1090,12 +1334,23 @@ drcTile (tile, arg)
if (cptr->drcc_flags & DRC_REVERSE)
{
mrd = drcCanonicalMaxwidth(tpbot, GEO_SOUTH, arg, cptr);
mrd = drcCanonicalMaxwidth(tpbot, GEO_SOUTH, arg, cptr,
&mrdcache[0]);
triggered = 0;
}
else if (firsttile)
else
{
mrd = drcCanonicalMaxwidth(tile, GEO_NORTH, arg, cptr);
if (cptrcache == NULL)
{
mrd = drcCanonicalMaxwidth(tile, GEO_NORTH, arg, cptr,
&mrdcache[1]);
cptrcache = cptr;
}
else if (cptrcache != cptr)
mrd = drcCanonicalMaxwidth(tile, GEO_NORTH, arg, cptr,
&mrdcache[2]);
else
mrd = mrdcache[1];
triggered = 0;
}
if (!trigpending || (DRCCurStyle->DRCFlags
@ -1135,7 +1390,7 @@ drcTile (tile, arg)
lr = &mrd->rlist[i];
GeoClip(lr, arg->dCD_clip);
if (!GEO_RECTNULL(lr))
{
{
(*(arg->dCD_function)) (arg->dCD_celldef,
lr, cptr, arg->dCD_clientData);
(*(arg->dCD_errors))++;

View File

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

View File

@ -203,13 +203,12 @@ DRCCheckThis (celldef, operation, area)
/* Insert celldef into list of Defs waiting to be checked, unless */
/* it is already there. */
#if (0)
/* The switch to copying up DRC errors from non-interacting */
/* child cells means that the child cells must be processed */
/* first. So this routine changes from prepending the cell */
/* to the list to appending it. */
#if (0)
pback = &DRCPendingRoot;
p = DRCPendingRoot;
@ -230,8 +229,8 @@ DRCCheckThis (celldef, operation, area)
}
p->dpc_next = DRCPendingRoot;
DRCPendingRoot = p;
#endif
/* Append new cell to check to the pending list */
if (DRCPendingRoot == NULL)
{
@ -548,8 +547,10 @@ DRCContinuous()
if (DRCPendingRoot != (DRCPendingCookie *)NULL) {
DBReComputeBbox(DRCPendingRoot->dpc_def);
freeMagic((char *) DRCPendingRoot);
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, (char *) DRCPendingRoot);
DRCPendingRoot = DRCPendingRoot->dpc_next;
freeMagic1_end(&mm1);
}
/* Give the timestamp manager a chance to update any mismatches. */
@ -638,9 +639,10 @@ checkDone:
/* ARGSUSED */
int
drcCheckTile(tile, arg)
Tile * tile; /* tile in DRC_CHECK plane */
ClientData arg; /* Not used. */
drcCheckTile(tile, dinfo, arg)
Tile *tile; /* Tile in DRC_CHECK plane */
TileType dinfo; /* Split tile information (unused) */
ClientData arg; /* Not used. */
{
Rect square; /* Square area of the checkerboard
* being processed right now.
@ -766,13 +768,15 @@ drcCheckTile(tile, arg)
*/
int
drcXorFunc(tile)
drcXorFunc(tile, dinfo, clientdata)
Tile *tile;
TileType dinfo;
ClientData clientdata;
{
Rect area;
TiToRect(tile, &area);
DBPaintPlane(drcDisplayPlane, &area, drcXorTable, (PaintUndoInfo *) NULL);
DBNMPaintPlane(drcDisplayPlane, dinfo, &area, drcXorTable, (PaintUndoInfo *) NULL);
return 0;
}
@ -781,14 +785,15 @@ drcXorFunc(tile)
*/
int
drcPutBackFunc(tile, cellDef)
drcPutBackFunc(tile, dinfo, cellDef)
Tile *tile; /* Error tile, from drcTempPlane. */
TileType dinfo; /* Split tile information */
CellDef *cellDef; /* Celldef in which to paint error. */
{
Rect 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),
(PaintUndoInfo *) NULL);
return 0;
@ -815,8 +820,9 @@ drcPutBackFunc(tile, cellDef)
*/
int
drcIncludeArea(tile, rect)
drcIncludeArea(tile, dinfo, rect)
Tile *tile;
TileType dinfo; /* (unused) */
Rect *rect; /* Rectangle in which to record total area. */
{
Rect dum;

View File

@ -449,6 +449,32 @@ drcCheckRectSize(starttile, arg, cptr)
}
}
/*
*-------------------------------------------------------------------------
*
* MaxRectsExclude ---
*
* Trivial callback function which detects if a type is found
* overlapping a Maxrects area.
*
* Results:
* Always return 1 to immediately halt the search.
*
* Side effects:
* None.
*
*-------------------------------------------------------------------------
*/
int
MaxRectsExclude(
Tile *tile, /* (unused) */
TileType dinfo, /* (unused) */
ClientData clientdata) /* (unused) */
{
return 1;
}
/*
*-------------------------------------------------------------------------
*
@ -484,16 +510,17 @@ drcCheckRectSize(starttile, arg, cptr)
*/
MaxRectsData *
drcCanonicalMaxwidth(starttile, dir, arg, cptr)
drcCanonicalMaxwidth(starttile, dir, arg, cptr, mrdptr)
Tile *starttile;
int dir; /* direction of rule */
struct drcClientData *arg;
DRCCookie *cptr;
MaxRectsData **mrdptr;
{
int s, edgelimit;
Tile *tile,*tp;
TileTypeBitMask wrongtypes;
static MaxRectsData *mrd = (MaxRectsData *)NULL;
MaxRectsData *mrd = *mrdptr;
Rect *boundrect, boundorig;
/* Generate an initial array size of 8 for rlist and swap. */
@ -503,6 +530,7 @@ drcCanonicalMaxwidth(starttile, dir, arg, cptr)
mrd->rlist = (Rect *)mallocMagic(8 * sizeof(Rect));
mrd->swap = (Rect *)mallocMagic(8 * sizeof(Rect));
mrd->listdepth = 8;
*mrdptr = mrd;
}
if (starttile == NULL) return mrd;
@ -563,10 +591,31 @@ drcCanonicalMaxwidth(starttile, dir, arg, cptr)
mrd->maxdist = edgelimit;
TTMaskCom2(&wrongtypes, &cptr->drcc_mask);
boundorig = *boundrect;
DBSrPaintArea(starttile, arg->dCD_celldef->cd_planes[cptr->drcc_plane],
DBSrPaintArea(starttile, arg->dCD_celldef->cd_planes[cptr->drcc_edgeplane],
&boundorig, &wrongtypes, FindMaxRects, mrd);
if (mrd->entries == 0)
return NULL;
else if (cptr->drcc_plane != cptr->drcc_edgeplane)
{
/* If the "exclude" option is used, then the maxrect rule will be
* ignored for any metal area partially or totally covered by any
* type in cptr->drcc_corner on plane cptr->drcc_plane (!=
* cptr->drcc_edgeplane).
*/
for (s = 0; s < mrd->entries; s++)
{
Rect *r = &(mrd->rlist[s]);
if (DBSrPaintArea((Tile *)NULL,
arg->dCD_celldef->cd_planes[cptr->drcc_plane],
r, &cptr->drcc_corner, MaxRectsExclude, NULL) != 0)
{
/* Take this area out of consideration */
r->r_xtop = r->r_xbot;
r->r_ytop = r->r_ybot;
}
}
return (MaxRectsData *)mrd;
}
else
return (MaxRectsData *)mrd;
}

View File

@ -184,9 +184,9 @@ drcSubstitute (cptr)
DRCCookie * cptr; /* Design rule violated */
{
static char *why_out = NULL;
char *whyptr, *sptr, *wptr;
int subscnt = 0, whylen;
float oscale, value;
char *whyptr, *sptr, *wptr, *vptr;
int subscnt = 0, whylen, saveunits;
float value;
extern float CIFGetOutputScale();
whyptr = DRCCurStyle->DRCWhyList[cptr->drcc_tag];
@ -203,10 +203,14 @@ drcSubstitute (cptr)
why_out = (char *)mallocMagic(whylen * sizeof(char));
strcpy(why_out, whyptr);
if (cptr->drcc_flags & DRC_CIFRULE)
oscale = CIFGetScale(100); /* 100 = microns to centimicrons */
else
oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */
/* For backwards compatibility: If the units are set to "default",
* then print the DRC value in microns, with units, which is how
* the output was previously presented.
*/
saveunits = DBWUnits;
if (saveunits == DBW_UNITS_DEFAULT)
DBWUnits = DBW_UNITS_MICRONS | DBW_UNITS_PRINT_FLAG;
wptr = why_out;
while ((sptr = strchr(whyptr, '%')) != NULL)
@ -218,21 +222,29 @@ drcSubstitute (cptr)
switch (*(sptr + 1))
{
case 'd':
/* Replace with "dist" value in microns */
value = (float)cptr->drcc_dist * oscale;
snprintf(wptr, 20, "%01.3gum", value);
if (cptr->drcc_flags & DRC_CIFRULE)
vptr = DBWPrintCIFValue(cptr->drcc_dist, (MagWindow *)NULL, TRUE);
else
vptr = DBWPrintValue(cptr->drcc_dist, (MagWindow *)NULL, TRUE);
snprintf(wptr, 20, "%s", vptr);
wptr += strlen(wptr);
break;
case 'c':
/* Replace with "cdist" value in microns */
value = (float)cptr->drcc_cdist * oscale;
snprintf(wptr, 20, "%01.3gum", value);
if (cptr->drcc_flags & DRC_CIFRULE)
vptr = DBWPrintCIFValue(cptr->drcc_cdist, (MagWindow *)NULL, TRUE);
else
vptr = DBWPrintValue(cptr->drcc_cdist, (MagWindow *)NULL, TRUE);
snprintf(wptr, 20, "%s", vptr);
wptr += strlen(wptr);
break;
case 'a':
/* Replace with "cdist" value in microns squared */
value = (float)cptr->drcc_cdist * oscale * oscale;
snprintf(wptr, 20, "%01.4gum^2", value);
if (cptr->drcc_flags & DRC_CIFRULE)
vptr = DBWPrintCIFSqValue(cptr->drcc_cdist, (MagWindow *)NULL);
else
vptr = DBWPrintSqValue(cptr->drcc_cdist, (MagWindow *)NULL);
snprintf(wptr, 20, "%s", vptr);
wptr += strlen(wptr);
break;
default:
@ -245,6 +257,7 @@ drcSubstitute (cptr)
/* copy remainder of string (including trailing null) */
strncpy(wptr, whyptr, strlen(whyptr) + 1);
DBWUnits = saveunits;
return why_out;
}
@ -277,20 +290,50 @@ drcPrintError (celldef, rect, cptr, scx)
{
HashEntry *h;
int i;
Rect *area, r;
Rect *area;
int drcsave = DRCErrorCount;
/* Forward declaration */
void drcWhyFunc(SearchContext *scx, ClientData cdarg);
ASSERT (cptr != (DRCCookie *) NULL, "drcPrintError");
area = &scx->scx_area;
if ((area != NULL) && (!GEO_OVERLAP(area, rect))) return;
i = DRCErrorList[cptr->drcc_tag];
if (i == 0)
TxPrintf("%s\n", drcSubstitute(cptr));
if (i >= 0)
if (cptr->drcc_tag == DRC_IN_SUBCELL_TAG)
{
DRCErrorCount += 1;
DRCErrorList[cptr->drcc_tag] = i + 1;
SearchContext newscx;
/* Recurse into subcells to find the error being flagged */
/* recursive call is drcWhyFunc, clientdata is FALSE */
newscx.scx_area = *rect;
newscx.scx_use = scx->scx_use;
newscx.scx_x = scx->scx_use->cu_xlo;
newscx.scx_y = scx->scx_use->cu_ylo;
newscx.scx_trans = scx->scx_trans;
DBTreeSrCells(&newscx, 0, drcWhyFunc, (ClientData)FALSE);
}
/* Hack to avoid printing "no errors found" when recursing on
* drcWhyFunc() above. In some cases like run-length rules,
* changing the search area can make the error disappear. If
* that happens, "See error definition in subcell" will be
* printed. The underlying error needs to be fixed, but this
* method provides the information the user needs to find the
* error.
*/
if (drcsave == DRCErrorCount)
{
i = DRCErrorList[cptr->drcc_tag];
if (i == 0)
TxPrintf("%s\n", drcSubstitute(cptr));
if (i >= 0)
{
DRCErrorCount += 1;
DRCErrorList[cptr->drcc_tag] = i + 1;
}
}
}
@ -309,24 +352,47 @@ drcListError (celldef, rect, cptr, scx)
HashEntry *h;
int i;
Rect *area;
int drcsave = DRCErrorCount;
/* Forward declaration */
void drcWhyFunc(SearchContext *scx, ClientData cdarg);
ASSERT (cptr != (DRCCookie *) NULL, "drcListError");
area = &scx->scx_area;
if ((area != NULL) && (!GEO_OVERLAP(area, rect))) return;
i = DRCErrorList[cptr->drcc_tag];
if (i == 0)
if (cptr->drcc_tag == DRC_IN_SUBCELL_TAG)
{
Tcl_Obj *lobj;
lobj = Tcl_GetObjResult(magicinterp);
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(drcSubstitute(cptr), -1));
Tcl_SetObjResult(magicinterp, lobj);
SearchContext newscx;
/* Recurse into subcells to find the error being flagged */
/* recursive call is drcWhyFunc, clientdata is TRUE */
newscx.scx_area = *rect;
newscx.scx_use = scx->scx_use;
newscx.scx_x = scx->scx_use->cu_xlo;
newscx.scx_y = scx->scx_use->cu_ylo;
newscx.scx_trans = scx->scx_trans;
DBTreeSrCells(&newscx, 0, drcWhyFunc, (ClientData)TRUE);
}
if (i >= 0)
if (drcsave == DRCErrorCount)
{
DRCErrorCount += 1;
DRCErrorList[cptr->drcc_tag] = i + 1;
i = DRCErrorList[cptr->drcc_tag];
if (i == 0)
{
Tcl_Obj *lobj;
lobj = Tcl_GetObjResult(magicinterp);
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(drcSubstitute(cptr), -1));
Tcl_SetObjResult(magicinterp, lobj);
}
if (i >= 0)
{
DRCErrorCount += 1;
DRCErrorList[cptr->drcc_tag] = i + 1;
}
}
}
@ -343,6 +409,10 @@ drcListallError (celldef, rect, cptr, scx)
Tcl_Obj *lobj, *pobj;
HashEntry *h;
Rect *area, r;
int drcsave = DRCErrorCount;
/* Forward declaration */
int drcWhyAllFunc(SearchContext *scx, ClientData cdarg);
ASSERT (cptr != (DRCCookie *) NULL, "drcListallError");
@ -350,21 +420,47 @@ drcListallError (celldef, rect, cptr, scx)
GeoTransRect(&scx->scx_trans, rect, &r);
area = &scx->scx_area;
if ((area != NULL) && (!GEO_OVERLAP(area, rect))) return;
DRCErrorCount += 1;
h = HashFind(&DRCErrorTable, drcSubstitute(cptr));
lobj = (Tcl_Obj *) HashGetValue(h);
if (lobj == NULL)
lobj = Tcl_NewListObj(0, NULL);
pobj = Tcl_NewListObj(0, NULL);
if (cptr->drcc_tag == DRC_IN_SUBCELL_TAG)
{
SearchContext newscx;
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_xbot));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_ybot));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_xtop));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_ytop));
Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
/* Recurse into subcells to find the error being flagged */
/* recursive call is drcWhyAllFunc, clientdata is NULL */
newscx.scx_area = *rect;
newscx.scx_use = scx->scx_use;
newscx.scx_x = scx->scx_use->cu_xlo;
newscx.scx_y = scx->scx_use->cu_ylo;
newscx.scx_trans = scx->scx_trans;
HashSetValue(h, lobj);
DBTreeSrCells(&newscx, 0, drcWhyAllFunc, (ClientData)NULL);
}
if (drcsave == DRCErrorCount)
{
char *rllx, *rlly, *rurx, *rury;
DRCErrorCount += 1;
h = HashFind(&DRCErrorTable, drcSubstitute(cptr));
lobj = (Tcl_Obj *) HashGetValue(h);
if (lobj == NULL)
lobj = Tcl_NewListObj(0, NULL);
pobj = Tcl_NewListObj(0, NULL);
rllx = DBWPrintValue(r.r_xbot, (MagWindow *)NULL, TRUE);
rlly = DBWPrintValue(r.r_ybot, (MagWindow *)NULL, FALSE);
rurx = DBWPrintValue(r.r_xtop, (MagWindow *)NULL, TRUE);
rury = DBWPrintValue(r.r_ytop, (MagWindow *)NULL, FALSE);
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(rllx, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(rlly, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(rurx, -1));
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(rury, -1));
Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
HashSetValue(h, lobj);
}
}
#else
@ -737,11 +833,12 @@ drcCheckFunc(scx, cdarg)
DBStdPaintTbl(TT_CHECKPAINT, PL_DRC_CHECK),
(PaintUndoInfo *) NULL);
DRCCheckThis(def, TT_CHECKPAINT, (Rect *) NULL);
/* Search children */
/* Search children and apply recursively */
(void) DBCellSrArea(scx, drcCheckFunc, (ClientData) NULL);
/* Then do self */
DRCCheckThis(def, TT_CHECKPAINT, (Rect *) NULL);
/* As a special performance hack, if the complete cell area is
* handled here, don't bother to look at any more array elements.
*/
@ -880,9 +977,10 @@ drcCountFunc(scx, dupTable)
}
int
drcCountFunc2(tile, countptr)
Tile *tile; /* Tile found in error plane. */
int *countptr; /* Address of count word. */
drcCountFunc2(tile, dinfo, countptr)
Tile *tile; /* Tile found in error plane. */
TileType dinfo; /* Split tile information (unused) */
int *countptr; /* Address of count word. */
{
if (TiGetType(tile) != (TileType) TT_SPACE) (*countptr)++;
return 0;
@ -1029,8 +1127,9 @@ drcFindFunc(scx, finddata)
}
int
drcFindFunc2(tile, finddata)
drcFindFunc2(tile, dinfo, finddata)
Tile *tile; /* Tile in error plane. */
TileType dinfo; /* Split tile information (unused) */
Sindx *finddata; /* Information about error to find */
{

View File

@ -32,7 +32,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "drc/drc.h"
extern char *maskToPrint();
extern char *DBTypeShortName();
extern const char *DBTypeShortName(TileType type);
/*
* ----------------------------------------------------------------------------

View File

@ -27,6 +27,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/magic.h"
#include "textio/textio.h"
#include "utils/malloc.h"
#include "utils/signals.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
@ -36,18 +38,12 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "commands/commands.h"
#include "utils/undo.h"
/* The variables below are made owns so that they can be used to
/* The variables below are made global so that they can be used to
* pass information to the various search functions.
*/
static Rect drcSubIntArea; /* Accumulates area of interactions. */
static CellDef *drcSubDef; /* Cell definition we're checking. */
static int drcSubRadius; /* Interaction radius. */
static CellUse *drcCurSub; /* Holds current use while searching for interactions */
static Rect drcSubLookArea; /* Area where we're looking for interactions */
static void (*drcSubFunc)(); /* Error function. */
static ClientData drcSubClientData;
/* To be passed to error function. */
static void (*drcSubFunc)(); /* Error function. */
static ClientData drcSubClientData; /* To be passed to error function. */
/* The cookie below is dummied up to provide an error message for
* errors that occur because of inexact overlaps between subcells.
@ -56,7 +52,7 @@ static ClientData drcSubClientData;
static DRCCookie drcSubcellCookie = {
0, 0, 0, 0,
{ {0} }, { {0} },
0, 0, 0,
0, DRC_EXCEPTION_NONE, 0, 0,
DRC_SUBCELL_OVERLAP_TAG,
(DRCCookie *) NULL
};
@ -69,7 +65,7 @@ static DRCCookie drcSubcellCookie = {
static DRCCookie drcInSubCookie = {
0, 0, 0, 0,
{ {0} }, { {0} },
0, 0, 0,
0, DRC_EXCEPTION_NONE, 0, 0,
DRC_IN_SUBCELL_TAG,
(DRCCookie *) NULL
};
@ -83,7 +79,7 @@ static DRCCookie drcInSubCookie = {
static DRCCookie drcOffGridCookie = {
0, 0, 0, 0,
{ {0} }, { {0} },
0, 0, 0,
0, DRC_EXCEPTION_NONE, 0, 0,
DRC_OFFGRID_TAG,
(DRCCookie *) NULL
};
@ -91,6 +87,28 @@ static DRCCookie drcOffGridCookie = {
extern int DRCErrorType;
extern CellDef *DRCErrorDef;
/* Structure used to hold information about child uses found in the
* search area during DRCFindInteractions(), so these can be
* subsequently searched for sibling interactions.
*/
struct drcLinkedUse {
CellUse *dlu_use; // Use being checked
Rect dlu_area; // Area of use to check (w/halo)
struct drcLinkedUse *dlu_next; // For linked list
};
/* Structure used to pass information to and from drcSubcellFunc() */
struct drcSubcellArg {
CellDef *dsa_def; /* Cell use being checked */
int dsa_radius; /* Halo radius around area to check */
Rect *dsa_searchArea; /* Area of cell use being searched */
Rect *dsa_intArea; /* Total interaction area */
bool dsa_found; /* At least one interacting cell was found */
struct drcLinkedUse *dsa_dlu;
};
/*
* ----------------------------------------------------------------------------
*
@ -112,12 +130,12 @@ extern CellDef *DRCErrorDef;
*/
int
drcFindOtherCells(use, area)
drcFindOtherCells(use, dlu)
CellUse *use;
Rect *area;
struct drcLinkedUse *dlu;
{
if (use != drcCurSub)
GeoInclude(&use->cu_bbox, area);
if (use != dlu->dlu_use)
GeoInclude(&use->cu_bbox, &dlu->dlu_area);
return 0;
}
@ -134,14 +152,15 @@ drcFindOtherCells(use, area)
* different for "drc why" commands than for "drc check".
*
* Returns:
* 0 to keep the search going.
* 0 to keep the search going. In case of an interrupt, return 1.
*
* ----------------------------------------------------------------------------
*/
int
drcSubCopyErrors(tile, cxp)
drcSubCopyErrors(tile, dinfo, cxp)
Tile *tile;
TileType dinfo; /* (unused) */
TreeContext *cxp;
{
Rect area;
@ -156,6 +175,9 @@ drcSubCopyErrors(tile, cxp)
arg->dCD_clientData);
(*(arg->dCD_errors))++;
/* Allow a break here */
if (SigInterruptPending) return 1;
return 0;
}
@ -224,68 +246,56 @@ drcSubCopyFunc(scx, cdarg)
*/
int
drcSubcellFunc(subUse, flags)
CellUse *subUse; /* Subcell instance. */
int *flags; /* Information to propagate up */
drcSubcellFunc(subUse, dsa)
CellUse *subUse; /* Subcell instance found in area. */
struct drcSubcellArg *dsa; /* Information needed for funtion and to pass
* back to the caller.
*/
{
Rect area, haloArea, intArea, subIntArea, locIntArea;
Rect area, haloArea, intArea;
int i;
/* A subcell has been seen, so set the "cell found" flag */
*flags |= CELLFOUND_FLAG;
/* Record that a subcell has been seen in the search area. */
dsa->dsa_found = TRUE;
/* To determine interactions, find the bounding box of
* all paint and other subcells within one halo of this
* subcell (and also within the original area where
* we're recomputing errors).
*/
area = subUse->cu_bbox;
GEO_EXPAND(&area, drcSubRadius, &haloArea);
GeoClip(&haloArea, &drcSubLookArea);
GEO_EXPAND(&area, dsa->dsa_radius, &haloArea);
GeoClip(&haloArea, dsa->dsa_searchArea);
intArea = GeoNullRect;
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
{
(void) DBSrPaintArea((Tile *) NULL, drcSubDef->cd_planes[i],
&haloArea, &DBAllButSpaceBits, drcIncludeArea,
(ClientData) &intArea);
(void) DBSrPaintArea((Tile *) NULL, dsa->dsa_def->cd_planes[i],
&haloArea, &DBAllButSpaceBits, drcIncludeArea,
(ClientData) &intArea);
}
/* DRC error tiles in a subcell are automatically pulled into the */
/* interaction area of the parent. Ultimately this is recursive as */
/* all cells are checked and errors propagate to the top level. */
/* To check sibling interactions, DBSrCellPlaneArea() must not be
* called from within itself, so save the information about this
* cell and its area in a linked list. If haloArea is already
* inside intArea, then do nothing.
*/
subIntArea = GeoNullRect;
#if (0)
/* NOTE: DRC errors inside a subcell should be ignored for */
/* the purpose of finding interactions. Errors should only */
/* be copied up into the parent when in a non-interaction */
/* area. This is done below in DRCFindInteractions(). */
/* (Method added by Tim, 10/15/2020) */
/* Maybe S and PS errors should be pulled here? */
DBSrPaintArea((Tile *) NULL, subUse->cu_def->cd_planes[PL_DRC_ERROR],
&TiPlaneRect, &DBAllButSpaceBits, drcIncludeArea,
(ClientData) &subIntArea);
GeoTransRect(&(subUse->cu_transform), &subIntArea, &locIntArea);
GeoInclude(&locIntArea, &intArea);
#endif
if (!GEO_RECTNULL(&subIntArea)) *flags |= PROPAGATE_FLAG;
drcCurSub = subUse;
(void) DBSrCellPlaneArea(drcSubDef->cd_cellPlane, &haloArea,
drcFindOtherCells, (ClientData)(&intArea));
if (!GEO_SURROUND(&intArea, &haloArea))
{
struct drcLinkedUse *newdlu;
newdlu = (struct drcLinkedUse *)mallocMagic(sizeof(struct drcLinkedUse));
newdlu->dlu_use = subUse;
newdlu->dlu_area = haloArea;
newdlu->dlu_next = dsa->dsa_dlu;
dsa->dsa_dlu = newdlu;
}
if (GEO_RECTNULL(&intArea)) return 0;
GEO_EXPAND(&intArea, drcSubRadius, &intArea);
GEO_EXPAND(&intArea, dsa->dsa_radius, &intArea);
GeoClip(&intArea, &haloArea);
(void) GeoInclude(&intArea, &drcSubIntArea);
(void) GeoInclude(&intArea, dsa->dsa_intArea);
return 0;
}
@ -308,7 +318,9 @@ drcSubcellFunc(subUse, flags)
*/
int
drcAlwaysOne()
drcAlwaysOne(Tile *tile,
TileType dinfo,
ClientData clientdata)
{
return 1;
}
@ -409,10 +421,10 @@ DRCFindInteractions(def, area, radius, interaction)
int i;
CellUse *use;
SearchContext scx;
int flags;
Rect searchArea, intArea;
struct drcSubcellArg dsa;
struct drcLinkedUse *curDLU;
drcSubDef = def;
drcSubRadius = radius;
DRCDummyUse->cu_def = def;
/* Find all the interactions in the area and compute the
@ -422,47 +434,85 @@ DRCFindInteractions(def, area, radius, interaction)
* each cell has material everywhere within its bounding box.
*/
drcSubIntArea = GeoNullRect;
GEO_EXPAND(area, radius, &drcSubLookArea);
flags = 0;
(void) DBSrCellPlaneArea(def->cd_cellPlane, &drcSubLookArea,
drcSubcellFunc, (ClientData)(&flags));
GEO_EXPAND(area, radius, &searchArea);
intArea = GeoNullRect;
/* Copy drcSubLookArea to a local Rect structure because it
* gets modified by drcSubcellFunc().
*/
dsa.dsa_def = def;
dsa.dsa_radius = radius;
dsa.dsa_searchArea = &searchArea;
dsa.dsa_intArea = &intArea;
dsa.dsa_found = FALSE;
dsa.dsa_dlu = (struct drcLinkedUse *)NULL;
(void) DBSrCellPlaneArea(def->cd_cellPlane, &searchArea,
drcSubcellFunc, (ClientData)&dsa);
/* If no subcells were in the search area, there is nothing
* more to do.
*/
if (dsa.dsa_found == FALSE) return -1;
/* If drcSubcellFunc() returned a list of uses, then check
* the area of each use for interacting sibling uses, and
* add the overlap to the potential interaction area.
*/
curDLU = dsa.dsa_dlu;
while (curDLU != NULL)
{
Rect subIntArea, subSearchArea;
struct drcLinkedUse *nextdlu = curDLU->dlu_next;
subSearchArea = curDLU->dlu_area;
curDLU->dlu_area = GeoNullRect;
(void) DBSrCellPlaneArea(def->cd_cellPlane, &subSearchArea,
drcFindOtherCells, (ClientData)curDLU);
/* Re-clip interaction area to subcell halo area */
GEO_EXPAND(&curDLU->dlu_area, radius, &curDLU->dlu_area);
GeoClip(&curDLU->dlu_area, &subSearchArea);
(void) GeoInclude(&curDLU->dlu_area, &intArea);
/* Free entry and move to next entry in linked list */
freeMagic((char *)curDLU);
curDLU = nextdlu;
}
/* If there seems to be an interaction area, make a second pass
* to make sure there's more than one cell with paint in the
* area. This will save us a lot of work where two cells
* have overlapping bounding boxes without overlapping paint.
*/
if (!(flags & CELLFOUND_FLAG)) return -1;
if (GEO_RECTNULL(&drcSubIntArea)) return 0;
if (GEO_RECTNULL(&intArea)) return 0;
use = NULL;
/* If errors are being propagated up from child to parent, */
/* 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],
&drcSubIntArea, &DBAllButSpaceBits, drcAlwaysOne,
(ClientData) NULL) != 0)
{
use = (CellUse *) -1;
break;
}
use = (CellUse *) -1;
break;
}
scx.scx_use = DRCDummyUse;
scx.scx_trans = GeoIdentityTransform;
scx.scx_area = drcSubIntArea;
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. */
*interaction = drcSubIntArea;
*interaction = intArea;
GeoClip(interaction, area);
if (GEO_RECTNULL(interaction)) return 0;
return 1;
@ -489,8 +539,9 @@ DRCFindInteractions(def, area, radius, interaction)
*/
int
drcExactOverlapCheck(tile, arg)
drcExactOverlapCheck(tile, dinfo, arg)
Tile *tile; /* Tile to check. */
TileType dinfo; /* Split tile information (unused) */
struct drcClientData *arg; /* How to detect and process errors. */
{
Rect rect;
@ -528,8 +579,9 @@ drcExactOverlapCheck(tile, arg)
*/
int
drcExactOverlapTile(tile, cxp)
drcExactOverlapTile(tile, dinfo, cxp)
Tile *tile; /* Tile that must overlap exactly. */
TileType dinfo; /* Split tile information (unused) */
TreeContext *cxp; /* Tells how to translate out of subcell.
* The client data must be a drcClientData
* record, and the caller must have filled
@ -734,9 +786,9 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
* square separately.
*/
x = (area->r_xbot/DRCStepSize) * DRCStepSize;
x = (area->r_xbot/DRCStepSize) * DRCStepSize - (DRCStepSize / 2);
if (x > area->r_xbot) x -= DRCStepSize;
y = (area->r_ybot/DRCStepSize) * DRCStepSize;
y = (area->r_ybot/DRCStepSize) * DRCStepSize - (DRCStepSize / 2);
if (y > area->r_ybot) y -= DRCStepSize;
for (square.r_xbot = x; square.r_xbot < area->r_xtop;
square.r_xbot += DRCStepSize)
@ -774,6 +826,7 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg)
*/
subArea = *erasebox;
GeoClip(&subArea, &cliparea);
if (GEO_RECTNULL(&subArea)) continue;
GEO_EXPAND(&subArea, DRCTechHalo, &intArea);
errorSaveType = DRCErrorType;

View File

@ -72,6 +72,12 @@ static int drcRulesOptimized = 0;
static int DRCtag = 0;
/* Keep track of what rule exemption or exception is in effect
* while reading the DRC tech file section.
*/
static unsigned char drcCurException = DRC_EXCEPTION_NONE;
/*
* Forward declarations.
*/
@ -79,6 +85,7 @@ int drcWidth(), drcSpacing(), drcEdge(), drcNoOverlap();
int drcExactOverlap(), drcExtend();
int drcSurround(), drcRectOnly(), drcOverhang();
int drcStepSize(), drcOption(), drcOffGrid();
int drcException(), drcExemption();
int drcMaxwidth(), drcArea(), drcRectangle(), drcAngles();
int drcCifSetStyle(), drcCifWidth(), drcCifSpacing();
int drcCifMaxwidth(), drcCifArea();
@ -301,6 +308,12 @@ drcTechFreeStyle()
/* Clear the Why string list */
freeMagic(DRCCurStyle->DRCWhyList);
/* Clear the exception list */
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
freeMagic(DRCCurStyle->DRCExceptionList[i]);
if (DRCCurStyle->DRCExceptionList != (char **)NULL)
freeMagic(DRCCurStyle->DRCExceptionList);
freeMagic(DRCCurStyle);
DRCCurStyle = NULL;
}
@ -384,6 +397,63 @@ drcWhyCreate(whystring)
return DRCCurStyle->DRCWhySize;
}
/*
* ----------------------------------------------------------------------------
* drcExceptionCreate --
*
* Create an entry for a DRC rule exception/exemption type, if it does
* not already exist.
*
* Results:
* The index of the exception (which is an unsigned character containing
* the index in the lower 7 bits and a high bit indicating if the rule
* is an exception (0) or an exemption (1)).
*
* Side effects:
* Adds to the DRCExceptionList if "name" has not been used before.
* Calls StrDup() and increments DRCExceptionSize.
*
* ----------------------------------------------------------------------------
*/
unsigned 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 (unsigned char)i;
/* Note that i cannot be 127 as this is reserved for DRC_EXCEPTION_NONE */
if (i > 126)
{
/* I would be shocked if this code ever got executed. */
TxError("Error: Too many rule exceptions! Limit is 126.\n");
return 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 (unsigned char)i;
}
/*
* ----------------------------------------------------------------------------
*
@ -522,11 +592,13 @@ DRCTechInit()
drcTechFreeStyle();
free_magic1_t mm1 = freeMagic1_init();
for (style = DRCStyleList; style != NULL; style = style->ds_next)
{
freeMagic(style->ds_name);
freeMagic(style);
freeMagic1(&mm1, style);
}
freeMagic1_end(&mm1);
DRCStyleList = NULL;
}
@ -569,6 +641,8 @@ DRCTechStyleInit()
DRCCurStyle->DRCStepSize = 0;
DRCCurStyle->DRCFlags = (char)0;
DRCCurStyle->DRCWhySize = 0;
DRCCurStyle->DRCExceptionList = (char **)NULL;
DRCCurStyle->DRCExceptionSize = 0;
HashInit(&DRCWhyErrorTable, 16, HT_STRINGKEYS);
@ -661,6 +735,7 @@ DRCTechStyleInit()
}
drcCifInit();
drcCurException = DRC_EXCEPTION_NONE;
}
/*
@ -953,6 +1028,7 @@ drcCifAssign(cookie, dist, next, mask, corner, tag, cdist, flags, planeto, plane
(cookie)->drcc_plane = planeto;
(cookie)->drcc_mod = 0;
(cookie)->drcc_cmod = 0;
(cookie)->drcc_exception = drcCurException;
}
// This is like drcCifAssign, but checks for bad plane numbers in planeto and
@ -1029,50 +1105,37 @@ DRCTechAddRule(sectionName, argc, argv)
int (*rk_proc)(); /* Procedure implementing this keyword */
const char *rk_err; /* Error message */
} ruleKeys[] = {
{"angles", 4, 4, drcAngles,
"layers 45|90 why"},
{"angles", 4, 4, drcAngles, "layers 45|90 why"},
{"edge", 8, 10, drcEdge,
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
{"edge4way", 8, 10, drcEdge,
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
{"exact_overlap", 2, 2, drcExactOverlap,
"layers"},
{"exact_overlap", 2, 2, drcExactOverlap, "layers"},
{"exception", 2, 2, drcException, "name"},
{"exemption", 2, 2, drcExemption, "name"},
{"extend", 5, 6, drcExtend,
"layers1 layers2 distance [option] why"},
{"no_overlap", 3, 3, drcNoOverlap,
"layers1 layers2"},
{"option", 2, 2, drcOption,
"option_name option_value"},
{"overhang", 5, 5, drcOverhang,
"layers1 layers2 distance why"},
{"rect_only", 3, 3, drcRectOnly,
"layers why"},
{"no_overlap", 3, 3, drcNoOverlap, "layers1 layers2"},
{"option", 2, 2, drcOption, "option_name option_value"},
{"overhang", 5, 5, drcOverhang, "layers1 layers2 distance why"},
{"rect_only", 3, 3, drcRectOnly, "layers why"},
{"spacing", 6, 7, drcSpacing,
"layers1 layers2 separation [layers3] adjacency why"},
{"stepsize", 2, 2, drcStepSize,
"step_size"},
{"stepsize", 2, 2, drcStepSize, "step_size"},
{"surround", 6, 7, drcSurround,
"layers1 layers2 distance presence why"},
{"width", 4, 5, drcWidth,
"layers width why"},
{"width", 4, 5, drcWidth, "layers width why"},
{"widespacing", 7, 8, drcSpacing,
"layers1 width layers2 separation adjacency why"},
{"area", 5, 5, drcArea,
"layers area horizon why"},
{"off_grid", 4, 4, drcOffGrid,
"layers pitch why"},
{"maxwidth", 4, 5, drcMaxwidth,
"layers maxwidth bends why"},
{"cifstyle", 2, 2, drcCifSetStyle,
"cif_style"},
{"cifwidth", 4, 4, drcCifWidth,
"layers width why"},
{"area", 5, 5, drcArea, "layers area horizon why"},
{"off_grid", 4, 4, drcOffGrid, "layers pitch why"},
{"maxwidth", 4, 6, drcMaxwidth, "layers maxwidth bends why"},
{"cifstyle", 2, 2, drcCifSetStyle, "cif_style"},
{"cifwidth", 4, 4, drcCifWidth, "layers width why"},
{"cifspacing", 6, 6, drcCifSpacing,
"layers1 layers2 separation adjacency why"},
{"cifarea", 5, 5, drcCifArea,
"layers area horizon why"},
{"cifmaxwidth", 5, 5, drcCifMaxwidth,
"layers maxwidth bends why"},
{"cifarea", 5, 5, drcCifArea, "layers area horizon why"},
{"cifmaxwidth", 5, 5, drcCifMaxwidth, "layers maxwidth bends why"},
{"rectangle", 5, 5, drcRectangle,
"layers maxwidth [even|odd|any] why"},
{0}
@ -1582,7 +1645,7 @@ drcOffGrid(argc, argv)
* Process a maxwidth rule.
* This is of the form:
*
* maxwidth layers distance [bends] why
* maxwidth layers distance [bends] [exclude_layers] why
*
* This routine was updated 3/6/05 to match the "canonical" definition of
* a maxwidth region, which is any rectangle containing <layers> that is
@ -1591,6 +1654,11 @@ drcOffGrid(argc, argv)
* (see below) for backwards-compatibility. Otherwise ("bend_ok" or
* nothing), the new routine is used.
*
* exclude_layers is optional and indicates a type or types (which if more
* than one must all be on the same plane) that prevent "maxwidth" from
* being checked. A common use case is using "glass" (passivation cut) to
* exclude top metal on a pad from being checked for maximum metal width.
*
* maxwidth metal1 389 "metal1 width > 35um must be slotted"
* maxwidth pmc 4 bend_illegal "poly contact area must be no wider than 4"
* maxwidth trench 4 bend_ok "trench width must be exactly 4"
@ -1629,11 +1697,11 @@ drcMaxwidth(argc, argv)
int distance = atoi(argv[2]);
char *bends = argv[3];
int why;
TileTypeBitMask set, setC;
TileTypeBitMask set, setC, setE;
DRCCookie *dp, *dpnew;
TileType i, j;
PlaneMask pmask, ptest, pset;
int plane;
PlaneMask pmask, pmask2, ptest, pset;
int plane, plane2;
int bend;
ptest = DBTechNoisyNameMask(layers, &set);
@ -1667,8 +1735,34 @@ drcMaxwidth(argc, argv)
TechError("unknown bend option %s\n",bends);
return (0);
}
why = drcWhyCreate(argv[4]);
if (argc == 6)
why = drcWhyCreate(argv[5]);
else
why = drcWhyCreate(argv[4]);
}
if (argc == 6)
{
ptest = DBTechNoisyNameMask(argv[4], &setE);
pmask2 = CoincidentPlanes(&setE, ptest);
if (pmask2 == 0)
{
TechError("All layers for \"maxwidth\" exclude types must "
"be on same plane.\n");
return (0);
}
else
{
for (plane2 = PL_TECHDEPBASE; plane2 < DBNumPlanes; plane2++)
if (PlaneMaskHasPlane(pmask2, plane2))
break;
if (PlaneMaskHasPlane(pmask, plane2))
TechError("Warning: Exclude types for \"maxwidth\" are on the "
"same plane and so cannot be checked.\n");
}
}
else
plane2 = -1;
for (i = 0; i < DBNumTypes; i++)
{
@ -1689,8 +1783,12 @@ drcMaxwidth(argc, argv)
/* find bucket preceding the new one we wish to insert */
dp = drcFindBucket(i, j, distance);
dpnew = (DRCCookie *) mallocMagic(sizeof (DRCCookie));
drcAssign(dpnew, distance, dp->drcc_next, &set, &set, why,
if (plane2 == -1)
drcAssign(dpnew, distance, dp->drcc_next, &set, &set, why,
distance, DRC_MAXWIDTH | bend, plane, plane);
else
drcAssign(dpnew, distance, dp->drcc_next, &set, &setE, why,
distance, DRC_MAXWIDTH | bend, plane2, plane);
dp->drcc_next = dpnew;
}
@ -3597,6 +3695,84 @@ drcRectangle(argc, argv)
return maxwidth;
}
/*
* ----------------------------------------------------------------------------
*
* drcException, drcExemption --
*
* Process a DRC exception declaration
* This is of the form:
*
* exception exception_name|none
* or
* exemption exemption_name|none
*
* e.g,
*
* exception SRAM
* exemption SRAM
*
* The exception_name or exemption_name is the suffix part of a MASKHINTS_*
* property name; e.g., the name SRAM corresponds to a property called
* MASKHINTS_SRAM. This declaration is followed by a block of DRC rules
* that are subject to the exception or the exemption. An exception is the
* opposite of an exemption: If a rule is excepted, then the rule applies
* within areas delineated by bounding boxes defined by the
* MASKHINTS_<exception_name> property. If a rule is exempted, then the
* rule applies only outside of areas delineated by bounding boxes defined
* by the MASKHINTS_<exemption_name> property. The block of rules subject
* to the exemption or exception ends with another exception or exemption
* declaration. If the following rules are not to be excepted or exempted
* at all, then use "exception none" or "exemption none".
*
* Results:
* Returns 0.
*
* Side effects:
* Updates drcCurException. drcCurException contains the index in
* the lower 7 bits, and a flag in the upper bit (0 = exception rule,
* 1 = exemption rule). The index can be recovered by masking off
* the upper bit.
*
* ----------------------------------------------------------------------------
*/
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 = 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 = DRC_EXCEPTION_NONE;
else
drcCurException = drcExceptionCreate(argv[1]) | DRC_EXCEPTION_MASK;
return (0);
}
/*
* ----------------------------------------------------------------------------
*
@ -4044,6 +4220,7 @@ drcTechFinalStyle(style)
{
for (j = 0; j < DBNumTypes; j++)
{
free_magic1_t mm1 = freeMagic1_init();
for (dp = style->DRCRulesTbl[i][j]; dp != NULL; dp = dp->drcc_next)
{
/* Don't optimize on trigger rules; optimize on the */
@ -4081,6 +4258,7 @@ drcTechFinalStyle(style)
if (dp->drcc_dist > next->drcc_dist) continue;
if (dp->drcc_cdist > next->drcc_cdist) continue;
if (dp->drcc_plane != next->drcc_plane) continue;
if (dp->drcc_exception != next->drcc_exception) continue;
if (dp->drcc_flags & DRC_REVERSE)
{
if (!(next->drcc_flags & DRC_REVERSE)) continue;
@ -4126,7 +4304,8 @@ drcTechFinalStyle(style)
if (dptrig != NULL)
{
dptrig = dp->drcc_next;
freeMagic((char *)dp->drcc_next);
free_magic1_t mm1_ = freeMagic1_init();
freeMagic1(&mm1_, (char *)dp->drcc_next);
*dp2back = dp->drcc_next->drcc_next;
/* Replace this entry so on the next cycle */
@ -4134,13 +4313,15 @@ drcTechFinalStyle(style)
/* even though dp is free'd (below), due to */
/* the one-delayed free mechanism. */
dp->drcc_next = *dp2back;
freeMagic1_end(&mm1_);
}
else
*dp2back = dp->drcc_next;
freeMagic((char *) dp);
freeMagic1(&mm1, (char *) dp);
drcRulesOptimized += 1;
}
freeMagic1_end(&mm1);
}
}
}

View File

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

View File

@ -35,9 +35,9 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
#include "dbwind/dbwind.h" /* for DBWclientID */
#include "commands/commands.h" /* for module auto-load */
#include "textio/txcommands.h"
#include "extract/extract.h" /* for extDevTable */
#include "extflat/extflat.h"
#include "extflat/EFint.h"
#include "extract/extract.h" /* for extDevTable */
#include "utils/runstats.h"
#include "utils/malloc.h"
@ -683,8 +683,10 @@ runexttosim:
EFVisitDevs(simmergeVisit, PTR2CD(NULL));
TxPrintf("Devices merged: %d\n", esDevsMerged);
esFMIndex = 0;
free_magic1_t mm1 = freeMagic1_init();
for (p = devMergeList; p != NULL; p = p->next)
freeMagic((char *)p);
freeMagic1(&mm1, (char *)p);
freeMagic1_end(&mm1);
devMergeList = NULL;
}
@ -812,7 +814,10 @@ main(
EFVisitDevs(simmergeVisit, PTR2CD(NULL));
TxPrintf("Devices merged: %d\n", esDevsMerged);
esFMIndex = 0;
for (p = devMergeList; p != NULL; p = p->next) freeMagic((char *)p);
free_magic1_t mm1 = freeMagic1_init();
for (p = devMergeList; p != NULL; p = p->next)
freeMagic1(&mm1, (char *)p);
freeMagic1_end(&mm1);
}
EFVisitDevs(simdevVisit, PTR2CD(NULL));
@ -1116,6 +1121,7 @@ simdevVisit(
break;
case DEV_MSUBCKT:
case DEV_CSUBCKT:
case DEV_DSUBCKT:
case DEV_RSUBCKT:
case DEV_SUBCKT:
/* Use the 'x' type in .sim format. This is implemented in the */

View File

@ -41,14 +41,11 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
#include "commands/commands.h" /* for module auto-load */
#include "textio/txcommands.h"
#include "extflat/extflat.h"
#include "extflat/EFint.h"
#include "extract/extract.h" /* for extDevTable */
#include "extflat/EFint.h"
#include "utils/runstats.h"
#include "ext2spice/ext2spice.h"
/* C99 compat */
#include "extflat/extflat.h"
/* These global values are defined in ext2spice.c */
extern HashTable subcktNameTable;
extern DQueue subcktNameQueue;
@ -126,6 +123,94 @@ GetHierNode(
return(nn->efnn_node);
}
/*
* ----------------------------------------------------------------------------
*
* spcHierWriteValue ---
*
* Special case of spcHierWriteParams() below. Only check for 'r' or 'c'
* parameters which have no parameter name. Write out the given value,
* which in the case of CDL format is written out after the pins but before
* everything else, arbitrarily.
*
* ----------------------------------------------------------------------------
*/
void
spcHierWriteValue(
HierContext *hc,
Dev *dev) /* Dev being output */
{
DevParam *plist;
plist = efGetDeviceParams(EFDevTypes[dev->dev_type]);
while (plist != NULL)
{
switch (plist->parm_type[0])
{
case 'r':
if (*(plist->parm_name) == '\0')
{
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, (double)(dev->dev_res));
}
break;
case 'c':
if (*(plist->parm_name) == '\0')
{
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, (double)(dev->dev_cap));
}
break;
}
plist = plist->parm_next;
}
}
/*
* ----------------------------------------------------------------------------
*
* spcHierWriteSubParam ---
*
* Special case of spcHierWriteParams() below. Only check for the substrate
* parameter, which in the case of CDL format is written out before the
* device model, for whatever reason. Return TRUE if the substrate parameter
* was output; otherwise return FALSE.
*
* ----------------------------------------------------------------------------
*/
bool
spcHierWriteSubParam(
HierContext *hc,
Dev *dev) /* Dev being output */
{
DevParam *plist;
bool retvalue = FALSE;
plist = efGetDeviceParams(EFDevTypes[dev->dev_type]);
while (plist != NULL)
{
switch (plist->parm_type[0])
{
case 's':
if (dev->dev_subsnode == NULL)
TxError("Error: Device %s missing substrate node!\n",
EFDevTypes[dev->dev_type]);
else
{
fprintf(esSpiceF, " %s=", plist->parm_name);
spcdevSubstrate(hc->hc_hierName,
dev->dev_subsnode->efnode_name->efnn_hier,
dev->dev_type, esSpiceF);
retvalue = TRUE;
}
break;
}
plist = plist->parm_next;
}
return retvalue;
}
/*
* ----------------------------------------------------------------------------
@ -145,7 +230,8 @@ spcHierWriteParams(
float scale, /* Scale transform for output */
int l, /* Device length, in internal units */
int w, /* Device width, in internal units */
float sdM) /* Device multiplier */
float sdM, /* Device multiplier */
bool subdone) /* If TRUE, then substrate parameter was already output */
{
DevParam *plist, *dparam;
int parmval;
@ -289,6 +375,7 @@ spcHierWriteParams(
else
esSIvalue(esSpiceF, (dval + plist->parm_offset)
* scale * esScale * 1.0E-6);
/* Why is this here? */
dparam->parm_name[0] = '\0';
break;
}
@ -342,10 +429,19 @@ spcHierWriteParams(
}
break;
case 's':
fprintf(esSpiceF, " %s=", plist->parm_name);
/*EFNode *subnodeFlat =*/ spcdevSubstrate(hc->hc_hierName,
dev->dev_subsnode->efnode_name->efnn_hier,
dev->dev_type, esSpiceF);
if (!subdone)
{
if (dev->dev_subsnode == NULL)
TxError("Error: Device %s missing substrate node!\n",
EFDevTypes[dev->dev_type]);
else
{
fprintf(esSpiceF, " %s=", plist->parm_name);
spcdevSubstrate(hc->hc_hierName,
dev->dev_subsnode->efnode_name->efnn_hier,
dev->dev_type, esSpiceF);
}
}
break;
case 'x':
fprintf(esSpiceF, " %s=", plist->parm_name);
@ -370,12 +466,18 @@ spcHierWriteParams(
* scale * esScale * 1.0E-6);
break;
case 'r':
fprintf(esSpiceF, " %s=", plist->parm_name);
fprintf(esSpiceF, "%f", (double)(dev->dev_res));
if (*(plist->parm_name) != '\0')
{
fprintf(esSpiceF, " %s=", plist->parm_name);
esSIvalue(esSpiceF, (double)(dev->dev_res));
}
break;
case 'c':
fprintf(esSpiceF, " %s=", plist->parm_name);
fprintf(esSpiceF, "%ff", (double)(dev->dev_cap));
if (*(plist->parm_name) != '\0')
{
fprintf(esSpiceF, " %s=", plist->parm_name);
esSIvalue(esSpiceF, (double)(dev->dev_cap));
}
break;
}
plist = plist->parm_next;
@ -449,10 +551,16 @@ esOutputHierResistor(
{
fprintf(esSpiceF, " %f", ((double)(dev->dev_res)
/ (double)(dscale)) / (double)sdM);
spcHierWriteParams(hc, dev, scale, l, w, sdM);
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
}
else
{
bool subdone = FALSE;
spcHierWriteValue(hc, dev);
if (esFormat == CDL)
subdone = spcHierWriteSubParam(hc, dev);
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
if (esScale < 0)
@ -467,7 +575,7 @@ esOutputHierResistor(
fprintf(esSpiceF, " l=");
esSIvalue(esSpiceF, 1.0E-6 * (float)((l * scale * esScale) / dscale));
}
spcHierWriteParams(hc, dev, scale, l, w, sdM);
spcHierWriteParams(hc, dev, scale, l, w, sdM, subdone);
if (sdM != 1.0)
fprintf(esSpiceF, " M=%g", sdM);
}
@ -526,7 +634,7 @@ subcktHierVisit(
if (hasports || is_top)
return subcktVisit(use, hierName, is_top);
else if (def->def_flags & DEF_NODEVICES)
else if ((def->def_flags & DEF_NODEVICES) && (!isStub))
return 0;
else
return subcktVisit(use, hierName, is_top);
@ -584,6 +692,7 @@ spcdevHierVisit(
float sdM;
char devchar;
bool has_model = TRUE;
bool subdone = FALSE;
/* If no terminals, or only a gate, can't do much of anything */
if (dev->dev_nterm <= 1 )
@ -694,6 +803,7 @@ spcdevHierVisit(
case DEV_SUBCKT:
case DEV_RSUBCKT:
case DEV_CSUBCKT:
case DEV_DSUBCKT:
case DEV_MSUBCKT:
devchar = 'X';
break;
@ -731,6 +841,7 @@ spcdevHierVisit(
case DEV_VERILOGA:
case DEV_RSUBCKT:
case DEV_CSUBCKT:
case DEV_DSUBCKT:
case DEV_MSUBCKT:
fprintf(esSpiceF, "%d", esSbckNum++);
break;
@ -765,12 +876,15 @@ spcdevHierVisit(
source->dterm_node->efnode_name->efnn_hier,
"base", esSpiceF);
if (esFormat == CDL)
subdone = spcHierWriteSubParam(hc, dev);
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
sdM = getCurDevMult();
spcHierWriteParams(hc, dev, scale, l, w, sdM);
spcHierWriteParams(hc, dev, scale, l, w, sdM, subdone);
break;
case DEV_MSUBCKT:
case DEV_DSUBCKT:
/* msubcircuit is "Xnnn drain gate [source [sub]]]" */
/* to more conveniently handle situations where MOSFETs */
/* are modeled by subcircuits with the same pin ordering. */
@ -799,7 +913,11 @@ spcdevHierVisit(
/* except that the "gate" node is treated as an identifier */
/* only and is not output. */
if (dev->dev_class != DEV_MSUBCKT)
if (dev->dev_class == DEV_DSUBCKT)
{
/* Do nothing; both terminals have already been output */
}
else if (dev->dev_class != DEV_MSUBCKT)
{
if (dev->dev_nterm > 1)
spcdevOutNode(hc->hc_hierName, source->dterm_node->efnode_name->efnn_hier,
@ -840,11 +958,13 @@ spcdevHierVisit(
subnode->efnode_name->efnn_hier,
dev->dev_type, esSpiceF);
}
/* Support for CDL format */
if (esFormat == CDL) fprintf(esSpiceF, " /");
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
/* Write all requested parameters to the subcircuit call. */
sdM = getCurDevMult();
spcHierWriteParams(hc, dev, scale, l, w, sdM);
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
if (sdM != 1.0)
fprintf(esSpiceF, " M=%g", sdM);
break;
@ -915,9 +1035,11 @@ spcdevHierVisit(
spcdevOutNode(hc->hc_hierName,
subnode->efnode_name->efnn_hier,
"diode_bot", esSpiceF);
if (esFormat == CDL)
subdone = spcHierWriteSubParam(hc, dev);
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
sdM = getCurDevMult();
spcHierWriteParams(hc, dev, scale, l, w, sdM);
spcHierWriteParams(hc, dev, scale, l, w, sdM, subdone);
break;
case DEV_NDIODE:
@ -936,9 +1058,11 @@ spcdevHierVisit(
spcdevOutNode(hc->hc_hierName,
gate->dterm_node->efnode_name->efnn_hier,
"diode_top", esSpiceF);
if (esFormat == CDL)
subdone = spcHierWriteSubParam(hc, dev);
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
sdM = getCurDevMult();
spcHierWriteParams(hc, dev, scale, l, w, sdM);
spcHierWriteParams(hc, dev, scale, l, w, sdM, subdone);
break;
case DEV_CAP:
@ -964,11 +1088,15 @@ spcdevHierVisit(
if (!has_model)
{
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
spcHierWriteParams(hc, dev, scale, l, w, sdM);
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
}
else
{
spcHierWriteValue(hc, dev);
if (esFormat == CDL)
subdone = spcHierWriteSubParam(hc, dev);
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
if (esScale < 0)
@ -982,7 +1110,7 @@ spcdevHierVisit(
fprintf(esSpiceF, " l=");
esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale);
}
spcHierWriteParams(hc, dev, scale, l, w, sdM);
spcHierWriteParams(hc, dev, scale, l, w, sdM, subdone);
if (sdM != 1.0)
fprintf(esSpiceF, " M=%g", sdM);
}
@ -1011,11 +1139,15 @@ spcdevHierVisit(
if (!has_model)
{
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
spcHierWriteParams(hc, dev, scale, l, w, sdM);
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
}
else
{
spcHierWriteValue(hc, dev);
if (esFormat == CDL)
subdone = spcHierWriteSubParam(hc, dev);
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
if (esScale < 0)
@ -1029,7 +1161,7 @@ spcdevHierVisit(
fprintf(esSpiceF, " l=");
esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale);
}
spcHierWriteParams(hc, dev, scale, l, w, sdM);
spcHierWriteParams(hc, dev, scale, l, w, sdM, subdone);
if (sdM != 1.0)
fprintf(esSpiceF, " M=%g", sdM);
}
@ -1073,7 +1205,7 @@ spcdevHierVisit(
fprintf(esSpiceF, " l=");
esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale);
}
spcHierWriteParams(hc, dev, scale, l, w, sdM);
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
if (sdM != 1.0)
fprintf(esSpiceF, " M=%g", sdM);
@ -2069,11 +2201,13 @@ esMakePorts(
}
/* Free table data */
free_magic1_t mm1 = freeMagic1_init();
while (flagtop != NULL)
{
freeMagic((char *)flagtop);
freeMagic1(&mm1, (char *)flagtop);
flagtop = flagtop->fdr_next;
}
freeMagic1_end(&mm1);
HashKill(&flagHashTable);
return 0;
}
@ -2205,8 +2339,10 @@ esHierVisit(
EFHierVisitDevs(hcf, spcdevHierMergeVisit, (ClientData)NULL);
TxPrintf("Devs merged: %d\n", esSpiceDevsMerged);
esFMIndex = 0;
free_magic1_t mm1 = freeMagic1_init();
for (p = devMergeList; p != NULL; p = p->next)
freeMagic((char *)p);
freeMagic1(&mm1, (char *)p);
freeMagic1_end(&mm1);
devMergeList = NULL;
}
else if (esDistrJunct)

View File

@ -38,9 +38,9 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
#include "dbwind/dbwind.h" /* for DBWclientID */
#include "commands/commands.h" /* for module auto-load */
#include "textio/txcommands.h"
#include "extract/extract.h" /* for extDevTable */
#include "extflat/extflat.h"
#include "extflat/EFint.h"
#include "extract/extract.h" /* for extDevTable */
#include "utils/runstats.h"
#include "ext2spice/ext2spice.h"
@ -284,7 +284,7 @@ CmdExtToSpice(
static int LocResistThreshold = INFINITE_THRESHOLD;
static const char * const spiceFormats[] = {
"SPICE2", "SPICE3", "HSPICE", "NGSPICE", NULL
"SPICE2", "SPICE3", "HSPICE", "NGSPICE", "CDL", NULL
};
static const char * const cmdExtToSpcOption[] = {
@ -330,6 +330,7 @@ CmdExtToSpice(
"spice3",
"hspice",
"ngspice",
"cdl",
NULL
};
@ -663,10 +664,10 @@ CmdExtToSpice(
{
#ifdef MAGIC_WRAPPER
Tcl_SetResult(magicinterp, "Bad format type. Formats are:"
"spice2, spice3, hspice, and ngspice.", NULL);
"spice2, spice3, hspice, ngspice, and cdl.", NULL);
#else
TxError("Bad format type. Formats are:"
"spice2, spice3, hspice, and ngspice.");
"spice2, spice3, hspice, ngspice, and cdl.");
#endif
return;
}
@ -876,7 +877,12 @@ runexttospice:
*/
if (spcesOutName == spcesDefaultOut)
sprintf(spcesDefaultOut, "%s.spice", inName);
{
if (esFormat == CDL)
sprintf(spcesDefaultOut, "%s.cdl", inName);
else
sprintf(spcesDefaultOut, "%s.spice", inName);
}
/* Read the hierarchical description of the input circuit */
if (EFReadFile(inName, esDoHierarchy, esDoExtResis, FALSE, TRUE)
@ -963,8 +969,11 @@ runexttospice:
locsubname = StrDup(NULL, subname);
bangptr = locsubname + strlen(locsubname) - 1;
if (*bangptr == '!') *bangptr = '\0';
if (esFormat != CDL)
{
bangptr = locsubname + strlen(locsubname) - 1;
if (*bangptr == '!') *bangptr = '\0';
}
// Ad-hoc check: Global names with "Error", "err", etc.
// should be rejected from the list. Also node name
@ -994,6 +1003,42 @@ runexttospice:
}
#ifdef MAGIC_WRAPPER
if (esFormat == CDL)
{
/* In CDL format, if the global substrate ends with "!" then
* add it to the list of globals; likewise for VDD and GND.
*/
char *glbstr;
globalList *glptr;
glbstr = (char *)Tcl_GetVar(magicinterp, "SUB", TCL_GLOBAL_ONLY);
if ((glbstr != NULL) && (*(glbstr + strlen(glbstr) - 1) == '!'))
{
glptr = (globalList *)mallocMagic(sizeof(globalList));
glptr->gll_name = StrDup((char **)NULL, glbstr);
glptr->gll_next = glist;
glist = glptr;
}
glbstr = (char *)Tcl_GetVar(magicinterp, "VDD", TCL_GLOBAL_ONLY);
if ((glbstr != NULL) && (*(glbstr + strlen(glbstr) - 1) == '!'))
{
glptr = (globalList *)mallocMagic(sizeof(globalList));
glptr->gll_name = StrDup((char **)NULL, glbstr);
glptr->gll_next = glist;
glist = glptr;
}
glbstr = (char *)Tcl_GetVar(magicinterp, "GND", TCL_GLOBAL_ONLY);
if ((glbstr != NULL) && (*(glbstr + strlen(glbstr) - 1) == '!'))
{
glptr = (globalList *)mallocMagic(sizeof(globalList));
glptr->gll_name = StrDup((char **)NULL, glbstr);
glptr->gll_next = glist;
glist = glptr;
}
}
if (EFCompat == TRUE)
{
/* Keep a pointer to the "GND" variable, if it exists. */
@ -1027,6 +1072,8 @@ runexttospice:
if (IS_FINITE_F(EFCapThreshold)) flatFlags |= EF_FLATCAPS;
if (esFormat == HSPICE)
EFOutputFlags |= EF_TRIMLOCAL;
if (esFormat == CDL)
EFOutputFlags &= ~EF_TRIMGLOB;
/* Write globals under a ".global" card */
@ -1057,8 +1104,10 @@ runexttospice:
fprintf(esSpiceF, " ");
freeMagic(glist->gll_name);
freeMagic(glist);
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, glist);
glist = glist->gll_next;
freeMagic1_end(&mm1);
}
fprintf(esSpiceF, "\n\n");
}
@ -1112,8 +1161,10 @@ runexttospice:
EFVisitDevs(devMergeVisit, (ClientData) NULL);
TxPrintf("Devs merged: %d\n", esSpiceDevsMerged);
esFMIndex = 0;
free_magic1_t mm1 = freeMagic1_init();
for (p = devMergeList; p != NULL; p = p->next)
freeMagic((char *) p);
freeMagic1(&mm1, (char *) p);
freeMagic1_end(&mm1);
devMergeList = NULL;
}
else if (esDistrJunct)
@ -1226,7 +1277,13 @@ main(
*/
if (spcesOutName == spcesDefaultOut)
sprintf(spcesDefaultOut, "%s.spice", inName);
{
if (esFormat == CDL)
sprintf(spcesDefaultOut, "%s.cdl", inName);
else
sprintf(spcesDefaultOut, "%s.spice", inName);
}
if ((esSpiceF = fopen(spcesOutName, "w")) == NULL)
{
@ -1288,9 +1345,12 @@ main(
TxPrintf("Devs merged: %d\n", esSpiceDevsMerged);
esFMIndex = 0 ;
{
const devMerge *p;
const devMerge *p;
for ( p = devMergeList ; p != NULL ; p=p->next ) freeMagic((char *)p);
free_magic1_t mm1 = freeMagic1_init();
for (p = devMergeList; p != NULL; p = p->next)
freeMagic1(&mm1, (char *)p);
freeMagic1_end(&mm1);
}
} else if ( esDistrJunct )
EFVisitDevs(devDistJunctVisit, (ClientData) NULL);
@ -1363,7 +1423,7 @@ spcParseArgs(
const char usage_text[] = "Usage: ext2spice "
"[-B] [-o spicefile] [-M|-m] [-J flat|hier]\n"
"[-f spice2|spice3|hspice|ngspice] [-M] [-m] "
"[-f spice2|spice3|hspice|ngspice|cdl] [-M] [-m] "
"[file]\n";
switch (argv[0][1])
@ -1407,6 +1467,8 @@ spcParseArgs(
}
else if (strcasecmp(ftmp, "NGSPICE") == 0)
esFormat = NGSPICE;
else if (strcasecmp(ftmp, "CDL") == 0)
esFormat = CDL;
else goto usage;
break;
@ -1627,23 +1689,43 @@ subcktVisit(
HashStartSearch(&hs);
while ((he = HashNext(&def->def_nodes, &hs)))
{
bool found = FALSE;
sname = (EFNodeName *) HashGetValue(he);
if (sname == NULL) continue;
snode = sname->efnn_node;
if ((snode == NULL) || !(snode->efnode_flags & EF_PORT)) continue;
portidx = snode->efnode_name->efnn_port;
if (portidx >= 0)
{
if (nodeList[portidx] == NULL)
{
nodeList[portidx] = snode->efnode_name;
found = TRUE;
}
}
/* Normally there should be a port associated with snode, but
* if not, go looking for one in the node name aliases.
*/
for (nodeName = sname; nodeName != NULL; nodeName = nodeName->efnn_next)
{
if (found == TRUE) break;
portidx = nodeName->efnn_port;
if (portidx < 0) continue;
if (nodeList[portidx] == NULL)
{
nodeList[portidx] = nodeName;
found = TRUE;
}
else if (EFHNBest(nodeName->efnn_hier, nodeList[portidx]->efnn_hier))
{
nodeList[portidx] = nodeName;
found = TRUE;
}
}
}
@ -1677,6 +1759,7 @@ subcktVisit(
}
if (tchars > 80) fprintf(esSpiceF, "\n+");
if (esFormat == CDL) fprintf(esSpiceF, " /");
fprintf(esSpiceF, " %s", subcktname); /* subcircuit model name */
// Check for a "device parameter" defined with the name of the cell.
@ -1849,8 +1932,10 @@ topVisit(
sname = lnn->lnn_nodeName;
if (esDoBlackBox == FALSE || !(def->def_flags & DEF_ABSTRACT))
sname->efnn_port = ++portmax;
freeMagic(lnn);
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, lnn);
lnn = lnn->lnn_next;
freeMagic1_end(&mm1);
}
/* Port numbers need not start at zero or be contiguous. They will be */
@ -1867,6 +1952,7 @@ topVisit(
{
char stmp[MAX_STR_SIZE];
int portidx;
bool found = FALSE;
sname = (EFNodeName *) HashGetValue(he);
if (sname == NULL) continue; /* Should not happen */
@ -1874,33 +1960,68 @@ topVisit(
snode = sname->efnn_node;
if ((!snode) || (!(snode->efnode_flags & EF_PORT))) continue;
/* Found a node which is also a port */
portidx = snode->efnode_name->efnn_port;
if (portidx >= 0)
{
if (sorted_ports[portidx] == NULL)
{
if ((def->def_flags & DEF_ABSTRACT))
{
EFHNSprintf(stmp, sname->efnn_hier);
pname = stmp;
}
else
pname = nodeSpiceName(snode->efnode_name->efnn_hier, NULL);
hep = HashLookOnly(&portNameTable, pname);
if (hep == (HashEntry *)NULL)
{
hep = HashFind(&portNameTable, pname);
HashSetValue(hep, (ClientData)(pointertype)portidx);
sorted_ports[portidx] = StrDup((char **)NULL, pname);
}
else
{
/* Node that was unassigned has been found to be
* a repeat (see NOTE at top), so make sure its
* port number is set correctly.
*/
snode->efnode_name->efnn_port = (int)(pointertype)HashGetValue(hep);
}
found = TRUE;
}
}
if (!(def->def_flags & DEF_ABSTRACT))
heh = HashLookOnly(&efNodeHashTable, (char *)snode->efnode_name->efnn_hier);
/* Might need to check here for a port that was optimized out? */
/* If snode is flagged as a port but no port number was found, then
* check the all of the node's name entries to see if any of them has
* a port number.
*/
for (nodeName = sname; nodeName != NULL; nodeName = nodeName->efnn_next)
{
if (found == TRUE) break;
portidx = nodeName->efnn_port;
if (portidx < 0) continue;
/* Check if the same hierName is recorded in the flattened/optimized
* def's efNodeHashTable. If not, then it has been optimized out
* and should be removed from the port list.
*/
if (def->def_flags & DEF_ABSTRACT)
heh = HashLookOnly(&efNodeHashTable, (char *)nodeName->efnn_hier);
else
heh = HashLookOnly(&efNodeHashTable,
(char *)snode->efnode_name->efnn_hier);
/* If view is abstract, rely on the given port name, not
* the node. Otherwise, artifacts of the abstract view
* may cause nodes to be merged and the names lost.
*/
if (def->def_flags & DEF_ABSTRACT)
{
heh = HashLookOnly(&efNodeHashTable, (char *)nodeName->efnn_hier);
/* If view is abstract, rely on the given port name, not
* the node. Otherwise, artifacts of the abstract view
* may cause nodes to be merged and the names lost.
*/
EFHNSprintf(stmp, nodeName->efnn_hier);
pname = stmp;
}
else
// pname = nodeSpiceName(snode->efnode_name->efnn_hier, NULL);
pname = nodeSpiceName(nodeName->efnn_hier, NULL);
if (heh == (HashEntry *)NULL) /* pname now resolved for log output */
@ -1918,7 +2039,10 @@ topVisit(
hep = HashFind(&portNameTable, pname);
HashSetValue(hep, (ClientData)(pointertype)nodeName->efnn_port);
if (sorted_ports[portidx] == NULL)
{
sorted_ports[portidx] = StrDup((char **)NULL, pname);
found = TRUE;
}
}
else
{
@ -1974,6 +2098,92 @@ topVisit(
fprintf(esSpiceF, "\n");
}
/*
* ----------------------------------------------------------------------------
*
* spcWriteValue ---
*
* Special handling for CDL format: Output any resistor or capacitor value,
* value only, no parameter name.
*
* ----------------------------------------------------------------------------
*/
void
spcWriteValue(
Dev *dev, /* Dev being output */
HierName *hierName) /* Hierarchical path down to this dev */
{
DevParam *plist;
plist = efGetDeviceParams(EFDevTypes[dev->dev_type]);
while (plist != NULL)
{
switch (plist->parm_type[0])
{
case 'r':
if (*(plist->parm_name) == '\0')
{
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, (double)dev->dev_res);
}
break;
case 'c':
if (*(plist->parm_name) == '\0')
{
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, (double)dev->dev_res);
}
break;
}
plist = plist->parm_next;
}
}
/*
* ----------------------------------------------------------------------------
*
* spcWriteSubParam ---
*
* Special handling for CDL format: Output any substrate parameter before
* the device model. Why this makes sense, I have no idea.
*
* ----------------------------------------------------------------------------
*/
bool
spcWriteSubParam(
Dev *dev, /* Dev being output */
HierName *hierName) /* Hierarchical path down to this dev */
{
bool retval; /* True if substrate parameter was output */
DevParam *plist;
retval = FALSE;
plist = efGetDeviceParams(EFDevTypes[dev->dev_type]);
while (plist != NULL)
{
switch (plist->parm_type[0])
{
case 's':
if (dev->dev_subsnode == NULL)
TxError("Error: No substrate definition for device %s\n",
EFDevTypes[dev->dev_type]);
else
{
fprintf(esSpiceF, " %s=", plist->parm_name);
spcdevSubstrate(hierName,
dev->dev_subsnode->efnode_name->efnn_hier,
dev->dev_type, esSpiceF);
retval = TRUE;
}
break;
}
plist = plist->parm_next;
}
return retval;
}
/*
* ----------------------------------------------------------------------------
*
@ -1993,7 +2203,8 @@ spcWriteParams(
float scale, /* Scale transform for output */
int l, /* Device length, in internal units */
int w, /* Device width, in internal units */
float sdM) /* Device multiplier */
float sdM, /* Device multiplier */
bool subdone) /* If TRUE, substrate parameter was already output */
{
bool hierD;
DevParam *plist, *dparam;
@ -2227,10 +2438,19 @@ spcWriteParams(
}
break;
case 's':
fprintf(esSpiceF, " %s=", plist->parm_name);
/*EFNode *subnodeFlat =*/ spcdevSubstrate(hierName,
dev->dev_subsnode->efnode_name->efnn_hier,
dev->dev_type, esSpiceF);
if (!subdone)
{
if (dev->dev_subsnode == NULL)
TxError("Error: No substrate definition for device %s\n",
EFDevTypes[dev->dev_type]);
else
{
fprintf(esSpiceF, " %s=", plist->parm_name);
spcdevSubstrate(hierName,
dev->dev_subsnode->efnode_name->efnn_hier,
dev->dev_type, esSpiceF);
}
}
break;
case 'x':
fprintf(esSpiceF, " %s=", plist->parm_name);
@ -2255,12 +2475,18 @@ spcWriteParams(
* scale * esScale * 1.0E-6);
break;
case 'r':
fprintf(esSpiceF, " %s=", plist->parm_name);
fprintf(esSpiceF, "%f", (double)(dev->dev_res));
if (*(plist->parm_name) != '\0')
{
fprintf(esSpiceF, " %s=", plist->parm_name);
esSIvalue(esSpiceF, (double)dev->dev_res);
}
break;
case 'c':
fprintf(esSpiceF, " %s=", plist->parm_name);
fprintf(esSpiceF, "%ff", (double)(dev->dev_cap));
if (*(plist->parm_name) != '\0')
{
fprintf(esSpiceF, " %s=", plist->parm_name);
esSIvalue(esSpiceF, (double)dev->dev_cap);
}
break;
}
plist = plist->parm_next;
@ -2326,10 +2552,14 @@ esOutputResistor(
{
fprintf(esSpiceF, " %f", ((double)(dev->dev_res)
/ (double)(dscale)) / (double)sdM);
spcWriteParams(dev, hierName, scale, l, w, sdM);
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
}
else
{
bool subdone = FALSE;
spcWriteValue(dev, hierName);
if (esFormat == CDL)
subdone = spcWriteSubParam(dev, hierName);
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
if (esScale < 0)
@ -2342,7 +2572,7 @@ esOutputResistor(
esSIvalue(esSpiceF, 1.0E-6 * (l * scale * esScale) / dscale);
}
spcWriteParams(dev, hierName, scale, l, w, sdM);
spcWriteParams(dev, hierName, scale, l, w, sdM, subdone);
if (sdM != 1.0)
fprintf(esSpiceF, " M=%g", sdM);
}
@ -2489,6 +2719,7 @@ spcdevVisit(
float sdM;
char name[12], devchar;
bool has_model = TRUE;
bool subdone = FALSE;
HierName *hierName = hc->hc_hierName;
sprintf(name, "output");
@ -2534,6 +2765,7 @@ spcdevVisit(
case DEV_VERILOGA:
case DEV_RSUBCKT:
case DEV_CSUBCKT:
case DEV_DSUBCKT:
case DEV_MSUBCKT:
break;
case DEV_DIODE:
@ -2631,6 +2863,7 @@ spcdevVisit(
case DEV_SUBCKT:
case DEV_RSUBCKT:
case DEV_CSUBCKT:
case DEV_DSUBCKT:
case DEV_MSUBCKT:
devchar = 'X';
break;
@ -2672,6 +2905,7 @@ spcdevVisit(
case DEV_VERILOGA:
case DEV_RSUBCKT:
case DEV_CSUBCKT:
case DEV_DSUBCKT:
case DEV_MSUBCKT:
fprintf(esSpiceF, "%d", esSbckNum++);
break;
@ -2703,12 +2937,15 @@ spcdevVisit(
spcdevOutNode(hierName, source->dterm_node->efnode_name->efnn_hier,
name, esSpiceF);
if (esFormat == CDL)
subdone = spcWriteSubParam(dev, hierName);
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
sdM = getCurDevMult();
spcWriteParams(dev, hierName, scale, l, w, sdM);
spcWriteParams(dev, hierName, scale, l, w, sdM, subdone);
break;
case DEV_MSUBCKT:
case DEV_DSUBCKT:
/* MOS-like subcircuit is "Xnnn drain gate [source [sub]]" */
/* to more conveniently handle cases where MOS devices are */
@ -2736,7 +2973,11 @@ spcdevVisit(
/* except that the "gate" node is treated as an identifier */
/* only and is not output. */
if (dev->dev_class != DEV_MSUBCKT)
if (dev->dev_class == DEV_DSUBCKT)
{
/* Do nothing: Both terminals have already been output */
}
else if (dev->dev_class != DEV_MSUBCKT)
{
if (dev->dev_nterm > 1)
spcdevOutNode(hierName, source->dterm_node->efnode_name->efnn_hier,
@ -2777,12 +3018,15 @@ spcdevVisit(
subnode->efnode_name->efnn_hier,
dev->dev_type, esSpiceF);
}
/* CDL format support: Output a slash followed by a space. */
if (esFormat == CDL) fprintf(esSpiceF, " /");
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
/* Write all requested parameters to the subcircuit call. */
sdM = getCurDevMult();
spcWriteParams(dev, hierName, scale, l, w, sdM);
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
if (sdM != 1.0)
fprintf(esSpiceF, " M=%g", sdM);
break;
@ -2848,9 +3092,12 @@ spcdevVisit(
spcdevOutNode(hierName, subnode->efnode_name->efnn_hier,
name, esSpiceF);
if (esFormat == CDL)
subdone = spcWriteSubParam(dev, hierName);
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
sdM = getCurDevMult();
spcWriteParams(dev, hierName, scale, l, w, sdM);
spcWriteParams(dev, hierName, scale, l, w, sdM, subdone);
break;
case DEV_NDIODE:
@ -2866,9 +3113,11 @@ spcdevVisit(
spcdevOutNode(hierName, gate->dterm_node->efnode_name->efnn_hier,
name, esSpiceF);
if (esFormat == CDL)
subdone = spcWriteSubParam(dev, hierName);
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
sdM = getCurDevMult();
spcWriteParams(dev, hierName, scale, l, w, sdM);
spcWriteParams(dev, hierName, scale, l, w, sdM, subdone);
break;
case DEV_CAP:
@ -2891,11 +3140,15 @@ spcdevVisit(
if (!has_model)
{
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
spcWriteParams(dev, hierName, scale, l, w, sdM);
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
}
else
{
spcWriteValue(dev, hierName);
if (esFormat == CDL)
subdone = spcWriteSubParam(dev, hierName);
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
if (esScale < 0)
@ -2908,7 +3161,7 @@ spcdevVisit(
esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale);
}
spcWriteParams(dev, hierName, scale, l, w, sdM);
spcWriteParams(dev, hierName, scale, l, w, sdM, subdone);
if (sdM != 1.0)
fprintf(esSpiceF, " M=%g", sdM);
}
@ -2934,11 +3187,15 @@ spcdevVisit(
if (!has_model)
{
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
spcWriteParams(dev, hierName, scale, l, w, sdM);
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
}
else
{
spcWriteValue(dev, hierName);
if (esFormat == CDL)
subdone = spcWriteSubParam(dev, hierName);
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
if (esScale < 0)
@ -2951,7 +3208,7 @@ spcdevVisit(
esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale);
}
spcWriteParams(dev, hierName, scale, l, w, sdM);
spcWriteParams(dev, hierName, scale, l, w, sdM, subdone);
if (sdM != 1.0)
fprintf(esSpiceF, " M=%g", sdM);
}
@ -2999,7 +3256,7 @@ spcdevVisit(
esSIvalue(esSpiceF, 1.0E-6 * l * scale * esScale);
}
spcWriteParams(dev, hierName, scale, l, w, sdM);
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
if (sdM != 1.0)
fprintf(esSpiceF, " M=%g", sdM);
@ -3118,12 +3375,15 @@ spcdevSubstrate(
/* Canonical name */
nn = (EFNodeName *) HashGetValue(he);
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 */
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) */
if (esDistrJunct)
@ -4260,6 +4520,7 @@ parallelDevs(
case DEV_VERILOGA:
case DEV_RSUBCKT:
case DEV_CSUBCKT:
case DEV_DSUBCKT:
break;
case DEV_VOLT:

View File

@ -173,6 +173,7 @@ typedef struct {
#define SPICE3 1
#define HSPICE 2
#define NGSPICE 3
#define CDL 4
#define AUTO 2 /* TRUE | FALSE | AUTO for esDoSubckt */

View File

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

View File

@ -34,8 +34,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header$";
#include "tiles/tile.h"
#include "database/database.h" /* for TileType definition */
#include "extflat/extflat.h"
#include "extflat/extparse.h"
#include "extflat/EFint.h"
#include "extract/extract.h" /* for device class list */
#include "extract/extract.h"
#include "extract/extractInt.h" /* for extGetDevType() */
/* C99 compat */
@ -603,33 +604,70 @@ efBuildEquiv(def, nodeName1, nodeName2, resist, isspice)
}
if (!equalByCase)
{
if ((EFOutputFlags & EF_SHORT_MASK) != EF_SHORT_NONE)
/* If one of the nodes has been generated from the
* other by "extract unique", then this is a case where
* the "extract unique" algorithm is blind to shorts
* through subcell hierarchy and has made a name unique
* unnecessarily. In that case, merge the node instead
* of generating a short.
*/
char *uniqstr1, *uniqstr2;
bool isuniq;
uniqstr1 = strstr(nodeName1, "_uq");
uniqstr2 = strstr(nodeName2, "_uq");
if (uniqstr1) *uniqstr1 = '\0';
if (uniqstr2) *uniqstr2 = '\0';
isuniq = !strcmp(nodeName1, nodeName2);
if (uniqstr1) *uniqstr1 = '_';
if (uniqstr2) *uniqstr2 = '_';
if (!isuniq)
{
int i;
int sdev;
char *argv[10], zeroarg[] = "0";
if ((EFOutputFlags & EF_SHORT_MASK) != EF_SHORT_NONE)
{
int i;
int sdev;
char *argv[10], zeroarg[] = "0";
if ((EFOutputFlags & EF_SHORT_MASK) == EF_SHORT_R)
sdev = DEV_RES;
if ((EFOutputFlags & EF_SHORT_MASK) == EF_SHORT_R)
sdev = DEV_RES;
else
sdev = DEV_VOLT;
for (i = 0; i < 10; i++) argv[i] = zeroarg;
argv[0] = StrDup((char **)NULL, "0.0");
argv[1] = StrDup((char **)NULL, "dummy");
argv[4] = StrDup((char **)NULL, nodeName1);
argv[7] = StrDup((char **)NULL, nodeName2);
efBuildDevice(def, sdev, "None", &GeoNullRect, 10, argv);
freeMagic(argv[0]);
freeMagic(argv[1]);
freeMagic(argv[4]);
freeMagic(argv[7]);
return;
}
else if (!resist)
{
char *uptr1, *uptr2;
/* Do not generate an error message if one or both node names
* is made by "extract unique".
*/
if ((uptr1 = strstr(nodeName1, "_uq")) != 0) *uptr1 = '\0';
if ((uptr2 = strstr(nodeName2, "_uq")) != 0) *uptr2 = '\0';
if ((uptr1 == NULL && uptr2 == NULL) ||
strcmp(nodeName1, nodeName2))
TxError("Warning: Ports \"%s\" and \"%s\" are electrically "
"shorted.\n", nodeName1, nodeName2);
if (uptr1) *uptr1 = '_';
if (uptr2) *uptr2 = '_';
}
else
sdev = DEV_VOLT;
for (i = 0; i < 10; i++) argv[i] = zeroarg;
argv[0] = StrDup((char **)NULL, "0.0");
argv[1] = StrDup((char **)NULL, "dummy");
argv[4] = StrDup((char **)NULL, nodeName1);
argv[7] = StrDup((char **)NULL, nodeName2);
efBuildDevice(def, sdev, "None", &GeoNullRect, 10, argv);
freeMagic(argv[0]);
freeMagic(argv[1]);
freeMagic(argv[4]);
freeMagic(argv[7]);
return;
/* Do not merge the nodes when folding in extresist parasitics */
return;
}
else if (!resist)
TxError("Warning: Ports \"%s\" and \"%s\" are electrically shorted.\n",
nodeName1, nodeName2);
else
else if (resist)
/* Do not merge the nodes when folding in extresist parasitics */
return;
}
@ -652,8 +690,6 @@ efBuildEquiv(def, nodeName1, nodeName2, resist, isspice)
if (efWarn)
efReadError("Merged nodes %s and %s\n", nodeName1, nodeName2);
lostnode = efNodeMerge(&nn1->efnn_node, &nn2->efnn_node);
if (nn1->efnn_port > 0) nn2->efnn_port = nn1->efnn_port;
else if (nn2->efnn_port > 0) nn1->efnn_port = nn2->efnn_port;
/* Check if there are any device terminals pointing to the
* node that was just removed.
@ -831,20 +867,20 @@ efBuildDeviceParams(name, argc, argv)
*/
int
efBuildDevice(def, class, type, r, argc, argv)
Def *def; /* Def to which this connection is to be added */
char class; /* Class (dev, bjt, etc.) of this device */
char *type; /* Type (name) of this device */
Rect *r; /* Coordinates of 1x1 rectangle entirely inside device */
int argc; /* Size of argv */
char *argv[]; /* Tokens for the rest of the dev line.
* Starts with the last two position values, used to
* hash the device record. The next arguments depend
* on the type of device. The rest are taken in groups
* of 3, one for each terminal. Each group of 3 consists
* of the node name to which the terminal connects, the
* length of the terminal, and an attribute list (or the
* token 0).
efBuildDevice(
Def *def, /* Def to which this connection is to be added */
char class, /* Class (dev, bjt, etc.) of this device */
char *type, /* Type (name) of this device */
const Rect *r, /* Coordinates of 1x1 rectangle entirely inside device */
int argc, /* Size of argv */
char *argv[]) /* Tokens for the rest of the dev line.
* Starts after the four device coordinate arguments.
* The next arguments (0, 1, or 2) depend on the type of
* device, followed by optional parameters. The rest are
* taken in groups of 3, one for each terminal. Each
* group of 3 consists of the node name to which the
* terminal connects, the length of the terminal, and
* an attribute list (or the token 0).
*/
{
int n, nterminals, pn;
@ -856,7 +892,7 @@ efBuildDevice(def, class, type, r, argc, argv)
int dev_type;
char ptype, *pptr, **av;
char devhash[64];
int argstart = 1; /* start of terminal list in argv[] */
int termstart;
bool hasModel = strcmp(type, "None") ? TRUE : FALSE;
int area, perim; /* Total area, perimeter of primary type (i.e., channel) */
@ -871,92 +907,162 @@ efBuildDevice(def, class, type, r, argc, argv)
devtmp.dev_width = 0;
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)
{
case DEV_FET:
case DEV_MOSFET:
case DEV_ASYMMETRIC:
/* Terminals start after L and W values, substrate, and parameters */
termstart = 3;
break;
case DEV_BJT:
argstart = 3;
/* Terminals start after L and W values, plus parameters */
termstart = 2;
break;
case DEV_DIODE:
case DEV_NDIODE:
case DEV_PDIODE:
argstart = 0;
/* Terminals start immediately after parameters */
termstart = 0;
break;
case DEV_RES:
case DEV_CAP:
case DEV_CAPREV:
if (hasModel)
argstart = 2;
/* Terminals start after L and W values, plus parameters */
termstart = 2;
/* Otherwise, terminals start after device value, plus parameters */
break;
case DEV_SUBCKT:
case DEV_VERILOGA:
case DEV_MSUBCKT:
case DEV_RSUBCKT:
case DEV_CSUBCKT:
argstart = 0;
case DEV_DSUBCKT:
/* Terminals start immediately after parameters */
termstart = 0;
}
devp = efGetDeviceParams(type);
/* Parse initial arguments for parameters */
while ((pptr = strchr(argv[argstart], '=')) != NULL)
while ((pptr = strchr(argv[termstart], '=')) != NULL)
{
// Check if this parameter is in the table.
// If so, handle appropriately. Otherwise, the
// parameter gets saved verbatim locally. The
// "parameters" line comes before any "device" line
// in the .ext file, so the table should be complete.
/* If the parameter is in the parameter list "devp", then save
* the value as appropriate. If not, then the entire phrase
* will be output verbatim, so just save the whole string.
*
* The "parameters" line comes before any "device" line in the
* .ext file, so the "devp" list should be complete.
*/
*pptr = '\0';
for (sparm = devp; sparm; sparm = sparm->parm_next)
if (!strcasecmp(sparm->parm_type, argv[argstart]))
if (!strncasecmp(sparm->parm_type, argv[termstart], 2))
break;
*pptr = '=';
if (sparm == NULL)
{
/* Copy the parameter into dev_params */
/* Copy the whole string into dev_params */
/* (parm_type and parm_scale records are not used) */
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;
devtmp.dev_params = newparm;
argstart++;
termstart++;
continue;
}
pptr++;
switch(*argv[argstart])
switch(*argv[termstart])
{
case 'a':
if ((pptr - argv[argstart]) == 2)
devtmp.dev_area = atoi(pptr);
if ((pptr - argv[termstart]) == 2)
devtmp.dev_area = (int)(0.5 + (float)atoi(pptr)
* locScale * locScale);
else
{
pn = *(argv[argstart] + 1) - '0';
/* Check for a0, a1, a2, ... If a0, handle like "a".
* Otherwise, don't handle it here.
*/
pn = *(argv[termstart] + 1) - '0';
if (pn == 0)
devtmp.dev_area = (int)(0.5 + (float)atoi(pptr)
* locScale * locScale);
/* Otherwise, punt */
}
break;
case 'p':
if ((pptr - argv[argstart]) == 2)
devtmp.dev_perim = atoi(pptr);
if ((pptr - argv[termstart]) == 2)
devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale);
else
{
pn = *(argv[argstart] + 1) - '0';
/* Check for p0, p1, p2, ... If p0, handle like "p".
* Otherwise, don't handle it here.
*/
pn = *(argv[termstart] + 1) - '0';
if (pn == 0)
devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale);
/* Otherwise, use verbatim */
}
break;
case 'l':
devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale);
if ((pptr - argv[termstart]) == 2)
devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale);
else
{
/* Check for l0, l1, l2, ... If l0, handle like "l".
* 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_length = (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;
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;
case 'c':
devtmp.dev_cap = (float)atof(pptr);
@ -965,7 +1071,7 @@ efBuildDevice(def, class, type, r, argc, argv)
devtmp.dev_res = (float)atof(pptr);
break;
}
argstart++;
termstart++;
}
/* Check for optional substrate node */
@ -973,31 +1079,33 @@ efBuildDevice(def, class, type, r, argc, argv)
{
case DEV_RES:
case DEV_CAP:
case DEV_BJT:
case DEV_CAPREV:
case DEV_RSUBCKT:
case DEV_CSUBCKT:
case DEV_DSUBCKT:
case DEV_MSUBCKT:
case DEV_SUBCKT:
case DEV_VERILOGA:
case DEV_DIODE:
case DEV_NDIODE:
case DEV_PDIODE:
n = argc - argstart;
n = argc - termstart;
if ((n % 3) == 1)
{
if (strncmp(argv[argstart], "None", 4) != 0)
devtmp.dev_subsnode = efBuildDevNode(def, argv[argstart], TRUE);
if (strncmp(argv[termstart], "None", 4) != 0)
devtmp.dev_subsnode = efBuildDevNode(def, argv[termstart], TRUE);
argstart++;
termstart++;
}
break;
}
/* Between argstart and argc, we should only have terminal triples */
if (((argc - argstart) % 3) != 0)
/* Between termstart and argc, we should only have terminal triples */
if (((argc - termstart) % 3) != 0)
return 1;
nterminals = (argc - argstart) / 3;
nterminals = (argc - termstart) / 3;
dev_type = efBuildAddStr(EFDevTypes, &EFDevNumTypes, TT_MAXTYPES, type);
@ -1160,17 +1268,17 @@ efBuildDevice(def, class, type, r, argc, argv)
case DEV_ASYMMETRIC:
case DEV_BJT:
/* "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);
break;
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);
break;
case DEV_CAP:
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);
break;
@ -1180,7 +1288,7 @@ efBuildDevice(def, class, type, r, argc, argv)
#define TERM_PERIM 1
#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->dterm_node = efBuildDevNode(def, av[TERM_NAME], FALSE);
@ -1309,10 +1417,10 @@ EFGetPortMax(def)
*/
EFNode *
efBuildDevNode(def, name, isSubsNode)
Def *def;
char *name;
bool isSubsNode;
efBuildDevNode(
Def *def,
char *name,
bool isSubsNode)
{
HashEntry *he;
EFNodeName *nn;
@ -1482,6 +1590,34 @@ efBuildUse(def, subDefName, subUseId, ta, tb, tc, td, te, tf)
HashSetValue(he, (ClientData)newuse);
}
/*
* ----------------------------------------------------------------------------
*
* efConnectionFreeLinkedList --
*
* Release memory for linked-list of Connection* based on internal list
* at Connection->conn_next. 'conn' argument must be non-NULL.
*
* Results:
* Deallocates linked-list of Connection* starting at 'conn'
*
* Side effects:
* Deallocates one or more connection record(s).
*
* ----------------------------------------------------------------------------
*/
void
efConnectionFreeLinkedList(Connection *conn)
{
while (conn)
{
Connection *next = conn->conn_next;
efFreeConn(conn);
conn = next;
}
}
/*
* ----------------------------------------------------------------------------
*
@ -1516,7 +1652,25 @@ efBuildConnect(def, nodeName1, nodeName2, deltaC, av, ac)
unsigned size = sizeof (Connection)
+ (efNumResistClasses - 1) * sizeof (EFPerimArea);
if ((EFOutputFlags & EF_SHORT_MASK) != EF_SHORT_NONE)
/* If one of the nodes has been generated from the
* other by "extract unique", then this is a case where
* the "extract unique" algorithm is blind to shorts
* through subcell hierarchy and has made a name unique
* unnecessarily. In that case, merge the node instead
* of generating a short.
*/
char *uniqstr1, *uniqstr2;
bool isuniq;
uniqstr1 = strstr(nodeName1, "_uq");
uniqstr2 = strstr(nodeName2, "_uq");
if (uniqstr1) *uniqstr1 = '\0';
if (uniqstr2) *uniqstr2 = '\0';
isuniq = !strcmp(nodeName1, nodeName2);
if (uniqstr1) *uniqstr1 = '_';
if (uniqstr2) *uniqstr2 = '_';
if (!isuniq && ((EFOutputFlags & EF_SHORT_MASK) != EF_SHORT_NONE))
{
/* Handle the case where two ports on different nets get merged.
* If "extract short resistor" or "extract short voltage" has
@ -1919,8 +2073,10 @@ efNodeMerge(node1ptr, node2ptr)
if (*node1ptr == *node2ptr)
return NULL;
/* Keep the node with the greater number of entries, and merge */
/* the node with fewer entries into it. */
/*
* Keep the node with the greater number of entries, and merge
* the node with fewer entries into it.
*/
if ((*node1ptr)->efnode_num >= (*node2ptr)->efnode_num)
{
@ -1960,7 +2116,7 @@ efNodeMerge(node1ptr, node2ptr)
/* Make all EFNodeNames point to "keeping" */
if (removing->efnode_name)
{
bool topportk, topportr;
bool topportk, topportr, bestname, swapnames;
for (nn = removing->efnode_name; nn; nn = nn->efnn_next)
{
@ -1971,10 +2127,31 @@ efNodeMerge(node1ptr, node2ptr)
topportk = (keeping->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
topportr = (removing->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
/* Concatenate list of EFNodeNames, taking into account precedence */
if ((!keeping->efnode_name) || (!topportk && (topportr
|| EFHNBest(removing->efnode_name->efnn_hier,
keeping->efnode_name->efnn_hier))))
/* The node "keeping" is being kept, but we need to decide which
* node name of the two will be the node name of "keeping". If
* "keeping" has the best node name, then we're good; otherwise,
* we need to copy the name from "removing" to "keeping".
*
* Order of precedence:
* 1) If one node does not have a name, then use the name of the other.
* 2) If one node is a port and the other isn't, then use the port name.
* 3) Use the one with the preferred lexigraphical order according to
* EFHNBest().
*/
if ((!keeping->efnode_name) && (removing->efnode_name))
swapnames = TRUE;
else if ((keeping->efnode_name) && (!removing->efnode_name))
swapnames = FALSE;
else if (!topportk && topportr)
swapnames = TRUE;
else if (topportk && !topportr)
swapnames = FALSE;
else
swapnames = EFHNBest(removing->efnode_name->efnn_hier,
keeping->efnode_name->efnn_hier);
/* Concatenate list of EFNodeNames */
if (swapnames)
{
/*
* New official name is that of "removing".
@ -2061,6 +2238,14 @@ efNodeMerge(node1ptr, node2ptr)
if (removing->efnode_flags & EF_SUBS_NODE)
keeping->efnode_flags |= EF_SUBS_NODE;
/*
* If "removing" has the EF_GLOB_SUBS_NODE flag set, then copy the
* port record in the flags to "keeping".
*/
if (removing->efnode_flags & EF_GLOB_SUBS_NODE)
keeping->efnode_flags |= EF_GLOB_SUBS_NODE;
/* If EFSaveLocs is set, then merge any disjoint segments from
/* If EFSaveLocs is set, then merge any disjoint segments from
* removing to keeping.
*/
@ -2238,23 +2423,33 @@ efFreeNodeList(head, func)
EFAttr *ap;
LinkedRect *lr;
free_magic1_t mm1 = freeMagic1_init();
for (node = (EFNode *) head->efnode_next;
node != head;
node = (EFNode *) node->efnode_next)
{
for (ap = node->efnode_attrs; ap; ap = ap->efa_next)
freeMagic((char *) ap);
{
free_magic1_t mm1_ = freeMagic1_init();
for (ap = node->efnode_attrs; ap; ap = ap->efa_next)
freeMagic1(&mm1_, (char *) ap);
freeMagic1_end(&mm1_);
}
if (node->efnode_client != (ClientData)NULL)
{
if (func != NULL)
(*func)(node->efnode_client);
freeMagic((char *)node->efnode_client);
}
for (lr = node->efnode_disjoint; lr; lr = lr->r_next)
freeMagic((char *)lr);
{
free_magic1_t mm1_ = freeMagic1_init();
for (lr = node->efnode_disjoint; lr; lr = lr->r_next)
freeMagic1(&mm1_, (char *)lr);
freeMagic1_end(&mm1_);
}
freeMagic((char *) node);
freeMagic1(&mm1, (char *) node);
}
freeMagic1_end(&mm1);
}
/*

View File

@ -119,18 +119,17 @@ EFDone(func)
HashKill(&def->def_dists);
HashKill(&def->def_uses);
HashKill(&def->def_devs);
for (conn = def->def_conns; conn; conn = conn->conn_next)
efFreeConn(conn);
for (conn = def->def_caps; conn; conn = conn->conn_next)
efFreeConn(conn);
for (conn = def->def_resistors; conn; conn = conn->conn_next)
efFreeConn(conn);
efConnectionFreeLinkedList(def->def_conns);
efConnectionFreeLinkedList(def->def_caps);
efConnectionFreeLinkedList(def->def_resistors);
free_magic1_t mm1 = freeMagic1_init();
for (kill = def->def_kills; kill; kill = kill->kill_next)
{
freeMagic(kill->kill_name);
freeMagic((char *) kill);
freeMagic1(&mm1, (char *) kill);
}
freeMagic1_end(&mm1);
freeMagic((char *) def);
}
@ -157,8 +156,10 @@ EFDone(func)
while (plist != NULL)
{
freeMagic(plist->parm_name);
freeMagic(plist);
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, plist);
plist = plist->parm_next;
freeMagic1_end(&mm1);
}
}
HashKill(&efDevParamTable);

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