Compare commits

...

64 Commits

Author SHA1 Message Date
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
97 changed files with 4498 additions and 1517 deletions

View File

@ -138,6 +138,8 @@ jobs:
echo "BUILD_GCC_VERSION=$BUILD_GCC_VERSION" >> $GITHUB_ENV echo "BUILD_GCC_VERSION=$BUILD_GCC_VERSION" >> $GITHUB_ENV
echo "BUILD_CLANG_VERSION=$BUILD_CLANG_VERSION" >> $GITHUB_ENV echo "BUILD_CLANG_VERSION=$BUILD_CLANG_VERSION" >> $GITHUB_ENV
sudo apt-get update
if [ -n "$BUILD_GCC_VERSION" ] if [ -n "$BUILD_GCC_VERSION" ]
then then
GCCV=$BUILD_GCC_VERSION GCCV=$BUILD_GCC_VERSION

View File

@ -33,10 +33,22 @@ jobs:
cd emsdk cd emsdk
./emsdk install latest ./emsdk install latest
./emsdk activate 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 - name: Build
run: | run: |
source ./emsdk/emsdk_env.sh 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 =====" echo "===== defs.mak ====="
cat defs.mak cat defs.mak
echo "===== defs.mak =====" echo "===== defs.mak ====="

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 # A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs: 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: simple_build_linux:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
@ -45,10 +32,22 @@ jobs:
cd emsdk cd emsdk
./emsdk install latest ./emsdk install latest
./emsdk activate 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 - name: Build
run: | run: |
source ./emsdk/emsdk_env.sh 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 =====" echo "===== defs.mak ====="
cat defs.mak cat defs.mak
echo "===== defs.mak =====" echo "===== defs.mak ====="

View File

