mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-10-06 01:43:00 +02:00
Initial commit at Tue Apr 25 08:41:48 EDT 2017 by tim on stravinsky
This commit is contained in:
+10
@@ -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
|
||||
<[email protected]> and the current distribution version is
|
||||
maintained by Rajit Manohar <[email protected]>. 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 ([email protected])
|
||||
|
||||
5) Integration of part of the DEC/WRL code fragments into the drc
|
||||
code. Since the code is not completely trustworthy the fragments
|
||||
are ifdef'd so if need be the drc will behave exactly as the old one.
|
||||
(you just need to change the #define DRC_EXTENSIONS in drc/drc.h
|
||||
to do that). For a description of the extensions look into
|
||||
doc/tutwrl1.ps (DEC/WRL)
|
||||
|
||||
6) Integration of some patches in to the CIF code that introduce:
|
||||
(i) A new cif operation squares-grid which generates contacts
|
||||
on grid.
|
||||
(ii) A new cif layer command min-width is added so that generated
|
||||
layers have the correct min drc width when magic expands
|
||||
layers in the hierarchy (like it does with wells).
|
||||
|
||||
|
||||
Magic-6.5 crashes if compiled with gcc in Solaris2.x/SunOS5.x (curiously enough
|
||||
it does not have that problem if compiled with Sun's cc compiler). To get
|
||||
around that you need to set the flag -DUSE_SYSTEM_MALLOC flag in misc/DFLAGS
|
||||
after you run make :config. The error has to do with allignment of doubles
|
||||
and an alternative way to get rid of it is to change extract/extractInt.h
|
||||
so that CapValue is float instead of double. Nevertheless the first method
|
||||
is recomended.
|
||||
|
||||
What's new in 6.4:
|
||||
------------------
|
||||
This release, magic 6.4, contains the following modifications:
|
||||
|
||||
1) A number of bug fixes from the 6.3 notes.
|
||||
|
||||
2) A version numbering facility for tech files. Please add a new
|
||||
section to each tech file after the "tech" section, following
|
||||
this example:
|
||||
|
||||
version
|
||||
version 2.0.3
|
||||
description "MOSIS CMOS 0.13u Nano-nano technology."
|
||||
end
|
||||
|
||||
Older versions of magic will complain about the new section, but
|
||||
no harm will be done.
|
||||
|
||||
4) Various comments describing dates and versions, including the
|
||||
above tech file information, are not written to the CIF file.
|
||||
|
||||
3) Support for patches and versioning: A new command called "version"
|
||||
lists out the version number and patches that are installed.
|
||||
A header file called patchlevel.h keeps track of a PATCHLEVEL
|
||||
integer and a string in patchlevel.c keeps track of the names of
|
||||
each installed patch. When posting patches to the net please be
|
||||
sure your patch updates variables. See the files for details.
|
||||
|
||||
4) Ports to Alpha AXP OSF/1, SGI/IRIX (courtesy of Stefanos
|
||||
Sidiropoulos) and Linux (courtesy of Harold Levy).
|
||||
|
||||
5) A change in the extractor algorithm to provide shielding for
|
||||
perimeter capacitances. Also a change in ext2sim to maintain
|
||||
information about the area and perimeter of diffusion and
|
||||
the bulk connection of the fets (written by Stefanos
|
||||
Sidiropoulos).
|
||||
+385
@@ -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).
|
||||
+1079
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);
|
||||
}
|
||||
+1018
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");
|
||||
}
|
||||
+2478
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 */
|
||||
+3338
File diff suppressed because it is too large
Load Diff
+1146
File diff suppressed because it is too large
Load Diff
+340
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* CIFint.h --
|
||||
*
|
||||
* Defines things shared internally by the cif module of Magic,
|
||||
* but not generally needed outside the cif module.
|
||||
*
|
||||
* *********************************************************************
|
||||
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
||||
* * Permission to use, copy, modify, and distribute this *
|
||||
* * software and its documentation for any purpose and without *
|
||||
* * fee is hereby granted, provided that the above copyright *
|
||||
* * notice appear in all copies. The University of California *
|
||||
* * makes no representations about the suitability of this *
|
||||
* * software for any purpose. It is provided "as is" without *
|
||||
* * express or implied warranty. Export of this software outside *
|
||||
* * of the United States of America may require an export license. *
|
||||
* *********************************************************************
|
||||
*
|
||||
* rcsid "$Header: /usr/cvsroot/magic-8.0/cif/CIFint.h,v 1.3 2008/12/04 17:10:29 tim Exp $"
|
||||
*/
|
||||
|
||||
#ifndef _CIFINT_H
|
||||
#define _CIFINT_H
|
||||
|
||||
#include "database/database.h"
|
||||
|
||||
/* The main data structure used in the cif module is a description
|
||||
* of how to generate CIF layers from the Magic tiles. There may
|
||||
* be several different styles for generating CIF from the same Magic
|
||||
* information, e.g. for fabricating at different geometries. Each
|
||||
* of these CIF styles involves three kinds of data. A "CIFStyle"
|
||||
* record gives overall information such as the number of layers.
|
||||
* One "CIFLayer" gives overall information for each layer, and
|
||||
* then a list of one or more "CIFOp" records describes a sequence
|
||||
* of geometrical operations to perform to generate the layer. This
|
||||
* data structure is built up by reading the technology file.
|
||||
*/
|
||||
|
||||
/* A CIFOp starts from a partially-completed CIF layer, does something
|
||||
* to it, which may possibly involve some existing layers or temporary
|
||||
* layers, and creates the next stage of the partially-completed
|
||||
* CIF layer. Example operations are to AND with some existing paint,
|
||||
* or to grow by a certain amount.
|
||||
*/
|
||||
|
||||
typedef struct bloat_data
|
||||
{
|
||||
int bl_plane; /* Plane on which a bloat or squares
|
||||
* operation is valid.
|
||||
*/
|
||||
int bl_distance[TT_MAXTYPES];
|
||||
} BloatData;
|
||||
|
||||
typedef struct squares_data
|
||||
{
|
||||
int sq_border;
|
||||
int sq_size;
|
||||
int sq_sep;
|
||||
int sq_gridx; /* Only used for "squares-grid" */
|
||||
int sq_gridy; /* Only used for "squares-grid" */
|
||||
} SquaresData;
|
||||
|
||||
typedef struct slots_data
|
||||
{
|
||||
int sl_sborder; /* short tile side */
|
||||
int sl_ssize;
|
||||
int sl_ssep;
|
||||
int sl_lborder; /* long tile side */
|
||||
int sl_lsize;
|
||||
int sl_lsep;
|
||||
int sl_offset;
|
||||
} SlotsData;
|
||||
|
||||
typedef struct cifop
|
||||
{
|
||||
TileTypeBitMask co_paintMask;/* Zero or more paint layers to consider. */
|
||||
TileTypeBitMask co_cifMask; /* Zero or more other CIF layers. */
|
||||
int co_opcode; /* Which geometric operation to use. See
|
||||
* below for the legal ones.
|
||||
*/
|
||||
int co_distance; /* Grow or shrink distance (if needed). */
|
||||
ClientData co_client; /* Pointer to a BloatData, SquaresData, or
|
||||
* SlotsData structure, or NULL.
|
||||
*/
|
||||
struct cifop *co_next; /* Next in list of operations to perform. */
|
||||
} CIFOp;
|
||||
|
||||
/* The opcodes defined so far are:
|
||||
*
|
||||
* CIFOP_AND - AND current results with the layers indicated by
|
||||
* the masks.
|
||||
* CIFOP_ANDNOT - Wherever there is material indicated by the masks,
|
||||
* erase those areas from the current results.
|
||||
* CIFOP_OR - OR current results with the layers indicated by
|
||||
* the masks.
|
||||
* CIFOP_GROW - Grow the current results uniformly by co_distance.
|
||||
* CIFOP_GROW_G - Grow the current results to snap to the indicated grid.
|
||||
* CIFOP_SHRINK - Shrink the current results uniformly by co_distance.
|
||||
* CIFOP_BLOAT - Find layers in paintMask, then bloat selectively
|
||||
* according to bl_distance, and OR the results into
|
||||
* the current plane
|
||||
* CIFOP_SQUARES - Generates a pattern of squares (used for making
|
||||
* contact vias. Each square is co_distance large,
|
||||
* the squares are separated from each other by
|
||||
* co_distance, and they are inside the edge of
|
||||
* the material by at least co_distance.
|
||||
* CIFOP_SLOTS - Generate a pattern of rectangles (used for making
|
||||
* slots and slot vias). Similar to squares except
|
||||
* for different dimensions in short and long tile
|
||||
* dimensions. "0" for the long size indicates that
|
||||
* the slot should extend the length of the tile
|
||||
* minus the long-side border length.
|
||||
* CIFOP_BLOATMAX - Like CIFOP_BLOAT, except whole side of tile gets
|
||||
* bloated by same amount, which is max bloat from
|
||||
* anywhere along side. Bloats can be negative.
|
||||
* CIFOP_BLOATMIN - Same as CIFOP_BLOAT, except use min bloat from
|
||||
* anywhere along side.
|
||||
* CIFOP_BLOATALL - Added 3/21/05---bloat to encompass all connected
|
||||
* material of the indicated type(s).
|
||||
* CIFOP_BBOX - Added 4/2/05---create a single rectangle encompassing
|
||||
* the cell bounding box. This involves no magic type
|
||||
* layers but may itself be acted upon with grow/shrink
|
||||
* rules.
|
||||
* CIFOP_NET - Added 11/3/08---pull an entire electrical net into
|
||||
* the CIF layer, selectively picking layers.
|
||||
* CIFOP_MAXRECT - Reduce all areas to the largest internal fitting
|
||||
* rectangle.
|
||||
* CIFOP_COPYUP - Added 5/5/16---make and keep a copy the resulting layer,
|
||||
* which will be painted into parent cells instead of the
|
||||
* current cell. This replaces the "fault" method.
|
||||
*/
|
||||
|
||||
#define CIFOP_AND 1
|
||||
#define CIFOP_OR 2
|
||||
#define CIFOP_GROW 3
|
||||
#define CIFOP_GROW_G 4
|
||||
#define CIFOP_SHRINK 5
|
||||
#define CIFOP_BLOAT 6
|
||||
#define CIFOP_SQUARES 7
|
||||
#define CIFOP_SLOTS 8
|
||||
#define CIFOP_BLOATMAX 9
|
||||
#define CIFOP_BLOATMIN 10
|
||||
#define CIFOP_BLOATALL 11
|
||||
#define CIFOP_ANDNOT 12
|
||||
#define CIFOP_SQUARES_G 13
|
||||
#define CIFOP_BBOX 14
|
||||
#define CIFOP_NET 15
|
||||
#define CIFOP_MAXRECT 16
|
||||
#define CIFOP_COPYUP 17
|
||||
|
||||
/* Added by Tim 10/21/2004 */
|
||||
/* The following structure is used to pass information on how to draw
|
||||
* contact subcell arrays for a specific magic contact tile type. For
|
||||
* the GDS write routine, the GDS file (FILE *) is passed as the client
|
||||
* data.
|
||||
*/
|
||||
|
||||
typedef struct cifsquaresinfo
|
||||
{
|
||||
SquaresData *csi_squares; /* Information on how to generate squares */
|
||||
TileType csi_type; /* Magic contact tile type */
|
||||
ClientData csi_client; /* Used to pass output file info. */
|
||||
} CIFSquaresInfo;
|
||||
|
||||
/* The following data structure contains all the information about
|
||||
* a particular CIF layer.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *cl_name; /* Name of layer. */
|
||||
CIFOp *cl_ops; /* List of operations. If NULL, layer is
|
||||
* determined entirely by cl_initial.
|
||||
*/
|
||||
int cl_growDist; /* Largest distance material may move in
|
||||
* this layer from its original Magic
|
||||
* position, due to grows. Expressed
|
||||
* in CIF units. If this layer uses temp
|
||||
* layers, this distance must include grows
|
||||
* from the temp layers.
|
||||
*/
|
||||
int cl_shrinkDist; /* Same as above, except for shrinks. */
|
||||
int cl_flags; /* Bunches of flags: see below. */
|
||||
int cl_calmanum; /* Number (0-63) of this layer for output as
|
||||
* Calma (GDS-II stream format), or -1 if
|
||||
* this layer should not be output.
|
||||
*/
|
||||
int cl_calmatype; /* Data type (0-63) for Calma output, or -1
|
||||
* if this layer should not be output.
|
||||
*/
|
||||
int min_width; /* the minimum width rule in centi-microns
|
||||
* for the layer. This is used by Grow Sliver
|
||||
* to generate drc correct parent slivers
|
||||
*/
|
||||
#ifdef THREE_D
|
||||
int cl_renderStyle; /* Style to render CIF layer with */
|
||||
float cl_height; /* (rendered) height of CIF layer above substrate */
|
||||
float cl_thick; /* (rendered) thickness of CIF layer */
|
||||
#endif
|
||||
|
||||
} CIFLayer;
|
||||
|
||||
/* The CIFLayer flags are:
|
||||
*
|
||||
* CIF_TEMP: Means that this is a temporary layer used to build
|
||||
* up CIF information. It isn't output in the CIF file.
|
||||
* CIF_BBOX_TOP: Indicates that the bounding box rectangle should
|
||||
* only be generated if the cell is a top-level cell.
|
||||
*/
|
||||
|
||||
#define CIF_TEMP 1
|
||||
#define CIF_BBOX_TOP 2
|
||||
|
||||
/* The following data structure describes a complete set of CIF
|
||||
* layers. The number of CIF layers (MAXCIFLAYERS) must not be
|
||||
* greater than the number of tile types (TT_MAXTYPES)!!
|
||||
*/
|
||||
|
||||
#define MAXCIFLAYERS (TT_MAXTYPES - 1)
|
||||
|
||||
typedef struct cifkeep
|
||||
{
|
||||
struct cifkeep *cs_next;
|
||||
char *cs_name;
|
||||
} CIFKeep;
|
||||
|
||||
typedef struct cifstyle
|
||||
{
|
||||
char cs_status; /* Status: Loaded, not loaded, or pending. */
|
||||
char *cs_name; /* Name used for this kind of CIF. */
|
||||
int cs_nLayers; /* Number of layers. */
|
||||
int cs_radius; /* Radius of interaction for hierarchical
|
||||
* processing (expressed in Magic units).
|
||||
*/
|
||||
int cs_stepSize; /* If non-zero, user-specified step size
|
||||
* for hierarchical processing (in Magic
|
||||
* units).
|
||||
*/
|
||||
int cs_gridLimit; /* The limit of grid scaling. This limits
|
||||
* the use of "scalegrid" to prevent Magic
|
||||
* from generating geometry smaller than the
|
||||
* process minimum grid.
|
||||
*/
|
||||
int cs_scaleFactor; /* Number of CIF units per Magic unit.
|
||||
* CIF units are usually centimicrons, but
|
||||
* see cs_expander below.
|
||||
*/
|
||||
int cs_reducer; /* Reduction factor (used only to reduce
|
||||
* number of zeroes in CIF files and make
|
||||
* file more readable). Default of 1.
|
||||
* Unused for GDS input/output.
|
||||
*/
|
||||
int cs_expander; /* cs_scaleFactor / cs_expander = scale in
|
||||
* centimicrons. Default of 1. Value 10
|
||||
* means cs_scaleFactor is measured in
|
||||
* nanometers (millimicrons)
|
||||
*/
|
||||
|
||||
TileTypeBitMask cs_yankLayers;
|
||||
/* For hierarchical processing, only these
|
||||
* Magic types need to be yanked.
|
||||
*/
|
||||
TileTypeBitMask cs_hierLayers;
|
||||
/* For hierarchical processing, only these
|
||||
* CIF layers need to be generated.
|
||||
*/
|
||||
int cs_labelLayer[TT_MAXTYPES];
|
||||
/* Each entry corresponds to one Magic layer,
|
||||
* and gives index of CIF real layer to use
|
||||
* for labels attached to this Magic layer.
|
||||
* -1 means no known CIF layer for this Magic
|
||||
* layer.
|
||||
*/
|
||||
CIFLayer *cs_layers[MAXCIFLAYERS];
|
||||
/* Describes how to generate each layer.*/
|
||||
int cs_flags; /* bitmask of boolean-valued output options */
|
||||
|
||||
} CIFStyle;
|
||||
|
||||
/* values for cs_flags */
|
||||
#define CWF_PERMISSIVE_LABELS 0x01
|
||||
#define CWF_GROW_SLIVERS 0x02
|
||||
#define CWF_ANGSTROMS 0x04
|
||||
#define CWF_GROW_EUCLIDEAN 0x08
|
||||
#define CWF_SEE_VENDOR 0x10 /* Override vendor GDS flag in cells */
|
||||
#define CWF_NO_ERRORS 0x20 /* Do not generate error msgs and fdbk */
|
||||
|
||||
/* procedures */
|
||||
|
||||
extern bool CIFNameToMask();
|
||||
extern void CIFGenSubcells();
|
||||
extern void CIFGenArrays();
|
||||
extern void CIFGen();
|
||||
extern void CIFClearPlanes();
|
||||
extern Plane *CIFGenLayer();
|
||||
extern void CIFInitCells();
|
||||
extern int cifHierCopyFunc();
|
||||
extern void CIFLoadStyle();
|
||||
|
||||
/* Shared variables and structures: */
|
||||
|
||||
extern Plane *CIFPlanes[]; /* Normal place to store CIF. */
|
||||
extern CIFKeep *CIFStyleList; /* List of all CIF styles. */
|
||||
extern CIFStyle *CIFCurStyle; /* Current style being used. */
|
||||
extern CellUse *CIFComponentUse; /* Flatten stuff in here if needed. */
|
||||
extern CellDef *CIFComponentDef; /* Corresponds to CIFComponentUse. */
|
||||
extern CellUse *CIFDummyUse; /* Used to dummy up a CellUse for a
|
||||
* def.
|
||||
*/
|
||||
|
||||
/* Valid values of CIFWarningLevel (see cif.h) */
|
||||
|
||||
typedef enum {CIF_WARN_DEFAULT, CIF_WARN_NONE, CIF_WARN_ALIGN,
|
||||
CIF_WARN_LIMIT, CIF_WARN_REDIRECT, CIF_WARN_END} CIFWarningTypes;
|
||||
|
||||
/* Statistics counters: */
|
||||
|
||||
extern int CIFTileOps;
|
||||
extern int CIFHierTileOps;
|
||||
extern int CIFRects;
|
||||
extern int CIFHierRects;
|
||||
|
||||
/* Tables used for painting and erasing CIF. */
|
||||
|
||||
extern PaintResultType CIFPaintTable[], CIFEraseTable[];
|
||||
|
||||
/* Procedures and variables for reporting errors. */
|
||||
|
||||
extern int CIFErrorLayer;
|
||||
extern CellDef *CIFErrorDef;
|
||||
extern void CIFError();
|
||||
|
||||
/* The following determines the tile type used to hold the CIF
|
||||
* information on its paint plane.
|
||||
*/
|
||||
|
||||
#define CIF_SOLIDTYPE 1
|
||||
extern TileTypeBitMask CIFSolidBits;
|
||||
|
||||
#endif /* _CIFINT_H */
|
||||
+413
@@ -0,0 +1,413 @@
|
||||
/* CIFmain.c -
|
||||
*
|
||||
* This file contains global information for the CIF module,
|
||||
* such as performance statistics.
|
||||
*
|
||||
* *********************************************************************
|
||||
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
||||
* * Permission to use, copy, modify, and distribute this *
|
||||
* * software and its documentation for any purpose and without *
|
||||
* * fee is hereby granted, provided that the above copyright *
|
||||
* * notice appear in all copies. The University of California *
|
||||
* * makes no representations about the suitability of this *
|
||||
* * software for any purpose. It is provided "as is" without *
|
||||
* * express or implied warranty. Export of this software outside *
|
||||
* * of the United States of America may require an export license. *
|
||||
* *********************************************************************
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFmain.c,v 1.3 2009/01/15 15:44:34 tim Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tcltk/tclmagic.h"
|
||||
#include "utils/magic.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "tiles/tile.h"
|
||||
#include "utils/hash.h"
|
||||
#include "database/database.h"
|
||||
#include "cif/CIFint.h"
|
||||
#include "textio/textio.h"
|
||||
#include "windows/windows.h"
|
||||
#include "dbwind/dbwind.h"
|
||||
#include "utils/styles.h"
|
||||
|
||||
/* The following points to a list of all the CIF output styles
|
||||
* currently understood:
|
||||
*/
|
||||
|
||||
CIFKeep *CIFStyleList;
|
||||
|
||||
/* The current style being used for CIF output: */
|
||||
|
||||
CIFStyle *CIFCurStyle = NULL;
|
||||
|
||||
/* The following are statistics gathered at various points in
|
||||
* CIF processing. There are two versions of each statistic:
|
||||
* a total number, and the number since stats were last printed.
|
||||
*/
|
||||
|
||||
int CIFTileOps = 0; /* Total tiles touched in geometrical
|
||||
* operations.
|
||||
*/
|
||||
int CIFHierTileOps = 0; /* Tiles touched in geometrical operations
|
||||
* as part of hierarchical processing.
|
||||
*/
|
||||
int CIFRects = 0; /* Total CIF rectangles output. */
|
||||
int CIFHierRects = 0; /* Rectangles stemming from interactions. */
|
||||
|
||||
static int cifTotalTileOps = 0;
|
||||
static int cifTotalHierTileOps = 0;
|
||||
static int cifTotalRects = 0;
|
||||
static int cifTotalHierRects = 0;
|
||||
|
||||
/* This file provides several procedures for dealing with errors during
|
||||
* the CIF generation process. Low-level CIF artwork-manipulation
|
||||
* procedures call CIFError without knowing what cell CIF is being
|
||||
* generated for, or what layer is being generated. Higher-level
|
||||
* routines are responsible for recording that information in the
|
||||
* variables below so that CIFError can output meaningful diagnostics
|
||||
* using the feedback mechanism.
|
||||
*/
|
||||
|
||||
global CellDef *CIFErrorDef; /* Definition in which to record errors. */
|
||||
global int CIFErrorLayer; /* Index of CIF layer associated with errors.*/
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CIFPrintStats --
|
||||
*
|
||||
* This procedure prints out CIF statistics including both
|
||||
* total values and counts since the last printing.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Several messages are printed.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
CIFPrintStats()
|
||||
{
|
||||
TxPrintf("CIF statistics (recent/total):\n");
|
||||
cifTotalTileOps += CIFTileOps;
|
||||
TxPrintf(" Geometrical tile operations: %d/%d\n",
|
||||
CIFTileOps, cifTotalTileOps);
|
||||
CIFTileOps = 0;
|
||||
cifTotalHierTileOps += CIFHierTileOps;
|
||||
TxPrintf(" Tile operations for hierarchy: %d/%d\n",
|
||||
CIFHierTileOps, cifTotalHierTileOps);
|
||||
CIFHierTileOps = 0;
|
||||
cifTotalRects += CIFRects;
|
||||
TxPrintf(" CIF rectangles output: %d/%d\n",
|
||||
CIFRects, cifTotalRects);
|
||||
CIFRects = 0;
|
||||
cifTotalHierRects += CIFHierRects;
|
||||
TxPrintf(" CIF rectangles due to hierarchical interactions: %d/%d\n",
|
||||
CIFHierRects, cifTotalHierRects);
|
||||
CIFHierRects = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CIFGetOutputScale --
|
||||
*
|
||||
* This routine is given here so that the CIF output scale can be
|
||||
* accessed from the "commands" directory source without declaring
|
||||
* external references to CIF global variables.
|
||||
*
|
||||
* Results:
|
||||
* Internal units-to-(nanometers * convert) conversion factor (float).
|
||||
* Use convert = 1000 for centimicrons-to-microns conversion
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
float
|
||||
CIFGetOutputScale(convert)
|
||||
int convert;
|
||||
{
|
||||
if (CIFCurStyle == NULL) return 1.0;
|
||||
|
||||
return ((float)(10 * CIFCurStyle->cs_scaleFactor) /
|
||||
(float)(CIFCurStyle->cs_expander * convert));
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CIFPrintStyle --
|
||||
*
|
||||
* This procedure prints the current CIF output style or list
|
||||
* of known styles.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Output.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
CIFPrintStyle(dolist, doforall, docurrent)
|
||||
bool dolist; /* Return as a list if true */
|
||||
bool doforall; /* Print all known styles if true */
|
||||
bool docurrent; /* Print current style if true */
|
||||
{
|
||||
CIFKeep *style;
|
||||
|
||||
if (docurrent)
|
||||
{
|
||||
if (CIFCurStyle == NULL)
|
||||
TxError("Error: No style is set\n");
|
||||
else
|
||||
{
|
||||
if (!dolist) TxPrintf("The current style is \"");
|
||||
#ifdef MAGIC_WRAPPER
|
||||
if (dolist)
|
||||
Tcl_SetResult(magicinterp, CIFCurStyle->cs_name, NULL);
|
||||
else
|
||||
#endif
|
||||
TxPrintf("%s", CIFCurStyle->cs_name);
|
||||
if (!dolist) TxPrintf("\".\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (doforall)
|
||||
{
|
||||
if (!dolist) TxPrintf("The CIF output styles are: ");
|
||||
|
||||
for (style = CIFStyleList; style != NULL; style = style->cs_next)
|
||||
{
|
||||
if (dolist)
|
||||
{
|
||||
#ifdef MAGIC_WRAPPER
|
||||
Tcl_AppendElement(magicinterp, style->cs_name);
|
||||
#else
|
||||
if (style != CIFStyleList) TxPrintf(" ");
|
||||
TxPrintf("%s", style->cs_name);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (style != CIFStyleList) TxPrintf(", ");
|
||||
TxPrintf("%s", style->cs_name);
|
||||
}
|
||||
}
|
||||
if (!dolist) TxPrintf(".\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CIFSetStyle --
|
||||
*
|
||||
* This procedure changes the current CIF output style to the one
|
||||
* named by the parameter.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* The current CIF style is changed. If the name doesn't match,
|
||||
* or is ambiguous, then a list of all CIF styles is output.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
CIFSetStyle(name)
|
||||
char *name; /* Name of the new style. If NULL, just
|
||||
* print out the valid styles.
|
||||
*/
|
||||
{
|
||||
CIFKeep *style, *match;
|
||||
int length;
|
||||
|
||||
if (name == NULL) return;
|
||||
|
||||
match = NULL;
|
||||
length = strlen(name);
|
||||
|
||||
for (style = CIFStyleList; style != NULL; style = style->cs_next)
|
||||
{
|
||||
if (strncmp(name, style->cs_name, length) == 0)
|
||||
{
|
||||
if (match != NULL)
|
||||
{
|
||||
TxError("CIF output style \"%s\" is ambiguous.\n", name);
|
||||
CIFPrintStyle(FALSE, TRUE, TRUE);
|
||||
return;
|
||||
}
|
||||
match = style;
|
||||
}
|
||||
}
|
||||
|
||||
if (match != NULL)
|
||||
{
|
||||
CIFLoadStyle(match->cs_name);
|
||||
TxPrintf("CIF output style is now \"%s\"\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
TxError("\"%s\" is not one of the CIF output styles Magic knows.\n", name);
|
||||
CIFPrintStyle(FALSE, TRUE, TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CIFNameToMask --
|
||||
*
|
||||
* Finds the CIF planes for a given name.
|
||||
*
|
||||
* Results:
|
||||
* Returns TRUE on success, or FALSE if "name" failed to match any layers.
|
||||
*
|
||||
* Side effects:
|
||||
* If there's no match, then an error message is output.
|
||||
* The sets 'result' to be all types containing the CIF layer named
|
||||
* "name". The current CIF style is used for the lookup. If "depend"
|
||||
* is non-NULL, then it is filled with the mask of all layers on which
|
||||
* the named layer depends.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bool
|
||||
CIFNameToMask(name, result, depend)
|
||||
char *name;
|
||||
TileTypeBitMask *result;
|
||||
TileTypeBitMask *depend;
|
||||
{
|
||||
int i, j;
|
||||
CIFOp *op;
|
||||
CIFLayer *cl;
|
||||
|
||||
if (!CIFCurStyle)
|
||||
{
|
||||
TxError("No CIF output style set!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TTMaskZero(result);
|
||||
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
|
||||
if (strcmp(name, CIFCurStyle->cs_layers[i]->cl_name) == 0)
|
||||
TTMaskSetType(result, i);
|
||||
|
||||
if (!TTMaskEqual(result, &DBZeroTypeBits))
|
||||
{
|
||||
/* This loop depends on the fact that templayers must */
|
||||
/* be declared in order of dependency; that is, you */
|
||||
/* can't use a layer before it is declared. Thus, the */
|
||||
/* dependent layers will always be filled in from layer */
|
||||
/* i back to zero. */
|
||||
|
||||
if (depend)
|
||||
{
|
||||
TTMaskZero(depend);
|
||||
TTMaskSetMask(depend, result);
|
||||
for (j = CIFCurStyle->cs_nLayers - 1; j >= 0; j--)
|
||||
if (TTMaskHasType(depend, j))
|
||||
{
|
||||
cl = CIFCurStyle->cs_layers[j];
|
||||
for (op = cl->cl_ops; op != NULL; op = op->co_next)
|
||||
TTMaskSetMask(depend, &op->co_cifMask);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
TxError("CIF name \"%s\" doesn't exist in style \"%s\".\n", name,
|
||||
CIFCurStyle->cs_name);
|
||||
TxError("The valid CIF layer names are: ");
|
||||
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
TxError("%s", CIFCurStyle->cs_layers[i]->cl_name);
|
||||
else
|
||||
TxError(", %s", CIFCurStyle->cs_layers[i]->cl_name);
|
||||
}
|
||||
TxError(".\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CIFError --
|
||||
*
|
||||
* This procedure is called by low-level CIF generation routines
|
||||
* when a problem is encountered in generating CIF. This procedure
|
||||
* notes the problem using the feedback mechanism.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Feedback information is added. The caller must have set CIFErrorDef
|
||||
* to point to the cell definition that area refers to. If CIFErrorDef
|
||||
* is NULL, then errors are ignored.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
CIFError(area, message)
|
||||
Rect *area; /* Place in CIFErrorDef where there was a
|
||||
* problem in generating CIFErrorLayer.
|
||||
*/
|
||||
char *message; /* Short note about what went wrong. */
|
||||
{
|
||||
char msg[200];
|
||||
|
||||
if (CIFCurStyle->cs_flags & CWF_NO_ERRORS) return;
|
||||
|
||||
if (CIFErrorDef == (NULL)) return;
|
||||
(void) sprintf(msg, "CIF error in cell %s, layer %s: %s",
|
||||
CIFErrorDef->cd_name, CIFCurStyle->cs_layers[CIFErrorLayer]->cl_name,
|
||||
message);
|
||||
DBWFeedbackAdd(area, msg, CIFErrorDef, CIFCurStyle->cs_scaleFactor,
|
||||
STYLE_PALEHIGHLIGHTS);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CIFOutputScaleFactor --
|
||||
*
|
||||
* Returns current conversion factor between CIF units and
|
||||
* Magic units.
|
||||
*
|
||||
* Results:
|
||||
* The return value is the number of centimicrons per Magic
|
||||
* unit in the current CIF output style. If there is no
|
||||
* known CIF output style, 1 is returned.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
CIFOutputScaleFactor()
|
||||
{
|
||||
if (CIFCurStyle == NULL) return 1;
|
||||
return CIFCurStyle->cs_scaleFactor;
|
||||
}
|
||||
+1389
File diff suppressed because it is too large
Load Diff
+335
@@ -0,0 +1,335 @@
|
||||
/* CIFreadpoly.c -
|
||||
*
|
||||
* This file contains procedures that turn polygons into
|
||||
* rectangles, as part of CIF file reading.
|
||||
*
|
||||
* *********************************************************************
|
||||
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
||||
* * Permission to use, copy, modify, and distribute this *
|
||||
* * software and its documentation for any purpose and without *
|
||||
* * fee is hereby granted, provided that the above copyright *
|
||||
* * notice appear in all copies. The University of California *
|
||||
* * makes no representations about the suitability of this *
|
||||
* * software for any purpose. It is provided "as is" without *
|
||||
* * express or implied warranty. Export of this software outside *
|
||||
* * of the United States of America may require an export license. *
|
||||
* *********************************************************************
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFrdpoly.c,v 1.3 2010/06/24 12:37:15 tim Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "utils/magic.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "tiles/tile.h"
|
||||
#include "utils/hash.h"
|
||||
#include "database/database.h"
|
||||
#include "cif/CIFint.h"
|
||||
#include "cif/CIFread.h"
|
||||
#include "utils/malloc.h"
|
||||
|
||||
#define HEDGE 0 /* Horizontal edge */
|
||||
#define REDGE 1 /* Rising edge */
|
||||
#define FEDGE -1 /* Falling edge */
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifLowX --
|
||||
*
|
||||
* This is a comparison procedure called by qsort.
|
||||
*
|
||||
* Results:
|
||||
* 1 if a.x > b.x,
|
||||
* -1 if a.x < b.x,
|
||||
* 0 otherwise.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifLowX(a, b)
|
||||
CIFPath **a, **b;
|
||||
{
|
||||
Point *p, *q;
|
||||
|
||||
p = &(*a)->cifp_point;
|
||||
q = &(*b)->cifp_point;
|
||||
if (p->p_x < q->p_x)
|
||||
return (-1);
|
||||
if (p->p_x > q->p_x)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifLowY --
|
||||
*
|
||||
* This is another comparison procedure called by qsort.
|
||||
*
|
||||
* Results:
|
||||
* 1 if a.y > b.y
|
||||
* -1 if a.y < b.y
|
||||
* 0 otherwise
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifLowY(a, b)
|
||||
Point **a, **b;
|
||||
{
|
||||
if ((*a)->p_y < (*b)->p_y)
|
||||
return (-1);
|
||||
if ((*a)->p_y > (*b)->p_y)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifOrient --
|
||||
*
|
||||
* This procedure assigns a direction to each of the edges in a
|
||||
* polygon.
|
||||
*
|
||||
* Results:
|
||||
* TRUE is returned if all of the edges are horizontal or vertical,
|
||||
* FALSE is returned otherwise. If FALSE is returned, not all of
|
||||
* the directions will have been filled in.
|
||||
*
|
||||
* Side effects:
|
||||
* The parameter dir is filled in with the directions, which are
|
||||
* each one of HEDGE, REDGE, or FEDGE.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bool
|
||||
cifOrient(edges, nedges, dir)
|
||||
CIFPath *edges[]; /* Array of edges to be categorized. */
|
||||
int dir[]; /* Array to hold directions. */
|
||||
int nedges; /* Size of arrays. */
|
||||
{
|
||||
Point *p, *q;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < nedges; n++)
|
||||
{
|
||||
/* note - path list should close on itself */
|
||||
p = &edges[n]->cifp_point;
|
||||
q = &edges[n]->cifp_next->cifp_point;
|
||||
if (p->p_y == q->p_y)
|
||||
{
|
||||
/* note - point may connect to itself here */
|
||||
dir[n] = HEDGE;
|
||||
continue;
|
||||
}
|
||||
if (p->p_x == q->p_x)
|
||||
{
|
||||
if (p->p_y < q->p_y)
|
||||
{
|
||||
dir[n] = REDGE;
|
||||
continue;
|
||||
}
|
||||
if (p->p_y > q->p_y)
|
||||
{
|
||||
dir[n] = FEDGE;
|
||||
continue;
|
||||
}
|
||||
/* Point connects to itself */
|
||||
dir[n] = HEDGE;
|
||||
continue;
|
||||
}
|
||||
/* It's not Manhattan, folks. */
|
||||
return (FALSE);
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifCross --
|
||||
*
|
||||
* This procedure is used to see if an edge crosses a particular
|
||||
* area.
|
||||
*
|
||||
* Results:
|
||||
* TRUE is returned if edge is vertical and if it crosses the
|
||||
* y-range defined by ybot and ytop. FALSE is returned otherwise.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bool
|
||||
cifCross(edge, dir, ybot, ytop)
|
||||
CIFPath *edge; /* Pointer to first of 2 path points in edge */
|
||||
int dir; /* Direction of edge */
|
||||
int ybot, ytop; /* Range of interest */
|
||||
{
|
||||
int ebot, etop;
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case REDGE:
|
||||
ebot = edge->cifp_point.p_y;
|
||||
etop = edge->cifp_next->cifp_point.p_y;
|
||||
return (ebot <= ybot && etop >= ytop);
|
||||
|
||||
case FEDGE:
|
||||
ebot = edge->cifp_next->cifp_point.p_y;
|
||||
etop = edge->cifp_point.p_y;
|
||||
return (ebot <= ybot && etop >= ytop);
|
||||
|
||||
}
|
||||
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CIFPolyToRects --
|
||||
*
|
||||
* Converts a manhattan polygon (specified as a path) into a
|
||||
* linked list of rectangles.
|
||||
*
|
||||
* Results:
|
||||
* The return value is a linked list of rectangles, or NULL if
|
||||
* something went wrong.
|
||||
*
|
||||
* Side effects:
|
||||
* Memory is allocated to hold the list of rectangles. It is
|
||||
* the caller's responsibility to free up the memory.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
LinkedRect *
|
||||
CIFPolyToRects(path, plane, resultTbl, ui)
|
||||
CIFPath *path; /* Path describing a polygon. */
|
||||
Plane *plane; /* Plane to draw on */
|
||||
PaintResultType *resultTbl;
|
||||
PaintUndoInfo *ui;
|
||||
{
|
||||
int npts = 0, n, *dir, curr, wrapno;
|
||||
int xbot, xtop, ybot, ytop;
|
||||
Point **pts;
|
||||
CIFPath *p, **edges, *tail = 0;
|
||||
LinkedRect *rex = 0, *new;
|
||||
|
||||
/* Close path list. */
|
||||
|
||||
for (tail = path; tail->cifp_next; tail = tail->cifp_next);
|
||||
|
||||
if ((tail->cifp_x != path->cifp_x) || (tail->cifp_y != path->cifp_y))
|
||||
{
|
||||
p = (CIFPath *) mallocMagic ((unsigned) sizeof (CIFPath));
|
||||
p->cifp_x = path->cifp_x;
|
||||
p->cifp_y = path->cifp_y;
|
||||
p->cifp_next = (CIFPath *) 0;
|
||||
tail->cifp_next = p;
|
||||
}
|
||||
|
||||
CIFMakeManhattanPath(path, plane, resultTbl, ui);
|
||||
|
||||
for (p = path; p->cifp_next; p = p->cifp_next, npts++);
|
||||
pts = (Point **)mallocMagic(npts * sizeof(Point *));
|
||||
dir = (int *)mallocMagic(npts * sizeof(int));
|
||||
edges = (CIFPath **)mallocMagic(npts * sizeof(CIFPath *));
|
||||
npts = 0;
|
||||
|
||||
for (p = path; p->cifp_next; p = p->cifp_next, npts++)
|
||||
{
|
||||
pts[npts] = &(p->cifp_point);
|
||||
edges[npts] = p;
|
||||
}
|
||||
|
||||
if (npts < 4)
|
||||
{
|
||||
if (npts > 0)
|
||||
CIFReadError("polygon with fewer than 4 points.\n" );
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Sort points by low y, edges by low x */
|
||||
|
||||
qsort ((char *) pts, npts, (int) sizeof (Point *), cifLowY);
|
||||
qsort ((char *) edges, npts, (int) sizeof (CIFPath *), cifLowX);
|
||||
|
||||
/* Find out which direction each edge points. */
|
||||
|
||||
if (!cifOrient (edges, npts, dir))
|
||||
{
|
||||
CIFReadError("non-manhattan polygon.\n" );
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Scan the polygon from bottom to top. At each step, process
|
||||
* a minimum-sized y-range of the polygon (i.e. a range such that
|
||||
* there are no vertices inside the range). Use wrap numbers
|
||||
* based on the edge orientations to determine how much of the
|
||||
* x-range for this y-range should contain material.
|
||||
*/
|
||||
|
||||
for (curr = 1; curr < npts; curr++)
|
||||
{
|
||||
/* Find the next minimum-sized y-range. */
|
||||
|
||||
ybot = pts[curr-1]->p_y;
|
||||
while (ybot == pts[curr]->p_y)
|
||||
if (++curr >= npts) goto done;
|
||||
ytop = pts[curr]->p_y;
|
||||
|
||||
/* Process all the edges that cross the y-range, from left
|
||||
* to right.
|
||||
*/
|
||||
|
||||
for (wrapno=0, n=0; n < npts; n++)
|
||||
{
|
||||
if (wrapno == 0) xbot = edges[n]->cifp_x;
|
||||
if (!cifCross(edges[n], dir[n], ybot, ytop))
|
||||
continue;
|
||||
wrapno += dir[n] == REDGE ? 1 : -1;
|
||||
if (wrapno == 0)
|
||||
{
|
||||
xtop = edges[n]->cifp_point.p_x;
|
||||
if (xbot == xtop) continue;
|
||||
new = (LinkedRect *) mallocMagic(sizeof(LinkedRect));
|
||||
new->r_r.r_xbot = xbot;
|
||||
new->r_r.r_ybot = ybot;
|
||||
new->r_r.r_xtop = xtop;
|
||||
new->r_r.r_ytop = ytop;
|
||||
new->r_next = rex;
|
||||
rex = new;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Normally, the loop exits directly to done, below. It
|
||||
* only falls through here if the polygon has a degenerate
|
||||
* spike at its top (i.e. if there's only one point with
|
||||
* highest y-coordinate).
|
||||
*/
|
||||
|
||||
done:
|
||||
freeMagic((char *)edges);
|
||||
freeMagic((char *)dir);
|
||||
freeMagic((char *)pts);
|
||||
return (rex);
|
||||
}
|
||||
+765
@@ -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;
|
||||
}
|
||||
+1383
File diff suppressed because it is too large
Load Diff
+1664
File diff suppressed because it is too large
Load Diff
+201
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* CIFread.h --
|
||||
*
|
||||
* This file contains definitions used by the CIF reader, but not
|
||||
* by the CIF writing code. The definitions are only used internally
|
||||
* to this module.
|
||||
*
|
||||
* *********************************************************************
|
||||
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
||||
* * Permission to use, copy, modify, and distribute this *
|
||||
* * software and its documentation for any purpose and without *
|
||||
* * fee is hereby granted, provided that the above copyright *
|
||||
* * notice appear in all copies. The University of California *
|
||||
* * makes no representations about the suitability of this *
|
||||
* * software for any purpose. It is provided "as is" without *
|
||||
* * express or implied warranty. Export of this software outside *
|
||||
* * of the United States of America may require an export license. *
|
||||
* *********************************************************************
|
||||
*
|
||||
*
|
||||
* rcsid "$Header: /usr/cvsroot/magic-8.0/cif/CIFread.h,v 1.3 2010/08/25 17:33:55 tim Exp $
|
||||
*/
|
||||
|
||||
#ifndef _CIFREAD_H
|
||||
#define _CIFREAD_H
|
||||
|
||||
#include "cif/CIFint.h"
|
||||
|
||||
/* The structures below are built up by CIFreadtech.c to describe
|
||||
* various styles for reading CIF.
|
||||
*/
|
||||
|
||||
/* The following structure describes a sequence of geometric
|
||||
* operations used to produce information for a single Magic
|
||||
* layer. There may be several of these structures for the
|
||||
* same Magic layer; in that case, the results end up being
|
||||
* OR'ed together.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
TileType crl_magicType; /* Magic layer to paint results. */
|
||||
CIFOp *crl_ops; /* List of operations to generate
|
||||
* info for Magic layer.
|
||||
*/
|
||||
int crl_flags; /* Miscellaneous flags (see below). */
|
||||
} CIFReadLayer;
|
||||
|
||||
/* The CIFReadLayer flags are:
|
||||
*
|
||||
* CIFR_SIMPLE: Means this layer is a simple one, coming from only
|
||||
* a single OR operation, so it can be handled specially.
|
||||
* CIFR_TEMPLAYER: Means this layer is a temporary CIF layer, and that
|
||||
* the "crl_magicType" should be interpreted as a CIF layer.
|
||||
* CIFR_TEXTLABELS: Means this layer is used for text-only layers, not to
|
||||
* be moved or electrically connected to any other layer.
|
||||
*/
|
||||
|
||||
#define CIFR_SIMPLE 1
|
||||
#define CIFR_TEMPLAYER 2
|
||||
#define CIFR_TEXTLABELS 4
|
||||
|
||||
/* The following structure defines a complete CIF read-in style.
|
||||
* The constant MAXCIFRLAYERS must be less than TT_MAXTYPES, and
|
||||
* is used both as the largest number of distinct CIF layer names
|
||||
* in all read styles, and as the larges number of distinct "layer"
|
||||
* commands in any one read style.
|
||||
*/
|
||||
|
||||
#define MAXCIFRLAYERS (TT_MAXTYPES - 1)
|
||||
|
||||
/*
|
||||
* To avoid the large memory demands of maintaining all CIF styles in
|
||||
* memory, we keep only the style names and re-read the technology file
|
||||
* as necessary
|
||||
*/
|
||||
|
||||
typedef struct cifrkeep
|
||||
{
|
||||
struct cifrkeep *crs_next;
|
||||
char *crs_name;
|
||||
} CIFReadKeep;
|
||||
|
||||
typedef struct cifrstyle
|
||||
{
|
||||
char crs_status; /* Status: Loaded, not loaded, or pending. */
|
||||
char *crs_name; /* Name for this style of CIF input. */
|
||||
TileTypeBitMask crs_cifLayers;
|
||||
/* Mask of CIF layers understood in
|
||||
* this style.
|
||||
*/
|
||||
int crs_nLayers; /* Number of CIFReadLayers involved. */
|
||||
int crs_scaleFactor; /* Number of CIF units per Magic unit. */
|
||||
int crs_multiplier; /* crs_scaleFactor / crs_multiplier =
|
||||
* units in traditional centimicrons.
|
||||
* So if crs_multiplier = 10, CIF units
|
||||
* are in nanometers (millimicrons).
|
||||
*/
|
||||
int crs_gridLimit; /* Input is considered off-grid if on
|
||||
* a pitch less than crs_gridLimit CIF
|
||||
* units, and input will be snapped to
|
||||
* grid rather than scaling the grid
|
||||
* to accomodate the data. 0 = no limit.
|
||||
*/
|
||||
|
||||
TileType crs_labelLayer[MAXCIFRLAYERS];
|
||||
/* Gives the Magic layer to use for labels
|
||||
* on each possible CIF layer.
|
||||
*/
|
||||
CIFReadLayer *crs_layers[MAXCIFRLAYERS];
|
||||
HashTable cifCalmaToCif; /* Table mapping from Calma layer numbers to
|
||||
* CIF layers
|
||||
*/
|
||||
int crs_flags; /* Mask of boolean cif-reading options */
|
||||
} CIFReadStyle;
|
||||
|
||||
/* option bitmasks used in crs_flags */
|
||||
#define CRF_IGNORE_UNKNOWNLAYER_LABELS 1
|
||||
#define CRF_NO_RECONNECT_LABELS 2
|
||||
|
||||
/* Methods to deal with fractional results of conversion from CIF to magic */
|
||||
/* units (see routine CIFScaleCoord() for details). */
|
||||
|
||||
#define COORD_EXACT 0
|
||||
#define COORD_HALF_U 1
|
||||
#define COORD_HALF_L 2
|
||||
#define COORD_ANY 3
|
||||
|
||||
/* For parsing CIF, we need to keep track of paths (wire locations
|
||||
* or polygon boundaries. These are just linked lists of points.
|
||||
*/
|
||||
|
||||
#define CIF_ZERO 0
|
||||
#define CIF_LEFT 1
|
||||
#define CIF_UP 2
|
||||
#define CIF_RIGHT 3
|
||||
#define CIF_DOWN 4
|
||||
#define CIF_DIAG 5
|
||||
|
||||
/* Specific diagonal directions */
|
||||
#define CIF_DIAG_UL 5
|
||||
#define CIF_DIAG_UR 6
|
||||
#define CIF_DIAG_DL 7
|
||||
#define CIF_DIAG_DR 8
|
||||
|
||||
typedef struct cifpath
|
||||
{
|
||||
Point cifp_point; /* A point in the path. */
|
||||
struct cifpath *cifp_next; /* The next point in the path, or NULL. */
|
||||
} CIFPath;
|
||||
|
||||
#define cifp_x cifp_point.p_x
|
||||
#define cifp_y cifp_point.p_y
|
||||
|
||||
/* Procedures */
|
||||
|
||||
extern bool CIFParseBox(), CIFParseWire(), CIFParsePoly();
|
||||
extern bool CIFParseFlash(), CIFParseLayer(), CIFParseStart();
|
||||
extern bool CIFParseFinish(), CIFParseDelete(), CIFParseUser();
|
||||
extern bool CIFParseCall(), CIFParseTransform(), CIFParseInteger();
|
||||
extern bool CIFParsePath(), CIFParsePoint(), CIFParseSInteger();
|
||||
extern void CIFSkipToSemi(), CIFSkipSep(), CIFSkipBlanks();
|
||||
extern void CIFFreePath(), CIFCleanPath();
|
||||
extern void CIFReadCellInit(), CIFReadCellCleanup();
|
||||
extern LinkedRect *CIFPolyToRects();
|
||||
extern Transform *CIFDirectionToTrans();
|
||||
extern int CIFReadNameToType();
|
||||
|
||||
/* Variable argument procedures require complete prototype */
|
||||
|
||||
extern void CIFReadError(char *format, ...);
|
||||
extern void CIFReadWarning(char *format, ...);
|
||||
|
||||
/* Variables shared by the CIF-reading modules, see CIFreadutils.c
|
||||
* for more details:
|
||||
*/
|
||||
|
||||
extern int cifReadScale1, cifReadScale2;
|
||||
extern int cifNReadLayers;
|
||||
extern Plane *cifReadPlane;
|
||||
extern Plane **cifCurReadPlanes;
|
||||
extern TileType cifCurLabelType;
|
||||
extern CIFReadStyle *cifCurReadStyle;
|
||||
extern bool cifSubcellBeingRead;
|
||||
extern CellDef *cifReadCellDef;
|
||||
extern FILE *cifInputFile;
|
||||
extern bool cifParseLaAvail;
|
||||
extern int cifParseLaChar;
|
||||
|
||||
/* Macros to read characters, with one-character look-ahead. */
|
||||
|
||||
#define PEEK() ( cifParseLaAvail \
|
||||
? cifParseLaChar \
|
||||
: (cifParseLaAvail = TRUE, \
|
||||
cifParseLaChar = getc(cifInputFile)))
|
||||
|
||||
#define TAKE() ( cifParseLaAvail \
|
||||
? (cifParseLaAvail = FALSE, cifParseLaChar) \
|
||||
: (cifParseLaChar = getc(cifInputFile)))
|
||||
|
||||
#endif /* _CIFREAD_H */
|
||||
+490
@@ -0,0 +1,490 @@
|
||||
/* CIFsee.c -
|
||||
*
|
||||
* This file provides procedures for displaying CIF layers on
|
||||
* the screen using the highlight facilities.
|
||||
*
|
||||
* *********************************************************************
|
||||
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
||||
* * Permission to use, copy, modify, and distribute this *
|
||||
* * software and its documentation for any purpose and without *
|
||||
* * fee is hereby granted, provided that the above copyright *
|
||||
* * notice appear in all copies. The University of California *
|
||||
* * makes no representations about the suitability of this *
|
||||
* * software for any purpose. It is provided "as is" without *
|
||||
* * express or implied warranty. Export of this software outside *
|
||||
* * of the United States of America may require an export license. *
|
||||
* *********************************************************************
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFsee.c,v 1.5 2010/06/24 12:37:15 tim Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "utils/magic.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "tiles/tile.h"
|
||||
#include "utils/hash.h"
|
||||
#include "database/database.h"
|
||||
#include "windows/windows.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "dbwind/dbwind.h"
|
||||
#include "utils/styles.h"
|
||||
#include "cif/CIFint.h"
|
||||
#include "textio/textio.h"
|
||||
#include "utils/undo.h"
|
||||
|
||||
/* The following variable holds the CellDef into which feedback
|
||||
* is to be placed for displaying CIF.
|
||||
*/
|
||||
|
||||
static CellDef *cifSeeDef;
|
||||
|
||||
/* Verbosity of warning messages */
|
||||
global int CIFWarningLevel = CIF_WARN_DEFAULT;
|
||||
|
||||
typedef struct {
|
||||
CellDef *paintDef;
|
||||
int layer;
|
||||
} PaintLayerData;
|
||||
|
||||
typedef struct {
|
||||
char *text;
|
||||
int layer;
|
||||
int style;
|
||||
} SeeLayerData;
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifPaintDBFunc --
|
||||
*
|
||||
* This routine paints CIF back into the database at the inverse
|
||||
* scale at which it was generated. Otherwise, it is very much like
|
||||
* cifPaintCurrentFunc() in CIFrdcl.c.
|
||||
*
|
||||
* Results:
|
||||
* Always returns 0 to keep the search alive.
|
||||
*
|
||||
* Side effects:
|
||||
* Paint is generated in the cell.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifPaintDBFunc(tile, pld)
|
||||
Tile *tile; /* Tile of CIF information. */
|
||||
PaintLayerData *pld;
|
||||
{
|
||||
Rect area;
|
||||
int pNum;
|
||||
TileType type = pld->layer; /* Magic type to be painted. */
|
||||
CellDef *paintDef = pld->paintDef; /* Cell to draw into. */
|
||||
int cifScale = CIFCurStyle->cs_scaleFactor;
|
||||
PaintUndoInfo ui;
|
||||
|
||||
/* Compute the area of the CIF tile, then scale it into
|
||||
* Magic coordinates.
|
||||
*/
|
||||
|
||||
TiToRect(tile, &area);
|
||||
area.r_xtop /= cifScale;
|
||||
area.r_xbot /= cifScale;
|
||||
area.r_ytop /= cifScale;
|
||||
area.r_ybot /= cifScale;
|
||||
|
||||
/* Check for degenerate areas (from rescale limiting) before painting */
|
||||
if ((area.r_xbot == area.r_xtop) || (area.r_ybot == area.r_ytop))
|
||||
return 0;
|
||||
|
||||
ui.pu_def = paintDef;
|
||||
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
|
||||
if (DBPaintOnPlane(type, pNum))
|
||||
{
|
||||
ui.pu_pNum = pNum;
|
||||
DBNMPaintPlane(paintDef->cd_planes[pNum], TiGetTypeExact(tile),
|
||||
&area, DBStdPaintTbl(type, pNum), (PaintUndoInfo *) &ui);
|
||||
}
|
||||
|
||||
return 0; /* To keep the search alive. */
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CIFPaintLayer --
|
||||
*
|
||||
* Generates CIF over a given area of a given cell, then
|
||||
* paints the CIF layer back into the cell (or optionally,
|
||||
* into a separate cell) as a magic layer.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Highlight information is drawn on the screen.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
CIFPaintLayer(rootDef, area, cifLayer, magicLayer, paintDef)
|
||||
CellDef *rootDef; /* Cell for which to generate CIF. Must be
|
||||
* the rootDef of a window.
|
||||
*/
|
||||
Rect *area; /* Area in which to generate CIF. */
|
||||
char *cifLayer; /* CIF layer to highlight on the screen. */
|
||||
int magicLayer; /* Magic layer to paint with the result */
|
||||
CellDef *paintDef; /* CellDef to paint into (may be NULL) */
|
||||
{
|
||||
int oldCount, i;
|
||||
char msg[100];
|
||||
SearchContext scx;
|
||||
PaintLayerData pld;
|
||||
TileTypeBitMask mask, depend;
|
||||
|
||||
/* Make sure the desired layer exists. */
|
||||
|
||||
if (!CIFNameToMask(cifLayer, &mask, &depend)) return;
|
||||
|
||||
/* Paint directly into the root cellDef if passed a NULL paintDef*/
|
||||
pld.paintDef = (paintDef == NULL) ? rootDef : paintDef;
|
||||
pld.layer = magicLayer;
|
||||
|
||||
/* Flatten the area and generate CIF for it. */
|
||||
|
||||
CIFErrorDef = rootDef;
|
||||
CIFInitCells();
|
||||
UndoDisable();
|
||||
CIFDummyUse->cu_def = rootDef;
|
||||
GEO_EXPAND(area, CIFCurStyle->cs_radius, &scx.scx_area);
|
||||
scx.scx_use = CIFDummyUse;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
oldCount = DBWFeedbackCount;
|
||||
CIFGen(CIFComponentDef, area, CIFPlanes, &depend, TRUE, TRUE);
|
||||
DBCellClearDef(CIFComponentDef);
|
||||
|
||||
/* Report any errors that occurred. */
|
||||
|
||||
if (DBWFeedbackCount != oldCount)
|
||||
{
|
||||
TxPrintf("%d problems occurred. See feedback entries.\n",
|
||||
DBWFeedbackCount-oldCount);
|
||||
}
|
||||
|
||||
/* Paint back the chosen layer. */
|
||||
|
||||
UndoEnable();
|
||||
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
|
||||
if (TTMaskHasType(&mask, i))
|
||||
DBSrPaintArea((Tile *)NULL, CIFPlanes[i], &TiPlaneRect,
|
||||
&CIFSolidBits, cifPaintDBFunc, (ClientData)&pld);
|
||||
|
||||
DBWAreaChanged(rootDef, area, DBW_ALLWINDOWS, &mask);
|
||||
DBReComputeBbox(rootDef);
|
||||
DRCCheckThis(rootDef, TT_CHECKPAINT, area);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifSeeFunc --
|
||||
*
|
||||
* Called once for each tile that is to be displayed as feedback.
|
||||
* This procedure enters the tile as feedback. Note: the caller
|
||||
* must arrange for cifSeeDef to contain a pointer to the cell
|
||||
* def where feedback is to be displayed.
|
||||
*
|
||||
* Results:
|
||||
* Always returns 0 to keep the search alive.
|
||||
*
|
||||
* Side effects:
|
||||
* A new feedback area is created over the tile. The parameter
|
||||
* "text" is associated with the feedback.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifSeeFunc(tile, sld)
|
||||
Tile *tile; /* Tile to be entered as feedback. */
|
||||
SeeLayerData *sld; /* Layer and explanation for the feedback. */
|
||||
{
|
||||
Rect area;
|
||||
|
||||
TiToRect(tile, &area);
|
||||
|
||||
if (((area.r_xbot & 0x1) || (area.r_ybot & 0x1))
|
||||
&& (CIFWarningLevel == CIF_WARN_ALIGN))
|
||||
{
|
||||
TxError("Warning: Corner (%.1f, %.1f) has half-lambda placement.\n",
|
||||
(float)area.r_xbot / (float)CIFCurStyle->cs_scaleFactor,
|
||||
(float)area.r_ybot / (float)CIFCurStyle->cs_scaleFactor);
|
||||
}
|
||||
|
||||
DBWFeedbackAdd(&area, sld->text, cifSeeDef, CIFCurStyle->cs_scaleFactor,
|
||||
sld->style |
|
||||
(TiGetTypeExact(tile) & (TT_DIAGONAL | TT_DIRECTION | TT_SIDE)));
|
||||
/* (preserve information about the geometry of a diagonal tile) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CIFSeeLayer --
|
||||
*
|
||||
* Generates CIF over a given area of a given cell, then
|
||||
* highlights a particular CIF layer on the screen.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Highlight information is drawn on the screen.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
CIFSeeLayer(rootDef, area, layer)
|
||||
CellDef *rootDef; /* Cell for which to generate CIF. Must be
|
||||
* the rootDef of a window.
|
||||
*/
|
||||
Rect *area; /* Area in which to generate CIF. */
|
||||
char *layer; /* CIF layer to highlight on the screen. */
|
||||
{
|
||||
int oldCount, i;
|
||||
char msg[100];
|
||||
SearchContext scx;
|
||||
SeeLayerData sld;
|
||||
TileTypeBitMask mask, depend;
|
||||
|
||||
/* Make sure the desired layer exists. */
|
||||
|
||||
if (!CIFNameToMask(layer, &mask, &depend)) return;
|
||||
|
||||
/* Flatten the area and generate CIF for it. */
|
||||
|
||||
CIFErrorDef = rootDef;
|
||||
CIFInitCells();
|
||||
UndoDisable();
|
||||
CIFDummyUse->cu_def = rootDef;
|
||||
GEO_EXPAND(area, CIFCurStyle->cs_radius, &scx.scx_area);
|
||||
scx.scx_use = CIFDummyUse;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
oldCount = DBWFeedbackCount;
|
||||
CIFGen(CIFComponentDef, area, CIFPlanes, &depend, TRUE, TRUE);
|
||||
DBCellClearDef(CIFComponentDef);
|
||||
|
||||
/* Report any errors that occurred. */
|
||||
|
||||
if (DBWFeedbackCount != oldCount)
|
||||
{
|
||||
TxPrintf("%d problems occurred. See feedback entries.\n",
|
||||
DBWFeedbackCount-oldCount);
|
||||
}
|
||||
|
||||
/* Display the chosen layer. */
|
||||
|
||||
(void) sprintf(msg, "CIF layer \"%s\"", layer);
|
||||
cifSeeDef = rootDef;
|
||||
sld.text = msg;
|
||||
|
||||
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
|
||||
{
|
||||
if (TTMaskHasType(&mask, i))
|
||||
{
|
||||
sld.layer = i;
|
||||
#ifdef THREE_D
|
||||
sld.style = CIFCurStyle->cs_layers[i]->cl_renderStyle
|
||||
+ TECHBEGINSTYLES;
|
||||
#else
|
||||
sld.style = STYLE_PALEHIGHLIGHTS;
|
||||
#endif
|
||||
DBSrPaintArea((Tile *)NULL, CIFPlanes[i], &TiPlaneRect,
|
||||
&CIFSolidBits, cifSeeFunc, (ClientData)&sld);
|
||||
}
|
||||
}
|
||||
UndoEnable();
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CIFSeeHierLayer --
|
||||
*
|
||||
* This procedure is similar to CIFSeeLayer except that it only
|
||||
* generates hierarchical interaction information.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* CIF information is highlighed on the screen. If arrays is
|
||||
* TRUE, then CIF that stems from array interactions is displayed.
|
||||
* if subcells is TRUE, then CIF stemming from subcell interactions
|
||||
* is displayed. If both are TRUE, then both are displayed.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
CIFSeeHierLayer(rootDef, area, layer, arrays, subcells)
|
||||
CellDef *rootDef; /* Def in which to compute CIF. Must be
|
||||
* the root definition of a window.
|
||||
*/
|
||||
Rect *area; /* Area in which to generate CIF. */
|
||||
char *layer; /* CIF layer to be highlighted. */
|
||||
bool arrays; /* TRUE means show array interactions. */
|
||||
bool subcells; /* TRUE means show subcell interactions. */
|
||||
{
|
||||
int i, oldCount;
|
||||
SeeLayerData sld;
|
||||
char msg[100];
|
||||
TileTypeBitMask mask;
|
||||
|
||||
/* Check out the CIF layer name. */
|
||||
|
||||
if (!CIFNameToMask(layer, &mask, NULL)) return;
|
||||
|
||||
CIFErrorDef = rootDef;
|
||||
oldCount = DBWFeedbackCount;
|
||||
CIFClearPlanes(CIFPlanes);
|
||||
if (subcells)
|
||||
CIFGenSubcells(rootDef, area, CIFPlanes);
|
||||
if (arrays)
|
||||
CIFGenArrays(rootDef, area, CIFPlanes);
|
||||
|
||||
/* Report any errors that occurred. */
|
||||
|
||||
if (DBWFeedbackCount != oldCount)
|
||||
{
|
||||
TxPrintf("%d problems occurred. See feedback entries.\n",
|
||||
DBWFeedbackCount - oldCount);
|
||||
}
|
||||
|
||||
(void) sprintf(msg, "CIF layer \"%s\"", layer);
|
||||
cifSeeDef = rootDef;
|
||||
sld.text = msg;
|
||||
|
||||
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
|
||||
{
|
||||
if (TTMaskHasType(&mask, i))
|
||||
{
|
||||
sld.layer = i;
|
||||
#ifdef THREE_D
|
||||
sld.style = CIFCurStyle->cs_layers[i]->cl_renderStyle
|
||||
+ TECHBEGINSTYLES;
|
||||
#else
|
||||
sld.style = STYLE_PALEHIGHLIGHTS;
|
||||
#endif
|
||||
DBSrPaintArea((Tile *)NULL, CIFPlanes[i], &TiPlaneRect,
|
||||
&CIFSolidBits, cifSeeFunc, (ClientData)&sld);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CIFCoverageLayer --
|
||||
*
|
||||
* This procedure reports the total area coverage of a CIF layer
|
||||
* within the bounding box of the root CellDef.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Prints results.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
long long coverage;
|
||||
Rect bounds;
|
||||
} coverstats;
|
||||
|
||||
void
|
||||
CIFCoverageLayer(rootDef, area, layer)
|
||||
CellDef *rootDef; /* Def in which to compute CIF coverage */
|
||||
Rect *area; /* Area in which to compute coverage */
|
||||
char *layer; /* CIF layer for coverage computation. */
|
||||
{
|
||||
coverstats cstats;
|
||||
int i, scale;
|
||||
long long atotal, btotal;
|
||||
SearchContext scx;
|
||||
TileTypeBitMask mask, depend;
|
||||
float fcover;
|
||||
int cifCoverageFunc();
|
||||
bool doBox = (area != &rootDef->cd_bbox) ? TRUE : FALSE;
|
||||
|
||||
/* Check out the CIF layer name. */
|
||||
|
||||
if (!CIFNameToMask(layer, &mask, &depend)) return;
|
||||
|
||||
CIFErrorDef = rootDef;
|
||||
CIFInitCells();
|
||||
UndoDisable();
|
||||
CIFDummyUse->cu_def = rootDef;
|
||||
|
||||
GEO_EXPAND(area, CIFCurStyle->cs_radius, &scx.scx_area);
|
||||
|
||||
scx.scx_use = CIFDummyUse;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
CIFGen(CIFComponentDef, area, CIFPlanes, &depend, TRUE, TRUE);
|
||||
DBCellClearDef(CIFComponentDef);
|
||||
|
||||
cstats.coverage = 0;
|
||||
cstats.bounds.r_xbot = cstats.bounds.r_xtop = 0;
|
||||
cstats.bounds.r_ybot = cstats.bounds.r_ytop = 0;
|
||||
|
||||
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
|
||||
if (TTMaskHasType(&mask, i))
|
||||
DBSrPaintArea((Tile *)NULL, CIFPlanes[i], &TiPlaneRect,
|
||||
&CIFSolidBits, cifCoverageFunc,
|
||||
(ClientData) &cstats);
|
||||
|
||||
/* Print results */
|
||||
|
||||
scale = CIFCurStyle->cs_scaleFactor;
|
||||
|
||||
btotal = (long long)(area->r_xtop - area->r_xbot);
|
||||
btotal *= (long long)(area->r_ytop - area->r_ybot);
|
||||
btotal *= (long long)(scale * scale);
|
||||
fcover = 0.0;
|
||||
if (btotal > 0.0) fcover = (float)cstats.coverage / (float)btotal;
|
||||
|
||||
atotal = (long long)(cstats.bounds.r_xtop - cstats.bounds.r_xbot);
|
||||
atotal *= (long long)(cstats.bounds.r_ytop - cstats.bounds.r_ybot);
|
||||
|
||||
TxPrintf("%s Area = %lld CIF units^2\n", doBox ? "Cursor Box" :
|
||||
"Cell", btotal);
|
||||
TxPrintf("Layer Bounding Area = %lld CIF units^2\n", atotal);
|
||||
TxPrintf("Layer Total Area = %lld CIF units^2\n", cstats.coverage);
|
||||
TxPrintf("Coverage in %s = %1.1f%%\n", doBox ? "box" :
|
||||
"cell", 100.0 * fcover);
|
||||
}
|
||||
|
||||
int
|
||||
cifCoverageFunc(tile, arg)
|
||||
Tile *tile;
|
||||
ClientData *arg;
|
||||
{
|
||||
coverstats *cstats = (coverstats *)arg;
|
||||
Rect r;
|
||||
|
||||
TiToRect(tile, &r);
|
||||
cstats->coverage += (long long)((r.r_xtop - r.r_xbot) * (r.r_ytop - r.r_ybot));
|
||||
GeoInclude(&r, &cstats->bounds);
|
||||
|
||||
return(0);
|
||||
}
|
||||
+2308
File diff suppressed because it is too large
Load Diff
+711
@@ -0,0 +1,711 @@
|
||||
/*
|
||||
* CIFwrite.c --
|
||||
*
|
||||
* Output of CIF.
|
||||
*
|
||||
* *********************************************************************
|
||||
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
||||
* * Permission to use, copy, modify, and distribute this *
|
||||
* * software and its documentation for any purpose and without *
|
||||
* * fee is hereby granted, provided that the above copyright *
|
||||
* * notice appear in all copies. The University of California *
|
||||
* * makes no representations about the suitability of this *
|
||||
* * software for any purpose. It is provided "as is" without *
|
||||
* * express or implied warranty. Export of this software outside *
|
||||
* * of the United States of America may require an export license. *
|
||||
* *********************************************************************
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFwrite.c,v 1.2 2010/06/24 12:37:15 tim Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "utils/magic.h"
|
||||
#include "utils/geometry.h"
|
||||
#include "tiles/tile.h"
|
||||
#include "utils/utils.h"
|
||||
#include "utils/hash.h"
|
||||
#include "database/database.h"
|
||||
#include "database/databaseInt.h"
|
||||
#include "utils/tech.h"
|
||||
#include "utils/stack.h"
|
||||
#include "utils/undo.h"
|
||||
#include "cif/cif.h"
|
||||
#include "cif/CIFint.h"
|
||||
#include "utils/signals.h"
|
||||
#include "windows/windows.h"
|
||||
#include "dbwind/dbwind.h"
|
||||
#include "utils/styles.h"
|
||||
#include "textio/textio.h"
|
||||
|
||||
/* Forward declarations */
|
||||
extern int cifWriteInitFunc();
|
||||
extern int cifWriteMarkFunc();
|
||||
extern int cifWritePaintFunc();
|
||||
extern int cifWriteUseFunc();
|
||||
extern void cifOutPreamble();
|
||||
extern void cifOut();
|
||||
extern void cifOutFunc();
|
||||
extern int GrClipTriangle();
|
||||
|
||||
/* Current cell number in CIF numbering scheme */
|
||||
|
||||
static int cifCellNum;
|
||||
|
||||
/* Stack of definitions left to process for generating CIF */
|
||||
|
||||
Stack *cifStack;
|
||||
|
||||
/* Scale factor for outputting paint: */
|
||||
|
||||
int cifPaintScale;
|
||||
|
||||
/* Current layer name. If non-NULL, then cifWritePaintFunc outputs
|
||||
* this string to the file before outputting a rectangle, then nulls.
|
||||
* This way, the layer name only gets output when there's actually
|
||||
* stuff on that layer.
|
||||
*/
|
||||
|
||||
char *cifPaintLayerName;
|
||||
|
||||
/* TRUE if area labels should be output */
|
||||
bool CIFDoAreaLabels = FALSE;
|
||||
|
||||
/* TRUE if cell ids should be output */
|
||||
bool CIFDoCellIdLabels = TRUE;
|
||||
|
||||
/* prefix string for pathnames */
|
||||
char *CIFPathPrefix = NULL;
|
||||
|
||||
/* These are normally FALSE---enable at your own risk! */
|
||||
bool CIFHierWriteDisable = FALSE;
|
||||
bool CIFArrayWriteDisable = FALSE;
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CIFWrite --
|
||||
*
|
||||
* Write out the entire tree rooted at the supplied CellDef in CIF format,
|
||||
* to the specified file.
|
||||
*
|
||||
* Results:
|
||||
* TRUE if the cell could be written successfully, FALSE otherwise.
|
||||
*
|
||||
* Side effects:
|
||||
* Writes a file to disk.
|
||||
* In the event of an error while writing out the cell,
|
||||
* the external integer errno is set to the UNIX error
|
||||
* encountered.
|
||||
*
|
||||
* Algorithm:
|
||||
* We make a depth-first traversal of the entire design tree,
|
||||
* marking each cell with a CIF symbol number and then outputting
|
||||
* it to the CIF file. If a given cell is not read in when we
|
||||
* visit it, we read it in.
|
||||
*
|
||||
* No hierarchical design rule checking or bounding box computation
|
||||
* occur during this traversal -- both are explicitly avoided.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bool
|
||||
CIFWrite(rootDef, f)
|
||||
CellDef *rootDef; /* Pointer to CellDef to be written */
|
||||
FILE *f; /* Open output file */
|
||||
{
|
||||
bool good;
|
||||
int oldCount = DBWFeedbackCount;
|
||||
CellUse dummy;
|
||||
|
||||
/*
|
||||
* Make sure that the entire hierarchy rooted at rootDef is
|
||||
* read into memory and that timestamp mismatches are resolved
|
||||
* (this is needed so that we know that bounding boxes are OK).
|
||||
*/
|
||||
|
||||
dummy.cu_def = rootDef;
|
||||
DBCellReadArea(&dummy, &rootDef->cd_bbox);
|
||||
DBFixMismatch();
|
||||
|
||||
if (CIFCurStyle->cs_reducer == 0)
|
||||
{
|
||||
TxError("The current CIF output style can only be used for writing\n");
|
||||
TxError("Calma output. Try picking another output style.\n");
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Go through all cells currently having CellDefs in the
|
||||
* def symbol table and mark them with negative symbol numbers.
|
||||
*/
|
||||
(void) DBCellSrDefs(0, cifWriteInitFunc, (ClientData) NULL);
|
||||
cifCellNum = (-2);
|
||||
rootDef->cd_client = (ClientData) -1;
|
||||
|
||||
/*
|
||||
* Start by pushing the root def on the stack of cell defs
|
||||
* to be processed.
|
||||
*/
|
||||
cifStack = StackNew(100);
|
||||
StackPush((ClientData) rootDef, cifStack);
|
||||
cifOutPreamble(f, rootDef);
|
||||
cifOut(f);
|
||||
StackFree(cifStack);
|
||||
if ((int) rootDef->cd_client < 0)
|
||||
rootDef->cd_client = (ClientData) (- (int) rootDef->cd_client);
|
||||
|
||||
/* See if any problems occurred. */
|
||||
|
||||
if (DBWFeedbackCount != oldCount)
|
||||
{
|
||||
TxPrintf("%d problems occurred. See feedback entries.\n",
|
||||
DBWFeedbackCount - oldCount);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we are almost done.
|
||||
* Just output a call on the root cell
|
||||
*/
|
||||
fprintf(f, "C %d;\nEnd\n", (int) rootDef->cd_client);
|
||||
good = !ferror(f);
|
||||
return (good);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifWriteInitFunc --
|
||||
*
|
||||
* Filter function called on behalf of CIFWrite() above.
|
||||
* Responsible for setting the cif number of each cell to zero.
|
||||
*
|
||||
* Results:
|
||||
* Returns 0 to indicate that the search should continue.
|
||||
*
|
||||
* Side effects:
|
||||
* Modify the cif numbers of the cells they are passed.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifWriteInitFunc(def)
|
||||
CellDef *def;
|
||||
{
|
||||
def->cd_client = (ClientData) 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifWriteMarkFunc --
|
||||
*
|
||||
* Called to add each cell def in the subcell plane of a parent
|
||||
* to the stack of cells to be processed.
|
||||
*
|
||||
* Results:
|
||||
* Returns 0 to indicate that DBCellEnum() should continue.
|
||||
*
|
||||
* Side effects:
|
||||
* Pushes the cell def on the stack.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifWriteMarkFunc(use)
|
||||
CellUse *use;
|
||||
{
|
||||
if (use->cu_def->cd_client != (ClientData) 0) return 0;
|
||||
use->cu_def->cd_client = (ClientData) cifCellNum;
|
||||
cifCellNum -= 1;
|
||||
StackPush((ClientData) use->cu_def, cifStack);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifOutPreamble --
|
||||
*
|
||||
* Write preamble in front of a CIF file for version control.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Preamble in CIF comment style - () are send to output file.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
cifOutPreamble(outf, cell)
|
||||
FILE *outf;
|
||||
CellDef *cell;
|
||||
{
|
||||
extern char *MagicVersion;
|
||||
extern char *MagicCompileTime;
|
||||
char *now, *t;
|
||||
struct tm *clock;
|
||||
time_t t_stamp = time((time_t *) NULL);
|
||||
|
||||
clock = localtime(&t_stamp);
|
||||
now = ctime(&t_stamp);
|
||||
/* remove the '\n' at the end of the string... */
|
||||
now[strlen(now)-1] = '\0';
|
||||
|
||||
fprintf(outf,"( @@user : %s );\n", (t = getenv("USER")) ? t : "?");
|
||||
fprintf(outf,"( @@machine : %s );\n", (t = getenv("HOSTNAME")) ? t : "?");
|
||||
fprintf(outf,"( @@source : %s );\n",(cell->cd_file) ? cell->cd_file : "?");
|
||||
fprintf(outf,"( @@tool : Magic %s.%s );\n", MagicVersion, MagicRevision);
|
||||
fprintf(outf,"( @@compiled : %s );\n", MagicCompileTime);
|
||||
fprintf(outf,"( @@technology : %s );\n", DBTechName);
|
||||
if (DBTechVersion)
|
||||
fprintf(outf,"( @@version : %s );\n", DBTechVersion);
|
||||
else
|
||||
fprintf(outf,"( @@version : unknown );\n");
|
||||
if (DBTechDescription)
|
||||
fprintf(outf,"( @@techdesc : %s );\n", DBTechDescription);
|
||||
fprintf(outf,"( @@style : %s );\n", CIFCurStyle->cs_name);
|
||||
fprintf(outf,"( @@date : %s );\n", now);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifOut --
|
||||
*
|
||||
* Main loop of CIF generation. Pull a cell def from the stack
|
||||
* and process it.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Causes CIF to be output.
|
||||
* Returns when the stack is empty.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
cifOut(outf)
|
||||
FILE *outf;
|
||||
{
|
||||
CellDef *def;
|
||||
|
||||
while (!StackEmpty(cifStack))
|
||||
{
|
||||
def = (CellDef *) StackPop(cifStack);
|
||||
if ((int) def->cd_client >= 0) continue; /* Already output */
|
||||
if (SigInterruptPending) continue;
|
||||
|
||||
def->cd_client = (ClientData) (- (int) def->cd_client);
|
||||
|
||||
/* Read the cell in if it is not already available. */
|
||||
if ((def->cd_flags & CDAVAILABLE) == 0)
|
||||
{
|
||||
if (!DBCellRead(def, (char *) NULL, TRUE, NULL)) continue;
|
||||
}
|
||||
|
||||
/* Add any subcells to the stack. This must be done before
|
||||
* outputting CIF to make sure that the subcells all have
|
||||
* CIF numbers.
|
||||
*/
|
||||
|
||||
(void) DBCellEnum(def, cifWriteMarkFunc, (ClientData) 0);
|
||||
|
||||
/* Output CIF for this cell */
|
||||
|
||||
cifOutFunc(def, outf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifOutFunc --
|
||||
*
|
||||
* Write out the definition for a single cell as CIF.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Appends to the open CIF output file.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
cifOutFunc(def, f)
|
||||
CellDef *def; /* Pointer to cell def to be written */
|
||||
FILE *f; /* Open output file */
|
||||
{
|
||||
Rect bigArea;
|
||||
Label *lab;
|
||||
int type;
|
||||
CIFLayer *layer;
|
||||
|
||||
fprintf(f, "DS %d %d %d;\n", (int) def->cd_client,
|
||||
CIFCurStyle->cs_reducer, 2 * CIFCurStyle->cs_expander);
|
||||
|
||||
if (def->cd_name != (char *) NULL)
|
||||
if (def->cd_name[0] != '\0')
|
||||
{
|
||||
if (strcmp(def->cd_name, "(UNNAMED)") == 0)
|
||||
fprintf(f, "9 UNNAMED;\n");
|
||||
else {
|
||||
if (CIFPathPrefix && CIFPathPrefix[0])
|
||||
fprintf(f, "9 %s/%s;\n", CIFPathPrefix, def->cd_name);
|
||||
else
|
||||
fprintf(f, "9 %s;\n", def->cd_name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Output all the tiles associated with this cell. Skip temporary
|
||||
* layers.
|
||||
*/
|
||||
|
||||
GEO_EXPAND(&def->cd_bbox, CIFCurStyle->cs_radius, &bigArea);
|
||||
CIFErrorDef = def;
|
||||
CIFGen(def, &bigArea, CIFPlanes, &DBAllTypeBits, TRUE, TRUE);
|
||||
if (!CIFHierWriteDisable)
|
||||
CIFGenSubcells(def, &bigArea, CIFPlanes);
|
||||
if (!CIFArrayWriteDisable)
|
||||
CIFGenArrays(def, &bigArea, CIFPlanes);
|
||||
for (type = 0; type < CIFCurStyle->cs_nLayers; type++)
|
||||
{
|
||||
layer = CIFCurStyle->cs_layers[type];
|
||||
if (layer->cl_flags & CIF_TEMP) continue;
|
||||
cifPaintLayerName = layer->cl_name;
|
||||
cifPaintScale = 1;
|
||||
(void) DBSrPaintArea((Tile *) NULL, CIFPlanes[type],
|
||||
&TiPlaneRect, &CIFSolidBits, cifWritePaintFunc,
|
||||
(ClientData) f);
|
||||
}
|
||||
|
||||
/* Output labels */
|
||||
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
||||
{
|
||||
int type = CIFCurStyle->cs_labelLayer[lab->lab_type];
|
||||
Point center, size;
|
||||
|
||||
center.p_x = lab->lab_rect.r_xbot + lab->lab_rect.r_xtop;
|
||||
center.p_y = lab->lab_rect.r_ybot + lab->lab_rect.r_ytop;
|
||||
center.p_x *= CIFCurStyle->cs_scaleFactor;
|
||||
center.p_x /= CIFCurStyle->cs_reducer;
|
||||
center.p_y *= CIFCurStyle->cs_scaleFactor;
|
||||
center.p_y /= CIFCurStyle->cs_reducer;
|
||||
|
||||
if (CIFDoAreaLabels)
|
||||
{
|
||||
size.p_x = lab->lab_rect.r_xtop - lab->lab_rect.r_xbot;
|
||||
size.p_y = lab->lab_rect.r_ytop - lab->lab_rect.r_ybot;
|
||||
size.p_x *= 2 * CIFCurStyle->cs_scaleFactor;
|
||||
size.p_x /= CIFCurStyle->cs_reducer;
|
||||
size.p_y *= 2 * CIFCurStyle->cs_scaleFactor;
|
||||
size.p_y /= CIFCurStyle->cs_reducer;
|
||||
if (type >= 0)
|
||||
{
|
||||
fprintf(f, "95 %s %d %d %d %d %s;\n",
|
||||
lab->lab_text, size.p_x, size.p_y, center.p_x, center.p_y,
|
||||
CIFCurStyle->cs_layers[type]->cl_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(f, "95 %s %d %d %d %d;\n",
|
||||
lab->lab_text, size.p_x, size.p_y, center.p_x, center.p_y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type >= 0)
|
||||
{
|
||||
fprintf(f, "94 %s %d %d %s;\n",
|
||||
lab->lab_text, center.p_x, center.p_y,
|
||||
CIFCurStyle->cs_layers[type]->cl_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(f, "94 %s %d %d;\n",
|
||||
lab->lab_text, center.p_x, center.p_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Output the calls that the child makes to its children. For
|
||||
* arrays it is necessary to output one call for each instance.
|
||||
*/
|
||||
(void) DBCellEnum(def, cifWriteUseFunc, (ClientData) f);
|
||||
fprintf(f, "DF;\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifWriteUseFunc --
|
||||
*
|
||||
* Filter function, called by DBCellEnum on behalf of cifOutFunc above,
|
||||
* to write out each CellUse called by the CellDef being output.
|
||||
*
|
||||
* Results:
|
||||
* Always return 0
|
||||
*
|
||||
* Side effects:
|
||||
* Appends to the open CIF output file.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifWriteUseFunc(use, f)
|
||||
CellUse *use;
|
||||
FILE *f;
|
||||
{
|
||||
int x, y, topx, topy;
|
||||
int realx, realy;
|
||||
Transform *t;
|
||||
int cifnum;
|
||||
|
||||
cifnum = (int) use->cu_def->cd_client;
|
||||
if (cifnum < 0) cifnum = (-cifnum);
|
||||
topx = use->cu_xhi - use->cu_xlo;
|
||||
if (topx < 0) topx = -topx;
|
||||
topy = use->cu_yhi - use->cu_ylo;
|
||||
if (topy < 0) topy = -topy;
|
||||
realx = use->cu_xlo;
|
||||
for (x = 0; x <= topx; x++)
|
||||
{
|
||||
realy = use->cu_ylo;
|
||||
for (y = 0; y <= topy; y++)
|
||||
{
|
||||
/*
|
||||
* We eventually want to tag each use with its unique
|
||||
* use identifier, which should include array subscripting
|
||||
* information.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Insert a 91 user command to label the next cell
|
||||
*/
|
||||
if (CIFDoCellIdLabels && use->cu_id && use->cu_id[0]) {
|
||||
fprintf (f, "91 %s", use->cu_id);
|
||||
if (topx > 0 || topy > 0) {
|
||||
if (topx > 0 && topy > 0)
|
||||
fprintf (f, "(%d,%d)", realy, realx);
|
||||
else {
|
||||
if (topx > 0)
|
||||
fprintf (f, "(%d)", realx);
|
||||
else
|
||||
fprintf (f, "(%d)", realy);
|
||||
}
|
||||
}
|
||||
fprintf (f, ";\n");
|
||||
}
|
||||
fprintf(f, "C %d", cifnum);
|
||||
|
||||
/*
|
||||
* The following translates from the abcdef transforms
|
||||
* that we use internally to the rotate and mirror
|
||||
* specs used in CIF. It only works because
|
||||
* orientations are orthogonal in magic. Check all
|
||||
* 8 possible positions if you don't believe this.
|
||||
*/
|
||||
|
||||
t = &use->cu_transform;
|
||||
if ((t->t_a != t->t_e) || ((t->t_a == 0) && (t->t_b == t->t_d)))
|
||||
fprintf(f, " MX R %d %d", -(t->t_a), -(t->t_d));
|
||||
else
|
||||
fprintf(f, " R %d %d", t->t_a, t->t_d);
|
||||
|
||||
fprintf(f, " T %d %d;\n",
|
||||
((t->t_c + t->t_a*(use->cu_xsep)*x + t->t_b*(use->cu_ysep)*y)
|
||||
* 2 * CIFCurStyle->cs_scaleFactor) / CIFCurStyle->cs_reducer,
|
||||
((t->t_f + t->t_d*(use->cu_xsep)*x + t->t_e*(use->cu_ysep)*y)
|
||||
* 2 * CIFCurStyle->cs_scaleFactor) / CIFCurStyle->cs_reducer);
|
||||
|
||||
if (use->cu_yhi > use->cu_ylo)
|
||||
realy++;
|
||||
else
|
||||
realy--;
|
||||
}
|
||||
if (use->cu_xhi > use->cu_xlo)
|
||||
realx++;
|
||||
else
|
||||
realx--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* cifWritePaintFunc --
|
||||
*
|
||||
* Filter function used to write out a single paint tile.
|
||||
*
|
||||
* Results:
|
||||
* Always return 0
|
||||
*
|
||||
* Side effects:
|
||||
* Writes to the disk file.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
cifWritePaintFunc(tile, f)
|
||||
Tile *tile; /* Tile to be written out. */
|
||||
FILE *f; /* File in which to write. */
|
||||
{
|
||||
Rect r;
|
||||
|
||||
/* Output the layer name if it hasn't been done already. */
|
||||
|
||||
if (cifPaintLayerName != NULL)
|
||||
{
|
||||
fprintf(f, "L %s;\n", cifPaintLayerName);
|
||||
cifPaintLayerName = NULL;
|
||||
}
|
||||
|
||||
TiToRect(tile, &r);
|
||||
|
||||
if (IsSplit(tile))
|
||||
{
|
||||
Point points[5];
|
||||
int i, np;
|
||||
|
||||
GrClipTriangle(&r, NULL, FALSE, TiGetTypeExact(tile), points, &np);
|
||||
|
||||
/* Write triangle as a CIF polygon */
|
||||
|
||||
fprintf(f, " P");
|
||||
for (i = 0; i < np; i++)
|
||||
{
|
||||
fprintf(f, " %d %d",
|
||||
(2*cifPaintScale*(points[i].p_x))/CIFCurStyle->cs_reducer,
|
||||
(2*cifPaintScale*(points[i].p_y))/CIFCurStyle->cs_reducer);
|
||||
}
|
||||
fprintf(f, ";\n");
|
||||
}
|
||||
else
|
||||
|
||||
/* The only tricky thing here is that we MUST scale the rectangle
|
||||
* up by a factor of two to avoid round-off errors in computing
|
||||
* its center point (what a bogosity in CIF!!). This is compensated
|
||||
* by shrinking by a factor of two in the "DS" statement.
|
||||
*/
|
||||
|
||||
fprintf(f, " B %d %d %d %d;\n",
|
||||
(2*cifPaintScale*(r.r_xtop - r.r_xbot))/CIFCurStyle->cs_reducer,
|
||||
(2*cifPaintScale*(r.r_ytop - r.r_ybot))/CIFCurStyle->cs_reducer,
|
||||
(cifPaintScale*(r.r_xtop + r.r_xbot))/CIFCurStyle->cs_reducer,
|
||||
(cifPaintScale*(r.r_ytop + r.r_ybot))/CIFCurStyle->cs_reducer);
|
||||
CIFRects += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* CIFWriteFlat --
|
||||
*
|
||||
* Write out the entire tree rooted at the supplied CellDef in CIF format,
|
||||
* to the specified file, but write non-hierarchical CIF.
|
||||
*
|
||||
* Results:
|
||||
* TRUE if the cell could be written successfully, FALSE otherwise.
|
||||
*
|
||||
* Side effects:
|
||||
* Writes a file to disk.
|
||||
* In the event of an error while writing out the cell,
|
||||
* the external integer errno is set to the UNIX error
|
||||
* encountered.
|
||||
*
|
||||
* Algorithm:
|
||||
* We operate on the cell in chunks chosen to keep the memory utilization
|
||||
* reasonable. Foreach chunk, we use DBTreeSrTiles and cifHierCopyFunc to
|
||||
* flatten the
|
||||
* chunk into a yank buffer ("eliminating" the subcell problem), then use
|
||||
* cifOut to generate the CIF.
|
||||
* No hierarchical design rule checking or bounding box computation
|
||||
* occur during this operation -- both are explicitly avoided.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bool
|
||||
CIFWriteFlat(rootDef, f)
|
||||
CellDef *rootDef; /* Pointer to CellDef to be written */
|
||||
FILE *f; /* Open output file */
|
||||
{
|
||||
bool good;
|
||||
int oldCount = DBWFeedbackCount;
|
||||
TileTypeBitMask cifMask;
|
||||
SearchContext scx;
|
||||
|
||||
cifStack = StackNew(1);
|
||||
CIFInitCells();
|
||||
UndoDisable();
|
||||
CIFDummyUse->cu_def = rootDef;
|
||||
/*
|
||||
* Write CIF preamble out first.
|
||||
*/
|
||||
cifOutPreamble(f, rootDef);
|
||||
|
||||
/*
|
||||
* Now process each chunk. We cheat and use cifOut(), so we need to have
|
||||
* a stack for the single flattened "component" to be on.
|
||||
*/
|
||||
|
||||
{
|
||||
scx.scx_use = CIFDummyUse;
|
||||
scx.scx_trans = GeoIdentityTransform;
|
||||
GEO_EXPAND(&rootDef->cd_bbox, CIFCurStyle->cs_radius, &scx.scx_area);
|
||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||
DBReComputeBbox(CIFComponentDef);
|
||||
cifCellNum = (-2);
|
||||
CIFComponentDef->cd_client = (ClientData) -1;
|
||||
StackPush((ClientData) CIFComponentDef, cifStack);
|
||||
cifOut(f);
|
||||
/* cifStack SHould be empty now */
|
||||
if(!StackEmpty(cifStack))
|
||||
{
|
||||
TxPrintf("Stack error in CIFWriteInverted()!! "
|
||||
"Your CIF is probably corrupted.\n");
|
||||
StackFree(cifStack);
|
||||
return FALSE;
|
||||
}
|
||||
DBCellClearDef(CIFComponentDef);
|
||||
}
|
||||
StackFree(cifStack);
|
||||
|
||||
/*
|
||||
* Now we are almost done.
|
||||
* Just output a call on the root cell
|
||||
*/
|
||||
|
||||
fprintf(f, "C %d;\nEnd\n", (int) CIFComponentDef->cd_client);
|
||||
DBCellClearDef(CIFComponentDef);
|
||||
good = !ferror(f);
|
||||
|
||||
/* Report any errors that occurred. */
|
||||
|
||||
if (DBWFeedbackCount != oldCount)
|
||||
{
|
||||
TxPrintf("%d problems occurred. See feedback entries.\n",
|
||||
DBWFeedbackCount-oldCount);
|
||||
}
|
||||
return good;
|
||||
}
|
||||
+45
@@ -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 */
|
||||
+1157
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 */
|
||||
+4048
File diff suppressed because it is too large
Load Diff
+1200
File diff suppressed because it is too large
Load Diff
+1955
File diff suppressed because it is too large
Load Diff
+1883
File diff suppressed because it is too large
Load Diff
+2708
File diff suppressed because it is too large
Load Diff
+1173
File diff suppressed because it is too large
Load Diff
+2037
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;
|
||||
}
|
||||
+3159
File diff suppressed because it is too large
Load Diff
+1551
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;
|
||||
}
|
||||
+3454
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);
|
||||
}
|
||||
+1057
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);
|
||||
}
|
||||
}
|
||||
+1007
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
|
||||
}
|
||||
+1781
File diff suppressed because it is too large
Load Diff
+1204
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();
|
||||
}
|
||||
+1044
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
|
||||
+235
@@ -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
Reference in New Issue
Block a user