Initial commit at Tue Apr 25 08:41:48 EDT 2017 by tim on stravinsky

This commit is contained in:
Tim Edwards 2017-04-25 08:41:48 -04:00
commit 231a299b16
1249 changed files with 520134 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
*.*%
*.cdslck
.inca.db.*
inca.*.pak
*.swp
*~
*/av_extracted*/
.nfs*
*.cd-
*/mommdl/

72
INSTALL Normal file
View File

@ -0,0 +1,72 @@
Autoconf Capsule Summary:
----------------------------------------
Compile and install:
./configure [options]
make
make install
Autoconf options (use "./configure --help" for a complete list):
--prefix=DIR Indicates the install directory. Determines the
install directory of the executable. Determines the
install directory of the libraries (${prefix}/lib)
unless use of "--libdir=DIR" overrides it. Defaults
to /usr/local/.
--libdir=DIR By default, ${prefix}/lib/. Otherwise, run-time
files used by magic are installed here, and
${CAD_ROOT} is set to DIR. In some distributions,
this is set to /usr/share/.
--with-interpreter=ARG
Enable one of the two interpreters. ARG may be
one of "tcl" or "scheme".
--with-tcl Equivalent to "--with-interpreter=tcl".
Normally enabled, if available.
--with-opengl Enable OpenGL as a graphics option. Normally
enabled, if available.
--without-x Disable X11 as a graphics option. Normally
enabled.
--disable-nonmanhattan
Disable non-Manhattan extensions. Normally
enabled.
--disable-readline
Disable the GNU "readline" package. Normally
enabled.
--disable-threads
Disable threaded X11 and OpenGL graphics.
Normally enabled.
Notes to Magic maintainers:
--------------------------
This directory contains all the sources for the Magic system and related
programs. The system runs on a number of machines. You should read the
Magic Maintainer's manual as well as the introduction to Magic before
compiling the system. These documents are in the "doc" subdirectory in
PostScript, as well as the original LaTeX source.
The "proper" way to profile the amount of CPU time spent in each procedure
is to edit "defs.mak" and add flag "-pg" to CFLAGS. Then recompile, install,
and run. Note that this doesn't work with the Tcl version; you have to
compile the standalone version. After running, magic creates a file "gmon.out".
To view the contents, run "gprof /usr/local/bin/magic > gprof.out" (the output
can be very long).
Memory tracing in Tcl requires that Tcl and Tk be compiled with the
TCL_MEM_DEBUG option. Magic also must be compiled with TCL_MEM_DEBUG,
which can be done by adding the definition -DTCL_MEM_DEBUG to DFLAGS
in defs.mak, after running "configure".
Magic is normally compiled without the optimization flag. This is handled
by explicitly setting CFLAGS as an environment variable in the top-level
"configure" script prior to calling scripts/configure. The top-level
configure script needs to be modified to enable compile-time optimization.

129
Makefile Normal file
View File

@ -0,0 +1,129 @@
#
# rcsid $Header: /usr/cvsroot/magic-8.0/Makefile,v 1.1.1.1 2008/02/03 20:43:49 tim Exp $
#
MAGICDIR = .
PROGRAMS = magic
TECH = scmos
LIBRARIES = database utils extflat
MODULES = cmwind commands database dbwind debug drc extflat extract \
graphics netmenu plow resis select sim textio tiles utils \
windows wiring
MAKEFLAGS =
INSTALL_CAD_DIRS = windows doc ${TECH}
include defs.mak
all: $(ALL_TARGET)
standard:
@echo --- errors and warnings logged in file make.log
@${MAKE} mains 2>&1 | tee -a make.log | egrep -i "(.c:|Stop.|---)"
tcl:
@echo --- errors and warnings logged in file make.log
@${MAKE} tcllibrary 2>&1 | tee -a make.log | egrep -i "(.c:|Stop.|---)"
force: clean all
defs.mak:
@echo No \"defs.mak\" file found. Run "configure" to make one.
config:
${MAGICDIR}/configure
tcllibrary: database/database.h modules
@echo --- making Tcl shared libraries
for dir in ${PROGRAMS}; do \
(cd $$dir && ${MAKE} tcl-main); done
mains: database/database.h modules libs
@echo --- making main programs
for dir in ${PROGRAMS}; do \
(cd $$dir && ${MAKE} main); done
database/database.h: database/database.h.in
@echo --- making header file database/database.h
${SCRIPTS}/makedbh database/database.h.in database/database.h
modules:
@echo --- making modules
for dir in ${MODULES} ${PROGRAMS}; do \
(cd $$dir && ${MAKE} module); done
libs:
@echo --- making libraries
for dir in ${LIBRARIES}; do \
(cd $$dir && ${MAKE} lib); done
depend: database/database.h
${RM} */Depend
for dir in ${MODULES} ${UNUSED_MODULES} ${PROGRAMS}; do \
(cd $$dir && ${MAKE} depend); done
install: $(INSTALL_TARGET)
install-magic:
@echo --- installing executable to $(DESTDIR)${BINDIR}
@echo --- installing runtime files to $(DESTDIR)${LIBDIR}
@${MAKE} install-real 2>&1 >> install.log
install-real: install-dirs
for dir in ${INSTALL_CAD_DIRS}; do \
(cd $$dir && ${MAKE} install); done
for dir in ${PROGRAMS}; do \
(cd $$dir && ${MAKE} install); done
install-tcl-dirs:
${MAGICDIR}/scripts/mkdirs $(DESTDIR)${BINDIR} $(DESTDIR)${MANDIR} \
$(DESTDIR)${SYSDIR} $(DESTDIR)${TCLDIR} $(DESTDIR)${TCLDIR}/bitmaps
install-dirs:
${MAGICDIR}/scripts/mkdirs $(DESTDIR)${BINDIR} $(DESTDIR)${MANDIR} \
$(DESTDIR)${SYSDIR} $(DESTDIR)${SCMDIR}
install-tcl:
@echo --- installing executable to $(DESTDIR)${BINDIR}
@echo --- installing runtime files to $(DESTDIR)${LIBDIR}
@${MAKE} install-tcl-real 2>&1 >> install.log
install-tcl-real: install-tcl-dirs
for dir in ${INSTALL_CAD_DIRS} ${PROGRAMS}; do \
(cd $$dir && ${MAKE} install-tcl); done
clean:
for dir in ${MODULES} ${PROGRAMS} ${TECH} ${UNUSED_MODULES}; do \
(cd $$dir && ${MAKE} clean); done
${RM} *.tmp */*.tmp *.sav */*.sav *.log TAGS tags
distclean:
touch defs.mak
@${MAKE} clean
${RM} defs.mak old.defs.mak ${MAGICDIR}/scripts/defs.mak
${RM} ${MAGICDIR}/scripts/default.conf
${RM} ${MAGICDIR}/scripts/config.log ${MAGICDIR}/scripts/config.status
${RM} scripts/magic.spec magic-`cat VERSION` magic-`cat VERSION`.tgz
${RM} *.log
dist:
${RM} scripts/magic.spec magic-`cat VERSION` magic-`cat VERSION`.tgz
sed -e /@VERSION@/s%@VERSION@%`cat VERSION`% \
scripts/magic.spec.in > scripts/magic.spec
ln -nsf . magic-`cat VERSION`
tar zchvf magic-`cat VERSION`.tgz --exclude CVS \
--exclude magic-`cat VERSION`/magic-`cat VERSION` \
--exclude magic-`cat VERSION`/magic-`cat VERSION`.tgz \
magic-`cat VERSION`
clean-mains:
for dir in ${PROGRAMS}; do \
(cd $$dir && ${RM} $$dir); done
tags:
${RM} tags
find . ${MODULES} ${PROGRAMS} -name "*.[ch]" -maxdepth 1 | xargs ctags -o tags
TAGS:
${RM} TAGS
find . ${MODULES} ${PROGRAMS} -name "*.[ch]" -maxdepth 1 | xargs etags -o TAGS

374
README Normal file
View File

@ -0,0 +1,374 @@
1. General Information:
---------------------------------
Use your World Wide Web browser to read:
http://opencircuitdesign.com/magic/
http://vlsi.csl.cornell.edu/magic/
http://www.research.digital.com/wrl/magic/magic.html
Primary documentation is on the opencircuitdesign.com website under
the "Documentation" link.
The current development versions of magic are maintained by Tim Edwards
<tim@opencircuitdesign.com> and the current distribution version is
maintained by Rajit Manohar <rajit@csl.cornell.edu>. Please let us
know of any problems/bugs you find. Development of versions 7.2 and
newer is generously funded by MultiGiG, Inc.
2. Compilation and Installation:
---------------------------------
See the file "INSTALL" in this directory.
3. Version 8.2 Release Notes:
---------------------------------
As of the release of version 8.2, Version 8.1 is now the new stable
distribution, and 8.2 is the development distribution.
4. Version 8.1 Release Notes:
---------------------------------
As of the release of version 8.1, Version 8.0 is now the new stable
distribution, and 8.1 is the development distribution.
What's new in 8.1:
------------------
1) Substantially revised substrate handling allows for "soft
connectivity" detection, and resolves (finally) the problem of
the hack handling of nMOS bulk connections using a default
name without any understanding of a substrate node and
connectivity.
5. Version 8.0 Release Notes:
---------------------------------
As of the release of version 8.0, Version 7.5 is now the new stable
distribution, and 8.0 is the development distribution.
What's new in 8.0:
------------------
1) Vector outline fonts with ability to control font, scale, rotation,
and offset. Public-license outline fonts provided by the freefont
project.
2) Hierarchical SPICE output for LVS.
3) New cifoutput operators including "net" and "maxrect", specifically
for using with the "cif paint" command.
4) DRC method for handling via rules specifying overlap on two
opposite sides but not on the others.
5) Improved DRC method that ignores errors in subcells that are
masked by the parent cell.
6) Improved cell manager based on methods available in Tk 8.5
7) New extraction method "msubcircuit" with methods for specifying
parameter names for source/drain area and perimeter.
6. Version 7.5 Release Notes:
---------------------------------
Version 7.5 is the development branch. Version 7.5.0 is the same as
7.4.2, which is essentially the same as 7.3.123, plus some
documentation updates. Intended development is as follows:
What's new in 7.5:
------------------
1) Use a finely spaced grid for the database, but keep the concept
of "lambda" for layout. Keep backwards compatibility, and resolve
issues with layout that does not work well on the lambda grid.
Implemented in 7.5.1 by allowing a DRC "scalefactor" line,
which declares that all DRC rules are in units of (lambda /
scalefactor). Rules "in use" are scaled to lambda and rounded to
the nearest integer. The original value is retained, however, so
that any call to "scalegrid" will recompute the DRC distances based
on the current internal grid. Thus, we can define DRC rules in
fractional lambda and therefore match vendor DRC rule distances
while still maintaining magic's concept of "lambda". This means
that users working entirely within magic have scalable CMOS rules,
but if a "vendor cell" (3rd party GDS or CIF) is loaded, the DRC
rules will be correct with respect to it.
2) Multiple DRC styles allowed in the technology file.
3) Memory-mapped tile allocation using the mmap() function.
4) Layer and cell instance locking
5) Euclidean-distance measure on "cif grow" operator.
6) "cif paint" command to automatically manipulate the database
paint using "cifoutput" rulesets.
7) New contact-cut generation algorithm.
8) Added the ability to define and extract MOS devices with
asymmetric source and drain.
9) Added extraction devices "rsubcircuit" and "subcircuit" to
produce subcircuit records in SPICE output, with a method to
define parameters to be passed to the subcircuit.
10) Added resistor corner scaling (i.e., the resistance of a
material at a corner can be set as a fraction of the resistance
of the same material on a straight path).
11) Updated the interactive maze router, fixing many bugs, and adding
many enhancements, including a maze router GUI that can be used
to aid in interactively routing an entire netlist, or performing
a verification of a netlist against the layout.
12) "gridlimit" keyword in the cifoutput section to prevent magic
from generating geometry beyond a specific resolution.
13) Added the ability to specify all units in the extract section in
microns, and added a simplified method for specifying standard
parasitic capacitance extraction rules.
14) "gds merge true" option to generate polygons in the GDS output
instead of tiles. This creates *much* smaller output files at
the expense of processing time.
15) New "contact" function to automatically contact two layers at
an intersection.
See the online release notes for a more thorough list of features.
7. Version 7.4 Release Notes:
---------------------------------
Version 7.4 is the new stable distribution version of magic.
Apart from changes to the release notes, it is identical to
the last revision (123) of development version 7.3. Revisions
of 7.4 will be made as necessary to fix bugs in the code. All
new additions and major changes will be done to the new
development distribution, version 7.5. Therefore there will
not be a "What's new in 7.4" section, as there is not supposed
to be anything new in version 7.4.
8. Version 7.3 Release Notes:
---------------------------------
Magic release 7.3 incorporates a stacked contact model which is,
for the most part, backwardly compatible with Magic releases
7.2 and earlier. Information about this developmental release
can be found at:
http://opencircuitdesign.com/magic/magic7_3.html
What's new in 7.3:
------------------
Provided by Tim Edwards (MultiGiG, Inc.):
1) Stacked contact model allowing arbitrary stacking of
contact types.
2) A separate "undo/redo" method for network selection, to
remove the memory overhead associated with selecting and
unselecting large networks. Also removes some time overhead
as well, especially when unselecting networks.
3) Much improved "plot pnm" function.
4) Improved transistor and resistor extraction.
5) LEF format reader; improved LEF/DEF input/output handling
6) New style and colormap file formats
7) Vendor GDS read/write capability
8) "wire segment" drawing function
9) Handling of path records in CIF and GDS input
10) Handling of cell scaling in GDS input
11) Pi-network device extraction for resistors
12) Option to write contacts as cell arrays in GDS output
13) New "widespacing" and "maxwidth" DRC algorithms.
14) "polygon" command
15) New cifoutput operator "bloat-all"
16) Backing-store for 24-bit and OpenGL graphics
17) New "pick" tool for interactive selection move and copy
18) New interactive "wire" tool
19) Crosshair
20) New cifoutput operator "slots"
21) New fcntl-based file locking mechanism
22) "angstroms" units supported in cifinput/cifoutput
23) Non-Manhattan device extraction support
24) New "feedback" mechanism
25) Proper support for > 32 planes (up to 64)
26) Fixed array interaction CIF/GDS generation
27) Added executable "magicdnull" for streamlined batch-mode use
28) New method for crash backups, including restore with "magic -r"
29) A number of other technology file additions and enhancements
9. Version 7.2 Release Notes:
---------------------------------
Magic release 7.2 incorporates the capability to run magic from the Tcl
interpreter with graphics handled by Tk. Instructions for compiling
and installing this version are in README.Tcl. Information about
this release can be found at:
http://opencircuitdesign.com/magic/magic7_2.html
What's new in 7.2:
------------------
Provided by Tim Edwards (MultiGiG, Inc., and JHU Applied Physics Lab):
1) Tcl interpreter extension option
2) Cygwin compile option
3) Memory resources cleaned up
4) GUI interface to Tcl version of Magic
5) Readline update to version 4.3
6) OpenGL fixes and refinements
7) Nonmanhattan geometry fixes and extensions
8) Threaded graphics in non-Tcl environments
9) Inductance extraction
10) CIF and GDS input/output support for deep submicron technologies
11) Different internal and lambda grids, including automatic or
induced ("scalegrid" command) grid subdivision and expansion.
"snap" and "grid" functions and extensions aid layout when
lambda and internal units differ.
12) Removed commands "list", "listall", "parent", and "child",
replacing them with the more general-purpose "cellname"
and "instance" commands.
13) Added command "tech", and re-loadable technologies.
14) Revamped the "dstyle" files and updated the dstyle version
15) Added "element" types for layout annotation.
16) Extended extract section of techfile to include "device"
keyword and devices "mosfet", "bjt", "capacitor", and "resistor".
New model resistor and mosfet use width/length instead of area/
perimeter.
17) Added 3D rendering window invoked by command "specialopen wind3d",
for the Tcl version compiled with OpenGL graphics.
18) Added "height" keyword to tech file for height/thickness values
19) Added "windowname" command for managing multiple wrapper windows
under Tcl.
20) Added extraction extension for annular (ring) MOSFETs.
21) Added "widespacing" DRC rule.
22) Added GNU autoconf compile
23) New command "property" for setting key:value pair properties
in cell definitions that can be interpreted by other routines
(such as LEF/DEF).
24) General-purpose subcircuit method using the "port" command to
declare a cell to be a subcircuit and to mark the position and
orientation of connections into the subcell. This replaces a
method previously built into version 7.2 using a "subcircuit"
layer; that method is now considered obsolete.
25) LEF and DEF format readers, LEF format writer.
26) Improved techfile format with asterisk-notation and DRC
"surround", "overhang", and "rect_only" statements.
10. Version 7.1 Release Notes:
---------------------------------
Magic release 7.1 consolidates all known patches/features
to magic version 6.5.x, and contains additional features that have
been added since the consolidation. Information about this release
is available at the magic web site:
http://vlsi.cornell.edu/magic/
What's new in 7.1:
------------------
Provided by Rajit Manohar (Cornell University) (formerly version 7.0):
1) Implementation of "scheme" (a subset of lisp), a powerful method
of generating complex functions.
2) Using CVS to facilitate source code development from multiple sites.
3) New commands using scheme: Too many to mention here; see the
tutorials in doc/tutscm* for explanations. Functions themselves
are defined in ${CAD_ROOT}/magic/scm/*.scm
4) Overhauled the readline interface. See doc/textfiles/readline.txt for
details.
5) Changed tons of stuff about the build environment:
- the include paths in all files is now canonical.
- redid the make process and rewrote all Makefiles.
- tons of other small things that hopefully make the build process
nicer.
11. Releases prior to version 7:
---------------------------------
What's new in 6.5.2:
--------------------
Provided by R. Timothy Edwards (Johns Hopkins Applied Physics Laboratory):
1) Support for OpenGL
Look at doc/open_gl.txt
2) Minor update to :config for selection of multiple graphics
interfaces.
3) Updates to dstyle and cmap files
4) Always do a check to see if there is only one active layout
window: There's no need to annoy the user with complaints
of "Put the cursor in a layout window" when there is no
possibility of confusion about the matter.
Provided by Philippe Pouliquen (Johns Hopkins University):
5) "readline" command line editing capability
6) Macro extensions for X11 (see doc/macro_extension.txt)
7) Better handling of filenames on the UNIX command-line (multiple
filenames allowed, ".mag" extension not required).
8) New commands: "child", "parent", "down", "xload", "list", "listall",
"listtop", "shell", "imacro".
9) Command alterations: "box [+|-][dir]", "select visible", area of box
included in "box" command.
10) Updated .magic macro file (source in magic/proto.magic, install in
${CAD_ROOT}/magic/sys/.magic) (see doc/default_macros.txt).
What's new in 6.5.1:
--------------------
1) Support for true-color displays (courtesy of Michael Godfrey)
Look into doc/hires-color.txt
2) Minor updates in ext2sim, ext2spice
What's new in 6.5:
-----------------
1) Bug fixes in the extractor propagation of attributes (SU)
2) New version of ext2sim ext2spice with support for hspice, spice2,
and spice3 (SU)
3) Integration of the port to SUN's Solaris OS (MIT)
4) Port to FreeBSD2.x. Thanks to John Wehle (john@jwlab.feith.com)
5) Integration of part of the DEC/WRL code fragments into the drc
code. Since the code is not completely trustworthy the fragments
are ifdef'd so if need be the drc will behave exactly as the old one.
(you just need to change the #define DRC_EXTENSIONS in drc/drc.h
to do that). For a description of the extensions look into
doc/tutwrl1.ps (DEC/WRL)
6) Integration of some patches in to the CIF code that introduce:
(i) A new cif operation squares-grid which generates contacts
on grid.
(ii) A new cif layer command min-width is added so that generated
layers have the correct min drc width when magic expands
layers in the hierarchy (like it does with wells).
Magic-6.5 crashes if compiled with gcc in Solaris2.x/SunOS5.x (curiously enough
it does not have that problem if compiled with Sun's cc compiler). To get
around that you need to set the flag -DUSE_SYSTEM_MALLOC flag in misc/DFLAGS
after you run make :config. The error has to do with allignment of doubles
and an alternative way to get rid of it is to change extract/extractInt.h
so that CapValue is float instead of double. Nevertheless the first method
is recomended.
What's new in 6.4:
------------------
This release, magic 6.4, contains the following modifications:
1) A number of bug fixes from the 6.3 notes.
2) A version numbering facility for tech files. Please add a new
section to each tech file after the "tech" section, following
this example:
version
version 2.0.3
description "MOSIS CMOS 0.13u Nano-nano technology."
end
Older versions of magic will complain about the new section, but
no harm will be done.
4) Various comments describing dates and versions, including the
above tech file information, are not written to the CIF file.
3) Support for patches and versioning: A new command called "version"
lists out the version number and patches that are installed.
A header file called patchlevel.h keeps track of a PATCHLEVEL
integer and a string in patchlevel.c keeps track of the names of
each installed patch. When posting patches to the net please be
sure your patch updates variables. See the files for details.
4) Ports to Alpha AXP OSF/1, SGI/IRIX (courtesy of Stefanos
Sidiropoulos) and Linux (courtesy of Harold Levy).
5) A change in the extractor algorithm to provide shielding for
perimeter capacitances. Also a change in ext2sim to maintain
information about the area and perimeter of diffusion and
the bulk connection of the fets (written by Stefanos
Sidiropoulos).

385
README.Tcl Normal file
View File

@ -0,0 +1,385 @@
-------------------------------------------------------------------
A Tcl-wrapped version of magic
-------------------------------------------------------------------
This file contains details on the compilation, installation, and
execution of the Tcl interpreter-based version of Magic.
-------------------------------------------------------------------
Compiling and Installation
-------------------------------------------------------------------
Compiling and installing have been simplified, but are not exactly the
same as the "standard" compile and install procedure, so be sure to
read these instructions first.
1) Software prerequisites:
You will need Tcl and Tk versions 8.2+. Testing has been done on Tcl
and Tk versions 8.3 and 8.4. Some commands are only compatible with
versions 8.2 and newer; these should be #ifdef'd sometime in the near
future to make the program compatible with Tcl versions at least back
to 8.0. For use with the wrapper GUI, it is preferable to have BLT
version 2.4 or newer to get the tree view of the cell hierarchy,
although the presence of BLT is not mandatory. For digital simulation,
you should have IRSIM version 9.6 revision 1 or newer. Presence of
IRSIM is not mandatory. Note that unlike magic versions 7.1 and older,
the IRSIM module is not selected at compile-time; in Tcl it is a
run-time loadable module.
2) At the top level, do "./configure" and any other options (such as
"--prefix=DIR" for non-default installation location). "prefix"
determines the value $CAD_ROOT, which is set to ${prefix}/lib,
unless "--libdir=DIR" is set, in which case $CAD_ROOT is set to
this value. The "configure" script will determine
if Tcl is on the system, and enable it if it appears to be usable.
Note that if Tcl is installed in a non-standard location, it will
be necessary to pass the option "--with-tcl=<DIR>" to "configure",
indicating the directory where the file "tclConfig.sh" can be found.
Likewise, the "configure" script attempts to find OpenGL include
files and libraries on the system, and enables the option if it can
find them. Again, if in a nonstandard location, it is necessary to
pass the option "--with-opengl=<DIR>" indicating the directory where
OpenGL include files may be found. It is assumed that the libraries
are in a standard directory; if not, it may be necessary to make
symbolic links to them from a standard directory like /usr/X11R6/lib/.
3) Do "make". This should complete the compilation of the Tcl-compatible
shared library file "magic/tcl/tclmagic.so".
4) Do "make install". This should place all the necessary executables,
library files, etc., into the proper places. The main executable is
"magic" (a script). Normally, it runs Tcl from a console window
("tkcon", at least for now). With a command-line argument "-noconsole",
it runs Tcl from the terminal (runs "magicexec", a stand-in for "wish").
Original executables "ext2spice" and "ext2sim" have been changed to magic
command-line commands. They are available as separate packages to Tcl
and are loaded automatically by the startup Tcl script.
5) Any other ".tcl" files (packages) for magic go in $CAD_ROOT/magic/tcl/.
Magic's Tcl startup appends this directory to Tcl's search directory for
Tcl/Tk executables.
6) Make sure that the default .magic script and any user .magic scripts do
not have embedded control characters (see below in "Known Bugs"). The
one installed by the distribution is correct; the warning applies to
any legacy files.
-------------------------------------------------------------------
Running Tcl-based magic
-------------------------------------------------------------------
1) The startup script works out namespaces so that all magic commands
become directly available from the command line. A number of
commands have to be specially handled because of conflicts with
existing Tcl/Tk commands. These are: "flush", "clockwise",
"array", "load", "label", and "grid". From magic version 7.2
revision 31, all of these commands can be run as either the
original Tcl/Tk command or as the magic command, and the
correct function will be called (because the syntax of the two
forms is mutually exclusive).
In cases such as starting magic from another application like
irsim or netgen, all magic commands are prefixed by the
namespace "::magic::" to differentiate them from command names
in other applications.
Note that some commands (ones which are not often used) have
simply been renamed. The command "list" has been replaced (and
its functionality extended) by commands "cellname" and "intance".
Command "split" has been changed to "splitpaint" (which matches
the "spliterase" command).
Commands "source" and "send" are superceded by Tcl methods and
no longer exist as their former selves in magic. In particular,
"send" (sends a magic command to a window) is superceded by the
syntax of the window name followed by the magic command (see item
4, below). Because magic extends Tcl, the "source" command is
equivalent to Tcl's "source" command).
Commands for separate packages (namely, ext2sim and ext2spice) share
the magic namespace: magic::ext2sim and magic::ext2spice.
The magic startup script automatically loads these packages and makes
the commands available from the root namespace, i.e., "ext2sim" and
"ext2spice".
2) Command entry works as follows: Because the underlying Tcl interpreter
is *supposed* to look and act like a normal Tcl interpreter, single-key
macros are only allowed from inside windows. The use of the ":" macro
(long-command) is implemented as faithfully as allowed by the interpreter.
When using the terminal as a console, it is not possible to enter a
command partially in the terminal or window and complete it in the
other. Also, the status of the background DRC is not reflected in the
cursor. The "tkcon" console-based version has a cursor which reflects
the DRC status, and commands may be entered partially or in full in
either the layout or the console windows. The cursor is "%" for normal
operation, "]" for DRC-in-progress, and ":" for commands initiated by
the long-command macro. Note that due to inherent limitations of the
Tk "text" widget, the insert cursor is not displayed in the console when
the cursor is in the layout window. Queries to the user force focus
into the console window; this will probably be reimplemented in dialog
boxes in the future.
3) Tcl-magic should work with "tclreadline". The "tkcon" console-based
version has its own working readline-like capability. Note that
internally defined completion functions like cellname completion are
not available.
4) Window commands: Note that in addition to the standard magic commands,
the Tcl/Tk version makes it possible to direct commands to a particular
window; e.g., ".magic2 paint m1" can be run from the command line in
place of putting the cursor in window ".magic2" and executing the
command "paint m1". This allows any possible magic command to be run
from a script.
The deprecation of magic's "send" command has repercussions on window
commands, particularly when using non-layout windows. For example, the
[non-TCL-based magic] command "send netlist shownet" is supposed to
execute the "shownet" command in the context of the netlist window
("specialopen netlist"). However, under Tk, "netlist" is not a valid
window path; the correct command is to note the window name (usually
something like ".magic2") and to use it to direct the command:
".magic2 shownet" will execute the command "shownet" in the context of
window ".magic2".
5) Command tags: A command called "tag" has been added with the following
syntax:
magic::tag <command_name> <tcl_procedure>
This allows an arbitrary Tcl procedure to be associated with any
magic command. The usual reason to do this is to allow GUI functions
to be updated in response to command-line entry or key macros in a
window. The method can also be used to re-organize Tcl output from
a command, or send commands to another Tcl application in response
to actions in magic.
<command_name> is a simple command name without any namespace
qualifier (e.g., "select" or "paint"). <tcl_procedure> is a string
which may be either an inline procedure or a call to a defined Tcl
procedure. This string may contain certain embedded escapes which
will be substituted prior to evaluation. The escapes are:
%W Full Tk pathname of the layout window
%R Tcl result of <command_name>. The result is
absorbed.
%r Tcl result of <command_name>. The result will be
returned to the calling function as usual.
%0 .. %5 Arguments passed to <command_name>.
%% A single percent character.
6) Windows can be generated as internal Tk windows instead of top-level
windows by using the command
magic::openwindow <cellname> <tk_window_path_name>.
For example, the script:
toplevel .layout
magic::openwindow "(UNNAMED)" .layout.magic1
pack .layout.magic1 -expand true -fill both
bind .layout.magic11 <Enter> {focus %W}
generates a new window inside a toplevel frame named "layout", which
can be customized. In this case, the layout window does nothing except
contain the magic window. The fourth line ensures that the magic
window can generate keyboard events.
Generation of full-frame GUIs is facilitated by the "-n[owindow]"
option, which brings magic up with the indicated graphics package but
no actual window displayed. It is up to the calling application to
call "magic::openwindow" and arrange the geometry and packing of the
windows.
7) Another method for generating windows is to use the
"image create layer" method. For example, the command
'openwindow "(UNNAMED)" .magic2' creates a new Tk window which
starts off unmapped. Followed by "image create layer img_layout
-name .magic2 -width 300 -height 300", an internal (offscreen)
pixmap is created in place of the Tk window, and will be updated
with changes to the layout just as any window would be. The
image "img_layout" can be used to drop the layout image into any Tk
widget which accepts images (such as the canvas and button widgets).
The syntax is "image create layer <image_name> -name <tk_window_path>
-width <width> -height <height>". Note that the Tk window is
destroyed when the image is instanced; this does not occur with the
"image create" command, but when the image is first mapped to the
screen. Here's an example which generates a button containing the
magic layout:
openwindow "(UNNAMED)" .magic2
image create layer img_layout -name .magic2
toplevel .new
button .new.b1 -image img_layout
pack .new.b1
Layout may be painted in the window using command-line commands.
Entering the button with the cursor will refresh the layout view.
IMPORTANT NOTE: When magic is run with OpenGL graphics ("-d OGL"
command-line option), the implementation uses the off-screen
rendering functions to draw layout onto pixmaps for the button
image feature mentioned above. There are a number of video card
drivers that do not correctly implement these functions, and will
crash magic if the toolbar is used.
8) Some commands have been altered in the Tcl environment to return
results to the interpreter rather than simply print them as
messages on stdout. One example is "getnode", which returns the
string value of the selected node:
set n [.magic1 getnode]
Others implemented: "path sys|cell|search" returns a string
containing the indicated path. "box values" returns the box
coordinates. "windowcaption" returns the window title caption.
"cellname" and "instance", with the option "list", return their
results as Tcl lists.
9) Environment variables and Tcl global variables: A few environment
variables are queried for backward compatibility; eventually all of
these should be either replaced or duplicated by Tcl global variables.
Currently, "$CAD_ROOT" is a duplicated variable. It can be set in the
UNIX shell environment prior to running Tcl-magic, and the Tcl variable
"$CAD_ROOT" will be duplicated from it. Otherwise, the Tcl variable
"$CAD_ROOT" will be set to the value determined by the "make config"
process. The use of "~cad" is completely deprecated.
The new "make" process encourages the use of standard directory
trees such as "/usr/local/lib" for CAD_ROOT, rather than the oddball
"/home/cad/lib". The new system works well with user-installed versions
having no access to root filesystem directories for installation.
10) Modes of operation: Tcl-based magic runs in all graphics modes,
including 8-bit PseudoColor, 16- and 24-bit TrueColor, and OpenGL.
When using a console and/or GUI wrapper in PseudoColor mode, magic
redefines all of the Tk colors in the console and the wrapper frame
so that they match the magic color scheme. The console gets the
magic layout colormap so that one can move between the layout
windows and the console without altering the colormap of either one.
11) A "wrapper" GUI is in "wrapper.tcl" and is normally present;
it can be disabled with the command "magic -nowrapper" (or
"magic -now"). This wrapper removes magic's own title bar and
frame and replaces them with a frame managed by Tcl/Tk.
The features of the wrapper are:
A) Scrollbars are replaced by Tk scrollbars, but the functions
are essentially the same.
B) The caption is replaced by a Tk widget, with the same
function.
C) The box coordinates are displayed at the right-hand side
of the title bar.
D) A menubar is provided at the top left-hand corner. This
has entries "File" and "Options". "File" takes
care of many read and write functions (including CIF and
GDS). Options are:
a) "Toolbar" enables a toolbar to the right of the
layout. This toolbar contains all of the layer types
in the technology file. Entering the button displays
the name of the layer type in the title bar. Clicking
with mouse button 2 or keystroke "p" paints the layer
type in the box on the layout window. Keystroke "e"
erases the layer type in the box. Clicking with mouse
button 3 hides the layer type in the layout window, and
clicking mouse button 1 restores it. Keystroke "s"
selects all paint of the layer type within the cursor
box.
b) "Cell Manager" pops up a display showing the hierarchy
of layout cells in memory. This option is only available
if the BLT package for Tcl/Tk has been installed on the
system. When BLT is installed, the option will simply
appear.
c) "Tech Manager" pops up a display showing various
properties of the currently loaded technology and provides
a convenient way to change technologies or CIF read/write
and extraction styles.
d) "Pinout List" is a simple list widget that can search
a layout for layer type "pad", and enumerates all of
the pad instances found in the layout. This aids in
the task of generating the pin names in the final
stages of a chip design.
12) Extraction:
The Tcl version of magic makes use of the interpreter variable
space to work around some former deficiencies of the extractor.
Power and ground nodes can be explicitly defined by setting
variables $VDD and $GND in the Tcl global variable space
(e.g, "::set VDD VDD" and "::set GND GND"). If these are not
defined, then magic reverts to its original behavior of looking
for node names ending with "!". The Tcl variable names (or any
Tcl variable names) can be added to the techfile definition of
a device's default substrate node name (include the "$" in front
of the variable). Normally, this would use the two built-in
variables $GND and $VDD. These variables should be set in the
".magic" file of each project directory, so that the default
device substrate connections will match the power and ground
definitions in a layout. If $GND and $VDD are defined but do
not match any node names in the layout, a warning is flagged.
13) IRSIM simulation:
Starting with revision 14, magic 7.2 supports interactive digital
simulation with IRSIM. It is necessary to compile IRSIM version
9.6 or better with Tcl enabled, and it is necessary to have the Tcl
package "BLT" for the graphing window to work. IRSIM version
9.6 has a "make" procedure which is exactly like magic's. It is
preferable to set CAD_ROOT to the same value for both programs
when doing "make config", so magic can find and automatically
load the IRSIM package when it needs to.
The Tcl procedure "startirsim" loads and runs IRSIM. Since both
programs get loaded into the same interpreter, commands for both
magic and IRSIM can be executed on the command line. When IRSIM
is started with magic running, a number of commands are added to
the interpreter which communicate between the two packages.
Examples are "watchnode", "watchtime", and "drawnode". See the
"README" file in the IRSIM source for more information on running
IRSIM under magic and an explanation of the full set of commands
available.
------------------------------------------------------------------
Tcl-specific bugs and annoyances:
-------------------------------------------------------------------
1) The Tcl prompt ("% ") appears at all times when the terminal is used
for command entry. The desired behavior is that the magic prompt
">" (or "]" while DRC is pending) should appear when the cursor is
in a window, indicating that the input is accepting keyboard macros.
When outside of the window or after using the macro ":" to get to the
command-line entry from magic, the Tcl "%" prompt appears, indicating
that all valid Tcl commands may be entered at the prompt.
Because it is not possible to detect if a partial Tcl command is on
the command line, it is only possible to enter part of a command in
the terminal window and complete the command in the magic window if
":" is typed in the magic window to redirect keyboard input to the
terminal.
The "tkcon" console-based version does not have this limitation and
operates more or less like the original magic prompt.
2) Magic's original ".magic" file has control characters embedded. This
is the only magic command syntax which is illegal Tcl syntax. However,
magic 7.1 allows control characters to be written either as "^X" (two
characters, with a caret) or "Control_X". If the original .magic is
used (i.e., Tcl-magic is compiled and run, but not installed),
the embedded controls should be changed to printable ASCII format.
3) There are routines which handle 8-bit pseudocolor mode by mapping
tk colors to magic colors by the magic "short name" as listed in
the dstyle file. This generally works well, except: 1) if the
cursor is inside a layout window when it comes up, the colormap
gets installed permanently; the window manager no longer reverts
to the original colormap when leaving the window. 2) there is
currently no routine to revert the console back to its original
colors and revert to the original colormap. 3) the colors could
use a bit of tweaking.
------------------------------------------------------------------

8
TODO Normal file
View File

@ -0,0 +1,8 @@
I. Bugs to fix (also in magic-7.5 [stable]):
1. The "extresist" code only recognizes original "fet" types, not
the new "device" types in the extract file.
2. "plow" has been broken for some time. It should derive its rules
from the DRC decks (using the new routines that are meant for just
that sort of thing).

1
VERSION Normal file
View File

@ -0,0 +1 @@
8.2.0

1079
calma/CalmaRdcl.c Normal file

File diff suppressed because it is too large Load Diff

547
calma/CalmaRdio.c Normal file
View File

@ -0,0 +1,547 @@
/*
* CalmaReadio.c --
*
* Input of Calma GDS-II stream format.
* Low-level input.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/calma/CalmaRdio.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/utils.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "utils/malloc.h"
#include "utils/tech.h"
#include "cif/cif.h"
#include "cif/CIFint.h"
#include "cif/CIFread.h"
#include "utils/signals.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "utils/styles.h"
#include "textio/textio.h"
#include "calma/calmaInt.h"
/* Forward declarations */
bool calmaReadR8();
bool calmaSkipBytes();
/*
* ----------------------------------------------------------------------------
*
* calmaReadTransform --
*
* Read a CALMA_STRANS, CALMA_MAG, CALMA_ANGLE sequence and construct
* the corresponding geometric transform.
*
* Results:
* TRUE normally, FALSE on EOF or fatal syntax error.
*
* Side effects:
* Consumes input.
* Modifies the Transform pointed to by 'ptrans'.
*
* ----------------------------------------------------------------------------
*/
bool
calmaReadTransform(ptrans, name)
Transform *ptrans; /* Fill in this transform */
char *name; /* Name of subcell (for errors) */
{
int nbytes, rtype, flags, angle;
double dangle;
double dmag;
Transform t;
/* Default is the identity transform */
*ptrans = GeoIdentityTransform;
/* Is there any transform at all? */
READRH(nbytes, rtype);
if (nbytes < 0) return (FALSE);
if (rtype != CALMA_STRANS)
{
UNREADRH(nbytes, rtype);
return (TRUE);
}
if (nbytes != 6)
{
(void) calmaSkipBytes(nbytes - CALMAHEADERLENGTH);
return (FALSE);
}
READI2(flags);
/* Look for magnification and angle */
READRH(nbytes, rtype);
if (nbytes < 0) return (FALSE);
if (rtype == CALMA_MAG)
{
if (nbytes != CALMAHEADERLENGTH + 8)
{
(void) calmaSkipBytes(nbytes - CALMAHEADERLENGTH);
return (FALSE);
}
if (!calmaReadR8(&dmag)) return (FALSE);
if (dmag != (double)((int)(dmag + 0.5)))
{
calmaReadError("Non-integer magnification (%g) in transform\n", dmag);
calmaReadError("Rounding to %d.\n", (int)(dmag + 0.5));
}
GeoScaleTrans(ptrans, (int)(dmag + 0.5), &t);
*ptrans = t;
}
else UNREADRH(nbytes, rtype);
READRH(nbytes, rtype);
if (nbytes < 0) return (FALSE);
dangle = 0.0;
if (rtype == CALMA_ANGLE)
{
if (nbytes != CALMAHEADERLENGTH + 8)
{
(void) calmaSkipBytes(nbytes - CALMAHEADERLENGTH);
return (FALSE);
}
if (!calmaReadR8(&dangle)) return (FALSE);
}
else UNREADRH(nbytes, rtype);
/* Make sure the angle is Manhattan */
angle = (int) dangle;
while (angle < 0) angle += 360;
while (angle > 360) angle -= 360;
switch (angle)
{
case 360:
angle = 0;
break;
case 0: case 90: case 180: case 270:
break;
default:
calmaReadError("Non-Manhattan angle (%d) in transform\n", angle);
if (angle < 45) angle = 0;
else if (angle < 135) angle = 90;
else if (angle < 225) angle = 180;
else if (angle < 315) angle = 270;
else angle = 0;
calmaReadError(" Rounding to %d degrees.\n", angle);
}
/*
* Construct the transform.
* Magic angles are clockwise; Calma angles are counterclockwise.
*/
if (flags & CALMA_STRANS_UPSIDEDOWN)
{
GeoTransTrans(ptrans, &GeoUpsideDownTransform, &t);
*ptrans = t;
}
switch (angle)
{
case 90:
GeoTransTrans(ptrans, &Geo270Transform, &t);
*ptrans = t;
break;
case 180:
GeoTransTrans(ptrans, &Geo180Transform, &t);
*ptrans = t;
break;
case 270:
GeoTransTrans(ptrans, &Geo90Transform, &t);
*ptrans = t;
break;
}
return (TRUE);
}
/*
* ----------------------------------------------------------------------------
*
* calmaReadI2Record --
*
* Read a record that should contain a two-byte integer.
*
* Results:
* TRUE on success, FALSE if the record type we read is not
* what we're expecting, or if it is of the wrong size.
*
* Side effects:
* Consumes input.
* Stores the result value in *pvalue (note that this is a normal
* int, even though we're reading only 16 bits from the input).
*
* ----------------------------------------------------------------------------
*/
bool
calmaReadI2Record(type, pvalue)
int type; /* Type of record expected */
int *pvalue; /* Store value here */
{
int nbytes, rtype, n;
READRH(nbytes, rtype);
if (nbytes < 0)
goto eof;
if (type != rtype)
{
calmaUnexpected(type, rtype);
return (FALSE);
}
/* Read the value */
READI2(n);
if (feof(calmaInputFile)) goto eof;
*pvalue = n;
return (TRUE);
eof:
calmaReadError("Unexpected EOF.\n");
return (FALSE);
}
/*
* ----------------------------------------------------------------------------
*
* calmaReadI4Record --
*
* Read a record that should contain a four-byte integer.
*
* Results:
* TRUE on success, FALSE if the record type we read is not
* what we're expecting, or if it is of the wrong size.
*
* Side effects:
* Consumes input.
* Stores the result value in *pvalue.
*
* ----------------------------------------------------------------------------
*/
bool
calmaReadI4Record(type, pvalue)
int type; /* Type of record expected */
int *pvalue; /* Store value here */
{
int nbytes, rtype, n;
READRH(nbytes, rtype);
if (nbytes < 0)
goto eof;
if (type != rtype)
{
calmaUnexpected(type, rtype);
return (FALSE);
}
/* Read the value */
READI4(n);
if (feof(calmaInputFile)) goto eof;
*pvalue = n;
return (TRUE);
eof:
calmaReadError("Unexpected EOF.\n");
return (FALSE);
}
/*
* ----------------------------------------------------------------------------
*
* calmaReadStringRecord --
*
* Read a record that should contain an ASCII string.
*
* Results:
* TRUE on success, FALSE if the record type we read is not
* what we're expecting.
*
* Side effects:
* Consumes input.
* Allocates memory for string str (must be freed by the caller)
* Stores the result in the string pointed to by 'str'.
*
* ----------------------------------------------------------------------------
*/
bool
calmaReadStringRecord(type, str)
int type;
char **str;
{
int nbytes, rtype;
READRH(nbytes, rtype);
if (nbytes < 0)
goto eof;
if (type != rtype)
{
calmaUnexpected(type, rtype);
return (FALSE);
}
nbytes -= CALMAHEADERLENGTH;
*str = (char *) mallocMagic(nbytes + 1);
if (fread(*str, sizeof (char), nbytes, calmaInputFile) != nbytes)
goto eof;
*(*str + nbytes) = '\0';
return (TRUE);
eof:
calmaReadError("Unexpected EOF.\n");
return (FALSE);
}
/*
* ----------------------------------------------------------------------------
*
* calmaReadR8 --
*
* Read a single 8-byte real number in Calma stream format.
* Convert to internal double-precision format and store in
* the double pointed to by 'pd'.
*
* Results:
* TRUE on success, FALSE if EOF is encountered.
*
* Side effects:
* Consumes input.
* Stores the result in the *pd.
*
* ----------------------------------------------------------------------------
*/
bool
calmaReadR8(pd)
double *pd; /* Store result in *pd */
{
int i, exponent;
unsigned char dchars[8];
double mantissa, d;
bool isneg;
if (fread((char *) dchars, sizeof (char), sizeof dchars,
calmaInputFile) != sizeof dchars)
return (FALSE);
/* Extract the sign and exponent */
exponent = dchars[0];
if (isneg = (exponent & 0x80))
exponent &= ~0x80;
exponent -= 64;
/* Construct the mantissa */
mantissa = 0.0;
for (i = 7; i > 0; i--)
{
mantissa += dchars[i];
mantissa /= 256.0;
}
/* Now raise the mantissa to the exponent */
d = mantissa;
if (exponent > 0)
{
while (exponent-- > 0)
d *= 16.0;
}
else if (exponent < 0)
{
while (exponent++ < 0)
d /= 16.0;
}
/* Make it negative if necessary */
if (isneg)
d = -d;
*pd = d;
return (TRUE);
}
/*
* ----------------------------------------------------------------------------
*
* calmaSkipSet --
*
* Skip all records falling in a specified set of types.
* Leave the input stream positioned to the start of the first
* record not in the specified set.
*
* The array pointed to by 'skipwhat' contains the record types
* of all records to be skipped, terminated with -1.
*
* Results:
* None.
*
* Side effects:
* Consumes input.
*
* ----------------------------------------------------------------------------
*/
void
calmaSkipSet(skipwhat)
int *skipwhat;
{
int *skipp;
int nbytes, rtype;
for (;;)
{
READRH(nbytes, rtype);
if (nbytes < 0)
return;
for (skipp = skipwhat; *skipp >= 0; skipp++)
if (*skipp == rtype)
goto skipit;
UNREADRH(nbytes, rtype);
break;
skipit:
(void) calmaSkipBytes(nbytes - CALMAHEADERLENGTH);
}
}
/*
* ----------------------------------------------------------------------------
*
* calmaSkipExact --
*
* Skip a single stream record, which must be of the type 'type'.
* Leave the input positioned to the start of the record following
* this one. Complain if the record is not the one expected.
*
* Results:
* TRUE if successful, FALSE if we encountered an error and
* the caller should abort.
*
* Side effects:
* Consumes input.
*
* ----------------------------------------------------------------------------
*/
bool
calmaSkipExact(type)
int type;
{
int nbytes, rtype;
/* Eat up the record header */
READRH(nbytes, rtype);
if (nbytes < 0)
goto eof;
/* Skip remainder of record */
if (!calmaSkipBytes(nbytes - CALMAHEADERLENGTH))
goto eof;
if (rtype != type)
{
calmaUnexpected(type, rtype);
return (FALSE);
}
return (TRUE);
eof:
calmaReadError("Unexpected EOF.\n");
return (FALSE);
}
/*
* ----------------------------------------------------------------------------
*
* calmaSkipTo --
*
* Skip to a record of a particular type. Leaves the input stream
* positioned AFTER the record whose type is given by 'what'.
*
* Results:
* TRUE if we found this record, FALSE if EOF was encountered.
*
* Side effects:
* Consumes input.
*
* ----------------------------------------------------------------------------
*/
bool
calmaSkipTo(what)
int what;
{
int nbytes, rtype;
do
{
READRH(nbytes, rtype);
if (nbytes < 0)
return (FALSE);
calmaSkipBytes(nbytes - CALMAHEADERLENGTH);
} while (rtype != what);
return (TRUE);
}
/*
* ----------------------------------------------------------------------------
*
* calmaSkipBytes --
*
* Skip 'nbytes' bytes from the input.
* WARNING: this procedure doesn't know about input saved via UNREADRH(),
* so if the caller wants this input to be discarded, it must call READRH()
* itself.
*
* Results:
* TRUE if successful, FALSE if EOF was encountered.
*
* Side effects:
* Consumes nbytes of input.
*
* ----------------------------------------------------------------------------
*/
bool
calmaSkipBytes(nbytes)
int nbytes; /* Skip this many bytes */
{
while (nbytes-- > 0)
if (getc(calmaInputFile) < 0)
return (FALSE);
return (TRUE);
}

1018
calma/CalmaRdpt.c Normal file

File diff suppressed because it is too large Load Diff

494
calma/CalmaRead.c Normal file
View File

@ -0,0 +1,494 @@
/*
* CalmaRead.c --
*
* Input of Calma GDS-II stream format.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/calma/CalmaRead.c,v 1.3 2010/06/24 12:37:15 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <netinet/in.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/utils.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "utils/malloc.h"
#include "utils/tech.h"
#include "cif/cif.h"
#include "cif/CIFint.h"
#include "cif/CIFread.h"
#include "utils/signals.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "utils/styles.h"
#include "textio/textio.h"
#include "calma/calmaInt.h"
#include "commands/commands.h" /* for CmdGetRootPoint */
#include "utils/undo.h"
/* Globals for Calma reading */
FILE *calmaInputFile = NULL; /* Read from this stream */
FILE *calmaErrorFile = NULL; /* Write error output here */
bool CalmaSubcellPolygons = FALSE; /* Put non-Manhattan polygons
* in their own subcells.
*/
int CalmaPolygonCount;
bool CalmaFlattenUses = FALSE; /* If TRUE, small cells in the input
* stream are flattened when encountered
* as uses. This improves magic's
* performance when handling contacts
* saved as subcell arrays.
*/
bool CalmaReadOnly = FALSE; /* Set files to read-only and
* retain file position information
* so cells can be written verbatim.
*/
bool CalmaNoDRCCheck = FALSE; /* If TRUE, don't mark cells as needing
* a DRC check; they will be assumed
* DRC clean.
*/
bool CalmaPostOrder = FALSE; /* If TRUE, forces the GDS parser to
* read cells in post-order. It is
* necessary, e.g., when we need to
* flatten cells that are contact cuts.
* Added by Nishit 8/16/2004
*/
extern void calmaUnexpected();
bool calmaParseUnits();
/*
* Scaling.
* Multiply all coordinates by calmaReadScale1, then divide them
* by calmaReadScale2 in order to get coordinates in centimicrons.
*/
int calmaReadScale1;
int calmaReadScale2;
int calmaTotalErrors;
/*
* Lookahead: calmaLApresent is TRUE when calmaLAnbytes and calmaLArtype
* are set to the record header of a record we just ungot.
*/
bool calmaLApresent; /* TRUE if lookahead input waiting */
int calmaLAnbytes; /* # bytes in record (from header) */
int calmaLArtype; /* Record type */
/*
* Hash table for errors, indexed by (layer, datatype).
* The corresponding entry in this table is created whenever
* a (layer, datatype) is seen that we don't recognize, so
* we don't output an error message more than once.
*/
HashTable calmaLayerHash;
/*
* Hash table to keep track of all defs that have appeared
* in this file. Indexed by cell def name.
*/
HashTable calmaDefInitHash;
/* Common stuff to ignore */
int calmaElementIgnore[] = { CALMA_ELFLAGS, CALMA_PLEX, -1 };
/*
* ----------------------------------------------------------------------------
*
* CalmaReadFile --
*
* Read an entire GDS-II stream format library from the open FILE 'file'.
*
* Results:
* None.
*
* Side effects:
* May modify the contents of cifReadCellDef by painting or adding
* new uses or labels. May also create new CellDefs.
*
* ----------------------------------------------------------------------------
*/
void
CalmaReadFile(file, filename)
FILE *file; /* File from which to read Calma */
char *filename; /* The real name of the file read */
{
int k, version;
char *libname = NULL;
MagWindow *mw;
static int hdrSkip[] = { CALMA_FORMAT, CALMA_MASK, CALMA_ENDMASKS,
CALMA_REFLIBS, CALMA_FONTS, CALMA_ATTRTABLE,
CALMA_STYPTABLE, CALMA_GENERATIONS, -1 };
static int skipBeforeLib[] = { CALMA_LIBDIRSIZE, CALMA_SRFNAME,
CALMA_LIBSECUR, -1 };
/* We will use full cell names as keys in this hash table */
CIFReadCellInit(0);
if (CIFWarningLevel == CIF_WARN_REDIRECT)
{
if (CIFErrorFilename == NULL)
calmaErrorFile = NULL;
else
calmaErrorFile = PaOpen(CIFErrorFilename, "w", (char *)NULL, ".",
(char *)NULL, (char **)NULL);
}
if (cifCurReadStyle == NULL)
{
TxError("Don't know how to read GDS-II:\n");
TxError("Nothing in \"cifinput\" section of tech file.\n");
return;
}
TxPrintf("Warning: Calma reading is not undoable! I hope that's OK.\n");
UndoDisable();
calmaTotalErrors = 0;
CalmaPolygonCount = 0;
HashInit(&calmaDefInitHash, 32, 0);
calmaLApresent = FALSE;
calmaInputFile = file;
/* Read the GDS-II header */
if (!calmaReadI2Record(CALMA_HEADER, &version)) goto done;
if (version < 600)
TxPrintf("Library written using GDS-II Release %d.0\n", version);
else
TxPrintf("Library written using GDS-II Release %d.%d\n",
version / 100, version % 100);
if (!calmaSkipExact(CALMA_BGNLIB)) goto done;
calmaSkipSet(skipBeforeLib);
if (!calmaReadStringRecord(CALMA_LIBNAME, &libname)) goto done;
if ((libname != NULL) && (libname[0] != '\0'))
{
/* Avoid generating a magic name with spaces in it. . . */
/* (added by Mike Godfrey, 7/17/05) */
for (k = 0; k < strlen(libname); k++)
if (libname[k] == ' ')
libname[k] = '_';
TxPrintf("Library name: %s\n", libname);
}
/* Skip the reflibs, fonts, etc. cruft */
calmaSkipSet(hdrSkip);
/* Set the scale factors */
if (!calmaParseUnits()) goto done;
/* Main body of GDS-II input */
while (calmaParseStructure(filename))
if (SigInterruptPending)
goto done;
(void) calmaSkipExact(CALMA_ENDLIB);
done:
/* Added by Nishit, Sept. 2004---Load cell read from GDS */
/* stream file to the magic layout window. If this fails */
/* then we do the original action and don't do a load into */
/* the window. Note that this follows the Magic GDS output */
/* convention of giving the library the name of the */
/* top-level cell, so magic-produced GDS can be read back */
/* with the expected cell appearing in the layout window. */
if (libname != NULL)
{
mw = CmdGetRootPoint((Point *)NULL, (Rect *)NULL);
if (mw == NULL)
windCheckOnlyWindow(&mw, DBWclientID);
if (mw != NULL)
{
if (calmaLookCell(libname, NULL) != (CellDef *)NULL)
DBWloadWindow(mw, libname, FALSE);
}
freeMagic(libname);
}
CIFReadCellCleanup(1);
HashKill(&calmaDefInitHash);
UndoEnable();
if (calmaErrorFile != NULL) fclose(calmaErrorFile);
}
/*
* ----------------------------------------------------------------------------
*
* calmaParseUnits --
*
* Process the CALMA_UNITS record that sets the relationship between
* user units (stored in the stream file) and centimicrons.
*
* Results:
* TRUE if successful, FALSE if we encountered an error and
* the caller should abort.
*
* Side effects:
* Consumes input.
* Sets calmaReadScale1 to the number of centimicrons per user
* unit, and calmaReadScale2 to 1, unless calmaReadScale1 would be
* less than 1, in which case we set calmaReadScale1 to 1 and
* calmaReadScale2 to 1/calmaReadScale1.
*
* NOTE:
* We don't care about user units, only database units. The
* GDS-II stream specifies the number of meters per database
* unit, which we use to compute the number of centimicrons
* per database unit. Since database units are floating point,
* there is a possibility of roundoff unless the number of
* centimicrons per user unit is an integer value.
*
* ----------------------------------------------------------------------------
*/
bool
calmaParseUnits()
{
int nbytes, rtype;
double metersPerDBUnit;
double userUnitsPerDBUnit;
double cuPerDBUnit;
READRH(nbytes, rtype);
#ifdef lint
nbytes = nbytes;
#endif /* lint */
if (rtype != CALMA_UNITS)
{
calmaUnexpected(CALMA_UNITS, rtype);
return (FALSE);
}
/* Skip user units per database unit */
if (!calmaReadR8(&userUnitsPerDBUnit)) return (FALSE);
/* Read meters per database unit */
if (!calmaReadR8(&metersPerDBUnit)) return (FALSE);
#ifdef notdef
TxPrintf("1 database unit equals %e user units\n", userUnitsPerDBUnit);
TxPrintf("1 database unit equals %e meters\n", metersPerDBUnit);
TxPrintf("1 user unit equals %e database units\n", 1.0/userUnitsPerDBUnit);
TxPrintf("1 meter equals %e database units\n", 1.0/metersPerDBUnit);
#endif /* notdef */
/* Meters per database unit (1.0e8 corresponds to traditional centimicrons) */
cuPerDBUnit = metersPerDBUnit * 1.0e8 * cifCurReadStyle->crs_multiplier;
/*
* Multiply database units by calmaReadScale1, then divide
* by calmaReadScale2 to get CIF units. The current scheme
* relies entirely on calmaReadScale1 being an integer.
*/
if (cuPerDBUnit >= 1.0)
{
calmaReadScale1 = (int)(cuPerDBUnit + 0.5);
calmaReadScale2 = 1;
}
else
{
cuPerDBUnit = 1.0 / cuPerDBUnit;
calmaReadScale1 = 1;
calmaReadScale2 = (int)(cuPerDBUnit + 0.5);
}
#ifdef notdef
TxPrintf("All units to be scaled by %d/%d\n", calmaReadScale1, calmaReadScale2);
#endif /* notdef */
return (TRUE);
}
/*
* ----------------------------------------------------------------------------
*
* calmaReadError --
*
* This procedure is called to print out error messages during
* Calma file reading.
*
* Results:
* None.
*
* Side effects:
* An error message is printed.
*
* Note:
* You can add more arguments if 10 turns out not to be enough.
*
* ----------------------------------------------------------------------------
*/
void
/*VARARGS1*/
calmaReadError(format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
char *format;
char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8, *a9, *a10;
{
calmaTotalErrors++;
if (CIFWarningLevel == CIF_WARN_NONE) return;
if ((calmaTotalErrors < 100) || (CIFWarningLevel != CIF_WARN_LIMIT))
{
if (CIFWarningLevel == CIF_WARN_REDIRECT)
{
if (calmaErrorFile != NULL)
{
fprintf(calmaErrorFile, "Error while reading cell \"%s\": ",
cifReadCellDef->cd_name);
fprintf(calmaErrorFile, format, a1, a2, a3, a4, a5, a6, a7,
a8, a9, a10);
}
}
else
{
TxError("Error while reading cell \"%s\": ", cifReadCellDef->cd_name);
TxError(format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
}
}
else if ((calmaTotalErrors == 100) && (CIFWarningLevel == CIF_WARN_LIMIT))
{
TxError("Error limit set: Remaining errors will not be reported.\n");
}
}
/*
* ----------------------------------------------------------------------------
*
* calmaUnexpected --
*
* Complain about a record where we expected one kind but got another.
*
* Results:
* None.
*
* Side effects:
* Prints an error message.
*
* ----------------------------------------------------------------------------
*/
void
calmaUnexpected(wanted, got)
int wanted; /* Type of record we wanted */
int got; /* Type of record we got */
{
calmaReadError("Unexpected record type in input: \n");
if (CIFWarningLevel == CIF_WARN_NONE) return;
if (calmaTotalErrors < 100 || (CIFWarningLevel != CIF_WARN_LIMIT))
{
if (CIFWarningLevel == CIF_WARN_REDIRECT)
{
if (calmaErrorFile != NULL)
{
fprintf(calmaErrorFile," Expected %s record ",
calmaRecordName(wanted));
fprintf(calmaErrorFile, "but got %s.\n", calmaRecordName(got));
}
}
else
{
TxError(" Expected %s record ", calmaRecordName(wanted));
TxError("but got %s.\n", calmaRecordName(got));
}
}
}
/*
* ----------------------------------------------------------------------------
*
* calmaRecordName --
*
* Return a pointer to the printable name of a CALMA record type.
*
* Results:
* See above.
*
* Side effects:
* May overwrite the string we returned on the previous call.
*
* ----------------------------------------------------------------------------
*/
char *
calmaRecordName(rtype)
int rtype;
{
static char numeric[10];
static char *calmaRecordNames[] =
{
"HEADER", "BGNLIB", "LIBNAME", "UNITS",
"ENDLIB", "BGNSTR", "STRNAME", "ENDSTR",
"BOUNDARY", "PATH", "SREF", "AREF",
"TEXT", "LAYER", "DATATYPE", "WIDTH",
"XY", "ENDEL", "SNAME", "COLROW",
"TEXTNODE", "NODE", "TEXTTYPE", "PRESENTATION",
"SPACING", "STRING", "STRANS", "MAG",
"ANGLE", "UINTEGER", "USTRING", "REFLIBS",
"FONTS", "PATHTYPE", "GENERATIONS", "ATTRTABLE",
"STYPTABLE", "STRTYPE", "ELFLAGS", "ELKEY",
"LINKTYPE", "LINKKEYS", "NODETYPE", "PROPATTR",
"PROPVALUE", "BOX", "BOXTYPE", "PLEX",
"BGNEXTN", "ENDEXTN", "TAPENUM", "TAPECODE",
"STRCLASS", "RESERVED", "FORMAT", "MASK",
"ENDMASKS"
};
if (rtype < 0 || rtype >= CALMA_NUMRECORDTYPES)
{
(void) sprintf(numeric, "%d", rtype);
return (numeric);
}
return (calmaRecordNames[rtype]);
}
/*
* ----------------------------------------------------------------------------
*
* CalmaTechInit --
*
* Prepare for a technology file.
*
* Results:
* None.
*
* Side effects:
* Error checking.
*
* ----------------------------------------------------------------------------
*/
void
CalmaTechInit()
{
ASSERT(sizeof(FourByteInt)==4, "definition in calmaInt.h");
ASSERT(sizeof(TwoByteInt)==2, "definition in calmaInt.h");
}

2478
calma/CalmaWrite.c Normal file

File diff suppressed because it is too large Load Diff

30
calma/Depend Normal file
View File

@ -0,0 +1,30 @@
CalmaRead.o: CalmaRead.c ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/utils.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../utils/malloc.h ../utils/tech.h ../cif/cif.h \
../cif/CIFint.h ../cif/CIFread.h ../utils/signals.h ../windows/windows.h \
../dbwind/dbwind.h ../utils/styles.h ../textio/textio.h \
../calma/calmaInt.h ../commands/commands.h ../utils/undo.h
CalmaRdcl.o: CalmaRdcl.c ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/utils.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../utils/malloc.h ../utils/tech.h ../cif/cif.h \
../cif/CIFint.h ../cif/CIFread.h ../utils/signals.h ../windows/windows.h \
../dbwind/dbwind.h ../utils/styles.h ../textio/textio.h \
../calma/calmaInt.h ../calma/calma.h
CalmaRdio.o: CalmaRdio.c ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/utils.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../utils/malloc.h ../utils/tech.h ../cif/cif.h \
../cif/CIFint.h ../cif/CIFread.h ../utils/signals.h ../windows/windows.h \
../dbwind/dbwind.h ../utils/styles.h ../textio/textio.h \
../calma/calmaInt.h
CalmaRdpt.o: CalmaRdpt.c ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/utils.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../utils/malloc.h ../utils/tech.h ../cif/cif.h \
../cif/CIFint.h ../cif/CIFread.h ../utils/signals.h ../windows/windows.h \
../dbwind/dbwind.h ../utils/styles.h ../textio/textio.h \
../calma/calmaInt.h ../calma/calma.h
CalmaWrite.o: CalmaWrite.c ../utils/magic.h ../utils/malloc.h \
../utils/geometry.h ../tiles/tile.h ../utils/utils.h ../utils/hash.h \
../database/database.h ../database/databaseInt.h ../utils/tech.h \
../cif/cif.h ../cif/CIFint.h ../utils/signals.h ../windows/windows.h \
../dbwind/dbwind.h ../utils/styles.h ../textio/textio.h \
../calma/calmaInt.h ../utils/main.h ../utils/stack.h

10
calma/Makefile Normal file
View File

@ -0,0 +1,10 @@
#
# rcsid $Header: /usr/cvsroot/magic-8.0/calma/Makefile,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $
#
MODULE = calma
MAGICDIR = ..
SRCS = CalmaRead.c CalmaRdcl.c CalmaRdio.c CalmaRdpt.c CalmaWrite.c
include ${MAGICDIR}/defs.mak
include ${MAGICDIR}/rules.mak

45
calma/calma.h Normal file
View File

@ -0,0 +1,45 @@
/*
* calma.h --
*
* This file defines things that are exported by the
* calma module to the rest of the world.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*
* rcsid $Header: /usr/cvsroot/magic-8.0/calma/calma.h,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $
*/
#ifndef _CALMA_H
#define _CALMA_H
#include "utils/magic.h"
/* Externally visible variables */
extern bool CalmaSubcellPolygons;
extern bool CalmaDoLabels;
extern bool CalmaDoLower;
extern bool CalmaMergeTiles;
extern bool CalmaFlattenArrays;
extern bool CalmaNoDRCCheck;
extern bool CalmaFlattenUses;
extern bool CalmaReadOnly;
extern bool CalmaContactArrays;
extern bool CalmaPostOrder;
/* Externally-visible procedures: */
extern bool CalmaWrite();
extern void CalmaReadFile();
extern void CalmaTechInit();
extern bool CalmaGenerateArray();
#endif /* _CALMA_H */

235
calma/calmaInt.h Normal file
View File

@ -0,0 +1,235 @@
/*
* calma.h --
*
* This file defines constants used internally by the calma
* module, but not exported to the rest of the world.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*
* rcsid $Header: /usr/cvsroot/magic-8.0/calma/calmaInt.h,v 1.2 2010/06/24 12:37:15 tim Exp $
*/
#ifndef _CALMAINT_H
#define _CALMAINT_H
#include "utils/magic.h"
#include "database/database.h"
/* Record data types */
#define CALMA_NODATA 0 /* No data present */
#define CALMA_BITARRAY 1 /* Bit array */
#define CALMA_I2 2 /* 2 byte integer */
#define CALMA_I4 3 /* 4 byte integer */
#define CALMA_R4 4 /* 4 byte real */
#define CALMA_R8 5 /* 8 byte real */
#define CALMA_ASCII 6 /* ASCII string */
/* Record types */
#define CALMA_HEADER 0
#define CALMA_BGNLIB 1
#define CALMA_LIBNAME 2
#define CALMA_UNITS 3
#define CALMA_ENDLIB 4
#define CALMA_BGNSTR 5
#define CALMA_STRNAME 6
#define CALMA_ENDSTR 7
#define CALMA_BOUNDARY 8
#define CALMA_PATH 9
#define CALMA_SREF 10
#define CALMA_AREF 11
#define CALMA_TEXT 12
#define CALMA_LAYER 13
#define CALMA_DATATYPE 14
#define CALMA_WIDTH 15
#define CALMA_XY 16
#define CALMA_ENDEL 17
#define CALMA_SNAME 18
#define CALMA_COLROW 19
#define CALMA_TEXTNODE 20
#define CALMA_NODE 21
#define CALMA_TEXTTYPE 22
#define CALMA_PRESENTATION 23
#define CALMA_SPACING 24
#define CALMA_STRING 25
#define CALMA_STRANS 26
#define CALMA_MAG 27
#define CALMA_ANGLE 28
#define CALMA_UINTEGER 29
#define CALMA_USTRING 30
#define CALMA_REFLIBS 31
#define CALMA_FONTS 32
#define CALMA_PATHTYPE 33
#define CALMA_GENERATIONS 34
#define CALMA_ATTRTABLE 35
#define CALMA_STYPTABLE 36
#define CALMA_STRTYPE 37
#define CALMA_ELFLAGS 38
#define CALMA_ELKEY 39
#define CALMA_LINKTYPE 40
#define CALMA_LINKKEYS 41
#define CALMA_NODETYPE 42
#define CALMA_PROPATTR 43
#define CALMA_PROPVALUE 44
#define CALMA_BOX 45
#define CALMA_BOXTYPE 46
#define CALMA_PLEX 47
#define CALMA_BGNEXTN 48
#define CALMA_ENDEXTN 49
#define CALMA_TAPENUM 50
#define CALMA_TAPECODE 51
#define CALMA_STRCLASS 52
#define CALMA_RESERVED 53
#define CALMA_FORMAT 54
#define CALMA_MASK 55
#define CALMA_ENDMASKS 56
#define CALMA_LIBDIRSIZE 57
#define CALMA_SRFNAME 58
#define CALMA_LIBSECUR 59
#define CALMA_NUMRECORDTYPES 60 /* Number of above types */
/* Property types defined for magic */
#define CALMA_PROP_USENAME 98 /* To record non-default cell use ids */
#define CALMA_PROP_ARRAY_LIMITS 99 /* To record non-default array limits */
/* Flags for transforms */
#define CALMA_STRANS_UPSIDEDOWN 0x8000 /* Mirror about X axis before rot */
#define CALMA_STRANS_ROTATE 0x0002 /* Rotate by absolute angle */
/* Path types */
#define CALMAPATH_SQUAREFLUSH 0 /* Square end flush with endpoint */
#define CALMAPATH_ROUND 1 /* Round end */
#define CALMAPATH_SQUAREPLUS 2 /* Square end plus half-width extent */
/* Largest calma layer or data type numbers */
#define CALMA_LAYER_MAX 255
#define CalmaIsValidLayer(n) ((n) >= 0 && (n) <= CALMA_LAYER_MAX)
/* Used to index hash tables of (layer, datatype) pairs */
typedef struct
{
int clt_layer;
int clt_type;
} CalmaLayerType;
/* Biggest calma string */
#define CALMANAMELENGTH 32
/* Length of record header */
#define CALMAHEADERLENGTH 4
/* ------------------------- Input macros ----------------------------- */
/* Globals for Calma reading */
extern FILE *calmaInputFile;
extern char *calmaFilename;
extern int calmaReadScale1;
extern int calmaReadScale2;
extern bool calmaLApresent;
extern int calmaLAnbytes;
extern int calmaLArtype;
/*
* Macros for number representation conversion.
*/
#ifdef ibm032
#include <netinet/in.h> /* as macros in in.h and don't exist as routines */
#endif
#ifndef ntohl
# ifdef WORDS_BIGENDIAN
# define ntohl(x) (x)
# define ntohs(x) (x)
# define htonl(x) (x)
# define htons(x) (x)
# endif
#endif
typedef union { char uc[2]; unsigned short us; } TwoByteInt;
typedef union { char uc[4]; unsigned int ul; } FourByteInt;
/* Macro to read a 2-byte integer */
#define READI2(z) \
{ \
TwoByteInt u; \
u.uc[0] = getc(calmaInputFile); \
u.uc[1] = getc(calmaInputFile); \
(z) = (int) ntohs(u.us); \
}
/* Macro to read a 4-byte integer */
#define READI4(z) \
{ \
FourByteInt u; \
u.uc[0] = getc(calmaInputFile); \
u.uc[1] = getc(calmaInputFile); \
u.uc[2] = getc(calmaInputFile); \
u.uc[3] = getc(calmaInputFile); \
(z) = (int) ntohl(u.ul); \
}
/* Macros for reading and unreading record headers */
#define READRH(nb, rt) \
{ \
if (calmaLApresent) { \
(nb) = calmaLAnbytes; \
(rt) = calmaLArtype; \
calmaLApresent = FALSE; \
} else { \
READI2(nb); \
if (feof(calmaInputFile)) nb = -1; \
else { \
(rt) = getc(calmaInputFile); \
(void) getc(calmaInputFile); \
} \
} \
}
#define UNREADRH(nb, rt) \
{ \
ASSERT(!calmaLApresent, "UNREADRH"); \
calmaLApresent = TRUE; \
calmaLAnbytes = (nb); \
calmaLArtype = (rt); \
}
#define PEEKRH(nb, rt) \
{ \
READRH(nb, rt); \
UNREADRH(nb, rt); \
}
/* Other commonly used globals */
extern HashTable calmaLayerHash;
extern int calmaElementIgnore[];
extern CellDef *calmaFindCell();
/* (Added by Nishit, 8/18/2004--8/24/2004) */
extern CellDef *calmaLookCell();
extern void calmaWriteContact();
extern CellDef *calmaGetContactCell();
extern bool calmaIsContactCell;
extern char *calmaRecordName();
extern void calmaSkipSet();
/* ------------------- Imports from CIF reading ----------------------- */
extern CellDef *cifReadCellDef;
extern Plane *cifSubcellPlanes[];
extern Plane **cifCurReadPlanes;
extern HashTable CifCellTable;
extern Plane *cifEditCellPlanes[];
#endif /* _CALMAINT_H */

3338
cif/CIFgen.c Normal file

File diff suppressed because it is too large Load Diff

1146
cif/CIFhier.c Normal file

File diff suppressed because it is too large Load Diff

340
cif/CIFint.h Normal file
View File

@ -0,0 +1,340 @@
/*
* CIFint.h --
*
* Defines things shared internally by the cif module of Magic,
* but not generally needed outside the cif module.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*
* rcsid "$Header: /usr/cvsroot/magic-8.0/cif/CIFint.h,v 1.3 2008/12/04 17:10:29 tim Exp $"
*/
#ifndef _CIFINT_H
#define _CIFINT_H
#include "database/database.h"
/* The main data structure used in the cif module is a description
* of how to generate CIF layers from the Magic tiles. There may
* be several different styles for generating CIF from the same Magic
* information, e.g. for fabricating at different geometries. Each
* of these CIF styles involves three kinds of data. A "CIFStyle"
* record gives overall information such as the number of layers.
* One "CIFLayer" gives overall information for each layer, and
* then a list of one or more "CIFOp" records describes a sequence
* of geometrical operations to perform to generate the layer. This
* data structure is built up by reading the technology file.
*/
/* A CIFOp starts from a partially-completed CIF layer, does something
* to it, which may possibly involve some existing layers or temporary
* layers, and creates the next stage of the partially-completed
* CIF layer. Example operations are to AND with some existing paint,
* or to grow by a certain amount.
*/
typedef struct bloat_data
{
int bl_plane; /* Plane on which a bloat or squares
* operation is valid.
*/
int bl_distance[TT_MAXTYPES];
} BloatData;
typedef struct squares_data
{
int sq_border;
int sq_size;
int sq_sep;
int sq_gridx; /* Only used for "squares-grid" */
int sq_gridy; /* Only used for "squares-grid" */
} SquaresData;
typedef struct slots_data
{
int sl_sborder; /* short tile side */
int sl_ssize;
int sl_ssep;
int sl_lborder; /* long tile side */
int sl_lsize;
int sl_lsep;
int sl_offset;
} SlotsData;
typedef struct cifop
{
TileTypeBitMask co_paintMask;/* Zero or more paint layers to consider. */
TileTypeBitMask co_cifMask; /* Zero or more other CIF layers. */
int co_opcode; /* Which geometric operation to use. See
* below for the legal ones.
*/
int co_distance; /* Grow or shrink distance (if needed). */
ClientData co_client; /* Pointer to a BloatData, SquaresData, or
* SlotsData structure, or NULL.
*/
struct cifop *co_next; /* Next in list of operations to perform. */
} CIFOp;
/* The opcodes defined so far are:
*
* CIFOP_AND - AND current results with the layers indicated by
* the masks.
* CIFOP_ANDNOT - Wherever there is material indicated by the masks,
* erase those areas from the current results.
* CIFOP_OR - OR current results with the layers indicated by
* the masks.
* CIFOP_GROW - Grow the current results uniformly by co_distance.
* CIFOP_GROW_G - Grow the current results to snap to the indicated grid.
* CIFOP_SHRINK - Shrink the current results uniformly by co_distance.
* CIFOP_BLOAT - Find layers in paintMask, then bloat selectively
* according to bl_distance, and OR the results into
* the current plane
* CIFOP_SQUARES - Generates a pattern of squares (used for making
* contact vias. Each square is co_distance large,
* the squares are separated from each other by
* co_distance, and they are inside the edge of
* the material by at least co_distance.
* CIFOP_SLOTS - Generate a pattern of rectangles (used for making
* slots and slot vias). Similar to squares except
* for different dimensions in short and long tile
* dimensions. "0" for the long size indicates that
* the slot should extend the length of the tile
* minus the long-side border length.
* CIFOP_BLOATMAX - Like CIFOP_BLOAT, except whole side of tile gets
* bloated by same amount, which is max bloat from
* anywhere along side. Bloats can be negative.
* CIFOP_BLOATMIN - Same as CIFOP_BLOAT, except use min bloat from
* anywhere along side.
* CIFOP_BLOATALL - Added 3/21/05---bloat to encompass all connected
* material of the indicated type(s).
* CIFOP_BBOX - Added 4/2/05---create a single rectangle encompassing
* the cell bounding box. This involves no magic type
* layers but may itself be acted upon with grow/shrink
* rules.
* CIFOP_NET - Added 11/3/08---pull an entire electrical net into
* the CIF layer, selectively picking layers.
* CIFOP_MAXRECT - Reduce all areas to the largest internal fitting
* rectangle.
* CIFOP_COPYUP - Added 5/5/16---make and keep a copy the resulting layer,
* which will be painted into parent cells instead of the
* current cell. This replaces the "fault" method.
*/
#define CIFOP_AND 1
#define CIFOP_OR 2
#define CIFOP_GROW 3
#define CIFOP_GROW_G 4
#define CIFOP_SHRINK 5
#define CIFOP_BLOAT 6
#define CIFOP_SQUARES 7
#define CIFOP_SLOTS 8
#define CIFOP_BLOATMAX 9
#define CIFOP_BLOATMIN 10
#define CIFOP_BLOATALL 11
#define CIFOP_ANDNOT 12
#define CIFOP_SQUARES_G 13
#define CIFOP_BBOX 14
#define CIFOP_NET 15
#define CIFOP_MAXRECT 16
#define CIFOP_COPYUP 17
/* Added by Tim 10/21/2004 */
/* The following structure is used to pass information on how to draw
* contact subcell arrays for a specific magic contact tile type. For
* the GDS write routine, the GDS file (FILE *) is passed as the client
* data.
*/
typedef struct cifsquaresinfo
{
SquaresData *csi_squares; /* Information on how to generate squares */
TileType csi_type; /* Magic contact tile type */
ClientData csi_client; /* Used to pass output file info. */
} CIFSquaresInfo;
/* The following data structure contains all the information about
* a particular CIF layer.
*/
typedef struct
{
char *cl_name; /* Name of layer. */
CIFOp *cl_ops; /* List of operations. If NULL, layer is
* determined entirely by cl_initial.
*/
int cl_growDist; /* Largest distance material may move in
* this layer from its original Magic
* position, due to grows. Expressed
* in CIF units. If this layer uses temp
* layers, this distance must include grows
* from the temp layers.
*/
int cl_shrinkDist; /* Same as above, except for shrinks. */
int cl_flags; /* Bunches of flags: see below. */
int cl_calmanum; /* Number (0-63) of this layer for output as
* Calma (GDS-II stream format), or -1 if
* this layer should not be output.
*/
int cl_calmatype; /* Data type (0-63) for Calma output, or -1
* if this layer should not be output.
*/
int min_width; /* the minimum width rule in centi-microns
* for the layer. This is used by Grow Sliver
* to generate drc correct parent slivers
*/
#ifdef THREE_D
int cl_renderStyle; /* Style to render CIF layer with */
float cl_height; /* (rendered) height of CIF layer above substrate */
float cl_thick; /* (rendered) thickness of CIF layer */
#endif
} CIFLayer;
/* The CIFLayer flags are:
*
* CIF_TEMP: Means that this is a temporary layer used to build
* up CIF information. It isn't output in the CIF file.
* CIF_BBOX_TOP: Indicates that the bounding box rectangle should
* only be generated if the cell is a top-level cell.
*/
#define CIF_TEMP 1
#define CIF_BBOX_TOP 2
/* The following data structure describes a complete set of CIF
* layers. The number of CIF layers (MAXCIFLAYERS) must not be
* greater than the number of tile types (TT_MAXTYPES)!!
*/
#define MAXCIFLAYERS (TT_MAXTYPES - 1)
typedef struct cifkeep
{
struct cifkeep *cs_next;
char *cs_name;
} CIFKeep;
typedef struct cifstyle
{
char cs_status; /* Status: Loaded, not loaded, or pending. */
char *cs_name; /* Name used for this kind of CIF. */
int cs_nLayers; /* Number of layers. */
int cs_radius; /* Radius of interaction for hierarchical
* processing (expressed in Magic units).
*/
int cs_stepSize; /* If non-zero, user-specified step size
* for hierarchical processing (in Magic
* units).
*/
int cs_gridLimit; /* The limit of grid scaling. This limits
* the use of "scalegrid" to prevent Magic
* from generating geometry smaller than the
* process minimum grid.
*/
int cs_scaleFactor; /* Number of CIF units per Magic unit.
* CIF units are usually centimicrons, but
* see cs_expander below.
*/
int cs_reducer; /* Reduction factor (used only to reduce
* number of zeroes in CIF files and make
* file more readable). Default of 1.
* Unused for GDS input/output.
*/
int cs_expander; /* cs_scaleFactor / cs_expander = scale in
* centimicrons. Default of 1. Value 10
* means cs_scaleFactor is measured in
* nanometers (millimicrons)
*/
TileTypeBitMask cs_yankLayers;
/* For hierarchical processing, only these
* Magic types need to be yanked.
*/
TileTypeBitMask cs_hierLayers;
/* For hierarchical processing, only these
* CIF layers need to be generated.
*/
int cs_labelLayer[TT_MAXTYPES];
/* Each entry corresponds to one Magic layer,
* and gives index of CIF real layer to use
* for labels attached to this Magic layer.
* -1 means no known CIF layer for this Magic
* layer.
*/
CIFLayer *cs_layers[MAXCIFLAYERS];
/* Describes how to generate each layer.*/
int cs_flags; /* bitmask of boolean-valued output options */
} CIFStyle;
/* values for cs_flags */
#define CWF_PERMISSIVE_LABELS 0x01
#define CWF_GROW_SLIVERS 0x02
#define CWF_ANGSTROMS 0x04
#define CWF_GROW_EUCLIDEAN 0x08
#define CWF_SEE_VENDOR 0x10 /* Override vendor GDS flag in cells */
#define CWF_NO_ERRORS 0x20 /* Do not generate error msgs and fdbk */
/* procedures */
extern bool CIFNameToMask();
extern void CIFGenSubcells();
extern void CIFGenArrays();
extern void CIFGen();
extern void CIFClearPlanes();
extern Plane *CIFGenLayer();
extern void CIFInitCells();
extern int cifHierCopyFunc();
extern void CIFLoadStyle();
/* Shared variables and structures: */
extern Plane *CIFPlanes[]; /* Normal place to store CIF. */
extern CIFKeep *CIFStyleList; /* List of all CIF styles. */
extern CIFStyle *CIFCurStyle; /* Current style being used. */
extern CellUse *CIFComponentUse; /* Flatten stuff in here if needed. */
extern CellDef *CIFComponentDef; /* Corresponds to CIFComponentUse. */
extern CellUse *CIFDummyUse; /* Used to dummy up a CellUse for a
* def.
*/
/* Valid values of CIFWarningLevel (see cif.h) */
typedef enum {CIF_WARN_DEFAULT, CIF_WARN_NONE, CIF_WARN_ALIGN,
CIF_WARN_LIMIT, CIF_WARN_REDIRECT, CIF_WARN_END} CIFWarningTypes;
/* Statistics counters: */
extern int CIFTileOps;
extern int CIFHierTileOps;
extern int CIFRects;
extern int CIFHierRects;
/* Tables used for painting and erasing CIF. */
extern PaintResultType CIFPaintTable[], CIFEraseTable[];
/* Procedures and variables for reporting errors. */
extern int CIFErrorLayer;
extern CellDef *CIFErrorDef;
extern void CIFError();
/* The following determines the tile type used to hold the CIF
* information on its paint plane.
*/
#define CIF_SOLIDTYPE 1
extern TileTypeBitMask CIFSolidBits;
#endif /* _CIFINT_H */

413
cif/CIFmain.c Normal file
View File

@ -0,0 +1,413 @@
/* CIFmain.c -
*
* This file contains global information for the CIF module,
* such as performance statistics.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFmain.c,v 1.3 2009/01/15 15:44:34 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include "tcltk/tclmagic.h"
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "cif/CIFint.h"
#include "textio/textio.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "utils/styles.h"
/* The following points to a list of all the CIF output styles
* currently understood:
*/
CIFKeep *CIFStyleList;
/* The current style being used for CIF output: */
CIFStyle *CIFCurStyle = NULL;
/* The following are statistics gathered at various points in
* CIF processing. There are two versions of each statistic:
* a total number, and the number since stats were last printed.
*/
int CIFTileOps = 0; /* Total tiles touched in geometrical
* operations.
*/
int CIFHierTileOps = 0; /* Tiles touched in geometrical operations
* as part of hierarchical processing.
*/
int CIFRects = 0; /* Total CIF rectangles output. */
int CIFHierRects = 0; /* Rectangles stemming from interactions. */
static int cifTotalTileOps = 0;
static int cifTotalHierTileOps = 0;
static int cifTotalRects = 0;
static int cifTotalHierRects = 0;
/* This file provides several procedures for dealing with errors during
* the CIF generation process. Low-level CIF artwork-manipulation
* procedures call CIFError without knowing what cell CIF is being
* generated for, or what layer is being generated. Higher-level
* routines are responsible for recording that information in the
* variables below so that CIFError can output meaningful diagnostics
* using the feedback mechanism.
*/
global CellDef *CIFErrorDef; /* Definition in which to record errors. */
global int CIFErrorLayer; /* Index of CIF layer associated with errors.*/
/*
* ----------------------------------------------------------------------------
*
* CIFPrintStats --
*
* This procedure prints out CIF statistics including both
* total values and counts since the last printing.
*
* Results:
* None.
*
* Side effects:
* Several messages are printed.
*
* ----------------------------------------------------------------------------
*/
void
CIFPrintStats()
{
TxPrintf("CIF statistics (recent/total):\n");
cifTotalTileOps += CIFTileOps;
TxPrintf(" Geometrical tile operations: %d/%d\n",
CIFTileOps, cifTotalTileOps);
CIFTileOps = 0;
cifTotalHierTileOps += CIFHierTileOps;
TxPrintf(" Tile operations for hierarchy: %d/%d\n",
CIFHierTileOps, cifTotalHierTileOps);
CIFHierTileOps = 0;
cifTotalRects += CIFRects;
TxPrintf(" CIF rectangles output: %d/%d\n",
CIFRects, cifTotalRects);
CIFRects = 0;
cifTotalHierRects += CIFHierRects;
TxPrintf(" CIF rectangles due to hierarchical interactions: %d/%d\n",
CIFHierRects, cifTotalHierRects);
CIFHierRects = 0;
}
/*
* ----------------------------------------------------------------------------
*
* CIFGetOutputScale --
*
* This routine is given here so that the CIF output scale can be
* accessed from the "commands" directory source without declaring
* external references to CIF global variables.
*
* Results:
* Internal units-to-(nanometers * convert) conversion factor (float).
* Use convert = 1000 for centimicrons-to-microns conversion
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
float
CIFGetOutputScale(convert)
int convert;
{
if (CIFCurStyle == NULL) return 1.0;
return ((float)(10 * CIFCurStyle->cs_scaleFactor) /
(float)(CIFCurStyle->cs_expander * convert));
}
/*
* ----------------------------------------------------------------------------
*
* CIFPrintStyle --
*
* This procedure prints the current CIF output style or list
* of known styles.
*
* Results:
* None.
*
* Side effects:
* Output.
*
* ----------------------------------------------------------------------------
*/
void
CIFPrintStyle(dolist, doforall, docurrent)
bool dolist; /* Return as a list if true */
bool doforall; /* Print all known styles if true */
bool docurrent; /* Print current style if true */
{
CIFKeep *style;
if (docurrent)
{
if (CIFCurStyle == NULL)
TxError("Error: No style is set\n");
else
{
if (!dolist) TxPrintf("The current style is \"");
#ifdef MAGIC_WRAPPER
if (dolist)
Tcl_SetResult(magicinterp, CIFCurStyle->cs_name, NULL);
else
#endif
TxPrintf("%s", CIFCurStyle->cs_name);
if (!dolist) TxPrintf("\".\n");
}
}
if (doforall)
{
if (!dolist) TxPrintf("The CIF output styles are: ");
for (style = CIFStyleList; style != NULL; style = style->cs_next)
{
if (dolist)
{
#ifdef MAGIC_WRAPPER
Tcl_AppendElement(magicinterp, style->cs_name);
#else
if (style != CIFStyleList) TxPrintf(" ");
TxPrintf("%s", style->cs_name);
#endif
}
else
{
if (style != CIFStyleList) TxPrintf(", ");
TxPrintf("%s", style->cs_name);
}
}
if (!dolist) TxPrintf(".\n");
}
}
/*
* ----------------------------------------------------------------------------
*
* CIFSetStyle --
*
* This procedure changes the current CIF output style to the one
* named by the parameter.
*
* Results:
* None.
*
* Side effects:
* The current CIF style is changed. If the name doesn't match,
* or is ambiguous, then a list of all CIF styles is output.
*
* ----------------------------------------------------------------------------
*/
void
CIFSetStyle(name)
char *name; /* Name of the new style. If NULL, just
* print out the valid styles.
*/
{
CIFKeep *style, *match;
int length;
if (name == NULL) return;
match = NULL;
length = strlen(name);
for (style = CIFStyleList; style != NULL; style = style->cs_next)
{
if (strncmp(name, style->cs_name, length) == 0)
{
if (match != NULL)
{
TxError("CIF output style \"%s\" is ambiguous.\n", name);
CIFPrintStyle(FALSE, TRUE, TRUE);
return;
}
match = style;
}
}
if (match != NULL)
{
CIFLoadStyle(match->cs_name);
TxPrintf("CIF output style is now \"%s\"\n", name);
return;
}
TxError("\"%s\" is not one of the CIF output styles Magic knows.\n", name);
CIFPrintStyle(FALSE, TRUE, TRUE);
}
/*
* ----------------------------------------------------------------------------
*
* CIFNameToMask --
*
* Finds the CIF planes for a given name.
*
* Results:
* Returns TRUE on success, or FALSE if "name" failed to match any layers.
*
* Side effects:
* If there's no match, then an error message is output.
* The sets 'result' to be all types containing the CIF layer named
* "name". The current CIF style is used for the lookup. If "depend"
* is non-NULL, then it is filled with the mask of all layers on which
* the named layer depends.
* ----------------------------------------------------------------------------
*/
bool
CIFNameToMask(name, result, depend)
char *name;
TileTypeBitMask *result;
TileTypeBitMask *depend;
{
int i, j;
CIFOp *op;
CIFLayer *cl;
if (!CIFCurStyle)
{
TxError("No CIF output style set!\n");
return FALSE;
}
TTMaskZero(result);
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
if (strcmp(name, CIFCurStyle->cs_layers[i]->cl_name) == 0)
TTMaskSetType(result, i);
if (!TTMaskEqual(result, &DBZeroTypeBits))
{
/* This loop depends on the fact that templayers must */
/* be declared in order of dependency; that is, you */
/* can't use a layer before it is declared. Thus, the */
/* dependent layers will always be filled in from layer */
/* i back to zero. */
if (depend)
{
TTMaskZero(depend);
TTMaskSetMask(depend, result);
for (j = CIFCurStyle->cs_nLayers - 1; j >= 0; j--)
if (TTMaskHasType(depend, j))
{
cl = CIFCurStyle->cs_layers[j];
for (op = cl->cl_ops; op != NULL; op = op->co_next)
TTMaskSetMask(depend, &op->co_cifMask);
}
}
return TRUE;
}
TxError("CIF name \"%s\" doesn't exist in style \"%s\".\n", name,
CIFCurStyle->cs_name);
TxError("The valid CIF layer names are: ");
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
{
if (i == 0)
TxError("%s", CIFCurStyle->cs_layers[i]->cl_name);
else
TxError(", %s", CIFCurStyle->cs_layers[i]->cl_name);
}
TxError(".\n");
return FALSE;
}
/*
* ----------------------------------------------------------------------------
*
* CIFError --
*
* This procedure is called by low-level CIF generation routines
* when a problem is encountered in generating CIF. This procedure
* notes the problem using the feedback mechanism.
*
* Results:
* None.
*
* Side effects:
* Feedback information is added. The caller must have set CIFErrorDef
* to point to the cell definition that area refers to. If CIFErrorDef
* is NULL, then errors are ignored.
*
* ----------------------------------------------------------------------------
*/
void
CIFError(area, message)
Rect *area; /* Place in CIFErrorDef where there was a
* problem in generating CIFErrorLayer.
*/
char *message; /* Short note about what went wrong. */
{
char msg[200];
if (CIFCurStyle->cs_flags & CWF_NO_ERRORS) return;
if (CIFErrorDef == (NULL)) return;
(void) sprintf(msg, "CIF error in cell %s, layer %s: %s",
CIFErrorDef->cd_name, CIFCurStyle->cs_layers[CIFErrorLayer]->cl_name,
message);
DBWFeedbackAdd(area, msg, CIFErrorDef, CIFCurStyle->cs_scaleFactor,
STYLE_PALEHIGHLIGHTS);
}
/*
* ----------------------------------------------------------------------------
*
* CIFOutputScaleFactor --
*
* Returns current conversion factor between CIF units and
* Magic units.
*
* Results:
* The return value is the number of centimicrons per Magic
* unit in the current CIF output style. If there is no
* known CIF output style, 1 is returned.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
CIFOutputScaleFactor()
{
if (CIFCurStyle == NULL) return 1;
return CIFCurStyle->cs_scaleFactor;
}

1389
cif/CIFrdcl.c Normal file

File diff suppressed because it is too large Load Diff

335
cif/CIFrdpoly.c Normal file
View File

@ -0,0 +1,335 @@
/* CIFreadpoly.c -
*
* This file contains procedures that turn polygons into
* rectangles, as part of CIF file reading.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFrdpoly.c,v 1.3 2010/06/24 12:37:15 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "cif/CIFint.h"
#include "cif/CIFread.h"
#include "utils/malloc.h"
#define HEDGE 0 /* Horizontal edge */
#define REDGE 1 /* Rising edge */
#define FEDGE -1 /* Falling edge */
/*
* ----------------------------------------------------------------------------
*
* cifLowX --
*
* This is a comparison procedure called by qsort.
*
* Results:
* 1 if a.x > b.x,
* -1 if a.x < b.x,
* 0 otherwise.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
cifLowX(a, b)
CIFPath **a, **b;
{
Point *p, *q;
p = &(*a)->cifp_point;
q = &(*b)->cifp_point;
if (p->p_x < q->p_x)
return (-1);
if (p->p_x > q->p_x)
return (1);
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* cifLowY --
*
* This is another comparison procedure called by qsort.
*
* Results:
* 1 if a.y > b.y
* -1 if a.y < b.y
* 0 otherwise
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
cifLowY(a, b)
Point **a, **b;
{
if ((*a)->p_y < (*b)->p_y)
return (-1);
if ((*a)->p_y > (*b)->p_y)
return (1);
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* cifOrient --
*
* This procedure assigns a direction to each of the edges in a
* polygon.
*
* Results:
* TRUE is returned if all of the edges are horizontal or vertical,
* FALSE is returned otherwise. If FALSE is returned, not all of
* the directions will have been filled in.
*
* Side effects:
* The parameter dir is filled in with the directions, which are
* each one of HEDGE, REDGE, or FEDGE.
*
* ----------------------------------------------------------------------------
*/
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[]; /* Array of edges to be categorized. */
int dir[]; /* Array to hold directions. */
int nedges; /* Size of arrays. */
{
Point *p, *q;
int n;
for (n = 0; n < nedges; n++)
{
/* note - path list should close on itself */
p = &edges[n]->cifp_point;
q = &edges[n]->cifp_next->cifp_point;
if (p->p_y == q->p_y)
{
/* note - point may connect to itself here */
dir[n] = HEDGE;
continue;
}
if (p->p_x == q->p_x)
{
if (p->p_y < q->p_y)
{
dir[n] = REDGE;
continue;
}
if (p->p_y > q->p_y)
{
dir[n] = FEDGE;
continue;
}
/* Point connects to itself */
dir[n] = HEDGE;
continue;
}
/* It's not Manhattan, folks. */
return (FALSE);
}
return (TRUE);
}
/*
* ----------------------------------------------------------------------------
*
* cifCross --
*
* This procedure is used to see if an edge crosses a particular
* area.
*
* Results:
* TRUE is returned if edge is vertical and if it crosses the
* y-range defined by ybot and ytop. FALSE is returned otherwise.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
bool
cifCross(edge, dir, ybot, ytop)
CIFPath *edge; /* Pointer to first of 2 path points in edge */
int dir; /* Direction of edge */
int ybot, ytop; /* Range of interest */
{
int ebot, etop;
switch (dir)
{
case REDGE:
ebot = edge->cifp_point.p_y;
etop = edge->cifp_next->cifp_point.p_y;
return (ebot <= ybot && etop >= ytop);
case FEDGE:
ebot = edge->cifp_next->cifp_point.p_y;
etop = edge->cifp_point.p_y;
return (ebot <= ybot && etop >= ytop);
}
return (FALSE);
}
/*
* ----------------------------------------------------------------------------
*
* CIFPolyToRects --
*
* Converts a manhattan polygon (specified as a path) into a
* linked list of rectangles.
*
* Results:
* The return value is a linked list of rectangles, or NULL if
* something went wrong.
*
* Side effects:
* Memory is allocated to hold the list of rectangles. It is
* the caller's responsibility to free up the memory.
*
* ----------------------------------------------------------------------------
*/
LinkedRect *
CIFPolyToRects(path, plane, resultTbl, ui)
CIFPath *path; /* Path describing a polygon. */
Plane *plane; /* Plane to draw on */
PaintResultType *resultTbl;
PaintUndoInfo *ui;
{
int npts = 0, n, *dir, curr, wrapno;
int xbot, xtop, ybot, ytop;
Point **pts;
CIFPath *p, **edges, *tail = 0;
LinkedRect *rex = 0, *new;
/* Close path list. */
for (tail = path; tail->cifp_next; tail = tail->cifp_next);
if ((tail->cifp_x != path->cifp_x) || (tail->cifp_y != path->cifp_y))
{
p = (CIFPath *) mallocMagic ((unsigned) sizeof (CIFPath));
p->cifp_x = path->cifp_x;
p->cifp_y = path->cifp_y;
p->cifp_next = (CIFPath *) 0;
tail->cifp_next = p;
}
CIFMakeManhattanPath(path, plane, resultTbl, ui);
for (p = path; p->cifp_next; p = p->cifp_next, npts++);
pts = (Point **)mallocMagic(npts * sizeof(Point *));
dir = (int *)mallocMagic(npts * sizeof(int));
edges = (CIFPath **)mallocMagic(npts * sizeof(CIFPath *));
npts = 0;
for (p = path; p->cifp_next; p = p->cifp_next, npts++)
{
pts[npts] = &(p->cifp_point);
edges[npts] = p;
}
if (npts < 4)
{
if (npts > 0)
CIFReadError("polygon with fewer than 4 points.\n" );
goto done;
}
/* Sort points by low y, edges by low x */
qsort ((char *) pts, npts, (int) sizeof (Point *), cifLowY);
qsort ((char *) edges, npts, (int) sizeof (CIFPath *), cifLowX);
/* Find out which direction each edge points. */
if (!cifOrient (edges, npts, dir))
{
CIFReadError("non-manhattan polygon.\n" );
goto done;
}
/* Scan the polygon from bottom to top. At each step, process
* a minimum-sized y-range of the polygon (i.e. a range such that
* there are no vertices inside the range). Use wrap numbers
* based on the edge orientations to determine how much of the
* x-range for this y-range should contain material.
*/
for (curr = 1; curr < npts; curr++)
{
/* Find the next minimum-sized y-range. */
ybot = pts[curr-1]->p_y;
while (ybot == pts[curr]->p_y)
if (++curr >= npts) goto done;
ytop = pts[curr]->p_y;
/* Process all the edges that cross the y-range, from left
* to right.
*/
for (wrapno=0, n=0; n < npts; n++)
{
if (wrapno == 0) xbot = edges[n]->cifp_x;
if (!cifCross(edges[n], dir[n], ybot, ytop))
continue;
wrapno += dir[n] == REDGE ? 1 : -1;
if (wrapno == 0)
{
xtop = edges[n]->cifp_point.p_x;
if (xbot == xtop) continue;
new = (LinkedRect *) mallocMagic(sizeof(LinkedRect));
new->r_r.r_xbot = xbot;
new->r_r.r_ybot = ybot;
new->r_r.r_xtop = xtop;
new->r_r.r_ytop = ytop;
new->r_next = rex;
rex = new;
}
}
}
/* Normally, the loop exits directly to done, below. It
* only falls through here if the polygon has a degenerate
* spike at its top (i.e. if there's only one point with
* highest y-coordinate).
*/
done:
freeMagic((char *)edges);
freeMagic((char *)dir);
freeMagic((char *)pts);
return (rex);
}

765
cif/CIFrdpt.c Normal file
View File

@ -0,0 +1,765 @@
/* CIFreadpaint.c -
*
* This file contains more routines to parse CIF files. In
* particular, it contains the routines to handle paint,
* including rectangles, wires, flashes, and polygons.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFrdpt.c,v 1.2 2010/06/24 12:37:15 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <ctype.h>
#include <math.h> /* for wire path-to-poly path conversion */
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "utils/malloc.h"
#include "database/database.h"
#include "windows/windows.h"
#include "utils/main.h"
#include "cif/CIFint.h"
#include "cif/CIFread.h"
/*
* ----------------------------------------------------------------------------
*
* CIFParseBox --
*
* This procedure parses a CIF box command.
*
* Results:
* TRUE is returned if the parse completed successfully, and
* FALSE is returned otherwise.
*
* Side effects:
* A box is added to the CIF information for this cell. The
* box better not have corners that fall on half-unit boundaries.
*
* Correction:
* A box may be centered on a half lambda grid but have width
* and height such that the resulting box is entirely on the lambda
* grid. So: don't divide by 2 until the last step!
* ---Tim Edwards, 4/20/00
*
* ----------------------------------------------------------------------------
*/
bool
CIFParseBox()
{
Point center;
Point direction;
Rect rectangle, r2;
int savescale;
/* Take the 'B'. */
TAKE();
if (cifReadPlane == NULL)
{
CIFSkipToSemi();
return FALSE;
}
/* Treat length and width as a point so we can make use of the code in */
/* CIFParsePoint(); however, before moving on, check that both values */
/* are strictly positive. */
if (!CIFParsePoint(&rectangle.r_ur, 1))
{
CIFReadError("box, but no length and/or width; ignored.\n");
CIFSkipToSemi();
return FALSE;
}
if (rectangle.r_xtop <= 0)
{
CIFReadError("box length not strictly positive; ignored.\n");
CIFSkipToSemi();
return FALSE;
}
if (rectangle.r_ytop <= 0)
{
CIFReadError("box width not strictly positive; ignored.\n");
CIFSkipToSemi();
return FALSE;
}
savescale = cifReadScale1;
if (!CIFParsePoint(&center, 2))
{
CIFReadError("box, but no center; ignored.\n");
CIFSkipToSemi();
return FALSE;
}
/* If reading the center causes a CIF input scale to be redefined, */
/* then the length and width must also be changed. */
if (savescale != cifReadScale1)
{
rectangle.r_xtop *= (cifReadScale1 / savescale);
rectangle.r_ytop *= (cifReadScale1 / savescale);
}
rectangle.r_xbot = -rectangle.r_xtop;
rectangle.r_ybot = -rectangle.r_ytop;
/* Optional direction vector: have to build transform to do rotate. */
if (CIFParseSInteger(&direction.p_x))
{
if (!CIFParseSInteger(&direction.p_y))
{
CIFReadError("box, direction botched; box ignored.\n");
CIFSkipToSemi();
return FALSE;
}
GeoTransRect(CIFDirectionToTrans(&direction), &rectangle , &r2);
}
else r2 = rectangle;
/* Offset by center only now that rotation is complete, and divide by two. */
r2.r_xbot = (r2.r_xbot + center.p_x) / 2;
r2.r_ybot = (r2.r_ybot + center.p_y) / 2;
r2.r_xtop = (r2.r_xtop + center.p_x) / 2;
r2.r_ytop = (r2.r_ytop + center.p_y) / 2;
DBPaintPlane(cifReadPlane, &r2, CIFPaintTable, (PaintUndoInfo *) NULL);
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* CIFParseFlash --
*
* This routine parses and processes a roundflash command. The syntax is:
* roundflash ::= R diameter center
*
* We approximate a roundflash by a box.
*
* Results:
* TRUE is returned if the parse completed successfully, and
* FALSE is returned otherwise.
*
* Side effects:
* Paint is added to the current CIF plane.
*
* Corrections: Incorrectly implemented. Now CIFParsePoint returns the
* center coordinate doubled; in this way, the center can be on the
* half-lambda grid but the resulting block on-grid, if the diameter
* is an odd number.
*
* ----------------------------------------------------------------------------
*/
bool
CIFParseFlash()
{
int diameter;
int savescale;
Point center;
Rect rectangle;
/* Take the 'R'. */
TAKE();
if (cifReadPlane == NULL)
{
CIFSkipToSemi();
return FALSE;
}
if (!CIFParseInteger(&diameter))
{
CIFReadError("roundflash, but no diameter; ignored.\n");
CIFSkipToSemi();
return FALSE;
}
diameter *= cifReadScale1;
if (diameter % cifReadScale2 != 0)
CIFReadWarning("Roundflash diameter snapped to nearest integer boundary.\n");
diameter /= cifReadScale2;
savescale = cifReadScale1;
if (!CIFParsePoint(&center, 2))
{
CIFReadError("roundflash, but no center; ignored.\n");
CIFSkipToSemi();
return FALSE;
}
if (savescale != cifReadScale1)
diameter *= (cifReadScale1 / savescale);
rectangle.r_xbot = (center.p_x - diameter) / 2;
rectangle.r_ybot = (center.p_y - diameter) / 2;
rectangle.r_xtop = (center.p_x + diameter) / 2;
rectangle.r_ytop = (center.p_y + diameter) / 2;
DBPaintPlane(cifReadPlane, &rectangle, CIFPaintTable,
(PaintUndoInfo *) NULL);
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* CIFPaintWirePath --
*
* Draw a "wire path" described by the endpoints of a centerline through
* a series of segments, and a wire width. We pass the plane and paint
* table information so this routine can be used by the database for
* painting paths from the command-line.
*
* Results:
* None.
*
* Side effects:
* Paints layout into magic. The original wire path is destroyed
* (memory free'd).
*
* Notes:
* Path coordinates for wires are always assumed to be twice the
* actual value to avoid roundoff errors, since the centerline of
* a path can be halfway between two coordinates of the layout grid
* and still describe a polygon whose endpoints are all on the grid.
*
* Warning:
* It is still possible to get roundoff problems with different
* values of segment width at different angles caused by snapping
* to grid points. While this is "as it should be", it causes
* problems when process design rules demand geometry at 45 degrees
* only, and the algorithm produces points that are 1 unit off.
* A possible solution is to adjust "cwidth" to match the average
* value of "width" after snapping at entering and exiting angles.
*
* ----------------------------------------------------------------------------
*/
void
CIFPaintWirePath(pathheadp, width, endcap, plane, ptable, ui)
CIFPath *pathheadp;
int width;
bool endcap;
Plane *plane;
PaintResultType *ptable;
PaintUndoInfo *ui;
{
CIFPath *pathp, *previousp, *nextp, *polypath;
CIFPath *returnpath, *newpath, *savepath;
LinkedRect *rectp;
double theta, phi, alpha, delta, cwidth, adjwidth, testmitre, savetheta;
double xmaxoff, ymaxoff, xminoff, yminoff;
double xmin, ymin, xmax, ymax, xnext, ynext;
bool firstpoint;
/* Get rid of any repeat points, which just screw up the algorithm */
previousp = pathheadp;
pathp = pathheadp->cifp_next;
if (pathp != NULL)
{
while (pathp->cifp_next != NULL)
{
if (pathp->cifp_next->cifp_x == pathp->cifp_x &&
pathp->cifp_next->cifp_y == pathp->cifp_y)
{
previousp->cifp_next = pathp->cifp_next;
freeMagic(pathp);
}
else
previousp = pathp;
pathp = pathp->cifp_next;
}
}
previousp = pathheadp;
polypath = NULL;
/* Single-point paths are okay; just set the endpoints equal */
if (pathheadp->cifp_next == NULL)
pathp = pathheadp;
else
pathp = pathheadp->cifp_next;
firstpoint = TRUE;
theta = 0;
while (pathp != NULL)
{
/* Advance to the next point */
xmin = (double)previousp->cifp_x;
xmax = (double)pathp->cifp_x;
ymin = (double)previousp->cifp_y;
ymax = (double)pathp->cifp_y;
/* Angle of this segment */
savetheta = theta;
theta = atan2(ymax - ymin, xmax - xmin);
/* Look ahead to the next point */
if (firstpoint)
{
/* Back first point up by endcap amount (width, */
/* which is half the width of the route segment.) */
if (endcap)
{
xmin -= (double)width * cos(theta);
ymin -= (double)width * sin(theta);
}
xminoff = (double)width * cos(theta - 1.5708); /* 90 degrees */
yminoff = (double)width * sin(theta - 1.5708);
firstpoint = FALSE;
newpath = (CIFPath *)mallocMagic(sizeof(CIFPath));
newpath->cifp_next = polypath;
polypath = newpath;
returnpath = polypath; /* returnpath is always at the end */
newpath->cifp_x = round((xmin + xminoff) / 2);
newpath->cifp_y = round((ymin + yminoff) / 2);
newpath = (CIFPath *)mallocMagic(sizeof(CIFPath));
newpath->cifp_next = polypath;
polypath = newpath;
newpath->cifp_x = round((xmin - xminoff) / 2);
newpath->cifp_y = round((ymin - yminoff) / 2);
}
nextp = pathp->cifp_next;
if (nextp != NULL)
{
xnext = (double)nextp->cifp_x;
ynext = (double)nextp->cifp_y;
phi = atan2(ynext - ymax, xnext - xmax);
}
else
{
/* Endpoint: create 1/2 width endcap */
phi = theta;
if (endcap)
{
xmax += (double)width * cos(theta);
ymax += (double)width * sin(theta);
}
}
alpha = 0.5 * (phi - theta);
testmitre = fabs(cos(alpha));
/* This routine does not (yet) do mitre limits, so for */
/* now, we do a sanity check. In the case of an */
/* extremely acute angle, we generate a warning and */
/* truncate the route. The mitre limit is arbitrarily */
/* set at 4 times the route width. Such extreme bends */
/* are usually DRC violations, anyway. Tighter bends */
/* than this tend to cause difficulties for the */
/* CIFMakeManhattanPath() routine. */
if (testmitre < 0.25) {
if (testmitre < 1.0e-10) {
/* Wire reverses direction. Break wire here, */
/* draw, and start new polygon. */
TxError("Warning: direction reversal in path.\n");
phi = theta;
if (endcap)
{
xmax += (double)width * cos(theta);
ymax += (double)width * sin(theta);
}
alpha = 0.5 * (phi - theta);
firstpoint = TRUE;
}
else {
TxError("Error: mitre limit exceeded at wire junction.\n");
TxError("Route has been truncated.\n");
break;
}
}
delta = (0.5 * (phi + theta)) - 1.5708;
cwidth = (double)width / cos(alpha);
xmaxoff = cwidth * cos(delta);
ymaxoff = cwidth * sin(delta);
newpath = (CIFPath *)mallocMagic(sizeof(CIFPath));
newpath->cifp_next = polypath;
polypath = newpath;
newpath->cifp_x = round((xmax - xmaxoff) / 2);
newpath->cifp_y = round((ymax - ymaxoff) / 2);
newpath = (CIFPath *)mallocMagic(sizeof(CIFPath));
newpath->cifp_next = NULL;
savepath = returnpath;
returnpath->cifp_next = newpath;
returnpath = newpath;
newpath->cifp_x = round((xmax + xmaxoff) / 2);
newpath->cifp_y = round((ymax + ymaxoff) / 2);
if (firstpoint == TRUE || nextp == NULL)
{
/* Slow draw for non-Manhattan paths: */
/* Break the area up into triangles and rectangles */
rectp = CIFPolyToRects(polypath, plane, ptable, ui);
CIFFreePath(polypath);
for (; rectp != NULL ; rectp = rectp->r_next)
{
DBPaintPlane(plane, &rectp->r_r, ptable, ui);
freeMagic((char *) rectp);
}
polypath = NULL;
}
else
{
Rect r;
double a1, a2, r2, d1;
Point newpt;
/* Check if either of the two new segments travels opposite */
/* to theta. If so, then we need to find the intersection */
/* with the previous point, to avoid creating a cut-out */
/* wedge in the path. */
a1 = fabs(atan2(returnpath->cifp_y - savepath->cifp_y,
returnpath->cifp_x - savepath->cifp_x) - theta);
a2 = fabs(atan2(polypath->cifp_y - polypath->cifp_next->cifp_y,
polypath->cifp_x - polypath->cifp_next->cifp_x) - theta);
if (a1 > 0.1 && a1 < 6.1)
{
/* Find new intersection point */
d1 = cos(savetheta) * sin(phi) - sin(savetheta) * cos(phi);
if (fabs(d1) > 1.0e-4)
{
r2 = (sin(phi) * (returnpath->cifp_x - savepath->cifp_x)
- cos(phi) * (returnpath->cifp_y - savepath->cifp_y)) / d1;
savepath->cifp_x += round(r2 * cos(savetheta));
savepath->cifp_y += round(r2 * sin(savetheta));
}
}
else if (a2 > 0.1 && a2 < 6.1)
{
/* Find new intersection point */
d1 = cos(savetheta) * sin(phi) - sin(savetheta) * cos(phi);
if (fabs(d1) > 1.0e-4)
{
r2 = (sin(phi) * (polypath->cifp_x - polypath->cifp_next->cifp_x)
- cos(phi) * (polypath->cifp_y - polypath->cifp_next->cifp_y))
/ d1;
polypath->cifp_next->cifp_x += round(r2 * cos(savetheta));
polypath->cifp_next->cifp_y += round(r2 * sin(savetheta));
}
}
}
previousp = pathp;
pathp = pathp->cifp_next;
}
CIFFreePath(pathheadp);
}
/*
* ----------------------------------------------------------------------------
*
* PaintPolygon --
*
* Convert a list of points in the form of an array of type Point to a
* CIFPath linked structure, and paint them into the database.
*
* Results:
* None.
*
* Side effects:
* Paints tiles into the layout database. Calling routine is
* responsible for free'ing memory of the pointlist, if necessary.
*
* Notes:
* This is a database routine, not a CIF routine. However, it makes
* use of the CIFPath structure, so it is included here.
*
* ----------------------------------------------------------------------------
*/
LinkedRect *
PaintPolygon(pointlist, number, plane, ptable, ui, keep)
Point *pointlist; /* Array of Point structures */
int number; /* total number of points */
Plane *plane; /* Plane structure to paint into */
PaintResultType *ptable; /* Paint result table */
PaintUndoInfo *ui; /* Undo record */
bool keep; /* Return list of rects if true */
{
LinkedRect *rectp, *rectlist;
CIFPath *newpath, *cifpath = (CIFPath *)NULL;
int i;
for (i = 0; i < number; i++)
{
newpath = (CIFPath *) mallocMagic((unsigned) sizeof (CIFPath));
newpath->cifp_x = pointlist[i].p_x;
newpath->cifp_y = pointlist[i].p_y;
newpath->cifp_next = cifpath;
cifpath = newpath;
}
rectlist = CIFPolyToRects(cifpath, plane, ptable, ui);
CIFFreePath(cifpath);
for (rectp = rectlist; rectp != NULL ; rectp = rectp->r_next)
{
DBPaintPlane(plane, &rectp->r_r, ptable, ui);
if (!keep) freeMagic((char *) rectp);
}
return (keep) ? rectlist : (LinkedRect *)NULL;
}
/*
* ----------------------------------------------------------------------------
*
* PaintWireList --
*
* Convert a list of points in the form of an array of type Point to a
* CIFPath linked structure, and paint them into the database.
*
* Results:
* None.
*
* Side effects:
* Paints tiles into the layout database. Calling routine is
* responsible for free'ing memory of the pointlist, if necessary.
*
* Notes:
* This is a database routine, not a CIF routine. However, it makes
* use of the CIFPath structure, so it is included here.
*
* ----------------------------------------------------------------------------
*/
void
PaintWireList(pointlist, number, width, endcap, plane, ptable, ui)
Point *pointlist; /* Array of Point structures */
int number; /* total number of points */
int width; /* Route width of path */
bool endcap; /* Whether or not to add 1/2 width endcaps */
Plane *plane; /* Plane structure to paint into */
PaintResultType *ptable; /* Paint result table */
PaintUndoInfo *ui; /* Undo record */
{
CIFPath *newpath, *cifpath = (CIFPath *)NULL;
int i;
for (i = 0; i < number; i++)
{
newpath = (CIFPath *) mallocMagic((unsigned) sizeof (CIFPath));
newpath->cifp_x = pointlist[i].p_x;
newpath->cifp_y = pointlist[i].p_y;
newpath->cifp_next = cifpath;
cifpath = newpath;
}
CIFPaintWirePath(cifpath, width, endcap, plane, ptable, ui);
}
/*
* ----------------------------------------------------------------------------
*
* CIFParseWire --
*
* This procedure parses CIF wire commands, and adds paint
* to the current CIF cell. A wire command consists of
* an integer width, then a path.
*
* Results:
* TRUE is returned if the parse completed successfully, and
* FALSE is returned otherwise.
*
* Side effects:
* The current CIF planes are modified.
*
* ----------------------------------------------------------------------------
*/
bool
CIFParseWire()
{
int width;
CIFPath *pathheadp, *polypath;
int savescale;
/* Take the 'W'. */
TAKE();
if (cifReadPlane == NULL)
{
CIFSkipToSemi();
return FALSE;
}
if (!CIFParseInteger(&width))
{
CIFReadError("wire, but no width; ignored.\n");
CIFSkipToSemi();
return FALSE;
}
width *= cifReadScale1;
if (width % cifReadScale2 != 0)
CIFReadWarning("Wire width snapped to nearest integer boundary.\n");
width /= cifReadScale2;
savescale = cifReadScale1;
if (!CIFParsePath(&pathheadp, 2))
{
CIFReadError("wire, but improper path; ignored.\n");
CIFSkipToSemi();
return FALSE;
}
if (savescale != cifReadScale1)
width *= (cifReadScale1 / savescale);
CIFPaintWirePath(pathheadp, width, TRUE, cifReadPlane, CIFPaintTable,
(PaintUndoInfo *)NULL);
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* CIFParseLayer --
*
* This procedure parses layer changes. The syntax is:
* layer ::= L { blank } processchar layerchars
*
* Results:
* TRUE is returned if the parse completed successfully, and
* FALSE is returned otherwise.
*
* Side effects:
* Switches the CIF plane where paint is being saved.
*
* ----------------------------------------------------------------------------
*/
bool
CIFParseLayer()
{
#define MAXCHARS 4
char name[MAXCHARS+1];
char c;
int i;
TileType type;
/* Take the 'L'. */
TAKE();
CIFSkipBlanks();
/* Get the layer name. */
for (i=0; i<=MAXCHARS; i++)
{
c = PEEK();
if (isdigit(c) || isupper(c))
name[i] = TAKE();
else break;
}
name[i] = '\0';
/* Set current plane for use by the routines that parse geometric
* elements.
*/
type = CIFReadNameToType(name, FALSE);
if (type < 0)
{
cifReadPlane = NULL;
cifCurLabelType = TT_SPACE;
CIFReadError("layer %s isn't known in the current style.\n",
name);
} else {
cifCurLabelType = cifCurReadStyle->crs_labelLayer[type];
cifReadPlane = cifCurReadPlanes[type];
}
CIFSkipToSemi();
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* CIFParsePoly --
*
* This procedure reads and processes a polygon command. The syntax is:
* polygon ::= path
*
* Results:
* TRUE is returned if the parse completed successfully, and
* FALSE is returned otherwise.
*
* Side effects:
* Paint is added to the current CIF plane.
*
* ----------------------------------------------------------------------------
*/
bool
CIFParsePoly()
{
CIFPath *pathheadp;
LinkedRect *rectp;
/* Take the 'P'. */
TAKE();
if (cifReadPlane == NULL)
{
CIFSkipToSemi();
return FALSE;
}
if (!CIFParsePath(&pathheadp, 1))
{
CIFReadError("polygon, but improper path; ignored.\n");
CIFSkipToSemi();
return FALSE;
}
/* Convert the polygon to rectangles. */
rectp = CIFPolyToRects(pathheadp, cifReadPlane, CIFPaintTable,
(PaintUndoInfo *)NULL);
CIFFreePath(pathheadp);
if (rectp == NULL)
{
/* The non-Manhattan geometry polygon parsing algorithm */
/* typically leaves behind degenerate paths, so they */
/* should not be considered erroneous. */
CIFSkipToSemi();
return FALSE;
}
for (; rectp != NULL ; rectp = rectp->r_next)
{
DBPaintPlane(cifReadPlane, &rectp->r_r, CIFPaintTable,
(PaintUndoInfo *) NULL);
freeMagic((char *) rectp);
}
return TRUE;
}

1383
cif/CIFrdtech.c Normal file

File diff suppressed because it is too large Load Diff

1664
cif/CIFrdutils.c Normal file

File diff suppressed because it is too large Load Diff

201
cif/CIFread.h Normal file
View File

@ -0,0 +1,201 @@
/*
* CIFread.h --
*
* This file contains definitions used by the CIF reader, but not
* by the CIF writing code. The definitions are only used internally
* to this module.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*
*
* rcsid "$Header: /usr/cvsroot/magic-8.0/cif/CIFread.h,v 1.3 2010/08/25 17:33:55 tim Exp $
*/
#ifndef _CIFREAD_H
#define _CIFREAD_H
#include "cif/CIFint.h"
/* The structures below are built up by CIFreadtech.c to describe
* various styles for reading CIF.
*/
/* The following structure describes a sequence of geometric
* operations used to produce information for a single Magic
* layer. There may be several of these structures for the
* same Magic layer; in that case, the results end up being
* OR'ed together.
*/
typedef struct
{
TileType crl_magicType; /* Magic layer to paint results. */
CIFOp *crl_ops; /* List of operations to generate
* info for Magic layer.
*/
int crl_flags; /* Miscellaneous flags (see below). */
} CIFReadLayer;
/* The CIFReadLayer flags are:
*
* CIFR_SIMPLE: Means this layer is a simple one, coming from only
* a single OR operation, so it can be handled specially.
* CIFR_TEMPLAYER: Means this layer is a temporary CIF layer, and that
* the "crl_magicType" should be interpreted as a CIF layer.
* CIFR_TEXTLABELS: Means this layer is used for text-only layers, not to
* be moved or electrically connected to any other layer.
*/
#define CIFR_SIMPLE 1
#define CIFR_TEMPLAYER 2
#define CIFR_TEXTLABELS 4
/* The following structure defines a complete CIF read-in style.
* The constant MAXCIFRLAYERS must be less than TT_MAXTYPES, and
* is used both as the largest number of distinct CIF layer names
* in all read styles, and as the larges number of distinct "layer"
* commands in any one read style.
*/
#define MAXCIFRLAYERS (TT_MAXTYPES - 1)
/*
* To avoid the large memory demands of maintaining all CIF styles in
* memory, we keep only the style names and re-read the technology file
* as necessary
*/
typedef struct cifrkeep
{
struct cifrkeep *crs_next;
char *crs_name;
} CIFReadKeep;
typedef struct cifrstyle
{
char crs_status; /* Status: Loaded, not loaded, or pending. */
char *crs_name; /* Name for this style of CIF input. */
TileTypeBitMask crs_cifLayers;
/* Mask of CIF layers understood in
* this style.
*/
int crs_nLayers; /* Number of CIFReadLayers involved. */
int crs_scaleFactor; /* Number of CIF units per Magic unit. */
int crs_multiplier; /* crs_scaleFactor / crs_multiplier =
* units in traditional centimicrons.
* So if crs_multiplier = 10, CIF units
* are in nanometers (millimicrons).
*/
int crs_gridLimit; /* Input is considered off-grid if on
* a pitch less than crs_gridLimit CIF
* units, and input will be snapped to
* grid rather than scaling the grid
* to accomodate the data. 0 = no limit.
*/
TileType crs_labelLayer[MAXCIFRLAYERS];
/* Gives the Magic layer to use for labels
* on each possible CIF layer.
*/
CIFReadLayer *crs_layers[MAXCIFRLAYERS];
HashTable cifCalmaToCif; /* Table mapping from Calma layer numbers to
* CIF layers
*/
int crs_flags; /* Mask of boolean cif-reading options */
} CIFReadStyle;
/* option bitmasks used in crs_flags */
#define CRF_IGNORE_UNKNOWNLAYER_LABELS 1
#define CRF_NO_RECONNECT_LABELS 2
/* Methods to deal with fractional results of conversion from CIF to magic */
/* units (see routine CIFScaleCoord() for details). */
#define COORD_EXACT 0
#define COORD_HALF_U 1
#define COORD_HALF_L 2
#define COORD_ANY 3
/* For parsing CIF, we need to keep track of paths (wire locations
* or polygon boundaries. These are just linked lists of points.
*/
#define CIF_ZERO 0
#define CIF_LEFT 1
#define CIF_UP 2
#define CIF_RIGHT 3
#define CIF_DOWN 4
#define CIF_DIAG 5
/* Specific diagonal directions */
#define CIF_DIAG_UL 5
#define CIF_DIAG_UR 6
#define CIF_DIAG_DL 7
#define CIF_DIAG_DR 8
typedef struct cifpath
{
Point cifp_point; /* A point in the path. */
struct cifpath *cifp_next; /* The next point in the path, or NULL. */
} CIFPath;
#define cifp_x cifp_point.p_x
#define cifp_y cifp_point.p_y
/* Procedures */
extern bool CIFParseBox(), CIFParseWire(), CIFParsePoly();
extern bool CIFParseFlash(), CIFParseLayer(), CIFParseStart();
extern bool CIFParseFinish(), CIFParseDelete(), CIFParseUser();
extern bool CIFParseCall(), CIFParseTransform(), CIFParseInteger();
extern bool CIFParsePath(), CIFParsePoint(), CIFParseSInteger();
extern void CIFSkipToSemi(), CIFSkipSep(), CIFSkipBlanks();
extern void CIFFreePath(), CIFCleanPath();
extern void CIFReadCellInit(), CIFReadCellCleanup();
extern LinkedRect *CIFPolyToRects();
extern Transform *CIFDirectionToTrans();
extern int CIFReadNameToType();
/* Variable argument procedures require complete prototype */
extern void CIFReadError(char *format, ...);
extern void CIFReadWarning(char *format, ...);
/* Variables shared by the CIF-reading modules, see CIFreadutils.c
* for more details:
*/
extern int cifReadScale1, cifReadScale2;
extern int cifNReadLayers;
extern Plane *cifReadPlane;
extern Plane **cifCurReadPlanes;
extern TileType cifCurLabelType;
extern CIFReadStyle *cifCurReadStyle;
extern bool cifSubcellBeingRead;
extern CellDef *cifReadCellDef;
extern FILE *cifInputFile;
extern bool cifParseLaAvail;
extern int cifParseLaChar;
/* Macros to read characters, with one-character look-ahead. */
#define PEEK() ( cifParseLaAvail \
? cifParseLaChar \
: (cifParseLaAvail = TRUE, \
cifParseLaChar = getc(cifInputFile)))
#define TAKE() ( cifParseLaAvail \
? (cifParseLaAvail = FALSE, cifParseLaChar) \
: (cifParseLaChar = getc(cifInputFile)))
#endif /* _CIFREAD_H */

490
cif/CIFsee.c Normal file
View File

@ -0,0 +1,490 @@
/* CIFsee.c -
*
* This file provides procedures for displaying CIF layers on
* the screen using the highlight facilities.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFsee.c,v 1.5 2010/06/24 12:37:15 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "windows/windows.h"
#include "graphics/graphics.h"
#include "dbwind/dbwind.h"
#include "utils/styles.h"
#include "cif/CIFint.h"
#include "textio/textio.h"
#include "utils/undo.h"
/* The following variable holds the CellDef into which feedback
* is to be placed for displaying CIF.
*/
static CellDef *cifSeeDef;
/* Verbosity of warning messages */
global int CIFWarningLevel = CIF_WARN_DEFAULT;
typedef struct {
CellDef *paintDef;
int layer;
} PaintLayerData;
typedef struct {
char *text;
int layer;
int style;
} SeeLayerData;
/*
* ----------------------------------------------------------------------------
*
* cifPaintDBFunc --
*
* This routine paints CIF back into the database at the inverse
* scale at which it was generated. Otherwise, it is very much like
* cifPaintCurrentFunc() in CIFrdcl.c.
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* Paint is generated in the cell.
* ----------------------------------------------------------------------------
*/
int
cifPaintDBFunc(tile, pld)
Tile *tile; /* Tile of CIF information. */
PaintLayerData *pld;
{
Rect area;
int pNum;
TileType type = pld->layer; /* Magic type to be painted. */
CellDef *paintDef = pld->paintDef; /* Cell to draw into. */
int cifScale = CIFCurStyle->cs_scaleFactor;
PaintUndoInfo ui;
/* Compute the area of the CIF tile, then scale it into
* Magic coordinates.
*/
TiToRect(tile, &area);
area.r_xtop /= cifScale;
area.r_xbot /= cifScale;
area.r_ytop /= cifScale;
area.r_ybot /= cifScale;
/* Check for degenerate areas (from rescale limiting) before painting */
if ((area.r_xbot == area.r_xtop) || (area.r_ybot == area.r_ytop))
return 0;
ui.pu_def = paintDef;
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
if (DBPaintOnPlane(type, pNum))
{
ui.pu_pNum = pNum;
DBNMPaintPlane(paintDef->cd_planes[pNum], TiGetTypeExact(tile),
&area, DBStdPaintTbl(type, pNum), (PaintUndoInfo *) &ui);
}
return 0; /* To keep the search alive. */
}
/*
* ----------------------------------------------------------------------------
*
* CIFPaintLayer --
*
* Generates CIF over a given area of a given cell, then
* paints the CIF layer back into the cell (or optionally,
* into a separate cell) as a magic layer.
*
* Results:
* None.
*
* Side effects:
* Highlight information is drawn on the screen.
*
* ----------------------------------------------------------------------------
*/
void
CIFPaintLayer(rootDef, area, cifLayer, magicLayer, paintDef)
CellDef *rootDef; /* Cell for which to generate CIF. Must be
* the rootDef of a window.
*/
Rect *area; /* Area in which to generate CIF. */
char *cifLayer; /* CIF layer to highlight on the screen. */
int magicLayer; /* Magic layer to paint with the result */
CellDef *paintDef; /* CellDef to paint into (may be NULL) */
{
int oldCount, i;
char msg[100];
SearchContext scx;
PaintLayerData pld;
TileTypeBitMask mask, depend;
/* Make sure the desired layer exists. */
if (!CIFNameToMask(cifLayer, &mask, &depend)) return;
/* Paint directly into the root cellDef if passed a NULL paintDef*/
pld.paintDef = (paintDef == NULL) ? rootDef : paintDef;
pld.layer = magicLayer;
/* Flatten the area and generate CIF for it. */
CIFErrorDef = rootDef;
CIFInitCells();
UndoDisable();
CIFDummyUse->cu_def = rootDef;
GEO_EXPAND(area, CIFCurStyle->cs_radius, &scx.scx_area);
scx.scx_use = CIFDummyUse;
scx.scx_trans = GeoIdentityTransform;
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef);
oldCount = DBWFeedbackCount;
CIFGen(CIFComponentDef, area, CIFPlanes, &depend, TRUE, TRUE);
DBCellClearDef(CIFComponentDef);
/* Report any errors that occurred. */
if (DBWFeedbackCount != oldCount)
{
TxPrintf("%d problems occurred. See feedback entries.\n",
DBWFeedbackCount-oldCount);
}
/* Paint back the chosen layer. */
UndoEnable();
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
if (TTMaskHasType(&mask, i))
DBSrPaintArea((Tile *)NULL, CIFPlanes[i], &TiPlaneRect,
&CIFSolidBits, cifPaintDBFunc, (ClientData)&pld);
DBWAreaChanged(rootDef, area, DBW_ALLWINDOWS, &mask);
DBReComputeBbox(rootDef);
DRCCheckThis(rootDef, TT_CHECKPAINT, area);
}
/*
* ----------------------------------------------------------------------------
*
* cifSeeFunc --
*
* Called once for each tile that is to be displayed as feedback.
* This procedure enters the tile as feedback. Note: the caller
* must arrange for cifSeeDef to contain a pointer to the cell
* def where feedback is to be displayed.
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* A new feedback area is created over the tile. The parameter
* "text" is associated with the feedback.
* ----------------------------------------------------------------------------
*/
int
cifSeeFunc(tile, sld)
Tile *tile; /* Tile to be entered as feedback. */
SeeLayerData *sld; /* Layer and explanation for the feedback. */
{
Rect area;
TiToRect(tile, &area);
if (((area.r_xbot & 0x1) || (area.r_ybot & 0x1))
&& (CIFWarningLevel == CIF_WARN_ALIGN))
{
TxError("Warning: Corner (%.1f, %.1f) has half-lambda placement.\n",
(float)area.r_xbot / (float)CIFCurStyle->cs_scaleFactor,
(float)area.r_ybot / (float)CIFCurStyle->cs_scaleFactor);
}
DBWFeedbackAdd(&area, sld->text, cifSeeDef, CIFCurStyle->cs_scaleFactor,
sld->style |
(TiGetTypeExact(tile) & (TT_DIAGONAL | TT_DIRECTION | TT_SIDE)));
/* (preserve information about the geometry of a diagonal tile) */
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* CIFSeeLayer --
*
* Generates CIF over a given area of a given cell, then
* highlights a particular CIF layer on the screen.
*
* Results:
* None.
*
* Side effects:
* Highlight information is drawn on the screen.
*
* ----------------------------------------------------------------------------
*/
void
CIFSeeLayer(rootDef, area, layer)
CellDef *rootDef; /* Cell for which to generate CIF. Must be
* the rootDef of a window.
*/
Rect *area; /* Area in which to generate CIF. */
char *layer; /* CIF layer to highlight on the screen. */
{
int oldCount, i;
char msg[100];
SearchContext scx;
SeeLayerData sld;
TileTypeBitMask mask, depend;
/* Make sure the desired layer exists. */
if (!CIFNameToMask(layer, &mask, &depend)) return;
/* Flatten the area and generate CIF for it. */
CIFErrorDef = rootDef;
CIFInitCells();
UndoDisable();
CIFDummyUse->cu_def = rootDef;
GEO_EXPAND(area, CIFCurStyle->cs_radius, &scx.scx_area);
scx.scx_use = CIFDummyUse;
scx.scx_trans = GeoIdentityTransform;
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef);
oldCount = DBWFeedbackCount;
CIFGen(CIFComponentDef, area, CIFPlanes, &depend, TRUE, TRUE);
DBCellClearDef(CIFComponentDef);
/* Report any errors that occurred. */
if (DBWFeedbackCount != oldCount)
{
TxPrintf("%d problems occurred. See feedback entries.\n",
DBWFeedbackCount-oldCount);
}
/* Display the chosen layer. */
(void) sprintf(msg, "CIF layer \"%s\"", layer);
cifSeeDef = rootDef;
sld.text = msg;
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
{
if (TTMaskHasType(&mask, i))
{
sld.layer = i;
#ifdef THREE_D
sld.style = CIFCurStyle->cs_layers[i]->cl_renderStyle
+ TECHBEGINSTYLES;
#else
sld.style = STYLE_PALEHIGHLIGHTS;
#endif
DBSrPaintArea((Tile *)NULL, CIFPlanes[i], &TiPlaneRect,
&CIFSolidBits, cifSeeFunc, (ClientData)&sld);
}
}
UndoEnable();
}
/*
* ----------------------------------------------------------------------------
*
* CIFSeeHierLayer --
*
* This procedure is similar to CIFSeeLayer except that it only
* generates hierarchical interaction information.
*
* Results:
* None.
*
* Side effects:
* CIF information is highlighed on the screen. If arrays is
* TRUE, then CIF that stems from array interactions is displayed.
* if subcells is TRUE, then CIF stemming from subcell interactions
* is displayed. If both are TRUE, then both are displayed.
*
* ----------------------------------------------------------------------------
*/
void
CIFSeeHierLayer(rootDef, area, layer, arrays, subcells)
CellDef *rootDef; /* Def in which to compute CIF. Must be
* the root definition of a window.
*/
Rect *area; /* Area in which to generate CIF. */
char *layer; /* CIF layer to be highlighted. */
bool arrays; /* TRUE means show array interactions. */
bool subcells; /* TRUE means show subcell interactions. */
{
int i, oldCount;
SeeLayerData sld;
char msg[100];
TileTypeBitMask mask;
/* Check out the CIF layer name. */
if (!CIFNameToMask(layer, &mask, NULL)) return;
CIFErrorDef = rootDef;
oldCount = DBWFeedbackCount;
CIFClearPlanes(CIFPlanes);
if (subcells)
CIFGenSubcells(rootDef, area, CIFPlanes);
if (arrays)
CIFGenArrays(rootDef, area, CIFPlanes);
/* Report any errors that occurred. */
if (DBWFeedbackCount != oldCount)
{
TxPrintf("%d problems occurred. See feedback entries.\n",
DBWFeedbackCount - oldCount);
}
(void) sprintf(msg, "CIF layer \"%s\"", layer);
cifSeeDef = rootDef;
sld.text = msg;
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
{
if (TTMaskHasType(&mask, i))
{
sld.layer = i;
#ifdef THREE_D
sld.style = CIFCurStyle->cs_layers[i]->cl_renderStyle
+ TECHBEGINSTYLES;
#else
sld.style = STYLE_PALEHIGHLIGHTS;
#endif
DBSrPaintArea((Tile *)NULL, CIFPlanes[i], &TiPlaneRect,
&CIFSolidBits, cifSeeFunc, (ClientData)&sld);
}
}
}
/*
* ----------------------------------------------------------------------------
*
* CIFCoverageLayer --
*
* This procedure reports the total area coverage of a CIF layer
* within the bounding box of the root CellDef.
*
* Results:
* None.
*
* Side effects:
* Prints results.
*
* ----------------------------------------------------------------------------
*/
typedef struct {
long long coverage;
Rect bounds;
} coverstats;
void
CIFCoverageLayer(rootDef, area, layer)
CellDef *rootDef; /* Def in which to compute CIF coverage */
Rect *area; /* Area in which to compute coverage */
char *layer; /* CIF layer for coverage computation. */
{
coverstats cstats;
int i, scale;
long long atotal, btotal;
SearchContext scx;
TileTypeBitMask mask, depend;
float fcover;
int cifCoverageFunc();
bool doBox = (area != &rootDef->cd_bbox) ? TRUE : FALSE;
/* Check out the CIF layer name. */
if (!CIFNameToMask(layer, &mask, &depend)) return;
CIFErrorDef = rootDef;
CIFInitCells();
UndoDisable();
CIFDummyUse->cu_def = rootDef;
GEO_EXPAND(area, CIFCurStyle->cs_radius, &scx.scx_area);
scx.scx_use = CIFDummyUse;
scx.scx_trans = GeoIdentityTransform;
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef);
CIFGen(CIFComponentDef, area, CIFPlanes, &depend, TRUE, TRUE);
DBCellClearDef(CIFComponentDef);
cstats.coverage = 0;
cstats.bounds.r_xbot = cstats.bounds.r_xtop = 0;
cstats.bounds.r_ybot = cstats.bounds.r_ytop = 0;
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
if (TTMaskHasType(&mask, i))
DBSrPaintArea((Tile *)NULL, CIFPlanes[i], &TiPlaneRect,
&CIFSolidBits, cifCoverageFunc,
(ClientData) &cstats);
/* Print results */
scale = CIFCurStyle->cs_scaleFactor;
btotal = (long long)(area->r_xtop - area->r_xbot);
btotal *= (long long)(area->r_ytop - area->r_ybot);
btotal *= (long long)(scale * scale);
fcover = 0.0;
if (btotal > 0.0) fcover = (float)cstats.coverage / (float)btotal;
atotal = (long long)(cstats.bounds.r_xtop - cstats.bounds.r_xbot);
atotal *= (long long)(cstats.bounds.r_ytop - cstats.bounds.r_ybot);
TxPrintf("%s Area = %lld CIF units^2\n", doBox ? "Cursor Box" :
"Cell", btotal);
TxPrintf("Layer Bounding Area = %lld CIF units^2\n", atotal);
TxPrintf("Layer Total Area = %lld CIF units^2\n", cstats.coverage);
TxPrintf("Coverage in %s = %1.1f%%\n", doBox ? "box" :
"cell", 100.0 * fcover);
}
int
cifCoverageFunc(tile, arg)
Tile *tile;
ClientData *arg;
{
coverstats *cstats = (coverstats *)arg;
Rect r;
TiToRect(tile, &r);
cstats->coverage += (long long)((r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot));
GeoInclude(&r, &cstats->bounds);
return(0);
}

2308
cif/CIFtech.c Normal file

File diff suppressed because it is too large Load Diff

711
cif/CIFwrite.c Normal file
View File

@ -0,0 +1,711 @@
/*
* CIFwrite.c --
*
* Output of CIF.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFwrite.c,v 1.2 2010/06/24 12:37:15 tim Exp $";
#endif /* not lint */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/utils.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "utils/tech.h"
#include "utils/stack.h"
#include "utils/undo.h"
#include "cif/cif.h"
#include "cif/CIFint.h"
#include "utils/signals.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "utils/styles.h"
#include "textio/textio.h"
/* Forward declarations */
extern int cifWriteInitFunc();
extern int cifWriteMarkFunc();
extern int cifWritePaintFunc();
extern int cifWriteUseFunc();
extern void cifOutPreamble();
extern void cifOut();
extern void cifOutFunc();
extern int GrClipTriangle();
/* Current cell number in CIF numbering scheme */
static int cifCellNum;
/* Stack of definitions left to process for generating CIF */
Stack *cifStack;
/* Scale factor for outputting paint: */
int cifPaintScale;
/* Current layer name. If non-NULL, then cifWritePaintFunc outputs
* this string to the file before outputting a rectangle, then nulls.
* This way, the layer name only gets output when there's actually
* stuff on that layer.
*/
char *cifPaintLayerName;
/* TRUE if area labels should be output */
bool CIFDoAreaLabels = FALSE;
/* TRUE if cell ids should be output */
bool CIFDoCellIdLabels = TRUE;
/* prefix string for pathnames */
char *CIFPathPrefix = NULL;
/* These are normally FALSE---enable at your own risk! */
bool CIFHierWriteDisable = FALSE;
bool CIFArrayWriteDisable = FALSE;
/*
* ----------------------------------------------------------------------------
*
* CIFWrite --
*
* Write out the entire tree rooted at the supplied CellDef in CIF format,
* to the specified file.
*
* Results:
* TRUE if the cell could be written successfully, FALSE otherwise.
*
* Side effects:
* Writes a file to disk.
* In the event of an error while writing out the cell,
* the external integer errno is set to the UNIX error
* encountered.
*
* Algorithm:
* We make a depth-first traversal of the entire design tree,
* marking each cell with a CIF symbol number and then outputting
* it to the CIF file. If a given cell is not read in when we
* visit it, we read it in.
*
* No hierarchical design rule checking or bounding box computation
* occur during this traversal -- both are explicitly avoided.
*
* ----------------------------------------------------------------------------
*/
bool
CIFWrite(rootDef, f)
CellDef *rootDef; /* Pointer to CellDef to be written */
FILE *f; /* Open output file */
{
bool good;
int oldCount = DBWFeedbackCount;
CellUse dummy;
/*
* Make sure that the entire hierarchy rooted at rootDef is
* read into memory and that timestamp mismatches are resolved
* (this is needed so that we know that bounding boxes are OK).
*/
dummy.cu_def = rootDef;
DBCellReadArea(&dummy, &rootDef->cd_bbox);
DBFixMismatch();
if (CIFCurStyle->cs_reducer == 0)
{
TxError("The current CIF output style can only be used for writing\n");
TxError("Calma output. Try picking another output style.\n");
return (TRUE);
}
/*
* Go through all cells currently having CellDefs in the
* def symbol table and mark them with negative symbol numbers.
*/
(void) DBCellSrDefs(0, cifWriteInitFunc, (ClientData) NULL);
cifCellNum = (-2);
rootDef->cd_client = (ClientData) -1;
/*
* Start by pushing the root def on the stack of cell defs
* to be processed.
*/
cifStack = StackNew(100);
StackPush((ClientData) rootDef, cifStack);
cifOutPreamble(f, rootDef);
cifOut(f);
StackFree(cifStack);
if ((int) rootDef->cd_client < 0)
rootDef->cd_client = (ClientData) (- (int) rootDef->cd_client);
/* See if any problems occurred. */
if (DBWFeedbackCount != oldCount)
{
TxPrintf("%d problems occurred. See feedback entries.\n",
DBWFeedbackCount - oldCount);
}
/*
* Now we are almost done.
* Just output a call on the root cell
*/
fprintf(f, "C %d;\nEnd\n", (int) rootDef->cd_client);
good = !ferror(f);
return (good);
}
/*
* ----------------------------------------------------------------------------
*
* cifWriteInitFunc --
*
* Filter function called on behalf of CIFWrite() above.
* Responsible for setting the cif number of each cell to zero.
*
* Results:
* Returns 0 to indicate that the search should continue.
*
* Side effects:
* Modify the cif numbers of the cells they are passed.
*
* ----------------------------------------------------------------------------
*/
int
cifWriteInitFunc(def)
CellDef *def;
{
def->cd_client = (ClientData) 0;
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* cifWriteMarkFunc --
*
* Called to add each cell def in the subcell plane of a parent
* to the stack of cells to be processed.
*
* Results:
* Returns 0 to indicate that DBCellEnum() should continue.
*
* Side effects:
* Pushes the cell def on the stack.
* ----------------------------------------------------------------------------
*/
int
cifWriteMarkFunc(use)
CellUse *use;
{
if (use->cu_def->cd_client != (ClientData) 0) return 0;
use->cu_def->cd_client = (ClientData) cifCellNum;
cifCellNum -= 1;
StackPush((ClientData) use->cu_def, cifStack);
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* cifOutPreamble --
*
* Write preamble in front of a CIF file for version control.
*
* Results:
* None.
*
* Side effects:
* Preamble in CIF comment style - () are send to output file.
* ----------------------------------------------------------------------------
*/
void
cifOutPreamble(outf, cell)
FILE *outf;
CellDef *cell;
{
extern char *MagicVersion;
extern char *MagicCompileTime;
char *now, *t;
struct tm *clock;
time_t t_stamp = time((time_t *) NULL);
clock = localtime(&t_stamp);
now = ctime(&t_stamp);
/* remove the '\n' at the end of the string... */
now[strlen(now)-1] = '\0';
fprintf(outf,"( @@user : %s );\n", (t = getenv("USER")) ? t : "?");
fprintf(outf,"( @@machine : %s );\n", (t = getenv("HOSTNAME")) ? t : "?");
fprintf(outf,"( @@source : %s );\n",(cell->cd_file) ? cell->cd_file : "?");
fprintf(outf,"( @@tool : Magic %s.%s );\n", MagicVersion, MagicRevision);
fprintf(outf,"( @@compiled : %s );\n", MagicCompileTime);
fprintf(outf,"( @@technology : %s );\n", DBTechName);
if (DBTechVersion)
fprintf(outf,"( @@version : %s );\n", DBTechVersion);
else
fprintf(outf,"( @@version : unknown );\n");
if (DBTechDescription)
fprintf(outf,"( @@techdesc : %s );\n", DBTechDescription);
fprintf(outf,"( @@style : %s );\n", CIFCurStyle->cs_name);
fprintf(outf,"( @@date : %s );\n", now);
}
/*
* ----------------------------------------------------------------------------
*
* cifOut --
*
* Main loop of CIF generation. Pull a cell def from the stack
* and process it.
*
* Results:
* None.
*
* Side effects:
* Causes CIF to be output.
* Returns when the stack is empty.
* ----------------------------------------------------------------------------
*/
void
cifOut(outf)
FILE *outf;
{
CellDef *def;
while (!StackEmpty(cifStack))
{
def = (CellDef *) StackPop(cifStack);
if ((int) def->cd_client >= 0) continue; /* Already output */
if (SigInterruptPending) continue;
def->cd_client = (ClientData) (- (int) def->cd_client);
/* Read the cell in if it is not already available. */
if ((def->cd_flags & CDAVAILABLE) == 0)
{
if (!DBCellRead(def, (char *) NULL, TRUE, NULL)) continue;
}
/* Add any subcells to the stack. This must be done before
* outputting CIF to make sure that the subcells all have
* CIF numbers.
*/
(void) DBCellEnum(def, cifWriteMarkFunc, (ClientData) 0);
/* Output CIF for this cell */
cifOutFunc(def, outf);
}
}
/*
* ----------------------------------------------------------------------------
*
* cifOutFunc --
*
* Write out the definition for a single cell as CIF.
*
* Results:
* None.
*
* Side effects:
* Appends to the open CIF output file.
*
* ----------------------------------------------------------------------------
*/
void
cifOutFunc(def, f)
CellDef *def; /* Pointer to cell def to be written */
FILE *f; /* Open output file */
{
Rect bigArea;
Label *lab;
int type;
CIFLayer *layer;
fprintf(f, "DS %d %d %d;\n", (int) def->cd_client,
CIFCurStyle->cs_reducer, 2 * CIFCurStyle->cs_expander);
if (def->cd_name != (char *) NULL)
if (def->cd_name[0] != '\0')
{
if (strcmp(def->cd_name, "(UNNAMED)") == 0)
fprintf(f, "9 UNNAMED;\n");
else {
if (CIFPathPrefix && CIFPathPrefix[0])
fprintf(f, "9 %s/%s;\n", CIFPathPrefix, def->cd_name);
else
fprintf(f, "9 %s;\n", def->cd_name);
}
}
/*
* Output all the tiles associated with this cell. Skip temporary
* layers.
*/
GEO_EXPAND(&def->cd_bbox, CIFCurStyle->cs_radius, &bigArea);
CIFErrorDef = def;
CIFGen(def, &bigArea, CIFPlanes, &DBAllTypeBits, TRUE, TRUE);
if (!CIFHierWriteDisable)
CIFGenSubcells(def, &bigArea, CIFPlanes);
if (!CIFArrayWriteDisable)
CIFGenArrays(def, &bigArea, CIFPlanes);
for (type = 0; type < CIFCurStyle->cs_nLayers; type++)
{
layer = CIFCurStyle->cs_layers[type];
if (layer->cl_flags & CIF_TEMP) continue;
cifPaintLayerName = layer->cl_name;
cifPaintScale = 1;
(void) DBSrPaintArea((Tile *) NULL, CIFPlanes[type],
&TiPlaneRect, &CIFSolidBits, cifWritePaintFunc,
(ClientData) f);
}
/* Output labels */
for (lab = def->cd_labels; lab; lab = lab->lab_next)
{
int type = CIFCurStyle->cs_labelLayer[lab->lab_type];
Point center, size;
center.p_x = lab->lab_rect.r_xbot + lab->lab_rect.r_xtop;
center.p_y = lab->lab_rect.r_ybot + lab->lab_rect.r_ytop;
center.p_x *= CIFCurStyle->cs_scaleFactor;
center.p_x /= CIFCurStyle->cs_reducer;
center.p_y *= CIFCurStyle->cs_scaleFactor;
center.p_y /= CIFCurStyle->cs_reducer;
if (CIFDoAreaLabels)
{
size.p_x = lab->lab_rect.r_xtop - lab->lab_rect.r_xbot;
size.p_y = lab->lab_rect.r_ytop - lab->lab_rect.r_ybot;
size.p_x *= 2 * CIFCurStyle->cs_scaleFactor;
size.p_x /= CIFCurStyle->cs_reducer;
size.p_y *= 2 * CIFCurStyle->cs_scaleFactor;
size.p_y /= CIFCurStyle->cs_reducer;
if (type >= 0)
{
fprintf(f, "95 %s %d %d %d %d %s;\n",
lab->lab_text, size.p_x, size.p_y, center.p_x, center.p_y,
CIFCurStyle->cs_layers[type]->cl_name);
}
else
{
fprintf(f, "95 %s %d %d %d %d;\n",
lab->lab_text, size.p_x, size.p_y, center.p_x, center.p_y);
}
}
else
{
if (type >= 0)
{
fprintf(f, "94 %s %d %d %s;\n",
lab->lab_text, center.p_x, center.p_y,
CIFCurStyle->cs_layers[type]->cl_name);
}
else
{
fprintf(f, "94 %s %d %d;\n",
lab->lab_text, center.p_x, center.p_y);
}
}
}
/*
* Output the calls that the child makes to its children. For
* arrays it is necessary to output one call for each instance.
*/
(void) DBCellEnum(def, cifWriteUseFunc, (ClientData) f);
fprintf(f, "DF;\n");
}
/*
* ----------------------------------------------------------------------------
*
* cifWriteUseFunc --
*
* Filter function, called by DBCellEnum on behalf of cifOutFunc above,
* to write out each CellUse called by the CellDef being output.
*
* Results:
* Always return 0
*
* Side effects:
* Appends to the open CIF output file.
*
* ----------------------------------------------------------------------------
*/
int
cifWriteUseFunc(use, f)
CellUse *use;
FILE *f;
{
int x, y, topx, topy;
int realx, realy;
Transform *t;
int cifnum;
cifnum = (int) use->cu_def->cd_client;
if (cifnum < 0) cifnum = (-cifnum);
topx = use->cu_xhi - use->cu_xlo;
if (topx < 0) topx = -topx;
topy = use->cu_yhi - use->cu_ylo;
if (topy < 0) topy = -topy;
realx = use->cu_xlo;
for (x = 0; x <= topx; x++)
{
realy = use->cu_ylo;
for (y = 0; y <= topy; y++)
{
/*
* We eventually want to tag each use with its unique
* use identifier, which should include array subscripting
* information.
*/
/*
* Insert a 91 user command to label the next cell
*/
if (CIFDoCellIdLabels && use->cu_id && use->cu_id[0]) {
fprintf (f, "91 %s", use->cu_id);
if (topx > 0 || topy > 0) {
if (topx > 0 && topy > 0)
fprintf (f, "(%d,%d)", realy, realx);
else {
if (topx > 0)
fprintf (f, "(%d)", realx);
else
fprintf (f, "(%d)", realy);
}
}
fprintf (f, ";\n");
}
fprintf(f, "C %d", cifnum);
/*
* The following translates from the abcdef transforms
* that we use internally to the rotate and mirror
* specs used in CIF. It only works because
* orientations are orthogonal in magic. Check all
* 8 possible positions if you don't believe this.
*/
t = &use->cu_transform;
if ((t->t_a != t->t_e) || ((t->t_a == 0) && (t->t_b == t->t_d)))
fprintf(f, " MX R %d %d", -(t->t_a), -(t->t_d));
else
fprintf(f, " R %d %d", t->t_a, t->t_d);
fprintf(f, " T %d %d;\n",
((t->t_c + t->t_a*(use->cu_xsep)*x + t->t_b*(use->cu_ysep)*y)
* 2 * CIFCurStyle->cs_scaleFactor) / CIFCurStyle->cs_reducer,
((t->t_f + t->t_d*(use->cu_xsep)*x + t->t_e*(use->cu_ysep)*y)
* 2 * CIFCurStyle->cs_scaleFactor) / CIFCurStyle->cs_reducer);
if (use->cu_yhi > use->cu_ylo)
realy++;
else
realy--;
}
if (use->cu_xhi > use->cu_xlo)
realx++;
else
realx--;
}
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* cifWritePaintFunc --
*
* Filter function used to write out a single paint tile.
*
* Results:
* Always return 0
*
* Side effects:
* Writes to the disk file.
*
* ----------------------------------------------------------------------------
*/
int
cifWritePaintFunc(tile, f)
Tile *tile; /* Tile to be written out. */
FILE *f; /* File in which to write. */
{
Rect r;
/* Output the layer name if it hasn't been done already. */
if (cifPaintLayerName != NULL)
{
fprintf(f, "L %s;\n", cifPaintLayerName);
cifPaintLayerName = NULL;
}
TiToRect(tile, &r);
if (IsSplit(tile))
{
Point points[5];
int i, np;
GrClipTriangle(&r, NULL, FALSE, TiGetTypeExact(tile), points, &np);
/* Write triangle as a CIF polygon */
fprintf(f, " P");
for (i = 0; i < np; i++)
{
fprintf(f, " %d %d",
(2*cifPaintScale*(points[i].p_x))/CIFCurStyle->cs_reducer,
(2*cifPaintScale*(points[i].p_y))/CIFCurStyle->cs_reducer);
}
fprintf(f, ";\n");
}
else
/* The only tricky thing here is that we MUST scale the rectangle
* up by a factor of two to avoid round-off errors in computing
* its center point (what a bogosity in CIF!!). This is compensated
* by shrinking by a factor of two in the "DS" statement.
*/
fprintf(f, " B %d %d %d %d;\n",
(2*cifPaintScale*(r.r_xtop - r.r_xbot))/CIFCurStyle->cs_reducer,
(2*cifPaintScale*(r.r_ytop - r.r_ybot))/CIFCurStyle->cs_reducer,
(cifPaintScale*(r.r_xtop + r.r_xbot))/CIFCurStyle->cs_reducer,
(cifPaintScale*(r.r_ytop + r.r_ybot))/CIFCurStyle->cs_reducer);
CIFRects += 1;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* CIFWriteFlat --
*
* Write out the entire tree rooted at the supplied CellDef in CIF format,
* to the specified file, but write non-hierarchical CIF.
*
* Results:
* TRUE if the cell could be written successfully, FALSE otherwise.
*
* Side effects:
* Writes a file to disk.
* In the event of an error while writing out the cell,
* the external integer errno is set to the UNIX error
* encountered.
*
* Algorithm:
* We operate on the cell in chunks chosen to keep the memory utilization
* reasonable. Foreach chunk, we use DBTreeSrTiles and cifHierCopyFunc to
* flatten the
* chunk into a yank buffer ("eliminating" the subcell problem), then use
* cifOut to generate the CIF.
* No hierarchical design rule checking or bounding box computation
* occur during this operation -- both are explicitly avoided.
*
* ----------------------------------------------------------------------------
*/
bool
CIFWriteFlat(rootDef, f)
CellDef *rootDef; /* Pointer to CellDef to be written */
FILE *f; /* Open output file */
{
bool good;
int oldCount = DBWFeedbackCount;
TileTypeBitMask cifMask;
SearchContext scx;
cifStack = StackNew(1);
CIFInitCells();
UndoDisable();
CIFDummyUse->cu_def = rootDef;
/*
* Write CIF preamble out first.
*/
cifOutPreamble(f, rootDef);
/*
* Now process each chunk. We cheat and use cifOut(), so we need to have
* a stack for the single flattened "component" to be on.
*/
{
scx.scx_use = CIFDummyUse;
scx.scx_trans = GeoIdentityTransform;
GEO_EXPAND(&rootDef->cd_bbox, CIFCurStyle->cs_radius, &scx.scx_area);
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
cifHierCopyFunc, (ClientData) CIFComponentDef);
DBReComputeBbox(CIFComponentDef);
cifCellNum = (-2);
CIFComponentDef->cd_client = (ClientData) -1;
StackPush((ClientData) CIFComponentDef, cifStack);
cifOut(f);
/* cifStack SHould be empty now */
if(!StackEmpty(cifStack))
{
TxPrintf("Stack error in CIFWriteInverted()!! "
"Your CIF is probably corrupted.\n");
StackFree(cifStack);
return FALSE;
}
DBCellClearDef(CIFComponentDef);
}
StackFree(cifStack);
/*
* Now we are almost done.
* Just output a call on the root cell
*/
fprintf(f, "C %d;\nEnd\n", (int) CIFComponentDef->cd_client);
DBCellClearDef(CIFComponentDef);
good = !ferror(f);
/* Report any errors that occurred. */
if (DBWFeedbackCount != oldCount)
{
TxPrintf("%d problems occurred. See feedback entries.\n",
DBWFeedbackCount-oldCount);
}
return good;
}

45
cif/Depend Normal file
View File

@ -0,0 +1,45 @@
CIFgen.o: CIFgen.c ../utils/magic.h ../utils/geometry.h ../tiles/tile.h \
../utils/hash.h ../database/database.h ../cif/CIFint.h ../calma/calma.h \
../commands/commands.h ../windows/windows.h ../select/selInt.h \
../utils/stack.h ../utils/malloc.h ../utils/maxrect.h
CIFhier.o: CIFhier.c ../utils/magic.h ../utils/geometry.h ../tiles/tile.h \
../utils/hash.h ../database/database.h ../cif/CIFint.h ../cif/cif.h \
../drc/drc.h ../textio/textio.h ../utils/undo.h ../utils/malloc.h \
../utils/signals.h
CIFmain.o: CIFmain.c ../tcltk/tclmagic.h ../utils/magic.h \
../utils/geometry.h ../tiles/tile.h ../utils/hash.h \
../database/database.h ../cif/CIFint.h ../textio/textio.h \
../windows/windows.h ../dbwind/dbwind.h ../utils/styles.h
CIFrdcl.o: CIFrdcl.c ../utils/magic.h ../utils/malloc.h \
../utils/geometry.h ../tiles/tile.h ../utils/hash.h ../utils/undo.h \
../database/database.h ../cif/CIFint.h ../cif/CIFread.h ../utils/utils.h \
../windows/windows.h ../dbwind/dbwind.h ../utils/main.h ../drc/drc.h
CIFrdpt.o: CIFrdpt.c ../utils/magic.h ../utils/geometry.h ../tiles/tile.h \
../utils/hash.h ../utils/malloc.h ../database/database.h \
../windows/windows.h ../utils/main.h ../cif/CIFint.h ../cif/CIFread.h
CIFrdpoly.o: CIFrdpoly.c ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/hash.h ../database/database.h ../cif/CIFint.h \
../cif/CIFread.h ../utils/malloc.h
CIFrdtech.o: CIFrdtech.c ../tcltk/tclmagic.h ../utils/magic.h \
../utils/geometry.h ../tiles/tile.h ../utils/hash.h \
../database/database.h ../utils/tech.h ../textio/textio.h \
../utils/utils.h ../cif/CIFint.h ../cif/CIFread.h ../calma/calmaInt.h \
../utils/malloc.h
CIFrdutils.o: CIFrdutils.c ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/hash.h ../database/database.h ../cif/CIFint.h \
../cif/CIFread.h ../cif/cif.h ../textio/textio.h ../utils/signals.h \
../utils/undo.h ../utils/malloc.h
CIFsee.o: CIFsee.c ../utils/magic.h ../utils/geometry.h ../tiles/tile.h \
../utils/hash.h ../database/database.h ../windows/windows.h \
../graphics/graphics.h ../dbwind/dbwind.h ../utils/styles.h \
../cif/CIFint.h ../textio/textio.h ../utils/undo.h
CIFtech.o: CIFtech.c ../utils/magic.h ../utils/geometry.h ../tiles/tile.h \
../utils/hash.h ../database/database.h ../utils/tech.h ../utils/utils.h \
../utils/styles.h ../cif/CIFint.h ../calma/calmaInt.h ../textio/textio.h \
../utils/malloc.h ../cif/cif.h ../drc/drc.h
CIFwrite.o: CIFwrite.c ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/utils.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../utils/tech.h ../utils/stack.h \
../utils/undo.h ../cif/cif.h ../cif/CIFint.h ../utils/signals.h \
../windows/windows.h ../dbwind/dbwind.h ../utils/styles.h \
../textio/textio.h

11
cif/Makefile Normal file
View File

@ -0,0 +1,11 @@
#
# rcsid $Header: /usr/cvsroot/magic-8.0/cif/Makefile,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $
#
MODULE = cif
MAGICDIR = ..
SRCS = CIFgen.c CIFhier.c CIFmain.c CIFrdcl.c CIFrdpt.c CIFrdpoly.c \
CIFrdtech.c CIFrdutils.c CIFsee.c CIFtech.c CIFwrite.c
include ${MAGICDIR}/defs.mak
include ${MAGICDIR}/rules.mak

88
cif/cif.h Normal file
View File

@ -0,0 +1,88 @@
/*
* cif.h --
*
* This procedure defines things that are exported by the
* cif module to the rest of the world.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*
*
* rcsid "$Header: /usr/cvsroot/magic-8.0/cif/cif.h,v 1.4 2010/06/24 12:37:15 tim Exp $
*/
#ifndef _CIF_H
#define _CIF_H
#include "database/database.h"
#define CIFMAXRESCALE 100 /* This value avoids integer overflow
* in most cases. However, that
* depends on the size of the layout.
*/
/* Exported global variables (commands/CmdCD.c) */
extern int CIFWarningLevel;
extern int CIFRescaleLimit;
extern bool CIFRescaleAllow;
extern bool CIFNoDRCCheck;
extern bool CIFDoAreaLabels;
extern bool CIFDoCellIdLabels;
extern char *CIFPathPrefix;
extern char *CIFErrorFilename;
extern bool CIFArrayWriteDisable;
extern bool CIFHierWriteDisable;
extern bool CIFSubcellPolygons;
extern bool CIFUnfracture;
/* Procedures that parse the cif sections of a technology file. */
extern void CIFTechStyleInit();
extern void CIFTechInit();
extern bool CIFTechLine();
extern void CIFTechFinal();
extern void CIFTechOutputScale();
extern void CIFTechInputScale();
extern bool CIFTechLimitScale();
extern void CIFReadTechStyleInit();
extern void CIFReadTechInit();
extern bool CIFReadTechLine();
extern void CIFReadTechFinal();
/* Externally-visible procedures: */
extern float CIFGetOutputScale();
extern float CIFGetInputScale();
extern int CIFGetDefaultContactSize();
extern int CIFPaintCurrent();
extern void CIFSeeLayer();
extern void CIFPaintLayer();
extern void CIFSeeHierLayer();
extern void CIFPrintStats();
extern bool CIFWrite();
extern void CIFReadFile();
extern void CIFSetStyle();
extern void CIFSetReadStyle();
extern void CIFPrintStyle();
extern void CIFPrintReadStyle();
extern int CIFOutputScaleFactor();
extern void PaintWireList();
extern LinkedRect *PaintPolygon();
#endif /* _CIF_H */

658
cmwind/CMWcmmnds.c Normal file
View File

@ -0,0 +1,658 @@
/*
* CMWcommands.c --
*
* Commands for the color map editor.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cmwind/CMWcmmnds.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include "tcltk/tclmagic.h"
#include "utils/magic.h"
#include "utils/geometry.h"
#include "windows/windows.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "dbwind/dbwind.h"
#include "utils/main.h"
#include "commands/commands.h"
#include "cmwind/cmwind.h"
#include "graphics/graphics.h"
#include "textio/textio.h"
#include "utils/utils.h"
#include "utils/styles.h"
#include "textio/txcommands.h"
#include "utils/undo.h"
/* Forward declarations: */
extern void cmwButtonUp(), cmwButtonDown();
extern void cbUpdate();
extern void RGBxHSV();
extern void HSVxRGB();
/* If a button is pressed over the top box in the window, which
* displays the current color, we must save the window in which
* it was pressed for use when the button is released. We also
* set a flag so we remember to process the button release.
*/
MagWindow *cmwWindow;
bool cmwWatchButtonUp;
/* The following variable keeps track of whether or not the color
* map has been modified, so that we can warn the user if he attempts
* to exit or load a new color map without saving the changes.
*/
bool cmwModified = FALSE;
/*
* ----------------------------------------------------------------------------
*
* CMWcommand --
*
* This procedure is invoked by the window package whenever a
* button is pushed or a command is typed while the cursor is
* over a colormap window.
*
* Results:
* None.
*
* Side effects:
* A color may be changed, depending on the command.
*
* ----------------------------------------------------------------------------
*/
void
CMWcommand(w, cmd)
MagWindow *w;
TxCommand *cmd;
{
switch (cmd->tx_button)
{
case TX_NO_BUTTON:
WindExecute(w, CMWclientID, cmd);
break;
case TX_LEFT_BUTTON:
case TX_RIGHT_BUTTON:
case TX_MIDDLE_BUTTON:
switch (cmd->tx_buttonAction)
{
case TX_BUTTON_UP:
cmwButtonUp(w, &(cmd->tx_p), cmd->tx_button);
break;
case TX_BUTTON_DOWN:
cmwButtonDown(w, &(cmd->tx_p), cmd->tx_button);
break;
}
break;
default:
ASSERT(FALSE, "CMWcommand");
}
UndoNext();
}
/*
* ----------------------------------------------------------------------------
*
* cmwButtonDown --
*
* Process the button command to change a color value.
*
* Results:
* None.
*
* Side effects:
* May update a color value. Depends on where the button is
* pushed. If a button is pushed over a color bar, then that
* bar is updated to fall where the cursor is. If a button
* is pushed over a color pump, the value is incremented or
* decremented, depending on which pump is hit. If the left
* button is pushed then a small increment is made (the value
* in the associated pump record). If one of the other buttons
* is pushed, an increment 5 times as great is made.
*
* ----------------------------------------------------------------------------
*/
void
cmwButtonDown(w, p, button)
MagWindow *w; /* Window where the button was pressed. */
Point *p;
int button;
{
ColorBar *cb;
ColorPump *cp;
Point surfacePoint;
int x;
double dx;
if (w == NULL) return;
WindPointToSurface(w, p, &surfacePoint, (Rect *) NULL);
/* See if the cursor is over a color bar. */
for (cb = colorBars; cb->cb_name; cb++)
{
if (GEO_ENCLOSE(&surfacePoint, &cb->cb_rect))
{
x = surfacePoint.p_x;
x = MAX(x, cb->cb_rect.r_xbot);
x = MIN(x, cb->cb_rect.r_xtop);
dx = (double) (x - cb->cb_rect.r_xbot)
/ (double) (cb->cb_rect.r_xtop - cb->cb_rect.r_xbot);
cbUpdate(w, cb->cb_code, dx, TRUE);
return;
}
}
/* See if the cursor is over a color pump. */
for (cp = colorPumps; cp->cp_code >= 0; cp++)
{
if (GEO_ENCLOSE(&surfacePoint, &cp->cp_rect))
{
if (button == TX_LEFT_BUTTON)
cbUpdate(w, cp->cp_code, cp->cp_amount, FALSE);
else
cbUpdate(w, cp->cp_code, (double) 5*cp->cp_amount, FALSE);
return;
}
}
/* Note that the "color picker" function can't work as implemented
* because this function is registered only with the color window,
* so it cannot be called with a different window "w". So, we can
* only disable the button functions when pushed over the "current
* color area" rectangle.
*/
#ifndef MAGIC_WRAPPER
/* See if the cursor is over the current color area. If so, remember
* the fact and wait for the button to be released.
*/
if (GEO_ENCLOSE(&surfacePoint, &cmwCurrentColorArea))
{
cmwWindow = w;
cmwWatchButtonUp = TRUE;
if (button == TX_LEFT_BUTTON)
TxPrintf("Release button over new color to edit.\n");
else TxPrintf("Release button over color to copy.\n");
}
#endif
}
/*
* ----------------------------------------------------------------------------
*
* cmwButtonUp --
*
* This procedure handles button releases.
*
* Results:
* None.
*
* Side effects:
* The current color, or its value, may be changed.
*
* ----------------------------------------------------------------------------
*/
void
cmwButtonUp(w, p, button)
MagWindow *w; /* Window where the button was released */
Point *p; /* Point where button was released, in window coords.*/
int button; /* Button that was released. */
{
CMWclientRec *crec;
int r, g, b, color, oldR, oldG, oldB;
extern int cmwRedisplayFunc();
/* If the button wasn't depressed over the top box in the window
* (the one displaying the current color), then we ignore the
* button release.
*/
if (!cmwWatchButtonUp) return;
cmwWatchButtonUp = FALSE;
/* If it's the left button, change the color being edited to the
* one at the pixel underneath the cursor. Otherwise, copy the
* color values from the pixel underneath the cursor to the current
* color.
*/
/* Read the pixel from the window that was underneath the cursor when
* the button was released.
*/
color = GrReadPixel(w, p->p_x, p->p_y);
if (color < 0)
{
TxError("Couldn't read that pixel!\n");
color = 0;
}
if (button == TX_LEFT_BUTTON)
CMWloadWindow(cmwWindow, color);
else
{
crec = (CMWclientRec *) cmwWindow->w_clientData;
(void) GrGetColor(color, &r, &g, &b);
(void) GrGetColor(crec->cmw_color, &oldR, &oldG, &oldB);
(void) GrPutColor(crec->cmw_color, r, g, b);
cmwModified = TRUE;
/* Record old values for undo. */
cmwUndoColor(crec->cmw_color, oldR, oldG, oldB, r, g, b);
/* Mark all windows containing this color as modified */
(void) WindSearch(CMWclientID, (ClientData) NULL, (Rect *) NULL,
cmwRedisplayFunc, (ClientData)(pointertype) crec->cmw_color);
}
}
/*
* ----------------------------------------------------------------------------
*
* cmwPushbutton --
*
* Usage:
* pushbutton <button>
*
* where button is "left", "middle", or "right".
*
* Results:
* None.
*
* Side effects:
* Performs the default action associated with the button event.
*
* ----------------------------------------------------------------------------
*/
void
cmwPushbutton(w, cmd)
MagWindow *w;
TxCommand *cmd;
{
int button;
static char *cmwButton[] = {"left", "middle", "right", NULL};
if (cmd->tx_argc != 2)
{
TxError("Usage: pushbutton <button>\n");
return;
}
button = Lookup(cmd->tx_argv[1], cmwButton);
if (button < 0)
{
TxError("Argument \"button\" must be one of "
"\"left\", \"middle\", or \"right\".\n");
return;
}
else switch(button)
{
case 0:
cmd->tx_button = TX_LEFT_BUTTON;
break;
case 1:
cmd->tx_button = TX_MIDDLE_BUTTON;
break;
case 2:
cmd->tx_button = TX_RIGHT_BUTTON;
break;
}
cmd->tx_buttonAction = TX_BUTTON_DOWN;
CMWcommand(w, cmd);
cmwWatchButtonUp = FALSE;
}
/*
* ----------------------------------------------------------------------------
*
* cmwColor --
*
* Load a color map window with a particular color.
*
* Usage:
* color color-#|next|last|get|rgb
*
* where color-# is the octal number of the color to be edited.
*
* Results:
* None.
*
* Side effects:
* Loads a new color into this window.
*
* ----------------------------------------------------------------------------
*/
void
cmwColor(w, cmd)
MagWindow *w;
TxCommand *cmd;
{
int color, r, g, b;
CMWclientRec *crec;
if (cmd->tx_argc == 1)
{
crec = (CMWclientRec *) w->w_clientData;
GrGetColor(crec->cmw_color, &r, &g, &b);
TxPrintf("Current color is %o octal (%d decimal) "
"(red = %d, green = %d, blue = %d)\n",
crec->cmw_color, crec->cmw_color, r, g, b);
}
else if (cmd->tx_argc == 2)
{
if (sscanf(cmd->tx_argv[1], "%i", &color) == 0)
{
/* Invalid color---allow keywords "next" and "last" */
crec = (CMWclientRec *) w->w_clientData;
if (!strncmp(cmd->tx_argv[1], "next", 4))
{
color = crec->cmw_color + 1;
if (color >= GrNumColors)
color = 0;
}
else if (!strncmp(cmd->tx_argv[1], "last", 4))
{
color = crec->cmw_color - 1;
if (color < 0)
color = GrNumColors - 1;
}
else if (!strncmp(cmd->tx_argv[1], "get", 3))
{
#ifdef MAGIC_WRAPPER
Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(crec->cmw_color));
#else
TxPrintf("Color index %d\n", crec->cmw_color);
#endif
return;
}
else if (!strncmp(cmd->tx_argv[1], "rgb", 3))
{
#ifdef MAGIC_WRAPPER
Tcl_Obj *cobj = Tcl_NewListObj(0, NULL);
GrGetColor(crec->cmw_color, &r, &g, &b);
Tcl_ListObjAppendElement(magicinterp, cobj, Tcl_NewIntObj(r));
Tcl_ListObjAppendElement(magicinterp, cobj, Tcl_NewIntObj(g));
Tcl_ListObjAppendElement(magicinterp, cobj, Tcl_NewIntObj(b));
Tcl_SetObjResult(magicinterp, cobj);
#else
GrGetColor(crec->cmw_color, &r, &g, &b);
TxPrintf("Color RGB=%d %d %d\n", r, g, b);
#endif
return;
}
else
{
TxError("Usage: color [#|next|last|get|rgb]\n");
return;
}
}
if (color < 0 || color >= GrNumColors)
{
TxError("The colormap only has values from 0 to %d (decimal).\n",
(GrNumColors - 1));
return;
}
CMWloadWindow(w, color);
}
else
TxError("Usage: color [#|next|last|get|rgb]\n");
}
/*
* ----------------------------------------------------------------------------
*
* cmwSave --
*
* Save the color map to a disk file.
*
* Usage:
* save [techStyle displayStyle monitorType]
*
* Results:
* None.
*
* Side effects:
* Writes the color map out to disk.
*
* ----------------------------------------------------------------------------
*/
void
cmwSave(w, cmd)
MagWindow *w;
TxCommand *cmd;
{
bool ok;
if ((cmd->tx_argc != 1) && (cmd->tx_argc != 4))
{
TxError("Usage: %s [techStyle displayStyle monitorType]\n",
cmd->tx_argv[0]);
return;
}
if (cmd->tx_argc > 1)
{
ok = GrSaveCMap(cmd->tx_argv[1], cmd->tx_argv[2],
cmd->tx_argv[3], ".", SysLibPath);
}
else
{
ok = GrSaveCMap(DBWStyleType, (char *) NULL, MainMonType,
".", SysLibPath);
}
if (ok) cmwModified = FALSE;
}
/*
* ----------------------------------------------------------------------------
*
* cmwLoad --
*
* Load a new color map from a disk file.
*
* Usage:
* load [file]
*
* Results:
* None.
*
* Side effects:
* A new color map is read from disk. If the file name isn't
* given, the current technology, display type, etc. are used.
*
* ----------------------------------------------------------------------------
*/
void
cmwLoad(w, cmd)
MagWindow *w;
TxCommand *cmd;
{
if ((cmd->tx_argc != 1) && (cmd->tx_argc != 4))
{
TxError("Usage: %s [techStyle displayStyle monitorType]\n",
cmd->tx_argv[0]);
return;
}
if (!CMWCheckWritten()) return;
if (cmd->tx_argc == 4)
{
(void) GrReadCMap(cmd->tx_argv[1], cmd->tx_argv[2],
cmd->tx_argv[3], ".", SysLibPath);
}
else (void) GrReadCMap(DBWStyleType, (char *) NULL,
MainMonType, ".", SysLibPath);
}
/*
* ----------------------------------------------------------------------------
*
* cbUpdate --
*
* Update the value stored with a particular color bar in
* this window. This is a low-level routine that does all
* the dirty work of updating colors.
*
* Results:
* None.
*
* Side effects:
* The color in window w is changed by either replacing one
* of its components (replace == TRUE), or by incrementing
* one of its components. All windows containing this color
* are forced to be redisplayed.
*
* ----------------------------------------------------------------------------
*/
void
cbUpdate(w, code, x, replace)
MagWindow *w; /* Window whose color is to be changed. */
int code; /* Indicates which color component to change. */
double x; /* Gives increment or new value for color. */
int replace; /* TRUE means replace component with x, FALSE
* means increment component by x.
*/
{
CMWclientRec *cr = (CMWclientRec *) w->w_clientData;
double values[6];
int r, g, b, nr, ng, nb;
extern int cmwRedisplayFunc();
/* Get current color map values */
(void) GrGetColor(cr->cmw_color, &r, &g, &b);
values[CB_RED] = ((double) r) / 255.0;
values[CB_GREEN] = ((double) g) / 255.0;
values[CB_BLUE] = ((double) b) / 255.0;
RGBxHSV(values[CB_RED], values[CB_GREEN], values[CB_BLUE],
&values[CB_HUE], &values[CB_SAT], &values[CB_VALUE]);
/* Update the color that changed */
if (replace) values[code] = x;
else values[code] = values[code] + x;
if (values[code] > 1.0) values[code] = 1.0;
if (values[code] < 0.0) values[code] = 0.0;
switch (code)
{
case CB_HUE:
case CB_SAT:
case CB_VALUE:
HSVxRGB(values[CB_HUE], values[CB_SAT], values[CB_VALUE],
&values[CB_RED], &values[CB_GREEN], &values[CB_BLUE]);
break;
}
/* Store this entry back in the color map */
nr = (int) (values[CB_RED] * 255.0 + 0.5);
ng = (int) (values[CB_GREEN] * 255.0 + 0.5);
nb = (int) (values[CB_BLUE] * 255.0 + 0.5);
(void) GrPutColor(cr->cmw_color, nr, ng, nb);
cmwModified = TRUE;
/* Record an undo entry */
cmwUndoColor(cr->cmw_color, r, g, b, nr, ng, nb);
/* Mark all windows containing this color as modified */
(void) WindSearch(CMWclientID, (ClientData) NULL, (Rect *) NULL,
cmwRedisplayFunc, (ClientData)(pointertype) cr->cmw_color);
/* Here. . . ought to mark the layout windows as modified? */
}
int
cmwRedisplayFunc(w, color)
MagWindow *w; /* Window that may have to be redisplayed. */
int color; /* If this color is in window, redisplay the
* color bars in the window.
*/
{
ColorBar *cb;
ColorPump *cp;
Rect screenR;
CMWclientRec *cr = (CMWclientRec *) w->w_clientData;
if (cr->cmw_color == color)
{
for (cb = colorBars; cb->cb_name; cb++)
{
WindSurfaceToScreen(w, &cb->cb_rect, &screenR);
WindAreaChanged(w, &screenR);
}
for (cp = colorPumps; cp->cp_code >= 0; cp++)
{
WindSurfaceToScreen(w, &cp->cp_rect, &screenR);
WindAreaChanged(w, &screenR);
}
}
/* Also update the "color being edited" rectangle */
WindSurfaceToScreen(w, &cmwCurrentColorArea, &screenR);
WindAreaChanged(w, &screenR);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* CMWCheckWritten --
*
* Checks to see if the current color map has been modified
* but not written back to disk. If so, asks user whether he
* cares about the changes.
*
* Results:
* Returns TRUE if the color map hasn't been modified, or if
* the user says he doesn't care about the changes. Returns FALSE
* if the user says he cares.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
bool
CMWCheckWritten()
{
bool indx;
char *prompt;
static char *(yesno[]) = {"no", "yes", NULL};
if (!cmwModified) return TRUE;
prompt = TxPrintString("The color map has been modified.\n"
" Do you want to lose the changes? ");
indx = TxDialog(prompt, yesno, 0);
return indx;
}

436
cmwind/CMWmain.c Normal file
View File

@ -0,0 +1,436 @@
/*
* CMWmain.c --
*
* Procedures to interface the colormap editor with the window package
* for the purposes of window creation, deletion, and modification.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cmwind/CMWmain.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "windows/windows.h"
#include "database/database.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "utils/main.h"
#include "commands/commands.h"
#include "cmwind/cmwind.h"
#include "graphics/graphicsInt.h"
#include "graphics/graphics.h"
#include "textio/textio.h"
#include "utils/utils.h"
#include "utils/styles.h"
#include "graphics/glyphs.h"
#include "utils/malloc.h"
global WindClient CMWclientID;
/* Forward and external declarations */
extern void cmwColor();
extern void cmwSave();
extern void cmwLoad();
extern void cmwPushbutton();
extern void RGBxHSV();
extern void CMWundoInit();
/* -------------------------------------------------------------------- */
/*
* The following is the layout of a color map window:
*
* +========================================================================+
* | +--------------------+ |
* | | | |
* | +--------------------+ |
* | |
* | Red Hue |
* | +---+ +----------------+ +---+ +---+ +----------------+ +---+ |
* | | - | | | | + | | - | | | | + | |
* | +---+ +----------------+ +---+ +---+ +----------------+ +---+ |
* | |
* | Green Saturation |
* | +---+ +----------------+ +---+ +---+ +----------------+ +---+ |
* | | - | | | | + | | - | | | | + | |
* | +---+ +----------------+ +---+ +---+ +----------------+ +---+ |
* | |
* | Blue Value
* | +---+ +----------------+ +---+ +---+ +----------------+ +---+ |
* | | - | | | | + | | - | | | | + | |
* | +---+ +----------------+ +---+ +---+ +----------------+ +---+ |
* | |
* +========================================================================+
*
* The top box displays the current color, and can be buttoned
* to select a different color for editing, or to copy an existing
* color into the current color.
*
* Each of the boxes Red, Green, Blue, etc, is referred to as a
* "color bar". The following table defines the location of each
* color bar. Each of the + and minus boxes as a "color pump",
* which increments or decrements the particular value depending on
* which pump is hit and which mouse button is used to hit it.
*/
ColorBar colorBars[] =
{
"Red", CB_RED, STYLE_RED, {2000, 8000, 10000, 9000},
{2000, 9500, 10000, 10500},
"Green", CB_GREEN, STYLE_GREEN, {2000, 5000, 10000, 6000},
{2000, 6500, 10000, 7500},
"Blue", CB_BLUE, STYLE_BLUE, {2000, 2000, 10000, 3000},
{2000, 3500, 10000, 4500},
"Hue", CB_HUE, STYLE_YELLOW, {14000, 8000, 22000, 9000},
{14000, 9500, 22000, 10500},
"Saturation", CB_SAT, STYLE_GRAY, {14000, 5000, 22000, 6000},
{14000, 6500, 22000, 7500},
"Value", CB_VALUE, STYLE_BROWN1, {14000, 2000, 22000, 3000},
{14000, 3500, 22000, 4500},
0
};
ColorPump colorPumps[] =
{
CB_RED, -.0078, {500, 8000, 1500, 9000},
CB_RED, .0078, {10500, 8000, 11500, 9000},
CB_GREEN, -.0078, {500, 5000, 1500, 6000},
CB_GREEN, .0078, {10500, 5000, 11500, 6000},
CB_BLUE, -.0078, {500, 2000, 1500, 3000},
CB_BLUE, .0078, {10500, 2000, 11500, 3000},
CB_HUE, -.01, {12500, 8000, 13500, 9000},
CB_HUE, .01, {22500, 8000, 23500, 9000},
CB_SAT, -.01, {12500, 5000, 13500, 6000},
CB_SAT, .01, {22500, 5000, 23500, 6000},
CB_VALUE, -.01, {12500, 2000, 13500, 3000},
CB_VALUE, .01, {22500, 2000, 23500, 3000},
-1
};
Rect cmwCurrentColorArea = {{6000, 12000}, {18000, 15000}};
Rect cmwCurrentColorTextBox = {{6000, 15500}, {18000, 16500}};
char *cmwCurrentColorText = "Color Being Edited";
/* Bounding rectangle for entire window */
Rect colorWindowRect = {{0, 1500}, {24000, 17000}};
/*
* ----------------------------------------------------------------------------
*
* CMWcreate --
*
* A new window has been created. Create and initialize the needed
* structures.
*
* Results:
* FALSE if we have too many windows, TRUE otherwise.
*
* Side effects:
* Initialize the window to be editing the background color.
*
* ----------------------------------------------------------------------------
*/
bool
CMWcreate(window, argc, argv)
MagWindow *window;
int argc;
char *argv[];
{
CMWclientRec *crec;
int color;
crec = (CMWclientRec *) mallocMagic(sizeof(CMWclientRec));
window->w_clientData = (ClientData) crec;
if (argc > 0) sscanf(argv[0], "%o", &color);
else color = 0;
color &= 0377;
window->w_flags &= ~(WIND_SCROLLABLE | WIND_SCROLLBARS | WIND_CAPTION);
window->w_frameArea.r_xtop = GrScreenRect.r_xtop;
window->w_frameArea.r_xbot = GrScreenRect.r_xtop - 250;
window->w_frameArea.r_ybot = 0;
window->w_frameArea.r_ytop = 200;
WindSetWindowAreas(window);
CMWloadWindow(window, color);
return (TRUE);
}
/*
* ----------------------------------------------------------------------------
*
* CMWdelete --
*
* Clean up the data structures before deleting a window.
*
* Results:
* TRUE if we really want to delete the window, FALSE otherwise.
*
* Side effects:
* A CMWclientRec is freed.
*
* ----------------------------------------------------------------------------
*/
bool
CMWdelete(window)
MagWindow *window;
{
CMWclientRec *cr;
cr = (CMWclientRec *) window->w_clientData;
if (cr->cmw_cname)
freeMagic(cr->cmw_cname);
freeMagic((char *) cr);
return (TRUE);
}
/*
* ----------------------------------------------------------------------------
*
* CMWreposition --
*
* A window has moved -- center it.
*
* Results:
* none.
*
* Side effects:
* May change the window's view.
*
* ----------------------------------------------------------------------------
*/
void
CMWreposition(window, newScreenArea, final)
MagWindow *window;
Rect *newScreenArea;
bool final;
{
if (final)
WindMove(window, &colorWindowRect);
}
/*
* ----------------------------------------------------------------------------
*
* CMWredisplay --
*
* Redisplay a portion of a window.
*
* Results:
* None.
*
* Side effects:
* Redisplay is done.
* ----------------------------------------------------------------------------
*/
void
CMWredisplay(w, rootArea, clipArea)
MagWindow *w; /* The window containing the area. */
Rect *rootArea; /* Redisplay area in surface coordinates. */
Rect *clipArea; /* An area on the screen to clip to. */
{
CMWclientRec *cr;
ColorBar *cb;
ColorPump *cp;
Rect rect, screenR;
Point screenP;
double values[6], x;
int r, g, b;
char *string;
GrLock(w, TRUE);
cr = (CMWclientRec *) w->w_clientData;
/* Erase previous information */
WindSurfaceToScreen(w, rootArea, &screenR);
GrClipBox(clipArea, STYLE_ERASEALL);
/* Get current color map values */
(void) GrGetColor(cr->cmw_color, &r, &g, &b);
values[CB_RED] = ( ((double) r) + 0.5 ) / 255.0;
values[CB_GREEN] = ( ((double) g) + 0.5 ) / 255.0;
values[CB_BLUE] = ( ((double) b) + 0.5 ) / 255.0;
RGBxHSV(values[CB_RED], values[CB_GREEN], values[CB_BLUE],
&values[CB_HUE], &values[CB_SAT], &values[CB_VALUE]);
/* Redisplay each bar */
for (cb = colorBars; cb->cb_name; cb++)
{
x = values[cb->cb_code];
/* Display the color bar and its bounding box. */
if (GEO_TOUCH(&cb->cb_rect, rootArea))
{
rect.r_xbot = cb->cb_rect.r_xbot;
rect.r_ybot = cb->cb_rect.r_ybot;
rect.r_ytop = cb->cb_rect.r_ytop;
rect.r_xtop = cb->cb_rect.r_xbot +
(int) (x * (double) (cb->cb_rect.r_xtop - cb->cb_rect.r_xbot));
WindSurfaceToScreen(w, &rect, &screenR);
GrClipBox(&screenR, cb->cb_style);
WindSurfaceToScreen(w, &cb->cb_rect, &screenR);
GrClipBox(&screenR, STYLE_BBOX);
}
/* Display bar name */
if (GEO_TOUCH(&cb->cb_textRect, rootArea))
{
WindSurfaceToScreen(w, &cb->cb_textRect, &screenR);
screenP.p_x = (screenR.r_xbot + screenR.r_xtop)/2;
screenP.p_y = (screenR.r_ybot + screenR.r_ytop)/2;
GeoClip(&screenR, &GrScreenRect);
GrPutText(cb->cb_name, STYLE_BBOX, &screenP,
GEO_CENTER, GR_TEXT_LARGE,
TRUE, &screenR, (Rect *) NULL);
}
}
/* Redisplay each of the color pumps. */
for (cp = colorPumps; cp->cp_code >= 0; cp++)
{
if (GEO_TOUCH(&cp->cp_rect, rootArea))
{
WindSurfaceToScreen(w, &cp->cp_rect, &screenR);
GrClipBox(&screenR, STYLE_BBOX);
screenP.p_x = (screenR.r_xbot + screenR.r_xtop)/2;
screenP.p_y = (screenR.r_ybot + screenR.r_ytop)/2;
if (cp->cp_amount < 0) string = "-";
else string = "+";
GeoClip(&screenR, &GrScreenRect);
GrPutText(string, STYLE_BBOX, &screenP, GEO_CENTER, GR_TEXT_LARGE,
TRUE, &screenR, (Rect *) NULL);
}
}
/* Redisplay the box at the top that shows the color being edited.
* This is a bit tricky, since we don't know the style corresponding
* to that color. Instead, change the color in a particular style
* reserved for our own use.
*/
if (GEO_TOUCH(&cmwCurrentColorArea, rootArea))
{
GrStyleTable[STYLE_CMEDIT].color = cr->cmw_color;
WindSurfaceToScreen(w, &cmwCurrentColorArea, &screenR);
GrClipBox(&screenR, STYLE_CMEDIT);
GrClipBox(&screenR, STYLE_BBOX);
}
if (GEO_TOUCH(&cmwCurrentColorTextBox, rootArea))
{
WindSurfaceToScreen(w, &cmwCurrentColorTextBox, &screenR);
screenP.p_x = (screenR.r_xbot + screenR.r_xtop)/2;
screenP.p_y = (screenR.r_ybot + screenR.r_ytop)/2;
GeoClip(&screenR, &GrScreenRect);
GrPutText(cmwCurrentColorText, STYLE_BBOX, &screenP,
GEO_CENTER, GR_TEXT_LARGE,
TRUE, &screenR, (Rect *) NULL);
}
GrUnlock(w);
}
/*
* ----------------------------------------------------------------------------
*
* CMWloadWindow --
*
* Load the window with a new color.
* A color name of NULL causes us to edit the background color.
*
* Results:
* None.
*
* Side effects:
* Loads a color into the window.
*
* ----------------------------------------------------------------------------
*/
void
CMWloadWindow(w, color)
MagWindow *w; /* Identifies window to which color is to be bound */
int color; /* New color to be bound to this window. */
{
CMWclientRec *cr = (CMWclientRec *) w->w_clientData;
char caption[40];
cr->cmw_color = color;
cr->cmw_cname = (char *) NULL;
sprintf(caption, "COLOR = 0%o", cr->cmw_color);
WindCaption(w, caption);
WindAreaChanged(w, (Rect *) NULL);
/* move the contents of the window so the color bars show */
WindMove(w, &colorWindowRect);
}
/*
* ----------------------------------------------------------------------------
*
* CMWinit --
*
* Add the color-map window client to the window module.
*
* Results:
* None.
*
* Side effects:
* Add ourselves as a client to the window package.
*
* ----------------------------------------------------------------------------
*/
void
CMWinit()
{
CMWclientID = WindAddClient("color", CMWcreate, CMWdelete,
CMWredisplay, CMWcommand,
(void(*)()) NULL,
CMWCheckWritten,
CMWreposition,
(GrGlyph *) NULL);
CMWundoInit();
/* Register commands with the client */
WindAddCommand(CMWclientID,
"pushbutton button invoke a button press in the color window",
cmwPushbutton, FALSE);
WindAddCommand(CMWclientID,
"color [color-#] specify color to edit, or print current intensities",
cmwColor, FALSE);
WindAddCommand(CMWclientID,
"load [techStyle displayStyle monitorType]\n\
load new color map techStyle.displayStyle.monitorType",
cmwLoad, FALSE);
WindAddCommand(CMWclientID,
"save [techStyle displayStyle monitorType]\n\
save color map to techStyle.displayStyle.monitorType",
cmwSave, FALSE);
}

325
cmwind/CMWrgbhsv.c Normal file
View File

@ -0,0 +1,325 @@
/*
* CMWrgbhsv.c --
*
* Procedures to translate between RGB color space and HSV color space.
* Courtesy of Ken Fishkin.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cmwind/CMWrgbhsv.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <math.h>
#include "utils/magic.h"
/* max of three numbers */
#define MAX3(a,b,c) (a > b ? (a > c ? a : c) : ( b > c ?b : c))
/* and min */
#define MIN3(a,b,c) (a < b ? (a < c ? a : c) : ( b < c ?b : c))
/*
|-----------------------------------------------------------------------|
| procedure : RGBxHSV |
| description : given r,g,b, each on [0,1], return hue, sat- |
| : uration, and value, each on [0,1]. |
| : returns true <==> hue is defined. |
| source : Smith, Alvy Ray. "Color Tutorial Notes". |
| : Technical Memo 37, LucasFilm. |
| : hue calc changed a tad, according to Foley |
| : and Van Dam. |
|-----------------------------------------------------------------------|
*/
bool
RGBxHSV( r, g, b, h, s, v)
double r, g, b;
double *h, *s, *v;
{
double max, delta;
double mr,mg,mb;
*v = max = MAX3(r,g,b);
if ( (max == 0) || ( (delta = max - MIN3(r,g,b) ) == 0) ) {
/* achromatic */
*s = 0;
*h = 0;
return(FALSE);
};
*s = delta/ max;
mr = (max - r)/delta;
mg = (max - g)/delta;
mb = (max - b)/delta;
if (r == max)
*h = mb - mg;
else if ( g == max)
*h = 2.0 + mr - mb;
else if ( b == max)
*h = 4.0 + mg - mr;
*h /= 6;
if (*h < 0.0)
*h += 1.0;
return(TRUE);
}
/*
|-----------------------------------------------------------------------|
| procedure : HSVxRGB |
| description : given HSV on [0,1], returns equivalent |
| : RGB on [0,1]. |
| source : Smith, Alvy Ray. "Color Tutorial Notes". |
| : Technical Memo 37, LucasFilm. |
|-----------------------------------------------------------------------|
*/
#define SETRGB(rr,gg,bb) *r=rr;*g=gg;*b=bb
void
HSVxRGB( h,s,v,r,g,b)
double h,s,v;
double *r,*g,*b;
{
double f,m,n,k;
int i;
double vs,vsf;
h *= 6;
i = h; /* integer part of hue */
f = h - i; /* fractional part */
vs = v*s;
vsf = vs*f;
m = v - vs;
n = v - vsf;
k = v - vs + vsf;
switch(i % 6) {
case 0 : SETRGB( v,k,m); break;
case 1 : SETRGB( n,v,m); break;
case 2 : SETRGB( m,v,k); break;
case 3 : SETRGB( m,n,v); break;
case 4 : SETRGB( k,m,v); break;
case 5 : SETRGB( v,m,n); break;
}
}
/*
|-----------------------------------------------------------------------|
| procedure : RGBxHSL |
| description : converts from RGB to HSL coordinates. |
| source : '79 graphics core. |
|-----------------------------------------------------------------------|
*/
bool
RGBxHSL( r, g, b, h, s, l )
double r, g, b;
double *h, *s, *l;
{
double min, max;
double delta, mr, mg, mb;
min = MIN3( r,g,b);
max = MAX3( r,g,b);
/* Lightness calculation */
/* source - 79 graphics core */
*l = 0.5 * (max + min);
if ( (delta = max - min) == 0) {
/* achromatic */
*s = 0.0;
*h = 0.0;
return FALSE;
}
/* Saturation calculation */
/* HSL is a double cone */
if (*l < 0.5)
*s = (delta)/(max+min);
else
*s = (delta)/(2.0-(max+min));
/* hue calculation */
mr = (max - r)/delta;
mg = (max - g)/delta;
mb = (max - b)/delta;
if (r == max)
*h = mb - mg;
else if ( g == max)
*h = 2.0 + mr - mb;
else if ( b == max)
*h = 4.0 + mg - mr;
*h /= 6;
if (*h < 0.0)
*h += 1.0;
return(TRUE);
}
/*
|-----------------------------------------------------------------------|
| procedure : HSLxRGB |
| description : converts from HSL, each on [0,1], to RGB, |
| : each on [0,1]. |
| note : the idea is to use s,l to get HSV s,v, and |
| : then use HSVxRGB - this is faster than the |
| : '79 core algorithm. |
|-----------------------------------------------------------------------|
*/
void
HSLxRGB( h, s, l, r, g, b )
double h, s, l;
double *r, *g, *b;
{
double min;
double v;
double f,n,k;
int i;
double vsf;
if ( l <= 0.5)
v = l * (1.0 + s);
else
v = l + s - l*s;
min = 2*l - v;
if ( (s == 0.0) || ( l == 0.0) || ( l == 1.0 ) ) {
SETRGB(l,l,l);
return;
}
/* now just use hsvxrgb */
s = ( v - min) / v;
h *= 6;
i = h; /* integer part of hue */
f = h - i; /* fractional part */
vsf = v*s*f;
n = v - vsf;
k = min + vsf;
switch(i % 6) {
case 0 : SETRGB( v,k,min); break;
case 1 : SETRGB( n,v,min); break;
case 2 : SETRGB( min,v,k); break;
case 3 : SETRGB( min,n,v); break;
case 4 : SETRGB( k,min,v); break;
case 5 : SETRGB( v,min,n); break;
}
}
/*
|-----------------------------------------------------------------------|
| procedure : Correct_chromaticity |
| description : given the white point at location (wx,wy), |
| : and an existing point (x,y), such that |
| : x + y > 1, intersect a line through the |
| : white point and the exisiting point with the |
| : line x+y = 1. side-affects new point. |
|-----------------------------------------------------------------------|
*/
void
Correct_chromaticity(x, y, wx, wy)
double *x,*y;
double wx,wy;
{
double oldx,oldy;
double slope;
double b;
oldx = *x; oldy = *y;
slope = ( oldy - wy ) / ( oldx - wx);
/* find b by eval'ing at white point */
b = wy - slope*wx;
*x = ( 1.0 - b ) / ( 1.0 + slope);
*y = 1.0 - *x;
}
/*
|-----------------------------------------------------------------------|
| procedure : xyz_to_mrgb |
| description : converts xyz to monitor rgb. |
| : only really correct for mitsubishi mon. |
|-----------------------------------------------------------------------|
*/
void
xyz_to_mrgb(x, y, z, mr, mg, mb)
double x, y, z;
double *mr, *mg, *mb;
{
*mr = 2.4513*x - 1.2249*y - 0.3237*z;
*mg = -1.4746*x + 2.5052*y + 0.0596*z;
*mb = 0.0212*x - 0.2550*y + 1.1487*z;
}
/*
|-----------------------------------------------------------------------|
| procedure : Make_mRGB_Nice |
| description : make mRGB values lie in 0..1, correcting for |
| : luminance overflow, chrominance irreproduc- |
| : ibility. |
| assumptions : at most one of mR,mG,mB < 0 |
|-----------------------------------------------------------------------|
*/
void
Make_mRGB_Nice(mR,mG,mB)
double *mR,*mG,*mB;
{
double min,max;
double mr, mg, mb;
double mY;
double white_mr,white_mg,white_mb;
max = *mR;
if ( max < *mG) max = *mG;
if ( max < *mB) max = *mB;
if ( max > 1.0) { /* luminance overflow, maintain chromaticity */
*mR /= max;
*mG /= max;
*mB /= max;
}
min = *mR;
if ( min > *mG) min = *mG;
if ( min > *mB) min = *mB;
if ( min >= 0.0 )
return;
/* correct in mrgb space */
mY = *mR + *mG + *mB;
mr = *mR/mY; mg = *mG / mY; mb = *mB / mY;
/* correct based on which component is < 0 */
/* find monitor white point */
xyz_to_mrgb(1.0/3.0,1.0/3.0,1.0/3.0,&white_mr,&white_mg,&white_mb);
if ( mr < 0 ) {
mr = 0.0;
Correct_chromaticity( &mg, &mb, white_mg,white_mb);
} else if ( mg < 0 ) {
mg = 0.0;
Correct_chromaticity( &mr, &mb, white_mr,white_mb);
} else if ( mb < 0 ) {
mb = 0.0;
Correct_chromaticity( &mr, &mg, white_mr,white_mg);
}
*mR = mr*mY;
*mG = mg*mY;
*mB = mb*mY;
}

210
cmwind/CMWundo.c Normal file
View File

@ -0,0 +1,210 @@
/*
* CMWundo.c --
*
* Interface to the undo package for the color map editor.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cmwind/CMWundo.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "graphics/graphics.h"
#include "windows/windows.h"
#include "cmwind/cmwind.h"
#include "utils/undo.h"
/*
* Identifiers for the color map window editing
* operation.
*/
UndoType cmwUndoClientID;
/*
* Functions to play events forward/backward.
*/
void cmwUndoForw(), cmwUndoBack();
void cmwUndoStart(), cmwUndoDone();
/*
* A single undo event for the
* color map module.
*/
typedef struct
{
int cue_color; /* Index in color map */
int old_r, old_g, old_b; /* Old RGB */
int new_r, new_g, new_b; /* New RGB */
} colorUE;
/*
* Table of colors that were changed as a result
* of an undo/redo command.
*/
bool cmwColorsChanged[256];
/*
* ----------------------------------------------------------------------------
*
* CMWundoInit --
*
* Initialize the color map editor part of the undo package.
* Makes the functions contained in here known to the
* undo module.
*
* Results:
* None.
*
* Side effects:
* Calls the undo package.
*
* ----------------------------------------------------------------------------
*/
void
CMWundoInit()
{
cmwUndoClientID = UndoAddClient(cmwUndoStart, cmwUndoDone, NULL, NULL,
cmwUndoForw, cmwUndoBack, "color map");
}
/*
* ----------------------------------------------------------------------------
*
* cmwUndoForw --
* cmwUndoBack --
*
* Play forward/backward a colormap undo event.
*
* Results:
* None.
*
* Side effects:
* Modifies the colormap.
*
* ----------------------------------------------------------------------------
*/
void
cmwUndoForw(up)
colorUE *up;
{
(void) GrPutColor(up->cue_color, up->new_r, up->new_g, up->new_b);
cmwColorsChanged[up->cue_color] = TRUE;
}
void
cmwUndoBack(up)
colorUE *up;
{
(void) GrPutColor(up->cue_color, up->old_r, up->old_g, up->old_b);
cmwColorsChanged[up->cue_color] = TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* cmwUndoColor --
*
* Record on the undo list a change in a color map entry.
*
* Results:
* None.
*
* Side effects:
* Updates the undo list.
*
* ----------------------------------------------------------------------------
*/
void
cmwUndoColor(color, oldr, oldg, oldb, newr, newg, newb)
int color;
int oldr, oldg, oldb;
int newr, newg, newb;
{
colorUE *up;
up = (colorUE *) UndoNewEvent(cmwUndoClientID, sizeof (colorUE));
if (up == (colorUE *) NULL)
return;
up->cue_color = color;
up->old_r = oldr;
up->old_g = oldg;
up->old_b = oldb;
up->new_r = newr;
up->new_g = newg;
up->new_b = newb;
}
/*
* ----------------------------------------------------------------------------
*
* cmwUndoStart --
*
* Initialization for undo/redo for the color map editor.
*
* Results:
* None.
*
* Side effects:
* Initializes cmwColorsChanged[].
*
* ----------------------------------------------------------------------------
*/
void
cmwUndoStart()
{
int i;
for (i = 0; i < 256; i++)
cmwColorsChanged[i] = FALSE;
}
/*
* ----------------------------------------------------------------------------
*
* cmwUndoDone --
*
* Termination for undo/redo for the color map editor.
* Forces redisplay of any of the windows containing colors that
* were changed.
*
* Results:
* None.
*
* Side effects:
* Causes redisplay.
*
* ----------------------------------------------------------------------------
*/
void
cmwUndoDone()
{
int i;
extern int cmwRedisplayFunc();
for (i = 0; i < 256; i++)
if (cmwColorsChanged[i])
(void) WindSearch(CMWclientID, (ClientData) NULL, (Rect *) NULL,
cmwRedisplayFunc, (ClientData) i);
}

16
cmwind/Depend Normal file
View File

@ -0,0 +1,16 @@
CMWmain.o: CMWmain.c ../utils/magic.h ../utils/geometry.h \
../windows/windows.h ../database/database.h ../tiles/tile.h \
../utils/hash.h ../utils/main.h ../commands/commands.h \
../cmwind/cmwind.h ../textio/txcommands.h ../graphics/graphicsInt.h \
../graphics/graphics.h ../textio/textio.h ../utils/utils.h \
../utils/styles.h ../graphics/glyphs.h ../utils/malloc.h
CMWcmmnds.o: CMWcmmnds.c ../tcltk/tclmagic.h ../utils/magic.h \
../utils/geometry.h ../windows/windows.h ../tiles/tile.h ../utils/hash.h \
../database/database.h ../dbwind/dbwind.h ../utils/main.h \
../commands/commands.h ../cmwind/cmwind.h ../textio/txcommands.h \
../graphics/graphics.h ../textio/textio.h ../utils/utils.h \
../utils/styles.h ../utils/undo.h
CMWundo.o: CMWundo.c ../utils/magic.h ../utils/geometry.h \
../graphics/graphics.h ../windows/windows.h ../cmwind/cmwind.h \
../textio/txcommands.h ../utils/undo.h
CMWrgbhsv.o: CMWrgbhsv.c ../utils/magic.h

10
cmwind/Makefile Normal file
View File

@ -0,0 +1,10 @@
#
# rcsid $Header: /usr/cvsroot/magic-8.0/cmwind/Makefile,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $
#
MODULE = cmwind
MAGICDIR = ..
SRCS = CMWmain.c CMWcmmnds.c CMWundo.c CMWrgbhsv.c
include ${MAGICDIR}/defs.mak
include ${MAGICDIR}/rules.mak

80
cmwind/cmwind.h Normal file
View File

@ -0,0 +1,80 @@
/*
* cmwind.h --
*
* Interface definitions for the 'glue' between the window
* manager and the color map editor.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*
* rcsid $Header: /usr/cvsroot/magic-8.0/cmwind/cmwind.h,v 1.2 2009/09/10 20:32:51 tim Exp $
*/
#ifndef _CMWIND_H
#define _CMWIND_H
#include "windows/windows.h"
#include "textio/txcommands.h"
/* data structures */
typedef struct
{
char *cmw_cname; /* Name of color */
int cmw_color; /* Index in color map if >= 0 */
} CMWclientRec;
#define CB_RED 0 /* Red */
#define CB_GREEN 1 /* Green */
#define CB_BLUE 2 /* Blue */
#define CB_HUE 3 /* Hue */
#define CB_SAT 4 /* Saturation */
#define CB_VALUE 5 /* Value */
/* The following data structure defines a color bar, used to display
* the value of a particular color parameter as a horizontal bar.
*/
typedef struct
{
char *cb_name; /* Name of color */
int cb_code; /* Which color bar */
int cb_style; /* Style for redisplay */
Rect cb_rect; /* Bounding rectangle of bar */
Rect cb_textRect; /* Bounding rectangle of box for name */
} ColorBar;
/* The following data structure defins a color pump, a little rectangle
* that, when buttoned, increments or decrements a particular color value.
*/
typedef struct
{
int cp_code; /* Which color bar */
double cp_amount; /* Amount to increment or decrement. */
Rect cp_rect; /* Bounding rectangle of pump */
} ColorPump;
/* Exported procedures */
extern void CMWloadWindow(MagWindow *, int);
extern void CMWcommand(MagWindow *, TxCommand *);
extern Rect colorWindowRect;
extern WindClient CMWclientID;
extern ColorBar colorBars[];
extern ColorPump colorPumps[];
extern Rect cmwCurrentColorArea;
extern void cmwUndoColor(int, int, int, int, int, int, int);
extern bool CMWCheckWritten(void);
#endif /* _CMWIND_H */

1157
commands/CmdAB.c Normal file

File diff suppressed because it is too large Load Diff

208
commands/CmdAuto.c Normal file
View File

@ -0,0 +1,208 @@
/*
* CmdAuto.c --
*
* This file contains functions which act as placeholders for command
* functions which have been compiled as Tcl modules, using the Tcl
* interface.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifdef MAGIC_WRAPPER
#include <stdio.h>
#include <stdlib.h>
#include "tcltk/tclmagic.h"
#include "utils/magic.h"
#include "utils/geometry.h"
#include "windows/windows.h"
#include "textio/txcommands.h"
#ifdef EXT2SIM_AUTO
/*
* ----------------------------------------------------------------------------
* CmdAutoExtToSim() --
*
* Tcl auto-loading module routine.
* This routine replaces CmdExtToSim.
* The exttosim routine is not loaded at runtime, but is
* loaded the first time the "exttosim" command is invoked.
*
* The job of replacing the appropriate functionTable entries is
* the responsibility of the initialization function. If something
* goes wrong with the auto-load, it MUST set an error condition in
* Tcl or this routine will infinitely recurse!
*
* ----------------------------------------------------------------------------
*/
void
CmdAutoExtToSim(w, cmd)
MagWindow *w;
TxCommand *cmd;
{
int result;
/* Auto-load */
result = Tcl_Eval(magicinterp, "load " TCL_DIR "/exttosim" SHDLIB_EXT);
/* Call function which was originally intended */
if (result == TCL_OK)
WindSendCommand(w, cmd, FALSE);
}
#endif /* EXT2SIM_AUTO */
#ifdef EXT2SPICE_AUTO
/*
* ----------------------------------------------------------------------------
* CmdAutoExtToSpice() --
*
* Tcl auto-loading module routine.
* This routine replaces CmdExtToSpice.
* The exttospice routine is not loaded at runtime, but is
* loaded the first time the "exttospice" command is invoked.
*
* The job of replacing the appropriate functionTable entries is
* the responsibility of the initialization function. If something
* goes wrong with the auto-load, it MUST set an error condition in
* Tcl or this routine will infinitely recurse!
*
* ----------------------------------------------------------------------------
*/
void
CmdAutoExtToSpice(w, cmd)
MagWindow *w;
TxCommand *cmd;
{
int result;
/* Auto-load */
result = Tcl_Eval(magicinterp, "load " TCL_DIR "/exttospice" SHDLIB_EXT);
/* Call function which was originally intended */
if (result == TCL_OK)
WindSendCommand(w, cmd, FALSE);
}
#endif /* EXT2SPICE_AUTO */
#ifdef ROUTE_AUTO
/*
* ----------------------------------------------------------------------------
* CmdAutoRoute() --
*
* Tcl auto-loading module routine. If "route" is configured as a
* Tcl module, then this routine replaces CmdRoute and the other
* command routines associated with the routing functions. Router
* routines are not loaded at runtime, but are loaded the first time
* the "route" ("iroute", "garoute", etc.) command is invoked.
*
* The job of replacing the appropriate functionTable entries is
* the responsibility of the initialization function. If something
* goes wrong with the auto-load, it MUST set an error condition in
* Tcl or this routine will infinitely recurse!
*
* ----------------------------------------------------------------------------
*/
void
CmdAutoRoute(w, cmd)
MagWindow *w;
TxCommand *cmd;
{
int result;
/* Auto-load */
result = Tcl_Eval(magicinterp, "load " TCL_DIR "/tclroute" SHDLIB_EXT);
/* Call function which was originally intended */
if (result == TCL_OK)
WindSendCommand(w, cmd, FALSE);
}
#endif /* ROUTE_AUTO */
#ifdef PLOT_AUTO
/*
* ----------------------------------------------------------------------------
* CmdAutoPlot() --
*
* Tcl auto-loading module routine. If "plot" is configured as a
* Tcl module, then this routine replaces CmdPlot. Plot routines
* are not loaded at runtime, but are loaded the first time the
* "plot" command is invoked.
*
* The job of replacing the appropriate functionTable entries is
* the responsibility of the initialization function. If something
* goes wrong with the auto-load, it MUST set an error condition in
* Tcl or this routine will infinitely recurse!
*
* ----------------------------------------------------------------------------
*/
void
CmdAutoPlot(w, cmd)
MagWindow *w;
TxCommand *cmd;
{
int result;
/* Auto-load */
result = Tcl_Eval(magicinterp, "load " TCL_DIR "/tclplot" SHDLIB_EXT);
/* Call function which was originally intended */
if (result == TCL_OK)
WindSendCommand(w, cmd, FALSE);
}
#endif /* PLOT_AUTO */
#ifdef LEF_AUTO
/*
* ----------------------------------------------------------------------------
* CmdAutoLef() --
*
* Tcl auto-loading module routine. If "lef" is configured as a
* Tcl module, then this routine replaces CmdLef. LEF routines
* are not loaded at runtime, but are loaded the first time the
* "lef" command is invoked.
*
* The job of replacing the appropriate functionTable entries is
* the responsibility of the initialization function. If something
* goes wrong with the auto-load, it MUST set an error condition in
* Tcl or this routine will infinitely recurse!
*
* ----------------------------------------------------------------------------
*/
void
CmdAutoLef(w, cmd)
MagWindow *w;
TxCommand *cmd;
{
int result;
/* Auto-load */
result = Tcl_Eval(magicinterp, "load " TCL_DIR "/magiclef" SHDLIB_EXT);
/* Call function which was originally intended */
if (result == TCL_OK)
WindSendCommand(w, cmd, FALSE);
}
#endif /* LEF_AUTO */
#endif /* MAGIC_WRAPPER */

4048
commands/CmdCD.c Normal file

File diff suppressed because it is too large Load Diff

1200
commands/CmdE.c Normal file

File diff suppressed because it is too large Load Diff

1955
commands/CmdFI.c Normal file

File diff suppressed because it is too large Load Diff

1883
commands/CmdLQ.c Normal file

File diff suppressed because it is too large Load Diff

2708
commands/CmdRS.c Normal file

File diff suppressed because it is too large Load Diff

1173
commands/CmdSubrs.c Normal file

File diff suppressed because it is too large Load Diff

2037
commands/CmdTZ.c Normal file

File diff suppressed because it is too large Load Diff

1067
commands/CmdWizard.c Normal file

File diff suppressed because it is too large Load Diff

62
commands/Depend Normal file
View File

@ -0,0 +1,62 @@
CmdSubrs.o: CmdSubrs.c ../utils/magic.h ../utils/geometry.h \
../utils/utils.h ../database/database.h ../tiles/tile.h ../utils/hash.h \
../windows/windows.h ../dbwind/dbwind.h ../utils/main.h \
../commands/commands.h ../textio/textio.h ../cif/cif.h ../drc/drc.h \
../textio/txcommands.h ../utils/undo.h ../utils/macros.h ../sim/sim.h \
../select/select.h
CmdAB.o: CmdAB.c ../tcltk/tclmagic.h ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/hash.h ../database/database.h \
../windows/windows.h ../dbwind/dbwind.h ../utils/main.h \
../commands/commands.h ../utils/utils.h ../textio/textio.h ../drc/drc.h \
../cif/cif.h ../graphics/graphics.h ../textio/txcommands.h \
../utils/malloc.h ../utils/netlist.h ../select/select.h
CmdCD.o: CmdCD.c ../tcltk/tclmagic.h ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/hash.h ../database/database.h \
../windows/windows.h ../dbwind/dbwind.h ../utils/main.h \
../commands/commands.h ../utils/utils.h ../textio/textio.h ../drc/drc.h \
../graphics/graphics.h ../textio/txcommands.h ../cif/cif.h \
../calma/calma.h ../utils/styles.h ../router/rtrDcmpose.h \
../select/select.h ../utils/signals.h ../utils/malloc.h ../cif/CIFint.h \
../cif/CIFread.h
CmdE.o: CmdE.c ../tcltk/tclmagic.h ../utils/magic.h ../utils/styles.h \
../utils/geometry.h ../utils/utils.h ../tiles/tile.h ../utils/hash.h \
../database/database.h ../windows/windows.h ../graphics/graphics.h \
../dbwind/dbwind.h ../utils/main.h ../commands/commands.h \
../textio/textio.h ../utils/macros.h ../drc/drc.h ../textio/txcommands.h \
../extract/extract.h ../select/select.h
CmdFI.o: CmdFI.c ../tcltk/tclmagic.h ../utils/magic.h ../utils/geometry.h \
../utils/utils.h ../utils/undo.h ../tiles/tile.h ../utils/hash.h \
../database/database.h ../windows/windows.h ../dbwind/dbwind.h \
../utils/main.h ../commands/commands.h ../textio/textio.h \
../utils/macros.h ../drc/drc.h ../textio/txcommands.h ../utils/styles.h \
../graphics/graphics.h ../extract/extract.h ../utils/malloc.h \
../select/select.h ../sim/sim.h ../gcr/gcr.h
CmdLQ.o: CmdLQ.c ../tcltk/tclmagic.h ../utils/magic.h ../utils/malloc.h \
../utils/geometry.h ../utils/utils.h ../tiles/tile.h ../utils/hash.h \
../database/database.h ../database/fonts.h ../windows/windows.h \
../dbwind/dbwind.h ../utils/main.h ../commands/commands.h \
../textio/textio.h ../graphics/graphics.h ../drc/drc.h \
../textio/txcommands.h ../utils/undo.h ../select/select.h \
../netmenu/netmenu.h
CmdRS.o: CmdRS.c ../tcltk/tclmagic.h ../utils/magic.h ../utils/stack.h \
../utils/geometry.h ../utils/utils.h ../tiles/tile.h ../utils/hash.h \
../database/database.h ../database/fonts.h ../windows/windows.h \
../dbwind/dbwind.h ../utils/main.h ../commands/commands.h \
../textio/textio.h ../graphics/graphics.h ../utils/tech.h ../drc/drc.h \
../textio/txcommands.h ../utils/malloc.h ../utils/netlist.h \
../netmenu/netmenu.h ../select/select.h ../utils/signals.h ../sim/sim.h
CmdTZ.o: CmdTZ.c ../tcltk/tclmagic.h ../utils/magic.h ../utils/malloc.h \
../utils/geometry.h ../utils/utils.h ../tiles/tile.h ../utils/hash.h \
../database/database.h ../windows/windows.h ../dbwind/dbwind.h \
../utils/main.h ../commands/commands.h ../textio/textio.h \
../textio/txcommands.h ../utils/signals.h ../utils/undo.h \
../select/select.h ../utils/styles.h ../wiring/wiring.h \
../utils/netlist.h ../netmenu/netmenu.h ../utils/tech.h ../drc/drc.h
CmdWizard.o: CmdWizard.c ../utils/magic.h ../utils/geometry.h \
../utils/malloc.h ../tiles/tile.h ../utils/hash.h ../database/database.h \
../windows/windows.h ../dbwind/dbwind.h ../utils/main.h \
../commands/commands.h ../utils/runstats.h ../textio/textio.h \
../graphics/graphics.h ../utils/signals.h ../utils/utils.h \
../textio/txcommands.h
CmdAuto.o: CmdAuto.c ../tcltk/tclmagic.h ../utils/magic.h \
../utils/geometry.h ../windows/windows.h ../textio/txcommands.h

21
commands/Makefile Normal file
View File

@ -0,0 +1,21 @@
#
# rcsid $Header: /usr/cvsroot/magic-8.0/commands/Makefile,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $
#
MODULE = commands
MAGICDIR = ..
SRCS = CmdSubrs.c CmdAB.c CmdCD.c CmdE.c CmdFI.c \
CmdLQ.c CmdRS.c CmdTZ.c CmdWizard.c CmdAuto.c
# Force the module to regenerate the symbolic link in the readline
# directory, as it may be needed by CmdFI.c (in the non-Tcl compile)
module: ${MAGICDIR}/readline/readline lib${MODULE}.o
${MAGICDIR}/readline/readline:
@if ( ! test -f ${MAGICDIR}/readline/readline ) ; then \
(cd ${MAGICDIR}/readline; ln -s `ls | grep readline` readline) ; \
fi
include ${MAGICDIR}/defs.mak
include ${MAGICDIR}/rules.mak

67
commands/commands.h Normal file
View File

@ -0,0 +1,67 @@
/*
* commands.h --
*
* Definitions for the commands module.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*
* Needs to include: tiles.h, database.h
*
* rcsid $Header: /usr/cvsroot/magic-8.0/commands/commands.h,v 1.3 2009/01/19 15:43:03 tim Exp $
*/
#ifndef _COMMANDS_H
#define _COMMANDS_H
#include "windows/windows.h"
#include "database/database.h"
/*
* Name of default yank buffer
*/
#define YANKBUFFERNAME "y"
/*
* Manipulation of user-supplied "layer" masks.
* These may include both layers specifiable in a TileTypeMask,
* and pseudo-layers such as "subcells" and "labels".
*
* These are treated just like other TileTypes, except they
* reside in the uppermost TT_RESERVEDTYPES tile type numbers.
*/
#define L_CELL (TT_MAXTYPES-1) /* Subcell layer */
#define L_LABEL (TT_MAXTYPES-2) /* Label "layer" */
extern TileTypeBitMask CmdYMCell;
extern TileTypeBitMask CmdYMLabel;
extern TileTypeBitMask CmdYMAllButSpace;
/* --------------------- Global procedure headers --------------------- */
extern MagWindow *CmdGetRootBox();
extern MagWindow *CmdGetEditPoint();
extern MagWindow *CmdGetRootPoint();
extern bool CmdWarnWrite();
extern bool CmdParseLayers();
extern void CmdAddSlop();
extern void CmdLabelProc();
extern void CmdSetWindCaption();
extern CellUse *CmdGetSelectedCell();
extern bool CmdIllegalChars();
extern void CmdDoMacro();
extern TileType CmdFindNetProc();
extern bool CmdCheckForPaintFunc();
#endif /* _COMMANDS_H */

12
configure vendored Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
#
# Use: ./configure [args]
#
# where [args] are arguments passed to the scripts/configure script
#
# This script is a workaround to GNU autoconf which can't deal with having
# all of its config scripts in a different directory than the configure
# script itself. It also sets up CFLAGS without the default optimizer
# flag (-O2).
( CFLAGS="-g"; export CFLAGS; cd scripts ; ./configure $* )

261
database/DBbound.c Normal file
View File

@ -0,0 +1,261 @@
/*
* DBbound.c --
*
* Computation of boundaries of a database tile plane.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBbound.c,v 1.2 2008/12/11 04:20:04 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "database/database.h"
#include "tiles/tile.h"
typedef struct dbcellboundstruct
{
Rect *area;
bool extended;
bool found;
} DBCellBoundStruct;
/*
* --------------------------------------------------------------------
* --------------------------------------------------------------------
*/
int
DBBoundCellPlane(def, extended, rect)
CellDef *def;
bool extended;
Rect *rect;
{
TreeFilter filter;
DBCellBoundStruct cbs;
int dbCellBoundFunc();
Plane *plane;
filter.tf_func = NULL;
filter.tf_arg = (ClientData)&cbs;
cbs.area = rect;
cbs.extended = extended;
cbs.found = FALSE;
*rect = GeoNullRect;
if (TiSrArea((Tile *)NULL, def->cd_planes[PL_CELL],
&TiPlaneRect, dbCellBoundFunc, (ClientData) &filter) == 0)
return cbs.found;
else
return -1;
}
int
dbCellBoundFunc(tile, fp)
Tile *tile;
TreeFilter *fp;
{
CellUse *use;
CellTileBody *body;
Rect *bbox;
DBCellBoundStruct *cbs;
cbs = (DBCellBoundStruct *)fp->tf_arg;
for (body = (CellTileBody *) TiGetBody(tile); body != NULL;
body = body->ctb_next)
{
use = body->ctb_use;
bbox = &use->cu_bbox;
if ((BOTTOM(tile) <= bbox->r_ybot) && (RIGHT(tile) >= bbox->r_xtop))
{
if (cbs->found)
{
if (cbs->extended)
GeoInclude(&use->cu_extended, cbs->area);
else
GeoInclude(&use->cu_bbox, cbs->area);
}
else
{
if (cbs->extended)
*cbs->area = use->cu_extended;
else
*cbs->area = use->cu_bbox;
cbs->found = TRUE;
}
}
}
return 0;
}
/*
* --------------------------------------------------------------------
*
* DBBoundPlane --
*
* Determine the bounding rectangle for the supplied tile plane.
* The bounding rectangle is the smallest rectangle that completely
* encloses all non-space tiles.
*
* If the tile plane is completely empty, we return a 0x0 bounding
* box at the origin.
*
* Results:
* TRUE if the tile plane contains any geometry, FALSE
* if it is completely empty.
*
* Side effects:
* Sets *rect to the bounding rectangle.
*
* --------------------------------------------------------------------
*/
bool
DBBoundPlane(plane, rect)
Plane *plane;
Rect *rect;
{
Tile *left, *right, *top, *bottom, *tp;
left = plane->pl_left;
right = plane->pl_right;
top = plane->pl_top;
bottom = plane->pl_bottom;
rect->r_ur = TiPlaneRect.r_ll;
rect->r_ll = TiPlaneRect.r_ur;
/*
* To find the rightmost and leftmost solid edges, we
* scan along the respective edges. Our assumption is
* that the only tiles along the edges are space tiles,
* which, by the maximum horizontal strip property, must
* have either solid tiles or the edge of the plane on
* their other sides.
*/
for (tp = TR(left); tp != bottom; tp = LB(tp))
if (RIGHT(tp) < rect->r_xbot)
rect->r_xbot = RIGHT(tp);
for (tp = BL(right); tp != top; tp = RT(tp))
if (LEFT(tp) > rect->r_xtop)
rect->r_xtop = LEFT(tp);
/*
* We assume that only space tiles extend all the way
* from the left edge of the plane to the right. We
* also assume that the topmost and bottommost tiles
* are space tiles.
*/
rect->r_ytop = BOTTOM(LB(top));
rect->r_ybot = TOP(RT(bottom));
/*
* If the bounding rectangle is degenerate (indicating no solid
* tiles in the plane), we make it the 1x1 rectangle: (0,0)::(1,1).
*/
if (rect->r_xtop < rect->r_xbot || rect->r_ytop < rect->r_ybot)
{
rect->r_xbot = rect->r_xtop = 0;
rect->r_ybot = rect->r_ytop = 0;
return (FALSE);
}
return (TRUE);
}
/*
* --------------------------------------------------------------------
*
* DBBoundPlaneVert --
*
* Determine the bounding rectangle for the supplied tile plane,
* which is organized into maximal vertical strips instead of
* maximal horizontal ones.
*
* The bounding rectangle is the smallest rectangle that completely
* encloses all non-space tiles.
*
* If the tile plane is completely empty, we return a 0x0 bounding
* box at the origin.
*
* Results:
* TRUE if the tile plane contains any geometry, FALSE
* if it is completely empty.
*
* Side effects:
* Sets *rect to the bounding rectangle.
*
* --------------------------------------------------------------------
*/
bool
DBBoundPlaneVert(plane, rect)
Plane *plane;
Rect *rect;
{
Tile *left, *right, *top, *bottom, *tp;
left = plane->pl_left;
right = plane->pl_right;
top = plane->pl_top;
bottom = plane->pl_bottom;
rect->r_ur = TiPlaneRect.r_ll;
rect->r_ll = TiPlaneRect.r_ur;
/*
* To find the topmost and bottommost solid edges, we
* scan along the respective edges. Our assumption is
* that the only tiles along the edges are space tiles,
* which, by the maximum vertical strip property, must
* have either solid tiles or the edge of the plane on
* their other sides.
*/
for (tp = RT(bottom); tp != left; tp = BL(tp))
if (TOP(tp) < rect->r_ybot)
rect->r_ybot = TOP(tp);
for (tp = LB(top); tp != right; tp = TR(tp))
if (BOTTOM(tp) > rect->r_ytop)
rect->r_ytop = BOTTOM(tp);
/*
* We assume that only space tiles extend all the way
* from the top edge of the plane to the bottom. We
* also assume that the leftmost and rightmost tiles
* are space tiles.
*/
rect->r_xtop = LEFT(BL(right));
rect->r_xbot = RIGHT(TR(left));
/*
* If the bounding rectangle is degenerate (indicating no solid
* tiles in the plane), we make it the 1x1 rectangle: (0,0)::(1,1).
*/
if (rect->r_xtop < rect->r_xbot || rect->r_ytop < rect->r_ybot)
{
rect->r_xbot = rect->r_xtop = 0;
rect->r_ybot = rect->r_ytop = 0;
return (FALSE);
}
return (TRUE);
}

706
database/DBcell.c Normal file
View File

@ -0,0 +1,706 @@
/*
* DBcell.c --
*
* Place and Delete subcells
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBcell.c,v 1.2 2008/12/11 04:20:04 tim Exp $";
#endif /* not lint */
#include <sys/types.h>
#include <stdio.h>
#include "utils/magic.h"
#include "utils/malloc.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "utils/undo.h"
#include "utils/signals.h"
int placeCellFunc();
int deleteCellFunc();
Tile * clipCellTile();
void dupTileBody();
void cellTileMerge();
bool ctbListMatch();
void freeCTBList();
struct searchArg
{
CellUse * celluse;
Rect * rect;
Plane * plane;
};
#define TOPLEFT 10
#define TOPLEFTRIGHT 11
#define TOPBOTTOM 12
#define TOPBOTTOMLEFT 14
#define TOPBOTTOMLEFTRIGHT 15
int dbCellDebug = 0;
/*
* ----------------------------------------------------------------------------
*
* DBCellFindDup --
*
* This procedure indicates whether a particular cell is already
* present at a particular point in a particular parent. It is
* used to avoid placing duplicate copies of a cell on top of
* each other.
*
* Results:
* The return value is NULL if there is not already a CellUse in parent
* that is identical to use (same bbox and def). If there is a duplicate
* already in parent, then the return value is a pointer to its CellUse.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
CellUse *
DBCellFindDup(use, parent)
CellUse *use; /* Use that is about to be placed in parent.
* Is it a duplicate?
*/
CellDef *parent; /* Parent definiton: does it already have
* something identical to use?
*/
{
Tile *tile;
CellTileBody *body;
CellUse *checkUse;
tile = TiSrPoint((Tile *) NULL, parent->cd_planes[PL_CELL],
&use->cu_bbox.r_ll);
for (body = (CellTileBody *) TiGetBody(tile);
body != NULL;
body = body->ctb_next)
{
checkUse = body->ctb_use;
if (use->cu_def != checkUse->cu_def) continue;
if ((use->cu_bbox.r_xbot != checkUse->cu_bbox.r_xbot)
|| (use->cu_bbox.r_xtop != checkUse->cu_bbox.r_xtop)
|| (use->cu_bbox.r_ybot != checkUse->cu_bbox.r_ybot)
|| (use->cu_bbox.r_ytop != checkUse->cu_bbox.r_ytop))
continue;
return checkUse;
}
return (CellUse *) NULL;
}
/*
* ----------------------------------------------------------------------------
*
* DBPlaceCell --
*
* Add a CellUse to the subcell tile plane of a CellDef.
* Assumes prior check that the new CellUse is not an exact duplicate
* of one already in place.
*
* Results:
* None.
*
* Side effects:
* Modifies the subcell tile plane of the given CellDef.
* Resets the plowing delta of the CellUse to 0. Sets the
* CellDef's parent pointer to point to the parent def.
*
* ----------------------------------------------------------------------------
*/
void
DBPlaceCell (celluse, targetcell)
CellUse * celluse; /* new celluse to add to subcell tile plane */
CellDef * targetcell; /* parent cell's definition */
{
Rect rect; /* argument to TiSrArea(), placeCellFunc() */
Plane * plane; /* argument to TiSrArea(), placeCellFunc() */
struct searchArg arg; /* argument to placeCellFunc() */
ASSERT(celluse != (CellUse *) NULL, "DBPlaceCell");
celluse->cu_parent = targetcell;
plane = targetcell->cd_planes[PL_CELL]; /* assign plane */
rect = celluse->cu_bbox;
/* rect = celluse->cu_extended; */
arg.rect = &rect;
arg.celluse = celluse;
arg.plane = plane;
/* Be careful not to permit interrupts during this, or the
* database could be left in a trashed state.
*/
SigDisableInterrupts();
(void) TiSrArea((Tile *) NULL, plane, &rect, placeCellFunc,
(ClientData) &arg);
targetcell->cd_flags |= CDMODIFIED|CDGETNEWSTAMP;
if (UndoIsEnabled())
DBUndoCellUse(celluse, UNDO_CELL_PLACE);
SigEnableInterrupts();
}
/*
* ----------------------------------------------------------------------------
* DBDeleteCell --
*
* Remove a CellUse from the subcell tile plane of a CellDef.
*
* Results:
* None.
*
* Side effects:
* Modifies the subcell tile plane of the CellDef, sets the
* parent pointer of the deleted CellUse to NULL.
* ----------------------------------------------------------------------------
*/
void
DBDeleteCell (celluse)
CellUse * celluse;
{
Rect rect; /* argument to TiSrArea(), deleteCellFunc() */
Plane * plane; /* argument to TiSrArea(), deleteCellFunc() */
struct searchArg arg; /* argument to deleteCellFunc() */
ASSERT(celluse != (CellUse *) NULL, "DBDeleteCell");
plane = celluse->cu_parent->cd_planes[PL_CELL]; /* assign plane */
rect = celluse->cu_bbox;
arg.rect = &rect;
arg.plane = plane;
arg.celluse = celluse;
/* It's important that this code run with interrupts disabled,
* or else we could leave the subcell tile plane in a weird
* state.
*/
SigDisableInterrupts();
(void) TiSrArea((Tile *) NULL, plane, &rect, deleteCellFunc,
(ClientData) &arg);
celluse->cu_parent->cd_flags |= CDMODIFIED|CDGETNEWSTAMP;
if (UndoIsEnabled())
DBUndoCellUse(celluse, UNDO_CELL_DELETE);
celluse->cu_parent = (CellDef *) NULL;
SigEnableInterrupts();
}
/*
* ----------------------------------------------------------------------------
* placeCellFunc --
*
* Add a new subcell to a tile.
* Clip the tile with respect to the subcell's bounding box.
* Insert the new CellTileBody into the linked list in ascending order
* based on the celluse pointer.
* This function is passed to TiSrArea.
*
* Results:
* 0 is always returned.
*
* Side effects:
* Modifies the subcell tile plane of the appropriate CellDef.
* Allocates a new CellTileBody.
* ----------------------------------------------------------------------------
*/
int
placeCellFunc (tile, arg)
Tile * tile; /* target tile */
struct searchArg * arg; /* celluse, rect, plane */
{
Tile * tp;
CellTileBody * body, * ctp, * ctplast;
#ifdef CELLDEBUG
if (dbCellDebug) TxPrintf("placeCellFunc called %x\n",tile);
#endif /* CELLDEBUG */
tp = clipCellTile (tile, arg->plane, arg->rect);
body = (CellTileBody *) mallocMagic((unsigned) (sizeof (CellTileBody)));
body->ctb_use = arg->celluse;
ctp = (CellTileBody *) tp->ti_body;
ctplast = ctp;
while ((ctp != (CellTileBody *) NULL) && (ctp->ctb_use > body->ctb_use))
{
ctplast = ctp;
ctp = ctp->ctb_next;
}
body->ctb_next = ctp;
if (ctp == (CellTileBody *) tp->ti_body) /* empty list or front of list */
TiSetBody(tp, body);
else /* after at least one CellTileBody */
ctplast->ctb_next = body;
/* merge tiles back into the the plane */
/* requires that TiSrArea visit tiles in NW to SE wavefront */
if ( RIGHT(tp) == arg->rect->r_xtop)
{
if (BOTTOM(tp) == arg->rect->r_ybot)
cellTileMerge (tp, arg->plane, TOPBOTTOMLEFTRIGHT);
else
cellTileMerge (tp, arg->plane, TOPLEFTRIGHT);
}
else if (BOTTOM(tp) == arg->rect->r_ybot)
cellTileMerge (tp, arg->plane, TOPBOTTOMLEFT);
else
cellTileMerge (tp, arg->plane, TOPLEFT);
return 0;
}
/*
* ----------------------------------------------------------------------------
* deleteCellFunc --
*
* Remove a subcell from a tile.
* This function is passed to TiSrArea.
*
* Results:
* Always returns 0.
*
* Side effects:
* Modifies the subcell tile plane of the appropriate CellDef.
* Deallocates a CellTileBody.
* ----------------------------------------------------------------------------
*/
int
deleteCellFunc (tile, arg)
Tile * tile;
struct searchArg * arg; /* plane, rect */
{
CellTileBody * ctp; /* CellTileBody to be freed */
CellTileBody * ctplast; /* follows one behind ctp */
CellUse * celluse;
#ifdef CELLDEBUG
if (dbCellDebug) TxPrintf("deleteCellFunc called %x\n",tile);
#endif /* CELLDEBUG */
celluse = arg->celluse;
/* find the appropriate CellTileBody in the linked list */
ctp = (CellTileBody *) tile->ti_body;
ctplast = ctp;
while ((ctp != (CellTileBody *) NULL) && (ctp->ctb_use != celluse))
{
ctplast = ctp;
ctp = ctp->ctb_next;
}
/* there should have been a match */
if (ctp == (CellTileBody *) NULL)
{
ASSERT (ctp != (CellTileBody *) NULL, "deleteCellFunc");
return 0;
}
/* relink the list with one CellTileBody deleted */
if (ctp == ctplast) /* front of list */
TiSetBody(tile, ctp->ctb_next);
else /* beyond front of list */
ctplast->ctb_next = ctp->ctb_next;
freeMagic((char *) ctp);
/* merge tiles back into the the plane */
/* requires that TiSrArea visit tiles in NW to SE wavefront */
if ( RIGHT(tile) == arg->rect->r_xtop)
{
if (BOTTOM(tile) == arg->rect->r_ybot)
cellTileMerge (tile, arg->plane, TOPBOTTOMLEFTRIGHT);
else
cellTileMerge (tile, arg->plane, TOPLEFTRIGHT);
}
else if (BOTTOM(tile) == arg->rect->r_ybot)
cellTileMerge (tile, arg->plane, TOPBOTTOMLEFT);
else
cellTileMerge (tile, arg->plane, TOPLEFT);
return (0);
}
/*
* ----------------------------------------------------------------------------
* clipCellTile --
*
* Clip the given tile against the given rectangle.
*
* Results:
* Returns a pointer to the clipped tile.
*
* Side effects:
* Modifies the database plane that contains the given tile.
* ----------------------------------------------------------------------------
*/
Tile *
clipCellTile (tile, plane, rect)
Tile * tile;
Plane * plane;
Rect * rect;
{
Tile * newtile;
if (TOP(tile) > rect->r_ytop)
{
#ifdef CELLDEBUG
if (dbCellDebug) TxPrintf("clipCellTile calls TiSplitY TOP\n");
#endif /* CELLDEBUG */
newtile = TiSplitY (tile, rect->r_ytop); /* no merge */
dupTileBody (tile, newtile);
}
if (BOTTOM(tile) < rect->r_ybot)
{
#ifdef CELLDEBUG
if (dbCellDebug) TxPrintf("clipCellTile calls TiSplitY BOTTOM\n");
#endif /* CELLDEBUG */
newtile = tile;
tile = TiSplitY (tile, rect->r_ybot); /* no merge */
dupTileBody (newtile, tile);
}
if (RIGHT(tile) > rect->r_xtop)
{
#ifdef CELLDEBUG
if (dbCellDebug) TxPrintf("clipCellTile calls TiSplitX RIGHT\n");
#endif /* CELLDEBUG */
newtile = TiSplitX (tile, rect->r_xtop);
dupTileBody (tile, newtile);
cellTileMerge (newtile, plane, TOPBOTTOM);
}
if (LEFT(tile) < rect->r_xbot)
{
#ifdef CELLDEBUG
if (dbCellDebug) TxPrintf("clipCellTile calls TiSplitX LEFT\n");
#endif /* CELLDEBUG */
newtile = tile;
tile = TiSplitX (tile, rect->r_xbot);
dupTileBody (newtile, tile);
cellTileMerge (newtile, plane, TOPBOTTOM);
}
return (tile);
} /* clipCellTile */
/*
* ----------------------------------------------------------------------------
* dupTileBody --
*
* Duplicate the body of an old tile as the body for a new tile.
*
* Results:
* None.
*
* Side effects:
* Allocates new CellTileBodies unless the old tile was a space tile.
* ----------------------------------------------------------------------------
*/
void
dupTileBody (oldtp, newtp)
Tile * oldtp;
Tile * newtp;
{
CellTileBody * oldctb, * newctb, * newctblast;
oldctb = (CellTileBody *) oldtp->ti_body;
if (oldctb != (CellTileBody *) NULL)
{
newctb = (CellTileBody *) mallocMagic((unsigned) (sizeof (CellTileBody)));
TiSetBody(newtp, newctb);
newctb->ctb_use = oldctb->ctb_use;
oldctb = oldctb->ctb_next;
newctblast = newctb;
while (oldctb != (CellTileBody *) NULL)
{
newctb = (CellTileBody *) mallocMagic((unsigned) (sizeof (CellTileBody)));
newctblast->ctb_next = newctb;
newctb->ctb_use = oldctb->ctb_use;
oldctb = oldctb->ctb_next;
newctblast = newctb;
}
newctblast->ctb_next = (CellTileBody *) NULL;
}
else TiSetBody(newtp, NULL);
} /* dupTileBody */
/*
* ----------------------------------------------------------------------------
* cellTileMerge --
*
* Merge the given tile with its plane in the directions specified.
*
* Results:
* None.
*
* Side effects:
* Modifies the database plane that contains the given tile.
* ----------------------------------------------------------------------------
*/
void
cellTileMerge (tile, plane, direction)
Tile * tile;
Plane * plane;
int direction; /* TOP = 8, BOTTOM = 4, LEFT = 2, RIGHT = 1 */
{
Point topleft, bottomright;
Tile * dummy, * tpleft, * tpright, * tp1, * tp2;
#ifdef CELLDEBUG
if (dbCellDebug) TxPrintf("cellTileMerge %x\n",tile);
#endif /* CELLDEBUG */
topleft.p_x = LEFT(tile);
topleft.p_y = TOP(tile);
bottomright.p_x = RIGHT(tile);
bottomright.p_y = BOTTOM(tile);
if ((direction >> 1) % 2) /* LEFT */
{
tpright = tile;
tpleft = BL(tpright);
#ifdef CELLDEBUG
if (dbCellDebug) TxPrintf("LEFT %x %x\n",tpleft,tpright);
#endif /* CELLDEBUG */
while (BOTTOM(tpleft) < topleft.p_y) /* go up left edge */
{
if (ctbListMatch (tpleft, tpright))
{
if (BOTTOM(tpleft) < BOTTOM(tpright))
{
dummy = tpleft;
tpleft = TiSplitY (tpleft, BOTTOM (tpright));
dupTileBody (dummy, tpleft);
}
else if (BOTTOM(tpleft) > BOTTOM(tpright))
{
dummy = tpright;
tpright = TiSplitY (tpright, BOTTOM (tpleft));
dupTileBody (dummy, tpright);
}
if (TOP(tpleft) > TOP(tpright))
{
dummy = TiSplitY (tpleft, TOP(tpright));
dupTileBody (tpleft, dummy);
}
else if (TOP(tpright) > TOP(tpleft))
{
dummy = TiSplitY (tpright, TOP(tpleft));
dupTileBody (tpright, dummy);
}
freeCTBList (tpright);
TiJoinX (tpleft, tpright, plane); /* tpright disappears */
tpright = RT(tpleft);
if (BOTTOM(tpright) < topleft.p_y) tpleft = BL(tpright);
else tpleft = tpright; /* we're off the top of the tile */
/* this will break the while loop */
} /* if (ctbListMatch (tpleft, tpright)) */
else tpleft = RT(tpleft);
} /* while */
tile = tpleft; /* for TiSrPoint in next IF statement */
}
if (direction % 2) /* RIGHT */
{
tpright = TiSrPoint (tile, plane, &bottomright);
--(bottomright.p_x);
tpleft = TiSrPoint (tpright, plane, &bottomright);
++(bottomright.p_x);
#ifdef CELLDEBUG
if (dbCellDebug) TxPrintf("RIGHT %x %x\n",tpleft,tpright);
#endif /* CELLDEBUG */
while (BOTTOM(tpright) < topleft.p_y) /* go up right edge */
{
if (ctbListMatch (tpleft, tpright))
{
if (BOTTOM(tpright) < BOTTOM(tpleft))
{
dummy = tpright;
tpright = TiSplitY (tpright, BOTTOM(tpleft));
dupTileBody (dummy, tpright);
}
else if (BOTTOM(tpleft) < BOTTOM(tpright))
{
dummy = tpleft;
tpleft = TiSplitY (tpleft, BOTTOM(tpright));
dupTileBody (dummy, tpleft);
}
if (TOP(tpright) > TOP(tpleft))
{
dummy = TiSplitY (tpright, TOP(tpleft));
dupTileBody (tpright, dummy);
}
else if (TOP(tpleft) > TOP(tpright))
{
dummy = TiSplitY (tpleft, TOP(tpright));
dupTileBody (tpleft, dummy);
}
freeCTBList (tpright);
TiJoinX (tpleft, tpright, plane); /* tpright disappears */
tpright = RT(tpleft);
while (LEFT(tpright) > bottomright.p_x) tpright = BL(tpright);
/* tpleft can be garbage if we're off the top of the loop, */
/* but it doesn't matter since the expression tests tpright */
tpleft = BL(tpright);
} /* if (ctbListMatch (tpleft, tpright)) */
else
{
tpright = RT(tpright);
while (LEFT(tpright) > bottomright.p_x) tpright = BL(tpright);
tpleft = BL(tpright); /* left side merges may have */
/* created more tiles */
}
} /* while */
tile = tpright; /* for TiSrPoint in next IF statement */
}
if ((direction >> 3) % 2) /* TOP */
{
tp1 = TiSrPoint (tile, plane, &topleft); /* merge across top */
--(topleft.p_y);
tp2 = TiSrPoint (tile, plane, &topleft);/* top slice of original tile */
++(topleft.p_y);
#ifdef CELLDEBUG
if (dbCellDebug) TxPrintf("TOP %x %x\n",tp1,tp2);
#endif /* CELLDEBUG */
if ((LEFT(tp1) == LEFT(tp2) ) &&
(RIGHT(tp1) == RIGHT(tp2)) &&
(ctbListMatch (tp1, tp2) ))
{
freeCTBList (tp2);
TiJoinY (tp1, tp2, plane);
}
tile = tp1; /* for TiSrPoint in next IF statement */
}
if ((direction >> 2) % 2) /* BOTTOM */
{
--(bottomright.p_x);
/* bottom slice of orig tile */
tp1 = TiSrPoint (tile, plane, &bottomright);
--(bottomright.p_y);
tp2 = TiSrPoint (tile, plane, &bottomright); /* merge across bottom */
#ifdef CELLDEBUG
if (dbCellDebug) TxPrintf("BOTTOM %x %x\n",tp1,tp2);
#endif /* CELLDEBUG */
if ((LEFT(tp1) == LEFT(tp2) ) &&
(RIGHT(tp1) == RIGHT(tp2)) &&
(ctbListMatch (tp1, tp2) ))
{
freeCTBList (tp2);
TiJoinY (tp1, tp2, plane);
}
}
}
/*
* ----------------------------------------------------------------------------
* freeCTBList --
*
* Free all CellTileBodies attached to the give tile.
*
* Results:
* None.
*
* Side effects:
* Frees CellTileBodies.
* ----------------------------------------------------------------------------
*/
void
freeCTBList (tile)
Tile * tile;
{
CellTileBody * ctp, * ctplast;
ctp = (CellTileBody *) tile->ti_body;
while (ctp != (CellTileBody *) NULL)
{
ctplast = ctp;
ctp = ctp->ctb_next;
freeMagic((char *) ctplast);
}
TiSetBody(tile, NULL);
}
/*
* ----------------------------------------------------------------------------
* ctbListMatch --
*
* Compare two linked lists of CellTileBodies, assuming that they are
* sorted in ascending order by celluse pointers.
*
* Results:
* True if the tiles have identical lists of CellTileBodies.
*
* Side effects:
* None.
* ----------------------------------------------------------------------------
*/
bool
ctbListMatch (tp1, tp2)
Tile * tp1, * tp2;
{
CellTileBody * ctp1, * ctp2;
ctp1 = (CellTileBody *) tp1->ti_body;
ctp2 = (CellTileBody *) tp2->ti_body;
while (ctp1 && ctp2 && (ctp1->ctb_use == ctp2->ctb_use))
ctp1 = ctp1->ctb_next, ctp2 = ctp2->ctb_next;
return ((ctp1 == (CellTileBody *) NULL) && (ctp2 == (CellTileBody *) NULL));
}

852
database/DBcellbox.c Normal file
View File

@ -0,0 +1,852 @@
/*
* DBcellbox.c --
*
* Procedures for calculating and changing cell bounding boxes,
* and for manipulating arrays of cells.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBcellbox.c,v 1.3 2008/12/11 18:36:43 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/geofast.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "utils/undo.h"
/*
*-----------------------------------------------------------------------------
*
* DBPrintUseId --
*
* Generate the print name of the use identifier indicated by the supplied
* SearchContext.
*
* Results:
* Returns a pointer to the NULL byte at the end of the string
* generated.
*
* Side effects:
* The character string pointed to by name is set to contain the use
* id of scx->scx_use followed by any array indices. If scx->scx_use
* is a two dimensional array, the array indices are of the form [y,x],
* otherwise there is a single array index either of the form [y] or [x].
* The array indices are taken from scx->scx_x and scx->scx_y. At most
* size characters are copied into the string pointed to by name.
*
*-----------------------------------------------------------------------------
*/
char *
DBPrintUseId(scx, name, size, display_only)
SearchContext *scx; /* Pointer to current search context, specifying a
* cell use and X,Y array indices.
*/
char *name; /* Pointer to string into which we will copy the
* print name of this instance.
*/
int size; /* Maximum number of characters to copy into string. */
bool display_only; /* TRUE if called for displaying only */
{
CellUse *use = scx->scx_use;
char *sp, *id, *ep;
char indices[100];
if ((id = use->cu_id) == (char *) NULL)
{
name[0] = '\0';
return (name);
}
sp = name;
if (display_only && (use->cu_flags & CU_LOCKED))
*sp++ = CULOCKCHAR;
for (ep = &name[size]; (sp < ep) && *id; *sp++ = *id++)
/* Nothing */;
if (use->cu_xlo != use->cu_xhi || use->cu_ylo != use->cu_yhi)
{
if (use->cu_xlo == use->cu_xhi)
(void) sprintf(indices, "[%d]", scx->scx_y);
else if (use->cu_ylo == use->cu_yhi)
(void) sprintf(indices, "[%d]", scx->scx_x);
else
(void) sprintf(indices, "[%d,%d]", scx->scx_y, scx->scx_x);
for (id = indices; (sp < ep) && *id; *sp++ = *id++)
/* Nothing */;
}
if (sp == ep)
sp--;
*sp = '\0';
return (sp);
}
/*
* ----------------------------------------------------------------------------
*
* DBCellSetAvail --
* DBCellClearAvail --
*
* Mark a cell as available/unavailable.
* These exist mainly to create a cell for the first time, and to
* allow a cell to be 'flushed' via the "flush" command.
*
* Results:
* None.
*
* Side effects:
* Modifies flags in cellDef.
*
* ----------------------------------------------------------------------------
*/
void
DBCellSetAvail(cellDef)
CellDef *cellDef; /* Pointer to definition of cell we wish to
* mark as available.
*/
{
cellDef->cd_flags &= ~CDNOTFOUND;
cellDef->cd_flags |= CDAVAILABLE;
}
void
DBCellClearAvail(cellDef)
CellDef *cellDef; /* Pointer to definition of cell we wish to
* mark as available.
*/
{
cellDef->cd_flags &= ~(CDNOTFOUND|CDAVAILABLE);
}
/*
* ----------------------------------------------------------------------------
*
* DBCellGetModified --
* DBCellSetModified --
*
* Get/set the CDMODIFIED status of a cell.
* DBCellGetModified returns TRUE if the cell has been modified, FALSE
* if not. DBCellSetModified marks the cell as having been modified
* if its argument is TRUE, and marks it as having been unmodified if
* its argument is FALSE.
*
* Results:
* DBCellGetModified: TRUE or FALSE.
* DBCellSetModified: None.
*
* Side effects:
* DBCellGetModified: None.
* DBCellSetModified: modifies cellDef->cd_flags.
*
* ----------------------------------------------------------------------------
*/
bool
DBCellGetModified(cellDef)
CellDef *cellDef; /* Pointer to definition of cell */
{
return ((cellDef->cd_flags & CDMODIFIED) != 0);
}
void
DBCellSetModified(cellDef, ismod)
CellDef *cellDef;
bool ismod; /* If TRUE, mark the cell as modified; if FALSE,
* mark it as unmodified.
*/
{
cellDef->cd_flags &= ~CDMODIFIED|CDGETNEWSTAMP;
if (ismod)
cellDef->cd_flags |= CDMODIFIED|CDGETNEWSTAMP;
}
/*
* ----------------------------------------------------------------------------
*
* DBComputeUseBbox --
*
* Compute the bounding box for a CellUse in coordinates of its parent.
*
* Results:
* None.
*
* Side effects:
* Sets cellUse->cu_bbox to be the bounding box for the indicated CellUse
* in coordinates of that CellUse's parent, and cellUse->cu_extended
* to the bounding box of the cell use including all rendered text labels.
*
* ----------------------------------------------------------------------------
*/
void
DBComputeUseBbox(use)
CellUse *use;
{
Rect *box, *extended;
Rect childRect, childExtend;
int xdelta, ydelta;
xdelta = use->cu_xsep * (use->cu_xhi - use->cu_xlo);
ydelta = use->cu_ysep * (use->cu_yhi - use->cu_ylo);
if (xdelta < 0) xdelta = (-xdelta);
if (ydelta < 0) ydelta = (-ydelta);
box = &(use->cu_def->cd_bbox);
extended = &(use->cu_def->cd_extended);
if (use->cu_xsep < 0)
{
childRect.r_xbot = box->r_xbot - xdelta;
childRect.r_xtop = box->r_xtop;
childExtend.r_xbot = extended->r_xbot - xdelta;
childExtend.r_xtop = extended->r_xtop;
}
else
{
childRect.r_xbot = box->r_xbot;
childRect.r_xtop = box->r_xtop + xdelta;
childExtend.r_xbot = extended->r_xbot;
childExtend.r_xtop = extended->r_xtop + xdelta;
}
if (use->cu_ysep < 0)
{
childRect.r_ybot = box->r_ybot - ydelta;
childRect.r_ytop = box->r_ytop;
childExtend.r_ybot = extended->r_ybot - ydelta;
childExtend.r_ytop = extended->r_ytop;
}
else
{
childRect.r_ybot = box->r_ybot;
childRect.r_ytop = box->r_ytop + ydelta;
childExtend.r_ybot = extended->r_ybot;
childExtend.r_ytop = extended->r_ytop + ydelta;
}
GeoTransRect(&use->cu_transform, &childRect, &use->cu_bbox);
GeoTransRect(&use->cu_transform, &childExtend, &use->cu_extended);
}
/*
* ----------------------------------------------------------------------------
*
* DBIsChild --
*
* Test to see if cu1 is a child of cu2.
*
* Results:
* TRUE if cu1 is a child of cu2, FALSE otherwise.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
bool
DBIsChild(cu1, cu2)
CellUse *cu1, *cu2;
{
return (cu1->cu_parent == cu2->cu_def);
}
/*
* ----------------------------------------------------------------------------
*
* DBSetArray --
*
* Copy the array information from fromCellUse to toCellUse
*
* Results:
* None.
*
* Side Effects:
* The array information if toCellUse is modified.
*
* ----------------------------------------------------------------------------
*/
void
DBSetArray(fromCellUse, toCellUse)
CellUse *fromCellUse;
CellUse *toCellUse;
{
toCellUse->cu_xlo = fromCellUse->cu_xlo;
toCellUse->cu_ylo = fromCellUse->cu_ylo;
toCellUse->cu_xhi = fromCellUse->cu_xhi;
toCellUse->cu_yhi = fromCellUse->cu_yhi;
toCellUse->cu_xsep = fromCellUse->cu_xsep;
toCellUse->cu_ysep = fromCellUse->cu_ysep;
}
/*
* ----------------------------------------------------------------------------
*
* DBSetTrans --
*
* Change the transform for cellUse to that supplied.
*
* Results:
* None.
*
* Side Effects:
* Updates cellUse->cu_trans and cellUse->cu_bbox
*
* ----------------------------------------------------------------------------
*/
void
DBSetTrans(cellUse, trans)
CellUse *cellUse;
Transform *trans;
{
cellUse->cu_transform = *trans;
DBComputeUseBbox(cellUse);
}
/*
* ----------------------------------------------------------------------------
*
* DBMakeArray --
*
* Turn cellUse into an array whose X indices run from xlo through xhi
* and whose Y indices run from ylo through yhi. The separation between
* adjacent array elements is xsep in the X direction, and ysep in the
* Y direction.
*
* The X and Y information is in coordinates of the root cell def.
* It gets transformed down to the def of cellUse according to the
* transform supplied. What we do guarantee is that the array
* indices will appear, in root coordinates, to run from xlo to xhi
* left-to-right, and from ylo to yhi bottom-to-top.
*
* Results:
* None.
*
* Side Effects:
* The array information if toCellUse is modified.
*
* ----------------------------------------------------------------------------
*/
void
DBMakeArray(cellUse, rootToCell, xlo, ylo, xhi, yhi, xsep, ysep)
CellUse *cellUse;
Transform *rootToCell;
int xlo, ylo;
int xhi, yhi;
int xsep, ysep;
{
int t;
cellUse->cu_xsep = rootToCell->t_a * xsep + rootToCell->t_b * ysep;
cellUse->cu_ysep = rootToCell->t_d * xsep + rootToCell->t_e * ysep;
/*
* Now transform the indices.
* We should preserve the property that indices in root coordinates
* should appear to run from xlo through xhi, left-to-right, and
* from ylo through yhi, bottom-to-top.
*/
if (rootToCell->t_a == 0)
{
t = xlo; xlo = ylo; ylo = t;
t = xhi; xhi = yhi; yhi = t;
}
cellUse->cu_xlo = xlo;
cellUse->cu_ylo = ylo;
cellUse->cu_xhi = xhi;
cellUse->cu_yhi = yhi;
DBComputeUseBbox(cellUse);
}
/*
* ----------------------------------------------------------------------------
*
* DBArrayOverlap --
*
* Determine which elements of an array overlap the supplied clipping
* rectangle. Assumes that the clipping rectangle overlaps at least
* some part of the array area.
*
* Results:
* None.
*
* WARNING:
* This code is very sensitive to being changed. Make sure you
* understand it before you change it.
*
* Side Effects:
* Sets *pxlo, *pxhi, *pylo, *pyhi to be the inclusive range of array
* indices which overlay the given clipping rectangle.
*
* If there is any overlap in X, *pxlo <= *pxhi; similarly, if there
* is any overlap in Y, *pylo <= *pyhi.
*
* ----------------------------------------------------------------------------
*/
void
DBArrayOverlap(cu, parentRect, pxlo, pxhi, pylo, pyhi)
CellUse *cu; /* Pointer to cell use which may be an array */
Rect *parentRect; /* Clipping rectangle cu->cu_parent coords */
int *pxlo, *pxhi;
int *pylo, *pyhi;
{
int outxlo, outxhi, outylo, outyhi, t;
int xlo, ylo, xhi, yhi, xsep, ysep;
Transform parentToCell;
Rect box, childR;
/* For a non-arrayed element, return the indices of the only element */
if (cu->cu_xlo == cu->cu_xhi && cu->cu_ylo == cu->cu_yhi)
{
*pxlo = *pxhi = cu->cu_xlo;
*pylo = *pyhi = cu->cu_ylo;
return;
}
box = cu->cu_def->cd_bbox;
GEOINVERTTRANS(&cu->cu_transform, &parentToCell);
GEOTRANSRECT(&parentToCell, parentRect, &childR);
xsep = cu->cu_xsep;
ysep = cu->cu_ysep;
/*
* Canonicalize the array indices so that the base element
* of the array has the minimum x and y coordinate, ie,
* so that xlo <= xhi and ylo <= yhi.
*/
if (cu->cu_xlo > cu->cu_xhi) xlo = cu->cu_xhi, xhi = cu->cu_xlo;
else xlo = cu->cu_xlo, xhi = cu->cu_xhi;
if (cu->cu_ylo > cu->cu_yhi) ylo = cu->cu_yhi, yhi = cu->cu_ylo;
else ylo = cu->cu_ylo, yhi = cu->cu_yhi;
/*
* If the separation along one of the coordinate axes is negative,
* flip everything about that axis.
*/
if (xsep < 0)
{
xsep = (-xsep);
t = childR.r_xbot; childR.r_xbot = -childR.r_xtop; childR.r_xtop = -t;
t = box.r_xbot; box.r_xbot = -box.r_xtop; box.r_xtop = -t;
}
if (ysep < 0)
{
ysep = (-ysep);
t = childR.r_ybot; childR.r_ybot = -childR.r_ytop; childR.r_ytop = -t;
t = box.r_ybot; box.r_ybot = -box.r_ytop; box.r_ytop = -t;
}
/*
* The following inequalities are used to derive the equations
* computed below. "Blo" is the lower coordinate of the incident
* box, and "Bhi" is the upper coordinate.
*
* min outlo : (outlo - lo) * sep + top >= Blo
* max outhi : (outhi - lo) * sep + bot <= Bhi
*
* The intent is that "outlo" will be the smaller of the two
* coordinates, and "outhi" the larger.
*/
/* Even though it should never happen, handle zero spacings
* gracefully.
*/
if (xsep != 0)
{
outxlo = xlo + (childR.r_xbot - box.r_xtop + xsep - 1) / xsep;
outxhi = xlo + (childR.r_xtop - box.r_xbot) / xsep;
}
else
{
outxlo = xlo;
outxhi = xhi;
}
if (ysep != 0)
{
outylo = ylo + (childR.r_ybot - box.r_ytop + ysep - 1) / ysep;
outyhi = ylo + (childR.r_ytop - box.r_ybot) / ysep;
}
else
{
outylo = ylo;
outyhi = yhi;
}
/*
* Clip against the canonicalized array indices.
* Note that this may result in rxlo > rxhi or rylo > ryhi, in which
* case the rectangle doesn't intersect the array at all.
*/
if (outxlo < xlo) outxlo = xlo;
if (outxhi > xhi) outxhi = xhi;
if (outylo < ylo) outylo = ylo;
if (outyhi > yhi) outyhi = yhi;
/*
* Convert canonicalized array indices back into actual
* array indices for output.
*/
if (cu->cu_xlo > cu->cu_xhi)
{
*pxhi = cu->cu_xhi + cu->cu_xlo - outxlo;
*pxlo = cu->cu_xhi + cu->cu_xlo - outxhi;
}
else
{
*pxlo = outxlo;
*pxhi = outxhi;
}
if (cu->cu_ylo > cu->cu_yhi)
{
*pyhi = cu->cu_yhi + cu->cu_ylo - outylo;
*pylo = cu->cu_yhi + cu->cu_ylo - outyhi;
}
else
{
*pylo = outylo;
*pyhi = outyhi;
}
}
/*
* ----------------------------------------------------------------------------
*
* DBReComputeBbox --
* DBReComputeBboxVert --
*
* Propagate changes to bounding boxes.
* The former is the default procedure; the latter should be used
* when the tile planes of a cell are organized into maximal vertical
* strips instead of maximal horizontal.
*
* Results:
* None.
*
* Side Effects:
* These procedures re-examine cellDef to see if its bounding box
* has gotten larger or smaller. If so, the bounding box is
* modified, and the change is reflected upwards in the
* hierarchy to parents of cellDef. This occurs recursively
* until the top of the hierarchy is reached.
*
* Also modifies the CellUse bounding boxes of parents as
* appropriate (cu_bbox).
*
* WARNING
*
* In order to preserve consistency, if it is discovered that a
* cell contains no material of any kind, its bounding box is
* set to a default of (0,0) :: (1,1). If the cell contains
* labels but still has a zero-size bounding box, then the bounding
* box is enlarged by one unit to give it non-zero area.
*
* ----------------------------------------------------------------------------
*/
void dbReComputeBboxFunc();
void
DBReComputeBbox(cellDef)
CellDef *cellDef; /* Cell def whose bounding box may have changed */
{
extern bool DBBoundPlane();
dbReComputeBboxFunc(cellDef, DBBoundPlane, DBReComputeBbox);
}
void
DBReComputeBboxVert(cellDef)
CellDef *cellDef; /* Cell def whose bounding box may have changed */
{
extern bool DBBoundPlaneVert();
dbReComputeBboxFunc(cellDef, DBBoundPlaneVert, DBReComputeBboxVert);
}
void
dbReComputeBboxFunc(cellDef, boundProc, recurseProc)
CellDef *cellDef; /* Cell def whose bounding box may have changed */
bool (*boundProc)();
void (*recurseProc)();
{
bool degenerate;
Rect rect, area, extended, *box;
Rect redisplayArea;
CellUse *use;
CellDef *parent;
Label *label;
bool foundAny;
int pNum;
/* Cells which declare their bounding box to be fixed */
/* must return immediately. */
if (cellDef->cd_flags & CDFIXEDBBOX) return;
/*
* Include area of subcells separately
*/
if ((foundAny = DBBoundCellPlane(cellDef, TRUE, &rect)) > 0)
area = rect;
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
if (pNum != PL_DRC_CHECK)
if ((*boundProc)(cellDef->cd_planes[pNum], &rect))
{
if (foundAny)
(void) GeoInclude(&rect, &area);
else
area = rect;
foundAny = TRUE;
}
/*
* Include the area of labels, too.
*/
for (label = cellDef->cd_labels; label != NULL; label = label->lab_next)
{
if (foundAny)
{
if (label->lab_rect.r_xbot < area.r_xbot)
area.r_xbot = label->lab_rect.r_xbot;
if (label->lab_rect.r_ybot < area.r_ybot)
area.r_ybot = label->lab_rect.r_ybot;
if (label->lab_rect.r_xtop > area.r_xtop)
area.r_xtop = label->lab_rect.r_xtop;
if (label->lab_rect.r_ytop > area.r_ytop)
area.r_ytop = label->lab_rect.r_ytop;
}
else
{
area = label->lab_rect;
foundAny = TRUE;
}
}
extended = area;
if (foundAny)
{
for (label = cellDef->cd_labels; label != NULL; label = label->lab_next)
if (label->lab_font >= 0)
GeoInclude(&label->lab_bbox, &extended);
}
/*
* If there is nothing at all, produce a 1x1 box with its
* lower left corner at the origin.
*/
if (!foundAny)
{
degenerate = TRUE;
area.r_xbot = area.r_ybot = 0;
area.r_xtop = area.r_ytop = 1;
}
else degenerate = FALSE;
/*
* Canonicalize degeneracy in all other directions by
* expanding the box by one unit in the degenerate
* direction.
*/
if (area.r_xbot == area.r_xtop)
area.r_xtop = area.r_xbot + 1;
if (area.r_ybot == area.r_ytop)
area.r_ytop = area.r_ybot + 1;
if (degenerate) extended = area;
/* Did the bounding box change? If not then there's no need to
* recompute the parents. If the cell has no material, then
* we must always propagate upwards. This is because DBClearCellDef
* sets the bounding box to the degenerate size WITHOUT propagating
* (it isn't safe for DBClearCellDef to propagate). At this point
* the propagation must be done.
*/
box = &cellDef->cd_extended;
if ((area.r_xbot == box->r_xbot && area.r_ybot == box->r_ybot
&& area.r_xtop == box->r_xtop && area.r_ytop == box->r_ytop)
&& !degenerate)
return;
/*
* Alas, the cell's bounding box has actually changed. Thus
* we must recompute the areas of all the parents of this
* cell recursively. We must rip up the child cell and place
* it down again to insure that the subcell tile planes in the
* parents are all correct.
*
* The undo package is disabled around this since it will already
* insure that DBReComputeBbox will be called at the appropriate
* times.
*/
UndoDisable();
for (use = cellDef->cd_parents; use != NULL; use = use->cu_nextuse)
if (use->cu_parent != (CellDef *) NULL)
{
/* DBDeleteCell trashes the parent pointer, but we restore
* it so we'll know where to put the cell back later.
*/
parent = use->cu_parent;
DBDeleteCell(use);
use->cu_parent = parent;
}
cellDef->cd_bbox = area;
cellDef->cd_extended = extended;
/*
* Relink each of the uses into the subcell tile planes
* of their respective parents. Also, redisplay the use
* in each parent, in each window where the cell isn't
* expanded (i.e. the bounding box is no longer correct).
*/
for (use = cellDef->cd_parents; use != NULL; use = use->cu_nextuse)
{
redisplayArea = use->cu_extended;
DBComputeUseBbox(use);
if ((parent = use->cu_parent) != (CellDef *) NULL)
{
parent->cd_flags |= CDBOXESCHANGED;
DBPlaceCell(use, parent);
(*recurseProc)(parent);
(void) GeoInclude(&use->cu_extended, &redisplayArea);
DBWAreaChanged(parent, &redisplayArea, (int) ~use->cu_expandMask,
&DBAllButSpaceBits);
}
}
UndoEnable();
}
/*
* ----------------------------------------------------------------------------
*
* DBComputeArrayArea --
*
* Given an area in native coordinates of a celldef, computes the
* corresponding area in a parent's coordinates, for a particular
* celluse and a particular element of an array.
*
* Results:
* None.
*
* Side Effects:
* Sets *prect to the given area in the given array instance,
* subject to the arraying and transformation inforamtion in
* the given cellUse.
*
* ----------------------------------------------------------------------------
*/
void
DBComputeArrayArea(area, cellUse, x, y, prect)
Rect *area; /* Area to be transformed. */
CellUse *cellUse; /* Cell use whose bounding box is to be computed */
int x, y; /* Indexes of array element whose box is being found */
Rect *prect; /* Pointer to rectangle to be set to bounding
* box of the given array element, in coordinates
* of the def of cellUse.
*/
{
int xdelta, ydelta;
if (cellUse->cu_xlo > cellUse->cu_xhi) x = cellUse->cu_xlo - x;
else x = x - cellUse->cu_xlo;
if (cellUse->cu_ylo > cellUse->cu_yhi) y = cellUse->cu_ylo - y;
else y = y - cellUse->cu_ylo;
xdelta = cellUse->cu_xsep * x;
ydelta = cellUse->cu_ysep * y;
prect->r_xbot = area->r_xbot + xdelta;
prect->r_xtop = area->r_xtop + xdelta;
prect->r_ybot = area->r_ybot + ydelta;
prect->r_ytop = area->r_ytop + ydelta;
}
/*
* ----------------------------------------------------------------------------
*
* DBGetArrayTransform --
*
* This procedure computes the transform from a particular element
* of an array to the coordinates of the array as a whole.
*
* Results:
* The return result is a pointer to a transform describing how
* coordinates of use->cu_def must be transformed in order to
* appear in the (x,y) element location. In other words, if the
* transform for the whole array (use->cu_transform) were
* GeoIdentityTransform, this is the transform from use->cu_def
* to the parent use for the (x,y) element. By the way, the
* return result is a locally-allocated transform that goes away
* the next time this procedure is called, so use it carefully.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
Transform *
DBGetArrayTransform(use, x, y)
CellUse *use;
int x, y; /* Array indices of the desired element.
* These must fall within the range of
* use's array indices.
*/
{
static Transform result;
int xsep, ysep, xbase, ybase;
if (use->cu_xlo > use->cu_xhi) xsep = -use->cu_xsep;
else xsep = use->cu_xsep;
if (use->cu_ylo > use->cu_yhi) ysep = -use->cu_ysep;
else ysep = use->cu_ysep;
xbase = xsep * (x - use->cu_xlo);
ybase = ysep * (y - use->cu_ylo);
GeoTransTranslate(xbase, ybase, &GeoIdentityTransform, &result);
return &result;
}

1023
database/DBcellcopy.c Normal file

File diff suppressed because it is too large Load Diff

2093
database/DBcellname.c Normal file

File diff suppressed because it is too large Load Diff

343
database/DBcellsel.c Normal file
View File

@ -0,0 +1,343 @@
/*
* DBcellsel.c --
*
* Cell selection.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBcellsel.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "utils/utils.h"
struct selectArg
{
int csa_xmask; /* Only the contents of uses whose
* expand masks match csa_xmask are
* visible.
*/
CellUse *csa_lastuse; /* Last cell selected */
Point csa_lastp; /* X, Y indices of csa_lastuse */
bool csa_sawlast; /* TRUE if csa_lastuse has been visited
* in this pass.
*/
CellUse *csa_retuse; /* Cell we will return as selected */
CellUse *csa_bestuse; /* Best candidate seen in this pass */
Point *csa_bestp; /* X, Y indices of csa_bestuse */
Transform *csa_besttrans; /* Points to a Transform that will be
* set to the transform from the parent
* of csa_bestuse to the root use.
*/
TerminalPath *csa_bestpath; /* Pathname of best candidate found */
TerminalPath csa_curpath; /* Current candidate's pathname */
};
/* Forward declarations */
int dbSelectCellSr();
/*
* ----------------------------------------------------------------------------
*
* DBSelectCell --
*
* Select the next cell containing a given point.
*
* Results:
* Returns a pointer to the next CellUse containing the given
* point, or NULL if we have visited all CellUses containing it.
* The ordering of CellUses visited is smallest in area to largest.
* Both expanded cells, and unexpanded cells all of whose parents
* are expanded, are returned.
*
* Side effects:
* Sets *transform to be the transform from coordinates of
* the CellUse's definition to those of the root cell use.
* Sets *selp to be the x and y array indices of the selected cell.
* Returns path in the argument "tpath".
*
* ----------------------------------------------------------------------------
*/
CellUse *
DBSelectCell(rootUse, lastUse, lastP, rootRect, xMask, transform, selp, tpath)
CellUse *rootUse; /* Root cell use for the search (usually
* that of the window containing the point
* tool). The pathname we construct into
* tpath will be relative to this use.
*/
CellUse *lastUse; /* Pointer to last CellUse returned by
* DBSelectCell(). This is only used when
* stepping through multiple overlapping
* cells.
*/
Point *lastP; /* X, Y array indices of last cell selected */
Rect *rootRect; /* Box around point tool in coordinates of
* the parent def of rootUse.
*/
int xMask; /* Expand bit mask for determining whether
* a cell is expanded or not.
*/
Transform *transform; /* Transform set by DBSelectCell, from
* coordinates of the returned CellUse's
* definition to those of the rootUse's
* def.
*/
Point *selp; /* X, Y array indices of the selected cell,
* also set by DBSelectCell.
*/
TerminalPath *tpath; /* Set to contain the use id of selected cell */
{
int xlo, xhi, ylo, yhi, xbase, ybase, xsep, ysep;
char currentId[BUFSIZ];
SearchContext scontext;
struct selectArg arg;
arg.csa_curpath.tp_first = arg.csa_curpath.tp_next = currentId;
arg.csa_curpath.tp_last = &currentId[sizeof currentId - 2];
currentId[0] = '\0';
arg.csa_xmask = xMask;
arg.csa_lastp = *lastP;
arg.csa_sawlast = FALSE;
arg.csa_retuse = (CellUse *) NULL;
arg.csa_lastuse = (CellUse *) NULL;
/*
* Sanity check in case lastUse has somehow been freed
* prior to our being called.
*/
if (lastUse && lastUse->cu_def)
arg.csa_lastuse = lastUse;
arg.csa_besttrans = transform;
arg.csa_bestp = selp;
arg.csa_bestuse = (CellUse *) NULL;
arg.csa_bestpath = tpath;
DBArrayOverlap(rootUse, rootRect, &xlo, &xhi, &ylo, &yhi);
scontext.scx_use = rootUse;
scontext.scx_area = *rootRect;
xsep = (rootUse->cu_xlo>rootUse->cu_xhi)?-rootUse->cu_xsep:rootUse->cu_xsep;
ysep = (rootUse->cu_ylo>rootUse->cu_yhi)?-rootUse->cu_ysep:rootUse->cu_ysep;
for (scontext.scx_y = ylo; scontext.scx_y <= yhi; scontext.scx_y++)
{
for (scontext.scx_x = xlo; scontext.scx_x <= xhi; scontext.scx_x++)
{
xbase = xsep * (scontext.scx_x - rootUse->cu_xlo);
ybase = ysep * (scontext.scx_y - rootUse->cu_ylo);
GeoTransTranslate(xbase, ybase, &GeoIdentityTransform,
&scontext.scx_trans);
(void) dbSelectCellSr(&scontext, &arg);
if (arg.csa_retuse != (CellUse *) NULL)
break;
}
}
return (arg.csa_bestuse);
}
/*
* Sets arg->csa_retuse if we've found the next use. This enables us
* to short-circuit the remainder of the tree search (it has now been
* changed to abort the search).
*
* Sets arg->csa_bestuse to point to the best candidate yet found
* for being the next CellUse. Sets arg->csa_sawlast to TRUE once
* arg->csa_lastuse has been seen.
*/
int
dbSelectCellSr(scx, arg)
SearchContext *scx; /* Context describing the cell use, the
* x and y array element under consider-
* ation, the area surrounding the
* selection point in coordinates of
* the def of the cell use, and a
* transform back to the "root".
*/
struct selectArg *arg; /* Client data */
{
/* BY NP */
dlong childArea, bestArea, lastArea;
TerminalPath *cpath = &arg->csa_curpath;
char *savenext;
Rect *pbx;
int n;
/*
* If we have already found the (use, element) to be returned,
* prune the search short.
*/
if (arg->csa_retuse != (CellUse *) NULL)
return 1;
/*
* If this was the (use, element) last returned by DBSelectCell,
* we can prune the search not to look at any of its subcells.
* Since the area of a parent must be at least as great as the
* area of any of its subcells, these subcells must have already
* been returned by a previous call to DBSelectCell.
*/
if (scx->scx_use == arg->csa_lastuse
&& scx->scx_x == arg->csa_lastp.p_x
&& scx->scx_y == arg->csa_lastp.p_y)
{
arg->csa_sawlast = TRUE;
return 0;
}
pbx = &scx->scx_use->cu_def->cd_bbox;
if (!GEO_OVERLAP((pbx), (&scx->scx_area)))
return 0;
/* compute childArea (using long long to avoid overflow). */
{
int xDiff, yDiff;
xDiff = pbx->r_xtop - pbx->r_xbot;
yDiff = pbx->r_ytop - pbx->r_ybot;
/* BY NP */
childArea = (dlong)xDiff * (dlong)yDiff;
}
/* Append the use identifier of this instance to the current path */
savenext = arg->csa_curpath.tp_next;
if (cpath->tp_next != cpath->tp_first)
*cpath->tp_next++ = '/';
n = cpath->tp_last - cpath->tp_next;
cpath->tp_next = DBPrintUseId(scx, cpath->tp_next, n, FALSE);
/*
* Visit all the children of the def for this use first.
* If, during the visiting of any of these, we get a non-NULL
* arg->csa_retuse value, we can return immediately.
*/
if (DBDescendSubcell(scx->scx_use, arg->csa_xmask))
{
(void) DBCellSrArea(scx, dbSelectCellSr, (ClientData) arg);
if (arg->csa_retuse != (CellUse *) NULL)
{
cpath->tp_next = savenext;
*savenext = '\0';
return 1;
}
}
if (arg->csa_lastuse != (CellUse *) NULL)
{
pbx = &arg->csa_lastuse->cu_def->cd_bbox;
/* compute lastArea (using long long to avoid overflow). */
{
int xDiff, yDiff;
xDiff = pbx->r_xtop - pbx->r_xbot;
yDiff = pbx->r_ytop - pbx->r_ybot;
/* BY NP */
lastArea = (dlong)xDiff * (dlong)yDiff;
}
}
else
/* BY NP */
lastArea = 0;
if (arg->csa_sawlast)
{
/*
* We have found a cell with the same area as the last cell
* selected, later in the search tree than the last one.
* We cut the search short and return this immediately.
*/
/* BY NP */
if (childArea == lastArea)
{
arg->csa_bestp->p_x = scx->scx_x;
arg->csa_bestp->p_y = scx->scx_y;
arg->csa_retuse = arg->csa_bestuse = scx->scx_use;
*arg->csa_besttrans = scx->scx_trans;
/* Copy current path into best path */
n = arg->csa_bestpath->tp_last - arg->csa_bestpath->tp_next;
strncpy(arg->csa_bestpath->tp_next, cpath->tp_first, n);
arg->csa_bestpath->tp_next[n] = '\0';
/* Pop last component of current path */
cpath->tp_next = savenext;
*savenext = '\0';
/* Abort the search */
return 1;
}
}
/*
* We only update our best guess if this cell is larger than
* the last one selected. This has the effect of ignoring all
* cells already returned by DBSelectCell in previous calls.
*
* This one might be okay. It is larger than the previous one, but
* there may be a smaller one to do first.
*/
if (childArea > lastArea)
{
if (arg->csa_bestuse != (CellUse *) NULL)
{
pbx = &arg->csa_bestuse->cu_def->cd_bbox;
/* compute bestArea (using long long to avoid overflow). */
{
int xDiff, yDiff;
xDiff = pbx->r_xtop - pbx->r_xbot;
yDiff = pbx->r_ytop - pbx->r_ybot;
bestArea = (dlong)xDiff * (dlong)yDiff;
}
/* BY NP */
if (childArea >= bestArea)
{
/* Too big: pop last component of current path */
cpath->tp_next = savenext;
*savenext = '\0';
/* Keep going */
return 0;
}
}
arg->csa_bestp->p_x = scx->scx_x;
arg->csa_bestp->p_y = scx->scx_y;
arg->csa_bestuse = scx->scx_use;
*arg->csa_besttrans = scx->scx_trans;
/* Copy current path into best path */
n = arg->csa_bestpath->tp_last - arg->csa_bestpath->tp_next;
strncpy(arg->csa_bestpath->tp_next, cpath->tp_first, n);
arg->csa_bestpath->tp_next[n] = '\0';
}
/* Pop last component of current path */
cpath->tp_next = savenext;
*savenext = '\0';
return 0;
}

1851
database/DBcellsrch.c Normal file

File diff suppressed because it is too large Load Diff

368
database/DBcellsubr.c Normal file
View File

@ -0,0 +1,368 @@
/*
* DBcellsubr.c --
*
* Low-level support for cell operations.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBcellsubr.c,v 1.2 2010/09/15 20:26:08 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "utils/malloc.h"
#include "utils/hash.h"
#include "utils/utils.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "utils/signals.h"
/* Forward declarations */
extern void dbSetPlaneTile();
/*
* ----------------------------------------------------------------------------
* DBDescendSubcell --
*
* Determine from the supplied mask if a tree search should descend into
* a cell. Note that the mask must be one of the following: 1) a single
* bit representing a window dbw_bitmask, 2) CU_DESCEND_ALL (== 0), or
* 3) a number that is not a power of two that is defined in database.h
* as a valid type for xMask (e.g., CU_DESCEND_SPECIAL).
*
* Results:
* TRUE if we should descend, FALSE if not.
*
* Side effects:
* None.
*
* Notes:
* This routine can be expanded as necessary, adding flags for various
* modes of determining whether or not to descend into a subcell.
*
* ----------------------------------------------------------------------------
*/
bool
DBDescendSubcell(use, xMask)
CellUse *use;
unsigned int xMask;
{
/* Check single bit (window ID) or zero */
if (((xMask - 1) & xMask) == 0)
return ((use->cu_expandMask & xMask) == xMask);
else switch (xMask) {
case CU_DESCEND_SPECIAL:
return (use->cu_expandMask == CU_DESCEND_SPECIAL);
case CU_DESCEND_NO_SUBCKT:
if ((use->cu_def->cd_flags & CDAVAILABLE) == 0)
if (!DBCellRead(use->cu_def, (char *) NULL, TRUE, NULL))
return FALSE;
return (DBIsSubcircuit(use->cu_def)) ? FALSE : TRUE;
case CU_DESCEND_NO_LOCK:
if (use->cu_flags & CU_LOCKED)
return FALSE;
else
return (use->cu_expandMask == CU_DESCEND_SPECIAL);
case CU_DESCEND_NO_VENDOR:
return (use->cu_def->cd_flags & CDVENDORGDS) ? FALSE : TRUE;
}
return TRUE; /* in case CU_DESCEND_ALL is not defined as 0 */
}
/*
* ----------------------------------------------------------------------------
*
* DBCellCopyDefBody --
*
* Copies the contents of the CellDef pointed to by sourceDef into the
* CellDef pointed to by destDef. Only the planes, labels, flags,
* use-id hash table, and bounding box are copied.
*
* Results:
* None.
*
* Side effects:
* Switches the contents of the bodies of the two CellDefs.
*
* ----------------------------------------------------------------------------
*/
void
DBCellCopyDefBody(sourceDef, destDef)
CellDef *sourceDef; /* Pointer to CellDef copied from */
CellDef *destDef; /* Pointer to CellDef copied to */
{
int i;
int dbCopyDefFunc();
destDef->cd_flags = sourceDef->cd_flags;
destDef->cd_bbox = sourceDef->cd_bbox;
destDef->cd_labels = sourceDef->cd_labels;
destDef->cd_lastLabel = sourceDef->cd_lastLabel;
destDef->cd_idHash = sourceDef->cd_idHash;
for (i = 0; i < MAXPLANES; i++)
destDef->cd_planes[i] = sourceDef->cd_planes[i];
/* Be careful to update parent pointers in the children of dest.
* Don't allow interrupts to wreck this.
*/
SigDisableInterrupts();
(void) TiSrArea((Tile *) NULL, destDef->cd_planes[PL_CELL],
&TiPlaneRect, dbCopyDefFunc, (ClientData) destDef);
SigEnableInterrupts();
}
int
dbCopyDefFunc(tile, def)
Tile *tile; /* Tile to search for subcell uses. */
CellDef *def; /* Set parent pointer in each use to this. */
{
CellTileBody *ctb;
for (ctb = (CellTileBody *) tile->ti_body; ctb != NULL;
ctb = ctb->ctb_next)
{
ctb->ctb_use->cu_parent = def;
}
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* DBCellClearDef --
*
* Empties out all tile planes of the indicated CellDef, making it
* as though the def had been newly allocated.
*
* Results:
* None.
*
* Side effects:
* The paint and subcells stored in the CellDef are all deleted.
* Sets the bounding box to the degenerate (0,0)::(1,1) box.
*
* ----------------------------------------------------------------------------
*/
void
DBCellClearDef(cellDef)
CellDef *cellDef; /* Pointer to CellDef to be deleted */
{
int pNum;
Plane *plane;
Label *lab;
Tile *tile;
/*
* We want the following searching to be non-interruptible
* to guarantee that everything gets cleared.
*/
SigDisableInterrupts();
/*
* We use a simple optimization to avoid trying
* to clear an already empty plane.
*/
plane = cellDef->cd_planes[PL_CELL];
tile = TR(plane->pl_left);
if (TiGetBody(tile) != (ClientData) NULL
|| LB(tile) != plane->pl_bottom
|| TR(tile) != plane->pl_right
|| RT(tile) != plane->pl_top)
{
DBClearCellPlane(plane);
}
/* Reduce clutter by reinitializing the id hash table */
HashKill(&cellDef->cd_idHash);
HashInit(&cellDef->cd_idHash, 16, HT_STRINGKEYS);
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
{
plane = cellDef->cd_planes[pNum];
tile = TR(plane->pl_left);
if (TiGetBody(tile) != TT_SPACE
|| LB(tile) != plane->pl_bottom
|| TR(tile) != plane->pl_right
|| RT(tile) != plane->pl_top)
DBClearPaintPlane(plane);
}
cellDef->cd_bbox.r_xbot = cellDef->cd_bbox.r_ybot = 0;
cellDef->cd_bbox.r_xtop = cellDef->cd_bbox.r_ytop = 1;
cellDef->cd_extended.r_xbot = cellDef->cd_extended.r_ybot = 0;
cellDef->cd_extended.r_xtop = cellDef->cd_extended.r_ytop = 1;
for (lab = cellDef->cd_labels; lab; lab = lab->lab_next)
freeMagic((char *) lab);
cellDef->cd_labels = (Label *) NULL;
cellDef->cd_lastLabel = (Label *) NULL;
SigEnableInterrupts();
}
/*
* ----------------------------------------------------------------------------
*
* DBClearCellPlane --
*
* Remove all cell uses contained in the given cell tile plane.
* Deallocates the Tiles and CellTileBodies contained in the plane,
* and constructs a new plane containing a single tile with a null
* tile body.
*
* Results:
* None.
*
* Side effects:
* Modifies the database plane given.
*
* ----------------------------------------------------------------------------
*/
void
DBClearCellPlane(plane)
Plane *plane;
{
Tile *newCenterTile;
/* Free all tiles from plane, and delete all uses */
DBFreeCellPlane(plane);
/* Allocate a new central space tile with a NULL body */
newCenterTile = TiAlloc();
plane->pl_hint = newCenterTile;
TiSetBody(newCenterTile, NULL);
dbSetPlaneTile(plane, newCenterTile);
}
/*
* ----------------------------------------------------------------------------
*
* DBClearPaintPlane --
*
* Similar in effect to painting space over an entire tile plane, but
* much faster. The resultant tile plane is guaranteed to contain a
* single central space tile, exactly as though it had been newly allocated.
*
* Results:
* None.
*
* Side effects:
* Modifies the database plane given.
*
* ----------------------------------------------------------------------------
*/
void
DBClearPaintPlane(plane)
Plane *plane;
{
Tile *newCenterTile;
/* Eliminate all the tiles from this plane */
DBFreePaintPlane(plane);
/* Allocate a new central space tile */
newCenterTile = TiAlloc();
plane->pl_hint = newCenterTile;
TiSetBody(newCenterTile, TT_SPACE);
dbSetPlaneTile(plane, newCenterTile);
}
/*
* ----------------------------------------------------------------------------
*
* dbSetPlaneTile --
*
* Set the single central tile of a plane to be that specified.
*
* Results:
* None.
*
* Side effects:
* Modifies the plane given.
*
* ----------------------------------------------------------------------------
*/
void
dbSetPlaneTile(plane, newCenterTile)
Plane *plane;
Tile *newCenterTile;
{
/*
* Set the stitches of the newly created center tile
* to point to the four boundaries of the plane.
*/
RT(newCenterTile) = plane->pl_top;
TR(newCenterTile) = plane->pl_right;
LB(newCenterTile) = plane->pl_bottom;
BL(newCenterTile) = plane->pl_left;
/*
* Set the stitches for the four boundaries of the plane
* all to point to the newly created center tile.
*/
RT(plane->pl_bottom) = newCenterTile;
LB(plane->pl_top) = newCenterTile;
TR(plane->pl_left) = newCenterTile;
BL(plane->pl_right) = newCenterTile;
LEFT(newCenterTile) = TiPlaneRect.r_xbot;
BOTTOM(newCenterTile) = TiPlaneRect.r_ybot;
}
/*
* ----------------------------------------------------------------------------
*
* DBNewPlane --
*
* Allocates and initializes a new tile plane for a cell.
* The new plane contains a single tile whose body is specified by
* the caller. The tile extends from minus infinity to plus infinity.
*
* Results:
* Returns a pointer to a new tile plane.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
Plane *
DBNewPlane(body)
ClientData body; /* Body of initial, central tile */
{
Tile *newtile;
newtile = TiAlloc();
TiSetBody(newtile, body);
LEFT(newtile) = TiPlaneRect.r_xbot;
BOTTOM(newtile) = TiPlaneRect.r_ybot;
return (TiNewPlane(newtile));
}

933
database/DBconnect.c Normal file
View File

@ -0,0 +1,933 @@
/* DBconnect.c -
*
* This file contains routines that extract electrically connected
* regions of a layout for Magic. There are two extractors, one
* that operates only within the paint of a single cell (DBSrConnect),
* and one that operates hierarchically, across cell boundaries
* (DBTreeCopyConnect).
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBconnect.c,v 1.6 2010/09/15 18:15:40 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h> // for memcpy()
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "utils/signals.h"
#include "utils/malloc.h"
/* General note for DBSrConnect:
*
* The connectivity extractor works in two passes, in order to avoid
* circularities. During the first pass, each connected tile gets
* marked, using the ti_client field. This marking is needed to
* avoid infinite searches on circular structures. The second pass
* is used to clear the markings again.
*/
/* The following structure is used to hold several pieces
* of information that must be passed through multiple
* levels of search function (used by dbSrConnectFunc).
*/
struct conSrArg
{
CellDef *csa_def; /* Definition being searched. */
int csa_plane; /* Index of current plane being searched. */
TileTypeBitMask *csa_connect; /* Table indicating what connects
* to what.
*/
int (*csa_clientFunc)(); /* Client function to call. */
ClientData csa_clientData; /* Argument for clientFunc. */
bool csa_clear; /* FALSE means pass 1, TRUE
* means pass 2.
*/
Rect csa_bounds; /* Area that limits search. */
};
/* The following structure is used to hold several pieces
* of information that must be passed through multiple
* levels of search function (used by dbcConnectFunc).
*/
typedef struct
{
Rect area; /* Area to process */
TileTypeBitMask *connectMask; /* Connection mask for search */
TileType dinfo; /* Info about triangular search areas */
} conSrArea;
struct conSrArg2
{
CellUse *csa2_use; /* Destination use */
TileTypeBitMask *csa2_connect; /* Table indicating what connects
* to what.
*/
SearchContext *csa2_topscx; /* Original top-level search context */
int csa2_xMask; /* Cell window mask for search */
Rect *csa2_bounds; /* Area that limits the search */
conSrArea *csa2_list; /* List of areas to process */
int csa2_top; /* Index of next area to process */
int csa2_size; /* Max. number bins in area list */
};
#define CSA2_LIST_START_SIZE 256
/*
*-----------------------------------------------------------------
* DBTransformDiagonal --
*
* Resolve geometric transformations on diagonally-split tiles
* Assumes that we have already determined that this tile is
* split.
*
* Results:
* A tile type containing embedded diagonal and side information.
* Note that this tile type does NOT contain any actual type
* information.
*
* Side Effects:
* None.
*-----------------------------------------------------------------
*/
TileType
DBTransformDiagonal(oldtype, trans)
TileType oldtype;
Transform *trans;
{
TileType dinfo;
int o1, o2, o3, dir, side;
o1 = ((trans->t_e > 0) || (trans->t_d > 0)) ? 1 : 0;
o2 = ((trans->t_a > 0) || (trans->t_b > 0)) ? 1 : 0;
o3 = (trans->t_a != 0) ? 1 : 0;
dir = (oldtype & TT_DIRECTION) ? 1 : 0;
side = ((oldtype & TT_SIDE) ? 1 : 0) ^ o2 ^ (dir | o3);
dir ^= o1 ^ o2;
dinfo = TT_DIAGONAL;
if (side) dinfo |= TT_SIDE;
if (dir) dinfo |= TT_DIRECTION;
return dinfo;
}
/*
*-----------------------------------------------------------------
* DBInvTransformDiagonal --
*
* This is equivalent to the routine above, but inverted, so
* that the result is correct for the orientation of the
* triangle in the coordinate system of the child cell,
* rather than the parent cell (which comes down to merely
* swapping transform positions b and d, since translation
* isn't considered).
*-----------------------------------------------------------------
*/
TileType
DBInvTransformDiagonal(oldtype, trans)
TileType oldtype;
Transform *trans;
{
TileType dinfo;
int o1, o2, o3;
int dir, side;
o1 = ((trans->t_e > 0) || (trans->t_b > 0)) ? 1 : 0;
o2 = ((trans->t_a > 0) || (trans->t_d > 0)) ? 1 : 0;
o3 = (trans->t_a != 0) ? 1 : 0;
dir = (oldtype & TT_DIRECTION) ? 1 : 0;
side = ((oldtype & TT_SIDE) ? 1 : 0) ^ o2 ^ (dir | o3);
dir ^= o1 ^ o2;
dinfo = TT_DIAGONAL;
if (side) dinfo |= TT_SIDE;
if (dir) dinfo |= TT_DIRECTION;
return dinfo;
}
/*
* ----------------------------------------------------------------------------
*
* DBSrConnect --
*
* Search through a cell to find all paint that is electrically
* connected to things in a given starting area.
*
* Results:
* 0 is returned if the search finished normally. 1 is returned
* if the search was aborted.
*
* Side effects:
* The search starts from one (random) non-space tile in "startArea"
* that matches the types in the mask parameter. For every paint
* tile that is electrically connected to the initial tile and that
* intersects the rectangle "bounds", func is called. Func should
* have the following form:
*
* int
* func(tile, clientData)
* Tile *tile;
* ClientData clientData;
* {
* }
*
* The clientData passed to func is the same one that was passed
* to us. Func returns 0 under normal conditions; if it returns
* 1 then the search is aborted.
*
* *** WARNING ***
*
* Func should not modify any paint during the search, since this
* will mess up pointers kept by these procedures and likely cause
* a core-dump.
*
* ----------------------------------------------------------------------------
*/
int
DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
CellDef *def; /* Cell definition in which to carry out
* the connectivity search. Only paint
* in this definition is considered.
*/
Rect *startArea; /* Area to search for an initial tile. Only
* tiles OVERLAPPING the area are considered.
* This area should have positive x and y
* dimensions.
*/
TileTypeBitMask *mask; /* Only tiles of one of these types are used
* as initial tiles.
*/
TileTypeBitMask *connect; /* Pointer to a table indicating what tile
* types connect to what other tile types.
* Each entry gives a mask of types that
* connect to tiles of a given type.
*/
Rect *bounds; /* Area, in coords of scx->scx_use->cu_def,
* that limits the search: only tiles
* overalapping this area will be returned.
* Use TiPlaneRect to search everywhere.
*/
int (*func)(); /* Function to apply at each connected tile. */
ClientData clientData; /* Client data for above function. */
{
struct conSrArg csa;
int startPlane, result;
Tile *startTile; /* Starting tile for search. */
extern int dbSrConnectFunc(); /* Forward declaration. */
extern int dbSrConnectStartFunc();
result = 0;
csa.csa_def = def;
csa.csa_bounds = *bounds;
/* Find a starting tile (if there are many tiles underneath the
* starting area, pick any one). The search function just saves
* the tile address and returns.
*/
startTile = NULL;
for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++)
{
if (DBSrPaintArea((Tile *) NULL,
def->cd_planes[startPlane], startArea, mask,
dbSrConnectStartFunc, (ClientData) &startTile) != 0) break;
}
if (startTile == NULL) return 0;
/* The following lets us call DBSrConnect recursively */
else if (startTile->ti_client == (ClientData)1) return 0;
/* Pass 1. During this pass the client function gets called. */
csa.csa_clientFunc = func;
csa.csa_clientData = clientData;
csa.csa_clear = FALSE;
csa.csa_connect = connect;
csa.csa_plane = startPlane;
if (dbSrConnectFunc(startTile, &csa) != 0) result = 1;
/* Pass 2. Don't call any client function, just clear the marks.
* Don't allow any interruptions.
*/
SigDisableInterrupts();
csa.csa_clientFunc = NULL;
csa.csa_clear = TRUE;
csa.csa_plane = startPlane;
(void) dbSrConnectFunc(startTile, &csa);
SigEnableInterrupts();
return result;
}
int
dbSrConnectStartFunc(tile, pTile)
Tile *tile; /* This will be the starting tile. */
Tile **pTile; /* We store tile's address here. */
{
*pTile = tile;
return 1;
}
/*
* ----------------------------------------------------------------------------
*
* dbSrConnectFunc --
*
* This search function gets called by DBSrPaintArea as part
* of DBSrConnect, and also recursively by itself. Each invocation
* is made to process a single tile that is of interest.
*
* Results:
* 0 is returned unless the client function returns a non-zero
* value, in which case 1 is returned.
*
* Side effects:
* If this tile has been seen before, then just return
* immediately. If this tile hasn't been seen before, it is
* marked and the client procedure is called. A NULL client
* procedure is not called, of course. In addition, we scan
* the tiles perimeter for any connected tiles, and call
* ourselves recursively on them.
*
* Design note:
* This one procedure is used during both the marking and clearing
* passes, so "seen before" is a function both of the ti_client
* field in the tile and the csa_clear value.
*
* ----------------------------------------------------------------------------
*/
int
dbSrConnectFunc(tile, csa)
Tile *tile; /* Tile that is connected. */
struct conSrArg *csa; /* Contains information about the search. */
{
Tile *t2;
Rect tileArea;
int i;
TileTypeBitMask *connectMask;
TileType loctype, checktype;
PlaneMask planes;
TiToRect(tile, &tileArea);
/* Make sure this tile overlaps the area we're interested in. */
if (!GEO_OVERLAP(&tileArea, &csa->csa_bounds)) return 0;
/* See if we've already been here before, and mark the tile as already
* visited.
*/
if (csa->csa_clear)
{
if (tile->ti_client == (ClientData) CLIENTDEFAULT) return 0;
tile->ti_client = (ClientData) CLIENTDEFAULT;
}
else
{
if (tile->ti_client != (ClientData) CLIENTDEFAULT) return 0;
tile->ti_client = (ClientData) 1;
}
/* Call the client function, if there is one. */
if (csa->csa_clientFunc != NULL)
{
if ((*csa->csa_clientFunc)(tile, csa->csa_plane, csa->csa_clientData) != 0)
return 1;
}
/* Now search around each of the four sides of this tile for
* connected tiles. For each one found, call ourselves
* recursively.
*/
if (IsSplit(tile))
{
if (SplitSide(tile))
loctype = SplitRightType(tile);
else
loctype = SplitLeftType(tile);
}
else
loctype = TiGetTypeExact(tile);
connectMask = &csa->csa_connect[loctype];
/* Left side: */
if (IsSplit(tile) && SplitSide(tile)) goto bottomside;
for (t2 = BL(tile); BOTTOM(t2) < tileArea.r_ytop; t2 = RT(t2))
{
if (IsSplit(t2))
{
checktype = SplitRightType(t2);
}
else
checktype = TiGetTypeExact(t2);
if (TTMaskHasType(connectMask, checktype))
{
if (csa->csa_clear)
{
if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue;
}
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) continue;
if (dbSrConnectFunc(t2, csa) != 0) return 1;
}
}
/* Bottom side: */
bottomside:
if (IsSplit(tile) && (!(SplitSide(tile) ^ SplitDirection(tile))))
goto rightside;
for (t2 = LB(tile); LEFT(t2) < tileArea.r_xtop; t2 = TR(t2))
{
if (IsSplit(t2))
{
checktype = SplitTopType(t2);
}
else
checktype = TiGetTypeExact(t2);
if (TTMaskHasType(connectMask, checktype))
{
if (csa->csa_clear)
{
if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue;
}
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) continue;
if (dbSrConnectFunc(t2, csa) != 0) return 1;
}
}
/* Right side: */
rightside:
if (IsSplit(tile) && !SplitSide(tile)) goto topside;
for (t2 = TR(tile); ; t2 = LB(t2))
{
if (IsSplit(t2))
{
checktype = SplitLeftType(t2);
}
else
checktype = TiGetTypeExact(t2);
if (TTMaskHasType(connectMask, checktype))
{
if (csa->csa_clear)
{
if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextRight;
}
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) goto nextRight;
if (dbSrConnectFunc(t2, csa) != 0) return 1;
}
nextRight: if (BOTTOM(t2) <= tileArea.r_ybot) break;
}
/* Top side: */
topside:
if (IsSplit(tile) && (SplitSide(tile) ^ SplitDirection(tile))) goto donesides;
for (t2 = RT(tile); ; t2 = BL(t2))
{
if (IsSplit(t2))
{
checktype = SplitBottomType(t2);
}
else
checktype = TiGetTypeExact(t2);
if (TTMaskHasType(connectMask, checktype))
{
if (csa->csa_clear)
{
if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextTop;
}
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) goto nextTop;
if (dbSrConnectFunc(t2, csa) != 0) return 1;
}
nextTop: if (LEFT(t2) <= tileArea.r_xbot) break;
}
donesides:
/* Lastly, check to see if this tile connects to anything on
* other planes. If so, search those planes.
*/
planes = DBConnPlanes[loctype];
planes &= ~(PlaneNumToMaskBit(csa->csa_plane));
if (planes != 0)
{
struct conSrArg newcsa;
Rect newArea;
newcsa = *csa;
TiToRect(tile, &newArea);
GEO_EXPAND(&newArea, 1, &newArea);
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
{
if (!PlaneMaskHasPlane(planes, i)) continue;
newcsa.csa_plane = i;
if (IsSplit(tile))
{
if (DBSrPaintNMArea((Tile *) NULL, csa->csa_def->cd_planes[i],
TiGetTypeExact(tile), &newArea, connectMask,
dbSrConnectFunc, (ClientData) &newcsa) != 0)
return 1;
}
else if (DBSrPaintArea((Tile *) NULL, csa->csa_def->cd_planes[i],
&newArea, connectMask, dbSrConnectFunc,
(ClientData) &newcsa) != 0) return 1;
}
}
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* dbcUnconnectFunc --
*
* This search function is invoked by DBSrPaintArea from
* DBTreeCopyConnect, whenever a tile is found in the result
* plane that is NOT connected to the current area. It
* returns 1 so that DBTreeCopyConnect will know it has
* to do a hierarchical check for the current area.
*
* Results:
* If the current tile OVERLAPS the search area, 1 is
* returned. Otherwise 0 is returned.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
dbcUnconnectFunc(tile, clientData)
Tile *tile; /* Current tile */
ClientData clientData; /* Unused. */
{
return 1;
}
/*
* ----------------------------------------------------------------------------
*
* dbcConnectLabelFunc --
*
* This function is invoked by DBTreeSrTiles from DBTreeCopyConnect;
* when a label is found which is connected to paint belonging to the
* network, it adds it to the destination definition.
*
* Results:
* Always 0.
*
* Side effects:
* Adds a label to the destination definition "def".
*
* ----------------------------------------------------------------------------
*/
int
dbcConnectLabelFunc(scx, lab, tpath, csa2)
SearchContext *scx;
Label *lab;
TerminalPath *tpath;
struct conSrArg2 *csa2;
{
CellDef *def = csa2->csa2_use->cu_def;
Rect r;
Point offset;
int pos, rotate;
int dbcConnectFunc(); /* Forward declaration */
GeoTransRect(&scx->scx_trans, &lab->lab_rect, &r);
pos = GeoTransPos(&scx->scx_trans, lab->lab_just);
GeoTransPointDelta(&scx->scx_trans, &lab->lab_offset, &offset);
rotate = GeoTransAngle(&scx->scx_trans, lab->lab_rotate);
DBEraseLabelsByContent(def, &r, -1, lab->lab_text);
DBPutFontLabel(def, &r, lab->lab_font, lab->lab_size, rotate, &offset,
pos, lab->lab_text, lab->lab_type, lab->lab_flags);
if (lab->lab_flags & PORT_DIR_MASK)
{
CellDef *orig_def = scx->scx_use->cu_def;
Label *slab;
int lidx = lab->lab_flags & PORT_NUM_MASK;
/* Check for equivalent ports. For any found, call */
/* DBTreeSrTiles recursively on the type and area */
/* of the label. */
for (slab = orig_def->cd_labels; slab != NULL; slab = slab->lab_next)
if ((slab->lab_flags & PORT_DIR_MASK) && (slab != lab))
if ((slab->lab_flags & PORT_NUM_MASK) == lidx)
{
SearchContext scx2 = *csa2->csa2_topscx;
TileTypeBitMask mask;
TTMaskSetOnlyType(&mask, slab->lab_type);
GeoTransRect(&scx->scx_trans, &slab->lab_rect, &scx2.scx_area);
DBTreeSrTiles(&scx2, &mask, csa2->csa2_xMask,
dbcConnectFunc, (ClientData) csa2);
}
}
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* dbcConnectFunc --
*
* This procedure is invoked by DBTreeSrTiles from DBTreeCopyConnect,
* whenever a tile is found that is connected to the current area
* being processed. If the tile overlaps the search area in a non-
* trivial way (i.e. more than a 1x1 square of overlap at a corner),
* then its area is checked against the equivalent destination area.
* If the destination area contains unconnected portions, then the
* area of the tile is painted into the destination, and an area 1
* unit larger than the tile is recursively checked for connecting
* tiles. The "non-trivial" overlap check is needed to prevent
* catecorner tiles from being considered as connected.
*
* Results:
* Always returns 0 to keep the search from aborting.
*
* Side effects:
* Adds paint to the destination definition.
*
* ----------------------------------------------------------------------------
*/
int
dbcConnectFunc(tile, cx)
Tile *tile; /* Tile found. */
TreeContext *cx; /* Describes context of search. The client
* data is a pointer to a conSrArg2 record
* containing various required information.
*/
{
struct conSrArg2 *csa2;
Rect tileArea, newarea;
TileTypeBitMask *connectMask, notConnectMask;
Rect *srArea;
SearchContext *scx = cx->tc_scx;
SearchContext scx2;
TileType loctype = TiGetTypeExact(tile);
TileType dinfo = 0;
int pNum = cx->tc_plane;
CellDef *def;
TiToRect(tile, &tileArea);
srArea = &scx->scx_area;
if (((tileArea.r_xbot >= srArea->r_xtop-1) ||
(tileArea.r_xtop <= srArea->r_xbot+1)) &&
((tileArea.r_ybot >= srArea->r_ytop-1) ||
(tileArea.r_ytop <= srArea->r_ybot+1)))
{
/* If the search area is only one unit wide or tall, then it's
* OK to have only a small overlap. This happens only when
* looking for an initial search tile.
*/
if (((srArea->r_xtop-1) != srArea->r_xbot)
&& ((srArea->r_ytop-1) != srArea->r_ybot)) return 0;
}
GeoTransRect(&scx->scx_trans, &tileArea, &newarea);
/* Clip the current area down to something that overlaps the
* area of interest.
*/
csa2 = (struct conSrArg2 *)cx->tc_filter->tf_arg;
GeoClip(&newarea, csa2->csa2_bounds);
if (GEO_RECTNULL(&newarea)) return 0;
if (IsSplit(tile))
{
dinfo = DBTransformDiagonal(loctype, &scx->scx_trans);
loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile);
}
/* See if the destination cell contains stuff over the whole
* current area (on its home plane) that is connected to it.
* If so, then there's no need to process the current area,
* since any processing that is needed was already done before.
*/
connectMask = &csa2->csa2_connect[loctype];
/* In the case of contact bits, the types underneath
* must be constituents of the contact before we punt
*/
if (DBIsContact(loctype))
{
// TileType ctype;
// TileTypeBitMask *cMask, *rMask = DBResidueMask(loctype);
// TTMaskSetOnlyType(&notConnectMask, loctype);
/* Different contact types may share residues (6/18/04) */
/* Use TTMaskIntersect(), not TTMaskEqual()---types */
/* which otherwise stack may be in separate cells */
/* (12/1/05) */
// for (ctype = TT_TECHDEPBASE; ctype < DBNumUserLayers; ctype++)
// {
// if (DBIsContact(ctype))
// {
// cMask = DBResidueMask(ctype);
// if (TTMaskIntersect(rMask, cMask))
// TTMaskSetType(&notConnectMask, ctype);
// }
// }
/* The mask of contact types must include all stacked contacts */
// for (ctype = DBNumUserLayers; ctype < DBNumTypes; ctype++)
// {
// cMask = DBResidueMask(ctype);
// if (TTMaskHasType(cMask, loctype))
// TTMaskSetType(&notConnectMask, ctype);
// }
// TTMaskCom(&notConnectMask);
TTMaskZero(&notConnectMask);
TTMaskSetMask(&notConnectMask, &DBNotConnectTbl[loctype]);
}
else
{
TTMaskCom2(&notConnectMask, connectMask);
}
/* Only check those tiles in the destination (select) */
/* which have not already been painted. */
def = csa2->csa2_use->cu_def;
if (DBSrPaintNMArea((Tile *) NULL, def->cd_planes[pNum],
dinfo, &newarea, &notConnectMask, dbcUnconnectFunc,
(ClientData) NULL) == 0)
return 0;
/* Paint this tile into the destination cell. This
* marks its area has having been processed. Then recycle
* the storage for the current list element.
*/
DBNMPaintPlane(def->cd_planes[pNum], dinfo,
&newarea, DBStdPaintTbl(loctype, pNum),
(PaintUndoInfo *) NULL);
/* Copy information from original context into new search context */
scx2 = *csa2->csa2_topscx;
scx2.scx_area = newarea;
/* Check the source def for any labels belonging to this */
/* tile area and plane, and add them to the destination. */
DBTreeSrLabels(&scx2, connectMask, csa2->csa2_xMask, NULL,
TF_LABEL_ATTACH, dbcConnectLabelFunc,
(ClientData) csa2);
/* Since the whole area of this tile hasn't been recorded,
* we must process its area to find any other tiles that
* connect to it. Add each of them to the list of things
* to process. We have to expand the search area by 1 unit
* on all sides because DBTreeSrTiles only returns things
* that overlap the search area, and we want things that
* even just touch.
*/
/* Only extend those sides bordering the diagonal tile */
if (dinfo & TT_DIAGONAL)
{
if (dinfo & TT_SIDE) /* right */
newarea.r_xtop += 1;
else /* left */
newarea.r_xbot -= 1;
if (((dinfo & TT_SIDE) >> 1)
== (dinfo & TT_DIRECTION)) /* top */
newarea.r_ytop += 1;
else /* bottom */
newarea.r_ybot -= 1;
}
else
{
newarea.r_ybot -= 1;
newarea.r_ytop += 1;
newarea.r_xbot -= 1;
newarea.r_xtop += 1;
}
/* Register the area and connection mask as needing to be processed */
if (++csa2->csa2_top == csa2->csa2_size)
{
/* Reached list size limit---need to enlarge the list */
/* Double the size of the list every time we hit the limit */
conSrArea *newlist;
int i, lastsize = csa2->csa2_size;
csa2->csa2_size *= 2;
newlist = (conSrArea *)mallocMagic(csa2->csa2_size * sizeof(conSrArea));
memcpy((void *)newlist, (void *)csa2->csa2_list,
(size_t)lastsize * sizeof(conSrArea));
// for (i = 0; i < lastsize; i++)
// {
// newlist[i].area = csa2->csa2_list[i].area;
// newlist[i].connectMask = csa2->csa2_list[i].connectMask;
// newlist[i].dinfo = csa2->csa2_list[i].dinfo;
// }
freeMagic((char *)csa2->csa2_list);
csa2->csa2_list = newlist;
}
csa2->csa2_list[csa2->csa2_top].area = newarea;
csa2->csa2_list[csa2->csa2_top].connectMask = connectMask;
csa2->csa2_list[csa2->csa2_top].dinfo = dinfo;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* DBTreeCopyConnect --
*
* This procedure copies connected information from a given cell
* hierarchy to a given (flat) cell. Starting from the tile underneath
* the given area, this procedure finds all paint in all cells
* that is connected to that information. All such paint is
* copied into the result cell. If there are several electrically
* distinct nets underneath the given area, one of them is picked
* at more-or-less random.
*
* Modified so the result cell is NOT first cleared of all paint. This
* allows multiple calls, to highlight incomplete routing nets.
*
* Results:
* None.
*
* Side effects:
* The contents of the result cell are modified.
*
* ----------------------------------------------------------------------------
*/
void
DBTreeCopyConnect(scx, mask, xMask, connect, area, destUse)
SearchContext *scx; /* Describes starting area. The
* scx_use field gives the root of
* the hierarchy to search, and the
* scx_area field gives the starting
* area. An initial tile must overlap
* this area. The transform is from
* coords of scx_use to destUse.
*/
TileTypeBitMask *mask; /* Tile types to start from in area. */
int xMask; /* Information must be expanded in all
* of the windows indicated by this
* mask. Use 0 to consider all info
* regardless of expansion.
*/
TileTypeBitMask *connect; /* Points to table that defines what
* each tile type is considered to
* connect to. Use DBConnectTbl as
* a default.
*/
Rect *area; /* The resulting information is
* clipped to this area. Pass
* TiPlaneRect to get everything.
*/
CellUse *destUse; /* Result use in which to place
* anything connected to material of
* type mask in area of rootUse.
*/
{
struct conSrArg2 csa2;
TileTypeBitMask *newmask;
TileType newtype;
csa2.csa2_use = destUse;
csa2.csa2_xMask = xMask;
csa2.csa2_bounds = area;
csa2.csa2_connect = connect;
csa2.csa2_topscx = scx;
/* Instead of using a linked list, we keep down the number of */
/* malloc calls by maintaining a small list and expanding it only */
/* when necessary. */
csa2.csa2_size = CSA2_LIST_START_SIZE;
csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_START_SIZE
* sizeof(conSrArea));
csa2.csa2_top = -1;
DBTreeSrTiles(scx, mask, xMask, dbcConnectFunc, (ClientData) &csa2);
while (csa2.csa2_top >= 0)
{
newmask = csa2.csa2_list[csa2.csa2_top].connectMask;
scx->scx_area = csa2.csa2_list[csa2.csa2_top].area;
newtype = csa2.csa2_list[csa2.csa2_top].dinfo;
csa2.csa2_top--;
if (newtype & TT_DIAGONAL)
DBTreeSrNMTiles(scx, newtype, newmask, xMask, dbcConnectFunc,
(ClientData) &csa2);
else
DBTreeSrTiles(scx, newmask, xMask, dbcConnectFunc, (ClientData) &csa2);
}
freeMagic((char *)csa2.csa2_list);
/* Recompute the bounding box of the destination and record its area
* for redisplay.
*/
DBReComputeBbox(destUse->cu_def);
}

168
database/DBcount.c Normal file
View File

@ -0,0 +1,168 @@
/*
* DBcount.c --
*
* Functions to compute statistics on the paint of
* a tree of cells.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBcount.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "utils/hash.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "database/database.h"
#include "database/databaseInt.h"
/*
* ----------------------------------------------------------------------------
*
* DBTreeCountPaint --
*
* Allow the client to compute statistics on the paint in a subtree.
* The client provides three functions: 'count', 'hiercount', and
* 'cleanup', which should be of the following form:
*
* int
* count(def, cdata)
* CellDef *def;
* ClientData cdata;
* {
* }
*
* The 'count' function is applied in a pre-order traversal of the
* cell graph; if it returns 0 then the subcells of 'def' are visited;
* if it returns 1 then the subcells are not visited.
*
* int
* hiercount(parent, uses, child, cdata)
* CellDef *parent, *child;
* int uses; /# Scale factor: number of times child
* # is used by parent
* #/
* ClientData cdata;
* {
* }
*
* The 'hiercount' function is applied in a post-order traversal of
* the cell graph, ie, it is applied only after all children of a
* cell have been visited.
*
* int
* cleanup(def, cdata)
* CellDef *def;
* ClientData cdata;
* {
* }
*
* The 'cleanup' function is applied in a pre-order traversal of the
* cell graph; if it returns 0 then the subcells of 'def' are visited;
* if it returns 1 then the subcells are not visited.
*
* Results:
* None.
*
* Side effects:
* Applies the client procedures as described above.
* The client is free to use each CellDef's cd_client
* field, but should reset this field to zero when the
* cleanup procedure is supplied.
*
* Algorithm:
* We first visit all CellDefs in the tree, applying the
* client's 'count' procedure to each CellDef.
*
* Next, we make a second pass over the cells, applying
* the client's 'hiercount' procedure to each CellDef
* in post-order (ie, the 'hiercount' procedure is first
* applied recursively to all the subtrees of a given
* def before being applied to the def itself).
*
* Finally, we make a pass over all CellDefs and apply
* the client's 'cleanup' procedure.
*
* ----------------------------------------------------------------------------
*/
struct countArg
{
int (*ca_count)();
int (*ca_hiercount)();
ClientData ca_cdata;
};
void
DBTreeCountPaint(def, count, hiercount, cleanup, cdata)
CellDef *def;
int (*count)();
int (*hiercount)();
int (*cleanup)();
ClientData cdata;
{
struct countArg ca;
int dbCountFunc(), dbCountHierFunc();
ca.ca_cdata = cdata;
/* Apply the count procedure to each cell */
ca.ca_count = count;
if ((*count)(def, cdata) == 0)
(void) DBCellEnum(def, dbCountFunc, (ClientData) &ca);
/* Now the hiercount */
ca.ca_hiercount = hiercount;
(void) DBCellEnum(def, dbCountHierFunc, (ClientData) &ca);
/* Now the cleanup */
ca.ca_count = cleanup;
if ((*cleanup)(def, cdata) == 0)
(void) DBCellEnum(def, dbCountFunc, (ClientData) &ca);
}
int
dbCountFunc(use, ca)
CellUse *use;
struct countArg *ca;
{
if ((*ca->ca_count)(use->cu_def, ca->ca_cdata) == 0)
(void) DBCellEnum(use->cu_def, dbCountFunc, (ClientData) ca);
return (0);
}
int
dbCountHierFunc(use, ca)
CellUse *use;
struct countArg *ca;
{
int nx, ny;
(void) DBCellEnum(use->cu_def, dbCountHierFunc, (ClientData) ca);
if (use->cu_xlo > use->cu_xhi)
nx = use->cu_xlo - use->cu_xhi + 1;
else
nx = use->cu_xhi - use->cu_xlo + 1;
if (use->cu_ylo > use->cu_yhi)
ny = use->cu_ylo - use->cu_yhi + 1;
else
ny = use->cu_yhi - use->cu_ylo + 1;
(*ca->ca_hiercount)(use->cu_parent, nx * ny, use->cu_def, ca->ca_cdata);
return (0);
}

324
database/DBexpand.c Normal file
View File

@ -0,0 +1,324 @@
/*
* DBexpand.c --
*
* Expansion and unexpansion of cells
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBexpand.c,v 1.3 2010/08/15 14:35:47 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "textio/textio.h"
#include "utils/utils.h"
#include "utils/stack.h"
/*
* Argument passed down to search functions when searching for
* cells to expand or unexpand.
*/
struct expandArg
{
int ea_xmask; /* Expand mask. */
int (*ea_func)(); /* Function to call for each cell whose
* status is changed.
*/
ClientData ea_arg; /* Argument to pass to func. */
};
/*
* ----------------------------------------------------------------------------
*
* DBExpand --
*
* Expand/unexpand a single CellUse.
*
* Results:
* None.
*
* Side effects:
* If expandFlag is TRUE, sets all the bits of expandMask in
* the flags of the given cellUse expandFlag is FALSE, clears
* all bits of expandMask.
*
* If expandFlag is TRUE and the cell being expanded has not
* been read in, reads it in from disk.
*
* ----------------------------------------------------------------------------
*/
void
DBExpand(cellUse, expandMask, expandFlag)
CellUse *cellUse;
int expandMask;
bool expandFlag;
{
CellDef *def;
if (DBDescendSubcell(cellUse, expandMask) == expandFlag)
return;
if (expandFlag)
{
def = cellUse->cu_def;
if ((def->cd_flags & CDAVAILABLE) == 0)
{
if (!DBCellRead(def, (char *) NULL, TRUE, NULL))
return;
/* Note: we don't have to recompute the bbox here, because
* if it changed, then a timestamp violation must have occurred
* and the timestamp manager will take care of recomputing
* the bbox.
*/
}
cellUse->cu_expandMask |= expandMask;
}
else
cellUse->cu_expandMask &= ~expandMask;
}
/*
* ----------------------------------------------------------------------------
*
* DBExpandAll --
*
* Recursively expand/unexpand all cells which intersect or are
* contained within the given rectangle. Furthermore, if func is
* non-NULL, it is invoked for each cell whose status has changed,
* just after the change has been made. The calling sequence is
*
* int
* func(cellUse, cdarg)
* CellUse *cellUse;
* ClientData cdarg;
* {
* }
*
* In the calls to func, cellUse is the use whose expand bit has just
* been changed, and cdarg is the argument that the caller gave to us.
* Func should normally return 0. If it returns a non-zero value, then
* the call terminates immediately and no more cells are expanded.
*
* Results:
* None.
*
* Side effects:
* If expandFlag is TRUE, sets all the bits specified by
* expandMask in the flags of each CellUse found to intersect
* the given rectangle. If expandFlag is FALSE, clears all bits
* of expandMask.
* ----------------------------------------------------------------------------
*/
void
DBExpandAll(rootUse, rootRect, expandMask, expandFlag, func, cdarg)
CellUse *rootUse; /* Root cell use from which search begins */
Rect *rootRect; /* Area to be expanded, in root coordinates */
int expandMask; /* Window mask in which cell is to be expanded */
bool expandFlag; /* TRUE => expand, FALSE => unexpand */
int (*func)(); /* Function to call for each cell whose expansion
* status is modified. NULL means don't call anyone.
*/
ClientData cdarg; /* Argument to pass to func. */
{
int dbExpandFunc(), dbUnexpandFunc();
SearchContext scontext;
struct expandArg arg;
if ((rootUse->cu_def->cd_flags & CDAVAILABLE) == 0)
(void) DBCellRead(rootUse->cu_def, (char *) NULL, TRUE, NULL);
/*
* Walk through the area and set the expansion state
* appropriately.
*/
arg.ea_xmask = expandMask;
arg.ea_func = func;
arg.ea_arg = cdarg;
scontext.scx_use = rootUse;
scontext.scx_trans = GeoIdentityTransform;
scontext.scx_area = *rootRect;
if (expandFlag)
DBCellSrArea(&scontext, dbExpandFunc, (ClientData) &arg);
else
DBCellSrArea(&scontext, dbUnexpandFunc, (ClientData) &arg);
}
/*
* dbExpandFunc --
*
* Filter function called by DBCellSrArea on behalf of DBExpandAll above
* when cells are being expanded.
*/
int
dbExpandFunc(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;
int n = DBLambda[1];
/*
* Change the expansion status of this cell if necessary. Call the
* client's function if the expansion status has changed.
*/
if (!DBDescendSubcell(childUse, arg->ea_xmask))
{
/* If the cell is unavailable, then don't expand it.
*/
if ((childUse->cu_def->cd_flags & CDAVAILABLE) == 0)
if(!DBCellRead(childUse->cu_def, (char *) NULL, 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;
if (arg->ea_func != NULL)
{
if ((*arg->ea_func)(childUse, arg->ea_arg) != 0) return 1;
}
}
if (DBCellSrArea(scx, dbExpandFunc, (ClientData) arg))
return 1;
return 2;
}
/*
* dbUnexpandFunc --
*
* Filter function called by DBCellSrArea on behalf of DBExpandAll above
* when cells are being unexpanded.
*/
int
dbUnexpandFunc(scx, arg)
SearchContext *scx; /* Pointer to search context containing
* child use, search area in coor-
* dinates of the child use, and
* transform back to "root".
*/
struct expandArg *arg; /* Client data from caller */
{
CellUse *childUse = scx->scx_use;
/*
* Change the expansion status of this cell if necessary.
*/
if (DBDescendSubcell(childUse, arg->ea_xmask))
{
if (!GEO_SURROUND(&childUse->cu_def->cd_bbox, &scx->scx_area)
|| GEO_SURROUND(&scx->scx_area, &childUse->cu_def->cd_bbox))
{
childUse->cu_expandMask &= ~arg->ea_xmask;
/* Call the client's function, if there is one. */
if (arg->ea_func != NULL)
{
if ((*arg->ea_func)(childUse, arg->ea_arg) != 0) return 1;
}
}
}
/* Don't recursively search things that aren't already expanded. */
else return 2;
if (DBCellSrArea(scx, dbUnexpandFunc, (ClientData) arg))
return 1;
return 2;
}
/*
* ----------------------------------------------------------------------------
*
* DBCellReadArea --
*
* Recursively read all cells which intersect or are contained within
* the given rectangle.
*
* Results:
* None.
*
* Side effects:
* May make new cells known to the database. Sets the CDAVAILABLE
* bit in all cells intersecting the search area.
*
* ----------------------------------------------------------------------------
*/
void
DBCellReadArea(rootUse, rootRect)
CellUse *rootUse; /* Root cell use from which search begins */
Rect *rootRect; /* Area to be read, in root coordinates */
{
int dbReadAreaFunc();
SearchContext scontext;
scontext.scx_use = rootUse;
scontext.scx_trans = GeoIdentityTransform;
scontext.scx_area = *rootRect;
(void) dbReadAreaFunc(&scontext);
}
int
dbReadAreaFunc(scx)
SearchContext *scx; /* Pointer to context specifying
* the cell use to be read in, and
* an area to be recursively read in
* coordinates of the cell use's def.
*/
{
CellDef *def = scx->scx_use->cu_def;
if ((def->cd_flags & CDAVAILABLE) == 0)
{
(void) DBCellRead(def, (char *) NULL, TRUE, NULL);
/* Note: we don't have to invoke DBReComputeBbox here because
* if the bbox changed then there was a timestamp mismatch and
* the timestamp code will take care of the bounding box later.
*/
}
(void) DBCellSrArea(scx, dbReadAreaFunc, (ClientData) NULL);
/* Be clever about handling arrays: if the search area covers this
* whole definition, then there's no need to look at any other
* array elements, since we've already expanded the entire area
* of the definition.
*/
if (GEO_SURROUND(&scx->scx_area, &scx->scx_use->cu_def->cd_bbox))
return 2;
return 0;
}

3159
database/DBio.c Normal file

File diff suppressed because it is too large Load Diff

1551
database/DBlabel.c Normal file

File diff suppressed because it is too large Load Diff

601
database/DBlabel2.c Normal file
View File

@ -0,0 +1,601 @@
/*
* DBlabel2.c --
*
* Label searching primitives.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBlabel2.c,v 1.3 2010/09/12 20:32:31 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "utils/malloc.h"
/*
* The following structure is used to pass data between DBNearestLabel
* and its search function.
*/
struct nldata
{
int nld_distance; /* Square of distance to nearest
* label seen so far.
*/
Point *nld_point; /* Reference: find nearest label to this */
Rect *nld_labelArea; /* Fill in with area of nearest label */
char *nld_name; /* Fill in with name of nearest label */
bool nld_gotLabel; /* TRUE means some label was found */
};
/*
* The following structure is used to pass the arguments of
* DBSearchLabel down to the filter function.
*/
#define MAXLABPATHSIZE 256
typedef struct {
char *labSrPattern; /* Pattern for matching. */
int (*labSrFunc)(); /* Function to apply to each label found */
ClientData labSrArg; /* Client data of caller */
} labSrStruct;
/* Forward declarations */
extern void DBTreeFindUse();
bool dbParseArray();
/*
* ----------------------------------------------------------------------------
*
* DBSearchLabel --
*
* Search for all occurrences of a point label matching the pattern in the
* region rect in the indicated cell and all of its children. On each label
* matching the pattern found in the area, the supplied procedure is invoked.
*
* The supplied procedure should be of the form
* int
* func(scx, label, tpath, cdarg)
* SearchContext *scx;
* Label *label;
* TerminalPath *tpath;
* ClientData cdarg;
* {
* }
*
* In the above, scx is a search context specifying the cell use whose
* def was found to contain the label, and label is a pointer to the
* Label structure itself. The transform specified in scx is from
* coordinates of the def of the cell containing the label to "root"
* coordinates. Func should normally return 0. If it returns 1 then
* the search is aborted.
*
* Results:
* If the search terminates normally, 0 is returned. 1 is
* returned if the search was aborted.
*
* Side effects:
* Applies the supplied procedure to each tile containing a label
* matching the pattern.
*
* WARNING: because of the way regex(3) works, it is possible to be
* searching for at most one pattern at a time.
*
* ----------------------------------------------------------------------------
*/
int
DBSearchLabel(scx, mask, xMask, pattern, func, cdarg)
SearchContext *scx; /* Search context: specifies CellUse,
* transform to "root" coordinates, and
* an area to search.
*/
TileTypeBitMask *mask; /* Only search for labels on these layers */
int xMask; /* Expansion state mask for searching. Cell
* uses are only considered to be expanded
* when their expand masks have all the bits
* of xMask set.
*/
char *pattern; /* Pattern for which to search */
int (*func)(); /* Function to apply to each match */
ClientData cdarg; /* Argument to pass to function */
{
TerminalPath tpath;
int dbSrLabelFunc();
labSrStruct labsr;
char labSrStr[MAXLABPATHSIZE]; /* String buffer in which the full pathname
* of each label is assembled for handing
* to the filter function.
*/
labsr.labSrPattern = pattern;
labsr.labSrFunc = func;
labsr.labSrArg = cdarg;
tpath.tp_first = tpath.tp_next = labSrStr;
tpath.tp_last = &(labSrStr[sizeof(labSrStr) - 2]);
if (DBTreeSrLabels(scx, mask, xMask, &tpath, TF_LABEL_ATTACH,
dbSrLabelFunc, (ClientData) &labsr))
return 1;
else return 0;
}
/*
* ----------------------------------------------------------------------------
*
* dbSrLabelFunc --
*
* Filter procedure applied to all labels by DBTreeSrLabels(). For
* each label that matches the pattern set by DBSearchLabel(), the
* filter function (*cdarg->lsa_func)() is applied.
*
* Results:
* Always return 0 to keep the search going.
*
* Side effects:
* Applies the supplied procedure to each label matching the pattern.
*
* ----------------------------------------------------------------------------
*/
int
dbSrLabelFunc(scx, label, tpath, labsr)
SearchContext *scx; /* Contains pointer to use in which label
* occurred, and transform back to root
* coordinates.
*/
Label *label; /* Label itself */
TerminalPath *tpath; /* Full pathname of the terminal */
labSrStruct *labsr; /* Information passed to this routine */
{
if (Match(labsr->labSrPattern, label->lab_text))
if ((*labsr->labSrFunc)(scx, label, tpath, labsr->labSrArg))
return 1;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* DBSrLabelLoc --
*
* This procedure finds the locations of all labels with a given
* hierarchical name. For each label found, a client-supplied
* search function is called. The search function has the form:
*
* int
* func(rect, name, label, cdarg)
* Rect *rect;
* char *name;
* Label *label;
* ClientData cdarg;
*
* Rect is the location of the label, in the coordinates of rootUse->cu_def,
* name is the label's hierarchical name (just the parameter passed to us),
* label is a pointer to the label, and cdarg is the client data passed in
* to us by the client. Note that there can be more than one label with the
* same name. Func should normally return 0. If it returns 1, then the
* search is aborted.
*
* Results:
* The return value is 0, unless func returned a non-zero value,
* in which case the return value is 1.
*
* Side effects:
* Whatever the search function does.
*
* ----------------------------------------------------------------------------
*/
int
DBSrLabelLoc(rootUse, name, func, cdarg)
CellUse *rootUse; /* Cell in which to search. */
char *name; /* A hierarchical label name consisting of zero or more
* use-ids followed by a label name (fields separated
* with slashes).
*/
int (*func)(); /* Applied to each instance of the label name */
ClientData cdarg; /* Data to pass through to (*func)() */
{
CellDef *def;
SearchContext scx;
char *cp;
Label *lab;
char csave;
Rect r;
if (cp = strrchr(name, '/'))
{
csave = *cp;
*cp = '\0';
DBTreeFindUse(name, rootUse, &scx);
*cp = csave;
if (scx.scx_use == NULL)
return 0;
cp++;
}
else
{
scx.scx_use = rootUse;
scx.scx_trans = GeoIdentityTransform;
cp = name;
}
def = scx.scx_use->cu_def;
for (lab = def->cd_labels; lab; lab = lab->lab_next)
if (lab->lab_text[0] == *cp && strcmp(lab->lab_text, cp) == 0)
{
GeoTransRect(&scx.scx_trans, &lab->lab_rect, &r);
if ((*func)(&r, name, lab, cdarg))
return 1;
}
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* DBTreeFindUse --
*
* This procedure finds the cell use with the given hierarchical name.
*
* Results:
* None.
*
* Side effects:
* Sets scx->scx_use to the cell use found, with scx->scx_trans
* and scx->scx_x, scx->scx_y also valid. If the cell was not
* found, leaves scx->scx_use set to NULL.
*
* ----------------------------------------------------------------------------
*/
void
DBTreeFindUse(name, use, scx)
char *name;
CellUse *use;
SearchContext *scx;
{
char *cp;
HashEntry *he;
CellDef *def;
char csave;
def = use->cu_def;
scx->scx_use = (CellUse *) NULL;
scx->scx_trans = GeoIdentityTransform;
scx->scx_x = scx->scx_y = 0;
while (*name)
{
/*
* Make sure that the cell whose children are being searched
* is read in from disk.
*/
if ((def->cd_flags & CDAVAILABLE) == 0)
(void) DBCellRead(def, (char *) NULL, TRUE, NULL);
/*
* Pull off the next component of path up to but not including
* any array subscripts.
*/
for (cp = name; *cp && *cp != '[' && *cp != '/'; cp++)
/* Nothing */;
csave = *cp;
*cp = '\0';
he = HashLookOnly(&def->cd_idHash, name);
*cp = csave;
if (he == NULL || HashGetValue(he) == NULL)
return;
use = (CellUse *) HashGetValue(he);
def = use->cu_def;
/*
* Pull off array subscripts and build next stage in transform.
* Return NULL if the number of subscripts specified doesn't
* match the number that are implied by the array, if use is
* an array.
*/
if (!dbParseArray(cp, use, scx))
{
/* Allow non-indexed match of array */
if (strcmp(name, use->cu_id)) return;
/* Check for both 1- and 2-dimensional arrays */
if (!dbParseArray("[0][0]", use, scx))
if (!dbParseArray("[0]", use, scx))
return;
break;
}
while (*cp && *cp++ != '/')
/* Nothing */;
name = cp;
}
/* Ensure that the leaf cell is read in */
def = use->cu_def;
if ((def->cd_flags & CDAVAILABLE) == 0)
(void) DBCellRead(def, (char *) NULL, TRUE, NULL);
scx->scx_use = use;
}
/*
* ----------------------------------------------------------------------------
*
* dbParseArray --
*
* Pull off the array subscripts starting at 'cp' (there may be none),
* checking to ensure that there are the correct number for 'use' and that
* they are in range. Store these in scx->scx_x and scx->scx_y, and use them
* to update scx->scx_trans to be use->cu_trans (as adjusted for the indicated
* array element) followed by the old value of scx->scx_trans.
*
* Results:
* Returns TRUE on success, FALSE on error.
*
* Side effects:
* See above.
*
* ----------------------------------------------------------------------------
*/
bool
dbParseArray(cp, use, scx)
char *cp;
CellUse *use;
SearchContext *scx;
{
int xdelta, ydelta, i1, i2, indexCount;
Transform trans, trans2;
/*
* The transform stuff is a little tricky because if there
* was only one index given we don't know whether it's the
* x- or y-index. Make sure the number of indices specified
* matches the number of dimensions in an array, and that
* the indices are in range.
*/
indexCount = 0;
if (*cp == '[')
{
if (sscanf(cp, "[%d][%d]", &i1, &i2) == 2)
{
indexCount = 2;
while (*cp++ != ']') /* Nothing */;
while (*cp++ != ']') /* Nothing */;
}
else if (sscanf(cp, "[%d,%d]", &i1, &i2) == 2)
{
indexCount = 2;
while (*cp++ != ']') /* Nothing */;
}
else if (sscanf(cp, "[%d]", &i1) == 1)
{
indexCount = 1;
while (*cp++ != ']') /* Nothing */;
}
if (indexCount && *cp != '\0' && *cp != '/')
return FALSE;
}
switch (indexCount)
{
case 0:
if (use->cu_xlo != use->cu_xhi || use->cu_ylo != use->cu_yhi)
return FALSE;
scx->scx_x = use->cu_xlo;
scx->scx_y = use->cu_ylo;
break;
case 1:
if (use->cu_xlo == use->cu_xhi)
{
scx->scx_x = use->cu_xlo;
scx->scx_y = i1;
}
else if (use->cu_ylo == use->cu_yhi)
{
scx->scx_x = i1;
scx->scx_y = use->cu_ylo;
}
else return FALSE;
break;
case 2:
if (use->cu_xlo == use->cu_xhi || use->cu_ylo == use->cu_yhi)
return FALSE;
scx->scx_y = i1;
scx->scx_x = i2;
break;
}
if (use->cu_xhi > use->cu_xlo)
{
if (scx->scx_x < use->cu_xlo || scx->scx_x > use->cu_xhi)
return FALSE;
xdelta = use->cu_xsep * (scx->scx_x - use->cu_xlo);
}
else
{
if (scx->scx_x > use->cu_xlo || scx->scx_x < use->cu_xhi)
return FALSE;
xdelta = use->cu_xsep * (use->cu_xlo - scx->scx_x);
}
if (use->cu_yhi > use->cu_ylo)
{
if (scx->scx_y < use->cu_ylo || scx->scx_y > use->cu_yhi)
return FALSE;
ydelta = use->cu_ysep * (scx->scx_y - use->cu_ylo);
}
else
{
if (scx->scx_y > use->cu_ylo || scx->scx_y < use->cu_yhi)
return FALSE;
ydelta = use->cu_ysep * (use->cu_ylo - scx->scx_y);
}
GeoTransTranslate(xdelta, ydelta, &use->cu_transform, &trans);
GeoTransTrans(&trans, &scx->scx_trans, &trans2);
scx->scx_trans = trans2;
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* DBNearestLabel --
*
* This procedure finds the nearest label to a given point
* and returns its hierarchical name and location.
*
* Results:
* Area is searched in cellUse to find the nearest label
* to point. TRUE is returned if any label was found.
* If there is no label in the given area, FALSE is
* returned.
*
* Side effects:
* The parameter labelArea is filled in with the location of
* the label, if one was found. LabelName is filled in with
* the hierarchical name of the label.
*
* ----------------------------------------------------------------------------
*/
bool
DBNearestLabel(cellUse, area, point, xMask, labelArea, labelName, length)
CellUse *cellUse; /* Start search at this cell. */
Rect *area; /* Search this area of cellUse. */
Point *point; /* Find nearest label to this point. */
int xMask; /* Recursively search subcells as long
* as their expand masks, when anded with
* xMask, are equal to xMask. 0 means search
* all the way down through the hierarchy.
*/
Rect *labelArea; /* To be filled in with area of closest
* label. NULL means ignore.
*/
char *labelName; /* Fill this in with name of label, unless
* NULL.
*/
int length; /* This gives the maximum number of chars
* that may be used in labelName, including
* the NULL character to terminate.
*/
{
TerminalPath tPath, *tp;
SearchContext scx;
char *name;
struct nldata funcData;
extern int dbNearestLabelFunc();
/* Allocate space to generate a label name, and set up information
* for the DBTreeSrLabels call.
*/
if (labelName == NULL) tp = NULL, name = NULL;
else
{
name = (char *) mallocMagic((unsigned) (length));
tPath.tp_first = name;
tPath.tp_next = name;
tPath.tp_last = name + length - 1;
tp = &tPath;
}
scx.scx_use = cellUse;
scx.scx_area = *area;
scx.scx_trans = GeoIdentityTransform;
funcData.nld_point = point;
funcData.nld_labelArea = labelArea;
funcData.nld_name = labelName;
funcData.nld_gotLabel = FALSE;
(void) DBTreeSrLabels(&scx, &DBAllTypeBits, xMask, tp, TF_LABEL_ATTACH,
dbNearestLabelFunc, (ClientData) &funcData);
if (name) freeMagic(name);
if (!funcData.nld_gotLabel) return FALSE;
else return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* dbNearestLabelFunc --
*
* This function is called by DBTreeSrLabels for each label
* found as part of DBNearestLabel.
*
* Results:
* Always returns 0 to continue the search.
*
* Side effects:
* If this is the closest label seen so far, update the information
* passed via funcData.
*
* ----------------------------------------------------------------------------
*/
int
dbNearestLabelFunc(scx, label, tpath, funcData)
SearchContext *scx; /* Describes state of search. */
Label *label; /* Label found. */
TerminalPath *tpath; /* Name of label. */
struct nldata *funcData; /* Parameters to DBNearestLabel (passed as
* ClientData).
*/
{
int x, y, distance, left, used;
Rect area;
char *src, *dst;
GeoTransRect(&scx->scx_trans, &label->lab_rect, &area);
x = (area.r_xtop + area.r_xbot)/2 - funcData->nld_point->p_x;
y = (area.r_ytop + area.r_ybot)/2 - funcData->nld_point->p_y;
distance = x*x + y*y;
if ((funcData->nld_gotLabel) && (distance > funcData->nld_distance))
return 0;
funcData->nld_distance = distance;
funcData->nld_gotLabel = TRUE;
if (funcData->nld_labelArea != NULL)
*(funcData->nld_labelArea) = area;
if (funcData->nld_name != NULL)
{
left = tpath->tp_last - tpath->tp_next;
used = tpath->tp_next - tpath->tp_first;
(void) strncpy(funcData->nld_name, tpath->tp_first, used);
dst = funcData->nld_name + used;
src = label->lab_text;
for ( ; left > 0; left -= 1)
{
if (*src == 0) break;
*dst++ = *src++;
}
*dst = 0;
}
return 0;
}

3454
database/DBpaint.c Normal file

File diff suppressed because it is too large Load Diff

408
database/DBpaint2.c Normal file
View File

@ -0,0 +1,408 @@
/*
* DBpaint2.c --
*
* More paint and erase primitives
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBpaint2.c,v 1.6 2010/06/24 12:37:15 tim Exp $";
#endif /* not lint */
#include <sys/types.h>
#include <stdio.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
/*
* ----------------------------------------------------------------------------
* DBPaint --
*
* Paint a rectangular area with a specific tile type.
* All paint tile planes in cellDef are painted.
*
* Results:
* None.
*
* Side effects:
* Modifies potentially all paint tile planes in cellDef.
* ----------------------------------------------------------------------------
*/
void
DBPaint (cellDef, rect, type)
CellDef * cellDef; /* CellDef to modify */
Rect * rect; /* Area to paint */
TileType type; /* Type of tile to be painted */
{
int pNum;
PaintUndoInfo ui;
TileType loctype = type; /* Local value of tile type */
Rect brect;
GEO_EXPAND(rect, 1, &brect);
if (type & TT_DIAGONAL)
loctype = (type & TT_SIDE) ?
(type & TT_RIGHTMASK) >> 14 : (type & TT_LEFTMASK);
cellDef->cd_flags |= CDMODIFIED|CDGETNEWSTAMP;
ui.pu_def = cellDef;
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
if (DBPaintOnPlane(loctype, pNum))
{
ui.pu_pNum = pNum;
DBNMPaintPlane(cellDef->cd_planes[pNum], type, rect,
DBStdPaintTbl(loctype, pNum), &ui);
DBMergeNMTiles(cellDef->cd_planes[pNum], &brect, &ui);
}
/* Resolve images over all their planes. This allows the */
/* definition of composite types generated from types on */
/* different planes, as well as relaxing the constraints on */
/* the "compose" section of the technology file. */
if (loctype < DBNumUserLayers)
{
TileTypeBitMask *rMask, tMask;
TileType itype;
int dbResolveImages();
for (itype = TT_SELECTBASE; itype < DBNumUserLayers; itype++)
{
/* Ignore self, or infinite looping will result */
if (itype == loctype) continue;
rMask = DBResidueMask(itype);
if (TTMaskHasType(rMask, loctype))
{
TTMaskZero(&tMask);
TTMaskSetType(&tMask, itype);
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
{
if (DBPaintOnPlane(itype, pNum))
{
DBSrPaintNMArea((Tile *)NULL, cellDef->cd_planes[pNum],
type, rect, &tMask, dbResolveImages,
(ClientData)cellDef);
}
}
}
}
}
}
/*
* dbResolveImages ---
*
* This callback function is called from DBSrPaintArea and
* makes a recursive call to DBPaint() for tiles that have
* images on multiple planes but which may not have been
* painted on all of those planes due to restrictions of
* the paint table.
*/
int
dbResolveImages(tile, cellDef)
Tile *tile;
CellDef *cellDef;
{
Rect rect;
TiToRect(tile, &rect);
/* Recursive call back to DBPaint---this will ensure that */
/* all of the planes of the image type are painted. */
DBPaint(cellDef, &rect, TiGetTypeExact(tile));
return 0;
}
/*
* ----------------------------------------------------------------------------
* DBErase --
*
* Erase a specific tile type from a rectangular area.
* The plane in which tiles of the given type reside is modified
* in cellDef.
*
* Results:
* None.
*
* Side effects:
* Modifies potentially all paint tile planes in cellDef.
* ----------------------------------------------------------------------------
*/
void
DBErase (cellDef, rect, type)
CellDef * cellDef; /* Cell to modify */
Rect * rect; /* Area to paint */
TileType type; /* Type of tile to be painted */
{
int pNum;
PaintUndoInfo ui;
TileType loctype = type; /* Local value of tile type */
Rect brect;
bool allPlane = FALSE;
if (GEO_SAMERECT(*rect, TiPlaneRect))
allPlane = TRUE;
else
GEO_EXPAND(rect, 1, &brect);
if (type & TT_DIAGONAL)
loctype = (type & TT_SIDE) ?
(type & TT_RIGHTMASK) >> 14 : (type & TT_LEFTMASK);
cellDef->cd_flags |= CDMODIFIED|CDGETNEWSTAMP;
ui.pu_def = cellDef;
if (loctype == TT_SPACE)
{
/*
* Erasing space is the same as erasing everything under
* the rectangle.
*/
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
{
ui.pu_pNum = pNum;
DBNMPaintPlane(cellDef->cd_planes[pNum], type, rect,
DBStdPaintTbl(loctype, pNum), &ui);
if (!allPlane)
DBMergeNMTiles(cellDef->cd_planes[pNum], &brect, &ui);
}
}
else
{
/*
* Ordinary type is being erased.
* Generate the erase on all planes in cellDef.
*/
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
if (DBEraseOnPlane(loctype, pNum))
{
ui.pu_pNum = pNum;
DBNMPaintPlane(cellDef->cd_planes[pNum], type, rect,
DBStdEraseTbl(loctype, pNum), &ui);
if (!allPlane)
DBMergeNMTiles(cellDef->cd_planes[pNum], &brect, &ui);
}
}
}
/*
* ----------------------------------------------------------------------------
* DBPaintMask --
*
* Paint a rectangular area with all tile types specified in the
* mask supplied.
*
* Results:
* None.
*
* Side effects:
* Modifies potentially all paint tile planes in cellDef.
* ----------------------------------------------------------------------------
*/
void
DBPaintMask(cellDef, rect, mask)
CellDef *cellDef; /* CellDef to modify */
Rect *rect; /* Area to paint */
TileTypeBitMask *mask; /* Mask of types to be erased */
{
TileType t;
for (t = TT_SPACE + 1; t < DBNumTypes; t++)
if (TTMaskHasType(mask, t))
DBPaint(cellDef, rect, t);
}
/*
* ----------------------------------------------------------------------------
* DBPaintValid --
*
* Paint a rectangular area with all tile types specified in the
* mask supplied, ANDed with valid layers.
*
* Results:
* None.
*
* Side effects:
* Modifies potentially all paint tile planes in cellDef.
* ----------------------------------------------------------------------------
*/
void
DBPaintValid(cellDef, rect, mask, dinfo)
CellDef *cellDef; /* CellDef to modify */
Rect *rect; /* Area to paint */
TileTypeBitMask *mask; /* Mask of types to be erased */
TileType dinfo; /* If non-zero, then rect is a triangle and
* dinfo contains side and direction information
*/
{
TileType t, tt, tloc, dloc;
TileTypeBitMask rmask, mmask, *tMask;
dloc = dinfo & (TT_DIAGONAL | TT_SIDE | TT_DIRECTION);
TTMaskZero(&mmask);
TTMaskSetMask(&mmask, mask);
/* Decompose stacked contacts */
for (t = DBNumUserLayers; t < DBNumTypes; t++)
if (TTMaskHasType(mask, t))
TTMaskSetMask(&mmask, DBResidueMask(t));
/* Remove any inactive layers */
TTMaskAndMask(&mmask, &DBActiveLayerBits);
/* If any residue of a contact is not in the active layers */
/* list, then paint only the valid residue layers. */
for (t = TT_SELECTBASE; t < DBNumUserLayers; t++)
if (TTMaskHasType(&mmask, t))
if (DBIsContact(t))
{
tMask = DBResidueMask(t);
TTMaskAndMask3(&rmask, tMask, &DBActiveLayerBits);
if (TTMaskEqual(&rmask, tMask))
{
tloc = dloc | ((dinfo & TT_DIAGONAL) ? ((dinfo & TT_SIDE) ?
(t << 14) : t) : t);
DBPaint(cellDef, rect, tloc);
}
else if (!TTMaskIsZero(&rmask))
{
for (tt = TT_SPACE + 1; tt < DBNumTypes; tt++)
if (TTMaskHasType(&rmask, tt))
{
tloc = dloc | ((dinfo & TT_DIAGONAL) ?
((dinfo & TT_SIDE) ? (tt << 14) : tt) : tt);
DBPaint(cellDef, rect, tloc);
}
}
}
else
{
tloc = dloc | ((dinfo & TT_DIAGONAL) ? ((dinfo & TT_SIDE) ?
(t << 14) : t) : t);
DBPaint(cellDef, rect, tloc);
}
}
/*
* ----------------------------------------------------------------------------
* DBEraseMask --
*
* Erase a rectangular area with all tile types specified in the
* mask supplied.
*
* Results:
* None.
*
* Side effects:
* Modifies potentially all paint tile planes in cellDef.
* ----------------------------------------------------------------------------
*/
void
DBEraseMask(cellDef, rect, mask)
CellDef *cellDef; /* CellDef to modify */
Rect *rect; /* Area to erase */
TileTypeBitMask *mask; /* Mask of types to be erased */
{
TileType t;
for (t = DBNumTypes - 1; t >= TT_SELECTBASE; t--)
if (TTMaskHasType(mask, t))
DBErase(cellDef, rect, t);
}
/*
* ----------------------------------------------------------------------------
* DBEraseValid --
*
* Erase a rectangular area with all tile types specified in the
* mask supplied, ANDed with valid layers.
*
* Results:
* None.
*
* Side effects:
* Modifies potentially all paint tile planes in cellDef.
* ----------------------------------------------------------------------------
*/
void
DBEraseValid(cellDef, rect, mask, dinfo)
CellDef *cellDef; /* CellDef to modify */
Rect *rect; /* Area to erase */
TileTypeBitMask *mask; /* Mask of types to be erased */
TileType dinfo; /* w/Non-Manhattan geometry, "rect" is a
* triangle and dinfo holds side & direction
*/
{
TileType t, tt, tloc, dloc;
TileTypeBitMask rmask, mmask, *tMask;
dloc = dinfo & (TT_DIAGONAL | TT_SIDE | TT_DIRECTION);
/* Remove any inactive layers */
TTMaskAndMask3(&mmask, mask, &DBActiveLayerBits);
/* If any residue of a contact is not in the active layers */
/* list, then erase the contact in multiple passes. */
for (t = TT_SELECTBASE; t < DBNumUserLayers; t++)
if (TTMaskHasType(&mmask, t))
if (DBIsContact(t))
{
tMask = DBResidueMask(t);
TTMaskAndMask3(&rmask, tMask, &DBActiveLayerBits);
if (TTMaskEqual(&rmask, tMask))
{
tloc = dloc | ((dinfo & TT_DIAGONAL) ? ((dinfo & TT_SIDE) ?
(t << 14) : t) : t);
DBErase(cellDef, rect, tloc);
}
else if (!TTMaskIsZero(&rmask))
{
for (tt = TT_SELECTBASE; tt < DBNumUserLayers; tt++)
if (TTMaskHasType(&rmask, tt))
{
tloc = dloc | ((dinfo & TT_DIAGONAL) ?
((dinfo & TT_SIDE) ? (tt << 14) : tt) : tt);
DBErase(cellDef, rect, tloc);
}
}
}
else
{
tloc = dloc | ((dinfo & TT_DIAGONAL) ? ((dinfo & TT_SIDE) ?
(t << 14) : t) : t);
DBErase(cellDef, rect, tloc);
}
}

202
database/DBprop.c Normal file
View File

@ -0,0 +1,202 @@
/*
* DBprop.c --
*
* Implement properties on database cells. Properties are name-value pairs
* and provide a flexible way of extending the data that is stored in a
* CellDef. Maybe in the future properties will be added to other database
* objects.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBprop.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "utils/malloc.h"
/* ----------------------------------------------------------------------------
*
*DBPropPut --
*
* Put a property onto a celldef.
*
* Results:
* None.
*
* ----------------------------------------------------------------------------
*/
void
DBPropPut(cellDef, name, value)
CellDef *cellDef; /* Pointer to definition of cell. */
char *name; /* The name of the property desired. */
ClientData value; /* MUST point to a malloc'ed structure, or NULL.
* This will be freed when the CellDef is freed.
*/
{
HashTable *htab;
HashEntry *entry;
/* Honor the NOEDIT flag */
if (cellDef->cd_flags & CDNOEDIT) return;
if (cellDef->cd_props == (ClientData) NULL)
{
cellDef->cd_props = (ClientData) mallocMagic(sizeof(HashTable));
HashInit( (HashTable *) cellDef->cd_props, 8, 0);
}
htab = (HashTable *) cellDef->cd_props;
entry = HashFind(htab, name);
HashSetValue(entry, value);
}
/* ----------------------------------------------------------------------------
*
* DBPropGet --
*
* Get a property from a celldef.
*
* Results:
* NULL if the property didn't exist, or if the property value was NULL.
* Otherwise, ClientData that represents the property.
*
* ----------------------------------------------------------------------------
*/
ClientData
DBPropGet(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.
*/
{
ClientData result;
bool haveit;
HashTable *htab;
HashEntry *entry;
result = (ClientData) NULL;
haveit = FALSE;
htab = (HashTable *) cellDef->cd_props;
if (htab == (HashTable *) NULL) goto done;
entry = HashLookOnly(htab, name);
if (entry != NULL)
{
haveit = TRUE;
result = (ClientData) HashGetValue(entry);
}
done:
if (found != (bool *) NULL) *found = haveit;
return result;
}
/* ----------------------------------------------------------------------------
*
* DBPropEnum --
*
* Enumerate all the properties on a cell.
*
* Results:
* 0 if the search completed, else whatever value was returned by the
* called proc.
*
* Side effects:
* Depends on the called proc.
* ----------------------------------------------------------------------------
*/
int
DBPropEnum(cellDef, func, cdata)
CellDef *cellDef; /* Pointer to definition of cell. */
int (*func)(); /* Function of the form:
*
* int foo(name, value, cdata)
* char *name;
* ClientData value;
* ClientData cdata;
* {
* -- return 0 to continue,
* -- nonzero to abort.
* return result;
* }
*/
ClientData cdata;
{
HashTable *htab;
HashSearch hs;
HashEntry *entry;
int res;
if (cellDef->cd_props == (ClientData) NULL) return 0;
htab = (HashTable *) cellDef->cd_props;
HashStartSearch(&hs);
while ((entry = HashNext(htab, &hs)) != NULL)
{
res = (*func)(entry->h_key.h_name, (ClientData) entry->h_pointer, cdata);
if (res != 0) return res;
}
return 0;
}
/* ----------------------------------------------------------------------------
*
* DBPropClearAll --
*
* Free up all properties and associated storage for a CellDef.
*
* Results:
* none.
*
* Side effects:
* Frees up storage, even for the property table itself.
* ----------------------------------------------------------------------------
*/
void
DBPropClearAll(cellDef)
CellDef *cellDef; /* Pointer to definition of cell. */
{
HashTable *htab;
HashSearch hs;
HashEntry *entry;
if (cellDef->cd_props == (ClientData) NULL) return;
htab = (HashTable *) cellDef->cd_props;
HashStartSearch(&hs);
while ((entry = HashNext(htab, &hs)) != NULL)
{
if (entry->h_pointer != NULL) freeMagic((char *) entry->h_pointer);
HashSetValue(entry, NULL);
}
HashKill(htab);
freeMagic((char *) htab);
cellDef->cd_props = (ClientData) NULL;
}

1013
database/DBtcontact.c Normal file

File diff suppressed because it is too large Load Diff

435
database/DBtech.c Normal file
View File

@ -0,0 +1,435 @@
/*
* DBtech.c --
*
* Technology initialization for the database module.
* This file handles overall initialization, construction
* of the general-purpose exported TileTypeBitMasks, and
* the "connect" section.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBtech.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/utils.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "utils/tech.h"
#include "textio/textio.h"
#include "utils/malloc.h"
/* Name of this technology */
char *DBTechName = 0;
char *DBTechVersion = 0;
char *DBTechDescription = 0;
/* Connectivity */
TileTypeBitMask DBConnectTbl[NT];
TileTypeBitMask DBNotConnectTbl[NT];
PlaneMask DBConnPlanes[NT];
PlaneMask DBAllConnPlanes[NT];
/*
* ----------------------------------------------------------------------------
*
* DBTechInit --
*
* Clear technology description information for database module.
*
* Results:
* None.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
void
DBTechInit()
{
/* StrDup() takes care of reallocating DBTechName */
/* TECH_FORMAT_VERSION is defined in utils/tech.h, */
/* and should be 27, the last version to be */
/* included as part of the tech filename suffix. */
TechFormatVersion = TECH_FORMAT_VERSION;
/* Initialization of bezier coefficients for font vectors */
DBFontInitCurves();
}
/*
* ----------------------------------------------------------------------------
*
* DBTechSetTech --
*
* Set the name for the technology.
*
* Results:
* Returns FALSE if there were an improper number of
* tokens on the line.
*
* Side effects:
* Sets DBTechName to the name of the technology.
*
* ----------------------------------------------------------------------------
*/
/*ARGSUSED*/
bool
DBTechSetTech(sectionName, argc, argv)
char *sectionName;
int argc;
char *argv[];
{
if (argc != 1)
{
if (argc == 2)
{
if (strncmp(argv[0], "format", 6) == 0 ||
strncmp(argv[0], "version", 7) == 0)
{
if (StrIsInt(argv[1]))
{
TechFormatVersion = atoi(argv[1]);
return TRUE;
}
else
{
TechError("Bad format version number. . . assuming %d\n",
TECH_FORMAT_VERSION);
return TRUE;
}
}
}
TechError("Badly formed technology name\n");
return FALSE;
}
(void) StrDup(&DBTechName, argv[0]);
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* DBTechInitVersion --
*
* Clean up memory allocated by the "version" section
*
* ----------------------------------------------------------------------------
*/
void
DBTechInitVersion()
{
/* StrDup() takes care of reallocating DBTechVersion and */
/* DBTechDescription. */
}
/*
* ----------------------------------------------------------------------------
*
* DBTechSetVersion --
*
* Set the version number & description for the technology.
*
* Results:
* Returns FALSE if there were an improper number of
* tokens on the line.
*
* Side effects:
* Sets DBTechVersion and DBTechDescription.
*
* ----------------------------------------------------------------------------
*/
/*ARGSUSED*/
bool
DBTechSetVersion(sectionName, argc, argv)
char *sectionName;
int argc;
char *argv[];
{
char *contline;
int n, slen;
if (argc < 2) goto usage;
if (strcmp(argv[0], "version") == 0)
{
(void) StrDup(&DBTechVersion, argv[1]);
for (n = 2; n < argc; n++)
{
slen = strlen(DBTechVersion);
contline = mallocMagic(strlen(argv[n]) + slen + 1);
sprintf(contline, "%s\n%s", DBTechVersion, argv[n]);
freeMagic(DBTechVersion);
DBTechVersion = contline;
}
return TRUE;
}
if (strcmp(argv[0], "description") == 0)
{
(void) StrDup(&DBTechDescription, argv[1]);
for (n = 2; n < argc; n++)
{
slen = strlen(DBTechDescription);
contline = mallocMagic(strlen(argv[n]) + slen + 1);
sprintf(contline, "%s\n%s", DBTechDescription, argv[n]);
freeMagic(DBTechDescription);
DBTechDescription = contline;
}
return TRUE;
}
usage:
TechError("Badly formed version line\nUsage: {version text}|{description text}\n");
return FALSE;
}
/*
* ----------------------------------------------------------------------------
*
* DBTechInitConnect --
*
* Initialize the connectivity tables.
*
* Results:
* None.
*
* Side effects:
* Initializes DBConnectTbl[], DBConnPlanes[], and DBAllConnPlanes[].
*
* ----------------------------------------------------------------------------
*/
void
DBTechInitConnect()
{
int i;
for (i = 0; i < TT_MAXTYPES; i++)
{
TTMaskSetOnlyType(&DBConnectTbl[i], i);
DBConnPlanes[i] = 0;
DBAllConnPlanes[i] = 0;
}
}
/*
* ----------------------------------------------------------------------------
*
* DBTechAddConnect --
*
* Add connectivity information.
* Record the fact that material of the types in the comma-separated
* list types1 connects to material of the types in the list types2.
*
* Results:
* TRUE if successful, FALSE on error
*
* Side effects:
* Updates DBConnectTbl[].
*
* ----------------------------------------------------------------------------
*/
/*ARGSUSED*/
bool
DBTechAddConnect(sectionName, argc, argv)
char *sectionName;
int argc;
char *argv[];
{
TileTypeBitMask types1, types2;
TileType t1, t2;
if (argc != 2)
{
TechError("Line must contain exactly 2 lists of types\n");
return FALSE;
}
DBTechNoisyNameMask(argv[0], &types1);
DBTechNoisyNameMask(argv[1], &types2);
for (t1 = 0; t1 < DBNumTypes; t1++)
if (TTMaskHasType(&types1, t1))
for (t2 = 0; t2 < DBNumTypes; t2++)
if (TTMaskHasType(&types2, t2))
{
TTMaskSetType(&DBConnectTbl[t1], t2);
TTMaskSetType(&DBConnectTbl[t2], t1);
}
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* DBTechFinalConnect --
*
* Postprocessing for the connectivity information.
* Modify DBConnectTbl[] so that:
*
* (1) Any type connecting to one of the images of a contact
* connects to all images of the contact.
* (2) Each image of a contact connects to the union of what
* all the images connect to.
*
* Modify DBConnPlanes[] so that only types belonging to a contact
* appear to connect to any plane other than their own.
*
* Constructs DBAllConnPlanes, which will be non-zero for those planes
* to which each type connects, exclusive of that type's home plane and
* those planes to which it connects as a contact.
*
* Create DBNotConnectTbl[], the complement of DBConnectTbl[].
*
* Results:
* None.
*
* Side effects:
* Modifies DBConnPlanes[], DBAllConnPlanes[], and DBConnectTbl[]
* as above.
*
* ----------------------------------------------------------------------------
*/
void
DBTechFinalConnect()
{
/* TileTypeBitMask saveConnect[TT_MAXTYPES]; */
TileTypeBitMask *cMask, *rMask;
TileType base, s;
LayerInfo *lp, *ls;
int n;
for (s = 0; s < DBNumTypes; s++)
DBConnPlanes[s] = 0;
/*
* Each stacked contact type must necessarily connect to its
* residual contact types, and the connecting types of those
* contacts. Each stacked contact type also connects to
* other contact types that share (first) residues.
*/
for (base = DBNumUserLayers; base < DBNumTypes; base++)
{
TileTypeBitMask *smask, *rmask = DBResidueMask(base), cmask;
TTMaskSetMask(&DBConnectTbl[base], rmask);
for (s = TT_TECHDEPBASE; s < DBNumUserLayers; s++)
if (TTMaskHasType(rmask, s))
TTMaskSetMask(&DBConnectTbl[base], &DBConnectTbl[s]);
/* Only need to start above "base"; the mirror-image */
/* connection is ensured by the code below. */
for (s = base + 1; s < DBNumTypes; s++)
{
smask = DBResidueMask(s);
TTMaskAndMask3(&cmask, smask, rmask);
if (!TTMaskIsZero(&cmask))
TTMaskSetType(&DBConnectTbl[base], s);
}
}
/* Make the connectivity matrix symmetric */
for (base = TT_TECHDEPBASE; base < DBNumTypes; base++)
for (s = TT_TECHDEPBASE; s < DBNumTypes; s++)
if (TTMaskHasType(&DBConnectTbl[base], s))
TTMaskSetType(&DBConnectTbl[s], base);
/* Construct DBNotConnectTbl[] */
/* For purposes of connectivity searching, this is not exactly the */
/* complement of DBConnectTbl[]. For non-contact layers, it is. */
/* For contact images, we compute differently to account for */
/* contacts being stacked by having different parts in different */
/* cells, which requires a different mask. */
for (base = 0; base < TT_MAXTYPES; base++)
TTMaskCom2(&DBNotConnectTbl[base], &DBConnectTbl[base]);
for (n = 0; n < dbNumContacts; n++)
{
lp = dbContactInfo[n];
TTMaskSetOnlyType(&DBNotConnectTbl[lp->l_type], lp->l_type);
rMask = DBResidueMask(lp->l_type);
/* Different contact types may share residues. */
/* Use TTMaskIntersect(), not TTMaskEqual()---types */
/* which otherwise stack may be in separate cells. */
for (s = 0; s < dbNumContacts; s++)
{
ls = dbContactInfo[s];
cMask = DBResidueMask(ls->l_type);
if (TTMaskIntersect(rMask, cMask))
TTMaskSetType(&DBNotConnectTbl[lp->l_type], ls->l_type);
}
/* The mask of contact types must include all stacked contacts */
for (base = DBNumUserLayers; base < DBNumTypes; base++)
{
cMask = DBResidueMask(base);
if (TTMaskHasType(cMask, lp->l_type))
TTMaskSetType(&DBNotConnectTbl[lp->l_type], base);
}
/* Note that everything above counted for all the */
/* connecting types. Invert this to get non-connecting */
/* types. */
TTMaskCom(&DBNotConnectTbl[lp->l_type]);
}
/*
* DBConnPlanes[] is nonzero only for contact images, for which
* it shows the planes connected to an image. It is the
* responsibility of the routine examining this value to exclude
* the plane being searched, if necessary.
*/
for (n = 0; n < dbNumContacts; n++)
{
lp = dbContactInfo[n];
DBConnPlanes[lp->l_type] = lp->l_pmask;
}
/*
* Now finally construct DBAllConnPlanes, which will be non-zero
* for those planes to which each type 'base' connects, exclusive
* of its home plane and those planes to which it connects as a
* contact.
*/
for (base = TT_TECHDEPBASE; base < DBNumTypes; base++)
{
DBAllConnPlanes[base] = DBTechTypesToPlanes(&DBConnectTbl[base]);
DBAllConnPlanes[base] &= ~(PlaneNumToMaskBit(DBPlane(base)));
DBAllConnPlanes[base] &= ~DBConnPlanes[base];
}
}

777
database/DBtechname.c Normal file
View File

@ -0,0 +1,777 @@
/*
* DBtechname.c --
*
* Mapping between tile types and their names.
* WARNING: with the exception of DB*TechName{Type,Plane}() and
* DB*ShortName(), * the procedures in this file MUST be called
* after DBTechFinalType() has been called.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBtechname.c,v 1.3 2008/06/01 18:37:39 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "tcltk/tclmagic.h"
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/utils.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "utils/tech.h"
#include "textio/textio.h"
#include "utils/malloc.h"
/*
* ----------------------------------------------------------------------------
*
* DBTechNameType --
*
* Map from a type name into a type number. If the type name has
* the form "<type>/<plane>" and <type> is a contact, then the
* type returned is the image of the contact on <plane>. Of
* course, in this case, <type> must have an image on <plane>.
*
* Results:
* Type number. A value of -2 indicates that the type name was
* unknown; -1 indicates that it was ambiguous.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
TileType
DBTechNameType(typename)
char *typename; /* The name of the type */
{
char *slash;
TileType type;
int plane;
LayerInfo *lp;
slash = strchr(typename, '/');
if (slash != NULL) *slash = 0;
type = (TileType)(spointertype) dbTechNameLookup(typename, &dbTypeNameLists);
if (type < 0)
{
/* Check against the alias table. However, any specified alias */
/* must point to a SINGLE tile type, or we treat it as */
/* ambiguous. */
HashEntry *he;
TileTypeBitMask *bitmask;
TileType ttest;
he = HashLookOnly(&DBTypeAliasTable, typename);
if (he)
{
bitmask = (TileTypeBitMask *)HashGetValue(he);
for (type = TT_TECHDEPBASE; type < DBNumUserLayers; type++)
if (TTMaskHasType(bitmask, type))
{
for (ttest = type + 1; ttest < DBNumUserLayers; ttest++)
if (TTMaskHasType(bitmask, ttest))
{
type = -1;
break;
}
break;
}
if (type == DBNumUserLayers)
type = -2;
}
}
if (slash == NULL) return type;
*slash = '/';
if (type < 0) return type;
/* There's a plane qualification. Make sure the type exists */
/* on the indicated plane. If not, return an error. */
plane = (spointertype) dbTechNameLookup(slash + 1, &dbPlaneNameLists);
if (plane < 0) return -2;
lp = &dbLayerInfo[type];
if (PlaneMaskHasPlane(lp->l_pmask, plane))
return type;
return -2;
}
TileType
DBTechNameTypeExact(typename)
char *typename; /* The name of the type */
{
char *slash;
ClientData result;
slash = strchr(typename, '/');
if (slash != NULL) return (TileType)(-1);
result = dbTechNameLookupExact(typename, &dbTypeNameLists);
return (TileType)((spointertype)result);
}
/*
*-------------------------------------------------------------------------
*
* The following returns a bitmask with the appropriate types set for the
* typename supplied.
*
* Results: returns the first type found
*
* Side Effects: sets bitmask with the appropriate types.
*
*-------------------------------------------------------------------------
*/
TileType
DBTechNameTypes(typename, bitmask)
char *typename; /* The name of the type */
TileTypeBitMask *bitmask;
{
char *slash;
TileType type;
int plane;
LayerInfo *lp;
TTMaskZero(bitmask);
slash = strchr(typename, '/');
if (slash != NULL) *slash = 0;
type = (TileType)(spointertype) dbTechNameLookup(typename, &dbTypeNameLists);
if (type < 0)
{
HashEntry *he;
/* Check against the alias table */
he = HashLookOnly(&DBTypeAliasTable, typename);
if (he)
{
TTMaskSetMask(bitmask, (TileTypeBitMask *)HashGetValue(he));
for (type = TT_TECHDEPBASE; type < DBNumUserLayers; type++)
if (TTMaskHasType(bitmask, type))
break;
if (type == DBNumUserLayers)
type = -2;
}
}
else
TTMaskSetType(bitmask, type);
if (slash == NULL)
return type;
else
*slash = '/';
/* There's a plane qualification. Locate the image. */
plane = (spointertype) dbTechNameLookup(slash + 1, &dbPlaneNameLists);
if (plane < 0) return -2;
TTMaskAndMask(bitmask, &DBPlaneTypes[plane]);
/* If the type is no longer in the bitmask, return the first type that is. */
if (!TTMaskHasType(bitmask, type))
for (type = TT_TECHDEPBASE; type < DBNumUserLayers; type++)
if (TTMaskHasType(bitmask, type))
break;
return (type < DBNumUserLayers) ? type : -2;
}
/*
* ----------------------------------------------------------------------------
*
* DBTechNoisyNameType --
*
* Map from a type name into a type number, complaining if the type
* is unknown.
*
* Results:
* Type number. A value of -2 indicates that the type name was
* unknown; -1 indicates that it was ambiguous.
*
* Side effects:
* Prints a diagnostic message if the type name is unknown.
*
* ----------------------------------------------------------------------------
*/
TileType
DBTechNoisyNameType(typename)
char *typename; /* The name of the type */
{
TileType type;
switch (type = DBTechNameType(typename))
{
case -1:
TechError("Ambiguous layer (type) name \"%s\"\n", typename);
break;
case -2:
TechError("Unrecognized layer (type) name \"%s\"\n", typename);
break;
default:
if (type < 0)
TechError("Funny type \"%s\" returned %d\n", typename, type);
break;
}
return (type);
}
/*
* ----------------------------------------------------------------------------
*
* DBTechNamePlane --
*
* Map from a plane name into a plane number.
*
* Results:
* Plane number. A value of -2 indicates that the plane name was
* unknown; -1 indicates that it was ambiguous.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
DBTechNamePlane(planename)
char *planename; /* The name of the plane */
{
return ((spointertype) dbTechNameLookup(planename, &dbPlaneNameLists));
}
/*
* ----------------------------------------------------------------------------
*
* DBTechNoisyNamePlane --
*
* Map from a plane name into a plane number, complaining if the plane
* is unknown.
*
* Results:
* Plane number. A value of -2 indicates that the plane name was
* unknown; -1 indicates that it was ambiguous.
*
* Side effects:
* Prints a diagnostic message if the type name is unknown.
*
* ----------------------------------------------------------------------------
*/
int
DBTechNoisyNamePlane(planename)
char *planename; /* The name of the plane */
{
int pNum;
switch (pNum = DBTechNamePlane(planename))
{
case -1:
TechError("Ambiguous plane name \"%s\"\n", planename);
break;
case -2:
TechError("Unrecognized plane name \"%s\"\n", planename);
break;
}
return (pNum);
}
/*
* ----------------------------------------------------------------------------
*
* DBTypeShortName --
* DBPlaneShortName --
*
* Return the short name for a type or plane.
* The short name is the "official abbreviation" for the type or plane,
* identified by a leading '*' in the list of names in the technology
* file.
*
* Results:
* Pointer to the primary short name for the given type or plane.
* If the type or plane has no official abbreviation, returns
* a pointer to the string "???".
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
char *
DBTypeShortName(type)
TileType type;
{
NameList *tbl;
for (tbl = dbTypeNameLists.sn_next;
tbl != &dbTypeNameLists;
tbl = tbl->sn_next)
{
if (tbl->sn_value == (ClientData)(pointertype) type && tbl->sn_primary)
return (tbl->sn_name);
}
if (type < 0) return ("ERROR");
else if (DBTypeLongNameTbl[type])
return (DBTypeLongNameTbl[type]);
return ("???");
}
char *
DBPlaneShortName(pNum)
int pNum;
{
NameList *tbl;
for (tbl = dbPlaneNameLists.sn_next;
tbl != &dbPlaneNameLists;
tbl = tbl->sn_next)
{
if (tbl->sn_value == (ClientData)(pointertype) pNum && tbl->sn_primary)
return (tbl->sn_name);
}
if (DBPlaneLongNameTbl[pNum])
return (DBPlaneLongNameTbl[pNum]);
return ("???");
}
/*
* ----------------------------------------------------------------------------
*
* DBTechTypesToPlanes --
*
* Convert a TileTypeBitMask into a mask of the planes which may
* contain tiles of that type.
*
* Results:
* A mask with bits set for those planes in which tiles of
* the types specified by the mask may reside. The mask
* is guaranteed only to contain bits corresponding to
* paint tile planes.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
PlaneMask
DBTechTypesToPlanes(mask)
TileTypeBitMask *mask;
{
TileType t;
PlaneMask planeMask, noCellMask, retMask;
/* Space tiles are present in all planes but the cell plane */
noCellMask = ~(PlaneNumToMaskBit(PL_CELL));
if (TTMaskHasType(mask, TT_SPACE)) {
retMask = PlaneNumToMaskBit(DBNumPlanes) - 1;
retMask &= noCellMask;
return retMask;
}
planeMask = 0;
for (t = 0; t < DBNumTypes; t++)
if (TTMaskHasType(mask, t))
planeMask |= DBTypePlaneMaskTbl[t];
retMask = planeMask & noCellMask;
return retMask;
}
/*
* ----------------------------------------------------------------------------
*
* DBTechPrintTypes --
*
* This routine prints out all the layer names for types defined
* in the current technology. If "typename" is non-NULL, then
* the "canonical" name of typename is printed.
*
* Results:
* None. In the Tcl version, the layer names are returned as a Tcl list.
*
* Side effects:
* Stuff is printed.
*
* ----------------------------------------------------------------------------
*/
void
DBTechPrintTypes(mask, dolist)
TileTypeBitMask *mask; /* Print layers defined by this mask. */
bool dolist; /* return as a list and don't print aliases */
{
TileType i;
NameList *p;
bool firstline = TRUE;
bool firstname;
DefaultType *dtp;
char *keepname;
if (!dolist) TxPrintf("Layer names are:\n");
/* List technology-dependent types */
for (i = TT_TECHDEPBASE; i < DBNumUserLayers; i++)
{
if (!TTMaskHasType(mask, i)) continue;
firstname = TRUE;
for (p = dbTypeNameLists.sn_next; p != &dbTypeNameLists;
p = p->sn_next)
{
if (((TileType)(spointertype) p->sn_value) == i)
{
if (dolist)
{
if (firstname) keepname = p->sn_name;
else if (strlen(p->sn_name) > strlen(keepname))
keepname = p->sn_name;
}
else
{
if (firstname) TxPrintf(" %s", p->sn_name);
else TxPrintf(" or %s", p->sn_name);
}
firstname = FALSE;
}
}
if (!firstline)
{
if (dolist)
{
#ifdef MAGIC_WRAPPER
Tcl_AppendResult(magicinterp, " ", (char *)NULL);
#else
TxPrintf(" ", keepname);
#endif
}
}
if (dolist)
{
#ifdef MAGIC_WRAPPER
Tcl_AppendResult(magicinterp, keepname, (char *)NULL);
#else
TxPrintf("%s", keepname);
#endif
}
else TxPrintf("\n");
firstline = FALSE;
}
/* List built-in types that are normally painted by name */
for (dtp = dbTechDefaultTypes; dtp->dt_names; dtp++)
{
if (!TTMaskHasType(mask, dtp->dt_type)) continue;
if (dtp->dt_print)
{
firstname = TRUE;
for (p = dbTypeNameLists.sn_next; p != &dbTypeNameLists;
p = p->sn_next)
{
if (((TileType)(spointertype) p->sn_value) == dtp->dt_type)
{
if (dolist)
{
if (firstname) keepname = p->sn_name;
else if (strlen(p->sn_name) > strlen(keepname))
keepname = p->sn_name;
}
else
{
if (firstname) TxPrintf(" %s", p->sn_name);
else TxPrintf(" or %s", p->sn_name);
}
firstname = FALSE;
}
}
if (!firstline)
{
if (dolist)
{
#ifdef MAGIC_WRAPPER
Tcl_AppendResult(magicinterp, " ", (char *)NULL);
#else
TxPrintf(" ", keepname);
#endif
}
}
if (dolist)
{
#ifdef MAGIC_WRAPPER
Tcl_AppendResult(magicinterp, keepname, (char *)NULL);
#else
TxPrintf("%s", keepname);
#endif
}
else TxPrintf("\n");
firstline = FALSE;
}
}
}
/*
* ----------------------------------------------------------------------------
*
* DBTechNoisyNameMask --
*
* Parses an argument string that selects a group of layers.
* The string may contain one or more layer names separated
* by commas. The special layer name of "0" specifies no layer,
* it is used as a place holder, e.g., to specify a null
* layer list for the CornerTypes field in a drc edge-rule.
* In addition, a tilde may be used to indicate
* "all layers but", and parentheses may be used for grouping.
* Thus ~x means "all layers but x", and ~(x,y),z means "z plus
* everything except x and y)". When contacts are specified,
* ALL images of the contact are automatically included, unless
* a specific plane is indicated in the layer specification
* using "/". For example, x/foo refers to the image of contact
* "x" on plane "foo". The layer specification may also follow
* a parenthesized group. For example, ~(x,y)/foo refers to
* all layers on plane "foo" except "x" and "y".
*
* Magic version 7.3 defines *x to mean "x and all
* contact layers containing x as a residue". Thus, for example,
* *metal1 expands to m1,pc,ndc,pdc,nsc,psc,m2c,... Because many
* connect, cif, extract, and drc rules list all these layers,
* the asterisk notation makes the techfile shorter and more
* readable.
*
* Magic version 7.3 also defines a hash table "DBTypeAliasTable"
* that allows macros to be embedded in the technology file.
* Macros are expanded first, prior to applying the parsing
* described above.
*
* Results:
* Returns a plane mask of all the planes specified.
*
* Side effects:
* Error messages are output if layers aren't understood.
* Sets the TileTypeBitMask 'mask' to all the layer names indicated.
*
* ----------------------------------------------------------------------------
*/
PlaneMask
DBTechNoisyNameMask(layers, mask)
char *layers; /* String to be parsed. */
TileTypeBitMask *mask; /* Where to store the layer mask. */
{
char *p, *p2, c;
TileTypeBitMask m2; /* Each time around the loop, we will
* form the mask for one section of
* the layer string.
*/
char save;
bool allBut;
PlaneMask planemask = 0;
TileTypeBitMask *rMask;
TTMaskZero(mask);
p = layers;
while (TRUE)
{
TTMaskZero(&m2);
c = *p;
if (c == 0) break;
/* Check for a tilde, and remember it in order to do negation. */
if (c == '~')
{
allBut = TRUE;
p += 1;
c = *p;
}
else allBut = FALSE;
/* Check for parentheses. If there's an open parenthesis,
* find the matching close parenthesis and recursively parse
* the string in-between.
*/
if (c == '(')
{
int nesting = 0;
p += 1;
for (p2 = p; ; p2 += 1)
{
if (*p2 == '(') nesting += 1;
else if (*p2 == ')')
{
nesting -= 1;
if (nesting < 0) break;
}
else if (*p2 == 0)
{
TechError("Unmatched parenthesis in layer name \"%s\".\n",
layers);
break;
}
}
save = *p2;
*p2 = 0;
planemask |= DBTechNoisyNameMask(p, &m2);
*p2 = save;
if (save == ')') p = p2 + 1;
else p = p2;
}
else
{
TileType t, rtype;
bool allResidues = FALSE;
/* No parenthesis, so just parse off a single name. Layer
* name "0" corresponds to no layers at all.
*/
for (p2 = p; ; p2++)
{
c = *p2;
if ((c == '/') || (c == ',') || (c == 0)) break;
}
if (p2 == p)
{
TechError("Missing layer name in \"%s\".\n", layers);
}
else if (strcmp(p, "0") != 0)
{
HashEntry *he;
save = *p2;
*p2 = '\0';
/* Check the alias table for macro definitions */
he = HashLookOnly(&DBTypeAliasTable, p);
if (he)
{
TileTypeBitMask *amask;
amask = (TileTypeBitMask *)HashGetValue(he);
TTMaskSetMask(&m2, amask);
}
else
{
/* Check for asterisk notation, meaning to include */
/* all types which have this type as a residue. */
if (*p == '*')
{
allResidues = TRUE;
p++;
}
t = DBTechNoisyNameType(p);
if (t >= 0)
m2 = DBLayerTypeMaskTbl[t];
/* Include all types which have t as a residue */
if (allResidues)
for (rtype = TT_TECHDEPBASE; rtype < DBNumUserLayers; rtype++)
{
rMask = DBResidueMask(rtype);
if (TTMaskHasType(rMask, t))
TTMaskSetType(&m2, rtype);
}
/* Include all stacking types which have t as a residue */
/* (this is done regardless of the presence of "*") */
for (rtype = DBNumUserLayers; rtype < DBNumTypes; rtype++)
{
rMask = DBResidueMask(rtype);
if (TTMaskIntersect(rMask, &m2))
TTMaskSetType(&m2, rtype);
}
}
*p2 = save;
}
p = p2;
}
/* Now negate the layers, if that is called for. */
if (allBut) TTMaskCom(&m2);
/* Restrict to a single plane, if that is called for. */
if (*p == '/')
{
int plane;
p2 = p+1;
while ((*p2 != 0) && (*p2 != ',')) p2 += 1;
save = *p2;
*p2 = 0;
plane = DBTechNoisyNamePlane(p+1);
*p2 = save;
p = p2;
if (plane > 0)
{
TTMaskAndMask(&m2, &DBPlaneTypes[plane]);
planemask = PlaneNumToMaskBit(plane);
}
}
else
{
TileType t;
for (t = TT_TECHDEPBASE; t < DBNumUserLayers; t++)
if (TTMaskHasType(&m2, t))
planemask |= DBTypePlaneMaskTbl[t];
}
TTMaskSetMask(mask, &m2);
while (*p == ',') p++;
}
/* If there are no types, or if "space" is the only type, then */
/* return a full planemask */
if ((TTMaskIsZero(mask) || TTMaskEqual(mask, &DBSpaceBits)) &&
(planemask == (PlaneMask)0))
planemask = DBTypePlaneMaskTbl[TT_SPACE];
return planemask;
}

826
database/DBtechtype.c Normal file
View File

@ -0,0 +1,826 @@
/*
* DBtechtype.c --
*
* Creation of tile and plane types and their names.
* Lookup procedures are in DBtechname.c
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBtechtype.c,v 1.2 2008/09/05 13:56:25 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/utils.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "utils/tech.h"
#include "textio/textio.h"
#include "utils/malloc.h"
/* Types and their names */
int DBNumTypes;
char *DBTypeLongNameTbl[NT];
int DBTypePlaneTbl[NT]; /* Normally accessed as macro "DBPlane(x)" */
NameList dbTypeNameLists = {NULL, NULL, NULL, (ClientData)0, FALSE};
HashTable DBTypeAliasTable;
/* Planes and their names */
int DBNumPlanes;
char *DBPlaneLongNameTbl[PL_MAXTYPES];
NameList dbPlaneNameLists = {NULL, NULL, NULL, (ClientData)0, FALSE};
/*
* Sets of types.
* These are generated after the "types" section of the
* technology file has been read, but before any automatically
* generated types (contact images) are created.
*/
int DBNumUserLayers;
TileTypeBitMask DBZeroTypeBits;
TileTypeBitMask DBAllTypeBits;
TileTypeBitMask DBBuiltinLayerBits;
TileTypeBitMask DBAllButSpaceBits;
TileTypeBitMask DBAllButSpaceAndDRCBits;
TileTypeBitMask DBSpaceBits;
TileTypeBitMask DBUserLayerBits;
TileTypeBitMask DBActiveLayerBits; /* Layers that are locked */
TileTypeBitMask DBTechActiveLayerBits; /* Layers marked locked in the techfile */
/* Table of default, builtin planes */
DefaultPlane dbTechDefaultPlanes[] =
{
PL_CELL, "subcell",
PL_DRC_ERROR, "designRuleError",
PL_DRC_CHECK, "designRuleCheck",
PL_M_HINT, "mhint",
PL_F_HINT, "fhint",
PL_R_HINT, "rhint",
0, 0, 0
};
/* Table of default, builtin types */
DefaultType dbTechDefaultTypes[] =
{
TT_SPACE, -1, "space", FALSE,
TT_CHECKPAINT, PL_DRC_CHECK, "checkpaint,CP", FALSE,
TT_CHECKSUBCELL, PL_DRC_CHECK, "checksubcell,CS", FALSE,
TT_ERROR_P, PL_DRC_ERROR, "error_p,EP", FALSE,
TT_ERROR_S, PL_DRC_ERROR, "error_s,ES", FALSE,
TT_ERROR_PS, PL_DRC_ERROR, "error_ps,EPS", FALSE,
TT_MAGNET, PL_M_HINT, "magnet,mag", TRUE,
TT_FENCE, PL_F_HINT, "fence,f", TRUE,
TT_ROTATE, PL_R_HINT, "rotate,r", TRUE,
0, 0, NULL, 0
};
/* Forward declarations */
char *dbTechNameAdd();
NameList *dbTechNameAddOne();
/*
* ----------------------------------------------------------------------------
*
* DBTechInitPlane --
*
* Initialize the default plane information.
*
* Results:
* None.
*
* Side effects:
* Initializes DBNumPlanes to PL_TECHDEPBASE.
* Initializes DBPlaneLongNameTbl[] for builtin planes.
*
* ----------------------------------------------------------------------------
*/
void
DBTechInitPlane()
{
DefaultPlane *dpp;
char *cp;
/* Clear out any old information */
if (dbPlaneNameLists.sn_next != NULL)
{
NameList *tbl;
for (tbl = dbPlaneNameLists.sn_next; tbl != &dbPlaneNameLists;
tbl = tbl->sn_next)
{
freeMagic(tbl->sn_name);
freeMagic(tbl);
}
}
/* Tables of short names */
dbPlaneNameLists.sn_next = &dbPlaneNameLists;
dbPlaneNameLists.sn_prev = &dbPlaneNameLists;
for (dpp = dbTechDefaultPlanes; dpp->dp_names; dpp++)
{
cp = dbTechNameAdd(dpp->dp_names, (ClientData) dpp->dp_plane,
&dbPlaneNameLists);
if (cp == NULL)
{
TxError("DBTechInit: can't add plane names %s\n", dpp->dp_names);
niceabort();
}
DBPlaneLongNameTbl[dpp->dp_plane] = cp;
}
DBNumPlanes = PL_TECHDEPBASE;
}
/*
* ----------------------------------------------------------------------------
*
* DBTypeInit --
*
* Initialization routine for the types database on startup (runs only
* once).
*
* Results:
* None.
*
* Side effects:
* Hash table initialization.
*
* ----------------------------------------------------------------------------
*/
void
DBTypeInit()
{
HashInit(&DBTypeAliasTable, 8, HT_STRINGKEYS);
}
/*
* ----------------------------------------------------------------------------
*
* DBTechInitType --
*
* Add the names and planes of the builtin types.
*
* Results:
* None.
*
* Side effects:
* See above.
* Initializes DBNumTypes to TT_TECHDEPBASE.
*
* ----------------------------------------------------------------------------
*/
void
DBTechInitType()
{
DefaultType *dtp;
char *cp;
/* Clear out any old information */
if (dbTypeNameLists.sn_next != NULL)
{
NameList *tbl;
for (tbl = dbTypeNameLists.sn_next; tbl != &dbTypeNameLists;
tbl = tbl->sn_next)
{
freeMagic(tbl->sn_name);
freeMagic(tbl);
}
}
/* Tables of short names */
dbTypeNameLists.sn_next = &dbTypeNameLists;
dbTypeNameLists.sn_prev = &dbTypeNameLists;
/*
* Add the type names to the list of known names, and set
* the default plane for each type.
*/
for (dtp = dbTechDefaultTypes; dtp->dt_names; dtp++)
{
cp = dbTechNameAdd(dtp->dt_names, (ClientData) dtp->dt_type,
&dbTypeNameLists);
if (cp == NULL)
{
TxError("DBTechInit: can't add type names %s\n", dtp->dt_names);
niceabort();
}
DBTypeLongNameTbl[dtp->dt_type] = cp;
DBPlane(dtp->dt_type) = dtp->dt_plane;
TTMaskSetOnlyType(&DBLayerTypeMaskTbl[dtp->dt_type], dtp->dt_type);
}
/* Zero the active layers (this mask is inverted later) */
TTMaskZero(&DBActiveLayerBits);
/* Hash table of layer aliases, free'ing the allocated type masks */
HashFreeKill(&DBTypeAliasTable);
HashInit(&DBTypeAliasTable, 8, HT_STRINGKEYS);
DBNumTypes = TT_TECHDEPBASE;
}
/*
* ----------------------------------------------------------------------------
*
* DBTechAddPlane --
*
* Define a tile plane type for the new technology.
*
* Results:
* TRUE if successful, FALSE on error
*
* Side effects:
* Updates the database technology variables.
* In particular, updates the number of known tile planes.
*
* ----------------------------------------------------------------------------
*/
/*ARGSUSED*/
bool
DBTechAddPlane(sectionName, argc, argv)
char *sectionName;
int argc;
char *argv[];
{
char *cp;
if (DBNumPlanes >= PL_MAXTYPES)
{
TechError("Too many tile planes (max=%d)\n", PL_MAXTYPES);
return FALSE;
}
if (argc != 1)
{
TechError("Line must contain names for plane\n");
return FALSE;
}
cp = dbTechNameAdd(argv[0], (ClientData) DBNumPlanes, &dbPlaneNameLists);
if (cp == NULL)
return FALSE;
DBPlaneLongNameTbl[DBNumPlanes++] = cp;
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* DBTechAddNameToType --
*
* Add a new name (alias) to an existing tile type.
*
* Results:
* None.
*
* Side Effects:
* Adds "newname" to dbTypeNameLists. May change the primary name
* of the type stored in the pointer array DBTypeLongNameTbl[].
*
* ----------------------------------------------------------------------------
*/
void
DBTechAddNameToType(newname, ttype, canonical)
char *newname;
TileType ttype;
bool canonical;
{
char *cp;
cp = dbTechNameAdd(newname, (ClientData) ttype, &dbTypeNameLists);
if (canonical)
DBTypeLongNameTbl[ttype] = cp;
}
/*
* ----------------------------------------------------------------------------
*
* DBTechAddAlias --
*
* Define an alias representing a mask of one or more tiletypes
*
* Results:
* TRUE if successful, FALSE on error. Returns TRUE on some
* errors that may not necessarily be fatal.
*
* Side effects:
* Updates the database technology variables.
* In particular, updates the alias hash table.
*
* ----------------------------------------------------------------------------
*/
bool
DBTechAddAlias(sectionName, argc, argv)
char *sectionName;
int argc;
char *argv[];
{
char *cp;
int pNum;
HashEntry *he;
TileType atype;
TileTypeBitMask *amask, tmask;
if (argc < 2)
{
TechError("Line must contain at least 2 fields\n");
return TRUE;
}
/* First check that the alias name does not shadow an existing type */
if (DBTechNameTypeExact(argv[0]) >= 0)
{
TechError("Type alias \"%s\" shadows a defined type\n", argv[0]);
return TRUE;
}
/* Next, check the type list. If there is only one type, then */
/* add the name to the type's names as usual, instead of adding */
/* it to the alias hash table, which is meant for names that */
/* map to multiple types. */
DBTechNoisyNameMask(argv[1], &tmask);
if ((atype = DBTechNameType(argv[1])) >= 0)
if (TTMaskEqual(&DBLayerTypeMaskTbl[atype], &tmask))
{
DBTechAddNameToType(argv[0], atype, FALSE);
return TRUE;
}
he = HashFind(&DBTypeAliasTable, argv[0]);
amask = (TileTypeBitMask *)HashGetValue(he);
if (amask == NULL)
{
amask = (TileTypeBitMask *)mallocMagic(sizeof(TileTypeBitMask));
TTMaskZero(amask);
TTMaskSetMask(amask, &tmask);
HashSetValue(he, amask);
}
else
{
TechError("Type \"%s\" is already defined and cannot be an alias\n",
argv[0]);
return TRUE;
}
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* DBTechAddType --
*
* Define a tile type for the new technology.
*
* Results:
* TRUE if successful, FALSE on error. Returns TRUE on some
* errors that may not necessarily be fatal.
*
* Side effects:
* Updates the database technology variables.
* In particular, updates the number of known tile types.
*
* ----------------------------------------------------------------------------
*/
/*ARGSUSED*/
bool
DBTechAddType(sectionName, argc, argv)
char *sectionName;
int argc;
char *argv[];
{
char *cp;
int pNum;
if (DBNumTypes >= TT_MAXTYPES-TT_RESERVEDTYPES)
{
TechError("Too many tile types (max=%d)\n",
TT_MAXTYPES-TT_RESERVEDTYPES);
return FALSE;
}
if (argc < 2)
{
TechError("Line must contain at least 2 fields\n");
return TRUE;
}
if (!strcmp(argv[0], "alias"))
{
/* Check that we have not used "*" in the alias list, since if */
/* we define aliases in the "types" section (which is allowed */
/* for backwards compatibility), the contacts have not yet been */
/* defined. */
if (strchr(argv[2], '*') != NULL)
{
TechError("Type alias \"%s\" contains the wildcard character "
"\"*\" (alias ignored).\n"
"Perhaps you want to define aliases in "
"the \"alias\" section?\n", argv[2]);
return TRUE;
}
return (DBTechAddAlias(sectionName, argc - 1, argv + 1));
}
else
{
cp = dbTechNameAdd(argv[1], (ClientData) DBNumTypes, &dbTypeNameLists);
if (cp == NULL)
return FALSE;
/* Set the lock layer bit if the plane name begins with '-' */
if (*argv[0] == LOCKLAYERCHAR)
{
TTMaskSetType(&DBActiveLayerBits, DBNumTypes);
argv[0]++;
}
pNum = DBTechNoisyNamePlane(argv[0]);
if (pNum < 0)
return FALSE;
DBTypeLongNameTbl[DBNumTypes] = cp;
DBPlane(DBNumTypes) = pNum;
TTMaskSetOnlyType(&DBLayerTypeMaskTbl[DBNumTypes], DBNumTypes);
DBNumTypes++;
}
return TRUE;
}
/*
* ----------------------------------------------------------------------------
* dbTechNewStackedType --
*
* Generate a new tiletype for a stacked layer (generally speaking,
* a stacked contact). Return the new tile type for the stacked
* contact type.
*
* Results:
* The new tile type
*
* Side effects:
* Updates the name tables with the new type name. Note that other
* tables, such as the home plane table, are not affected by this
* routine.
* ----------------------------------------------------------------------------
*/
TileType
dbTechNewStackedType(type1, type2)
TileType type1, type2;
{
char buf[1024], *cp;
if (DBNumTypes >= TT_MAXTYPES - TT_RESERVEDTYPES)
{
TechError("Too many types to generate a new contact. Maximum=%d\n",
TT_MAXTYPES - TT_RESERVEDTYPES);
return (TileType) -1;
}
sprintf(buf, "%s+%s", DBTypeShortName(type1), DBTypeShortName(type2));
cp = dbTechNameAdd(buf, (ClientData) DBNumTypes, &dbTypeNameLists);
if (cp == NULL)
{
TechError("Couldn't generate new stacking type %s\n", buf);
return (TileType) -1;
}
DBTypeLongNameTbl[DBNumTypes] = cp;
return DBNumTypes++;
}
/*
* ----------------------------------------------------------------------------
*
* DBTechFinalType --
*
* After processing the types and planes sections, compute the
* various derived type and plane masks and tables.
*
* Results:
* None.
*
* Side effects:
* Initializes DBNumUserLayers to be DBNumTypes at the time
* this procedure is called, since none of the automatically
* generated plane images have yet been created.
* Initializes the following bit masks:
* DBAllTypeBits
* DBSpaceBits
* DBBuiltinLayerBits
* DBAllButSpaceBits
* DBAllButSpaceAndDRCBits
* DBUserLayerBits
*
* ----------------------------------------------------------------------------
*/
void
DBTechFinalType()
{
TileType i;
int pNum;
DBNumUserLayers = DBNumTypes;
for (i = 0; i < TT_MAXTYPES; i++)
{
if (i >= TT_SELECTBASE)
TTMaskSetType(&DBAllButSpaceAndDRCBits, i);
if (i < TT_TECHDEPBASE)
TTMaskSetType(&DBBuiltinLayerBits, i);
else if (i < DBNumUserLayers)
TTMaskSetType(&DBUserLayerBits, i);
}
TTMaskCom2(&DBAllTypeBits, &DBZeroTypeBits);
TTMaskSetOnlyType(&DBSpaceBits, TT_SPACE);
TTMaskCom2(&DBAllButSpaceBits, &DBSpaceBits);
/* UserLayerBits includes space */
TTMaskSetType(&DBUserLayerBits, TT_SPACE);
/* Set locked layer bitmask */
TTMaskCom(&DBActiveLayerBits);
TTMaskAndMask(&DBActiveLayerBits, &DBAllButSpaceAndDRCBits);
/* Save this mask for later reference */
TTMaskZero(&DBTechActiveLayerBits);
TTMaskSetMask(&DBTechActiveLayerBits, &DBActiveLayerBits);
/* Space is visible on all planes but the subcell plane */
TTMaskZero(&DBPlaneTypes[PL_CELL]);
for (pNum = PL_PAINTBASE; pNum < PL_MAXTYPES; pNum++)
TTMaskSetOnlyType(&DBPlaneTypes[pNum], TT_SPACE);
}
/*
* ----------------------------------------------------------------------------
*
* dbTechNameLookupExact --
*
* Lookup a type or plane name.
* Case is significant.
*
* Results:
* Returns the ClientData associated with the given name.
* If the name was not found, we return -2. Unlike dbTechNameLookup,
* this routine requires an exact name match, and never returns -1
* (which indicates ambiguity in dbTechNameLookup()).
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
ClientData
dbTechNameLookupExact(str, table)
char *str; /* The name to be looked up */
NameList *table; /* Table of names to search */
{
NameList *top;
top = table;
while ((top = top->sn_next) != table)
if (!strcmp(top->sn_name, str))
return (top->sn_value);
return ((ClientData) -2);
}
/*
* ----------------------------------------------------------------------------
*
* dbTechNameLookup --
*
* Lookup a type or plane name.
* Case is significant.
*
* Results:
* Returns the ClientData associated with the given name.
* If the name was not found, we return -2; if it was ambiguous,
* we return -1.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
ClientData
dbTechNameLookup(str, table)
char *str; /* The name to be looked up */
NameList *table; /* Table of names to search */
{
/*
* The search is carried out by using two pointers, one which moves
* forward through list from its start, and one which moves backward
* through table from its end. The two pointers mark the range of
* strings that match the portion of str that we have scanned. When
* all of the characters of str have been scanned, then the two
* pointers better be identical, or one of the strings in the range
* between the two pointers better match 'str' exactly.
*/
NameList *bot, *top;
char currentchar;
int indx;
bot = table->sn_next;
top = table->sn_prev;
if (top == bot) return ((ClientData) -2);
for (indx = 0; ; indx++)
{
/* Check for the end of string */
currentchar = str[indx];
if (currentchar == '\0')
{
if (bot == top)
return (bot->sn_value);
/*
* Several entries match this one up to the last character
* of the string. If one is an exact match, we allow it;
* otherwise, we claim the string was ambiguous.
*/
for ( ; bot != top; bot = bot->sn_next)
if (bot->sn_name[indx] == '\0')
return (bot->sn_value);
return ((ClientData) -1);
}
/*
* Move bot up until the string it points to matches str in the
* indx'th position. Make match refer to the indx of bot in table.
*/
while (bot->sn_name[indx] != currentchar)
{
if (bot == top) return((ClientData) -2);
bot = bot->sn_next;
}
/* Move top down until it matches */
while (top->sn_name[indx] != currentchar)
{
if (bot == top) return((ClientData) -2);
top = top->sn_prev;
}
}
/*NOTREACHED*/
}
/*
* ----------------------------------------------------------------------------
*
* dbTechNameAdd --
*
* Add several names to a name table.
* The shortest name is marked as the standard "short" name
* for this cdata value.
*
* Results:
* Returns a pointer to the first name added if successful,
* or NULL if not. In this latter case, we print error messages.
*
* Side effects:
* Adds new entries to the table pointed to by *ptable, and
* modifies *ptable if necessary.
*
* ----------------------------------------------------------------------------
*/
char *
dbTechNameAdd(name, cdata, ptable)
char *name; /* Comma-separated list of names to be added */
ClientData cdata; /* Value to be stored with each name above */
NameList *ptable; /* Table to which we will add names */
{
char *cp;
char onename[BUFSIZ];
char *first;
int shortestLength, length;
NameList *primary, *current;
if (name == NULL)
return (NULL);
first = NULL;
shortestLength = INFINITY;
primary = NULL;
while (*name)
{
if (*name == ',')
{
name++;
continue;
}
for (cp = onename; *name && *name != ','; *cp++ = *name++)
/* Nothing */;
*cp = '\0';
if (*(cp = onename))
{
if ((current = dbTechNameAddOne(cp, cdata, FALSE, ptable)) == NULL)
return (NULL);
if (first == NULL)
first = current->sn_name;
length = strlen(onename);
if (length < shortestLength)
shortestLength = length, primary = current;
}
}
if (primary)
primary->sn_primary = TRUE;
return (first);
}
/*
* ----------------------------------------------------------------------------
*
* dbTechNameAddOne --
*
* Add a single name to the table.
*
* Results:
* Returns a pointer to the new entry if succesful,
* or NULL if the name was already in the table.
*
* Side effects:
* See above.
*
* ----------------------------------------------------------------------------
*/
NameList *
dbTechNameAddOne(name, cdata, isPrimary, ptable)
char *name; /* Name to be added */
ClientData cdata; /* Client value associated with this name */
bool isPrimary; /* TRUE if this is the primary abbreviation */
NameList *ptable; /* Table of names to which we're adding this */
{
int cmp;
NameList *tbl, *new;
/* Sort the name into the existing list */
for (tbl = ptable->sn_next ;tbl != ptable; tbl = tbl->sn_next)
if ((cmp = strcmp(name, tbl->sn_name)) == 0)
{
TechError("Duplicate name: %s\n", name);
return (NULL);
}
else if (cmp < 0)
break;
/* Create a new name */
new = (NameList *) mallocMagic((unsigned) (sizeof (NameList)));
new->sn_name = StrDup((char **) NULL, name);
new->sn_value = cdata;
new->sn_primary = isPrimary;
/* Link this entry in to the list before 'tbl' */
new->sn_next = tbl;
new->sn_prev = tbl->sn_prev;
tbl->sn_prev->sn_next = new;
tbl->sn_prev = new;
return (new);
}

1057
database/DBtiles.c Normal file

File diff suppressed because it is too large Load Diff

295
database/DBtimestmp.c Normal file
View File

@ -0,0 +1,295 @@
/* DBtimestamp.c --
*
* Provides routines to help manage the timestamps stored in
* cell definitions.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBtimestmp.c,v 1.2 2009/05/30 03:13:59 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <sys/types.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "windows/windows.h"
#include "textio/textio.h"
#include "drc/drc.h"
#include "utils/signals.h"
#include "utils/malloc.h"
/* Overall comments:
*
* Cell timestamps are kept around primarily for the benefit
* of the design rule checker. In order for the hierarchical
* and continuous checker to work, we have to make sure that
* we know whenever cells have changed, even if a cell is
* edited out of context. Thus, we record a timestamp value
* in every cell, which is the time when the cell was last
* modified. The timestamp for a cell should always be at
* least as large as the latest timestamp for any of that
* cell's descendants (larger timestamps correspond to later
* times). If a child is edited out of context, this condition
* may be violated, so each parent keeps an expected timestamp
* for each of its children. If the actual child timestamp is
* ever found to be different, we must re-check interactions
* between that child and other pieces of the parent, and then
* update the parent's timestamp. If a child changes, then
* timestamps must be changed in all parents of the child, their
* parents, and so on, so that we're guaranteed to see interactions
* coming even from several levels up the tree.
*/
/* The structure below is used to keep track of cells whose timestamps
* mismatched. The DBStampMismatch routine creates this structure.
* at convenient times (between commands), the DBFixMismatch routine
* is called to process the entries. It updates bounding boxes (the
* bounding box update cannot be done at arbitrary times, because it
* can reorganize tile planes that are pending in searches. The
* indentation below is necessary to keep lintpick happy.
*/
typedef struct mm {
CellDef *mm_cellDef; /* CellDef whose stamp was wrong. */
Rect mm_oldArea; /* The old area that the cellDef used
* to occupy.
*/
struct mm *mm_next; /* Next mismatch record in list. */
} Mismatch;
Mismatch *mismatch = NULL; /* List head. */
/* The time value below is passed to the dbStampFunct so it
* uses the same value everywhere, and doesn't have to call
* the system routine repeatedly.
*/
int timestamp;
/*
* ----------------------------------------------------------------------------
* DBFixMismatch --
*
* This procedure is called when it safe to recompute bounding
* boxes in order to fix timestamp mismatches.
*
* Results:
* None.
*
* Side effects:
* Bounding boxes get recomputed and information gets passed to
* the DRC module. The DRC module will recheck both the old and
* new areas of the cell whose timestamp mismatched.
* ----------------------------------------------------------------------------
*/
void
DBFixMismatch()
{
CellDef *cellDef;
CellUse *parentUse;
Rect oldArea, parentArea, tmp;
int redisplay;
int firstOne = TRUE;
Mismatch *tmpm;
/* It's very important to disable interrupts during this section!
* Otherwise, we may not paint the recheck tiles properly.
*/
redisplay = FALSE;
if (mismatch == NULL) return;
TxPrintf("Processing timestamp mismatches:");
SigDisableInterrupts();
for (tmpm = mismatch; tmpm; tmpm = tmpm->mm_next)
tmpm->mm_cellDef->cd_flags &= (~CDPROCESSED);
while (mismatch != NULL)
{
/* Be careful to remove the front element from the mismatch
* list before processing it, because while processing it we
* may add new elements to the list.
*/
cellDef = mismatch->mm_cellDef;
oldArea = mismatch->mm_oldArea;
freeMagic((char *) mismatch);
mismatch = mismatch->mm_next;
if (cellDef->cd_flags & CDPROCESSED) continue;
(void) DBCellRead(cellDef, (char *) NULL, TRUE, NULL);
/* Jimmy up the cell's current bounding box, so the following
* procedure call will absolutely and positively know that
* the bbox has changed. This is necessary because not all
* the uses necessarily reflect the current def bounding box,
* and we want DBReComputeArea to be sure to update all of
* the uses.
*/
cellDef->cd_bbox.r_xtop = cellDef->cd_bbox.r_xbot - 1;
cellDef->cd_extended.r_xtop = cellDef->cd_extended.r_xbot - 1;
DBReComputeBbox(cellDef);
/* Now, for each parent, recheck the parent in both the
* old area of the child and the new area.
*/
for (parentUse = cellDef->cd_parents; parentUse != NULL;
parentUse = parentUse->cu_nextuse)
{
if (parentUse->cu_parent == NULL) continue;
DBComputeArrayArea(&oldArea, parentUse, parentUse->cu_xlo,
parentUse->cu_ylo, &parentArea);
DBComputeArrayArea(&oldArea, parentUse, parentUse->cu_xhi,
parentUse->cu_yhi, &tmp);
(void) GeoInclude(&parentArea, &tmp);
GeoTransRect(&parentUse->cu_transform, &tmp, &parentArea);
DRCCheckThis(parentUse->cu_parent, TT_CHECKSUBCELL, &parentArea);
DRCCheckThis(parentUse->cu_parent, TT_CHECKSUBCELL,
&(parentUse->cu_bbox));
redisplay = TRUE;
}
cellDef->cd_flags |= CDPROCESSED;
if (firstOne)
{
TxPrintf(" %s", cellDef->cd_name);
firstOne = FALSE;
}
else TxPrintf(", %s", cellDef->cd_name);
TxFlush(); /* This is needed to prevent _doprnt screwups */
}
SigEnableInterrupts();
TxPrintf(".\n");
TxFlush();
if (redisplay) WindAreaChanged((MagWindow *) NULL, (Rect *) NULL);
}
/*
* ----------------------------------------------------------------------------
* DBUpdateStamps --
*
* Updates all timestamps in all cells in the database.
*
* Results:
* None.
*
* Side effects:
* For every cell that has been modified, its timestamp and
* the timestamps of all its parents, grandparents, etc. are
* updated. The result is that the timestamp in any given cell is
* at least as great as the timestamps in any of its descendants.
* ----------------------------------------------------------------------------
*/
void
DBUpdateStamps()
{
extern int dbStampFunc();
extern time_t time();
DBFixMismatch();
timestamp = time((time_t *) 0);
(void) DBCellSrDefs(CDGETNEWSTAMP, dbStampFunc, (ClientData) NULL);
}
int
dbStampFunc(cellDef)
CellDef *cellDef;
{
CellUse *cu;
CellDef *cd;
/* The following check keeps us from making multiple recursive
* scans of any cell.
*/
if (cellDef->cd_timestamp == timestamp) return 0;
cellDef->cd_timestamp = timestamp;
cellDef->cd_flags &= ~CDGETNEWSTAMP;
/* printf("Writing new timestamp %d for %s.\n",
timestamp, cellDef->cd_name); */
/* If a child's stamp has changed, then the stamps must change
* in all its parents too. When the hierarchical DRC becomes
* completely operational, this recursive update may be unnecessary
* since the DRC will have painted check tiles in all ancestors.
*/
for (cu = cellDef->cd_parents; cu != NULL; cu = cu->cu_nextuse)
{
cd = cu->cu_parent;
if (cd == NULL) continue;
cd->cd_flags |= CDSTAMPSCHANGED;
(void) dbStampFunc(cd);
}
return 0;
}
/*
* ----------------------------------------------------------------------------
* DBStampMismatch --
*
* This routine is invoked when a mismatch is discovered for a
* cell. The parameter wrongArea tells what the cell's bounding
* box used to be (but the timestamp mismatch means this was
* probably wrong, so that area has to be re-design-rule-checked).
*
* Results:
* None.
*
* Side effects:
* We record the definition on a list of mismatches for later
* processing. When DBFixMismatch is called, it will notify
* the design-rule checker to recheck both wrongArea, and
* the cell's eventual correct area.
* ----------------------------------------------------------------------------
*/
void
DBStampMismatch(cellDef, wrongArea)
CellDef *cellDef;
Rect *wrongArea; /* Guess of cell's bounding box that
* was wrong.
*/
{
Mismatch *mm;
CellUse *parentUse;
mm = (Mismatch *) mallocMagic((unsigned) (sizeof (Mismatch)));
mm->mm_cellDef = cellDef;
mm->mm_oldArea = *wrongArea;
mm->mm_next = mismatch;
mismatch = mm;
for (parentUse = cellDef->cd_parents; parentUse != NULL;
parentUse = parentUse->cu_nextuse)
{
if (parentUse->cu_parent == NULL) continue;
parentUse->cu_parent->cd_flags |= CDSTAMPSCHANGED;
}
}

832
database/DBtpaint.c Normal file
View File

@ -0,0 +1,832 @@
/*
* DBtechpaint.c --
*
* Management of composition rules and the paint/erase tables.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBtpaint.c,v 1.2 2010/06/08 19:16:42 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <ctype.h>
#include <string.h> /* for memset(), memcpy() */
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/utils.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "utils/tech.h"
#include "textio/textio.h"
/* Painting and erasing tables */
PaintResultType DBPaintResultTbl[NP][NT][NT];
PaintResultType DBEraseResultTbl[NP][NT][NT];
PaintResultType DBWriteResultTbl[NT][NT];
PaintResultType DBSpecialResultTbl[NT];
PlaneMask DBTypePaintPlanesTbl[NT];
PlaneMask DBTypeErasePlanesTbl[NT];
/* ----------------- Data local to tech file processing --------------- */
/*
* Tables telling which rules are default, and which have come
* from user-specified rules. The bit is CLEAR if the type is
* a default type.
*/
TileTypeBitMask dbNotDefaultEraseTbl[NT];
TileTypeBitMask dbNotDefaultPaintTbl[NT];
/* --------------------- Data local to this file ---------------------- */
int dbNumSavedRules = 0;
Rule dbSavedRules[NT];
/* Forward declarations */
extern void dbTechBitTypeInit();
bool dbTechAddPaintErase();
bool dbTechSaveCompose();
/*
* ----------------------------------------------------------------------------
*
* DBTechInitCompose --
*
* Initialize the painting and erasing rules prior to processing
* the "compose" section. The rules for builtin types are computed
* here, as well as the default rules for all other types. This
* procedure must be called after the "types" and "contacts" sections
* have been read, since we need to know about all existing tile types.
*
* Results:
* None.
*
* Side effects:
* Modifies the paint and erase tables.
*
* ----------------------------------------------------------------------------
*/
void
DBTechInitCompose()
{
TileType s, t, r;
int ps;
PaintResultType *stype, *dtype;
TileTypeBitMask *ttype;
/* Default painting rules for error types */
static TileType errorBitToType[] =
{
TT_SPACE, /* 0 */ TT_ERROR_P, /* 1 */
TT_ERROR_S, /* 2 */ TT_ERROR_PS, /* 3 */
};
/* Painting and erasing are no-ops for undefined tile types */
/* The following code is the FAST version using memcpy(). */
/* See below for the actual slow loops. */
stype = dtype = &(DBEraseResultTbl[0][0][0]);
for (ps = 0; ps < TT_MAXTYPES; ps++)
*dtype++ = (PaintResultType)ps;
for (ps = 1; ps < PL_MAXTYPES * TT_MAXTYPES; ps++)
{
memcpy((void *)dtype, (void *)stype, (size_t)TT_MAXTYPES
* sizeof(PaintResultType));
dtype += TT_MAXTYPES;
}
/* Fast copy the entire erase table to the paint table memory */
dtype = &(DBPaintResultTbl[0][0][0]);
memcpy((void *)dtype, (void *)stype, (size_t)(TT_MAXTYPES
* TT_MAXTYPES * PL_MAXTYPES * sizeof(PaintResultType)));
/* The following code is dreadfully slow, but I'm leaving it */
/* in as a comment because it's easier to read. The code */
/* above uses memory copying tricks to speed up the process. */
/*
for (pNum = 0; pNum < PL_MAXTYPES; pNum++)
{
for (s = 0; s < TT_MAXTYPES; s++)
{
for (t = 0; t < TT_MAXTYPES; t++)
{
/- Paint and erase are no-ops -/
dbSetEraseEntry(s, t, pNum, s);
dbSetPaintEntry(s, t, pNum, s);
}
}
}
for (s = 0; s < TT_MAXTYPES; s++)
{
for (t = 0; t < TT_MAXTYPES; t++)
{
/- Write overwrites existing contents -/
dbSetWriteEntry(s, t, t);
}
}
*/
#if TT_MAXTYPES <= 256
/* For single-byte values, memset() is fastest.
dtype = &(DBWriteResultTbl[0][0]);
for (q = 0; q < TT_MAXTYPES; q++)
{
memset((void *)dtype, (int)q, (size_t)TT_MAXTYPES);
dtype += TT_MAXTYPES;
}
#else
/* This is the slow loop, but it still faster than using */
/* macro dbSetWriteEntry(). */
dtype = &(DBWriteResultTbl[0][0]);
for (t = 0; t < TT_MAXTYPES; t++)
for (s = 0; s < TT_MAXTYPES; s++)
*dtype++ = t;
#endif
/* All painting and erasing rules are default initially */
/* This is also faster than the loop below. */
ttype = &(dbNotDefaultEraseTbl[0]);
for (s = 0; s < DBNumTypes; s++) *ttype++ = DBZeroTypeBits;
ttype = &(dbNotDefaultPaintTbl[0]);
for (s = 0; s < DBNumTypes; s++) *ttype++ = DBZeroTypeBits;
/*
for (s = 0; s < DBNumTypes; s++)
{
dbNotDefaultEraseTbl[s] = DBZeroTypeBits;
dbNotDefaultPaintTbl[s] = DBZeroTypeBits;
}
*/
/*
* For each type t:
* erase(t, t, plane(t)) -> SPACE
*
* For each type s, t:
* paint(s, t, plane(t)) -> t
* paint(s, t, ~plane(t)) -> s
*/
for (s = 0; s < DBNumTypes; s++)
{
if ((ps = DBPlane(s)) > 0)
{
for (t = 0; t < DBNumTypes; t++)
{
if (DBPlane(t) > 0)
{
r = (ps == DBPlane(t)) ? t : s;
dbSetEraseEntry(s, t, ps, s);
dbSetPaintEntry(s, t, ps, r);
}
}
/* Everything can be erased to space on its home plane */
dbSetEraseEntry(s, s, ps, TT_SPACE);
/* Everything paints over space on its home plane */
dbSetPaintEntry(TT_SPACE, s, ps, s);
}
}
/*
* Special handling for check tile and error tile combinations.
*/
#define PCHK PL_DRC_CHECK
#define PERR PL_DRC_ERROR
#define tblsize(t) ( (sizeof (t)) / (sizeof (t[0])) )
dbTechBitTypeInit(errorBitToType, tblsize(errorBitToType), PERR, FALSE);
#undef tblsize
/*
* Paint results are funny for check plane because
* CHECKPAINT+CHECKSUBCELL = CHECKPAINT
*/
dbSetPaintEntry(TT_SPACE, TT_CHECKPAINT, PCHK, TT_CHECKPAINT);
dbSetPaintEntry(TT_SPACE, TT_CHECKSUBCELL, PCHK, TT_CHECKSUBCELL);
dbSetPaintEntry(TT_CHECKPAINT, TT_CHECKSUBCELL, PCHK, TT_CHECKPAINT);
dbSetPaintEntry(TT_CHECKSUBCELL, TT_CHECKPAINT, PCHK, TT_CHECKPAINT);
#undef PCHK
#undef PERR
/* Added 5/27/10: Special table used for painting non-Manhattan */
/* tiles. Uses TT_CHECKSUBCELL because that type does not exist on */
/* any paintable plane, and the checkpaint plane does not use non- */
/* manhattan tiles. */
for (s = 0; s < DBNumTypes; s++) DBSpecialResultTbl[s] = TT_CHECKSUBCELL;
}
/*
* ----------------------------------------------------------------------------
*
* dbTechBitTypeInit --
*
* Handle initialization of the paint and erase result tables for a
* set of ln2(n) primary types with n distinct mutual overlap types.
* The table bitToType points to a table containing n TileTypes
* (the overlap types) with the property that
*
* bitToType[i] and bitToType[j] combine to yield bitToType[i | j]
*
* Also (unless composeFlag is set) erasing bitToType[j] from bitToType[i]
* gives bitToType[i & (~j)],
* i.e., it clears all of the j-type material out of the i-type material.
* The bitToType[k] for which k's binary representation has only a single
* bit set in it are the "primary" types.
*
* If composeFlag is set, the above is modified slightly to be analagous
* to compose rules, specifically, erase rules for nonprimary types are
* the default rules, i.e. they only erase precisely themselves. This
* makes ":erase *-primary" work in the expected way.
*
* Results:
* None.
*
* Side effects:
* See above.
*
* ----------------------------------------------------------------------------
*/
void
dbTechBitTypeInit(bitToType, n, pNum, composeFlag)
TileType *bitToType;
int n, pNum;
bool composeFlag;
{
int i, j;
TileType have, type;
for (i = 0; i < n; i++)
{
have = bitToType[i];
for (j = 0; j < n; j++)
{
type = bitToType[j];
dbSetPaintEntry(have, type, pNum, bitToType[i | j]);
if(!composeFlag || dbIsPrimary(j))
{
dbSetEraseEntry(have, type, pNum, bitToType[i & (~j)]);
}
}
}
}
/* Returns nonzero if exactly one bit set */
int
dbIsPrimary(n)
int n;
{
int bitCount;
for(bitCount=0; n>0; n=n>>1)
{
if(n&1)
{
bitCount++;
}
}
return (bitCount==1);
}
/*
* ----------------------------------------------------------------------------
*
* DBTechAddCompose --
*
* Process a single compose/erase rule. If the type being described is
* a contact, save the rule and defer processing it until the end of this
* section, because we need to know the behavior of all non-contact types
* that might be residues before processing a contact composition rule.
* Rules for non-contact types are processed here.
*
* Results:
* TRUE if successful, FALSE on error.
*
* Side effects:
* Modifies the paint/erase tables if the type being described
* is not a contact; otherwise, appends a rule to the list of
* contact erase/compose rules for later processing. Marks the
* paint/erase table entries affected to show that they contain
* user-specified rules instead of the default ones, so we don't
* override them later.
*
* ----------------------------------------------------------------------------
*/
/*ARGSUSED*/
bool
DBTechAddCompose(sectionName, argc, argv)
char *sectionName;
int argc;
char *argv[];
{
TileType type, r, s;
int pNum, ruleType, i;
static char *ruleNames[] =
{ "compose", "decompose", "paint", "erase", 0 };
static int ruleTypes[] =
{ RULE_COMPOSE, RULE_DECOMPOSE, RULE_PAINT, RULE_ERASE };
if (argc < 4)
{
TechError("Line must contain at least ruletype, result + pair\n");
return FALSE;
}
/* Look up and skip over type of rule */
i = Lookup(*argv, ruleNames);
if (i < 0)
{
TechError("%s rule type %s. Must be one of:\n\t",
i == -1 ? "Ambiguous" : "Unknown", *argv);
for (i = 0; ruleNames[i]; i++)
TxError("\"%s\" ", ruleNames[i]);
TxError("\n");
return FALSE;
}
ruleType = ruleTypes[i];
argv++, argc--;
/* Paint or erase rules are processed specially */
switch (ruleType)
{
case RULE_PAINT:
case RULE_ERASE:
return (dbTechAddPaintErase(ruleType, sectionName, argc, argv));
}
/* Compose or decompose rule: find result type and then skip over it */
if ((type = DBTechNoisyNameType(*argv)) < 0)
return FALSE;
argv++, argc--;
if (argc & 01)
{
TechError("Types on RHS of rule must be in pairs\n");
return FALSE;
}
/* Compose/decompose rules for contacts are saved away */
if (IsContact(type))
return dbTechSaveCompose(ruleType, type, argc, argv);
/* Rules for non-contacts are processed here */
for ( ; argc > 0; argc -= 2, argv += 2)
{
if ((r = DBTechNoisyNameType(argv[0])) < 0
|| (s = DBTechNoisyNameType(argv[1])) < 0)
return FALSE;
if (IsContact(r) || IsContact(s))
{
TechError("Can't have contact layers on RHS of non-contact rule\n");
return FALSE;
}
pNum = DBPlane(r);
switch (ruleType)
{
case RULE_COMPOSE:
dbSetPaintEntry(r, s, pNum, type);
dbSetPaintEntry(s, r, pNum, type);
TTMaskSetType(&dbNotDefaultPaintTbl[r], s);
TTMaskSetType(&dbNotDefaultPaintTbl[s], r);
/* Fall through to */
case RULE_DECOMPOSE:
dbSetPaintEntry(type, r, pNum, type);
dbSetPaintEntry(type, s, pNum, type);
dbSetEraseEntry(type, r, pNum, s);
dbSetEraseEntry(type, s, pNum, r);
TTMaskSetType(&dbNotDefaultPaintTbl[type], r);
TTMaskSetType(&dbNotDefaultPaintTbl[type], s);
TTMaskSetType(&dbNotDefaultEraseTbl[type], r);
TTMaskSetType(&dbNotDefaultEraseTbl[type], s);
break;
}
}
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* dbTechSaveCompose --
*
* Save a compose rule for a contact 't' in the table dbSavedRules.
* Check to make sure the rule is legal.
*
* Results:
* Returns TRUE if successful, FALSE on error.
*
* Side effects:
* Updates dbSavedRules[] and increments dbNumSavedRules.
*
* ----------------------------------------------------------------------------
*/
bool
dbTechSaveCompose(ruleType, t, argc, argv)
int ruleType;
TileType t;
int argc;
char *argv[];
{
TileType r, s;
Rule *rp;
rp = &dbSavedRules[dbNumSavedRules++];
rp->r_ruleType = ruleType;
rp->r_result = t;
rp->r_npairs = 0;
for ( ; argc > 0; argc -= 2, argv += 2)
{
r = DBTechNoisyNameType(argv[0]);
s = DBTechNoisyNameType(argv[1]);
if (r < 0 || s < 0)
return FALSE;
/* At most one of r and s may be a contact */
if (IsContact(r) && IsContact(s))
{
TechError("Only one type in each pair may be a contact\n");
return FALSE;
}
/*
* The planes comprising 't' must be a superset of the
* planes comprising 'r' and the planes comprising 's'.
*/
if (((LayerPlaneMask(r) | LayerPlaneMask(s)) & ~LayerPlaneMask(t)) != 0)
{
TechError("Component planes are a superset of result planes\n");
return FALSE;
}
if (ruleType == RULE_COMPOSE)
{
/* Types r and s can't appear on planes outside of t's */
if ((LayerPlaneMask(r) | LayerPlaneMask(s)) != LayerPlaneMask(t))
{
TechError("Union of pair planes must = result planes\n");
return FALSE;
}
/* The following restriction has been lifted due to */
/* the recursive plane painting method added to */
/* routine DBPaint(). (Tim, 5/11/04) */
// if (!dbTechCheckImages(t, r, s) || !dbTechCheckImages(t, s, r))
// return FALSE;
}
rp->r_pairs[rp->r_npairs].rp_a = r;
rp->r_pairs[rp->r_npairs].rp_b = s;
rp->r_npairs++;
}
return TRUE;
}
#if 0 /* deprecated function (5/11/04) */
/*
* ----------------------------------------------------------------------------
*
* dbTechCheckImages --
*
* When processing a compose rule for 't' with RHS components
* 'r' and 's', check to be sure that the images of 't' on
* those planes present in 'r' but not in 's' are identical to
* the images of 'r' on those planes. This is necessary in order
* that the result on these planes not depend on types present on
* other planes.
*
* Results:
* Returns TRUE if successful, FALSE on error.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
bool
dbTechCheckImages(t, r, s)
TileType t; /* Type that is composed */
TileType r; /* First constituent */
TileType s; /* Second constituent */
{
int pNum;
PlaneMask pMask;
if (pMask = (LayerPlaneMask(r) & ~LayerPlaneMask(s)))
{
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(pMask, pNum) && (t != r))
{
TechError("Result image on plane %s must be the same "
"as image of %s on plane %s\n",
DBPlaneLongName(pNum),
DBTypeLongName(r),
DBPlaneLongName(pNum));
return FALSE;
}
}
return TRUE;
}
#endif /* 0 */
/*
* ----------------------------------------------------------------------------
*
* dbTechAddPaintErase --
*
* Add a new entry to the paint or erase table.
* The semantics is that painting a tile of type1 with paint type2
* yields a tile of typeres.
*
* Results:
* Returns TRUE if successful, FALSE on error.
*
* Side effects:
* Updates the database technology variables.
*
* ----------------------------------------------------------------------------
*/
bool
dbTechAddPaintErase(type, sectionName, argc, argv)
int type;
char *sectionName;
int argc;
char *argv[];
{
int pNum;
PlaneMask pMask, rMask;
TileType t1, t2, tres;
if (argc < 3)
{
TechError("Line must contain at least 3 types\n");
return FALSE;
}
if ((t1 = DBTechNoisyNameType(argv[0])) < 0) return FALSE;
if ((t2 = DBTechNoisyNameType(argv[1])) < 0) return FALSE;
if ((tres = DBTechNoisyNameType(argv[2])) < 0) return FALSE;
if (argc == 3)
{
if (t1 == TT_SPACE)
{
TechError("<%s, %s, %s>:\n"
"Must specify plane in paint table for "
"painting space\n",
argv[0], argv[1], argv[2]);
return FALSE;
}
else
pMask = LayerPlaneMask(t1);
}
else
{
if ((pNum = DBTechNoisyNamePlane(argv[3])) < 0) return FALSE;
else
pMask = PlaneNumToMaskBit(pNum);
}
rMask = LayerPlaneMask(tres);
/* (The plane mask of "tres" may be a subset of t1, but NOT vice */
/* versa. Otherwise we will end up creating rules that are not */
/* dependent on t1 in some planes.) */
/* This restriction lifted 5/11/04 with code in DBPaint() that */
/* recursively paints image types onto planes where they may be */
/* missed by the inability to generate the correct paint table for */
/* the operation. */
// if (rMask & ~pMask)
// {
// TechError("Planes of result type must be a subset of those of have-type\n");
// return FALSE;
// }
pMask &= ~rMask;
if (type == RULE_PAINT)
{
/* Apply to all planes of rMask. */
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(rMask, pNum))
dbSetPaintEntry(t1, t2, pNum, tres);
/* For all planes of pMask which are not in rMask, result is space */
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(pMask, pNum))
dbSetPaintEntry(t1, t2, pNum, TT_SPACE);
}
else /* (type == RULE_ERASE) */
{
/* Apply to all planes of rMask. */
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(rMask, pNum))
dbSetEraseEntry(t1, t2, pNum, tres);
/* For all planes of pMask which are not in rMask, result is space */
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(pMask, pNum))
dbSetEraseEntry(t1, t2, pNum, TT_SPACE);
}
TTMaskSetType(&dbNotDefaultPaintTbl[t1], t2);
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* dbTechCheckPaint --
*
* DEBUGGING.
* Check painting and erasing rules to make sure that the result
* type is legal for the plane being affected.
*
* Results:
* None.
*
* Side effects:
* Prints stuff in the event of an error.
*
* ----------------------------------------------------------------------------
*/
void
dbTechCheckPaint(where)
char *where; /* If non-null, print this as header */
{
TileType have, t, result;
bool printedHeader = FALSE;
for (have = TT_TECHDEPBASE; have < DBNumTypes; have++)
{
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
{
result = DBStdPaintEntry(have, t, DBPlane(have));
if (result != TT_SPACE && DBPlane(result) != DBPlane(have))
{
if (!printedHeader && where)
TxPrintf("\n%s:\n", where), printedHeader = TRUE;
TxPrintf("%s + %s -> %s\n",
DBTypeShortName(have), DBTypeShortName(t),
DBTypeShortName(result));
}
result = DBStdEraseEntry(have, t, DBPlane(have));
if (result != TT_SPACE && DBPlane(result) != DBPlane(have))
{
if (!printedHeader && where)
TxPrintf("\n%s:\n", where), printedHeader = TRUE;
TxPrintf("%s - %s -> %s\n",
DBTypeShortName(have), DBTypeShortName(t),
DBTypeShortName(result));
}
}
}
}
/*
* ----------------------------------------------------------------------------
*
* dbTechPrintPaint --
*
* DEBUGGING.
* Print painting and erasing rules. If contactsOnly is TRUe, only
* print those rules involving pairs of contact types. The argument
* "where" is printed as a header if it is non-NULL. If doPaint is
* TRUE, we print the paint rules, else we print the erase rules.
*
* Results:
* None.
*
* Side effects:
* Prints stuff.
*
* ----------------------------------------------------------------------------
*/
void
dbTechPrintPaint(where, doPaint, contactsOnly)
char *where; /* If non-null, print this as header */
bool doPaint; /* TRUE -> print paint tables, FALSE -> print erase */
bool contactsOnly;
{
TileType have, paint, erase, result;
int plane;
LayerInfo *lp;
if (where)
TxPrintf("\n%s:\n\n", where);
if (doPaint)
{
TxPrintf("PAINTING RULES:\n");
for (have = TT_TECHDEPBASE; have < DBNumTypes; have++)
{
if (contactsOnly && !IsContact(have)) continue;
for (paint = TT_TECHDEPBASE; paint < DBNumTypes; paint++)
{
if (contactsOnly && !IsContact(paint)) continue;
for (plane = PL_TECHDEPBASE; plane < DBNumPlanes; plane++)
{
lp = &dbLayerInfo[have];
if (!PlaneMaskHasPlane(lp->l_pmask, plane))
continue;
result = DBStdPaintEntry(have, paint, plane);
if (result != have)
{
TxPrintf("%s ",
DBTypeShortName(have));
if (IsContact(have))
TxPrintf("(on %s) ",
DBPlaneLongName(plane));
TxPrintf(" + %s -> %s\n",
DBTypeShortName(paint),
DBTypeShortName(result));
}
}
}
}
}
else
{
TxPrintf("ERASING RULES:\n");
for (have = TT_TECHDEPBASE; have < DBNumTypes; have++)
{
if (contactsOnly && !IsContact(have)) continue;
for (erase = TT_TECHDEPBASE; erase < DBNumTypes; erase++)
{
if (contactsOnly && !IsContact(erase)) continue;
for (plane = PL_TECHDEPBASE; plane < DBNumPlanes; plane++)
{
lp = &dbLayerInfo[have];
if (!PlaneMaskHasPlane(lp->l_pmask, plane))
continue;
result = DBStdEraseEntry(have, erase, plane);
if (result != have)
{
TxPrintf("%s ",
DBTypeShortName(have));
if (IsContact(have))
TxPrintf("(on %s) ",
DBPlaneLongName(plane));
TxPrintf(" - %s -> %s\n",
DBTypeShortName(erase),
DBTypeShortName(result));
}
}
}
}
}
}

920
database/DBtpaint2.c Normal file
View File

@ -0,0 +1,920 @@
/*
* DBtechpaint2.c --
*
* Default composition rules.
* Pretty complicated, unfortunately, so it's in a separate file.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBtpaint2.c,v 1.4 2009/12/30 13:42:33 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <ctype.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/utils.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "utils/tech.h"
#include "textio/textio.h"
#define SETPAINT(have,paint,plane,get) \
if (IsDefaultPaint((have), (paint)) \
&& TTMaskHasType(&DBPlaneTypes[(plane)], (have))) \
dbSetPaintEntry((have), (paint), (plane), (get))
#define SETERASE(have,erase,plane,get) \
if (IsDefaultErase((have), (erase)) \
&& TTMaskHasType(&DBPlaneTypes[(plane)], (have))) \
dbSetEraseEntry((have), (erase), (plane), (get))
LayerInfo *dbTechLpPaint;
/* Forward declarations */
extern void dbTechPaintErasePlanes();
extern void dbComposePaintAllImages();
extern void dbComposeResidues();
extern void dbComposeContacts();
extern void dbComposePaintContact();
extern void dbComposeEraseContact();
extern void dbComposeSavedRules();
extern void dbComposeCompose();
extern void dbComposeDecompose();
/*
* ----------------------------------------------------------------------------
*
* DBTechFinalCompose --
*
* Process all the contact erase/compose rules saved by DBTechAddCompose
* when it was reading in the "compose" section of a technology file.
* Also sets up the default paint/erase rules for contacts.
*
* Since by the end of this section we've processed all the painting
* rules, we initialize the tables that say which planes get affected
* by painting/erasing a given type.
*
* There's a great deal of work done here, so it's broken up into a
* number of separate procedures, each of which implements a single
* operation or default rule. Most of the work deals with painting
* and erasing contacts.
*
* Results:
* None.
*
* Side effects:
* Modifies the paint/erase tables.
* Initializes DBTypePaintPlanesTbl[] and DBTypeErasePlanesTbl[].
*
* ----------------------------------------------------------------------------
*/
void
DBTechFinalCompose()
{
TileType i;
TileTypeBitMask testmask, *rMask;
/* Default rules for painting/erasing contacts */
dbComposePaintAllImages();
dbComposeResidues();
dbComposeContacts();
/* Process rules saved from reading the "compose" section */
dbComposeSavedRules();
/* Build up exported tables */
dbTechPaintErasePlanes();
/* Adjust paint tables for any locked layers */
for (i = TT_TECHDEPBASE; i < DBNumUserLayers; i++)
if (!TTMaskHasType(&DBActiveLayerBits, i))
if (DBIsContact(i))
DBLockContact(i);
for (i = DBNumUserLayers; i < DBNumTypes; i++)
{
rMask = DBResidueMask(i);
TTMaskAndMask3(&testmask, &DBActiveLayerBits, rMask);
if (!TTMaskEqual(&testmask, rMask))
{
TTMaskClearType(&DBActiveLayerBits, i);
DBLockContact(i);
}
}
/* Diagnostic */
/* dbTechPrintPaint("DBTechFinalCompose", TRUE, FALSE); */
/* dbTechPrintPaint("DBTechFinalCompose", FALSE, FALSE); */
}
/*
* ----------------------------------------------------------------------------
*
* dbTechPaintErasePlanes --
*
* Fill in the tables telling which planes get affected
* by painting and erasing. One may take the naive view that only
* the planes on which a type is defined can be affected, but then
* one can't define arbitrary composite types.
*
* Results:
* None.
*
* Side effects:
* Fills in DBTypePaintPlanesTbl[] and DBTypeErasePlanesTbl[].
*
* ----------------------------------------------------------------------------
*/
void
dbTechPaintErasePlanes()
{
TileType t, s;
int pNum;
/* Space tiles are special: they may appear on any plane */
DBTypePaintPlanesTbl[TT_SPACE] = ~(PlaneNumToMaskBit(PL_CELL));
DBTypeErasePlanesTbl[TT_SPACE] = ~(PlaneNumToMaskBit(PL_CELL));
/* Skip TT_SPACE */
for (t = 1; t < DBNumTypes; t++)
{
DBTypePaintPlanesTbl[t] = DBTypeErasePlanesTbl[t] = 0;
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
for (s = 0; s < DBNumTypes; s++)
{
if (DBStdPaintEntry(s, t, pNum) != s)
DBTypePaintPlanesTbl[t] |= PlaneNumToMaskBit(pNum);
if (DBStdEraseEntry(s, t, pNum) != s)
DBTypeErasePlanesTbl[t] |= PlaneNumToMaskBit(pNum);
}
}
}
/*
* ----------------------------------------------------------------------------
*
* dbComposePaintAllImages --
*
* Painting the primary type of a contact layer paints its image
* over all types on each image's plane. (The only types that
* should ever be painted are primary types.)
*
* This rule is called first because it may be overridden by later
* rules, or by explicit composition rules.
*
* Only affects paint entries that haven't already been set to other
* values by explicit paint rules.
*
* Results:
* None.
*
* Side effects:
* Modifies paint/erase tables.
*
* ----------------------------------------------------------------------------
*/
void
dbComposePaintAllImages()
{
TileType tPaint, s, res;
LayerInfo *lp;
int p, n;
/* Iterate over primary types only */
for (n = 0; n < dbNumContacts; n++)
{
lp = dbContactInfo[n];
tPaint = lp->l_type;
if (tPaint >= DBNumUserLayers) continue;
for (res = TT_TECHDEPBASE; res < DBNumTypes; res++)
{
if (TTMaskHasType(&lp->l_residues, res))
{
p = DBPlane(res);
for (s = TT_TECHDEPBASE; s < DBNumTypes; s++)
if (DBPlane(s) == p)
SETPAINT(s, tPaint, p, tPaint);
if (IsDefaultPaint(TT_SPACE, tPaint))
dbSetPaintEntry(TT_SPACE, tPaint, p, tPaint);
}
}
}
}
/*
* ----------------------------------------------------------------------------
*
* dbComposeResidues --
*
* The behavior of a contact type when other, non-contact types are
* painted over it or erased from it is derived from the behavior of
* its residue types.
*
* 1. If painting doesn't affect a contact's residue on a plane,
* it doesn't affect the contact's image on that plane either.
* This allows, for example, painting metal1 over a contact
* "containing" metal1 without breaking the contact.
*
* 2. If painting or erasing a type affects a residue of a
* contact, the image's connectivity to adjacent planes
* is broken and the image is replaced by the result of
* painting or erasing over the residue.
*
* Results:
* None.
*
* Side effects:
* Modifies paint/erase tables.
*
* ----------------------------------------------------------------------------
*/
void
dbComposeResidues()
{
LayerInfo *lp;
TileType s, res;
int n;
/* Painting that doesn't affect the residue doesn't affect the contact. */
for (n = 0; n < dbNumContacts; n++)
{
lp = dbContactInfo[n];
for (res = TT_TECHDEPBASE; res < DBNumUserLayers; res++)
{
if (TTMaskHasType(&lp->l_residues, res))
{
for (s = TT_TECHDEPBASE; s < DBNumUserLayers; s++)
if (!PAINTAFFECTS(res, s))
SETPAINT(lp->l_type, s, DBPlane(res), lp->l_type);
}
}
}
}
/*
* ----------------------------------------------------------------------------
*
* dbComposeContacts --
*
* This procedure handles the rules for composition of contact types.
* We look at the results of painting each type of contact in
* dbContactInfo[] over all other contact types.
*
* Results:
* None.
*
* Side effects:
* Modifies paint/erase tables.
*
* ----------------------------------------------------------------------------
*/
void
dbComposeContacts()
{
LayerInfo *lpImage, *lpPaint;
int m, pNum;
TileTypeBitMask *rmask;
TileType n, ttype, itype, presult, eresult;
for (m = 0; m < dbNumContacts; m++)
{
lpImage = dbContactInfo[m]; /* Existing contact image */
for (n = TT_TECHDEPBASE; n < DBNumUserLayers; n++)
{
lpPaint = &dbLayerInfo[n]; /* Layer being painted or erased */
if (lpImage->l_type != n)
dbComposePaintContact(lpImage, lpPaint);
dbComposeEraseContact(lpImage, lpPaint);
}
}
/* For stacking types, determine the result of painting or erasing */
/* each stacking type by applying the paint and erase results of */
/* each of its residues in sequence. */
for (itype = 0; itype < DBNumTypes; itype++)
{
for (n = DBNumUserLayers; n < DBNumTypes; n++)
{
lpPaint = &dbLayerInfo[n]; /* Layer being painted or erased */
rmask = &lpPaint->l_residues;
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
presult = eresult = itype;
for (ttype = TT_TECHDEPBASE; ttype < DBNumUserLayers; ttype++)
if (TTMaskHasType(rmask, ttype))
{
presult = DBStdPaintEntry(presult, ttype, pNum);
eresult = DBStdEraseEntry(eresult, ttype, pNum);
}
SETPAINT(itype, n, pNum, presult);
SETERASE(itype, n, pNum, eresult);
}
}
}
}
/*
* ----------------------------------------------------------------------------
* dbComposePaintContact --
*
* Construct the painting rules for painting type lpPaint over
* the contact image lpImage.
* ----------------------------------------------------------------------------
*/
void
dbComposePaintContact(lpImage, lpPaint)
LayerInfo *lpImage, *lpPaint;
{
int pNum;
PlaneMask pmask, pshared;
LayerInfo *lp;
TileTypeBitMask rmask, cmask;
TileType newtype, ptype, itype;
bool overlap;
/*
* If the residues of lpImage and lpPaint can be merged without
* affecting any of the layers, then we merge them, and look for
* any contact matching the merged residues. If none is found,
* and the planes do not overlap, then just paint the new
* contact. If they cannot be merged, then the original contact
* is dissolved and replaced by its residues.
*/
pmask = lpImage->l_pmask & lpPaint->l_pmask;
overlap = (pmask == 0) ? FALSE : TRUE;
if (overlap)
{
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
if (PlaneMaskHasPlane(pmask, pNum))
{
ptype = DBPlaneToResidue(lpPaint->l_type, pNum);
itype = DBPlaneToResidue(lpImage->l_type, pNum);
if (ptype != itype)
break;
}
}
if (pNum == DBNumPlanes)
{
/* Residues are compatible; check for a contact type with */
/* the merged residues (explicitly defined stacked contact */
/* type) */
TTMaskZero(&rmask);
TTMaskSetMask3(&rmask, &lpImage->l_residues, &lpPaint->l_residues);
dbTechMatchResidues(&rmask, &cmask, TRUE);
/* Implicitly-defined stacking types override any */
/* explicitly-defined types, or havoc results. */
/* This allows one to create a type such as "pad" */
/* having the same residues as "m123c" without */
/* magic confusing them in the paint tables. */
newtype = DBTechFindStacking(lpImage->l_type, lpPaint->l_type);
if (TTMaskIsZero(&cmask) || (newtype != -1))
{
/* If there is a stacking contact type, use it */
if (newtype >= DBNumUserLayers)
{
pshared = lpImage->l_pmask & lpPaint->l_pmask;
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(pshared, pNum))
SETPAINT(lpImage->l_type, lpPaint->l_type,
pNum, newtype);
}
else if (lpPaint->l_isContact && (lpImage->l_type < DBNumUserLayers))
{
/* Original contact is replaced by the new one where
* the planes overlap, and is dissolved into its
* residues where they don't.
* In this condition, the residues of image must be
* non-contact types.
*/
for (itype = TT_TECHDEPBASE; itype < DBNumUserLayers; itype++)
{
if (TTMaskHasType(&lpImage->l_residues, itype))
{
if (TTMaskHasType(&lpPaint->l_residues, itype))
{
SETPAINT(lpImage->l_type, lpPaint->l_type,
DBPlane(itype), lpPaint->l_type);
}
else
{
SETPAINT(lpImage->l_type, lpPaint->l_type,
DBPlane(itype), itype);
}
}
}
}
else if (lpPaint->l_isContact &&
!TTMaskHasType(&lpImage->l_residues, lpPaint->l_type))
{
/* Original contact is replaced by the new one where
* the planes overlap, and is dissolved into its
* residues where they don't.
* In this condition, the residues of image are contact
* types.
*/
for (itype = TT_TECHDEPBASE; itype < DBNumUserLayers; itype++)
{
if (TTMaskHasType(&lpImage->l_residues, itype))
{
if (TTMaskHasType(&lpPaint->l_residues, itype))
{
SETPAINT(lpImage->l_type, lpPaint->l_type,
DBPlane(itype), lpPaint->l_type);
}
}
}
}
else
{
/* Painting a residue type on top of a contact */
/* with a compatible residue does nothing, as does */
/* painting one of the types of a stacked contact */
/* on the stacking contact type. In the plane of */
/* the image type, this is non-default behavior. */
SETPAINT(lpImage->l_type, lpPaint->l_type,
DBPlane(lpImage->l_type), lpImage->l_type);
}
}
else
{
/* Presumably there is at most one contact type here */
for (newtype = TT_TECHDEPBASE; newtype < DBNumUserLayers; newtype++)
{
if (TTMaskHasType(&cmask, newtype))
{
lp = &dbLayerInfo[newtype];
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(lp->l_pmask, pNum))
SETPAINT(lpImage->l_type, lpPaint->l_type,
pNum, newtype);
break;
}
}
}
}
else
{
/* Image and paint types overlap in a plane, but */
/* residues are not compatible. Replace image with the */
/* residues of image, except on the overlapping plane. */
for (ptype = TT_TECHDEPBASE; ptype < DBNumUserLayers; ptype++)
if (TTMaskHasType(&lpImage->l_residues, ptype))
if (ptype != itype)
SETPAINT(lpImage->l_type, lpPaint->l_type,
DBPlane(ptype), ptype);
}
}
else if (lpPaint->l_isContact)
{
/* No overlapping planes, and both paint & image types are contacts */
TTMaskZero(&rmask);
TTMaskSetMask3(&rmask, &lpImage->l_residues, &lpPaint->l_residues);
dbTechMatchResidues(&rmask, &cmask, TRUE);
if (!TTMaskIsZero(&cmask))
{
/* Replace image with the new contact type */
for (newtype = TT_TECHDEPBASE; newtype < DBNumUserLayers; newtype++)
{
if (TTMaskHasType(&cmask, newtype))
{
lp = &dbLayerInfo[newtype];
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(lp->l_pmask, pNum))
SETPAINT(lpImage->l_type, lpPaint->l_type,
pNum, newtype);
}
break;
}
}
/* else default paint/erase behavior */
}
}
/*
* ----------------------------------------------------------------------------
*
* dbComposeSubsetResidues --
*
* Create a mask of all contact types whose residues are subsets
* of the "have" type but are not supersets of the "erase" type.
*
* Results:
* True if residues of types in outMask overlap, False if not.
*
* Side Effects:
* outMask is filled with the mask of types.
*
* ----------------------------------------------------------------------------
*/
bool
dbComposeSubsetResidues(lpImage, lpErase, outMask)
LayerInfo *lpImage, *lpErase;
TileTypeBitMask *outMask;
{
TileTypeBitMask ires;
TileTypeBitMask smask, overlapmask;
LayerInfo *li;
int n;
bool rval = FALSE;
/* The residues of lpImage must themselves be decomposed if lpImage */
/* is a stacking type. */
TTMaskZero(&ires);
if (lpImage->l_type >= DBNumUserLayers)
{
for (n = 0; n < dbNumContacts; n++)
{
li = dbContactInfo[n];
if (TTMaskHasType(&lpImage->l_residues, li->l_type))
TTMaskSetMask(&ires, &li->l_residues);
}
}
else
TTMaskSetMask(&ires, &lpImage->l_residues);
/*
* Generate a mask of all contact types whose residue masks are
* subsets of the residues of lpImage. These are all types
* which contain no residues that are not part of lpImage.
*/
TTMaskZero(outMask);
TTMaskZero(&overlapmask);
for (n = 0; n < dbNumContacts; n++)
{
li = dbContactInfo[n];
TTMaskAndMask3(&smask, &li->l_residues, &ires);
if (TTMaskEqual(&smask, &li->l_residues))
{
/* The residues of type cannot be a superset of the */
/* residues of the erase type */
TTMaskAndMask3(&smask, &li->l_residues, &lpErase->l_residues);
if (!TTMaskEqual(&smask, &lpErase->l_residues))
{
TTMaskSetType(outMask, li->l_type);
/* Check if the residues of type overlap one of */
/* the types already generated. */
TTMaskAndMask3(&smask, &overlapmask, &li->l_residues);
if (TTMaskIsZero(&smask))
TTMaskSetMask(&overlapmask, &li->l_residues);
else
rval = TRUE;
}
}
}
return rval;
}
/*
* ----------------------------------------------------------------------------
* dbComposeEraseContact --
*
* Construct the erasing rules for erasing type lpErase from
* the contact image lpImage.
* ----------------------------------------------------------------------------
*/
void
dbComposeEraseContact(lpImage, lpErase)
LayerInfo *lpImage, *lpErase;
{
int pNum;
PlaneMask pmask;
LayerInfo *lp;
TileTypeBitMask cmask;
TileType itype;
bool overlap;
/* The erased planes generally end up with space, so we generate */
/* space as default behavior. This may be altered in specific */
/* cases, below. */
/* The specific check for lpImage as a stacking contact is not */
/* necessary, but prevents generation of non-default rules in */
/* cases which cannot occur. */
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(lpErase->l_pmask, pNum))
if ((lpImage->l_type < DBNumUserLayers)
|| (pNum == DBPlane(lpImage->l_type)))
SETERASE(lpImage->l_type, lpErase->l_type, pNum, TT_SPACE);
/* Erasing self should always leave space; otherwise */
/* the "undo" records aren't symmetric, which screws */
/* everything up. */
if (lpImage->l_type == lpErase->l_type) return;
/* If planes of HAVE and ERASE types don't overlap, we can erase */
/* the ERASE type without affecting the image, so we're done. */
pmask = lpImage->l_pmask & lpErase->l_pmask;
overlap = (pmask == 0) ? FALSE : TRUE;
if (!overlap) return;
/* Find what contacts are subsets of this one and generate a mask */
/* of the types that might be left over after erasing this one. */
/* If those types overlap, leave the existing type alone. If they */
/* don't, then paint them. */
overlap = dbComposeSubsetResidues(lpImage, lpErase, &cmask);
if (overlap)
{
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(lpImage->l_pmask, pNum))
// SETERASE(lpImage->l_type, lpErase->l_type, pNum, TT_SPACE);
SETERASE(lpImage->l_type, lpErase->l_type, pNum, lpImage->l_type);
}
else
{
pmask = lpImage->l_pmask & (~(lpErase->l_pmask));
for (itype = TT_TECHDEPBASE; itype < DBNumTypes; itype++)
if (TTMaskHasType(&cmask, itype))
{
lp = &dbLayerInfo[itype];
pmask &= ~(lp->l_pmask);
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(lp->l_pmask, pNum))
if ((lpImage->l_type < DBNumUserLayers)
|| (pNum == DBPlane(lpImage->l_type)))
SETERASE(lpImage->l_type, lpErase->l_type, pNum, itype);
}
/* If there are any planes in the image which have not been */
/* accounted for, then we decompose these into the residues */
/* of the image. */
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(pmask, pNum))
{
itype = DBPlaneToResidue(lpImage->l_type, pNum);
SETERASE(lpImage->l_type, lpErase->l_type, pNum, itype);
}
}
/* Diagnostic (to be removed or commented out) */
/*
if (!TTMaskIsZero(&cmask))
{
TxPrintf("Have %s, Erase %s: ", DBTypeLongNameTbl[lpImage->l_type],
DBTypeLongNameTbl[lpErase->l_type]);
for (itype = TT_TECHDEPBASE; itype < DBNumTypes; itype++)
if (TTMaskHasType(&cmask, itype))
TxPrintf("%s ", DBTypeLongNameTbl[itype]);
if (overlap)
TxPrintf("overlapping");
TxPrintf("\n");
}
*/
}
/*
* ----------------------------------------------------------------------------
* DBLockContact --
*
* This procedure modifies the erase tables so that the specified contact
* type cannot be erased by erasing one of its residues, which is the default
* behavior.
* ----------------------------------------------------------------------------
*/
void
DBLockContact(ctype)
TileType ctype;
{
LayerInfo *lpImage, *lpPaint;
TileType c, n, itype, eresult;
TileTypeBitMask *rmask;
int m, pNum;
/* Have type, Erase * --> Result is type */
lpPaint = &dbLayerInfo[ctype];
for (n = TT_TECHDEPBASE; n < DBNumTypes; n++)
{
if (n == ctype) continue;
/* Avoid the case, e.g., if ctype is pc+v, then pc+v - pc = v */
/* is still valid if pc is an active layer. */
if (ctype >= DBNumUserLayers)
{
rmask = DBResidueMask(ctype);
if (TTMaskHasType(rmask, n))
if (TTMaskHasType(&DBActiveLayerBits, n))
continue;
}
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(lpPaint->l_pmask, pNum))
SETERASE(ctype, n, pNum, ctype);
}
}
/*
* ----------------------------------------------------------------------------
* DBUnlockContact --
*
* This procedure reverses the operation of DBLockContact, allowing a contact
* to be erased by erasing one of its residues. This is the same code as
* dbComposeContacts(), for a single contact type.
* ----------------------------------------------------------------------------
*/
void
DBUnlockContact(ctype)
TileType ctype;
{
LayerInfo *lpImage, *lpPaint;
TileType n, itype, eresult;
TileTypeBitMask *rmask;
int m, pNum;
lpImage = &dbLayerInfo[ctype];
for (n = TT_TECHDEPBASE; n < DBNumUserLayers; n++)
{
lpPaint = &dbLayerInfo[n];
dbComposeEraseContact(lpImage, lpPaint);
}
/* To be done (maybe): revert rules for stacked contact types */
}
/*
* ----------------------------------------------------------------------------
*
* dbComposeSavedRules --
*
* Process all the contact compose/decompose rules saved
* when the compose section of the tech file was read.
* Each pair on the RHS of one of these rules must contain
* exactly one contact type that spans the same set of planes
* as the image type.
*
* Results:
* None.
*
* Side effects:
* Modifies entries in the paint and erase tables.
*
* ----------------------------------------------------------------------------
*/
void
dbComposeSavedRules()
{
LayerInfo *lpContact;
TileType imageType;
TypePair *pair;
Rule *rule;
int n;
for (n = 0; n < dbNumSavedRules; n++)
{
rule = &dbSavedRules[n];
lpContact = &dbLayerInfo[rule->r_result];
imageType = lpContact->l_type;
for (pair = rule->r_pairs; pair < &rule->r_pairs[rule->r_npairs];
pair++)
{
dbComposeDecompose(imageType, pair->rp_a, pair->rp_b);
dbComposeDecompose(imageType, pair->rp_b, pair->rp_a);
if (rule->r_ruleType == RULE_COMPOSE)
{
dbComposeCompose(imageType, pair->rp_a, pair->rp_b);
dbComposeCompose(imageType, pair->rp_b, pair->rp_a);
}
}
}
}
/*
* ----------------------------------------------------------------------------
* dbComposeDecompose --
*
* Painting componentType over imageType is a no-op.
* Erasing componentType from imageType gives either the image of
* remainingType, if one exists on DBPlane(imageType), or else
* gives the residue of imageType.
*
* Results:
* None.
*
* Side effects:
* Modifies the paint/erase tables as described above.
* Indicates that these modifications are not default
* rules by setting the corresponding bits in the tables
* dbNotDefaultPaintTbl[] and dbNotDefaultEraseTbl[].
* ----------------------------------------------------------------------------
*/
void
dbComposeDecompose(imageType, componentType, remainingType)
TileType imageType;
TileType componentType;
TileType remainingType;
{
int pNum = DBPlane(imageType);
TileType resultType;
/* Painting componentType is a no-op */
dbSetPaintEntry(imageType, componentType, pNum, imageType);
TTMaskSetType(&dbNotDefaultPaintTbl[imageType], componentType);
/* Which residue belongs to the plane pNum? */
resultType = DBPlaneToResidue(imageType, pNum);
/*
* Erasing componentType gives remainingType or breaks
* imageType's contact.
*/
dbSetEraseEntry(imageType, componentType, pNum, resultType);
TTMaskSetType(&dbNotDefaultEraseTbl[imageType], componentType);
}
/*
* ----------------------------------------------------------------------------
* dbComposeCompose --
*
* Painting paintType over existingType gives imageType.
*
* Results:
* None.
*
* Side effects:
* Modifies the paint/erase tables as described above.
* Indicates that these modifications are not default
* rules by setting the corresponding bits in the tables
* dbNotDefaultPaintTbl[] and dbNotDefaultEraseTbl[].
* ----------------------------------------------------------------------------
*/
void
dbComposeCompose(imageType, existingType, paintType)
TileType imageType;
TileType existingType;
TileType paintType;
{
int pNum = DBPlane(imageType);
if (PlaneMaskHasPlane(LayerPlaneMask(existingType), pNum))
{
dbSetPaintEntry(existingType, paintType, pNum, imageType);
TTMaskSetType(&dbNotDefaultPaintTbl[existingType], paintType);
}
}

1007
database/DBundo.c Normal file

File diff suppressed because it is too large Load Diff

96
database/Depend Normal file
View File

@ -0,0 +1,96 @@
DBbound.o: DBbound.c ../utils/magic.h ../utils/geometry.h \
../database/database.h ../tiles/tile.h ../utils/hash.h
DBcell.o: DBcell.c ../utils/magic.h ../utils/malloc.h ../utils/geometry.h \
../tiles/tile.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../utils/undo.h ../utils/signals.h
DBcellbox.o: DBcellbox.c ../utils/magic.h ../utils/geometry.h \
../utils/geofast.h ../tiles/tile.h ../utils/hash.h \
../database/database.h ../database/databaseInt.h ../windows/windows.h \
../dbwind/dbwind.h ../utils/undo.h
DBcellcopy.o: DBcellcopy.c ../utils/magic.h ../utils/geometry.h \
../utils/geofast.h ../utils/malloc.h ../tiles/tile.h ../utils/hash.h \
../database/database.h ../database/databaseInt.h ../textio/textio.h \
../windows/windows.h ../dbwind/dbwind.h ../commands/commands.h
DBcellname.o: DBcellname.c ../tcltk/tclmagic.h ../utils/magic.h \
../utils/hash.h ../utils/utils.h ../utils/geometry.h ../tiles/tile.h \
../database/database.h ../database/databaseInt.h ../select/select.h \
../utils/signals.h ../utils/undo.h ../utils/malloc.h \
../windows/windows.h ../textio/textio.h ../dbwind/dbwind.h \
../utils/main.h ../drc/drc.h
DBcellsrch.o: DBcellsrch.c ../utils/magic.h ../utils/malloc.h \
../utils/geometry.h ../utils/geofast.h ../tiles/tile.h ../utils/hash.h \
../database/database.h ../database/databaseInt.h ../textio/textio.h \
../utils/signals.h ../windows/windows.h ../utils/main.h \
../mzrouter/mzrouter.h ../utils/list.h
DBcellsel.o: DBcellsel.c ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../utils/utils.h
DBcellsubr.o: DBcellsubr.c ../utils/magic.h ../utils/malloc.h \
../utils/hash.h ../utils/utils.h ../utils/geometry.h ../tiles/tile.h \
../database/database.h ../database/databaseInt.h ../utils/signals.h
DBconnect.o: DBconnect.c ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../utils/signals.h ../utils/malloc.h
DBcount.o: DBcount.c ../utils/magic.h ../utils/hash.h ../utils/geometry.h \
../tiles/tile.h ../database/database.h ../database/databaseInt.h
DBexpand.o: DBexpand.c ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../textio/textio.h ../utils/utils.h \
../utils/stack.h
DBio.o: DBio.c ../utils/magic.h ../utils/geometry.h ../tiles/tile.h \
../utils/utils.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../database/fonts.h ../windows/windows.h \
../dbwind/dbwind.h ../utils/tech.h ../textio/textio.h ../drc/drc.h \
../utils/undo.h ../utils/malloc.h ../utils/signals.h
DBlabel.o: DBlabel.c ../utils/magic.h ../utils/malloc.h \
../utils/geometry.h ../tiles/tile.h ../utils/hash.h ../utils/utils.h \
../database/database.h ../database/fonts.h ../database/databaseInt.h \
../windows/windows.h ../dbwind/dbwind.h ../commands/commands.h \
../textio/textio.h
DBlabel2.o: DBlabel2.c ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../utils/malloc.h
DBpaint2.o: DBpaint2.c ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h
DBpaint.o: DBpaint.c ../utils/magic.h ../utils/malloc.h \
../utils/geometry.h ../tiles/tile.h ../utils/hash.h \
../database/database.h ../database/databaseInt.h ../windows/windows.h \
../graphics/graphics.h ../dbwind/dbwind.h ../utils/signals.h \
../textio/textio.h ../utils/undo.h
DBprop.o: DBprop.c ../utils/magic.h ../utils/geometry.h ../tiles/tile.h \
../utils/hash.h ../database/database.h ../utils/malloc.h
DBtech.o: DBtech.c ../utils/magic.h ../utils/geometry.h ../utils/utils.h \
../tiles/tile.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../utils/tech.h ../textio/textio.h \
../utils/malloc.h
DBtcontact.o: DBtcontact.c ../utils/magic.h ../utils/geometry.h \
../utils/utils.h ../utils/malloc.h ../tiles/tile.h ../utils/hash.h \
../database/database.h ../database/databaseInt.h ../utils/tech.h \
../textio/textio.h
DBtechname.o: DBtechname.c ../tcltk/tclmagic.h ../utils/magic.h \
../utils/geometry.h ../utils/utils.h ../tiles/tile.h ../utils/hash.h \
../database/database.h ../database/databaseInt.h ../utils/tech.h \
../textio/textio.h ../utils/malloc.h
DBtpaint.o: DBtpaint.c ../utils/magic.h ../utils/geometry.h \
../utils/utils.h ../tiles/tile.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../utils/tech.h ../textio/textio.h
DBtpaint2.o: DBtpaint2.c ../utils/magic.h ../utils/geometry.h \
../utils/utils.h ../tiles/tile.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../utils/tech.h ../textio/textio.h
DBtechtype.o: DBtechtype.c ../utils/magic.h ../utils/geometry.h \
../utils/utils.h ../tiles/tile.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../utils/tech.h ../textio/textio.h \
../utils/malloc.h
DBtiles.o: DBtiles.c ../utils/magic.h ../utils/geometry.h ../tiles/tile.h \
../utils/signals.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../utils/malloc.h
DBtimestmp.o: DBtimestmp.c ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../windows/windows.h ../textio/textio.h \
../drc/drc.h ../utils/signals.h ../utils/malloc.h
DBundo.o: DBundo.c ../utils/magic.h ../utils/malloc.h ../utils/geometry.h \
../tiles/tile.h ../utils/hash.h ../database/database.h \
../database/databaseInt.h ../utils/undo.h ../windows/windows.h \
../dbwind/dbwind.h ../utils/main.h ../utils/utils.h ../drc/drc.h \
../utils/signals.h

20
database/Makefile Normal file
View File

@ -0,0 +1,20 @@
#
# Makefile rcsid $Header: /usr/cvsroot/magic-8.0/database/Makefile,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $
#
MODULE = database
MAGICDIR = ..
LIB_SRCS =
SRCS = DBbound.c DBcell.c DBcellbox.c DBcellcopy.c \
DBcellname.c DBcellsrch.c DBcellsel.c DBcellsubr.c \
DBconnect.c DBcount.c DBexpand.c DBio.c DBlabel.c DBlabel2.c \
DBpaint2.c DBpaint.c DBprop.c DBtech.c DBtcontact.c \
DBtechname.c DBtpaint.c DBtpaint2.c DBtechtype.c \
DBtiles.c DBtimestmp.c DBundo.c
include ${MAGICDIR}/defs.mak
LIB_OBJS += ${MAGICDIR}/tiles/libtiles.o ${MAGICDIR}/utils/libutils.o
CLEANS += database.h
include ${MAGICDIR}/rules.mak

1109
database/database.h.in Normal file

File diff suppressed because it is too large Load Diff

243
database/databaseInt.h Normal file
View File

@ -0,0 +1,243 @@
/*
* databaseInt.h --
*
* Definitions internal to the database module.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*
* Needs to include: magic.h, tile.h, database.h
*
* rcsid $Header: /usr/cvsroot/magic-8.0/database/databaseInt.h,v 1.3 2010/06/24 12:37:15 tim Exp $
*/
#ifndef _DATABASEINT_H
#define _DATABASEINT_H
#include "database/database.h"
/* ----------- Argument to area search when writing out cell ---------- */
struct writeArg
{
FILE *wa_file; /* File to which to output */
TileType wa_type; /* Type of tile being searched for */
bool wa_found; /* Have any tiles been found yet? */
int wa_reducer; /* Scale factor for all geometry */
int wa_plane; /* Current plane being searched */
};
/* --------------------- Undo info for painting ----------------------- */
/* The following is the structure of the undo info saved for each tile */
typedef struct
{
Rect pue_rect; /* Rectangle painted/erased */
TileType pue_oldtype; /* Material erased */
TileType pue_newtype; /* Material painted */
char pue_plane; /* Plane index affected */
} paintUE;
/* The following is the structure of the undo info saved for a split tile */
typedef struct
{
Point sue_point; /* lower-left position of split/joined tile */
int sue_splitx; /* x position of split/join */
char sue_plane; /* Plane of material that was split/joined */
} splitUE;
/* -------------- Codes for undo of cell use operations --------------- */
#define UNDO_CELL_CLRID 0 /* Clear use id */
#define UNDO_CELL_SETID 1 /* Set use id */
#define UNDO_CELL_PLACE 2 /* Create and place cell use */
#define UNDO_CELL_DELETE 3 /* Delete and destroy cell use */
#define UNDO_CELL_LOCKDOWN 4 /* Lock down a cell use */
/* --------------- Default types and planes, and name lists ----------- */
/*
* Type or plane names.
* These are invisible outside of the technology module
* except via DBTechNameType() and DBTechNamePlane().
* The first name in any list is by convention pointed
* to by DBTypeLongNameTbl[] or DBPlaneLongNameTbl[]
* respectively.
*/
typedef struct namelist
{
struct namelist *sn_next; /* Next name in table */
struct namelist *sn_prev; /* Previous name in table */
char *sn_name; /* Text of name */
ClientData sn_value; /* Value (TileType or plane number) */
bool sn_primary; /* If TRUE, this is the primary name */
} NameList;
typedef struct
{
int dp_plane; /* Internal index for this plane */
char *dp_names; /* List of comma-separated names */
} DefaultPlane;
typedef struct
{
TileType dt_type; /* This type's number */
int dt_plane; /* Plane on which this type resides */
char *dt_names; /* List of comma-separated names. The first
* is the "long" name of the type.
*/
bool dt_print; /* TRUE if layer is to be printed by
* DBTechPrintTypes. These are layers
* that user would normally paint.
*/
} DefaultType;
extern NameList dbTypeNameLists; /* Type abbreviations */
extern NameList dbPlaneNameLists; /* Plane abbreviations */
extern DefaultPlane dbTechDefaultPlanes[]; /* Builtin planes */
extern DefaultType dbTechDefaultTypes[]; /* Builtin types */
/* ------------------- Layer composition tables ----------------------- */
/*
* Contacts in Magic are funny beasts. Instead of representing the via
* holes separately from the two layers they connect, Magic bundles them
* into a single "type" that implies the presence of adjacent vias.
* In the discussion that follows, "contact" means the aggregate described
* by a line in the "contacts" section of the technology file, while "type"
* has its usual meaning, namely a TileType. "Painting a contact" means
* painting its primary type, namely the one that appeared in the "types"
* section of the technology file (as opposed to any automatically generated
* tile types).
*
* Magic represents contacts between tile planes by storing the tile type
* on each plane, each of which is referred to as an "image" of the
* particular type of contact on its respective plane. The primary contact
* type indicates the planes it connects to, and also the "residues" on
* each connected plane (residues are the types that would be present if
* there were no contact).
*
* When the technology file is read, the "types" section defines the tile
* type names that users will paint and erase. Contacts can be painted
* and erased by a single name, but actually consist of several tiles;
* the "contacts" section provides the information needed to automatically
* generate the tiles needed to represent a contact with the specified
* connectivity.
*
* Magic's scheme has a couple of important properties. Each contact
* defined in the technology file determines a set of planes that will
* be painted with the type when that contact is painted over empty
* space.
*
* The LayerInfo structure is used primarily to store information about
* the various types of contacts, although it contains degenerate information
* about non-contact types as well.
*/
typedef struct
{
TileType l_type; /* Back-index into dbLayerInfo[] */
bool l_isContact; /* TRUE if this layer has images */
/* Residues of this contact on its contacted planes. */
TileTypeBitMask l_residues;
/* Mask of connected planes, including this one */
PlaneMask l_pmask;
} LayerInfo;
extern LayerInfo dbLayerInfo[];
extern LayerInfo *dbContactInfo[];
extern int dbNumContacts;
extern int dbNumImages;
/* Macros for above table */
#define LayerPlaneMask(t) dbLayerInfo[t].l_pmask
#define IsContact(t) dbLayerInfo[t].l_isContact
/* --------------------- Composition rule tables ---------------------- */
/* Saved contact compose/erase rules */
typedef struct
{
TileType rp_a, rp_b; /* Two types in pair */
} TypePair;
typedef struct
{
int r_ruleType; /* Kind of rule (RULE_* below) */
TileType r_result; /* Result type */
int r_npairs; /* Number of type pairs in rule */
TypePair r_pairs[NT]; /* Pairs of types in rule */
} Rule;
/*
* Types of rules in the compose section of a technology file
* (represented in the Rule structure above).
*/
#define RULE_DECOMPOSE 0
#define RULE_COMPOSE 1
#define RULE_PAINT 2
#define RULE_ERASE 3
extern int dbNumSavedRules;
extern Rule dbSavedRules[];
/* -------------------- Internal procedure headers -------------------- */
extern void DBUndoPutLabel();
extern void DBUndoEraseLabel();
extern void DBUndoCellUse();
extern void DBStampMismatch();
extern void DBTechAddNameToType();
extern void dbComputeBbox();
extern void dbFreeCellPlane();
extern void dbFreePaintPlane();
extern bool dbTechAddPaint();
extern bool dbTechAddErase();
ClientData dbTechNameLookup();
ClientData dbTechNameLookupExact();
/* --------------- Internal database technology variables ------------- */
/*
* Macros to set the paint result tables.
* The argument order is different from the index order in
* the tables, for historical reasons.
*
* Usage:
* dbSetPaintEntry(oldType, paintType, planeNum, resultType)
* dbSetEraseEntry(oldType, paintType, planeNum, resultType)
* dbSetWriteEntry(oldType, paintType, resultType)
*/
#define dbSetPaintEntry(h,t,p,r) (DBPaintResultTbl[p][t][h] = r)
#define dbSetEraseEntry(h,t,p,r) (DBEraseResultTbl[p][t][h] = r)
#define dbSetWriteEntry(h,t,r) (DBWriteResultTbl[t][h] = r)
extern TileTypeBitMask dbNotDefaultEraseTbl[];
extern TileTypeBitMask dbNotDefaultPaintTbl[];
#define IsDefaultErase(h, e) (!TTMaskHasType(&dbNotDefaultEraseTbl[h], e))
#define IsDefaultPaint(h, p) (!TTMaskHasType(&dbNotDefaultPaintTbl[h], p))
/*
* Macros to determine whether painting or erasing type s affects
* type t on its home plane. The check for t != TT_SPACE is because
* TT_SPACE has no specific home plane and is handled specially.
*/
#define PAINTAFFECTS(t, s) \
((t) != TT_SPACE && DBStdPaintEntry((t), (s), DBPlane(t)) != (t))
#define ERASEAFFECTS(t, s) \
((t) != TT_SPACE && DBStdEraseEntry((t), (s), DBPlane(t)) != (t))
#endif /* _DATABASEINT_H */

42
database/fonts.h Normal file
View File

@ -0,0 +1,42 @@
/*
* fonts.h --
*
* Vectored font definitions for the database module.
* This file defines variables and procedures that are visible to clients
* outside the database module.
*
* Copyright (C) 2008 OpenCircuitDesign, Inc.
*
* rcsid "$$"
*/
#ifndef _FONTS_H
#define _FONTS_H
#ifndef _TILES_H
#include "tiles/tile.h"
#endif /* _TILES_H */
/* ---------------------------- Fonts --------------------------------- */
typedef struct fontchar *FontCharPtr;
typedef struct fontchar
{
short fc_numpoints;
Point *fc_points;
FontCharPtr fc_next;
} FontChar;
typedef struct
{
char *mf_name;
Rect mf_extents; /* Character extents (max bbox) */
FontChar *mf_vectors[96]; /* ASCII characters 32 through 126 */
Point mf_offset[96]; /* Vector offset to next character */
Rect mf_bbox[96]; /* Character bounding boxes */
} MagicFont;
extern MagicFont **DBFontList; /* List of loaded font vectors */
extern int DBNumFonts; /* Number of loaded fonts */
#endif /* _FONTS_H */

404
dbwind/DBWbuttons.c Normal file
View File

@ -0,0 +1,404 @@
/*
* DBWbuttons.c --
*
* This file provides a general facility whereby clients that are
* willing to provide handlers for button presses in layout windows
* can themselves, and the current handler can be switched
* between them. This file also provides the default button handler,
* which is used to move the box.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/dbwind/DBWbuttons.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "windows/windows.h"
#include "graphics/graphics.h"
#include "dbwind/dbwind.h"
#include "utils/styles.h"
#include "textio/textio.h"
#include "textio/txcommands.h"
#include "utils/utils.h"
/* The arrays below are used to store information about the various
* button handlers that have registered themselves.
*/
#define MAXBUTTONHANDLERS 10
static char *dbwButtonHandlers[MAXBUTTONHANDLERS];
/* Name of each button handler: used to select
* that handler as the current one. A NULL entry
* here means that this handler slot isn't in use.
*/
static char *dbwButtonDoc[MAXBUTTONHANDLERS];
/* A documentation string for each handler: tells
* what the button pushes and releases mean.
*/
static void (*dbwButtonProcs[MAXBUTTONHANDLERS])();
/* A procedure for each handler that is invoked
* on button presses and releases when that handler
* is the current one.
*/
static int dbwButtonCursors[MAXBUTTONHANDLERS];
/* Cursor shape to use for each handler. */
static int dbwButtonCurrentIndex;
/* Index of current handler. */
void (*DBWButtonCurrentProc)();
/* Current button-handling procedure. */
static int buttonCorner = TOOL_ILG; /* Nearest corner when button went
* down.
*/
/*
* ----------------------------------------------------------------------------
*
* DBWAddButtonHandler --
*
* This procedure is called by would-be button handlers to register
* themselves. After a client has called this procedure, it may
* make itself the current button handler by calling the procedure
* DBWChangeButtonHandler.
*
* Results:
* None.
*
* Side effects:
* The client's information is added to the registry of potential
* button handlers. When the handler is made the current one (by
* a call to DBWChangeButtonHandler) each button press or release
* in a layout window causes proc to be invoked as follows:
*
* int
* proc(w, cmd)
* MagWindow *w;
* TxCommand *cmd;
* {
* }
*
* W is the window in which the button was pushed, and cmd describes
* exactly what happened.
*
* ----------------------------------------------------------------------------
*/
void
DBWAddButtonHandler(name, proc, cursor, doc)
char *name; /* Name of this button handler. This name
* is what's passed to DBWChangeButtonHandler
* to activate the handler.
*/
void (*proc)(); /* Procedure to call on button actions when
* this handler is active.
*/
int cursor; /* Cursor shape (e.g. STYLE_CURS_NORMAL) to
* use when this handler is active.
*/
char *doc; /* A documentation string for this handler:
* describes what the button pushes do when
* this handler is active.
*/
{
int i;
for (i = 0; i < MAXBUTTONHANDLERS; i++)
{
if (dbwButtonHandlers[i] != NULL) continue;
(void) StrDup(&dbwButtonHandlers[i], name);
(void) StrDup(&dbwButtonDoc[i], doc);
dbwButtonProcs[i] = proc;
dbwButtonCursors[i] = cursor;
return;
}
TxError("Can't add tool \"%s\": no space in button handler\n",
name);
TxError(" table. Get your Magic wizard to increase the size of\n");
TxError(" MAXBUTTONHANDLERS in DBWbuttons.c\n");
}
/*
* ----------------------------------------------------------------------------
*
* DBWChangeButtonHandler --
*
* Change the active button handler.
*
* Results:
* The return value is the name of the previous button handler, in
* case the caller should wish to restore it.
*
* Side effects:
* If name is NULL, then the "next" button handler is activated, in a
* circular fashion. If name isn't NULL, then it is the name of a
* handler, which is activated. If the name doesn't match a handler
* then a message is printed and the handler isn't changed.
*
* ----------------------------------------------------------------------------
*/
char *
DBWChangeButtonHandler(name)
char *name; /* Name of new handler. Must be a unique
* abbreviation of a name passed previously
* to DBAddButtonHandler, or NULL.
*/
{
char *oldName = dbwButtonHandlers[dbwButtonCurrentIndex];
static int firstTime = TRUE;
if (name == NULL)
{
/* Just rotate to the next available client. */
while (TRUE)
{
dbwButtonCurrentIndex += 1;
if (dbwButtonCurrentIndex >= MAXBUTTONHANDLERS)
dbwButtonCurrentIndex = 0;
if (dbwButtonHandlers[dbwButtonCurrentIndex] == NULL)
continue;
if (firstTime)
{
firstTime = FALSE;
TxPrintf("Switching to \"%s\" tool.",
dbwButtonHandlers[dbwButtonCurrentIndex]);
TxPrintf(" If you didn't really want to switch,\n");
TxPrintf(" type \":tool box\" to");
TxPrintf(" switch back to the box tool.\n");
}
else
{
TxPrintf("Switching to \"%s\" tool.\n",
dbwButtonHandlers[dbwButtonCurrentIndex]);
}
break;
}
}
else
{
int i, match, length;
match = -1;
length = strlen(name);
for (i = 0; i < MAXBUTTONHANDLERS; i++)
{
if (dbwButtonHandlers[i] == NULL) continue;
if (strncmp(name, dbwButtonHandlers[i], length) != 0) continue;
if (match >= 0)
{
TxError("\"%s\" is an ambiguous tool name.", name);
match = -2;
break;
}
match = i;
}
if (match == -1)
TxError("\"%s\" isn't a tool name.", name);
if (match < 0)
{
TxError(" The legal names are:\n");
for (i = 0; i < MAXBUTTONHANDLERS; i++)
{
if (dbwButtonHandlers[i] == NULL) continue;
TxError(" %s\n", dbwButtonHandlers[i]);
}
return oldName;
}
dbwButtonCurrentIndex = match;
}
GrSetCursor(dbwButtonCursors[dbwButtonCurrentIndex]);
DBWButtonCurrentProc = dbwButtonProcs[dbwButtonCurrentIndex];
return oldName;
}
/*
* ----------------------------------------------------------------------------
*
* DBWPrintButtonDoc --
*
* This procedure prints out documentation for the current
* button handler.
*
* Results:
* None.
*
* Side effects:
* Stuff gets printed on the tty, ostensibly describing what
* the current buttons do.
*
* ----------------------------------------------------------------------------
*/
void
DBWPrintButtonDoc()
{
TxPrintf("%s", dbwButtonDoc[dbwButtonCurrentIndex]);
}
/*
* ----------------------------------------------------------------------------
* dbwButtonSetCursor --
*
* Used to set the programmable cursor for a particular
* button state.
*
* Results:
* None.
*
* Side effects:
* Selects and sets a programmable cursor based on the given
* button (for sizing or moving) and corner.
* ----------------------------------------------------------------------------
*/
void
dbwButtonSetCursor(button, corner)
int button; /* Button that is down. */
int corner; /* Corner to be displayed in cursor. */
{
switch (corner)
{
case TOOL_BL:
if (button == TX_LEFT_BUTTON)
GrSetCursor(STYLE_CURS_LLBOX);
else
GrSetCursor(STYLE_CURS_LLCORNER);
break;
case TOOL_BR:
if (button == TX_LEFT_BUTTON)
GrSetCursor(STYLE_CURS_LRBOX);
else
GrSetCursor(STYLE_CURS_LRCORNER);
break;
case TOOL_TL:
if (button == TX_LEFT_BUTTON)
GrSetCursor(STYLE_CURS_ULBOX);
else
GrSetCursor(STYLE_CURS_ULCORNER);
break;
case TOOL_TR:
if (button == TX_LEFT_BUTTON)
GrSetCursor(STYLE_CURS_URBOX);
else
GrSetCursor(STYLE_CURS_URCORNER);
break;
}
}
/*
* ----------------------------------------------------------------------------
*
* DBWBoxHandler --
*
* This procedure is called to handle button actions in layout
* windows when the "box" handler is active. It adjusts the box
* position and size.
*
* Results:
* None.
*
* Side effects:
* Left button: used to move the whole box by the lower-left corner.
* Right button: used to re-size the box by its upper-right corner.
* If one of the left or right buttons is pushed, then the
* other is pushed, the corner is switched to the nearest
* one to the cursor. This corner is remembered for use
* in box positioning/sizing when both buttons have gone up.
* Middle button: used to paint whatever layers are underneath the
* crosshair.
*
* ----------------------------------------------------------------------------
*/
void
DBWBoxHandler(w, cmd)
MagWindow *w; /* Window containing cursor. */
TxCommand *cmd; /* Describes what happened. */
{
int button = cmd->tx_button;
if (button == TX_MIDDLE_BUTTON)
{
if (cmd->tx_buttonAction == TX_BUTTON_DOWN)
CmdPaintEraseButton(w, &cmd->tx_p, TRUE);
return;
}
if (cmd->tx_buttonAction == TX_BUTTON_DOWN)
{
if ((WindNewButtons & (TX_LEFT_BUTTON|TX_RIGHT_BUTTON))
== (TX_LEFT_BUTTON|TX_RIGHT_BUTTON))
{
/* Both buttons are now down. In this case, the FIRST
* button pressed determines whether we move or size,
* and the second button is just used as a signal to pick
* the closest corner.
*/
buttonCorner = ToolGetCorner(&cmd->tx_p);
if (button == TX_LEFT_BUTTON) button = TX_RIGHT_BUTTON;
else button = TX_LEFT_BUTTON;
}
else if (button == TX_LEFT_BUTTON) buttonCorner = TOOL_BL;
else buttonCorner = TOOL_TR;
dbwButtonSetCursor(button, buttonCorner);
}
else
{
/* A button has just come up. If both buttons are down and one
* is released, we just change the cursor to reflect the current
* corner and the remaining button (i.e. move or size box).
*/
if (WindNewButtons != 0)
{
if (button == TX_LEFT_BUTTON)
dbwButtonSetCursor(TX_RIGHT_BUTTON, buttonCorner);
else dbwButtonSetCursor(TX_LEFT_BUTTON, buttonCorner);
return;
}
/* The last button has been released. Reset the cursor to normal
* form and then move or size the box.
*/
GrSetCursor(STYLE_CURS_NORMAL);
switch (button)
{
case TX_LEFT_BUTTON:
ToolMoveBox(buttonCorner, &cmd->tx_p, TRUE, (CellDef *) NULL);
break;
case TX_RIGHT_BUTTON:
ToolMoveCorner(buttonCorner, &cmd->tx_p, TRUE,
(CellDef *) NULL);
}
}
}

680
dbwind/DBWcommands.c Normal file
View File

@ -0,0 +1,680 @@
/*
* DBWCommands.c --
*
* This file contains the dispatch tables for layout commands.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/dbwind/DBWcommands.c,v 1.3 2010/06/24 12:37:16 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "utils/main.h"
#include "commands/commands.h"
#include "textio/textio.h"
#include "textio/txcommands.h"
/*
* Standard DBWind command set
*/
extern void CmdAddPath(), CmdArray();
extern void CmdBox(), CmdCellname(), CmdClockwise();
extern void CmdContact(), CmdCopy(), CmdCorner();
extern void CmdCrash(), CmdCrosshair();
extern void CmdDelete(), CmdDown(), CmdDrc(), CmdDump();
extern void CmdEdit(), CmdElement(), CmdErase(), CmdExpand(), CmdExtract();
extern void CmdFeedback(), CmdFill(), CmdFindBox(), CmdFindLabel(), CmdFlush();
extern void CmdGetcell(), CmdGrid(), CmdIdentify();
extern void CmdLabel(), CmdLoad();
extern void CmdMove(), CmdNetlist(), CmdPaint(), CmdPath(), CmdPlow();
extern void CmdPolygon(), CmdPort(), CmdProperty();
extern void CmdSave(), CmdScaleGrid(), CmdSee();
extern void CmdSelect(), CmdSetLabel(), CmdSideways();
extern void CmdShell(), CmdSnap();
extern void CmdStretch(), CmdStraighten();
extern void CmdTech(), CmdTool(), CmdUnexpand();
extern void CmdUpsidedown(), CmdWhat(), CmdWire(), CmdWriteall();
extern void CmdGoto(), CmdFlatten(), CmdXload(), CmdXor();
/*
* Nonmanhattan geometry extensions
*/
extern void CmdSplit();
extern void CmdSplitErase();
/*
* Wizard commands
*/
extern void CmdCoord();
extern void CmdExtractTest();
extern void CmdExtResis();
extern void CmdPsearch();
extern void CmdPlowTest();
extern void CmdShowtech();
extern void CmdTilestats();
extern void CmdTsearch();
extern void CmdWatch();
/*
* CIF and GDS commands
*/
#ifdef CIF_MODULE
extern void CmdCif();
#endif
#ifdef CALMA_MODULE
extern void CmdCalma();
#endif
/*
* Plot module commands
*/
#ifdef PLOT_MODULE
extern void CmdPlot();
#endif
#ifdef PLOT_AUTO
extern void CmdAutoPlot();
#endif
/*
* SIM module commands
*/
#ifndef NO_SIM_MODULE
extern void CmdGetnode();
#ifdef RSIM_MODULE
extern void CmdRsim(), CmdSimCmd(), CmdStartRsim();
#endif
#endif
/*
* Router module commands
*/
#ifdef ROUTE_MODULE
extern void CmdGARouterTest(), CmdGRouterTest(), CmdIRouterTest();
extern void CmdMZRouterTest(), CmdSeeFlags();
extern void CmdChannel(), CmdGaRoute(), CmdIRoute(), CmdRoute();
#endif
#ifdef ROUTE_AUTO
extern void CmdAutoRoute();
#endif
/*
* LEF module commands
*/
#ifdef LEF_MODULE
extern void CmdLef();
#endif
#ifdef LEF_AUTO
extern void CmdAutoLef();
#endif
/*
* Wrapper commands for ext2spice and ext2sim
*/
#ifdef MAGIC_WRAPPER
#ifdef EXT2SIM_AUTO
extern void CmdAutoExtToSim();
#else
extern void CmdExtToSim();
#endif
#ifdef EXT2SPICE_AUTO
extern void CmdAutoExtToSpice();
#else
extern void CmdExtToSpice();
#endif
#endif
/*
* Readline extension history command
*/
#ifdef USE_READLINE
extern void CmdHistory();
#endif
/*
* Commands only in the Lawrence Livermore Version
*/
#ifdef LLNL
extern void CmdMakeSW();
extern void CmdSgraph();
#endif /* LLNL */
/*
* --------------------------------------------------------------
* DBWInitCommands --
*
* Add commands to the dbw command-line interface. As of
* Magic 7.2.41, this has been changed from a statically-pre-
* allocated array to a dynamically allocated array, allowing
* individual modules to add their commands outside of the
* scope of the "commands" subdirectory, and inside of their
* own initialization functions. The bulk of the dbwind
* interface functions is still in this file, however, with
* only a few functions moved out to improve modularization
* of the source code. It would be preferable to move every-
* thing out and remove the "commands" subdirectory altogether,
* but this is unlikely to happen.
*
* Results:
* None.
*
* SideEffects:
* DBWind commands are registered with the command interpreter.
*
* --------------------------------------------------------------
*/
void
DBWInitCommands()
{
/* Add wizard commands */
WindAddCommand(DBWclientID,
"*coord show coordinates of various things",
CmdCoord, FALSE);
WindAddCommand(DBWclientID,
"*extract [args] debug the circuit extractor",
CmdExtractTest, FALSE);
WindAddCommand(DBWclientID,
"*plow cmd [args] debug plowing",
CmdPlowTest, FALSE);
WindAddCommand(DBWclientID,
"*psearch plane count invoke point search over box area",
CmdPsearch, FALSE);
WindAddCommand(DBWclientID,
"*showtech [file] print internal technology tables",
CmdShowtech, FALSE);
WindAddCommand(DBWclientID,
"*tilestats [file] print statistics on tile utilization",
CmdTilestats, FALSE);
WindAddCommand(DBWclientID,
"*tsearch plane count invoke area search over box area",
CmdTsearch, FALSE);
WindAddCommand(DBWclientID,
"*watch [plane] enable verbose tile plane redisplay",
CmdWatch, FALSE);
WindAddCommand(DBWclientID,
"addpath [path] append to current search path",
CmdAddPath, FALSE);
WindAddCommand(DBWclientID,
"array xsize ysize OR\n"
"array xlo xhi ylo yhi\n"
" array everything in selection",
CmdArray, FALSE);
WindAddCommand(DBWclientID,
"box [dir [amount]] move box dist units in direction or (with\n"
" no arguments) show box size",
CmdBox, FALSE);
WindAddCommand(DBWclientID,
"cellname [list] children|parents|exists|self [name] OR\n"
"cellname [list] allcells|topcells\n"
" list cells by relationship to cell \"name\", or\n"
" the current selection if no name given. \"list\"\n"
" returns result as a list. \"exists + name\" returns\n"
" true or false (also see command instance)",
CmdCellname, FALSE);
WindAddCommand(DBWclientID,
"clockwise [deg] rotate selection and box clockwise",
CmdClockwise, FALSE);
WindAddCommand(DBWclientID,
"contact type paint contact type on the intersection of its\n"
" residues",
CmdContact, FALSE);
WindAddCommand(DBWclientID,
"copy [dir [amount]] OR\n"
"copy to x y copy selection: what used to be at box\n"
" lower-left will be copied at cursor location (or,\n"
" copy will appear amount units in dir from original);\n"
" second form will copy to location x y",
CmdCopy, FALSE);
WindAddCommand(DBWclientID,
"corner d1 d2 [layers] make L-shaped wires inside box, filling\n"
" first in direction d1, then in d2",
CmdCorner, FALSE);
WindAddCommand(DBWclientID,
"crash save|recover [file]\n"
" recover the crash file \"file\", or the first\n"
" crash file discovered.",
CmdCrash, FALSE);
WindAddCommand(DBWclientID,
"crosshair x y | off enable and move or disable the screen crosshair",
CmdCrosshair, FALSE);
WindAddCommand(DBWclientID,
"delete delete everything in selection",
CmdDelete, FALSE);
WindAddCommand(DBWclientID,
"down load selected cell into a window",
CmdDown, FALSE);
WindAddCommand(DBWclientID,
"drc option design rule checker; type \"drc help\"\n"
" for information on options",
CmdDrc, FALSE);
WindAddCommand(DBWclientID,
"dump cell [child refPointC] [parent refPointP]\n\
copy contents of cell into edit cell, so that\n\
refPointC (or lower left) of cell is at refPointP\n\
(or box lower-left); refPoints are either labels\n\
or a pair of coordinates (e.g, 100 200)",
CmdDump, FALSE);
WindAddCommand(DBWclientID,
"edit use selected cell as new edit cell",
CmdEdit, FALSE);
WindAddCommand(DBWclientID,
"element option add a generic drawing element to the layout",
CmdElement, FALSE);
WindAddCommand(DBWclientID,
"erase [layers]|cursor erase mask information",
CmdErase, FALSE);
WindAddCommand(DBWclientID,
"expand [toggle] expand everything under box, or toggle\n\
expanded/unexpanded cells in selection",
CmdExpand, FALSE);
WindAddCommand(DBWclientID,
"ext option OR",
CmdExtract, FALSE); /* For "ext" abbreviation */
WindAddCommand(DBWclientID,
"extract option circuit extractor; type \"extract help\"\n\
for information on options",
CmdExtract, FALSE); /* For "extract" */
WindAddCommand(DBWclientID,
"extresist [args] patch .ext file with resistance info",
CmdExtResis, FALSE);
WindAddCommand(DBWclientID,
"feedback option find out about problems; "
"type \"feedback help\"\n\t\t\tfor information on options",
CmdFeedback, FALSE);
WindAddCommand(DBWclientID,
"fill dir [layers] fill layers from one side of box to other",
CmdFill, FALSE);
WindAddCommand(DBWclientID,
"findbox [zoom] center the window on the box and optionally zoom in",
CmdFindBox, FALSE);
WindAddCommand(DBWclientID,
"findlabel lab set the box to the location of this label",
CmdFindLabel, FALSE);
WindAddCommand(DBWclientID,
"flatten destname flatten edit cell into cell destname",
CmdFlatten, FALSE);
WindAddCommand(DBWclientID,
"flush [cellname] flush changes to cellname (edit cell default)",
CmdFlush, FALSE);
WindAddCommand(DBWclientID,
"get OR",
CmdGetcell, FALSE);
WindAddCommand(DBWclientID,
"getcell cell [child refPointC] [parent refPointP]\n\
get cell as a subcell of the edit cell, so that\n\
refPointC (or lower left) of cell is at refPointP\n\
(or box lower-left); refPoints are either labels\n\
or a pair of coordinates (e.g, 100 200)",
CmdGetcell, FALSE);
WindAddCommand(DBWclientID,
"goto nodename goto the node named nodename",
CmdGoto, FALSE);
WindAddCommand(DBWclientID,
"grid [xSpacing [ySpacing [xOrigin yOrigin]]]\n\
toggle grid on/off (and set parameters)",
CmdGrid, FALSE);
WindAddCommand(DBWclientID,
"id OR",
CmdIdentify, FALSE);
WindAddCommand(DBWclientID,
"identify use_id set the use identifier of the selected cell",
CmdIdentify, FALSE);
WindAddCommand(DBWclientID,
"instance [list] children|parents|exists|self [name] OR\n"
"instance [list] allcells|topcells\n\
List cells by relationship to cell \"name\", or\n\
the current selection if no name given. \"list\"\n\
returns result as a list. \"exists + name\" returns\n\
true or false (also see command cellname)",
CmdCellname, FALSE);
WindAddCommand(DBWclientID,
"label str [pos [layer]]\n\
place a label",
CmdLabel, FALSE);
WindAddCommand(DBWclientID,
"load [cellname] load a cell into a window",
CmdLoad, FALSE);
WindAddCommand(DBWclientID,
"move [dir [amount]] OR\n"
"move to x y move box and selection, either by amount\n\
in dir, or pick up by box lower-left and put\n\
down at cursor position; second form will\n\
put box at location x y",
CmdMove, FALSE);
/* Added by NP 10/28/2004 */
WindAddCommand(DBWclientID,
"netlist option netlist operation; type \"netlist help\"\n\
for information on options",
CmdNetlist, FALSE);
WindAddCommand(DBWclientID,
"paint layers|cursor paint mask information",
CmdPaint, FALSE);
WindAddCommand(DBWclientID,
"path [search|cell|sys] [[+]path]\n\
set or print search paths",
CmdPath, FALSE);
WindAddCommand(DBWclientID,
"plow option [args] stretching and compaction; type \"plow help\"\n\
for information on options",
CmdPlow, FALSE);
WindAddCommand(DBWclientID,
"port [index] [direction...]\n\
declare a label to be a subcircuit port",
CmdPort, FALSE);
WindAddCommand(DBWclientID,
"polygon type x1 y1 x2 y2 [x3 y3. . .] xn yn\n\
draw a polygon from a list of point pairs",
CmdPolygon, FALSE);
WindAddCommand(DBWclientID,
"property [name] [value]\n\
add a property (string) to the edit cell",
CmdProperty, FALSE);
WindAddCommand(DBWclientID,
"rotate [+/-][deg] rotate selection and box (counter)clockwise",
CmdClockwise, FALSE); /* "rotate" is alias for "clockwise" */
WindAddCommand(DBWclientID,
"save [filename] save edit cell on disk",
CmdSave, FALSE);
WindAddCommand(DBWclientID,
"scalegrid a b scale magic units vs. lambda by a / b",
CmdScaleGrid, FALSE);
WindAddCommand(DBWclientID,
"see [no] layers|allSame change what's displayed in the window",
CmdSee, FALSE);
WindAddCommand(DBWclientID,
"select [option] change selection; type \"select help\"\n\
for information on options",
CmdSelect, FALSE);
WindAddCommand(DBWclientID,
"setlabel [option [value]] place a label",
CmdSetLabel, FALSE);
WindAddCommand(DBWclientID,
"shell [command] execute a command in a subshell",
CmdShell, FALSE);
WindAddCommand(DBWclientID,
"sideways flip selection and box sideways",
CmdSideways, FALSE);
WindAddCommand(DBWclientID,
"snap [internal|lambda|user]\n\
cause box to snap to the selected grid when moved\n\
by the cursor",
CmdSnap, FALSE);
WindAddCommand(DBWclientID,
"straighten direction straighten jogs by pulling in direction",
CmdStraighten, FALSE);
WindAddCommand(DBWclientID,
"stretch [dir [amount]] stretch box and selection",
CmdStretch, FALSE);
WindAddCommand(DBWclientID,
"tech option technology handling; type \"techinfo help\"\n\
for information on options",
CmdTech, FALSE);
#ifndef MAGIC_WRAPPER
WindAddCommand(DBWclientID,
"tool [name|info] change layout tool or print info about what\n\
buttons mean for current tool",
CmdTool, FALSE);
#endif
WindAddCommand(DBWclientID,
"unexpand unexpand subcells under box",
CmdUnexpand, FALSE);
WindAddCommand(DBWclientID,
"upsidedown flip selection and box upside down",
CmdUpsidedown, FALSE);
WindAddCommand(DBWclientID,
"what print out information about what's selected",
CmdWhat, FALSE);
WindAddCommand(DBWclientID,
"wire option [args] wiring-style user interface; type\n\
\"wire help\" for information on options",
CmdWire, FALSE);
WindAddCommand(DBWclientID,
"writeall [force] write out all modified cells to disk",
CmdWriteall, FALSE);
WindAddCommand(DBWclientID,
"xload [cellname] load a cell into a window unexpanded",
CmdXload, FALSE);
WindAddCommand(DBWclientID,
"xor destname flatten current top level cell into destname\n\
and xor with existing contents",
CmdXor, FALSE);
#ifdef CIF_MODULE
/* Add the CIF extension commands */
WindAddCommand(DBWclientID,
"cif option CIF processor; type \"cif help\"\n\
for information on options",
CmdCif, FALSE);
#endif
#ifdef CALMA_MODULE
/* Add the GDS extension commands */
WindAddCommand(DBWclientID,
"calma option Calma GDS-II stream file processor; type\n\
\"calma help\" for information on options",
CmdCalma, FALSE); /* "gds" is an alias for "calma" */
WindAddCommand(DBWclientID,
"gds option alias for the \"calma\" command",
CmdCalma, FALSE);
#endif
/* Add the NonManhattan Geometry extension commands */
WindAddCommand(DBWclientID,
"splitpaint dir layer [layer2]\n\
split box diagonally with layer in corner dir and\n\
layer2 in the opposite corner (default layer2 is space)",
CmdSplit, FALSE);
WindAddCommand(DBWclientID,
"spliterase dir [layer] erase layers from diagonal corner dir of the\n\
edit box",
CmdSplitErase, FALSE);
#ifdef MAGIC_WRAPPER
/* Add the Tcl commands for exttospice, exttosim, and aliases ext2spice, ext2sim */
#ifdef EXT2SIM_AUTO
WindAddCommand(DBWclientID,
"exttosim [args] convert extracted file(s) to a sim format file;"
" type\n\t\t\t\"exttosim help\" for information on options",
CmdAutoExtToSim, FALSE);
WindAddCommand(DBWclientID,
"ext2sim [args] convert extracted file(s) to a sim format file;"
" type\n\t\t\t\"ext2sim help\" for information on options",
CmdAutoExtToSim, FALSE);
#else
WindAddCommand(DBWclientID,
"exttosim [args] convert extracted file(s) to a sim format file;"
" type\n\t\t\t\"exttosim help\" for information on options",
CmdExtToSim, FALSE);
WindAddCommand(DBWclientID,
"ext2sim [args] convert extracted file(s) to a sim format file;"
" type\n\t\t\t\"ext2sim help\" for information on options",
CmdExtToSim, FALSE);
#endif /* EXT2SIM_AUTO */
#ifdef EXT2SPICE_AUTO
WindAddCommand(DBWclientID,
"exttospice [args] convert extracted file(s) to a SPICE format file;"
" type\n\t\t\t\"exttospice help\" for information on options",
CmdAutoExtToSpice, FALSE);
WindAddCommand(DBWclientID,
"ext2spice [args] convert extracted file(s) to a SPICE format file;"
" type\n\t\t\t\"ext2spice help\" for information on options",
CmdAutoExtToSpice, FALSE);
#else
WindAddCommand(DBWclientID,
"exttospice [args] convert extracted file(s) to a SPICE format file;"
" type\n\t\t\t\"exttospice help\" for information on options",
CmdExtToSpice, FALSE);
WindAddCommand(DBWclientID,
"ext2spice [args] convert extracted file(s) to a SPICE format file;"
" type\n\t\t\t\"ext2spice help\" for information on options",
CmdExtToSpice, FALSE);
#endif /* EXT2SPICE_AUTO */
#endif /* MAGIC_WRAPPER */
#ifdef USE_READLINE
/* Add the Readline extension history command */
WindAddCommand(DBWclientID,
"history print out the command history list",
CmdHistory, FALSE);
#endif
#ifdef LLNL
/* Add the Lawrence Livermore extensions */
WindAddCommand(DBWclientID,
"makesw options generate scan window for LP apparatus",
CmdMakeSW, FALSE);
WindAddCommand(DBWclientID,
"sgraph [options] manipulate a cell's stretch graphs",
CmdSgraph, FALSE);
#endif
#ifndef NO_SIM_MODULE
/* Add the IRSIM commands */
WindAddCommand(DBWclientID,
"getnode option get node names of all selected paint",
CmdGetnode, FALSE);
#ifdef RSIM_MODULE
WindAddCommand(DBWclientID,
"rsim [options] filename run Rsim under Magic",
CmdRsim, FALSE);
WindAddCommand(DBWclientID,
"simcmd cmd send a command to Rsim, applying it to selected paint",
CmdSimCmd, FALSE);
WindAddCommand(DBWclientID,
"startrsim [options] file start Rsim and return to Magic",
CmdStartRsim, FALSE);
#endif
#endif
#ifdef PLOT_MODULE
/* Add the plot extensions */
WindAddCommand(DBWclientID,
"plot type [args] hardcopy plotting; type \"plot help\"\n\
for information on types and args",
CmdPlot, FALSE);
#endif
#ifdef PLOT_AUTO
/* Placeholder for plot extensions */
WindAddCommand(DBWclientID,
"plot type [args] hardcopy plotting; type \"plot help\"\n\
for information on types and args",
CmdAutoPlot, FALSE);
#endif
#ifdef LEF_MODULE
/* Add the LEF/DEF extensions */
WindAddCommand(DBWclientID,
"lef [options] LEF-format input/output; type \"lef help\"\n\
for information on options",
CmdLef, FALSE);
WindAddCommand(DBWclientID,
"def [options] DEF-format input; type \"def help\"\n\
for information on options",
CmdLef, FALSE);
#endif
#ifdef LEF_AUTO
/* Placeholder for LEF/DEF extensions */
WindAddCommand(DBWclientID,
"lef [options] LEF-format input/output; type \"lef help\"\n\
for information on options",
CmdAutoLef, FALSE);
WindAddCommand(DBWclientID,
"def [options] DEF-format input; type \"def help\"\n\
for information on options",
CmdAutoLef, FALSE);
#endif
#ifdef ROUTE_MODULE
/* Add the router extensions */
WindAddCommand(DBWclientID,
"*garoute [cmd [args]] debug the gate-array router",
CmdGARouterTest, FALSE);
WindAddCommand(DBWclientID,
"*groute [cmd [args]] debug the global router",
CmdGRouterTest, FALSE);
WindAddCommand(DBWclientID,
"*iroute [cmd [args]] debug the interactive router",
CmdIRouterTest, FALSE);
WindAddCommand(DBWclientID,
"*mzroute [cmd [args]] debug the maze router",
CmdMZRouterTest, FALSE);
WindAddCommand(DBWclientID,
"*seeflags [flag] display channel flags over channel",
CmdSeeFlags, FALSE);
WindAddCommand(DBWclientID,
"channels see channels (feedback) without doing routing",
CmdChannel, FALSE);
WindAddCommand(DBWclientID,
"garoute [cmd [args]] gate-array router",
CmdGaRoute, FALSE);
WindAddCommand(DBWclientID,
"iroute [cmd [args]] do interactive point to point route",
CmdIRoute, FALSE);
WindAddCommand(DBWclientID,
"route route the current cell",
CmdRoute, FALSE);
#endif
#ifdef ROUTE_AUTO
/* Placeholder for router extensions */
WindAddCommand(DBWclientID,
"*garoute [cmd [args]] debug the gate-array router",
CmdAutoRoute, FALSE);
WindAddCommand(DBWclientID,
"*groute [cmd [args]] debug the global router",
CmdAutoRoute, FALSE);
WindAddCommand(DBWclientID,
"*iroute [cmd [args]] debug the interactive router",
CmdAutoRoute, FALSE);
WindAddCommand(DBWclientID,
"*mzroute [cmd [args]] debug the maze router",
CmdAutoRoute, FALSE);
WindAddCommand(DBWclientID,
"*seeflags [flag] display channel flags over channel",
CmdAutoRoute, FALSE);
WindAddCommand(DBWclientID,
"channels see channels (feedback) without doing routing",
CmdAutoRoute, FALSE);
WindAddCommand(DBWclientID,
"garoute [cmd [args]] gate-array router",
CmdAutoRoute, FALSE);
WindAddCommand(DBWclientID,
"iroute [cmd [args]] do interactive point to point route",
CmdAutoRoute, FALSE);
WindAddCommand(DBWclientID,
"route route the current cell",
CmdAutoRoute, FALSE);
#endif
}

1781
dbwind/DBWdisplay.c Normal file

File diff suppressed because it is too large Load Diff

1204
dbwind/DBWelement.c Normal file

File diff suppressed because it is too large Load Diff

645
dbwind/DBWfdback.c Normal file
View File

@ -0,0 +1,645 @@
/* DBWfeedback.c -
*
* This file provides a standard set of procedures for Magic
* commands to use to provide feedback to users. Feedback
* consists of areas of the screen that are highlighted, along
* with text describing why those particular areas are important.
* Feedback is used for things like displaying CIF, and for errors
* in CIF-generation and routing.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/dbwind/DBWfdback.c,v 1.2 2010/06/24 12:37:16 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "windows/windows.h"
#include "graphics/graphics.h"
#include "dbwind/dbwind.h"
#include "utils/utils.h"
#include "utils/styles.h"
#include "utils/malloc.h"
#include "utils/signals.h"
/* Use a reference-counted character structure for feedback info */
typedef struct rcstring
{
int refcount;
char *string;
} RCString;
/* Each feedback area is stored in a record that looks like this: */
typedef struct feedback
{
Rect fb_area; /* The area to be highlighted, in coords of
* fb_rootDef, but prior to scaling by
* fb_scale.
*/
Rect fb_rootArea; /* The area of the feedback, in Magic coords.
* of fb_rootDef, scaled up to the next
* integral Magic unit.
*/
RCString *fb_text; /* Text explanation for the feedback. */
CellDef *fb_rootDef; /* Root definition of windows in which to
* display this feedback.
*/
int fb_scale; /* Scale factor to use in redisplaying
* (fb_scale units in fb_area correspond
* to one unit in fb_rootDef).
*/
int fb_style; /* Display style to use for this feedback. */
} Feedback;
/* The following stuff describes all the feedback information we know
* about. The feedback is stored in a big array that grows whenever
* necessary.
*/
static Feedback *dbwfbArray = NULL; /* Array holding all feedback info. */
global int DBWFeedbackCount = 0; /* Number of active entries in
* dbwfbArray.
*/
static int dbwfbSize = 0; /* Size of dbwfbArray, in entries. */
static int dbwfbNextToShow = 0; /* Index of first feedback area that
* hasn't been displayed yet. Used by
* DBWFBShow.
*/
static CellDef *dbwfbRootDef; /* To pass root cell definition from
* dbwfbGetTransform back up to
* DBWFeedbackAdd.
*/
/*
* ----------------------------------------------------------------------------
*
* DBWFeedbackRedraw --
*
* This procedure is called by the highlight manager to redisplay
* feedback highlights. The window is locked before entry.
*
* Results:
* None.
*
* Side effects:
* Any feedback information that overlaps a non-space tile in
* plane is redrawn.
*
* Tricky stuff:
* Redisplay is numerically difficult, particularly when feedbacks
* have a large internal scale factor: the tendency is to get
* integer overflow and get everything goofed up. Be careful
* when making changes to the code below.
*
* ----------------------------------------------------------------------------
*/
void
DBWFeedbackRedraw(window, plane)
MagWindow *window; /* Window in which to redraw. */
Plane *plane; /* Non-space tiles on this plane mark what
* needs to be redrawn.
*/
{
dlong x, y;
int i, halfScale, curStyle, newStyle, curScale;
CellDef *windowRoot;
Rect worldArea, screenArea, tmp;
Feedback *fb;
extern int dbwFeedbackAlways1(); /* Forward reference. */
if (DBWFeedbackCount == 0) return;
windowRoot = ((CellUse *) (window->w_surfaceID))->cu_def;
curStyle = -1;
curScale = -1;
for (i = 0, fb = dbwfbArray; i < DBWFeedbackCount; i++, fb++)
{
/* We expect that most of the feedbacks will have the same
* style and scale, so compute information with the current
* values, and recompute only when the values change.
*/
if (fb->fb_scale != curScale)
{
curScale = fb->fb_scale;
halfScale = curScale / 2;
worldArea.r_xbot = window->w_surfaceArea.r_xbot * curScale;
worldArea.r_xtop = window->w_surfaceArea.r_xtop * curScale;
worldArea.r_ybot = window->w_surfaceArea.r_ybot * curScale;
worldArea.r_ytop = window->w_surfaceArea.r_ytop * curScale;
}
/*
* Check to make sure this feedback area is relevant.
* Clip it to TiPlaneRect as a sanity check against
* callers who provide a feedback area that extends
* out somewhere in never-never land.
*/
if (fb->fb_rootDef != windowRoot) continue;
tmp = fb->fb_rootArea;
GeoClip(&tmp, &TiPlaneRect);
if (!DBSrPaintArea((Tile *) NULL, plane, &tmp,
&DBAllButSpaceBits, dbwFeedbackAlways1, (ClientData) NULL))
continue;
/* Transform the feedback area to screen coords. This is
* very similar to the code in WindSurfaceToScreen, except
* that there's additional scaling involved.
*/
tmp = fb->fb_area;
/* Don't clip non-Manhattan tiles, or else the diagonals are */
/* clipped to an incorrect position. */
if (!(fb->fb_style & TT_DIAGONAL))
GeoClip(&tmp, &worldArea);
/*
* Ignore areas which have been clipped out of existence
*/
if (tmp.r_xtop < tmp.r_xbot || tmp.r_ytop < tmp.r_ybot)
continue;
x = ((dlong)(tmp.r_xbot - worldArea.r_xbot) * window->w_scale) + halfScale;
screenArea.r_xbot = (int)((x/curScale + window->w_origin.p_x) >> SUBPIXELBITS);
x = ((dlong)(tmp.r_xtop - worldArea.r_xbot) * window->w_scale) + halfScale;
screenArea.r_xtop = (int)((x/curScale + window->w_origin.p_x) >> SUBPIXELBITS);
y = ((dlong)(tmp.r_ybot - worldArea.r_ybot) * window->w_scale) + halfScale;
screenArea.r_ybot = (int)((y/curScale + window->w_origin.p_y) >> SUBPIXELBITS);
y = ((dlong)(tmp.r_ytop - worldArea.r_ybot) * window->w_scale) + halfScale;
screenArea.r_ytop = (int)((y/curScale + window->w_origin.p_y) >> SUBPIXELBITS);
/*
* Sanity check on integer bounds
*/
if (screenArea.r_xtop < screenArea.r_xbot ||
screenArea.r_ytop < screenArea.r_ybot)
{
TxError("Internal error: Feedback area exceeds integer bounds "
"on screen rectangle!\n");
continue;
}
newStyle = fb->fb_style & (TT_LEFTMASK | TT_RIGHTMASK);
/* Another little trick: when the feedback area is very small ("very
* small" is a hand-tuned constant), change all stippled styles to
* solid.
* (The usefulness of this trick is questionable, as it generally
* creates very bothersome output for the "cif see" function and
* other places where the feedback is generated from tiles.)
*/
/*
if (((GEO_WIDTH(&screenArea) < 18) || (GEO_HEIGHT(&screenArea) < 18))
&& ((newStyle == STYLE_MEDIUMHIGHLIGHTS)
|| (newStyle == STYLE_PALEHIGHLIGHTS)))
newStyle = STYLE_SOLIDHIGHLIGHTS;
*/
if (newStyle != curStyle)
{
curStyle = newStyle;
GrSetStuff(curStyle);
}
if (fb->fb_style & TT_DIAGONAL)
GrDiagonal(&screenArea, fb->fb_style);
/* Special case (i.e., "hack")---to get a diagonal line */
/* instead of a triangle, set TT_SIDE but not */
/* TT_DIAGONAL. TT_DIRECTION still indicates / or \ */
else if (fb->fb_style & TT_SIDE)
{
if (fb->fb_style & TT_DIRECTION)
GrClipLine(screenArea.r_xbot, screenArea.r_ytop,
screenArea.r_xtop, screenArea.r_ybot);
else
GrClipLine(screenArea.r_xbot, screenArea.r_ybot,
screenArea.r_xtop, screenArea.r_ytop);
}
else
GrFastBox(&screenArea);
}
}
int
dbwFeedbackAlways1()
{
return 1;
}
/*
* ----------------------------------------------------------------------------
*
* DBWFeedbackClear --
*
* This procedure clears all existing feedback information from
* the screen.
*
* Results:
* None.
*
* Side effects:
* Any existing feedback information is cleared from the screen
* and from our database.
*
* ----------------------------------------------------------------------------
*/
void
DBWFeedbackClear(text)
char *text;
{
int i, oldCount;
Feedback *fb, *fl, *fe;
Rect area;
CellDef *currentRoot;
RCString *quickptr = NULL;
/* Clear out the feedback array and recycle string storage. Whenever
* the root cell changes, make a call to erase from the screen.
*/
currentRoot = (CellDef *) NULL;
oldCount = DBWFeedbackCount;
DBWFeedbackCount = 0;
for (fb = dbwfbArray; fb < dbwfbArray + oldCount; fb++)
{
if ((text == NULL) ||
((quickptr != NULL) && (fb->fb_text == quickptr)) ||
(strstr(fb->fb_text->string, text) != NULL))
{
// Track the last refcount string that matched the
// text so we can run through lists of matching text
// without having to call strstr()
if (text != NULL) quickptr = fb->fb_text;
if (currentRoot != fb->fb_rootDef)
{
if (currentRoot != (CellDef *) NULL)
DBWHLRedraw(currentRoot, &area, TRUE);
area = GeoNullRect;
}
(void) GeoInclude(&fb->fb_rootArea, &area);
currentRoot = fb->fb_rootDef;
// Decrement refcount and free if zero.
fb->fb_text->refcount--;
if (fb->fb_text->refcount == 0)
{
freeMagic(fb->fb_text->string);
freeMagic(fb->fb_text);
}
fb->fb_text = NULL;
}
}
if (currentRoot != NULL)
DBWHLRedraw(currentRoot, &area, TRUE);
dbwfbNextToShow = 0;
if (text != NULL)
{
/* Close up feedback list around removed text entries */
fl = dbwfbArray;
fe = fl + oldCount;
for (fb = dbwfbArray; fb < fe; fb++)
{
while ((fb->fb_text == NULL) && (fb < fe)) fb++;
if (fb < fe) *fl++ = *fb;
}
DBWFeedbackCount = (int)(fl - dbwfbArray);
for (fb = fl; fb < dbwfbArray + oldCount; fb++)
fb->fb_text = NULL;
}
/* Free up feedback memory whenever we have removed all feedback entries */
if (DBWFeedbackCount == 0)
{
if (dbwfbArray != NULL) {
freeMagic((char *) dbwfbArray);
dbwfbArray = NULL;
}
dbwfbSize = 0;
return;
}
}
/*
* ----------------------------------------------------------------------------
*
* DBWFeedbackAdd --
*
* Adds a new piece of feedback information to the list we have
* already.
*
* Results:
* None.
*
* Side effects:
* CellDef's ancestors are searched until its first root definition
* is found, and the coordinates of area are transformed into the
* root. Then the feedback area is added to our current list, using
* the style and scalefactor given. This stuff will be displayed on
* the screen at the end of the current command.
* ----------------------------------------------------------------------------
*/
void
DBWFeedbackAdd(area, text, cellDef, scaleFactor, style)
Rect *area; /* The area to be highlighted. */
char *text; /* Text associated with the area. */
CellDef *cellDef; /* The cellDef in whose coordinates area
* is given.
*/
int scaleFactor; /* The coordinates provided for feedback
* areas are divided by this to produce
* coordinates in Magic database units.
* This will probably be 1 most of the time.
* By making it bigger, say 10, and scaling
* other coordinates appropriately, it's
* possible to draw narrow lines on the
* screen, or to handle CIF, which isn't in
* exactly the same coordinates as other Magic
* stuff.
*/
int style; /* A display style to use for the feedback.
* Use one of:
* STYLE_OUTLINEHIGHLIGHTS: solid outlines
* STYLE_DOTTEDHIGHLIGHTS: dotted outlines
* STYLE_SOLIDHIGHLIGHTS: solid fill
* STYLE_MEDIUMHIGHLIGHTS: medium stipple
* STYLE_PALEHIGHLIGHTS: pald stipple
* At very coarse viewing scales, the last
* two styles are hard to see, so they are
* turned into STYLE_SOLIDHIGHLIGHTS.
*/
{
Rect tmp, tmp2, tmp3;
Transform transform;
int i;
Feedback *fb, *fblast;
extern int dbwfbGetTransform(); /* Forward declaration. */
/* Find a transform from this cell to the root, and use it to
* transform the area. If the root isn't an ancestor, just
* return.
*/
if (!DBSrRoots(cellDef, &GeoIdentityTransform,
dbwfbGetTransform, (ClientData) &transform)) return;
/* SigInterruptPending screws up DBSrRoots */
if (SigInterruptPending)
return;
/* Don't get fooled like I did. The translations for
* this transform are in Magic coordinates, not feedback
* coordinates. Scale them into feedback coordinates.
*/
transform.t_c *= scaleFactor;
transform.t_f *= scaleFactor;
GeoTransRect(&transform, area, &tmp2);
area = &tmp2;
/* Make sure there's enough space in the current array. If
* not, make a new array, copy the old to the new, then delete
* the old array. Use memcpy() to make sure this happens very fast.
*/
if (DBWFeedbackCount == dbwfbSize)
{
Feedback *new;
if (dbwfbSize == 0) dbwfbSize = 32;
else dbwfbSize <<= 1;
new = (Feedback *) mallocMagic(dbwfbSize * sizeof(Feedback));
memcpy((char *)new, (char *)dbwfbArray, DBWFeedbackCount * sizeof(Feedback));
for (i = DBWFeedbackCount; i < dbwfbSize; i++) new[i].fb_text = NULL;
if (dbwfbArray != NULL) freeMagic((char *) dbwfbArray);
dbwfbArray = new;
}
fb = &dbwfbArray[DBWFeedbackCount];
fb->fb_area = *area;
fblast = (DBWFeedbackCount == 0) ? NULL : &dbwfbArray[DBWFeedbackCount - 1];
if (fblast && (!strcmp(fblast->fb_text->string, text)))
{
fb->fb_text = fblast->fb_text;
fb->fb_text->refcount++;
}
else
{
fb->fb_text = (RCString *)mallocMagic(sizeof(RCString));
fb->fb_text->refcount = 1;
fb->fb_text->string = StrDup(NULL, text);
}
fb->fb_rootDef = dbwfbRootDef;
fb->fb_scale = scaleFactor;
fb->fb_style = style;
DBWFeedbackCount++;
/* Round the area up into Magic coords, and save it too. */
if (area->r_xtop > 0)
tmp.r_xtop = (area->r_xtop + scaleFactor - 1)/scaleFactor;
else tmp.r_xtop = area->r_xtop/scaleFactor;
if (area->r_ytop > 0)
tmp.r_ytop = (area->r_ytop + scaleFactor - 1)/scaleFactor;
else tmp.r_ytop = area->r_ytop/scaleFactor;
if (area->r_xbot > 0) tmp.r_xbot = area->r_xbot/scaleFactor;
else tmp.r_xbot = (area->r_xbot - scaleFactor + 1)/scaleFactor;
if (area->r_ybot > 0) tmp.r_ybot = area->r_ybot/scaleFactor;
else tmp.r_ybot = (area->r_ybot - scaleFactor + 1)/scaleFactor;
/* Clip to ensure well within TiPlaneRect */
tmp3.r_xbot = TiPlaneRect.r_xbot + 10;
tmp3.r_ybot = TiPlaneRect.r_ybot + 10;
tmp3.r_xtop = TiPlaneRect.r_xtop - 10;
tmp3.r_ytop = TiPlaneRect.r_ytop - 10;
GeoClip(&tmp, &tmp3);
fb->fb_rootArea = tmp;
}
/* This utility procedure is invoked by DBSrRoots. Save the root definition
* in dbwfbRootDef, save the transform in the argument, and abort the search.
* Make sure that the root we pick is actually displayed in a window
* someplace (there could be root cells that are no longer displayed
* anywhere).
*/
int
dbwfbGetTransform(use, transform, cdarg)
CellUse *use; /* A root use that is an ancestor
* of cellDef in DBWFeedbackAdd.
*/
Transform *transform; /* Transform up from cellDef to use. */
Transform *cdarg; /* Place to store transform from
* cellDef to its root def.
*/
{
extern int dbwfbWindFunc();
if (use->cu_def->cd_flags & CDINTERNAL) return 0;
if (!WindSearch((ClientData) DBWclientID, (ClientData) use,
(Rect *) NULL, dbwfbWindFunc, (ClientData) NULL)) return 0;
if (SigInterruptPending)
return 0;
dbwfbRootDef = use->cu_def;
*cdarg = *transform;
return 1;
}
/* This procedure is called if a window is found for the cell in
* dbwfbGetTransform above. It returns 1 to abort the search and
* notify dbwfbGetTransform that there was a window for that root
* cell.
*/
int
dbwfbWindFunc()
{
return 1;
}
/*
* ----------------------------------------------------------------------------
*
* Client initialization
*
* ----------------------------------------------------------------------------
*/
void
dbwFeedbackInit()
{
DBWHLAddClient(DBWFeedbackRedraw);
}
/*
* ----------------------------------------------------------------------------
*
* DBWFeedbackShow --
*
* Causes new feedback information actually to be displayed on
* the screen.
*
* Results:
* None.
*
* Side effects:
* All new feedback information that has been created since the
* last call to this procedure is added to the display.
*
* ----------------------------------------------------------------------------
*/
void
DBWFeedbackShow()
{
Rect area;
CellDef *currentRoot;
Feedback *fb;
int i;
/* Scan through all of the feedback areas starting with dbwfbNextToShow.
* Save up the total bounding box until the root definition changes,
* then redisplay what's been saved up so far.
*/
currentRoot = NULL;
for (i = dbwfbNextToShow, fb = &(dbwfbArray[dbwfbNextToShow]);
i < DBWFeedbackCount; i++, fb++)
{
if (currentRoot != fb->fb_rootDef)
{
if (currentRoot != NULL)
DBWHLRedraw(currentRoot, &area, FALSE);
area = GeoNullRect;
}
(void) GeoInclude(&fb->fb_rootArea, &area);
currentRoot = fb->fb_rootDef;
}
if (currentRoot != NULL)
DBWHLRedraw(currentRoot, &area, FALSE);
dbwfbNextToShow = DBWFeedbackCount;
}
/*
* ----------------------------------------------------------------------------
*
* DBWFeedbackNth --
*
* Provides the area and text associated with a particular
* feedback area.
*
* Results:
* Returns a pointer to the text associated with the Nth feedback
* entry.
*
* Side effects:
* The parameter "area" is filled with the area of the nth
* feedback, and the text of that feedback is returned. *pRootDef
* is filled in with rootDef for window of feedback area. *pStyle
* is filled in with the display style for the feedback area. If
* the particular area doesn't exist (nth >= DBWFeedbackCount),
* area and *pRootDef and *pStyle are untouched and NULL is
* returned. NULL may also be returned if there simply wasn't
* any text associated with the selected feedback.
*
* ----------------------------------------------------------------------------
*/
char *
DBWFeedbackNth(nth, area, pRootDef, pStyle)
int nth; /* Selects which feedback area to return
* stuff from. (0 <= nth < DBWFeedbackCount)
*/
Rect *area; /* To be filled in with area of feedback, in
* rounded-outward Magic coordinates.
*/
CellDef **pRootDef; /* *pRootDef gets filled in with root def for
* this feedback area. If pRootDef is NULL,
* nothing is touched.
*/
int *pStyle; /* *pStyle gets filled in with the display
* style for this feedback area. If NULL,
* nothing is touched.
*/
{
if (nth >= DBWFeedbackCount) return NULL;
*area = dbwfbArray[nth].fb_rootArea;
if (pRootDef != NULL) *pRootDef = dbwfbArray[nth].fb_rootDef;
if (pStyle != NULL) *pStyle = dbwfbArray[nth].fb_style;
return dbwfbArray[nth].fb_text->string;
}

438
dbwind/DBWhlights.c Normal file
View File

@ -0,0 +1,438 @@
/* DBWhighlights.c -
*
* This file contains routines that allow the highlight plane
* to be used to display additional things besides the box.
* The routines coordinate all the clients that have highlights
* to display so that when one of them updates its highlights
* it doesn't trash the others' highlights.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/dbwind/DBWhlights.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/styles.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "windows/windows.h"
#include "graphics/graphics.h"
#include "dbwind/dbwind.h"
#include "textio/textio.h"
#include "graphics/graphicsInt.h"
#define WINDOW_DEF(w) (((CellUse *)(w->w_surfaceID))->cu_def)
/* The array below is used to hold the addresses of redisplay
* procedures for each of the highlight clients. Whenever
* highlights must be redisplayed, each highlight client
* is invoked for each database window.
*/
#define MAXCLIENTS 10
static int (*(dbwhlClients[MAXCLIENTS]))();
/*
* ----------------------------------------------------------------------------
*
* DBWHLAddClient --
*
* This procedure is used to add another client to those
* that are displaying highlights. The redisplay procedure
* passed in by the client will be invoked in the following
* way:
* int
* redisplayProc(window, plane)
* MagWindow *window;
* Plane *plane;
* {
* }
* The procedure is invoked once for each window that contains
* database information (and potentially has highlights). The
* window has been locked via GrLock() before the proc is called,
* and the clipping area has already been set up. The procedure
* is given a pointer to the window, and a pointer to a plane.
* The plane contains non-space tiles over all areas where highlight
* information needs to be redrawn (all of these areas have had
* their highlight information erased). The client should redraw
* any of its highlights that touch any non-space areas.
*
* Results:
* None.
*
* Side effects:
* The client is added to our list of clients.
*
* ----------------------------------------------------------------------------
*/
void
DBWHLAddClient(redisplayProc)
int (*redisplayProc)(); /* Procedure to call during redisplays. */
{
int i;
for (i = 0; i < MAXCLIENTS; i++)
{
if (dbwhlClients[i] == NULL)
{
dbwhlClients[i] = redisplayProc;
return;
}
}
TxError("Magic error: ran out of space in highlight client table.\n");
TxError("Tell your system maintainer to enlarge the table.\n");
}
/*
* ----------------------------------------------------------------------------
*
* DBWHLRemoveClient --
*
* This just removes a client from the list of those that we
* know about.
*
* Results:
* None.
*
* Side effects:
* The given redisplay procedure will no longer be invoked
* during redisplays.
*
* ----------------------------------------------------------------------------
*/
void
DBWHLRemoveClient(redisplayProc)
int (*redisplayProc)(); /* A redisplay procedure. This
* procedure must previously have been
* passed in to DBWHLAddClient.
*/
{
int i;
for (i = 0; i < MAXCLIENTS; i += 1)
{
if (dbwhlClients[i] == redisplayProc)
{
dbwhlClients[i] = NULL;
return;
}
}
ASSERT(FALSE, "DBWHLRemoveClient");
}
/*
* ----------------------------------------------------------------------------
*
* DBWHLRedraw --
*
* This procedure is invoked to redisplay highlights. The
* clients that manage highlights are free to draw on the screen
* at will. But if a client ever erases highlight information, it
* must call this procedure so that the other clients can redraw
* any of their highlights that might have been erased. This
* procedure records what has changed. The information isn't actually
* redrawn until the next time WindUpdate is called. This is done
* to avoid repeated redraws when several pieces of highlights change
* in the same area at the same time.
*
* Results:
* None.
*
* Side effects:
* Information is recorded so that specified area will have its
* highlight information erased and redrawn the next time that
* WindUpdate is called.
*
* ----------------------------------------------------------------------------
*/
void
DBWHLRedraw(rootDef, area, erase)
CellDef *rootDef; /* Highlight information will be redrawn in
* all windows for which this is the root
* cell definition.
*/
Rect *area; /* The area over which to redraw. Highlights
* will be redrawn in this area plus enough
* surrounding area to catch degenerate boxes
* (drawn as crosses) and labels that may
* stick out from their attachment points.
*/
bool erase; /* TRUE means we should erase are before
* redrawing it. FALSE means that either the
* client has erased the area, or there's no
* need to erase it because all that's
* happening is to add new information to the
* display.
*/
{
extern CellDef *dbwhlDef;
extern bool dbwhlErase;
extern int dbwhlRedrawFunc();
Rect ourArea;
dbwhlDef = rootDef; /* Must pass to search function. */
dbwhlErase = erase;
/* If we're passed a NULL area, expand it by one unit so that
* we're certain to have non-zero area. Otherwise the various
* search procedures have big troubles.
*/
ourArea = *area;
if (ourArea.r_xbot >= ourArea.r_xtop)
ourArea.r_xtop = ourArea.r_xbot + 1;
if (ourArea.r_ybot >= ourArea.r_ytop)
ourArea.r_ytop = ourArea.r_ybot + 1;
(void) WindSearch(DBWclientID, (ClientData) NULL, &ourArea,
dbwhlRedrawFunc, (ClientData) &ourArea);
}
CellDef *dbwhlDef;
bool dbwhlErase;
/* This procedure records the area to be erased (if any) and the
* area to be redisplayed (which is larger than the area to be
* erased).
*/
int
dbwhlRedrawFunc(window, area)
MagWindow *window; /* Window to redraw. */
Rect *area; /* Passed as client data. */
{
Rect erase, expand, redraw;
DBWclientRec *crec = (DBWclientRec *) window->w_clientData;
if (WINDOW_DEF(window) != dbwhlDef) return 0;
/* The area that we erase must be large enough to include material
* that sticks out from the area of the highlights. There are two
* ways that material sticks out: (a) zero-size boxes are drawn as
* crosses, and the crosses stick outside of the box's area; (b)
* labels are attached to points or rectangles, but the text usually
* extends far beyond the attachment point.
*/
WindSurfaceToScreen(window, area, &erase);
expand = GrCrossRect;
(void) GeoInclude(&crec->dbw_expandAmounts, &expand);
if (dbwhlErase)
{
bool needErase = TRUE;
erase.r_xbot += expand.r_xbot;
erase.r_ybot += expand.r_ybot;
erase.r_xtop += expand.r_xtop;
erase.r_ytop += expand.r_ytop;
/* On some displays (e.g. black-and-white ones), highlights use
* the same color planes as other information. If this is the
* case, redisplay everything (this will redisplay highlights too,
* so there's nothing additional to do here).
*
* This is also the case if we use backing store but the backing
* store has been removed due to becoming invalid, such as when
* an attempt is made to redraw into an obscured or unmapped
* window.
*/
if (((GrGetBackingStorePtr == NULL) &&
((GrStyleTable[STYLE_ERASEHIGHLIGHTS].mask &
GrStyleTable[STYLE_ERASEALLBUTTOOLS].mask) != 0)) ||
((GrGetBackingStorePtr != NULL) &&
window->w_backingStore == (ClientData)NULL))
{
DBWAreaChanged(dbwhlDef, area, crec->dbw_bitmask,
(TileTypeBitMask *) NULL);
WindAnotherUpdatePlease = TRUE;
return 0;
}
DBPaintPlane(crec->dbw_hlErase, &erase,
DBStdPaintTbl(TT_ERROR_P, PL_DRC_ERROR),
(PaintUndoInfo *) NULL);
}
/* The area whose highlights must be redrawn is the area erased, but
* it must be expanded again to include the fact that we may have
* just erased a piece of a label that stuck out from some other point.
* This area gets translated back into database coordinates and saved
* in dbwhlRedrawPlane, but first it gets expanded by one more unit just to
* eliminate edge effects: all impacted highlights are now guaranteed
* to OVERLAP an area in dbwhlRedrawPlane, not just touch.
*/
erase.r_xbot -= expand.r_xtop;
erase.r_ybot -= expand.r_ytop;
erase.r_xtop -= expand.r_xbot;
erase.r_ytop -= expand.r_ybot;
(void) WindScreenToSurface(window, &erase, &redraw);
GEO_EXPAND(&redraw, 1, &redraw);
DBPaintPlane(crec->dbw_hlRedraw, &redraw,
DBStdPaintTbl(TT_ERROR_P, PL_DRC_ERROR),
(PaintUndoInfo *) NULL);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* DBWHLRedrawPrepWindow --
*
* This procedure is similar to DBWHLRedraw. However, it is
* intended to indicate areas to redraw highlights for a
* single window only. This is required by the backing store
* mechanism when a window is scrolled, and the part of the
* window area that remains visible is refreshed from backing
* store. This area does not need to have layout redrawn, but
* does need to have all hightlights redrawn, since the
* highlights aren't saved in backing store.
*
* Results:
* None.
*
* Side effects:
* Information is recorded so that specified area will have its
* highlight information erased and redrawn the next time that
* WindUpdate is called.
*
* ----------------------------------------------------------------------------
*/
void
DBWHLRedrawPrepWindow(MagWindow *window, Rect *area)
{
extern CellDef *dbwhlDef;
extern bool dbwhlErase;
extern int dbwhlRedrawFunc();
dbwhlDef = WINDOW_DEF(window);
dbwhlErase = FALSE;
dbwhlRedrawFunc(window, area);
}
/*
* ----------------------------------------------------------------------------
*
* DBWHLRedrawWind --
*
* This procedure is called to redraw highlight information in a
* particular window. It is normally called as part of WindUpdate
* by DBWHLUpdate. The areas to be erased and redrawn must already
* be present in the clientData record.
*
* Results:
* Always returns 0 to keep searches from aborting.
*
* Side effects:
* The plane dbw_hlPlane indicates which highlight areas must be
* redrawn for this window. Any highlights that touch any of these
* areas are redrawn. The plane is then cleared.
*
* ----------------------------------------------------------------------------
*/
int
DBWHLRedrawWind(window)
MagWindow *window; /* Window in which to redraw highlights. */
{
int i;
DBWclientRec *crec;
extern int dbwhlEraseFunc(); /* Forward reference. */
GrLock(window, TRUE);
crec = (DBWclientRec *) window->w_clientData;
/* First erase, then redraw: */
(void) DBSrPaintArea((Tile *) NULL, crec->dbw_hlErase, &TiPlaneRect,
&DBAllButSpaceBits, dbwhlEraseFunc, (ClientData)window);
/* Now call each client to redraw its own stuff. */
for (i = 0; i < MAXCLIENTS; i += 1)
{
if (dbwhlClients[i] == NULL) continue;
(void) (*(dbwhlClients[i]))(window, crec->dbw_hlRedraw);
}
DBClearPaintPlane(crec->dbw_hlErase);
DBClearPaintPlane(crec->dbw_hlRedraw);
GrUnlock(window);
return 0;
}
/* The procedure below erases highlight information for each tile that
* it's called with. Returns 0 to keep the search from aborting.
*/
int
dbwhlEraseFunc(tile, window)
Tile *tile; /* Tile describing area to be erased. */
MagWindow *window; /* Window that is being altered. */
{
Rect area;
bool needErase = TRUE;
TiToRect(tile, &area);
/* If the graphics package allows highlight areas to be */
/* cached in backing store, then we do a quick check to */
/* see if we can just copy the background back in and */
/* avoid repainting. */
if (GrGetBackingStorePtr != NULL)
if ((*GrGetBackingStorePtr)(window, &area))
needErase = FALSE;
if (needErase) GrClipBox(&area, STYLE_ERASEHIGHLIGHTS);
return 0;
}
/*
* ----------------------------------------------------------------------------
* DBWHLUpdate --
*
* This procedure is called once as part of each WindUpdate call.
* It checks for any windows that have highlight information that
* needs to be redrawn
*
* Results:
* None.
*
* Side effects:
* Highlights get redrawn on the screen.
* ----------------------------------------------------------------------------
*/
void
DBWHLUpdate()
{
extern int dbwhlUpdateWindowFunc();
/* Scan through all of the layout windows and redraw their
* highlight information, if necessary.
*/
(void) WindSearch(DBWclientID, (ClientData) NULL, (Rect *) NULL,
DBWHLRedrawWind, (ClientData) NULL);
}

722
dbwind/DBWprocs.c Normal file
View File

@ -0,0 +1,722 @@
/*
* DBWprocs.c --
*
* Procedures to interface the database with the window package
* for the purposes of window creation, deletion, and modification.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/dbwind/DBWprocs.c,v 1.3 2008/06/01 18:37:39 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include "utils/main.h"
#include "utils/magic.h"
#include "utils/geometry.h"
#include "windows/windows.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "utils/main.h"
#include "commands/commands.h"
#include "dbwind/dbwind.h"
#include "graphics/graphics.h"
#include "textio/textio.h"
#include "textio/txcommands.h"
#include "utils/utils.h"
#include "utils/undo.h"
#include "graphics/glyphs.h"
#include "utils/malloc.h"
#include "utils/styles.h"
global WindClient DBWclientID;
static int dbwBitMask = 0;
#define MAX_BITMASK INT_MAX
#define MAX_BITS_IN_MASK (sizeof(unsigned int) * 8 - 1)
extern void DBWredisplay(); /* Defined in DBWdisplay.c */
/* The following variable is used to allow somebody besides ourselves
* to take over button handling for database windows. If it is NULL
* (which it usually is) we handle buttons. If it isn't NULL, it gives
* the address of a procedure to handle buttons.
*/
static int (*dbwButtonHandler)() = NULL;
/*
* ----------------------------------------------------------------------------
*
* DBWcreate
*
* A new window has been created, create and initialize the needed
* structures.
*
* Results:
* FALSE if we have too many windows, TRUE otherwise.
*
* Side effects:
* Load the given cell into the window. If no cell is given, then
* if the box exists, load a zoomed-in view of the box. Otherwise
* load a new blank cell.
*
* ----------------------------------------------------------------------------
*/
bool
DBWcreate(window, argc, argv)
MagWindow *window;
int argc;
char *argv[];
{
int bitMask, newBitMask, expand;
DBWclientRec *crec;
CellDef *boxDef;
Rect box;
/*
* See if we can create a new window without running out
* of bits in our bitMask.
*/
newBitMask = (dbwBitMask + 1) | dbwBitMask;
if (newBitMask > MAX_BITMASK)
return FALSE;
bitMask = newBitMask ^ dbwBitMask;
dbwBitMask = newBitMask;
crec = (DBWclientRec *) mallocMagic(sizeof(DBWclientRec));
crec->dbw_flags = DBW_SEELABELS | DBW_SEECELLS;
crec->dbw_watchPlane = -1;
crec->dbw_watchDef = (CellDef *) NULL;
crec->dbw_bitmask = bitMask;
crec->dbw_expandAmounts.r_xbot = 0;
crec->dbw_expandAmounts.r_ybot = 0;
crec->dbw_expandAmounts.r_xtop = 0;
crec->dbw_expandAmounts.r_ytop = 0;
crec->dbw_gridRect.r_xbot = 0;
crec->dbw_gridRect.r_ybot = 0;
crec->dbw_gridRect.r_xtop = 1;
crec->dbw_gridRect.r_ytop = 1;
crec->dbw_visibleLayers = DBAllTypeBits;
crec->dbw_hlErase = DBNewPlane((ClientData) TT_SPACE);
crec->dbw_hlRedraw = DBNewPlane((ClientData) TT_SPACE);
crec->dbw_labelSize = 0;
crec->dbw_scale = -1;
crec->dbw_surfaceArea.r_xbot = 0;
crec->dbw_surfaceArea.r_ybot = 0;
crec->dbw_surfaceArea.r_xtop = -1;
crec->dbw_surfaceArea.r_ytop = -1;
crec->dbw_origin.p_x = 0;
crec->dbw_origin.p_y = 0;
window->w_clientData = (ClientData) crec;
if (argc > 0)
DBWloadWindow(window, argv[0], TRUE, FALSE);
else if (ToolGetBox(&boxDef, &box))
{
DBWloadWindow(window, boxDef->cd_name, TRUE, FALSE);
/* Zoom in on the box, leaving a 10% border or at least 2 units
* on each side.
*/
expand = (box.r_xtop - box.r_xbot)/20;
if (expand < 2) expand = 2;
box.r_xtop += expand;
box.r_xbot -= expand;
expand = (box.r_ytop - box.r_ybot)/20;
if (expand < 2) expand = 2;
box.r_ytop += expand;
box.r_ybot -= expand;
WindMove(window, &box);
}
else
{
DBWloadWindow(window, (char *) NULL, TRUE, FALSE);
}
return TRUE;
}
/*
* ----------------------------------------------------------------------------
* DBWdelete --
*
* Clean up the data structures before deleting a window.
*
* Results:
* TRUE if we really want to delete the window, FALSE otherwise.
*
* Side effects:
* A DBWclientRec is freed.
* ----------------------------------------------------------------------------
*/
bool
DBWdelete(window)
MagWindow *window;
{
DBWclientRec *cr;
cr = (DBWclientRec *) window->w_clientData;
dbwBitMask &= ~(cr->dbw_bitmask);
DBFreePaintPlane(cr->dbw_hlErase);
DBFreePaintPlane(cr->dbw_hlRedraw);
TiFreePlane(cr->dbw_hlErase);
TiFreePlane(cr->dbw_hlRedraw);
freeMagic( (char *) cr);
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* dbwLoadFunc --
*
* This is a utility function passed to WindSearch by
* DBWloadWindow. Its job is to see if the edit cell is
* present in any window except a given one.
*
* Results:
* 1 is returned if the window doesn't match the ClientData
* but contains the Edit Cell. 0 is returned otherwise.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
dbwLoadFunc(w, clientData)
MagWindow *w; /* A window found in the search. */
MagWindow *clientData; /* Window to ignore (passed as ClientData). */
{
if (w == clientData) return 0;
if (((CellUse *) w->w_surfaceID)->cu_def == EditRootDef)
return 1;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* DBWreload --
*
* Re-load all windows to contain the named cell as a root.
* This is intended to be called during startup or when restarting a saved
* image of Magic.
*
* Results:
* None.
*
* Side effects:
* Loads windows with the named cell.
*
* ----------------------------------------------------------------------------
*/
void
DBWreload(name)
char *name;
{
int dbwReloadFunc();
(void) WindSearch(DBWclientID, (ClientData) NULL, (Rect *) NULL,
dbwReloadFunc, (ClientData) name);
}
int
dbwReloadFunc(w, name)
MagWindow *w;
char *name;
{
DBWloadWindow(w, name, TRUE, FALSE);
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* DBWloadWindow
*
* Replace the root cell of a window by the specified cell.
*
* A cell name of NULL causes the cell with name "(UNNAMED)" to be
* created if it does not already exist, or used if it does.
*
* Results:
* None.
*
* Side effects:
* If there is currently no edit use, or if this is the only
* window containing the edit cell, then set the edit cell
* to the topmost cell in the new window. Otherwise, the edit
* cell doesn't change.
*
* If "expand" is true, unexpands all subcells of the root cell.
*
* ----------------------------------------------------------------------------
*/
void
DBWloadWindow(window, name, ignoreTech, expand)
MagWindow *window; /* Identifies window to which cell is to be bound */
char *name; /* Name of new cell to be bound to this window */
bool ignoreTech; /* If FALSE, indicates that the technology of
* the layout must match the current technology.
*/
bool expand; /* Indicates whether or not to expand the cell */
{
CellDef *newEditDef;
CellUse *newEditUse;
void DisplayWindow();
int res, newEdit, error_val;
int xadd, yadd;
Rect loadBox;
char *rootname;
int UnexpandFunc(); /* forward declaration */
loadBox.r_xbot = loadBox.r_ybot = 0;
loadBox.r_xtop = loadBox.r_ytop = 1;
/* See if we're to change the edit cell */
newEdit = !WindSearch((WindClient) DBWclientID, (ClientData) NULL,
(Rect *) NULL, dbwLoadFunc, (ClientData) window);
if ((name == (char *) NULL) || (name[0] == '\0'))
{
/*
* If there is an existing unnamed cell, we use it.
* Otherwise, we create one afresh.
*/
newEditDef = DBCellLookDef(UNNAMED);
if (newEditDef == (CellDef *) NULL)
{
newEditDef = DBCellNewDef(UNNAMED, (char *) NULL);
DBCellSetAvail(newEditDef);
}
}
else
{
/*
* Name specified.
* First try to find it in main memory, then try to
* read it from disk.
*/
char *dotptr;
rootname = strrchr(name, '/');
if (rootname == NULL)
rootname = name;
else
rootname++;
/* Strip off any ".mag" extension from the name */
dotptr = strrchr(rootname, '.');
if (dotptr != NULL)
if (!strcmp(dotptr, ".mag"))
*dotptr = '\0';
newEditDef = DBCellLookDef(rootname);
if ((newEditDef != (CellDef *)NULL) && (newEditDef->cd_file != NULL))
{
/* If the cellname exists already, check if we are really */
/* looking at the same file. If not, and two files in two */
/* different paths have the same root cellname, then keep */
/* the full pathname for the new cellname. */
char *fullpath;
struct stat statbuf;
ino_t inode;
if (DBTestOpen(name, &fullpath))
{
if (stat(fullpath, &statbuf) == 0)
{
inode = statbuf.st_ino;
if (stat(newEditDef->cd_file, &statbuf) == 0)
{
if (inode != statbuf.st_ino)
newEditDef = (CellDef *)NULL;
}
else
newEditDef = (CellDef *)NULL;
}
else
newEditDef = (CellDef *)NULL;
}
else
newEditDef = (CellDef *)NULL;
/* If the cells have the same name but different */
/* paths, then give the new cell the full path name */
if (newEditDef == NULL)
{
rootname = name;
newEditDef = DBCellLookDef(rootname);
}
}
if (newEditDef == (CellDef *) NULL)
newEditDef = DBCellNewDef(rootname, (char *) NULL);
if (!DBCellRead(newEditDef, name, ignoreTech, &error_val))
{
if (error_val == ENOENT)
{
TxPrintf("Creating new cell\n");
DBCellSetAvail(newEditDef);
}
else
{
/* File exists but some error has occurred like
* file is unreadable or max file descriptors
* was reached, in which csae we don't want to
* create a new cell, so delete the new celldef
* and return.
*/
UndoDisable();
DBCellDeleteDef(newEditDef);
UndoEnable();
/*
* Go back to loading cell (UNNAMED) if
* there is no EditRootDef or EditCellUse.
* Otherwise, on error, keep whatever was already
* the root def & use.
*/
if (EditRootDef == NULL || EditCellUse == NULL)
{
newEditDef = DBCellLookDef(UNNAMED);
if (newEditDef == (CellDef *) NULL)
{
newEditDef = DBCellNewDef(UNNAMED, (char *) NULL);
DBCellSetAvail(newEditDef);
}
}
else
return;
}
}
else
{
/* DBCellRead doesn't dare to change bounding boxes, so
* we have to call DBReComputeBbox here (we know that it's
* safe).
*/
DBReComputeBbox(newEditDef);
loadBox = newEditDef->cd_bbox;
}
}
/*
* Attach the new cell to the selected window.
*/
if (window != NULL)
{
newEditUse = DBCellNewUse(newEditDef, (char *) NULL);
(void) StrDup(&(newEditUse->cu_id), "Topmost cell in the window");
DBExpand(newEditUse,
((DBWclientRec *)window->w_clientData)->dbw_bitmask, TRUE);
if (expand)
DBExpandAll(newEditUse, &(newEditUse->cu_bbox),
((DBWclientRec *)window->w_clientData)->dbw_bitmask,
FALSE, UnexpandFunc, (ClientData)
(((DBWclientRec *)window->w_clientData)->dbw_bitmask));
if (newEdit)
{
if (EditCellUse && EditRootDef)
{
DBWUndoOldEdit(EditCellUse, EditRootDef,
&EditToRootTransform, &RootToEditTransform);
DBWUndoNewEdit(newEditUse, newEditDef,
&GeoIdentityTransform, &GeoIdentityTransform);
}
if (newEditUse->cu_def->cd_flags & CDNOEDIT)
{
newEdit = FALSE;
EditCellUse = NULL;
EditRootDef = NULL;
}
else
{
EditCellUse = newEditUse;
EditRootDef = newEditDef;
}
EditToRootTransform = GeoIdentityTransform;
RootToEditTransform = GeoIdentityTransform;
}
/* enforce a minimum size of 60 and a border of 10% around the sides */
xadd = MAX(0, (60 - (loadBox.r_xtop - loadBox.r_xbot)) / 2) +
(loadBox.r_xtop - loadBox.r_xbot + 1) / 10;
yadd = MAX(0, (60 - (loadBox.r_ytop - loadBox.r_ybot)) / 2) +
(loadBox.r_ytop - loadBox.r_ybot + 1) / 10;
loadBox.r_xbot -= xadd; loadBox.r_xtop += xadd;
loadBox.r_ybot -= yadd; loadBox.r_ytop += yadd;
window->w_bbox = &(newEditUse->cu_def->cd_bbox);
res = WindLoad(window, DBWclientID, (ClientData) newEditUse, &loadBox);
ASSERT(res, "DBWcreate");
/* Update the captions in all windows to reflect the new
* edit cell. Also, if we've got a new edit cell, we need
* to explicitly ask for redisplay, because there could be
* another window on this cell somewhere else, and it needs
* to be redisplayed too (if it's just the new window, that
* is taken care of during WindLoad).
*/
CmdSetWindCaption(EditCellUse, EditRootDef);
}
if (newEdit)
DBWAreaChanged(newEditDef, &newEditDef->cd_bbox, DBW_ALLWINDOWS,
&DBAllButSpaceBits);
}
/* This function is called for each cell whose expansion status changed.
* It forces the cells area to be redisplayed, then returns 0 to keep
* looking for more cells to unexpand.
*/
int
UnexpandFunc(use, windowMask)
CellUse *use; /* Use that was just unexpanded. */
int windowMask; /* Window where it was unexpanded. */
{
if (use->cu_parent == NULL) return 0;
DBWAreaChanged(use->cu_parent, &use->cu_bbox, windowMask,
(TileTypeBitMask *) NULL);
return 0;
}
/*
* ----------------------------------------------------------------------------
* DBWexit --
*
* Magic is about to exit. Check to see if any cells need to be written.
*
* Results:
* TRUE if it is OK to exit.
* FALSE otherwise.
*
* Side effects:
* The user is asked if he wants to write out any cells that are left.
* ----------------------------------------------------------------------------
*/
bool
DBWexit()
{
return (CmdWarnWrite() == 1);
}
/*
* ----------------------------------------------------------------------------
*
* DBWcommands --
*
* This procedure is called by the window package whenever a
* button is pushed or command is typed while the cursor is over
* a database window. This procedure dispatches to the handler
* for the command.
*
* Results:
* None.
*
* Side effects:
* Whatever the command procedure does.
*
* ----------------------------------------------------------------------------
*/
void
DBWcommands(w, cmd)
MagWindow *w;
TxCommand *cmd;
{
int cmdNum;
/* If it was a keyboard command, just dispatch to the proper
* command routine.
*/
if (cmd->tx_button == TX_NO_BUTTON)
{
WindExecute(w, DBWclientID, cmd);
}
else
{
/* It's a button. */
(*DBWButtonCurrentProc)(w, cmd);
}
UndoNext();
/* Update timestamps now that it's safe */
DBFixMismatch();
}
/*
* ----------------------------------------------------------------------------
*
* DBWNewButtonHandler --
*
* This procedure permits anyone else in Magic to take over
* handling of button pushes in database windows. One example
* of this is the netlist editor.
*
* Results:
* The return value is the old button handler. NULL means the
* default handler (moving the box and painting) was the old
* handler. The caller must restore the old handler when it is
* finished.
*
* Side effects:
* From now on, all button pushes within database windows are
* passed to buttonProc, in the following form:
*
* int
* buttonProc(w, cmd)
* MagWindow *w;
* TxCommand *cmd;
* {
* }
*
* ----------------------------------------------------------------------------
*/
int (*(DBWNewButtonHandler(buttonProc)))()
int (*buttonProc)(); /* New button handler. */
{
int (*result)();
result = dbwButtonHandler;
dbwButtonHandler = buttonProc;
return result;
}
/*
* ----------------------------------------------------------------------------
* DBWupdate--
*
* This procedure is called once during each WindUpdate call. It
* takes care of redisplay stuff that's not already handled by
* DBWAreaChanged (e.g. highlight redisplay).
*
* Results:
* None.
*
* Side effects:
* Stuff gets redisplayed.
* ----------------------------------------------------------------------------
*/
void
DBWupdate()
{
DBWFeedbackShow();
DBWHLUpdate();
}
/*
* ----------------------------------------------------------------------------
* DBWinit --
*
* Initialize this module and open an initial window.
*
* Results:
* None.
*
* Side effects:
* A client is added, and an initial empty window is made
* ----------------------------------------------------------------------------
*/
void
DBWinit()
{
MagWindow *initialWindow;
int i;
static char *doc =
"You are currently using the \"box\" tool. The button actions are:\n"
" left - move the box so its lower-left corner is at cursor position\n"
" right - resize box by moving upper-right corner to cursor position\n"
" middle - paint box area with material underneath cursor\n"
"You can move or resize the box by different corners by pressing left\n"
" or right, holding it down, moving the cursor near a different corner\n"
" and clicking the other (left or right) button down then up without\n"
" releasing the initial button.\n";
/* Initialize */
DBWclientID = WindAddClient("layout", DBWcreate, DBWdelete,
DBWredisplay, DBWcommands, DBWupdate, DBWexit,
(void (*)()) NULL,
(GrGlyph *) NULL);
/* Add all of the commands for the DBWind interface. These */
/* are defined in DBWCommands.c. Commands added by other */
/* modules are registered with the client by each module. */
DBWInitCommands();
DBWHLAddClient(DBWDrawBox);
DBWAddButtonHandler("box", DBWBoxHandler, STYLE_CURS_NORMAL, doc);
(void) DBWChangeButtonHandler("box");
UndoDisable();
DBCellInit();
DBUndoInit();
dbwUndoInit();
/* Create initial window, but don't load anything into it. */
WIND_MAX_WINDOWS(MAX_BITS_IN_MASK);
#ifdef MAGIC_WRAPPER
if (MakeMainWindow)
#endif
initialWindow = WindCreate(DBWclientID, (Rect *) NULL, TRUE,
0, (char **) NULL);
#ifndef MAGIC_WRAPPER
ASSERT(initialWindow != (MagWindow *) NULL, "DBWinit");
#endif
/* Other initialization routines in the DBW package */
dbwFeedbackInit();
dbwElementInit();
dbwCrosshairInit();
UndoEnable();
}

1044
dbwind/DBWtools.c Normal file

File diff suppressed because it is too large Load Diff

312
dbwind/DBWundo.c Normal file
View File

@ -0,0 +1,312 @@
/*
* DBWundo.c --
*
* Procedures for undoing/redoing operations associated
* with the dbwind module.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/dbwind/DBWundo.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "windows/windows.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "utils/main.h"
#include "dbwind/dbwind.h"
#include "utils/undo.h"
#include "textio/textio.h"
#include "commands/commands.h"
/*
* Client identifiers returned by the undo package
* in dbwUndoInit().
*/
UndoType dbwUndoIDOldEdit, dbwUndoIDNewEdit, dbwUndoIDBox;
/*
* Function to play events forward/backward.
*/
void dbwUndoChangeEdit(), dbwUndoBoxForw(), dbwUndoBoxBack();
/*
* Structure to hold all the information needed to switch
* to a new edit cell. We rely upon the fact that no CellDef
* is ever deleted, so it is safe to retain pointers to defs.
* The defs, transform, and use identifier are used to identify
* uniquely the cell use affected.
*/
typedef struct
{
Transform e_editToRoot; /* Transform to root coordinates from edit */
Transform e_rootToEdit; /* Transform to edit coordinates from root */
CellDef *e_rootDef; /* Root def in the edit cell's home window */
CellDef *e_editDef; /* Edit cell def itself */
CellDef *e_parentDef; /* Parent def of the editcell, or NULL if the
* edit cell was a root itself.
*/
char e_useId[4]; /* Use identifier. This is a place holder
* only; the actual structure is allocated to
* hold all the bytes in the use id, plus the
* null byte.
*/
} editUE;
#define editSize(n) (sizeof (editUE) - 3 + (n))
/* Structure used for undo-ing changes in the box. It just holds the
* box's old and new locations.
*/
typedef struct
{
CellDef *bue_oldDef;
Rect bue_oldArea;
CellDef *bue_newDef;
Rect bue_newArea;
} BoxUndoEvent;
/*
* ----------------------------------------------------------------------------
*
* dbwUndoInit --
*
* Initialize handling of undo for the dbwind module.
*
* Results:
* None.
*
* Side effects:
* Calls the undo package to add several clients.
*
* ----------------------------------------------------------------------------
*/
void
dbwUndoInit()
{
void (*nullProc)() = NULL;
dbwUndoIDOldEdit = UndoAddClient(nullProc, nullProc,
(UndoEvent *(*)()) NULL, (int (*)()) NULL, nullProc,
dbwUndoChangeEdit, "change edit cell");
dbwUndoIDNewEdit = UndoAddClient(nullProc, nullProc,
(UndoEvent *(*)()) NULL, (int (*)()) NULL, dbwUndoChangeEdit,
nullProc, "change edit cell");
dbwUndoIDBox = UndoAddClient(nullProc, nullProc,
(UndoEvent *(*)()) NULL, (int (*)()) NULL, dbwUndoBoxForw,
dbwUndoBoxBack, "box change");
}
/*
* ----------------------------------------------------------------------------
*
* DBWUndoOldEdit --
* DBWUndoNewEdit --
*
* Record the old and new edit cells when the edit cell changes.
*
* Results:
* None.
*
* Side effects:
* Each creates a single undo list entry.
*
* ----------------------------------------------------------------------------
*/
void
DBWUndoOldEdit(editUse, editRootDef, editToRootTrans, rootToEditTrans)
CellUse *editUse;
CellDef *editRootDef;
Transform *editToRootTrans, *rootToEditTrans;
{
char *useid = editUse->cu_id;
editUE *ep;
ep = (editUE *) UndoNewEvent(dbwUndoIDOldEdit,
(unsigned) editSize(strlen(useid)));
if (ep == (editUE *) NULL)
return;
ep->e_editToRoot = *editToRootTrans;
ep->e_rootToEdit = *rootToEditTrans;
ep->e_rootDef = editRootDef;
ep->e_editDef = editUse->cu_def;
ep->e_parentDef = editUse->cu_parent;
(void) strcpy(ep->e_useId, useid);
}
void
DBWUndoNewEdit(editUse, editRootDef, editToRootTrans, rootToEditTrans)
CellUse *editUse;
CellDef *editRootDef;
Transform *editToRootTrans, *rootToEditTrans;
{
char *useid = editUse->cu_id;
editUE *ep;
ep = (editUE *) UndoNewEvent(dbwUndoIDNewEdit,
(unsigned) editSize(strlen(useid)));
if (ep == (editUE *) NULL)
return;
ep->e_editToRoot = *editToRootTrans;
ep->e_rootToEdit = *rootToEditTrans;
ep->e_rootDef = editRootDef;
ep->e_editDef = editUse->cu_def;
ep->e_parentDef = editUse->cu_parent;
(void) strcpy(ep->e_useId, useid);
}
/*
* ----------------------------------------------------------------------------
*
* dbwUndoChangeEdit
*
* Change the edit cell.
* The UndoEvent passed as an argument contains a pointer to
* the root cell def of the new edit cell and the parent def
* of the edit cell. Both pointers are safe because we never
* delete a CellDef.
*
* Results:
* None.
*
* Side effects:
* Changes the edit cell.
* Redisplays the old edit cell and the new one.
*
* ----------------------------------------------------------------------------
*/
void
dbwUndoChangeEdit(ep)
editUE *ep;
{
Rect area;
CellUse *use;
CellDef *editDef, *parent;
static Rect origin = {-1, -1, 1, 1};
/* Redisplay the old edit cell */
GeoTransRect(&EditToRootTransform, &(EditCellUse->cu_def->cd_bbox), &area);
DBWAreaChanged(EditRootDef, &area, DBW_ALLWINDOWS, &DBAllButSpaceBits);
GeoTransRect(&EditToRootTransform, &origin, &area);
DBWAreaChanged(EditRootDef, &area, DBW_ALLWINDOWS, &DBAllButSpaceBits);
/* Set up the transforms for the new edit cell */
EditToRootTransform = ep->e_editToRoot;
RootToEditTransform = ep->e_rootToEdit;
/*
* Search for the use uniquely identified by the parent cell
* def 'parent' (which may be NULL) and the use identifier
* 'ep->e_useId'.
*
* It's gotta be there.
*/
EditRootDef = ep->e_rootDef;
editDef = ep->e_editDef;
parent = ep->e_parentDef;
for (use = editDef->cd_parents; use != NULL; use = use->cu_nextuse)
if (use->cu_parent == parent && strcmp(use->cu_id, ep->e_useId) == 0)
break;
ASSERT(use != (CellUse *) NULL, "dbwUndoChangeEdit");
TxPrintf("Edit cell is now %s (%s)\n", editDef->cd_name, use->cu_id);
EditCellUse = use;
GeoTransRect(&EditToRootTransform, &(EditCellUse->cu_def->cd_bbox), &area);
DBWAreaChanged(EditRootDef, &area, DBW_ALLWINDOWS, &DBAllButSpaceBits);
GeoTransRect(&EditToRootTransform, &origin, &area);
DBWAreaChanged(EditRootDef, &area, DBW_ALLWINDOWS, &DBAllButSpaceBits);
CmdSetWindCaption(EditCellUse, EditRootDef);
}
/*
* ----------------------------------------------------------------------------
*
* DBWUndoBox --
*
* Remember a box change for later undo-ing.
*
* Results:
* None.
*
* Side effects:
* An entry is added to the undo list.
*
* ----------------------------------------------------------------------------
*/
void
DBWUndoBox(oldDef, oldArea, newDef, newArea)
CellDef *oldDef; /* Celldef containing old box. */
Rect *oldArea; /* Area of old box in oldDef coords. */
CellDef *newDef; /* Celldef containing new box. */
Rect *newArea; /* Area of new box in newDef coords. */
{
BoxUndoEvent *bue;
bue = (BoxUndoEvent *) UndoNewEvent(dbwUndoIDBox, sizeof(BoxUndoEvent));
if (bue == NULL) return;
bue->bue_oldDef = oldDef;
bue->bue_oldArea = *oldArea;
bue->bue_newDef = newDef;
bue->bue_newArea = *newArea;
}
/*
* ----------------------------------------------------------------------------
*
* dbwUndoBoxForw --
* dbwUndoBoxBack --
*
* This routines are called to undo a change to the box. They
* are invoked by the undo package.
*
* Results:
* None.
*
* Side effects:
* The box's location is modified.
*
* ----------------------------------------------------------------------------
*/
void
dbwUndoBoxForw(bue)
BoxUndoEvent *bue; /* Event to be redone. */
{
DBWSetBox(bue->bue_newDef, &bue->bue_newArea);
}
void
dbwUndoBoxBack(bue)
BoxUndoEvent *bue; /* Event to be undone. */
{
DBWSetBox(bue->bue_oldDef, &bue->bue_oldArea);
}

41
dbwind/Depend Normal file
View File

@ -0,0 +1,41 @@
DBWcommands.o: DBWcommands.c ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/hash.h ../database/database.h \
../windows/windows.h ../dbwind/dbwind.h ../utils/main.h \
../commands/commands.h ../textio/textio.h ../textio/txcommands.h
DBWdisplay.o: DBWdisplay.c ../utils/magic.h ../utils/malloc.h \
../utils/geometry.h ../tiles/tile.h ../utils/hash.h \
../database/database.h ../windows/windows.h ../graphics/graphics.h \
../dbwind/dbwind.h ../utils/utils.h ../dbwind/dbwtech.h \
../utils/styles.h ../utils/main.h ../utils/tech.h ../utils/signals.h
DBWbuttons.o: DBWbuttons.c ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/hash.h ../database/database.h \
../windows/windows.h ../graphics/graphics.h ../dbwind/dbwind.h \
../utils/styles.h ../textio/textio.h ../textio/txcommands.h \
../utils/utils.h
DBWelement.o: DBWelement.c ../tcltk/tclmagic.h ../utils/magic.h \
../utils/geometry.h ../tiles/tile.h ../utils/hash.h \
../database/database.h ../windows/windows.h ../graphics/graphics.h \
../dbwind/dbwind.h ../utils/utils.h ../utils/styles.h ../utils/malloc.h \
../utils/signals.h
DBWfdback.o: DBWfdback.c ../utils/magic.h ../utils/geometry.h \
../tiles/tile.h ../utils/hash.h ../database/database.h \
../windows/windows.h ../graphics/graphics.h ../dbwind/dbwind.h \
../utils/utils.h ../utils/styles.h ../utils/malloc.h ../utils/signals.h
DBWhlights.o: DBWhlights.c ../utils/magic.h ../utils/geometry.h \
../utils/styles.h ../tiles/tile.h ../utils/hash.h ../database/database.h \
../windows/windows.h ../graphics/graphics.h ../dbwind/dbwind.h \
../textio/textio.h ../graphics/graphicsInt.h
DBWprocs.o: DBWprocs.c ../utils/main.h ../windows/windows.h \
../utils/magic.h ../utils/geometry.h ../database/database.h \
../tiles/tile.h ../utils/hash.h ../commands/commands.h \
../dbwind/dbwind.h ../graphics/graphics.h ../textio/textio.h \
../textio/txcommands.h ../utils/utils.h ../utils/undo.h \
../graphics/glyphs.h ../utils/malloc.h ../utils/styles.h
DBWtools.o: DBWtools.c ../utils/magic.h ../utils/geometry.h \
../utils/styles.h ../tiles/tile.h ../utils/hash.h ../database/database.h \
../windows/windows.h ../graphics/graphics.h ../dbwind/dbwind.h \
../textio/textio.h ../utils/main.h ../textio/txcommands.h
DBWundo.o: DBWundo.c ../utils/magic.h ../utils/geometry.h \
../windows/windows.h ../tiles/tile.h ../utils/hash.h \
../database/database.h ../utils/main.h ../dbwind/dbwind.h \
../utils/undo.h ../textio/textio.h ../commands/commands.h

11
dbwind/Makefile Normal file
View File

@ -0,0 +1,11 @@
#
# rcsid $Header: /usr/cvsroot/magic-8.0/dbwind/Makefile,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $
#
MODULE = dbwind
MAGICDIR = ..
SRCS = DBWcommands.c DBWdisplay.c DBWbuttons.c DBWelement.c \
DBWfdback.c DBWhlights.c DBWprocs.c DBWtools.c DBWundo.c
include ${MAGICDIR}/defs.mak
include ${MAGICDIR}/rules.mak

235
dbwind/dbwind.h Normal file
View File

@ -0,0 +1,235 @@
/*
* dbwind.h --
*
* Interface definitions for the 'glue' between the window
* manager and the database.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*
*
* rcsid $Header: /usr/cvsroot/magic-8.0/dbwind/dbwind.h,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $
*/
#ifndef _DBWIND_H
#define _DBWIND_H
#include "database/database.h"
#include "windows/windows.h"
/*--------------------------- Window Client Data ----------------------------
* The dbwind package keeps special client data that it uses to
* manage windows on the database.
*/
typedef struct DBW1 {
int dbw_bitmask; /* A single bit in a word, unique between all
* layout windows. Any cell that is expanded
* in this window has this bit set in its
* expand mask.
*/
int dbw_flags; /* Various flags, see below. */
int dbw_watchPlane; /* The plane number of a plane to watch
* (show tile structure)
*/
CellDef *dbw_watchDef; /* The name of a celldef to watch */
Transform dbw_watchTrans; /* A transform to root coordinates that
* uniquely identifies the -position- of
* the cell use being watched, in the root
* cell of the window.
*/
Rect dbw_expandAmounts; /* The sides of this rectangle are expanded
* out from the origin by the same amount
* that a redisplayed area should be expanded
* in order to catch all labels. This
* reflects the size of the largest label
* displayed anywhere in the window.
*/
TileTypeBitMask dbw_visibleLayers;
/* This bit mask tells which mask layers
* should be displayed on the screen.
*/
Plane *dbw_hlErase; /* ERROR_P tiles on this plane record highlight
* areas that must be erased in this window,
* in screen coordinates.
*/
Plane *dbw_hlRedraw; /* ERROR_P tiles on this plane record highlight
* areas that must be redrawn in this window, in
* root database coordinates.
*/
Rect dbw_gridRect; /* Defines grid in world coordinates: grid
* lines run along sides of rect, rect size
* determines spacing.
*/
int dbw_labelSize; /* What size to use for text when drawing
* labels in this window (e.g. GR_TEXT_SMALL).
* This is recomputed each time the window
* is completely redrawn. -1 means don't
* draw labels at all.
*/
Rect dbw_surfaceArea; /* This field and the next two that follow
* are just copies of the corresponding
* fields from window records. They're used
* to detect when a window has resized or
* rescaled.
*/
Point dbw_origin;
int dbw_scale;
} DBWclientRec;
/* Flag values for dbw_flags:
*
* DBW_GRID: Means grid is to be displayed in window.
* DBW_WATCHDEMO: Use `demo' style of watching (arrows, not addresses)
* DBW_ALLSAME: Means don't use different display styles for
* edit and other cells.
* DBW_SEELABELS: 0 means don't display labels ever.
* DBW_SEECELLS 0 means don't display cell names and bounding boxes
* DBW_SEETYPES display tiletype instead of tile address
*/
#define DBW_GRID 1
#define DBW_WATCHDEMO 2
#define DBW_ALLSAME 4
#define DBW_SEELABELS 010
#define DBW_SEECELLS 020
#define DBW_SEETYPES 040
/*
* exported variables
*
*/
extern WindClient DBWclientID;
extern int DBWSnapToGrid;
extern int DBWMaxTechStyles;
extern int DBWMaxTileStyles;
extern int DBWNumStyles;
extern int RtrPolyWidth, RtrMetalWidth, RtrContactWidth;
/*
* Exported procedure headers for redisplay
*/
extern int DBWWatchTiles();
extern void DBWAreaChanged();
extern void DBWLabelChanged();
extern void DBWDrawLabel();
/*
* Exported procedures and variables related to the technology file
*/
extern void DBWTechInitStyles();
extern bool DBWTechAddStyle();
extern char *DBWStyleType;
/*
* exported button procedures and variables
*/
extern void (*DBWButtonCurrentProc)();
extern void DBWAddButtonHandler();
extern char *DBWChangeButtonHandler();
extern void DBWPrintButtonDoc();
extern void DBWBoxHandler();
/* The following defines are used to indicate corner positions
* of the box:
*/
#define TOOL_BL 0
#define TOOL_BR 1
#define TOOL_TR 2
#define TOOL_TL 3
#define TOOL_ILG -1
/* The following defines are used to indicate which coordinate system
* the cursor box snaps to when moved with mouse clicks (values for
* DBWSnapToGrid).
*/
#define DBW_SNAP_INTERNAL 0 /* internal units (fine grid) */
#define DBW_SNAP_LAMBDA 1 /* lambda units (coarse grid) */
#define DBW_SNAP_USER 2 /* user grid units (user grid) */
#define DBW_SNAP_MICRONS 3 /* micron units */
/* The following window mask can be used to select all database windows
* for things like the mask parameter to DBWAreaChanged.
*/
#define DBW_ALLWINDOWS -1
extern MagWindow *ToolGetPoint();
extern MagWindow *ToolGetBoxWindow();
extern bool ToolGetBox();
extern void ToolSnapToGrid();
extern bool ToolGetEditBox(Rect *);
extern void ToolMoveBox(), ToolMoveCorner();
extern int ToolGetCorner();
extern void DBWloadWindow(), DBWxloadWindow();
extern void DBWSetBox();
extern void DBWUndoOldEdit();
extern void DBWUndoNewEdit();
/* Exported procedures for managing highlights: */
extern void DBWHLAddClient();
extern void DBWHLRemoveClient();
extern void DBWHLRedraw();
extern int DBWHLRedrawWind();
extern void DBWDrawBox();
extern void DBWDrawCrosshair();
/* Exported procedures and variables relating to feedback: */
extern int DBWFeedbackCount;
extern void DBWFeedbackClear();
extern void DBWFeedbackAdd();
extern char *DBWFeedbackNth();
/* Exported procedures and variables relating to elements: */
/* flag fields for all elements (8 bits maximum) */
#define DBW_ELEMENT_PERSISTENT 0x01
#define DBW_ELEMENT_TEXT_SIZE 0x0e /* 3 bits (5 text sizes) */
#define DBW_ELEMENT_TEXT_POS 0xf0 /* 4 bits (9 positions) */
#define DBW_ELEMENT_LINE_HALFX 0x02 /* Add 1/2 to X position */
#define DBW_ELEMENT_LINE_HALFY 0x04 /* Add 1/2 to Y position */
#define DBW_ELEMENT_LINE_ARROWL 0x08 /* Add arrowhead left/bottom */
#define DBW_ELEMENT_LINE_ARROWR 0x10 /* Add arrowhead top/right */
extern void DBWElementAddRect();
extern void DBWElementAddLine();
extern void DBWElementAddText();
extern void DBWElementDelete();
extern void DBWElementNames();
extern void DBWElementInbox();
extern void DBWElementParseFlags();
extern char *DBWPrintElements();
/* Random procedures used internally to this module. None of these
* should ever need to be called by the outside world.
*/
extern void DBWCheckBoxDisplay();
extern void DBWUndoBox();
extern void DBWHLUpdate();
extern void DBWFeedbackShow();
extern void dbwElementInit();
extern void dbwCrosshairInit();
#endif /* _DBWIND_H */

21
dbwind/dbwtech.h Normal file
View File

@ -0,0 +1,21 @@
/*
* dbwtech.h --
*
* Style information for display.
* MAXTILESTYLES is the maximum number of styles usable for display
* of tiles.
*
* rcsid $Header: /usr/cvsroot/magic-8.0/dbwind/dbwtech.h,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $
*/
#ifndef _DBWTECH_H
#define _DBWTECH_H
extern TileTypeBitMask *DBWStyleToTypesTbl;
#define DBWStyleToTypes(s) (DBWStyleToTypesTbl + s)
/* forward declarations */
int DBWTechParseStyle();
#endif /* _DBWTECH_H */

5
debug/Depend Normal file
View File

@ -0,0 +1,5 @@
debugFlags.o: debugFlags.c ../utils/magic.h ../debug/debug.h \
../textio/textio.h ../utils/malloc.h ../utils/utils.h
hist.o: hist.c ../utils/magic.h ../utils/geometry.h \
../database/database.h ../tiles/tile.h ../utils/hash.h ../utils/utils.h \
../textio/textio.h ../debug/debug.h ../utils/malloc.h

10
debug/Makefile Normal file
View File

@ -0,0 +1,10 @@
#
# rcsid $Header: /usr/cvsroot/magic-8.0/debug/Makefile,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $
#
MODULE = debug
MAGICDIR = ..
SRCS = debugFlags.c hist.c
include ${MAGICDIR}/defs.mak
include ${MAGICDIR}/rules.mak

78
debug/debug.h Normal file
View File

@ -0,0 +1,78 @@
/*
* debug.h --
*
* Defines the interface to the debugging module.
* The debugging module provides a standard collection of
* procedures for setting, examining, and testing debugging flags.
* Also measurement code.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*
* rcsid $Header: /usr/cvsroot/magic-8.0/debug/debug.h,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $
*/
#ifndef _DEBUG_H
#define _DEBUG_H
#include "utils/magic.h"
struct debugClient
{
char *dc_name; /* Name of client */
int dc_maxflags; /* Maximum number of flags */
int dc_nflags; /* Number flags now in array */
struct debugFlag *dc_flags; /* Array of flags */
};
struct debugFlag
{
char *df_name; /* Name of debugging flag */
bool df_value; /* Current value of the flag */
};
/* A histogram counts of the number of data items in each of
* a number of ranges. It is defined by a low value, a bin size, and
* the number of bins. Items falling in the range hi_lo..hi_lo+n*hi_step-1
* go into hi_data[n], for n=1 to the number of bins. Values outside the
* range are stored in locations 0 and n+1.
*/
typedef struct histogram
{
int hi_lo; /* Lowest bin value */
int hi_step; /* Size of a bin */
int hi_bins; /* Number of bins in histogram */
int hi_max; /* Largest item in the histogram*/
int hi_min; /* Smallest item in the histogram*/
int hi_cum; /* Cumulative item total */
char * hi_title; /* Histogram identifier */
bool hi_ptrKeys; /* TRUE if title is a pointer */
int * hi_data; /* Buckets for histogram counts */
struct histogram * hi_next; /* Linked list to next histogram*/
} Histogram;
/* constants */
#define MAXDEBUGCLIENTS 50 /* Maximum # of clients of debug module */
extern struct debugClient debugClients[];
#define DebugIsSet(cid, f) debugClients[(spointertype) cid].dc_flags[f].df_value
/* procedures */
extern void HistCreate();
extern void HistAdd();
extern void HistPrint();
extern ClientData DebugAddClient();
extern int DebugAddFlag();
extern void DebugShow(), DebugSet();
#endif /* _DEBUG_H */

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