@ -1 +1 @@
8.3.604 8.3.636

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -779,8 +779,8 @@ CmdBox(
break; break;
case BOX_EXISTS: case BOX_EXISTS:
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
Tcl_SetResult(magicinterp, ToolGetBox(NULL, NULL) ? "1" : "0", Tcl_SetObjResult(magicinterp,
NULL); Tcl_NewBooleanObj(ToolGetBox(NULL, NULL) ? TRUE : FALSE));
#else #else
TxPrintf("%s\n", ToolGetBox(NULL, NULL) ? "True" : "False"); TxPrintf("%s\n", ToolGetBox(NULL, NULL) ? "True" : "False");
#endif #endif

View File

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

View File

@ -781,39 +781,82 @@ cmdEraseCellsFunc(
* Implement the "expand" command. * Implement the "expand" command.
* *
* Usage: * Usage:
* expand * expand [selection|surround|overlap|all] [toggle]
* expand 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: * Results:
* None. * None.
* *
* Side effects: * Side effects:
* If "toggle" is specified, flips the expanded/unexpanded status * Expansion state of cells is changed. May read cells in from
* of all selected cells. Otherwise, aren't any unexpanded cells * disk, and update bounding boxes that have changed.
* left under the box. May read cells in from disk, and updates
* 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 void
CmdExpand( CmdExpand(
MagWindow *w, MagWindow *w,
TxCommand *cmd) TxCommand *cmd)
{ {
int windowMask, boxMask, d; int windowMask, boxMask, d, option;
bool doToggle = FALSE;
const char * const *msg;
Rect rootRect; Rect rootRect;
CellUse *rootBoxUse; CellUse *rootBoxUse;
CellDef *rootBoxDef; CellDef *rootBoxDef;
int cmdExpandFunc(CellUse *use, int windowMask); /* Forward reference. */ int cmdExpandFunc(CellUse *use, int windowMask); /* Forward reference. */
if (cmd->tx_argc > 2 || (cmd->tx_argc == 2 static const char * const cmdExpandOption[] = {
&& (strncmp(cmd->tx_argv[1], "toggle", strlen(cmd->tx_argv[1])) != 0))) "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]); if (!strncmp(cmd->tx_argv[cmd->tx_argc - 1], "toggle",
return; 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); windCheckOnlyWindow(&w, DBWclientID);
if (w == (MagWindow *) NULL) if (w == (MagWindow *) NULL)
{ {
@ -844,23 +887,95 @@ CmdExpand(
WindScale(d, 1); WindScale(d, 1);
TxPrintf("expand: rescaled by %d\n", d); TxPrintf("expand: rescaled by %d\n", d);
d = DBLambda[1]; d = DBLambda[1];
if (cmd->tx_argc == 2) break; /* Don't toggle twice */ if (doToggle) break; /* Don't toggle twice */
} }
(void) ToolGetBoxWindow(&rootRect, &boxMask); (void) ToolGetBoxWindow(&rootRect, &boxMask);
if (cmd->tx_argc == 2) if (option != EXPAND_SELECTION)
SelectExpand(windowMask);
else
{ {
if ((boxMask & windowMask) != windowMask) if ((boxMask & windowMask) != windowMask)
{ {
TxError("The box isn't in the same window as the cursor.\n"); TxError("The box isn't in the same window as the cursor.\n");
return; 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]); } 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. /* This function is called for each cell whose expansion status changed.

View File

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

View File

@ -1801,13 +1801,18 @@ cmdLabelSizeFunc(
if (value == NULL) if (value == NULL)
{ {
char *labsize;
MagWindow *w;
windCheckOnlyWindow(&w, DBWclientID);
labsize = DBWPrintValue(label->lab_size / 8, w, FALSE);
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
lobj = Tcl_GetObjResult(magicinterp); lobj = Tcl_GetObjResult(magicinterp);
Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_NewStringObj(labsize, -1));
Tcl_NewDoubleObj((double)label->lab_size / 8.0));
Tcl_SetObjResult(magicinterp, lobj); Tcl_SetObjResult(magicinterp, lobj);
#else #else
TxPrintf("%g\n", (double)label->lab_size / 8.0); TxPrintf("%s\n", labsize);
#endif #endif
} }
else if (label->lab_size != *value) else if (label->lab_size != *value)
@ -1952,18 +1957,22 @@ cmdLabelOffsetFunc(
if (point == NULL) 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 #ifdef MAGIC_WRAPPER
lobj = Tcl_GetObjResult(magicinterp); lobj = Tcl_GetObjResult(magicinterp);
pobj = Tcl_NewListObj(0, NULL); pobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj, pobj); Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(laboffx, -1));
Tcl_NewDoubleObj((double)label->lab_offset.p_x / 8.0)); Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(laboffy, -1));
Tcl_ListObjAppendElement(magicinterp, pobj,
Tcl_NewDoubleObj((double)label->lab_offset.p_y / 8.0));
Tcl_SetObjResult(magicinterp, lobj); Tcl_SetObjResult(magicinterp, lobj);
#else #else
TxPrintf("%g %g\n", (double)(label->lab_offset.p_x) / 8.0, TxPrintf("%s %s\n", laboffx, laboffy);
(double)(label->lab_offset.p_y) / 8.0);
#endif #endif
} }
else if (!GEO_SAMEPOINT(label->lab_offset, *point)) else if (!GEO_SAMEPOINT(label->lab_offset, *point))
@ -2212,9 +2221,13 @@ CmdSetLabel(
} }
else if (EditCellUse) else if (EditCellUse)
{ {
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL, if (locargc == 2)
cmdLabelTextFunc, (locargc == 3) ? SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
(ClientData)cmd->tx_argv[argstart + 1] : (ClientData)NULL); cmdLabelTextFunc, (ClientData)NULL);
else
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelTextFunc,
(ClientData)cmd->tx_argv[argstart + 1]);
} }
break; break;
@ -2280,9 +2293,12 @@ CmdSetLabel(
} }
else if (EditCellUse) else if (EditCellUse)
{ {
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL, if (locargc == 2)
cmdLabelFontFunc, (locargc == 3) ? SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
(ClientData)&font : (ClientData)NULL); cmdLabelFontFunc, (ClientData)NULL);
else
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelFontFunc, (ClientData)&font);
} }
} }
break; break;
@ -2310,9 +2326,12 @@ CmdSetLabel(
} }
else if (EditCellUse) else if (EditCellUse)
{ {
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL, if (locargc == 2)
cmdLabelJustFunc, (locargc == 3) ? SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
(ClientData)&pos : (ClientData)NULL); cmdLabelJustFunc, (ClientData)NULL);
else
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelJustFunc, (ClientData)&pos);
} }
break; break;
@ -2341,9 +2360,12 @@ CmdSetLabel(
} }
else if (EditCellUse) else if (EditCellUse)
{ {
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL, if (locargc == 2)
cmdLabelSizeFunc, (locargc == 3) ? SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
(ClientData)&size : (ClientData)NULL); cmdLabelSizeFunc, (ClientData)NULL);
else
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelSizeFunc, (ClientData)&size);
} }
break; break;
@ -2393,9 +2415,12 @@ CmdSetLabel(
} }
else if (EditCellUse) else if (EditCellUse)
{ {
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL, if (locargc == 2)
cmdLabelOffsetFunc, (locargc != 2) ? SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
(ClientData)&offset : (ClientData)NULL); cmdLabelOffsetFunc, (ClientData)NULL);
else
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelOffsetFunc, (ClientData)&offset);
} }
break; break;
@ -2459,10 +2484,12 @@ CmdSetLabel(
rect.r_ytop = cmdScaleCoord(w, cmd->tx_argv[argstart + 4], rect.r_ytop = cmdScaleCoord(w, cmd->tx_argv[argstart + 4],
TRUE, FALSE, 1); TRUE, FALSE, 1);
} }
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL, if ((locargc == 3) || (locargc == 6))
cmdLabelRectFunc, SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
((locargc == 6) || (locargc == 3)) ? cmdLabelRectFunc, (ClientData)&rect);
(ClientData)&rect : (ClientData)NULL); else
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelRectFunc, (ClientData)NULL);
} }
break; break;
@ -2488,9 +2515,12 @@ CmdSetLabel(
} }
else if (EditCellUse) else if (EditCellUse)
{ {
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL, if (locargc == 2)
cmdLabelRotateFunc, (locargc == 3) ? SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
(ClientData)&rotate : (ClientData)NULL); cmdLabelRotateFunc, (ClientData)NULL);
else
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelRotateFunc, (ClientData)&rotate);
} }
break; break;
@ -2522,9 +2552,12 @@ CmdSetLabel(
} }
else if (EditCellUse) else if (EditCellUse)
{ {
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL, if (locargc == 2)
cmdLabelStickyFunc, (locargc == 3) ? SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
(ClientData)&flags : (ClientData)NULL); cmdLabelStickyFunc, (ClientData)NULL);
else
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelStickyFunc, (ClientData)&flags);
} }
break; break;
@ -2563,9 +2596,12 @@ CmdSetLabel(
} }
else if (EditCellUse) else if (EditCellUse)
{ {
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL, if (locargc == 2)
cmdLabelLayerFunc, (locargc == 3) ? SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
(ClientData)&ttype : (ClientData)NULL); cmdLabelLayerFunc, (ClientData)NULL);
else
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
cmdLabelLayerFunc, (ClientData)&ttype);
} }
break; break;
@ -2900,6 +2936,29 @@ CmdSnap(
TxPrintf("Usage: snap [internal | lambda | user]\n"); TxPrintf("Usage: snap [internal | lambda | user]\n");
return; return;
} }
/* Backwards compatibility: Use of "snap" to set units display and
* parsing has been deprecated as of February 2026. However, as this
* is rather disruptive to existing scripts which use "snap" to change
* the parsing of units, then the following measure is being taken
* (for now, anyway): If DBWUnits is set to DBW_UNITS_DEFAULT, then
* "snap internal" will set DBWUnits as well as DBWSnapToGrid. If
* DBWUnits is changed first (e.g., "units internal"), then "snap" will
* affect only the snap grid. The older usage will be accompanied by a
* warning message. Note that backwards compatibility is being kept
* only in the case of "snap internal", which was commonly used in
* scripts to make sure that all units were interpreted as internal
* units.
*/
if ((DBWUnits == DBW_UNITS_DEFAULT) && (n == SNAP_INTERNAL))
{
DBWUnits = DBW_UNITS_INTERNAL;
TxError("Warning: snap setting is also changing units. This usage "
"is deprecated\nand may be removed in the future. Use "
"\"units\" to change units, and\nchange units before "
"setting snap to keep this message from appearing.\n");
}
switch (n) switch (n)
{ {
case SNAP_OFF: case SNAP_INTERNAL: case SNAP_OFF: case SNAP_INTERNAL:

View File

@ -156,6 +156,9 @@ cmdScaleCoord(
* "snap" setting. This behavior remains in effect until the "units" * "snap" setting. This behavior remains in effect until the "units"
* command is used, in which case units follow the selected units * command is used, in which case units follow the selected units
* value indepedendently of the snap setting. * 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) if (DBWUnits == DBW_UNITS_DEFAULT)
curunits = DBWSnapToGrid; curunits = DBWSnapToGrid;
@ -163,19 +166,22 @@ cmdScaleCoord(
curunits = DBWUnits & DBW_UNITS_TYPE_MASK; curunits = DBWUnits & DBW_UNITS_TYPE_MASK;
if ((*endptr == 'l') if ((*endptr == 'l')
|| ((*endptr == '\0') && (curunits == DBW_UNITS_LAMBDA))) || (((*endptr == '\0') || isspace(*endptr))
&& (curunits == DBW_UNITS_LAMBDA)))
{ {
/* lambda or default units */ /* lambda or default units */
dval *= (double)DBLambda[1]; dval *= (double)DBLambda[1];
dval /= (double)DBLambda[0]; dval /= (double)DBLambda[0];
} }
else if ((*endptr == 'i') else if ((*endptr == 'i')
|| ((*endptr == '\0') && (curunits == DBW_UNITS_INTERNAL))) || (((*endptr == '\0') || isspace(*endptr))
&& (curunits == DBW_UNITS_INTERNAL)))
{ {
/* internal units */ /* internal units */
} }
else if ((*endptr == 'g') else if ((*endptr == 'g')
|| ((*endptr == '\0') && (curunits == DBW_UNITS_USER))) || (((*endptr == '\0') || isspace(*endptr))
&& (curunits == DBW_UNITS_USER)))
{ {
/* grid units */ /* grid units */
if (w == (MagWindow *)NULL) if (w == (MagWindow *)NULL)
@ -203,11 +209,12 @@ cmdScaleCoord(
dval += (double)crec->dbw_gridRect.r_ybot; dval += (double)crec->dbw_gridRect.r_ybot;
} }
} }
else if (*endptr == '\0' && (curunits == DBW_UNITS_MICRONS)) else if (((*endptr == '\0') || isspace(*endptr))
&& (curunits == DBW_UNITS_MICRONS))
{ {
mscale = 1000; mscale = 1000;
} }
else else if (*endptr != '\0')
{ {
/* natural units referred to the current cifoutput style */ /* natural units referred to the current cifoutput style */
if (*(endptr + 1) == 'm') if (*(endptr + 1) == 'm')
@ -249,7 +256,7 @@ cmdScaleCoord(
mscale = -1; mscale = -1;
} }
} }
if ((mscale != -1) && !isspace(*endptr)) if (mscale != -1)
dval /= CIFGetOutputScale(mscale); dval /= CIFGetOutputScale(mscale);
curval = round(dval); curval = round(dval);
@ -297,9 +304,13 @@ cmdScaleCoord(
parseop = PARSEOP_DIV; parseop = PARSEOP_DIV;
endptr++; endptr++;
break; break;
default: case ' ':
case '\t':
endptr++; endptr++;
break; break;
default:
/* Should this flag an error? */
return retval;
} }
if (parseop != PARSEOP_NONE) break; if (parseop != PARSEOP_NONE) break;
} }
@ -750,13 +761,16 @@ cmdSaveCell(
if (!tryRename || (fileName == NULL) || (strcmp(cellDef->cd_name, fileName) == 0)) if (!tryRename || (fileName == NULL) || (strcmp(cellDef->cd_name, fileName) == 0))
goto cleanup; goto cleanup;
/* Rename the cell */ /* Rename the cell, unless fileName is a .tcl file (scripted output) */
if (!DBCellRenameDef(cellDef, fileName)) if ((strlen(fileName) <= 4) || strcmp(fileName + strlen(fileName) - 4, ".tcl"))
{ {
/* This should never happen */ if (!DBCellRenameDef(cellDef, fileName))
TxError("Magic error: there is already a cell named \"%s\"\n", {
/* This should never happen */
TxError("Magic error: there is already a cell named \"%s\"\n",
fileName); fileName);
goto cleanup; goto cleanup;
}
} }
if (EditCellUse && (cellDef == EditCellUse->cu_def)) if (EditCellUse && (cellDef == EditCellUse->cu_def))
@ -1225,7 +1239,7 @@ cmdExpandOneLevel(
extern int cmdExpand1func(CellUse *cu, ClientData bitmask); extern int cmdExpand1func(CellUse *cu, ClientData bitmask);
/* first, expand this cell use */ /* 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) */ /* now, unexpand its direct children (ONE LEVEL ONLY) */
if (expand) if (expand)
@ -1237,7 +1251,7 @@ cmdExpand1func(
CellUse *cu, CellUse *cu,
ClientData bitmask) ClientData bitmask)
{ {
DBExpand(cu, (int)CD2INT(bitmask), FALSE); DBExpand(cu, (int)CD2INT(bitmask), DB_UNEXPAND);
return 0; return 0;
} }

View File

@ -702,32 +702,62 @@ CmdTool(
* Implement the "unexpand" command. * Implement the "unexpand" command.
* *
* Usage: * 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: * Results:
* None. * None.
* *
* Side effects: * Side effects:
* Unexpands all cells under the box that don't completely * Changes the expansion state of cells.
* contain the box.
* *
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
#define UNEXPAND_SELECTION 0
#define UNEXPAND_SURROUND 1
#define UNEXPAND_OVERLAP 2
#define UNEXPAND_ALL 3
#define UNEXPAND_HELP 4
void void
CmdUnexpand( CmdUnexpand(
MagWindow *w, MagWindow *w,
TxCommand *cmd) TxCommand *cmd)
{ {
int windowMask, boxMask; int windowMask, boxMask, option;
const char * const *msg;
Rect rootRect; Rect rootRect;
int cmdUnexpandFunc(CellUse *use, int windowMask); /* Forward reference. */ 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]); option = Lookup(cmd->tx_argv[1], cmdUnexpandOption);
return; if (option < 0) option = UNEXPAND_HELP;
} }
else
option = UNEXPAND_SURROUND;
if (option == UNEXPAND_HELP) goto badusage;
windCheckOnlyWindow(&w, DBWclientID); windCheckOnlyWindow(&w, DBWclientID);
if (w == (MagWindow *) NULL) if (w == (MagWindow *) NULL)
@ -743,8 +773,42 @@ CmdUnexpand(
TxError("The box isn't in the same window as the cursor.\n"); TxError("The box isn't in the same window as the cursor.\n");
return; 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. /* This function is called for each cell whose expansion status changed.

View File

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

View File

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

View File

@ -152,10 +152,9 @@ DBCellRename(cellname, newname, doforce)
if (doforce && ((celldef->cd_flags & CDVENDORGDS) == CDVENDORGDS)) if (doforce && ((celldef->cd_flags & CDVENDORGDS) == CDVENDORGDS))
{ {
char *chkgdsfile;
bool isReadOnly; bool isReadOnly;
chkgdsfile = (char *)DBPropGet(celldef, "GDS_FILE", &isReadOnly); DBPropGet(celldef, "GDS_FILE", &isReadOnly);
/* Note that clearing GDS_FILE will also clear CDVENDORGDS flag */ /* Note that clearing GDS_FILE will also clear CDVENDORGDS flag */
if (isReadOnly) DBPropPut(celldef, "GDS_FILE", NULL); if (isReadOnly) DBPropPut(celldef, "GDS_FILE", NULL);
@ -1620,6 +1619,7 @@ dbAbutmentUseFunc(selUse, use, transform, data)
{ {
Rect bbox, refbox; Rect bbox, refbox;
Transform *trans; Transform *trans;
PropertyRecord *proprec;
char *propvalue; char *propvalue;
char *refllx, *reflly, *refurx, *refury; char *refllx, *reflly, *refurx, *refury;
bool found; bool found;
@ -1643,14 +1643,25 @@ dbAbutmentUseFunc(selUse, use, transform, data)
} }
trans = &use->cu_transform; trans = &use->cu_transform;
propvalue = (char *)DBPropGet(use->cu_def, "FIXED_BBOX", &found); proprec = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
if (!found) if (!found)
bbox = use->cu_def->cd_bbox; bbox = use->cu_def->cd_bbox;
else else
{ {
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot, if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
&bbox.r_xtop, &bbox.r_ytop) != 4) (proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
}
else
{
TxError("Unable to parse the cell's FIXED_BBOX property; using "
"the instance bounding box instead.\n");
bbox = use->cu_def->cd_bbox; bbox = use->cu_def->cd_bbox;
}
} }
GeoTransRect(trans, &bbox, &refbox); GeoTransRect(trans, &bbox, &refbox);

View File

@ -588,6 +588,25 @@ DBTreeSrLabels(scx, mask, xMask, tpath, flags, func, cdarg)
if (!DBCellRead(def, TRUE, TRUE, NULL)) if (!DBCellRead(def, TRUE, TRUE, NULL))
return 0; 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) for (lab = def->cd_labels; lab; lab = lab->lab_next)
{ {
if (SigInterruptPending) break; if (SigInterruptPending) break;
@ -640,6 +659,8 @@ DBTreeSrLabels(scx, mask, xMask, tpath, flags, func, cdarg)
return (1); return (1);
} }
if (flags & TF_LABEL_REVERSE_SEARCH) return 0; /* children already searched */
filter.tf_func = func; filter.tf_func = func;
filter.tf_arg = cdarg; filter.tf_arg = cdarg;
filter.tf_mask = mask; filter.tf_mask = mask;
@ -711,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. */ /* Apply the function first to any of the labels in this def. */
result = 0; result = 0;
@ -732,9 +763,11 @@ dbCellLabelSrFunc(scx, fp)
} }
} }
/* Now visit each child use recursively */ /* Now visit each child use recursively, if not doing a reverse search */
if (DBCellSrArea(scx, dbCellLabelSrFunc, (ClientData) fp))
result = 1; if (!(fp->tf_flags & TF_LABEL_REVERSE_SEARCH))
if (DBCellSrArea(scx, dbCellLabelSrFunc, (ClientData) fp))
result = 1;
cleanup: cleanup:
/* Remove the trailing pathname component from the TerminalPath */ /* Remove the trailing pathname component from the TerminalPath */
@ -1713,7 +1746,7 @@ dbTileMoveFunc(tile, dinfo, mvvals)
if (IsSplit(tile)) if (IsSplit(tile))
type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile); type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
DBNMPaintPlane(mvvals->ptarget, exact, &targetRect, DBNMPaintPlane(mvvals->ptarget, exact, &targetRect,
DBStdPaintTbl(type, mvvals->pnum), (mvvals->pnum < 0) ? CIFPaintTable : DBStdPaintTbl(type, mvvals->pnum),
(PaintUndoInfo *)NULL); (PaintUndoInfo *)NULL);
return 0; return 0;
} }
@ -1806,84 +1839,48 @@ typedef struct _cellpropstruct {
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
int dbScaleProp(name, value, cps) int dbScaleProp(name, proprec, cps)
char *name; char *name;
char *value; PropertyRecord *proprec;
CellPropStruct *cps; CellPropStruct *cps;
{ {
int scalen, scaled; int i, scalen, scaled;
char *newvalue, *vptr; Point p;
Rect r;
if ((strlen(name) > 5) && !strncmp(name + strlen(name) - 5, "_BBOX", 5)) /* Only "dimension" and "plane" type properties get scaled */
if (proprec->prop_type == PROPERTY_TYPE_PLANE)
{ {
if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot, Plane *newplane;
&r.r_xtop, &r.r_ytop) == 4) newplane = DBNewPlane((ClientData)TT_SPACE);
{ DBClearPaintPlane(newplane);
/* Scale numerator held in point X value, */ /* Plane index is unused; arbitrarily substitute -1 */
/* scale denominator held in point Y value */ dbScalePlane(proprec->prop_value.prop_plane, newplane, -1,
scalen, scaled, TRUE);
scalen = cps->cps_point.p_x; DBFreePaintPlane(proprec->prop_value.prop_plane);
scaled = cps->cps_point.p_y; TiFreePlane(proprec->prop_value.prop_plane);
proprec->prop_value.prop_plane = newplane;
DBScalePoint(&r.r_ll, scalen, scaled); return 0;
DBScalePoint(&r.r_ur, scalen, scaled);
newvalue = (char *)mallocMagic(40);
sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot,
r.r_xtop, r.r_ytop);
DBPropPut(cps->cps_def, name, newvalue);
}
} }
else if (!strncmp(name, "MASKHINTS_", 10))
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
/* Scale numerator held in point X value, */
/* scale denominator held in point Y value */
scalen = cps->cps_point.p_x;
scaled = cps->cps_point.p_y;
for (i = 0; i < proprec->prop_len; i += 2)
{ {
char *vptr, *lastval; if ((i + 1) >= proprec->prop_len) break;
int lastlen;
newvalue = (char *)NULL; p.p_x = proprec->prop_value.prop_integer[i];
vptr = value; p.p_y = proprec->prop_value.prop_integer[i + 1];
while (*vptr != '\0') DBScalePoint(&p, scalen, scaled);
{ proprec->prop_value.prop_integer[i] = p.p_x;
if (sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot, proprec->prop_value.prop_integer[i + 1] = p.p_y;
&r.r_xtop, &r.r_ytop) == 4)
{
/* Scale numerator held in point X value, */
/* scale denominator held in point Y value */
scalen = cps->cps_point.p_x;
scaled = cps->cps_point.p_y;
DBScalePoint(&r.r_ll, scalen, scaled);
DBScalePoint(&r.r_ur, scalen, scaled);
lastval = newvalue;
lastlen = (lastval) ? strlen(lastval) : 0;
newvalue = mallocMagic(40 + lastlen);
if (lastval)
strcpy(newvalue, lastval);
else
*newvalue = '\0';
sprintf(newvalue + lastlen, "%s%d %d %d %d", (lastval) ? " " : "",
r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
if (lastval) freeMagic(lastval);
/* Parse through the four values and check if there's more */
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
}
else break;
}
if (newvalue)
DBPropPut(cps->cps_def, name, newvalue);
} }
return 0; /* Keep enumerating through properties */ return 0; /* Keep enumerating through properties */
} }
@ -1899,33 +1896,47 @@ int dbScaleProp(name, value, cps)
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
int dbMoveProp(name, value, cps) int dbMoveProp(name, proprec, cps)
char *name; char *name;
char *value; PropertyRecord *proprec;
CellPropStruct *cps; CellPropStruct *cps;
{ {
int origx, origy; int i, origx, origy;
char *newvalue; char *newvalue;
Rect r; Point p;
if (((strlen(name) > 5) && !strncmp(name + strlen(name) - 5, "_BBOX", 5)) /* Only "dimension" and "plane" type properties get scaled */
|| !strncmp(name, "MASKHINTS_", 10))
if (proprec->prop_type == PROPERTY_TYPE_PLANE)
{ {
if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot, Plane *newplane;
&r.r_xtop, &r.r_ytop) == 4)
{
origx = cps->cps_point.p_x;
origy = cps->cps_point.p_y;
DBMovePoint(&r.r_ll, origx, origy); newplane = DBNewPlane((ClientData) TT_SPACE);
DBMovePoint(&r.r_ur, origx, origy); DBClearPaintPlane(newplane);
/* Use plane index -1 to indicate use of CIFPaintTable */
newvalue = (char *)mallocMagic(40); dbMovePlane(proprec->prop_value.prop_plane, newplane, -1, origx, origy);
sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot, DBFreePaintPlane(proprec->prop_value.prop_plane);
r.r_xtop, r.r_ytop); TiFreePlane(proprec->prop_value.prop_plane);
DBPropPut(cps->cps_def, name, newvalue); proprec->prop_value.prop_plane = newplane;
} return 0;
} }
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
origx = cps->cps_point.p_x;
origy = cps->cps_point.p_y;
for (i = 0; i < proprec->prop_len; i += 2)
{
if ((i + 1) >= proprec->prop_len) break;
p.p_x = proprec->prop_value.prop_integer[i];
p.p_y = proprec->prop_value.prop_integer[i + 1];
DBMovePoint(&p, origx, origy);
proprec->prop_value.prop_integer[i] = p.p_x;
proprec->prop_value.prop_integer[i + 1] = p.p_y;
}
return 0; /* Keep enumerating through properties */ return 0; /* Keep enumerating through properties */
} }

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -651,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_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_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_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 */ /* To do: Make the tpath entries dynamically allocated */
#define FLATTERMSIZE 4096 /* Used for generating flattened labels */ #define FLATTERMSIZE 4096 /* Used for generating flattened labels */
@ -704,6 +705,25 @@ struct conSrArg2
#define CSA2_LIST_SIZE 65536 /* Number of entries per list */ #define CSA2_LIST_SIZE 65536 /* Number of entries per list */
/* ------------------------ Properties ------------------------------ */
/* Note that the property record is a single allocated block large enough
* to hold the string or integer list, and can be freed as a single block.
* The array bounds, like those of lab_text for labels, are placeholders.
*/
typedef struct
{
int prop_type; /* See codes below; e.g., PROPERTY_TYPE_STRING */
int prop_len; /* String length or number of values */
union {
char prop_string[8]; /* For PROPERTY_TYPE_STRING */
int prop_integer[2]; /* For PROPERTY_TYPE_INTEGER or _DIMENSION */
dlong prop_double[1]; /* For PROPERTY_TYPE_DOUBLE */
Plane *prop_plane; /* For PROPERTY_TYPE_PLANE */
} prop_value;
} PropertyRecord;
/* -------------- Undo information passed to DBPaintPlane ------------- */ /* -------------- Undo information passed to DBPaintPlane ------------- */
typedef struct typedef struct
@ -736,6 +756,14 @@ typedef struct
#define PAINT_MARK 1 /* Mark tiles that are painted */ #define PAINT_MARK 1 /* Mark tiles that are painted */
#define PAINT_XOR 2 /* Use with XOR function to prevent double-painting */ #define PAINT_XOR 2 /* Use with XOR function to prevent double-painting */
/* ---------------------- Codes for properties -------------------------*/
#define PROPERTY_TYPE_STRING 0 /* ASCII string property */
#define PROPERTY_TYPE_INTEGER 1 /* Fixed integer property */
#define PROPERTY_TYPE_DIMENSION 2 /* Integer property that scales with units */
#define PROPERTY_TYPE_DOUBLE 3 /* Double-long integer (for file positions) */
#define PROPERTY_TYPE_PLANE 4 /* A tile plane structure */
/* -------------------- Exported procedure headers -------------------- */ /* -------------------- Exported procedure headers -------------------- */
/* Painting/erasing */ /* Painting/erasing */
@ -921,7 +949,9 @@ extern void DBFreePaintPlane();
/* Cell properties */ /* Cell properties */
extern void DBPropPut(); extern void DBPropPut();
extern ClientData DBPropGet(); extern PropertyRecord *DBPropGet();
extern char *DBPropGetString();
extern dlong DBPropGetDouble();
extern int DBPropEnum(); extern int DBPropEnum();
extern void DBPropClearAll(); extern void DBPropClearAll();
@ -1019,6 +1049,7 @@ extern int DBLambda[2];
/* -------------------- Exported magic file suffix -------------------- */ /* -------------------- Exported magic file suffix -------------------- */
extern char *DBSuffix; /* Suffix appended to all Magic cell names */ extern char *DBSuffix; /* Suffix appended to all Magic cell names */
extern bool DBPropCompat; /* Backwards-compatible properties */
/* -------------------- User Interface Stuff -------------------------- */ /* -------------------- User Interface Stuff -------------------------- */
@ -1031,6 +1062,19 @@ extern unsigned char DBVerbose; /* If 0, don't print any messages */
#define DB_VERBOSE_WARN 2 #define DB_VERBOSE_WARN 2
#define DB_VERBOSE_ALL 3 #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 ------------------- */ /* ------------------ Exported technology variables ------------------- */
/*** /***

View File

@ -131,8 +131,11 @@ DBWAddButtonHandler(
for (i = 0; i < MAXBUTTONHANDLERS; i++) for (i = 0; i < MAXBUTTONHANDLERS; i++)
{ {
if (dbwButtonHandlers[i] != NULL) continue; if (dbwButtonHandlers[i] != NULL) continue;
(void) StrDup(&dbwButtonHandlers[i], name); StrDup(&dbwButtonHandlers[i], name);
(void) StrDup(&dbwButtonDoc[i], doc); if (doc != NULL)
StrDup(&dbwButtonDoc[i], doc);
else
dbwButtonDoc[i] = (char *)NULL;
dbwButtonProcs[i] = proc; dbwButtonProcs[i] = proc;
dbwButtonCursors[i] = cursor; dbwButtonCursors[i] = cursor;
return; return;
@ -273,6 +276,37 @@ DBWGetButtonHandler()
return dbwButtonHandlers[dbwButtonCurrentIndex]; 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;
}
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -294,7 +328,10 @@ DBWGetButtonHandler()
void void
DBWPrintButtonDoc() DBWPrintButtonDoc()
{ {
TxPrintf("%s", dbwButtonDoc[dbwButtonCurrentIndex]); if (dbwButtonDoc[dbwButtonCurrentIndex])
TxPrintf("%s", dbwButtonDoc[dbwButtonCurrentIndex]);
else
TxPrintf("(no usage information)\n");
} }

View File

@ -421,7 +421,8 @@ DBWredisplay(w, rootArea, clipArea)
/* Set style information beforehand */ /* Set style information beforehand */
GrSetStuff(STYLE_LABEL); GrSetStuff(STYLE_LABEL);
(void) DBTreeSrLabels(&scontext, &DBAllTypeBits, bitMask, (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)); dbwLabelFunc, (ClientData)(&crec->dbw_visibleLayers));
GrClipTo(&rootClip); GrClipTo(&rootClip);
} }

