Initial commit at Tue Apr 25 08:41:48 EDT 2017 by tim on stravinsky
This commit is contained in:
commit
231a299b16
|
|
@ -0,0 +1,10 @@
|
|||
*.*%
|
||||
*.cdslck
|
||||
.inca.db.*
|
||||
inca.*.pak
|
||||
*.swp
|
||||
*~
|
||||
*/av_extracted*/
|
||||
.nfs*
|
||||
*.cd-
|
||||
*/mommdl/
|
||||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
@ -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).
|
||||
|
|
@ -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.
|
||||
|
||||
------------------------------------------------------------------
|
||||
|
|
@ -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).
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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");
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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(¢er, 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(¢er, 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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -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 */
|
||||
|
|
@ -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);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 $* )
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 = ▭
|
||||
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 = ▭
|
||||
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));
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -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 = ¤tId[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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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));
|
||||
}
|
||||
|
|
@ -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(¬ConnectMask, 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(¬ConnectMask, 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(¬ConnectMask, ctype);
|
||||
// }
|
||||
// TTMaskCom(¬ConnectMask);
|
||||
|
||||
TTMaskZero(¬ConnectMask);
|
||||
TTMaskSetMask(¬ConnectMask, &DBNotConnectTbl[loctype]);
|
||||
}
|
||||
else
|
||||
{
|
||||
TTMaskCom2(¬ConnectMask, 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, ¬ConnectMask, 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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
Loading…
Reference in New Issue