View File

@ -546,12 +546,12 @@ DBWloadWindow(window, name, flags)
newEditUse = DBCellNewUse(newEditDef, (char *) NULL); newEditUse = DBCellNewUse(newEditDef, (char *) NULL);
(void) StrDup(&(newEditUse->cu_id), "Topmost cell in the window"); (void) StrDup(&(newEditUse->cu_id), "Topmost cell in the window");
DBExpand(newEditUse, DBExpand(newEditUse,
((DBWclientRec *)window->w_clientData)->dbw_bitmask, TRUE); ((DBWclientRec *)window->w_clientData)->dbw_bitmask, DB_EXPAND);
if (expand) if (expand)
DBExpandAll(newEditUse, &(newEditUse->cu_bbox), DBExpandAll(newEditUse, &(newEditUse->cu_bbox),
((DBWclientRec *)window->w_clientData)->dbw_bitmask, ((DBWclientRec *)window->w_clientData)->dbw_bitmask,
FALSE, UnexpandFunc, DB_UNEXPAND, UnexpandFunc,
INT2CD(((DBWclientRec *)window->w_clientData)->dbw_bitmask)); INT2CD(((DBWclientRec *)window->w_clientData)->dbw_bitmask));
if (newEdit) if (newEdit)

View File

@ -152,6 +152,7 @@ extern void DBWAddButtonHandler(const char *name, const cb_database_buttonhandle
int cursor, const char *doc); int cursor, const char *doc);
extern char *DBWGetButtonHandler(); extern char *DBWGetButtonHandler();
extern char *DBWChangeButtonHandler(); extern char *DBWChangeButtonHandler();
extern int DBWButtonHandlerIndex();
extern void DBWPrintButtonDoc(); extern void DBWPrintButtonDoc();
extern void DBWBoxHandler(); extern void DBWBoxHandler();

View File

@ -71,12 +71,15 @@ Operations on cell definitions.
<DT> <B>rename</B> <I>name newname</I> <DT> <B>rename</B> <I>name newname</I>
<DD> Change the name of the cell definition <I>name</I> to <DD> Change the name of the cell definition <I>name</I> to
<I>newname</I>. <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 <DD> Delete the cell definition with name <I>name</I>. If cell
<I>name</I> is a descendent of another cell, the command <I>name</I> is a descendent of another cell, the command
will be prohibited. If the cell <I>name</I> is currently will be prohibited. If the cell <I>name</I> is currently
the topmost cell in the window, the window will be loaded 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> <DT> <B>dereference</B> <I>name</I>
<DD> Perform a flush of the cell (per the "<B>flush</B>" command), <DD> Perform a flush of the cell (per the "<B>flush</B>" command),
first removing any file path associated with the cell, so first removing any file path associated with the cell, so

View File

@ -26,7 +26,8 @@ expanded/unexpanded cells in the current selection.
<H3>Usage:</H3> <H3>Usage:</H3>
<BLOCKQUOTE> <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> </BLOCKQUOTE>
<H3>Shortcuts:</H3> <H3>Shortcuts:</H3>
@ -38,14 +39,32 @@ expanded/unexpanded cells in the current selection.
<H3>Summary:</H3> <H3>Summary:</H3>
<BLOCKQUOTE> <BLOCKQUOTE>
The <B>expand</B> command expands the view of subcells to The <B>expand</B> command expands the view of subcells to
display the contents of the subcells. Without arguments, display the contents of the subcells.
the <B>expand</B> command expands all unexpanded subcells that
touch or intersect the cursor box in the layout window. <P> 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> </BLOCKQUOTE>
<H3>Implementation Notes:</H3> <H3>Implementation Notes:</H3>

View File

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

View File

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

View File

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

View File

@ -25,7 +25,8 @@ Unexpand everything inside or touching the cursor box.
<H3>Usage:</H3> <H3>Usage:</H3>
<BLOCKQUOTE> <BLOCKQUOTE>
<B>unexpand</B> <BR><BR> <B>unexpand</B> [<B>selection</B>|<B>surround</B>|<B>overlap</B>|<B>all</B>]
<BR><BR>
</BLOCKQUOTE> </BLOCKQUOTE>
<H3>Shortcuts:</H3> <H3>Shortcuts:</H3>
@ -37,8 +38,23 @@ Unexpand everything inside or touching the cursor box.
<BLOCKQUOTE> <BLOCKQUOTE>
The <B>unexpand</B> command unexpands the view of subcells to The <B>unexpand</B> command unexpands the view of subcells to
hide the contents of the subcells and show the bounding box hide the contents of the subcells and show the bounding box
outline only. The <B>unexpand</B> command unexpands all subcells outline only.
that touch or intersect the cursor box in the layout window. <P>
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> </BLOCKQUOTE>
<H3>Implementation Notes:</H3> <H3>Implementation Notes:</H3>

View File

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

View File

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

View File

@ -27,6 +27,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include <stdio.h> #include <stdio.h>
#include <string.h> // for memcpy() #include <string.h> // for memcpy()
#include <math.h> // for sqrt() for diagonal check #include <math.h> // for sqrt() for diagonal check
#include "tcltk/tclmagic.h"
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "tiles/tile.h" #include "tiles/tile.h"
@ -36,7 +38,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/signals.h" #include "utils/signals.h"
#include "utils/maxrect.h" #include "utils/maxrect.h"
#include "utils/malloc.h" #include "utils/malloc.h"
#include "utils/undo.h"
#include "textio/textio.h" #include "textio/textio.h"
#include "cif/CIFint.h"
int dbDRCDebug = 0; int dbDRCDebug = 0;
@ -48,7 +52,7 @@ int dbDRCDebug = 0;
static DRCCookie drcOverlapCookie = { static DRCCookie drcOverlapCookie = {
0, 0, 0, 0, 0, 0, 0, 0,
{ {0} }, { {0} }, { {0} }, { {0} },
0, 0, 0, 0, DRC_EXCEPTION_NONE, 0, 0,
DRC_OVERLAP_TAG, DRC_OVERLAP_TAG,
(DRCCookie *) NULL (DRCCookie *) NULL
}; };
@ -62,7 +66,33 @@ extern MaxRectsData *drcCanonicalMaxwidth();
/* /*
*----------------------------------------------------------------------- *-----------------------------------------------------------------------
* *
* drcCifPointToSegment * drcFoundOneFunc --
*
* Simple callback for a plane search on a mask-hint plane inside
* a DRC check area.
*
* Results:
* Return 1 always, indicating that a tile has been found in the
* DRC search area, and the search can end.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------
*/
int
drcFoundOneFunc(Tile *tile,
TileType dinfo,
ClientData cdata)
{
return 1;
}
/*
*-----------------------------------------------------------------------
*
* drcCifPointToSegment --
* *
* Euclidean-distance point-to-segment distance (squared) * Euclidean-distance point-to-segment distance (squared)
* calculation (borrowed from XCircuit) * calculation (borrowed from XCircuit)
@ -468,6 +498,26 @@ DRCBasicCheck (celldef, checkRect, clipRect, function, cdata)
DBResetTilePlane(celldef->cd_planes[planeNum], DRC_UNPROCESSED); DBResetTilePlane(celldef->cd_planes[planeNum], DRC_UNPROCESSED);
(void) DBSrPaintArea ((Tile *) NULL, celldef->cd_planes[planeNum], (void) DBSrPaintArea ((Tile *) NULL, celldef->cd_planes[planeNum],
checkRect, &DBAllTypeBits, drcTile, (ClientData) &arg); checkRect, &DBAllTypeBits, drcTile, (ClientData) &arg);
#ifdef MAGIC_WRAPPER
/* Execute pending Tcl events, so the DRC process doesn't block. */
/* 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); drcCifCheck(&arg);
if (arg.dCD_rlist != NULL) freeMagic(arg.dCD_rlist); if (arg.dCD_rlist != NULL) freeMagic(arg.dCD_rlist);
@ -727,6 +777,44 @@ drcTile (tile, dinfo, arg)
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL; for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
cptr = cptr->drcc_next) cptr = cptr->drcc_next)
{ {
/* Handle rule exceptions and exemptions */
if (cptr->drcc_exception != 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 */ /* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
/* the code above for non-Manhattan shapes and do not */ /* the code above for non-Manhattan shapes and do not */
/* need to be processed again. */ /* need to be processed again. */
@ -1136,6 +1224,44 @@ drcTile (tile, dinfo, arg)
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL; for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
cptr = cptr->drcc_next) cptr = cptr->drcc_next)
{ {
/* Handle rule exceptions and exemptions */
if (cptr->drcc_exception != 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 */ /* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
/* the code above for non-Manhattan shapes and do not */ /* the code above for non-Manhattan shapes and do not */
/* need to be processed again. */ /* need to be processed again. */

View File

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

View File

@ -72,6 +72,12 @@ static int drcRulesOptimized = 0;
static int DRCtag = 0; static int DRCtag = 0;
/* Keep track of what rule exemption or exception is in effect
* while reading the DRC tech file section.
*/
static unsigned char drcCurException = DRC_EXCEPTION_NONE;
/* /*
* Forward declarations. * Forward declarations.
*/ */
@ -79,6 +85,7 @@ int drcWidth(), drcSpacing(), drcEdge(), drcNoOverlap();
int drcExactOverlap(), drcExtend(); int drcExactOverlap(), drcExtend();
int drcSurround(), drcRectOnly(), drcOverhang(); int drcSurround(), drcRectOnly(), drcOverhang();
int drcStepSize(), drcOption(), drcOffGrid(); int drcStepSize(), drcOption(), drcOffGrid();
int drcException(), drcExemption();
int drcMaxwidth(), drcArea(), drcRectangle(), drcAngles(); int drcMaxwidth(), drcArea(), drcRectangle(), drcAngles();
int drcCifSetStyle(), drcCifWidth(), drcCifSpacing(); int drcCifSetStyle(), drcCifWidth(), drcCifSpacing();
int drcCifMaxwidth(), drcCifArea(); int drcCifMaxwidth(), drcCifArea();
@ -301,6 +308,12 @@ drcTechFreeStyle()
/* Clear the Why string list */ /* Clear the Why string list */
freeMagic(DRCCurStyle->DRCWhyList); freeMagic(DRCCurStyle->DRCWhyList);
/* Clear the exception list */
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
freeMagic(DRCCurStyle->DRCExceptionList[i]);
if (DRCCurStyle->DRCExceptionList != (char **)NULL)
freeMagic(DRCCurStyle->DRCExceptionList);
freeMagic(DRCCurStyle); freeMagic(DRCCurStyle);
DRCCurStyle = NULL; DRCCurStyle = NULL;
} }
@ -384,6 +397,63 @@ drcWhyCreate(whystring)
return DRCCurStyle->DRCWhySize; return DRCCurStyle->DRCWhySize;
} }
/*
* ----------------------------------------------------------------------------
* drcExceptionCreate --
*
* Create an entry for a DRC rule exception/exemption type, if it does
* not already exist.
*
* Results:
* The index of the exception (which is 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;
}
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -571,6 +641,8 @@ DRCTechStyleInit()
DRCCurStyle->DRCStepSize = 0; DRCCurStyle->DRCStepSize = 0;
DRCCurStyle->DRCFlags = (char)0; DRCCurStyle->DRCFlags = (char)0;
DRCCurStyle->DRCWhySize = 0; DRCCurStyle->DRCWhySize = 0;
DRCCurStyle->DRCExceptionList = (char **)NULL;
DRCCurStyle->DRCExceptionSize = 0;
HashInit(&DRCWhyErrorTable, 16, HT_STRINGKEYS); HashInit(&DRCWhyErrorTable, 16, HT_STRINGKEYS);
@ -663,6 +735,7 @@ DRCTechStyleInit()
} }
drcCifInit(); drcCifInit();
drcCurException = DRC_EXCEPTION_NONE;
} }
/* /*
@ -955,6 +1028,7 @@ drcCifAssign(cookie, dist, next, mask, corner, tag, cdist, flags, planeto, plane
(cookie)->drcc_plane = planeto; (cookie)->drcc_plane = planeto;
(cookie)->drcc_mod = 0; (cookie)->drcc_mod = 0;
(cookie)->drcc_cmod = 0; (cookie)->drcc_cmod = 0;
(cookie)->drcc_exception = drcCurException;
} }
// This is like drcCifAssign, but checks for bad plane numbers in planeto and // This is like drcCifAssign, but checks for bad plane numbers in planeto and
@ -1031,50 +1105,37 @@ DRCTechAddRule(sectionName, argc, argv)
int (*rk_proc)(); /* Procedure implementing this keyword */ int (*rk_proc)(); /* Procedure implementing this keyword */
const char *rk_err; /* Error message */ const char *rk_err; /* Error message */
} ruleKeys[] = { } ruleKeys[] = {
{"angles", 4, 4, drcAngles, {"angles", 4, 4, drcAngles, "layers 45|90 why"},
"layers 45|90 why"},
{"edge", 8, 10, drcEdge, {"edge", 8, 10, drcEdge,
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"}, "layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
{"edge4way", 8, 10, drcEdge, {"edge4way", 8, 10, drcEdge,
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"}, "layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
{"exact_overlap", 2, 2, drcExactOverlap, {"exact_overlap", 2, 2, drcExactOverlap, "layers"},
"layers"}, {"exception", 2, 2, drcException, "name"},
{"exemption", 2, 2, drcExemption, "name"},
{"extend", 5, 6, drcExtend, {"extend", 5, 6, drcExtend,
"layers1 layers2 distance [option] why"}, "layers1 layers2 distance [option] why"},
{"no_overlap", 3, 3, drcNoOverlap, {"no_overlap", 3, 3, drcNoOverlap, "layers1 layers2"},
"layers1 layers2"}, {"option", 2, 2, drcOption, "option_name option_value"},
{"option", 2, 2, drcOption, {"overhang", 5, 5, drcOverhang, "layers1 layers2 distance why"},
"option_name option_value"}, {"rect_only", 3, 3, drcRectOnly, "layers why"},
{"overhang", 5, 5, drcOverhang,
"layers1 layers2 distance why"},
{"rect_only", 3, 3, drcRectOnly,
"layers why"},
{"spacing", 6, 7, drcSpacing, {"spacing", 6, 7, drcSpacing,
"layers1 layers2 separation [layers3] adjacency why"}, "layers1 layers2 separation [layers3] adjacency why"},
{"stepsize", 2, 2, drcStepSize, {"stepsize", 2, 2, drcStepSize, "step_size"},
"step_size"},
{"surround", 6, 7, drcSurround, {"surround", 6, 7, drcSurround,
"layers1 layers2 distance presence why"}, "layers1 layers2 distance presence why"},
{"width", 4, 5, drcWidth, {"width", 4, 5, drcWidth, "layers width why"},
"layers width why"},
{"widespacing", 7, 8, drcSpacing, {"widespacing", 7, 8, drcSpacing,
"layers1 width layers2 separation adjacency why"}, "layers1 width layers2 separation adjacency why"},
{"area", 5, 5, drcArea, {"area", 5, 5, drcArea, "layers area horizon why"},
"layers area horizon why"}, {"off_grid", 4, 4, drcOffGrid, "layers pitch why"},
{"off_grid", 4, 4, drcOffGrid, {"maxwidth", 4, 6, drcMaxwidth, "layers maxwidth bends why"},
"layers pitch why"}, {"cifstyle", 2, 2, drcCifSetStyle, "cif_style"},
{"maxwidth", 4, 6, drcMaxwidth, {"cifwidth", 4, 4, drcCifWidth, "layers width why"},
"layers maxwidth bends why"},
{"cifstyle", 2, 2, drcCifSetStyle,
"cif_style"},
{"cifwidth", 4, 4, drcCifWidth,
"layers width why"},
{"cifspacing", 6, 6, drcCifSpacing, {"cifspacing", 6, 6, drcCifSpacing,
"layers1 layers2 separation adjacency why"}, "layers1 layers2 separation adjacency why"},
{"cifarea", 5, 5, drcCifArea, {"cifarea", 5, 5, drcCifArea, "layers area horizon why"},
"layers area horizon why"}, {"cifmaxwidth", 5, 5, drcCifMaxwidth, "layers maxwidth bends why"},
{"cifmaxwidth", 5, 5, drcCifMaxwidth,
"layers maxwidth bends why"},
{"rectangle", 5, 5, drcRectangle, {"rectangle", 5, 5, drcRectangle,
"layers maxwidth [even|odd|any] why"}, "layers maxwidth [even|odd|any] why"},
{0} {0}
@ -1695,7 +1756,7 @@ drcMaxwidth(argc, argv)
if (PlaneMaskHasPlane(pmask2, plane2)) if (PlaneMaskHasPlane(pmask2, plane2))
break; break;
if (plane2 == plane) if (PlaneMaskHasPlane(pmask, plane2))
TechError("Warning: Exclude types for \"maxwidth\" are on the " TechError("Warning: Exclude types for \"maxwidth\" are on the "
"same plane and so cannot be checked.\n"); "same plane and so cannot be checked.\n");
} }
@ -3634,6 +3695,84 @@ drcRectangle(argc, argv)
return maxwidth; return maxwidth;
} }
/*
* ----------------------------------------------------------------------------
*
* drcException, drcExemption --
*
* Process a DRC exception declaration
* This is of the form:
*
* exception exception_name|none
* or
* exemption exemption_name|none
*
* e.g,
*
* exception SRAM
* exemption SRAM
*
* The exception_name or exemption_name is the suffix part of a MASKHINTS_*
* property name; e.g., the name SRAM corresponds to a property called
* MASKHINTS_SRAM. This declaration is followed by a block of DRC rules
* that are subject to the exception or the exemption. An exception is the
* opposite of an exemption: If a rule is excepted, then the rule applies
* within areas delineated by bounding boxes defined by the
* MASKHINTS_<exception_name> property. If a rule is exempted, then the
* rule applies only outside of areas delineated by bounding boxes defined
* by the MASKHINTS_<exemption_name> property. The block of rules subject
* to the exemption or exception ends with another exception or exemption
* declaration. If the following rules are not to be excepted or exempted
* at all, then use "exception none" or "exemption none".
*
* Results:
* Returns 0.
*
* Side effects:
* Updates drcCurException. drcCurException 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);
}
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -4119,6 +4258,7 @@ drcTechFinalStyle(style)
if (dp->drcc_dist > next->drcc_dist) continue; if (dp->drcc_dist > next->drcc_dist) continue;
if (dp->drcc_cdist > next->drcc_cdist) continue; if (dp->drcc_cdist > next->drcc_cdist) continue;
if (dp->drcc_plane != next->drcc_plane) continue; if (dp->drcc_plane != next->drcc_plane) continue;
if (dp->drcc_exception != next->drcc_exception) continue;
if (dp->drcc_flags & DRC_REVERSE) if (dp->drcc_flags & DRC_REVERSE)
{ {
if (!(next->drcc_flags & DRC_REVERSE)) continue; if (!(next->drcc_flags & DRC_REVERSE)) continue;

View File

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

View File

@ -634,7 +634,7 @@ subcktHierVisit(
if (hasports || is_top) if (hasports || is_top)
return subcktVisit(use, hierName, is_top); return subcktVisit(use, hierName, is_top);
else if (def->def_flags & DEF_NODEVICES) else if ((def->def_flags & DEF_NODEVICES) && (!isStub))
return 0; return 0;
else else
return subcktVisit(use, hierName, is_top); return subcktVisit(use, hierName, is_top);
@ -1088,6 +1088,7 @@ spcdevHierVisit(
if (!has_model) if (!has_model)
{ {
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap); esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE); spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
} }
@ -1138,6 +1139,7 @@ spcdevHierVisit(
if (!has_model) if (!has_model)
{ {
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap); esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE); spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
} }

View File

@ -3140,6 +3140,7 @@ spcdevVisit(
if (!has_model) if (!has_model)
{ {
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap); esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE); spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
} }
@ -3186,6 +3187,7 @@ spcdevVisit(
if (!has_model) if (!has_model)
{ {
fprintf(esSpiceF, " ");
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap); esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE); spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
} }

View File

@ -2238,6 +2238,14 @@ efNodeMerge(node1ptr, node2ptr)
if (removing->efnode_flags & EF_SUBS_NODE) if (removing->efnode_flags & EF_SUBS_NODE)
keeping->efnode_flags |= EF_SUBS_NODE; keeping->efnode_flags |= EF_SUBS_NODE;
/*
* If "removing" has the EF_GLOB_SUBS_NODE flag set, then copy the
* port record in the flags to "keeping".
*/
if (removing->efnode_flags & EF_GLOB_SUBS_NODE)
keeping->efnode_flags |= EF_GLOB_SUBS_NODE;
/* If EFSaveLocs is set, then merge any disjoint segments from
/* If EFSaveLocs is set, then merge any disjoint segments from /* If EFSaveLocs is set, then merge any disjoint segments from
* removing to keeping. * removing to keeping.
*/ */

View File

@ -326,7 +326,7 @@ extBasic(def, outFile)
} }
/* Check for "device", as it modifies handling of parasitics */ /* Check for "device", as it modifies handling of parasitics */
propptr = (char *)DBPropGet(def, "device", &propfound); propptr = DBPropGetString(def, "device", &propfound);
if (propfound) if (propfound)
{ {
/* Remove parasitics from local nodes */ /* Remove parasitics from local nodes */
@ -1702,7 +1702,7 @@ extOutputParameters(def, transList, outFile)
* and device name, and if detected, add the type corresponding to the * and device name, and if detected, add the type corresponding to the
* device name to the mask so it gets handled, too. * device name to the mask so it gets handled, too.
*/ */
propptr = DBPropGet(def, "device", &propfound); propptr = DBPropGetString(def, "device", &propfound);
if (propfound) if (propfound)
{ {
char *devname; char *devname;
@ -1835,6 +1835,8 @@ extOutputDevParams(reg, devptr, outFile, length, width, areavec, perimvec)
ParamList *chkParam; ParamList *chkParam;
HashEntry *he; HashEntry *he;
ResValue resvalue; ResValue resvalue;
LabRegion *node; /* Node connected to gate terminal */
LabelList *ll; /* Gate's label list */
for (chkParam = devptr->exts_deviceParams; chkParam for (chkParam = devptr->exts_deviceParams; chkParam
!= NULL; chkParam = chkParam->pl_next) != NULL; chkParam = chkParam->pl_next)
@ -1966,6 +1968,34 @@ extOutputDevParams(reg, devptr, outFile, length, width, areavec, perimvec)
break; break;
} }
} }
/* If there are device attribute labels (labels attached to the device
* type ending with "^") with "=" in them, then treat them as extra
* parameters. Output each one and remove the gate attribute property
* from the label.
*/
node = (LabRegion *)ExtGetRegion(reg->treg_tile, reg->treg_dinfo);
for (ll = node->lreg_labels; ll; ll = ll->ll_next)
{
if (ll->ll_attr == LL_GATEATTR)
{
char cs, *ct, *cp = ll->ll_label->lab_text;
if (strchr(cp, '=') != NULL)
{
/* Since this is an attribute label, it has a special character
* at the end, which needs to be stripped off while printing
* and then put back again.
*/
ct = ll->ll_label->lab_text + strlen(ll->ll_label->lab_text) - 1;
cs = *ct;
*ct = '\0';
fprintf(outFile, " %s", ll->ll_label->lab_text);
ll->ll_attr = LL_NOATTR;
*ct = cs;
}
}
}
} }
/* Structures used by extTermAPFunc() for storing area and perimeter data */ /* Structures used by extTermAPFunc() for storing area and perimeter data */
@ -2725,6 +2755,56 @@ extOutputDevices(def, transList, outFile)
/* get corrected by extComputeEffectiveLW(). */ /* get corrected by extComputeEffectiveLW(). */
length = (extTransRec.tr_gatelen - width) / 2; length = (extTransRec.tr_gatelen - width) / 2;
} }
if ((n == 1) && (length == 0) && (extTransRec.tr_gatelen == 0))
{
/* If a one-terminal device has not recorded any
* gate length, then get W and L from the bounding
* box of the device. This routine could be much
* better optimized but it is probably not worth
* the effort. Just reusing the code from above
* for creating extSpecialDevice, a list of device
* tiles. Note that W and L are not distinguishable
* and hopefully the PDK defines the device by area
* and perimeter.
*/
LinkedTile *lt;
Rect devbbox, ltbox;
extSpecialDevice = (LinkedTile *)NULL;
arg.fra_uninit = (ClientData)extTransRec.tr_gatenode;
arg.fra_region = (ExtRegion *)reg;
arg.fra_each = extSDTileFunc;
ExtFindNeighbors(reg->treg_tile, reg->treg_dinfo,
arg.fra_pNum, &arg);
arg.fra_uninit = (ClientData) reg;
arg.fra_region = (ExtRegion *) extTransRec.tr_gatenode;
arg.fra_each = (int (*)()) NULL;
ExtFindNeighbors(reg->treg_tile, reg->treg_dinfo,
arg.fra_pNum, &arg);
lt = extSpecialDevice;
if (lt)
{
TiToRect(lt->t, &devbbox);
for (; lt; lt = lt->t_next)
{
TiToRect(lt->t, &ltbox);
GeoInclude(&ltbox, &devbbox);
}
free_magic1_t mm1 = freeMagic1_init();
for (lt = extSpecialDevice; lt; lt = lt->t_next)
freeMagic1(&mm1, (char *)lt);
freeMagic1_end(&mm1);
}
length = devbbox.r_xtop - devbbox.r_xbot;
/* Width was likely a perimeter value and will
* be recalculated as the actual device width.
*/
width = devbbox.r_ytop - devbbox.r_ybot;
}
} }
/*------------------------------------------------------*/ /*------------------------------------------------------*/

View File

@ -594,7 +594,7 @@ extHeader(def, f)
/* are to be passed to instances of the cell */ /* are to be passed to instances of the cell */
/* (created by defining property "parameter") */ /* (created by defining property "parameter") */
propvalue = (char *)DBPropGet(def, "parameter", &propfound); propvalue = DBPropGetString(def, "parameter", &propfound);
if (propfound) if (propfound)
{ {
// Use device parameter table to store the cell def parameters, // Use device parameter table to store the cell def parameters,

View File

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

View File

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

View File

@ -614,6 +614,7 @@ termtop:
termdone: termdone:
/* (continue) */ /* (continue) */
(void)0; /* older compilers need a statement after the label to prevent a compile error */
} }
/* Clean up---Put the ClientData entries in the tiles back to /* Clean up---Put the ClientData entries in the tiles back to

View File

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

View File

@ -63,7 +63,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include <unistd.h> #include <unistd.h>
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/magsgtty.h"
#include "textio/textio.h" #include "textio/textio.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "utils/hash.h" #include "utils/hash.h"

View File

@ -20,7 +20,6 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "utils/magsgtty.h"
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "windows/windows.h" #include "windows/windows.h"

View File

@ -17,7 +17,6 @@
#include <signal.h> #include <signal.h>
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/magsgtty.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "graphics/graphics.h" #include "graphics/graphics.h"
#include "windows/windows.h" #include "windows/windows.h"

View File

@ -22,7 +22,6 @@
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/magsgtty.h"
#include "textio/textio.h" #include "textio/textio.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "graphics/graphics.h" #include "graphics/graphics.h"

View File

@ -28,7 +28,6 @@
#include "utils/main.h" #include "utils/main.h"
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/malloc.h" #include "utils/malloc.h"
#include "utils/magsgtty.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "windows/windows.h" #include "windows/windows.h"
#include "graphics/graphics.h" #include "graphics/graphics.h"

View File

@ -15,7 +15,6 @@
#include "tcltk/tclmagic.h" #include "tcltk/tclmagic.h"
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/magsgtty.h"
#include "textio/textio.h" #include "textio/textio.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "windows/windows.h" #include "windows/windows.h"

View File

@ -26,7 +26,6 @@
#include "utils/main.h" #include "utils/main.h"
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/malloc.h" #include "utils/malloc.h"
#include "utils/magsgtty.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "windows/windows.h" #include "windows/windows.h"
#include "graphics/graphics.h" #include "graphics/graphics.h"

View File

@ -13,7 +13,6 @@
#include "tcltk/tclmagic.h" #include "tcltk/tclmagic.h"
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/magsgtty.h"
#include "textio/textio.h" #include "textio/textio.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "windows/windows.h" #include "windows/windows.h"

View File

@ -23,7 +23,6 @@
#include "utils/main.h" #include "utils/main.h"
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/malloc.h" #include "utils/malloc.h"
#include "utils/magsgtty.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "windows/windows.h" #include "windows/windows.h"
#include "graphics/graphics.h" #include "graphics/graphics.h"

View File

@ -13,7 +13,6 @@
#include "tcltk/tclmagic.h" #include "tcltk/tclmagic.h"
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/magsgtty.h"
#include "textio/textio.h" #include "textio/textio.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "windows/windows.h" #include "windows/windows.h"

View File

@ -31,7 +31,6 @@
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/magsgtty.h"
#include "textio/textio.h" #include "textio/textio.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "textio/txcommands.h" #include "textio/txcommands.h"

View File

@ -22,7 +22,6 @@
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/magsgtty.h"
#include "textio/textio.h" #include "textio/textio.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "graphics/graphics.h" #include "graphics/graphics.h"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1356,7 +1356,7 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename)
} }
if (extDev->subs == extNode) if (extDev->subs == extNode)
{ {
if ((subs = layoutDev->rd_fet_subs) != NULL) if ((layoutDev->rd_nterms >= 4) && ((subs = layoutDev->rd_fet_subs) != NULL))
{ {
if (subs->rn_name != NULL && notdecremented) if (subs->rn_name != NULL && notdecremented)
{ {

View File

@ -386,7 +386,7 @@ ResMoveDevices(node1, node2)
devptr = devptr->te_nextt; devptr = devptr->te_nextt;
if (device->rd_fet_gate == node1) if (device->rd_fet_gate == node1)
device->rd_fet_gate = node2; device->rd_fet_gate = node2;
else if (device->rd_fet_subs == node1) else if ((device->rd_nterms >= 4) && (device->rd_fet_subs == node1))
device->rd_fet_subs = node2; device->rd_fet_subs = node2;
else if (device->rd_fet_source == node1) else if (device->rd_fet_source == node1)
device->rd_fet_source = node2; device->rd_fet_source = node2;

View File

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

View File

@ -1216,13 +1216,21 @@ SelectTransform(transform)
SelectAndCopy2(EditRootDef); SelectAndCopy2(EditRootDef);
} }
/* Client data used by SelectExpand */
typedef struct selExpData {
int sed_mask; /* window mask */
int sed_type; /* DB_EXPAND, etc. */
Rect *sed_box; /* selection box if used, or NULL */
} SelExpData;
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
* SelectExpand -- * SelectExpand --
* *
* Expand all of the selected cells that are unexpanded, and * Expand or unexpand all of the selected cells according to
* unexpand all of those that are expanded. * expandType.
* *
* Results: * Results:
* None. * None.
@ -1230,58 +1238,166 @@ SelectTransform(transform)
* Side effects: * Side effects:
* The contents of the selected cells will become visible or * The contents of the selected cells will become visible or
* invisible on the display in the indicated window(s). * invisible on the display in the indicated window(s).
* Both the cell in the layout and the selection are updated
* so that they are synchonized with respect to the state of
* visibility.
* *
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
void void
SelectExpand(mask) SelectExpand(mask, expandType, rootBox)
int mask; /* Bits of this word indicate which int mask; /* Bits of this word indicate which
* windows the selected cells will be * windows the selected cells will be
* expanded in. * expanded in.
*/ */
int expandType; /* Operation to perform: Expand,
* unexpand, or expand toggle.
*/
Rect *rootBox; /* Area of root box, if selecting by
* cursor box area.
*/
{ {
extern int selExpandFunc(); /* Forward reference. */ /* Forward references */
extern int selExpandFunc();
(void) SelEnumCells(FALSE, (bool *) NULL, (SearchContext *) NULL, SelExpData sed;
selExpandFunc, INT2CD(mask));
sed.sed_type = expandType;
sed.sed_box = rootBox;
sed.sed_mask = mask;
if (rootBox != NULL)
{
SearchContext scx;
scx.scx_use = SelectUse;
scx.scx_area = *rootBox;
scx.scx_trans = GeoIdentityTransform;
SelEnumCells(FALSE, (bool *) NULL, &scx, selExpandFunc, &sed);
return;
}
SelEnumCells(FALSE, (bool *) NULL, (SearchContext *)NULL,
selExpandFunc, &sed);
} }
/* ARGSUSED */ /* ARGSUSED */
int int
selExpandFunc(selUse, use, transform, mask) selExpandFunc(selUse, use, transform, sed)
CellUse *selUse; /* Use from selection. */ CellUse *selUse; /* Use from selection. */
CellUse *use; /* Use to expand (in actual layout). */ CellUse *use; /* Use to expand (in actual layout). */
Transform *transform; /* Not used. */ Transform *transform; /* Not used. */
int mask; /* Windows in which to expand. */ SelExpData *sed; /* Information for expansion */
{ {
/* Don't change expansion status of root cell: screws up int expandType = sed->sed_type;
* DBWAreaChanged (need to always have at least top-level int mask = sed->sed_mask;
* cell be expanded). Rect *rootBox = sed->sed_box;
*/
if (use->cu_parent == NULL) /* If a rootBox is provided, then we are here trying to sync the
* cells in the selection to those in the edit cell. Need to
* follow the policy of expandType: If DB_EXPAND_SURROUND, then
* selUse must be inside the rootBox. If DB_EXPAND_OVERLAP, then
* selUse must ovelap the rootBox.
*/
if (rootBox != NULL)
{ {
TxError("Can't unexpand root cell of window.\n"); if ((expandType & DB_EXPAND_SURROUND_MASK) == DB_EXPAND_OVERLAP)
return 0; {
if (!GEO_OVERLAP(rootBox, &selUse->cu_bbox))
return 0;
}
else /* (expandType & DB_EXPAND_SURROUND_MASK) == DB_EXPAND_SURROUND */
{
if (!GEO_SURROUND(rootBox, &selUse->cu_bbox))
return 0;
}
} }
/* Be sure to modify the expansion bit in the selection as well as /* If a rootBox was given, then the expansion is being done in the
* the one in the layout in order to keep them consistent. * edit cell, and the selection is being updated to reflect any
* changes there, so only handle the selection. Otherwise, we
* have to sync the corresponding cells in the edit def here.
*/ */
if ((expandType & DB_EXPAND_MASK) == DB_EXPAND)
if (DBDescendSubcell(use, mask))
{ {
DBExpand(selUse, mask, FALSE); /* Be sure to modify the expansion bit in the selection as well as
DBExpand(use, mask, FALSE); * the one in the layout in order to keep them consistent.
DBWAreaChanged(use->cu_parent, &use->cu_bbox, mask, */
(TileTypeBitMask *) NULL); DBExpand(selUse, mask, DB_EXPAND);
if (!rootBox)
{
DBExpand(use, mask, DB_EXPAND);
if (use->cu_parent == NULL)
DBWAreaChanged(use->cu_def, &use->cu_bbox, mask, &DBAllButSpaceBits);
else
DBWAreaChanged(use->cu_parent, &use->cu_bbox, mask, &DBAllButSpaceBits);
}
} }
else else if ((expandType & DB_EXPAND_MASK) == DB_UNEXPAND)
{ {
DBExpand(selUse, mask, TRUE); /* Don't change expansion status of root cell: screws up
DBExpand(use, mask, TRUE); * DBWAreaChanged (need to always have at least top-level
DBWAreaChanged(use->cu_parent, &use->cu_bbox, mask, &DBAllButSpaceBits); * cell be expanded).
*/
if ((use->cu_parent == NULL) && !rootBox)
{
TxError("Can't unexpand root cell of window.\n");
return 0;
}
if (use->cu_parent != NULL)
{
/* Be sure to modify the expansion bit in the selection as well as
* the one in the layout in order to keep them consistent.
*/
DBExpand(selUse, mask, DB_UNEXPAND);
if (!rootBox)
{
DBExpand(use, mask, DB_UNEXPAND);
DBWAreaChanged(use->cu_parent, &use->cu_bbox, mask,
(TileTypeBitMask *) NULL);
}
}
}
else /* (expandType & DB_EXPAND_MASK) == DB_EXPAND_TOGGLE */
{
/* Don't change expansion status of root cell: screws up
* DBWAreaChanged (need to always have at least top-level
* cell be expanded).
*/
if (use->cu_parent == NULL)
{
if (!rootBox) TxError("Can't unexpand root cell of window.\n");
return 0;
}
/* Be sure to modify the expansion bit in the selection as well as
* the one in the layout in order to keep them consistent.
*/
if (DBDescendSubcell(selUse, mask))
{
DBExpand(selUse, mask, DB_UNEXPAND);
if (!rootBox)
{
DBExpand(use, mask, DB_UNEXPAND);
DBWAreaChanged(use->cu_parent, &use->cu_bbox, mask,
(TileTypeBitMask *) NULL);
}
}
else
{
DBExpand(selUse, mask, DB_EXPAND);
if (!rootBox)
{
DBExpand(use, mask, DB_EXPAND);
DBWAreaChanged(use->cu_parent, &use->cu_bbox, mask, &DBAllButSpaceBits);
}
}
} }
return 0; return 0;
} }

View File

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

View File

@ -148,6 +148,10 @@ proc magic::make_texthelper { mgrpath } {
proc magic::analyze_labels {} { proc magic::analyze_labels {} {
global typedflt typesticky typeport global typedflt typesticky typeport
# Ensure units of microns
set curunits [units]
units microns
# Pick up values from the first entry returned # Pick up values from the first entry returned
set tval [lindex [setlabel text] 0] set tval [lindex [setlabel text] 0]
@ -157,6 +161,7 @@ proc magic::analyze_labels {} {
set oval [lindex [setlabel offset] 0] set oval [lindex [setlabel offset] 0]
set lval [lindex [setlabel layer] 0] set lval [lindex [setlabel layer] 0]
set kval [lindex [setlabel sticky] 0] set kval [lindex [setlabel sticky] 0]
set sval [lindex [setlabel size] 0]
set isport [lindex [port exists] 0] set isport [lindex [port exists] 0]
if {$isport} { if {$isport} {
set pval [lindex [port index] 0] set pval [lindex [port index] 0]
@ -164,14 +169,6 @@ proc magic::analyze_labels {} {
set pval -1 set pval -1
} }
# Rescale internal units to microns
set sval [lindex [setlabel size] 0]
set sscale [cif scale out]
set tmp_pre $::tcl_precision
set ::tcl_precision 3
set sval [expr $sscale * $sval]
set ::tcl_precision $tmp_pre
.texthelper.text.tent delete 0 end .texthelper.text.tent delete 0 end
.texthelper.text.tent insert 0 $tval .texthelper.text.tent insert 0 $tval
set jbtn [string map {NORTH N WEST W SOUTH S EAST E CENTER center} $jval] set jbtn [string map {NORTH N WEST W SOUTH S EAST E CENTER center} $jval]
@ -206,6 +203,9 @@ proc magic::analyze_labels {} {
pack .texthelper.layer.tent -side left -fill x -expand true pack .texthelper.layer.tent -side left -fill x -expand true
pack .texthelper.layer.btn2 -side left pack .texthelper.layer.btn2 -side left
} }
# Revert units
units {*}$curunits
} }
@ -220,6 +220,9 @@ proc magic::change_label {} {
return return
} }
set curunits [units]
units microns
set ltext [.texthelper.text.tent get] set ltext [.texthelper.text.tent get]
set lfont [.texthelper.font.btn cget -text] set lfont [.texthelper.font.btn cget -text]
set lsize [.texthelper.size.tent get] set lsize [.texthelper.size.tent get]
@ -247,13 +250,10 @@ proc magic::change_label {} {
} }
} }
if {$lsize != ""} { if {$lsize != ""} {
setlabel size ${lsize}um setlabel size $lsize
} }
if {$loff != ""} { if {$loff != ""} {
set oldsnap [snap list]
snap internal
setlabel offset [join $loff] setlabel offset [join $loff]
snap $oldsnap
} }
if {$lrot != ""} { if {$lrot != ""} {
setlabel rotate $lrot setlabel rotate $lrot
@ -274,6 +274,8 @@ proc magic::change_label {} {
port remove port remove
} }
} }
units {*}$curunits
} }
proc magic::make_new_label {} { proc magic::make_new_label {} {

View File

@ -10,6 +10,15 @@
# Revision 2 (names are hashed from properties) # Revision 2 (names are hashed from properties)
# March 9, 2021 # March 9, 2021
# Added spice-to-layout procedure # Added spice-to-layout procedure
# March 4, 2026
# Changed to make use of new "units" command
# March 26, 2026
# Added behavior to handle ideal devices (resistor, capacitor,
# inductor)
# April 2, 2026
# Changed the hash to MurmurHash3, as the existing hash
# is prone to creating name collisions (rare, but not rare
# enough).
#-------------------------------------------------------------- #--------------------------------------------------------------
# Sets up the environment for a toolkit. The toolkit must # Sets up the environment for a toolkit. The toolkit must
# supply a namespace that is the "library name". For each # supply a namespace that is the "library name". For each
@ -118,6 +127,8 @@ magic::tag add select "magic::gencell_update %1"
proc magic::move_forward_by_width {instname} { proc magic::move_forward_by_width {instname} {
select cell $instname select cell $instname
set curunits [units]
units internal
set anum [lindex [array -list count] 1] set anum [lindex [array -list count] 1]
set xpitch [lindex [array -list pitch] 0] set xpitch [lindex [array -list pitch] 0]
set bbox [box values] set bbox [box values]
@ -125,7 +136,8 @@ proc magic::move_forward_by_width {instname} {
set posy [lindex $bbox 1] set posy [lindex $bbox 1]
set width [expr [lindex $bbox 2] - $posx] set width [expr [lindex $bbox 2] - $posx]
set posx [expr $posx + $width + $xpitch * $anum] set posx [expr $posx + $width + $xpitch * $anum]
box position ${posx}i ${posy}i box position ${posx} ${posy}
units {*}$curunits
return [lindex $bbox 3] return [lindex $bbox 3]
} }
@ -141,10 +153,13 @@ proc magic::get_and_move_inst {cellname instname {anum 1}} {
if {$newinst == ""} {return} if {$newinst == ""} {return}
identify $instname identify $instname
if {$anum > 1} {array 1 $anum} if {$anum > 1} {array 1 $anum}
set curunits [units]
units internal
set bbox [box values] set bbox [box values]
set posx [lindex $bbox 2] set posx [lindex $bbox 2]
set posy [lindex $bbox 1] set posy [lindex $bbox 1]
box position ${posx}i ${posy}i box position ${posx} ${posy}
units {*}$curunits
return [lindex $bbox 3] return [lindex $bbox 3]
} }
@ -155,11 +170,14 @@ proc magic::get_and_move_inst {cellname instname {anum 1}} {
# given layer. Otherwise, the pin is created on the m1 layer. # given layer. Otherwise, the pin is created on the m1 layer.
proc magic::create_new_pin {pinname portnum {layer m1}} { proc magic::create_new_pin {pinname portnum {layer m1}} {
box size 1um 1um set curunits [units]
units microns
box size 1 1
paint $layer paint $layer
label $pinname FreeSans 16 0 0 0 c $layer label $pinname FreeSans 1 0 0 0 c $layer
port make $portnum port make $portnum
box move s 2um box move s 2
units {*}$curunits
} }
# generate_layout_add -- # generate_layout_add --
@ -172,6 +190,9 @@ proc magic::create_new_pin {pinname portnum {layer m1}} {
proc magic::generate_layout_add {subname subpins complist library} { proc magic::generate_layout_add {subname subpins complist library} {
global PDKNAMESPACE global PDKNAMESPACE
set curunits [units]
units internal
# Create a new subcircuit. # Create a new subcircuit.
load $subname -quiet load $subname -quiet
@ -188,7 +209,7 @@ proc magic::generate_layout_add {subname subpins complist library} {
select cell $inst select cell $inst
delete delete
} }
cellname delete $child cellname delete $child -noprompt
} }
} }
} }
@ -241,7 +262,7 @@ proc magic::generate_layout_add {subname subpins complist library} {
box size 0 0 box size 0 0
set posx 0 set posx 0
set posy [expr {round(3 / [cif scale out])}] set posy [expr {round(3 / [cif scale out])}]
box position ${posx}i ${posy}i box position ${posx} ${posy}
# Find all instances in the circuit # Find all instances in the circuit
select top cell select top cell
@ -267,8 +288,13 @@ proc magic::generate_layout_add {subname subpins complist library} {
set paramlist {} set paramlist {}
# NOTE: This routine deals with subcircuit calls and devices # NOTE: This routine deals with subcircuit calls and devices
# with models. It needs to determine when a device is instantiated # with models. There are two exceptions, for toolkits which
# without a model, and ignore such devices. # wish to implement a way to generate unmodeled capacitors,
# resistors, or inductors based on value; for example, metal
# interdigitated capacitors. For those exceptions, the device
# value is recast as a parameter called "value", and the device
# is given a model "capacitor", "resistor", or "inductor",
# respectively.
# Parse SPICE line into pins, device name, and parameters. Make # Parse SPICE line into pins, device name, and parameters. Make
# sure parameters incorporate quoted expressions as {} or ''. # sure parameters incorporate quoted expressions as {} or ''.
@ -312,6 +338,23 @@ proc magic::generate_layout_add {subname subpins complist library} {
set devtype [lindex $pinlist end] set devtype [lindex $pinlist end]
set pinlist [lrange $pinlist 0 end-1] set pinlist [lrange $pinlist 0 end-1]
# Ideal device check: "devtype" will start with a digit.
# The instname will begin with "c", "r", or "l".
if {[regexp {^([0-9\.]+.*)} $devtype pval]} {
set comptype [string tolower [string range $instname 0 0]]
if {$comptype == "c"} {
lappend paramlist [list value $pval]
set devtype capacitor
} elseif {$comptype == "r"} {
lappend paramlist [list value $pval]
set devtype resistor
} elseif {$comptype == "l"} {
lappend paramlist [list value $pval]
set devtype inductor
}
}
set mult 1 set mult 1
foreach param $paramlist { foreach param $paramlist {
set parmname [lindex $param 0] set parmname [lindex $param 0]
@ -323,6 +366,27 @@ proc magic::generate_layout_add {subname subpins complist library} {
} }
} }
# Check if devtype has routines by looking for ${devtype}_defaults.
# If not found, do a case-insensitive check against all devices
# before deciding that devtype is a subcircuit and not a device.
# If found by case-insensitive check, then change the device name
# to the one used in the library.
if {$library != ""} {
set alldevices [namespace eval ::${library} {info procs}]
} else {
set alldevices [namespace eval ::${PDKNAMESPACE} {info procs}]
}
set devdefault [lsearch $alldevices ${devtype}_defaults]
if {$devdefault == -1} {
set devdefault [lsearch -nocase $alldevices ${devtype}_defaults]
if {$devdefault != -1} {
set devprocname [lindex $alldevices $devdefault]
set devproclist [split $devprocname "_"]
set devtype [lindex $devproclist 0]
}
}
# devtype is assumed to be in library. If not, it will attempt to # devtype is assumed to be in library. If not, it will attempt to
# use 'getcell' on devtype. Note that this code depends on the # use 'getcell' on devtype. Note that this code depends on the
# PDK setting varible PDKNAMESPACE. # PDK setting varible PDKNAMESPACE.
@ -374,6 +438,7 @@ proc magic::generate_layout_add {subname subpins complist library} {
} }
} }
save $subname save $subname
units {*}$curunits
} }
#-------------------------------------------------------------- #--------------------------------------------------------------
@ -485,7 +550,7 @@ proc magic::netlist_to_layout {netfile library} {
set subname [lindex $ftokens 1] set subname [lindex $ftokens 1]
set subpins [lrange $ftokens 2 end] set subpins [lrange $ftokens 2 end]
set insub true set insub true
} elseif {[regexp -nocase {^[xmcrdq]([^ \t]+)[ \t](.*)$} $line \ } elseif {[regexp -nocase {^[xmcrldq]([^ \t]+)[ \t](.*)$} $line \
valid instname rest]} { valid instname rest]} {
lappend toplist $line lappend toplist $line
} elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \ } elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \
@ -500,7 +565,7 @@ proc magic::netlist_to_layout {netfile library} {
set subname "" set subname ""
set subpins "" set subpins ""
set complist {} set complist {}
} elseif {[regexp -nocase {^[xmcrdq]([^ \t]+)[ \t](.*)$} $line \ } elseif {[regexp -nocase {^[xmcrldq]([^ \t]+)[ \t](.*)$} $line \
valid instname rest]} { valid instname rest]} {
lappend complist $line lappend complist $line
} elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \ } elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \
@ -783,11 +848,16 @@ proc magic::gencell_change {instname gencell_type library parameters} {
set pdefaults [${library}::${gencell_type}_defaults] set pdefaults [${library}::${gencell_type}_defaults]
# Pull user-entered values from dialog # Pull user-entered values from dialog
set parameters [dict merge $pdefaults [magic::gencell_getparams]] set parameters [dict merge $pdefaults [magic::gencell_getparams]]
set newinstname [.params.title.ient get]
if {$newinstname == "(default)"} {set newinstname $instname}
if {$newinstname == $instname} {set newinstname $instname}
if {[instance list exists $newinstname] != ""} {set newinstname $instname}
} }
# Attempt to set the new instance name as specified in the dialog.
# If the entry is "(default)" or if there is a name collision,
# revert the name to the original name.
set newinstname [.params.title.ient get]
if {$newinstname == "(default)"} {set newinstname $instname}
if {[instance list exists $newinstname] != ""} {set newinstname $instname}
if {[dict exists $parameters gencell]} { if {[dict exists $parameters gencell]} {
# Setting special parameter "gencell" forces the gencell to change type # Setting special parameter "gencell" forces the gencell to change type
set gencell_type [dict get $parameters gencell] set gencell_type [dict get $parameters gencell]
@ -805,6 +875,20 @@ proc magic::gencell_change {instname gencell_type library parameters} {
set gsuffix [magic::get_gencell_hash ${parameters}] set gsuffix [magic::get_gencell_hash ${parameters}]
set gname ${gencell_type}_${gsuffix} set gname ${gencell_type}_${gsuffix}
# Handle instance name changing first. If no parameters changed, then
# we're done.
if {$newinstname != $instname} {
identify $newinstname
# The buttons "Apply" and "Okay" need to be changed for the new
# instance name
catch {.params.buttons.apply config -command \
"magic::gencell_change $newinstname $gencell_type $library {}"}
catch {.params.buttons.okay config -command \
"magic::gencell_change $newinstname $gencell_type $library {} ;\
destroy .params"}
set instname $newinstname
}
# Guard against instance having been deleted. Also, if parameters have not # Guard against instance having been deleted. Also, if parameters have not
# changed as evidenced by the cell suffix not changing, then nothing further # changed as evidenced by the cell suffix not changing, then nothing further
# needs to be done. # needs to be done.
@ -813,8 +897,8 @@ proc magic::gencell_change {instname gencell_type library parameters} {
return return
} }
set snaptype [snap list] set curunits [units]
snap internal units internal
set savebox [box values] set savebox [box values]
catch {setpoint 0 0 $Opts(focus)} catch {setpoint 0 0 $Opts(focus)}
@ -840,31 +924,9 @@ proc magic::gencell_change {instname gencell_type library parameters} {
if {$abox != ""} {box values {*}$abox} if {$abox != ""} {box values {*}$abox}
set newinstname [getcell $gname $orient] set newinstname [getcell $gname $orient]
select cell $newinstname select cell $newinstname
set origname $newinstname
expand expand
# If the old instance name was not formed from the old cell name,
# then keep the old instance name.
if {[string first $old_gname $instname] != 0} {
set newinstname $instname
}
if {[cellname list parents $old_gname] == []} {
# If the original cell has no intances left, delete it. It can
# be regenerated if and when necessary.
cellname delete $old_gname
}
} else {
select cell $instname
set orient [instance list orientation]
set abox [instance list abutment]
delete
# There is no cell of this name, so generate one and instantiate it.
if {$abox != ""} {box values {*}$abox}
set newinstname [magic::gencell_create $gencell_type $library $parameters $orient]
select cell $newinstname
# If the old instance name was not formed from the old cell name, # If the old instance name was not formed from the old cell name,
# then keep the old instance name. # then keep the old instance name.
if {[string first $old_gname $instname] != 0} { if {[string first $old_gname $instname] != 0} {
@ -878,10 +940,51 @@ proc magic::gencell_change {instname gencell_type library parameters} {
"magic::gencell_change $newinstname $gencell_type $library {} ;\ "magic::gencell_change $newinstname $gencell_type $library {} ;\
destroy .params"} destroy .params"}
} }
if {[cellname list parents $old_gname] == []} {
# If the original cell has no intances left, delete it. It can
# be regenerated if and when necessary.
cellname delete $old_gname -noprompt
select cell $origname
}
} else {
select cell $instname
set orient [instance list orientation]
set abox [instance list abutment]
delete
# There is no cell of this name, so generate one and instantiate it.
if {$abox != ""} {box values {*}$abox}
set newinstname [magic::gencell_create $gencell_type $library $parameters $orient]
select cell $newinstname
set origname $newinstname
# If the old instance name was not formed from the old cell name,
# then keep the old instance name.
if {[string first $old_gname $instname] != 0} {
set newinstname $instname
} else {
# The buttons "Apply" and "Okay" need to be changed for the new
# instance name
catch {.params.buttons.apply config -command \
"magic::gencell_change $newinstname $gencell_type $library {}"}
catch {.params.buttons.okay config -command \
"magic::gencell_change $newinstname $gencell_type $library {} ;\
destroy .params"}
}
# If the old cell is not used anywhere, delete it
if {[cellname list parents $old_gname] == []} {
# If the original cell has no intances left, delete it. It can
# be regenerated if and when necessary.
cellname delete $old_gname -noprompt
select cell $origname
}
} }
identify $newinstname identify $newinstname
eval "box values $savebox" eval "box values $savebox"
snap $snaptype units {*}$curunits
# Update window # Update window
if {$gname != $old_gname} { if {$gname != $old_gname} {
@ -940,8 +1043,8 @@ proc magic::gencell_change_orig {instname gencell_type library parameters} {
return return
} }
set snaptype [snap list] set curunits [units]
snap internal units internal
set savebox [box values] set savebox [box values]
catch {setpoint 0 0 $Opts(focus)} catch {setpoint 0 0 $Opts(focus)}
@ -969,7 +1072,7 @@ proc magic::gencell_change_orig {instname gencell_type library parameters} {
} }
identify $newinstname identify $newinstname
eval "box values $savebox" eval "box values $savebox"
snap $snaptype units {*}$curunits
resumeall resumeall
redraw redraw
} }
@ -1008,38 +1111,47 @@ proc magic::get_gencell_name {gencell_type} {
# gives a result that is repeatable for the same set of # gives a result that is repeatable for the same set of
# parameter values with a very low probability of a collision. # parameter values with a very low probability of a collision.
# #
# The hash function is similar to elfhash but reduced from 32 # The hash function is murmur3 but reduced from 32 to 30 bits
# to 30 bits so that the result can form a 6-character value # so that the result can form a 6-character value in base36
# in base32 with all characters being valid for a SPICE subcell # with all characters being valid for a SPICE subcell name
# name (e.g., alphanumeric only and case-insensitive). # (e.g., alphanumeric only and case-insensitive). This
# reduces the space from ~4 billion unique suffixes to ~1
# billion; however, even a complex mixed-signal chip design
# is unlikely to have more than a few hundred unique parameter
# sets for any given device.
#
# Code courtesy of ChatGPT, derived from my implementation.
#---------------------------------------------------------------- #----------------------------------------------------------------
proc magic::get_gencell_hash {parameters} { proc magic::get_gencell_hash {parameters} {
set hash 0 # Canonicalize: sort by key
# Apply hash set keys [lsort [dict keys $parameters]]
dict for {key value} $parameters {
foreach s [split $value {}] { # Build input string (values only, but delimited)
set hash [expr {($hash << 4) + [scan $s %c]}] set input ""
set high [expr {$hash & 0x03c0000000}] foreach k $keys {
set hash [expr {$hash ^ ($high >> 30)}] set value [magic::normalize_value [dict get $parameters $k]]
set hash [expr {$hash & (~$high)}] append input "${value};"
}
} }
# Divide hash up into 5 bit values and convert to base32
# using letters A-Z less I and O, and digits 2-9. # Compute Murmur hash
set hash [magic::murmur3_32 $input]
# Convert to 6-character base32
set cvals "" set cvals ""
for {set i 0} {$i < 6} {incr i} { for {set i 0} {$i < 6} {incr i} {
set oval [expr {($hash >> ($i * 5)) & 0x1f}] set oval [expr {($hash >> ($i * 5)) & 0x1f}]
if {$oval < 8} { if {$oval < 8} {
set bval [expr {$oval + 50}] set bval [expr {$oval + 50}] ;# '2'-'9'
} elseif {$oval < 16} { } elseif {$oval < 16} {
set bval [expr {$oval + 57}] set bval [expr {$oval + 57}] ;# 'A'-'H'
} elseif {$oval < 21} { } elseif {$oval < 21} {
set bval [expr {$oval + 58}] set bval [expr {$oval + 58}] ;# 'J'-'N'
} else { } else {
set bval [expr {$oval + 59}] set bval [expr {$oval + 59}] ;# 'P'-'Z'
} }
append cvals [binary format c* $bval] append cvals [binary format c* $bval]
} }
return $cvals return $cvals
} }
@ -1092,8 +1204,8 @@ proc magic::gencell_create {gencell_type library parameters {orient 0}} {
set parameters [dict remove $parameters gencell] set parameters [dict remove $parameters gencell]
} }
set snaptype [snap list] set curunits [units]
snap internal units internal
set savebox [box values] set savebox [box values]
catch {setpoint 0 0 $Opts(focus)} catch {setpoint 0 0 $Opts(focus)}
@ -1123,7 +1235,7 @@ proc magic::gencell_create {gencell_type library parameters {orient 0}} {
identify $newinstname identify $newinstname
set instname $newinstname set instname $newinstname
} }
snap $snaptype units {*}$curunits
resumeall resumeall
redraw redraw
return $instname return $instname
@ -1163,17 +1275,7 @@ proc magic::add_entry {pname ptext parameters} {
proc magic::add_check_callbacks {gencell_type library} { proc magic::add_check_callbacks {gencell_type library} {
set wlist [winfo children .params.body.area.edits] set wlist [winfo children .params.body.area.edits]
foreach w $wlist { foreach w $wlist {
if {[regexp {\.params\.body\.area\.edits\.(.+)_ent} $w valid pname]} { if {[regexp {\.params\.body\.area\.edits\.(.+)_.+} $w valid pname]} {
# Add callback on enter or focus out
bind $w <Return> \
"magic::update_dialog {} $pname $gencell_type $library"
bind $w <FocusOut> \
"magic::update_dialog {} $pname $gencell_type $library"
}
if {[regexp {\.params\.body\.area\.edits\.(.+)_sel} $w valid pname]} {
magic::add_dependency \{\} $gencell_type $library $pname
}
if {[regexp {\.params\.body\.area\.edits\.(.+)_chk} $w valid pname]} {
magic::add_dependency \{\} $gencell_type $library $pname magic::add_dependency \{\} $gencell_type $library $pname
} }
} }
@ -1192,6 +1294,16 @@ proc magic::add_check_callbacks {gencell_type library} {
# dictionary. # dictionary.
# #
# Also handle dependencies on checkboxes and selection lists # Also handle dependencies on checkboxes and selection lists
#
# If dependency callbacks exist, then chain them together.
# A final default dependency will be added to all entries
# to run the "check" procedure for the device. Dependencies
# that are more targeted get run first.
#
# NOTE: The "check" procedure must be the first in the
# list, as otherwise, any invalid entry that is corrected
# by the check callback will have been used to evaluate
# dependent values.
#---------------------------------------------------------- #----------------------------------------------------------
proc magic::add_dependency {callback gencell_type library args} { proc magic::add_dependency {callback gencell_type library args} {
@ -1206,21 +1318,28 @@ proc magic::add_dependency {callback gencell_type library args} {
foreach pname $args { foreach pname $args {
if {[lsearch $clist .params.body.area.edits.${pname}_ent] >= 0} { if {[lsearch $clist .params.body.area.edits.${pname}_ent] >= 0} {
# Add callback on enter or focus out # Add callback on enter or focus out
bind .params.body.area.edits.${pname}_ent <Return> \ set oldbind [bind .params.body.area.edits.${pname}_ent <Return>]
"magic::update_dialog $callback $pname $gencell_type $library" set newbind "magic::update_dialog $callback $pname $gencell_type $library"
bind .params.body.area.edits.${pname}_ent <FocusOut> \ if {$oldbind != {}} {set newbind "$oldbind ; $newbind"}
"magic::update_dialog $callback $pname $gencell_type $library" bind .params.body.area.edits.${pname}_ent <Return> $newbind
set oldbind [bind .params.body.area.edits.${pname}_ent <FocusOut>]
set newbind "magic::update_dialog $callback $pname $gencell_type $library"
if {$oldbind != {}} {set newbind "$oldbind ; $newbind"}
bind .params.body.area.edits.${pname}_ent <FocusOut> $newbind
} elseif {[lsearch $clist .params.body.area.edits.${pname}_chk] >= 0} { } elseif {[lsearch $clist .params.body.area.edits.${pname}_chk] >= 0} {
# Add callback on checkbox change state # Add callback on checkbox change state
.params.body.area.edits.${pname}_chk configure -command \ set oldcmd [.params.body.area.edits.${pname}_chk cget -command]
"magic::update_dialog $callback $pname $gencell_type $library" set newcmd "magic::update_dialog $callback $pname $gencell_type $library"
if {$oldcmd != {}} {set newcmd "$oldcmd ; $newcmd"}
.params.body.area.edits.${pname}_chk configure -command $newcmd
} elseif {[lsearch $clist .params.body.area.edits.${pname}_sel] >= 0} { } elseif {[lsearch $clist .params.body.area.edits.${pname}_sel] >= 0} {
set smenu .params.body.area.edits.${pname}_sel.menu set smenu .params.body.area.edits.${pname}_sel.menu
set sitems [${smenu} index end] set sitems [${smenu} index end]
for {set idx 0} {$idx <= $sitems} {incr idx} { for {set idx 0} {$idx <= $sitems} {incr idx} {
set curcommand [${smenu} entrycget $idx -command] set oldcmd [${smenu} entrycget $idx -command]
${smenu} entryconfigure $idx -command "$curcommand ; \ set newcmd "magic::update_dialog $callback $pname $gencell_type $library"
magic::update_dialog $callback $pname $gencell_type $library" if {$oldcmd != {}} {set newcmd "$oldcmd ; $newcmd"}
${smenu} entryconfigure $idx -command $newcmd
} }
} }
} }
@ -1241,13 +1360,13 @@ proc magic::update_dialog {callback pname gencell_type library} {
set parameters [dict merge $pdefaults [magic::gencell_getparams]] set parameters [dict merge $pdefaults [magic::gencell_getparams]]
} }
if {$callback != {}} {
set parameters [$callback $pname $parameters]
}
if {[catch {set parameters [${library}::${gencell_type}_check $parameters]} \ if {[catch {set parameters [${library}::${gencell_type}_check $parameters]} \
checkerr]} { checkerr]} {
puts stderr $checkerr puts stderr $checkerr
} }
if {$callback != {}} {
set parameters [$callback $pname $parameters]
}
magic::gencell_setparams $parameters magic::gencell_setparams $parameters
} }
@ -1611,3 +1730,99 @@ proc magic::gencell_dialog {instname gencell_type library parameters} {
} }
#------------------------------------------------------------- #-------------------------------------------------------------
# Implementation of murmur3 hash, 32 bits
# Code courtesy of ChatGPT.
#-------------------------------------------------------------
proc magic::murmur3_32 {key {seed 0}} {
set length [string length $key]
set c1 0xcc9e2d51
set c2 0x1b873593
set h1 $seed
# Body (process 4 bytes at a time)
set nblocks [expr {$length / 4}]
for {set i 0} {$i < $nblocks} {incr i} {
binary scan [string range $key [expr {$i*4}] [expr {$i*4+3}]] i k1
set k1 [expr {($k1 * $c1) & 0xffffffff}]
set k1 [expr {(($k1 << 15) | (($k1 & 0xffffffff) >> 17)) & 0xffffffff}]
set k1 [expr {($k1 * $c2) & 0xffffffff}]
set h1 [expr {$h1 ^ $k1}]
set h1 [expr {(($h1 << 13) | (($h1 & 0xffffffff) >> 19)) & 0xffffffff}]
set h1 [expr {(($h1 * 5) + 0xe6546b64) & 0xffffffff}]
}
# Tail
set k1 0
set tail_index [expr {$nblocks * 4}]
set tail [string range $key $tail_index end]
set remaining [string length $tail]
if {$remaining >= 3} {
binary scan [string index $tail 2] c b
set k1 [expr {$k1 ^ (($b & 0xff) << 16)}]
}
if {$remaining >= 2} {
binary scan [string index $tail 1] c b
set k1 [expr {$k1 ^ (($b & 0xff) << 8)}]
}
if {$remaining >= 1} {
binary scan [string index $tail 0] c b
set k1 [expr {$k1 ^ ($b & 0xff)}]
set k1 [expr {($k1 * $c1) & 0xffffffff}]
set k1 [expr {(($k1 << 15) | (($k1 & 0xffffffff) >> 17)) & 0xffffffff}]
set k1 [expr {($k1 * $c2) & 0xffffffff}]
set h1 [expr {$h1 ^ $k1}]
}
# Finalization (fmix)
set h1 [expr {$h1 ^ $length}]
set h1 [expr {$h1 ^ (($h1 & 0xffffffff) >> 16)}]
set h1 [expr {($h1 * 0x85ebca6b) & 0xffffffff}]
set h1 [expr {$h1 ^ (($h1 & 0xffffffff) >> 13)}]
set h1 [expr {($h1 * 0xc2b2ae35) & 0xffffffff}]
set h1 [expr {$h1 ^ (($h1 & 0xffffffff) >> 16)}]
return $h1
}
#-------------------------------------------------------------
# Numerical normalization: Avoid having different suffixes
# for cells with the same parameter values due to Tcl handling
# numerical values as strings, which makes "2", "2.0", and "2e0"
# all separate values. If hashed on the verbatim values, then
# the same device with the same parameters can have many
# different cell names, even though the layout is exactly the
# same. Avoid this by detecting when a parameter value is
# numeric and enforcing a consistent format (fixed precision,
# four decimal places).
#
# Code courtesy of ChatGPT
#-------------------------------------------------------------
proc magic::normalize_value {value} {
# Detect if value is numeric
if {[string is double -strict $value]} {
set num [expr {double($value)}]
# Check if effectively integer
if {abs($num - round($num)) < 1e-9} {
return [format "%d" [expr {int(round($num))}]]
}
# Otherwise, format to fixed precision (3 decimal places)
set str [format "%.3f" $num]
# Strip trailing zeros
regsub {\.?0+$} $str "" str
return $str
}
# Non-numeric: return as-is
return $value
}

View File

@ -138,7 +138,11 @@ proc magic::pushstack {{name ""}} {
if {[catch {lindex $editstack end}]} { if {[catch {lindex $editstack end}]} {
set editstack {} set editstack {}
} }
# Protect against changing units by always using internal units
set curunits [units]
units internal
lappend editstack [view get] lappend editstack [view get]
units {*}$curunits
lappend editstack [cellname list window] lappend editstack [cellname list window]
set ltag [tag load] set ltag [tag load]
tag load {} tag load {}
@ -158,10 +162,11 @@ proc magic::popstack {} {
tag load {} tag load {}
suspendall suspendall
load [lindex $editstack end] load [lindex $editstack end]
set snaptype [snap] # Protect against changing units by always using internal units
snap internal set curunits [units]
units internal
view [lindex $editstack end-1] view [lindex $editstack end-1]
snap $snaptype units {*}$curunits
catch {magic::cellmanager} catch {magic::cellmanager}
catch {magic::captions} catch {magic::captions}
resumeall resumeall
@ -186,8 +191,8 @@ proc magic::clearstack {} {
proc magic::pushbox {{values {}}} { proc magic::pushbox {{values {}}} {
global boxstack global boxstack
set snaptype [snap list] set curunits [units]
snap internal units internal
if {[catch {set boxstack}]} { if {[catch {set boxstack}]} {
set boxstack {} set boxstack {}
} }
@ -196,7 +201,7 @@ proc magic::pushbox {{values {}}} {
} else { } else {
lappend boxstack $values lappend boxstack $values
} }
snap $snaptype units {*}$curunits
return return
} }
@ -210,8 +215,8 @@ proc magic::pushbox {{values {}}} {
proc magic::popbox {{type values}} { proc magic::popbox {{type values}} {
global boxstack global boxstack
set snaptype [snap list] set curunits [units]
snap internal units internal
if {[catch {set boxstack}]} { if {[catch {set boxstack}]} {
error "No stack" error "No stack"
} elseif {$boxstack == {}} { } elseif {$boxstack == {}} {
@ -231,7 +236,7 @@ proc magic::popbox {{type values}} {
} }
} }
set boxstack [lrange $boxstack 0 end-1] set boxstack [lrange $boxstack 0 end-1]
snap $snaptype units {*}$curunits
return $b return $b
} }
@ -355,8 +360,8 @@ proc magic::ruler {{text {}} {orient auto}} {
set mmx [expr {($llx + $urx) / 2}] set mmx [expr {($llx + $urx) / 2}]
set mmy [expr {($lly + $ury) / 2}] set mmy [expr {($lly + $ury) / 2}]
set snapsave [snap] set curunits [units]
snap internal units internal
if {$orient == "horizontal"} { if {$orient == "horizontal"} {
element add line l1_$Opts(rulers) black $llx $lly $llx $ury element add line l1_$Opts(rulers) black $llx $lly $llx $ury
@ -410,7 +415,7 @@ proc magic::ruler {{text {}} {orient auto}} {
element configure l3_$Opts(rulers) flags arrowbottom element configure l3_$Opts(rulers) flags arrowbottom
} }
} }
snap $snapsave units {*}$curunits
} }
#--------------------------------------------------------------------- #---------------------------------------------------------------------
@ -529,8 +534,11 @@ proc magic::enable_tools {} {
# The user can change these bindings at will by using the # The user can change these bindings at will by using the
# "macro" command when the tool is active. # "macro" command when the tool is active.
# NOTE: Do not name a tool "netlist" because it will get
# confused with the "netlist" window.
magic::macro copy wiring magic::macro copy wiring
magic::macro copy netlist magic::macro copy nettool
magic::macro copy pick magic::macro copy pick
magic::tool wiring magic::tool wiring
@ -544,7 +552,7 @@ proc magic::enable_tools {} {
macro Button4 "wire incr width ; wire show" macro Button4 "wire incr width ; wire show"
macro Button5 "wire decr width ; wire show" macro Button5 "wire decr width ; wire show"
magic::tool netlist magic::tool nettool
macro Button1 "netlist select" macro Button1 "netlist select"
macro Button2 "netlist join" macro Button2 "netlist join"
macro Button3 "netlist terminal" macro Button3 "netlist terminal"
@ -699,8 +707,8 @@ proc magic::tool {{type next}} {
if {$type == "next"} { if {$type == "next"} {
switch $Opts(tool) { switch $Opts(tool) {
box { set type wiring } box { set type wiring }
wiring { set type netlist } wiring { set type nettool }
netlist { set type pick } nettool { set type pick }
pick { set type box } pick { set type box }
} }
} }
@ -756,9 +764,9 @@ proc magic::tool {{type next}} {
set Opts(tool) wiring set Opts(tool) wiring
cursor 19 ;# sets the cursor cursor 19 ;# sets the cursor
} }
netlist { nettool {
puts stdout {Switching to NETLIST tool.} puts stdout {Switching to NETLIST tool.}
set Opts(tool) netlist set Opts(tool) nettool
cursor 18 ;# sets the cursor cursor 18 ;# sets the cursor
} }
pick { pick {

View File

@ -684,7 +684,10 @@ proc magic::cursorview {win} {
*bypass crosshair ${olstx}um ${olsty}um *bypass crosshair ${olstx}um ${olsty}um
} }
if {[${win} box exists]} { # I do not know why the T/F result gets lost or overridden sometimes
set gotbox [${win} box exists]
if {$gotbox == {}} {set gotbox false}
if {$gotbox} {
set curunits [${win} units list] set curunits [${win} units list]
${win} units microns noprint ${win} units microns noprint
set dlst [${win} box position] set dlst [${win} box position]
@ -825,9 +828,9 @@ proc magic::setscrollvalues {win} {
global Opts global Opts
*bypass logcommands suspend *bypass logcommands suspend
set svalues [${win} view get]
set curunits [units list] set curunits [units list]
units internal noprint units internal noprint
set svalues [${win} view get]
set bvalues [${win} view bbox] set bvalues [${win} view bbox]
units {*}$curunits units {*}$curunits

View File

@ -25,6 +25,8 @@
#ifndef _MAGIC__TEXTIO__TEXTIO_H #ifndef _MAGIC__TEXTIO__TEXTIO_H
#define _MAGIC__TEXTIO__TEXTIO_H #define _MAGIC__TEXTIO__TEXTIO_H
#include <stdarg.h> /* va_list */
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/dqueue.h" /* DQueue */ #include "utils/dqueue.h" /* DQueue */

View File

@ -42,20 +42,6 @@ typedef struct {
#define TX_PROMPT '>' #define TX_PROMPT '>'
#define TX_CMD_PROMPT ":" #define TX_CMD_PROMPT ":"
/* all of the state associated with a tty terminal */
#if !defined(SYSV) && !defined(CYGWIN) && !defined(__OpenBSD__) && !defined(EMSCRIPTEN)
#if defined(HAVE_SYS_IOCTL_COMPAT_H) || defined(HAVE_SGTTY_H)
#if defined(HAVE_SYS_IOCTL_COMPAT_H)
#include <sys/ioctl_compat.h> /* replaced sgtty.h */
#elif defined(HAVE_SGTTY_H)
#include <sgtty.h>/* legacy - struct sgttyb{} defn */
#endif
typedef struct {
struct sgttyb tx_i_sgtty;
struct tchars tx_i_tchars;
} txTermState;
#endif /* HAVE_SYS_IOCTL_COMPAT_H || HAVE_SGTTY_H */
#endif /* SYSV */
extern bool TxGetInputEvent(bool block, bool returnOnSigWinch); extern bool TxGetInputEvent(bool block, bool returnOnSigWinch);

View File

@ -39,7 +39,6 @@ static char rcsid[] __attribute__ ((unused)) ="$Header: /usr/cvsroot/magic-8.0/t
#endif #endif
#include "tcltk/tclmagic.h" #include "tcltk/tclmagic.h"
#include "utils/magsgtty.h"
#include "utils/magic.h" #include "utils/magic.h"
#include "textio/textio.h" #include "textio/textio.h"
#include "utils/geometry.h" #include "utils/geometry.h"

View File

@ -32,14 +32,13 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include <dirent.h> #include <dirent.h>
#include "utils/magsgtty.h"
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/magsgtty.h"
#include "utils/main.h" #include "utils/main.h"
#include "textio/textio.h" #include "textio/textio.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "textio/txcommands.h" #include "textio/txcommands.h"
#include "textio/textioInt.h" #include "textio/textioInt.h"
#include "utils/magsgtty.h" /* txTermState */
#include "utils/dqueue.h" #include "utils/dqueue.h"
#include "utils/macros.h" #include "utils/macros.h"
#include "utils/hash.h" #include "utils/hash.h"
@ -1225,36 +1224,21 @@ TxGetLine(
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
#if defined(SYSV) || defined(CYGWIN)
void
txGetTermState(
struct termio *buf)
{
ioctl( fileno( stdin ), TCGETA, buf);
}
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
void
txGetTermState(
struct termios *buf)
{
(void) tcgetattr(fileno(stdin), buf);
}
#else
void void
txGetTermState( txGetTermState(
txTermState *buf) txTermState *buf)
{ {
#if defined(HAVE_TERMIOS_H)
(void) tcgetattr(fileno(stdin), &buf->termios);
#elif defined(HAVE_TERMIO_H)
ioctl(fileno(stdin), TCGETA, &buf->termio);
#else /* sgtty */
ASSERT(TxStdinIsatty, "txGetTermState"); ASSERT(TxStdinIsatty, "txGetTermState");
/* save the current terminal characteristics */ /* save the current terminal characteristics */
(void) ioctl(fileno(stdin), TIOCGETP, (char *) &(buf->tx_i_sgtty) ); (void) ioctl(fileno(stdin), TIOCGETP, (char *) &buf->tx_i_sgtty);
(void) ioctl(fileno(stdin), TIOCGETC, (char *) &(buf->tx_i_tchars) ); (void) ioctl(fileno(stdin), TIOCGETC, (char *) &buf->tx_i_tchars);
#endif
} }
#endif /* SYSV */
/* /*
@ -1273,24 +1257,17 @@ txGetTermState(
void void
txSetTermState( txSetTermState(
#if defined(SYSV) || defined(CYGWIN) txTermState *buf)
struct termio *buf
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
struct termios *buf
#else
txTermState *buf
#endif /* SYSV */
)
{ {
#if defined(SYSV) || defined(CYGWIN) #if defined(HAVE_TERMIOS_H)
ioctl( fileno(stdin), TCSETAF, buf ); (void) tcsetattr(fileno(stdin), TCSANOW, &buf->termios);
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN) #elif defined(HAVE_TERMIO_H)
(void) tcsetattr( fileno(stdin), TCSANOW, buf ); ioctl(fileno(stdin), TCSETAF, &buf->termio);
#else #else /* sgtty */
/* set the current terminal characteristics */ /* set the current terminal characteristics */
(void) ioctl(fileno(stdin), TIOCSETN, (char *) &(buf->tx_i_sgtty) ); (void) ioctl(fileno(stdin), TIOCSETN, (char *) &buf->tx_i_sgtty);
(void) ioctl(fileno(stdin), TIOCSETC, (char *) &(buf->tx_i_tchars) ); (void) ioctl(fileno(stdin), TIOCSETC, (char *) &buf->tx_i_tchars);
#endif /* SYSV */ #endif
} }
@ -1313,37 +1290,27 @@ txSetTermState(
void void
txInitTermRec( txInitTermRec(
#if defined(SYSV) || defined(CYGWIN) txTermState *buf)
struct termio *buf
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
struct termios *buf
#else
txTermState *buf
#endif /* SYSV */
)
{ {
#if defined(SYSV) || defined(CYGWIN) || defined(__OpenBSD__) || defined(EMSCRIPTEN) #if defined(HAVE_TERMIOS_H)
buf->c_lflag = ISIG; /* raw: no echo and no processing, allow signals */ buf->termios.c_lflag = ISIG; /* raw: no echo and no processing, allow signals */
buf->c_cc[ VMIN ] = 1; buf->termios.c_cc[ VMIN ] = 1;
buf->c_cc[ VTIME ] = 0; buf->termios.c_cc[ VTIME ] = 0;
#else #elif defined(HAVE_TERMIO_H)
buf->termio.c_lflag = ISIG; /* raw: no echo and no processing, allow signals */
buf->termio.c_cc[ VMIN ] = 1;
buf->termio.c_cc[ VTIME ] = 0;
#else /* sgtty */
/* set things up for us, turn off echo, turn on cbreak, no EOF */ /* set things up for us, turn off echo, turn on cbreak, no EOF */
buf->tx_i_sgtty.sg_flags |= CBREAK; buf->tx_i_sgtty.sg_flags |= CBREAK;
buf->tx_i_sgtty.sg_flags &= ~ECHO; buf->tx_i_sgtty.sg_flags &= ~ECHO;
buf->tx_i_tchars.t_eofc = -1; buf->tx_i_tchars.t_eofc = -1;
#endif
#endif /* SYSV */
} }
#if defined(SYSV) || defined(CYGWIN)
struct termio closeTermState;
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
struct termios closeTermState;
#else
static txTermState closeTermState; static txTermState closeTermState;
#endif /* SYSV */
static bool haveCloseState = FALSE; static bool haveCloseState = FALSE;
@ -1366,21 +1333,21 @@ static bool haveCloseState = FALSE;
void void
txSaveTerm(void) txSaveTerm(void)
{ {
#if defined(SYSV) || defined(CYGWIN) #if defined(HAVE_TERMIOS_H)
ioctl( fileno( stdin ), TCGETA, &closeTermState); (void) tcgetattr(fileno(stdin), &closeTermState.termios);
txEraseChar = closeTermState.c_cc[VERASE]; txEraseChar = closeTermState.termios.c_cc[VERASE];
txKillChar = closeTermState.c_cc[VKILL]; txKillChar = closeTermState.termios.c_cc[VKILL];
TxEOFChar = closeTermState.c_cc[VEOF]; TxEOFChar = closeTermState.termios.c_cc[VEOF];
TxInterruptChar = closeTermState.c_cc[VINTR]; TxInterruptChar = closeTermState.termios.c_cc[VINTR];
haveCloseState = TRUE; haveCloseState = TRUE;
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN) #elif defined(HAVE_TERMIO_H)
(void) tcgetattr( fileno( stdin ), &closeTermState); ioctl(fileno(stdin), TCGETA, &closeTermState.termio);
txEraseChar = closeTermState.c_cc[VERASE]; txEraseChar = closeTermState.termio.c_cc[VERASE];
txKillChar = closeTermState.c_cc[VKILL]; txKillChar = closeTermState.termio.c_cc[VKILL];
TxEOFChar = closeTermState.c_cc[VEOF]; TxEOFChar = closeTermState.termio.c_cc[VEOF];
TxInterruptChar = closeTermState.c_cc[VINTR]; TxInterruptChar = closeTermState.termio.c_cc[VINTR];
haveCloseState = TRUE; haveCloseState = TRUE;
#else #else /* sgtty */
struct ltchars lt; struct ltchars lt;
txGetTermState(&closeTermState); txGetTermState(&closeTermState);
(void) ioctl(fileno(stdin), TIOCGLTC, (char *) &lt); (void) ioctl(fileno(stdin), TIOCGLTC, (char *) &lt);
@ -1393,7 +1360,7 @@ txSaveTerm(void)
TxEOFChar = closeTermState.tx_i_tchars.t_eofc; TxEOFChar = closeTermState.tx_i_tchars.t_eofc;
TxInterruptChar = closeTermState.tx_i_tchars.t_intrc; TxInterruptChar = closeTermState.tx_i_tchars.t_intrc;
haveCloseState = TRUE; haveCloseState = TRUE;
#endif /* SYSV */ #endif
} }
@ -1414,13 +1381,7 @@ txSaveTerm(void)
void void
TxSetTerminal(void) TxSetTerminal(void)
{ {
#if defined(SYSV) || defined(CYGWIN)
struct termio buf;
#elif defined (__OpenBSD__) || defined(EMSCRIPTEN)
struct termios buf;
#else
txTermState buf; txTermState buf;
#endif /* SYSV */
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
/* If using Tk console, don't mess with the terminal settings; */ /* If using Tk console, don't mess with the terminal settings; */

View File

@ -26,7 +26,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "utils/magsgtty.h"
#include "utils/magic.h" #include "utils/magic.h"
#include "textio/textio.h" #include "textio/textio.h"
#include "utils/geometry.h" #include "utils/geometry.h"

View File

@ -31,7 +31,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include "utils/magsgtty.h"
#include "utils/magic.h" #include "utils/magic.h"
#include "textio/textio.h" #include "textio/textio.h"
#include "utils/geometry.h" #include "utils/geometry.h"

View File

@ -21,44 +21,54 @@
#ifndef _MAGIC__UTILS__MAGSGTTY_H #ifndef _MAGIC__UTILS__MAGSGTTY_H
#define _MAGIC__UTILS__MAGSGTTY_H #define _MAGIC__UTILS__MAGSGTTY_H
/* maybe this can be #ifndef HAVE_TERMIO_H */
#if !defined(SYSV) && !defined(CYGWIN)
# ifdef ALPHA
# undef MAX
# undef MIN
# endif
/* unclear what platform requires this OpenBSD/FreeBSD ? */
# ifndef COMPAT_43TTY
# define COMPAT_43TTY
# endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#if defined(HAVE_TERMIOS_H) #if defined(HAVE_TERMIOS_H)
#include <termios.h> /* In modern times everything has POSIX */
#elif defined(HAVE_SYS_IOCTL_COMPAT_H) #include <termios.h>
/* unclear which platform(s) require <sys/ioctl_compat.h> and the structure
* of this file is such that it will try to include it by default, better #ifdef HAVE_SYS_IOCTL_H
* to invert the #if and only select this on the known platforms that need /* Linux glibx 2.x - present
* it so that <termios.h> goes by default, which exists on MacOSX, Linux, etc.. * FreeBSD 14.3-RELEASE - present
* many possible solutions to make this work by default: * Solaris 11.4 - present
* HAVE_SYS_IOCTL_COMPAT_H ? HAVE_TERMIOS_H ? !defined(linux) at top (MaxOSX is BSD type) */
*/ #include <sys/ioctl.h>
#include <sys/ioctl_compat.h> /* replaced sgtty.h */ #endif
#elif defined(HAVE_SGTTY_H)
#include <sgtty.h> /* legacy - struct sgttyb{} defn */ #elif defined(HAVE_TERMIO_H)
/* Linux glibx 2.x - present (just includes termios.h & sys/ioctl.h)
* Linux glibc 2.45+ - not present
* FreeBSD 14.3-RELEASE - not present
* Solaris 11.4 - present
*/
#include <termio.h>
#else /* sgtty */
#if defined(HAVE_SYS_IOCTL_COMPAT_H)
/* Linux glibc2.x - not present
* FreeBSD 14.3-RELEASE - not present
* Solaris 11.4 - not present
*/
#include <sys/ioctl_compat.h> /* replaced sgtty.h */
#elif defined(HAVE_SGTTY_H)
/* Linux glibc2.x - present (includes sys/ioctl.h)
* FreeBSD 14.3-RELEASE - not present
* Solaris 11.4 - present
*/
#include <sgtty.h> /* legacy - struct sgttyb{} defn */
#endif
#endif #endif
#else
#if defined(HAVE_TERMIO_H) /* all of the state associated with a tty terminal */
#include <termio.h> typedef struct {
#if defined(HAVE_TERMIOS_H)
struct termios termios;
#elif defined(HAVE_TERMIO_H)
struct termio termio;
#else /* sgtty */
struct sgttyb tx_i_sgtty;
struct tchars tx_i_tchars;
#endif #endif
} txTermState;
#endif /* !SYSV && !CYGWIN */
#endif /* _MAGIC__UTILS__MAGSGTTY_H */ #endif /* _MAGIC__UTILS__MAGSGTTY_H */

View File

@ -38,7 +38,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/main.h" #include "utils/main.h"
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/malloc.h" #include "utils/malloc.h"
#include "utils/magsgtty.h"
#include "utils/hash.h" #include "utils/hash.h"
#include "utils/macros.h" #include "utils/macros.h"
#include "textio/textio.h" #include "textio/textio.h"

View File

@ -33,7 +33,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "tcltk/tclmagic.h" #include "tcltk/tclmagic.h"
#include "utils/main.h" #include "utils/main.h"
#include "utils/magic.h" #include "utils/magic.h"
#include "utils/magsgtty.h"
#include "textio/textio.h" #include "textio/textio.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "utils/signals.h" #include "utils/signals.h"

View File

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

View File

@ -1056,6 +1056,7 @@ windDoMacro(w, cmd, interactive)
bool do_help = FALSE; bool do_help = FALSE;
bool do_reverse = FALSE; bool do_reverse = FALSE;
char *searchterm = NULL; char *searchterm = NULL;
char *clientName = NULL;
macrodef *cMacro; macrodef *cMacro;
HashTable *clienttable; HashTable *clienttable;
HashEntry *h; HashEntry *h;
@ -1073,9 +1074,25 @@ windDoMacro(w, cmd, interactive)
argstart = 1; argstart = 1;
if (cmd->tx_argc == 1) if (cmd->tx_argc == 1)
wc = DBWclientID; /* Added by NP 11/15/04 */ wc = DBWclientID; /* Default client */
else if (cmd->tx_argc > 1) else if (cmd->tx_argc > 1)
{
wc = WindGetClient(cmd->tx_argv[1], TRUE); wc = WindGetClient(cmd->tx_argv[1], TRUE);
if (wc != NULL)
{
clientName = cmd->tx_argv[1];
argstart++;
}
else
{
/* Check if argument is a known layout button handler */
if (DBWButtonHandlerIndex(cmd->tx_argv[1]) != -1)
{
clientName = cmd->tx_argv[1];
argstart++;
}
}
}
while (cmd->tx_argc > argstart) while (cmd->tx_argc > argstart)
{ {
@ -1116,6 +1133,15 @@ windDoMacro(w, cmd, interactive)
wc = DBWclientID; wc = DBWclientID;
} }
MacroCopy(wc, cmd->tx_argv[argstart]); MacroCopy(wc, cmd->tx_argv[argstart]);
/* If tool name did not previously exist, then add
* it to the list of known tool names, so that it
* can be found later by the "macro" command.
*/
if (DBWButtonHandlerIndex(cmd->tx_argv[argstart]) == -1)
DBWAddButtonHandler(cmd->tx_argv[argstart],
(const cb_database_buttonhandler_t)NULL,
0, (const char *)NULL);
} }
return; return;
} }
@ -1147,26 +1173,53 @@ windDoMacro(w, cmd, interactive)
if (MacroKey(cmd->tx_argv[argstart], &verbose) == 0) if (MacroKey(cmd->tx_argv[argstart], &verbose) == 0)
if (MacroKey(cmd->tx_argv[argstart + 1], &verbose) != 0) if (MacroKey(cmd->tx_argv[argstart + 1], &verbose) != 0)
{
wc = 0;
argstart++;
return; return;
}
} }
} }
else
argstart++; /* If a clientName wasn't given, but wc is DBWclientID, then get
* the clientName from the default button handler.
*/
if ((clientName == NULL) && (wc == DBWclientID))
clientName = DBWGetButtonHandler();
if (cmd->tx_argc == argstart) if (cmd->tx_argc == argstart)
{ {
if (wc == (WindClient)0) if (clientName == NULL)
h = NULL;
else
h = HashLookOnly(&MacroClients, (char *)clientName);
if (h == NULL)
{ {
TxError("No such client.\n"); #ifdef MAGIC_WRAPPER
Tcl_Obj *lobj;
lobj = Tcl_NewListObj(0, NULL);
#endif
TxError("Cannot get macro list from current window.\n");
#ifndef MAGIC_WRAPPER
TxError("List of known macro clients:\n");
#endif
/* If clientName was not in MacroClients, then what is? */
HashStartSearch(&hs);
while ((h = HashNext(&MacroClients, &hs)) != NULL)
{
char *clientName = h->h_key.h_name;
#ifdef MAGIC_WRAPPER
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(clientName, -1));
#else
TxError("%s ", clientName);
#endif
}
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, lobj);
#else
TxError("\n");
#endif
return; return;
} }
h = HashLookOnly(&MacroClients, (char *)wc);
if (h == NULL)
return;
else else
{ {
clienttable = (HashTable *)HashGetValue(h); clienttable = (HashTable *)HashGetValue(h);

View File

@ -820,22 +820,27 @@ windViewCmd(w, cmd)
if (!strncmp(cmd->tx_argv[1], "get", 3)) if (!strncmp(cmd->tx_argv[1], "get", 3))
{ {
char *vllx, *vlly, *vurx, *vury;
vllx = DBWPrintValue(w->w_surfaceArea.r_xbot, w, TRUE);
vlly = DBWPrintValue(w->w_surfaceArea.r_ybot, w, FALSE);
vurx = DBWPrintValue(w->w_surfaceArea.r_xtop, w, TRUE);
vury = DBWPrintValue(w->w_surfaceArea.r_ytop, w, FALSE);
/* NOTE: The surface area is in screen (pixel) coordinates /* NOTE: The surface area is in screen (pixel) coordinates
* and so does not follow the "units" display type. * and so does not follow the "units" display type.
*/ */
#ifndef MAGIC_WRAPPER #ifndef MAGIC_WRAPPER
TxPrintf("(%d, %d) to (%d, %d)\n", TxPrintf("(%s, %s) to (%s, %s)\n", vllx, vlly, vurx, vury);
w->w_surfaceArea.r_xbot, w->w_surfaceArea.r_ybot,
w->w_surfaceArea.r_xtop, w->w_surfaceArea.r_ytop);
#else #else
Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_ListObjAppendElement(magicinterp, listxy,
Tcl_NewIntObj((int)w->w_surfaceArea.r_xbot)); Tcl_NewStringObj(vllx, -1));
Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_ListObjAppendElement(magicinterp, listxy,
Tcl_NewIntObj((int)w->w_surfaceArea.r_ybot)); Tcl_NewStringObj(vlly, -1));
Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_ListObjAppendElement(magicinterp, listxy,
Tcl_NewIntObj((int)w->w_surfaceArea.r_xtop)); Tcl_NewStringObj(vurx, -1));
Tcl_ListObjAppendElement(magicinterp, listxy, Tcl_ListObjAppendElement(magicinterp, listxy,
Tcl_NewIntObj((int)w->w_surfaceArea.r_ytop)); Tcl_NewStringObj(vury, -1));
Tcl_SetObjResult(magicinterp, listxy); Tcl_SetObjResult(magicinterp, listxy);
#endif #endif
} }
@ -949,7 +954,7 @@ windXviewCmd(w, cmd)
celluse = (CellUse *) (w->w_surfaceID); celluse = (CellUse *) (w->w_surfaceID);
DBExpandAll(celluse, &(celluse->cu_bbox), DBExpandAll(celluse, &(celluse->cu_bbox),
((DBWclientRec *)w->w_clientData)->dbw_bitmask, FALSE, ((DBWclientRec *)w->w_clientData)->dbw_bitmask, DB_UNEXPAND,
ViewUnexpandFunc, ViewUnexpandFunc,
(ClientData)(pointertype) (((DBWclientRec *)w->w_clientData)->dbw_bitmask)); (ClientData)(pointertype) (((DBWclientRec *)w->w_clientData)->dbw_bitmask));