Initial commit at Mon May 18 09:27:46 EDT 2015 by tim on stravinsky

This commit is contained in:
Tim Edwards 2015-05-18 09:27:46 -04:00
commit d5e9f81cb0
129 changed files with 65358 additions and 0 deletions

10
.gitignore vendored Normal file
View File

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

176
Changes Normal file
View File

@ -0,0 +1,176 @@
Changes
Version 1.4
-------------------------------------------------------------------
For changes since 9/3/05, refer to the list of changes posted
on the website at http://opencircuitdesign.com/netgen/.
Version 1.3
-------------------------------------------------------------------
9/3/05 -- Added Xilinx .xnf output format.
-------------------------------------------------------------------
11/13/04 -- Changed the make process to GNU "autoconf" to match
magic-7.3 and irsim-9.7.
-------------------------------------------------------------------
9/30/03 -- Fixed the "lvs" script such that it no longer suggests that
circuits having passed "run converge" match uniquely! Script now
checks the "verify equivalent" to check if the circuit passed the
local connections test, and does a "run resolve" to check global
connectivity, with a final call to "verify unique" to give a pass/
fail answer. Note that by doing "run converge" first and then
testing keeps the output short while obvious errors like transistor
mismatch exist.
Also: Changed the "varargs" method in dbug.c to "stdarg".
9/22/03 -- Added capability to work with multiple transistors declared
with the "M=" syntax in SPICE input decks.
3/31/03 -- "make config" updates and a couple of bug fixes. Updated
the Tcl script for interoperability with applications "Magic",
"IRSIM", and "XCircuit".
3/10/03 -- finished the preliminary new Tcl-based netgen, and updated
the version number to 1.2. Added the tkcon console, worked out
ctrl-C interrupts for both the console and the terminal-based modes,
and extended the log file capability. Added scripted command "lvs"
to do basically what the standalone command "netcomp" used to do.
12/12/02 -- started work on new version 1.1, incorporating Tcl as an
interpreter, changing the command structure to full-name commands
with arguments, redesigning the make process to match that for
magic version 7.2 and irsim version 9.6, and cleaning up 10 years'
worth of accumulated obsolescence.
Between 1991 and 2002 -- some functionality was added to the .sim
file format to incorporate two-terminal devices (namely resistors
and capacitors), and pseudo-three-terminal devices from magic's
extractor (poly-poly caps and bipolar transistors). Each of these
becomes a separate class for the netlist comparison. Added better
handling of hierarchical and array node names passed down from
magic. Ports (sort of) to IRIX and Linux. Changes largely
undocumented.
9/13/91 -- modified ntk.c to allow reading previously undefined
instances. If a cell does not exist in the cell hash table,
it is automatically created. To facilitate this operation, an
explicit procedure ReopenCellDef() is used to avoid the complications
of the AddToExistingDefinition flag.
4/12/91 -- fixed some noise after #endif in netcmp.c and place.c.
Fixed template of ReadNetgenFile in the case of USE_PORTABLE_FILE.
Moved definition of HAVE_GETOPT to config.h under VMUNIX.
Version 1.04 frozen.
11/21/90 -- added 'spice' shell script to wrap spice decks around .ckt files
produced by netgen. Also added sample spice.top and spice.bot files.
11/20/90 -- added checks in NodeName for illegal indices into nodename_cache.
Also repaired a serious bug in generating SPICE and ESACAP output.
Made some mods (#ifdef mips) in netfile.c for brain-dead MIPS compiler.
11/9/90 -- added UNIX man-page documentation: netgen.1, netcomp.1, ntk2adl.1
Modified installation procedure to allow install to occur in a
subdirectory (for different binaries/architectures).
11/7/90 -- fixed actelCell() to correctly write out power and
ground nets even when they are not connected to any logic inputs.
10/25/90 -- modified Flatten to avoid coredumping on cells that
had illegally changed the portlist of their instances (e.g., by
re-opening definitions).
Also added global variable: AddToExistingDefinition that controls
whether subsequent CellDefs add to or replace previous definition.
Default: 0.
9/13/90 -- added ConnectAllNodes(cellname) to eliminate all disconnected
(i.e., connected to node -1) nodes within a cell. Also added global flag
NoDisconnectedNodes that, when true, causes EndCell() to automatically
call ConnectAllNodes. Modified NETCOMP to set this by default.
9/12/90 -- improved netcomp algorithm upon detection of illegal partition.
Improved output format from netcomp (much more user-friendly).
9/11/90 -- portability enhancements: removed all instances of
variables "new","template", and "class" for C++ compatibility.
Modified proto.h to provide correct definition of sprintf for SUNOS-4.0
9/6/90 -- added makemake shell script to configure makefile.
9/1/90 -- version 1.03 frozen.
8/29/90 -- fixed up .EXT parser to correctly accept quoted names.
Added .SIM input parser. Added GNU Public Licence and copyrights.
Modified all cell readers to return the name of the top-level cell
that has been read. Added CellDelete(), CellRename(), and CellCopy()
functions.
7/5/90 -- added VerboseOutput flag to control optional output of routines.
added NoOutput flag to disable printing of stdout.
4/22/90 -- added Str() procedure to generate temporary strings.
Streamlined X_main_loop() to call Query() if not running X.
4/5/90 -- added ESACAP output facility
3/20/90 -- version 1.02 frozen.
3/19/90 -- removed object hashing for IBMPC (for memory efficiency
reasons (see objlist.h)). Improved makefile in tests subdirectory.
3/5/90 -- arbitrary automorphism resolver added to netcmp
2/12/90 -- unified X/non-X code (looks for DISPLAY environment variable).
added .SIM output format
1/25/90 -- added ability to read command files, from Query() and from X.
1/23/90 -- added C-code netlist output format. added named parameter
lists to Cell() procedure. Added Wire() procedure to wire-up an instance.
12/14/89 -- functional X interface completed. All command-line functionality
should be present.
11/21/89 -- deleted all references to data.c and data.h. Modified
print.c to call X hooks, and to provide Finsert function.
10/26/89 -- version 1.01 frozen. New makefile target 'dist' uses
contents of file 'manifest' to generate a distribution tape.
Version 1.01 made available for anonymous FTP from hobiecat.
10/25/89 -- modified ntk2adl to automatically operate on top-level
cell (or, optionally, on cell named in optional second arguement).
Modified dbug/dbug.c to not include <varargs.h> if IBMPC defined.
10/24/89 -- stomped bug in FlattenCell. Added global variable
EquivalenceTransistors to control equivalence of transistor
source/drains in function Compare() only. Added Fwrap() to print.c.
10/17/89 -- collected all public domain software into file pdutils.
Unified 'makefile' between UNIX and MSDOS.
Added internal support for random number generation.
10/13/89 -- added routine ReadNetlist, replacing ReadNtk, ReadExt...
Added NETGEN-internal netlist format: non-portable but fast.
10/10/89 -- added netcmp module to perform graph isomorphism tests.
Wrote stand-alone stub: netcomp.c
9/20/89 -- added support for reading/writing SPICE decks.
9/13/89 -- added caching of NodeName for each cell. This speeds
up writing of all netlist formats, while slowing down creation
of cells somewhat. New procedure NodeAlias replaces NodeName in
most applications, as it correctly handles disconnected nodes.
9/12/89 -- improved List() procedure to call LookupObject
in the absence of wildcards. Removed duplicate call to List() in Cell().
Sped up ReadNtk by 4x. Added timing command to Query();
9/11/89 -- improved support for BSD: synthesized v*printf on VAX,
provided emulation of SYSV string routines, fixed tolower() bug on BSD.
Get CPU time through getrusage().
9/7/89 -- Netgen 1.00 released to Mike Godfrey (version frozen)

249
Copying Normal file
View File

@ -0,0 +1,249 @@
GNU GENERAL PUBLIC LICENSE
Version 1, February 1989
Copyright (C) 1989 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The license agreements of most software companies try to keep users
at the mercy of those companies. By contrast, our General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. The
General Public License applies to the Free Software Foundation's
software and to any other program whose authors commit to using it.
You can use it for your programs, too.
When we speak of free software, we are referring to freedom, not
price. Specifically, the General Public License is designed to make
sure that you have the freedom to give away or sell copies of free
software, that you receive source code or can get it if you want it,
that you can change the software or use pieces of it in new free
programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of a such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must tell them their rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any program or other work which
contains a notice placed by the copyright holder saying it may be
distributed under the terms of this General Public License. The
"Program", below, refers to any such program or work, and a "work based
on the Program" means either the Program or any work containing the
Program or a portion of it, either verbatim or with modifications. Each
licensee is addressed as "you".
1. You may copy and distribute verbatim copies of the Program's source
code as you receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice and
disclaimer of warranty; keep intact all the notices that refer to this
General Public License and to the absence of any warranty; and give any
other recipients of the Program a copy of this General Public License
along with the Program. You may charge a fee for the physical act of
transferring a copy.
2. You may modify your copy or copies of the Program or any portion of
it, and copy and distribute such modifications under the terms of Paragraph
1 above, provided that you also do the following:
a) cause the modified files to carry prominent notices stating that
you changed the files and the date of any change; and
b) cause the whole of any work that you distribute or publish, that
in whole or in part contains the Program or any part thereof, either
with or without modifications, to be licensed at no charge to all
third parties under the terms of this General Public License (except
that you may choose to grant warranty protection to some or all
third parties, at your option).
c) If the modified program normally reads commands interactively when
run, you must cause it, when started running for such interactive use
in the simplest and most usual way, to print or display an
announcement including an appropriate copyright notice and a notice
that there is no warranty (or else, saying that you provide a
warranty) and that users may redistribute the program under these
conditions, and telling the user how to view a copy of this General
Public License.
d) You may charge a fee for the physical act of transferring a
copy, and you may at your option offer warranty protection in
exchange for a fee.
Mere aggregation of another independent work with the Program (or its
derivative) on a volume of a storage or distribution medium does not bring
the other work under the scope of these terms.
3. You may copy and distribute the Program (or a portion or derivative of
it, under Paragraph 2) in object code or executable form under the terms of
Paragraphs 1 and 2 above provided that you also do one of the following:
a) accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of
Paragraphs 1 and 2 above; or,
b) accompany it with a written offer, valid for at least three
years, to give any third party free (except for a nominal charge
for the cost of distribution) a complete machine-readable copy of the
corresponding source code, to be distributed under the terms of
Paragraphs 1 and 2 above; or,
c) accompany it with the information you received as to where the
corresponding source code may be obtained. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form alone.)
Source code for a work means the preferred form of the work for making
modifications to it. For an executable file, complete source code means
all the source code for all modules it contains; but, as a special
exception, it need not include source code for modules which are standard
libraries that accompany the operating system on which the executable
file runs, or for standard header files or definitions files that
accompany that operating system.
4. You may not copy, modify, sublicense, distribute or transfer the
Program except as expressly provided under this General Public License.
Any attempt otherwise to copy, modify, sublicense, distribute or transfer
the Program is void, and will automatically terminate your rights to use
the Program under this License. However, parties who have received
copies, or rights to use copies, from you under this General Public
License will not have their licenses terminated so long as such parties
remain in full compliance.
5. By copying, distributing or modifying the Program (or any work based
on the Program) you indicate your acceptance of this license to do so,
and all its terms and conditions.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the original
licensor to copy, distribute or modify the Program subject to these
terms and conditions. You may not impose any further restrictions on the
recipients' exercise of the rights granted herein.
7. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of the license which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
the license, you may choose any version ever published by the Free Software
Foundation.
8. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to humanity, the best way to achieve this is to make it
free software which everyone can redistribute and change under these
terms.
To do so, attach the following notices to the program. It is safest to
attach them to the start of each source file to most effectively convey
the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19xx name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the
appropriate parts of the General Public License. Of course, the
commands you use may be called something other than `show w' and `show
c'; they could even be mouse-clicks or menu items--whatever suits your
program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
program `Gnomovision' (a program to direct compilers to make passes
at assemblers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
That's all there is to it!

104
Makefile Normal file
View File

@ -0,0 +1,104 @@
#
# Makefile redesigned for netgen-1.3
#
NETGENDIR = .
PROGRAMS = netgen
MODULES = base
MAKEFLAGS =
INSTALL_CAD_DIRS = lib doc
include defs.mak
all: $(ALL_TARGET)
standard:
@echo --- errors and warnings logged in file make.log
@${MAKE} mains 2>&1 | tee -a make.log
tcl:
@echo --- errors and warnings logged in file make.log
@${MAKE} tcllibrary 2>&1 | tee -a make.log
force: clean all
defs.mak:
@echo No \"defs.mak\" file found. Run "configure" to make one.
config:
${NETGENDIR}/configure
tcllibrary: modules
@echo --- making Tcl shared-object libraries
for dir in ${PROGRAMS}; do \
(cd $$dir && ${MAKE} tcl-main); done
mains: modules
@echo --- making main programs
for dir in ${PROGRAMS}; do \
(cd $$dir && ${MAKE} main); done
modules:
@echo --- making modules
for dir in ${MODULES}; do \
(cd $$dir && ${MAKE} module); done
depend:
for dir in ${MODULES} ${PROGRAMS}; do \
(cd $$dir && ${MAKE} depend); done
install: $(INSTALL_TARGET)
install-netgen:
@echo --- installing executable to $(DESTDIR)${BINDIR}
@echo --- installing run-time files to $(DESTDIR)${LIBDIR}
@${MAKE} install-real >> install.log
install-real: install-dirs
for dir in ${PROGRAMS} ${INSTALL_CAD_DIRS}; do \
(cd $$dir && ${MAKE} install); done
install-tcl-dirs:
${NETGENDIR}/scripts/mkdirs $(DESTDIR)${BINDIR} $(DESTDIR)${MANDIR} \
$(DESTDIR)${TCLDIR}
install-dirs:
${NETGENDIR}/scripts/mkdirs $(DESTDIR)${BINDIR} $(DESTDIR)${MANDIR}
install-tcl: install-dirs
@echo --- installing executable to $(DESTDIR)${BINDIR}
@echo --- installing run-time 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} ${UNUSED_MODULES}; do \
(cd $$dir && ${MAKE} clean); done
distclean:
touch defs.mak
@${MAKE} clean
${RM} defs.mak old.defs.mak ${NETGENDIR}/scripts/defs.mak
${RM} ${NETGENDIR}/scripts/default.conf
${RM} ${NETGENDIR}/scripts/config.log ${NETGENDIR}/scripts/config.status
${RM} scripts/netgen.spec netgen-`cat VERSION` netgen-`cat VERSION`.tgz
${RM} *.log
dist:
${RM} scripts/netgen.spec netgen-`cat VERSION` netgen-`cat VERSION`.tgz
sed -e /@VERSION@/s%@VERSION@%`cat VERSION`% \
scripts/netgen.spec.in > scripts/netgen.spec
ln -nsf . netgen-`cat VERSION`
tar zchvf netgen-`cat VERSION`.tgz --exclude CVS \
--exclude netgen-`cat VERSION`/netgen-`cat VERSION` \
--exclude netgen-`cat VERSION`/netgen-`cat VERSION`.tgz \
netgen-`cat VERSION`
clean-mains:
for dir in ${PROGRAMS}; do \
(cd $$dir && ${RM} $$dir); done

158
README Normal file
View File

@ -0,0 +1,158 @@
NETGEN: VERSION 1.5
NETGEN is a general-purpose netlist management system. It can read
and write several netlist formats, including NTK (Caltech, CMU),
WOMBAT (Berkeley), SIM (Berkeley), ACTEL (Actel Inc., Sunnyvale), and
SPICE (Berkeley). In addition, a C-language embedded interface exists
for specifying netlists directly. Please see the documentation file
NETGEN.DOC
NETGEN was intended as an efficient specification language for
hierarchical systems. Secondary features, such as testing isomorphism
between two netlists, have been added over time. As netgen has
primarily been used in its capacity as a netlist comparator, this
has essentially become the primary useful feature of netgen.
Version 1.5 (September 2014) was created largely to allow the
well-developed version 1.4 to be marked as the stable version.
Bug fixes will continue on version 1.4 as version 1.5 continues
development.
Version 1.4 (November 2007) is an effort to make netgen into an
industry-standard LVS tool, handling device classes, device
properties, hierarchy, and providing a sensible output making it
easy to trace a problem to its exact source.
Version 1.2/1.3 (Mar. 2003) takes the original netgen and recasts it
as a Tcl extension in the same manner as magic version 7.2 and
IRSIM version 9.6, while retaining the option to compile the original,
non-interpreter-based version(s). Under Tcl, all of the single-character
commands have been recast as complete function names. The syntax has
been changed to match Tcl generally-accepted syntactical norms. The
X11 GUI has been scrapped and may eventually be replaced by a Tk GUI.
Version 1.3 is a minor update on version 1.2 with GNU autoconf and a
number of associated make-process fixes that were applied to magic
and irsim.
REVISION HISTORY:
-----------------
Revision 0: December 29, 2002 (first cut of port to Tcl).
1) New command-line interface with full-word commands.
2) The usual "toolscript" stuff with printf() functions
passed to Tcl's "eval" function, support for and use
of the TkCon console, compilation as a Tcl shared-object file.
3) New "make config" script to match magic's.
Revision 1: January 10 2003.
1) Improved "nodes" and "elements" commands so they return relevant
information about specific points in the network.
2) Added position information to ".sim" file elements, so this can
be used to trace back problems to a layout and/or schematic.
3) Fixed errors in the printing routines.
4) Improved some horribly inefficient code; speeds up some node
printing commands and causes the "compare" command to become
nearly instantaneous.
5) Removed regular-expression matching from the code. It is
intended that Tcl's built-in regular expression matching will
suffice, although it will be necessary to rewrite some functions
to return Tcl lists instead of just dumping text to the screen.
The main effect this has is that arrayed nodes in magic retain
their names, simplifying the (intended) interface to magic.
Version 1.2, Revision 0: March 10 2003.
1) Fixed and extended the log file capability through the Tcl
command "log". Includes the ability to turn screen echo on
and off while logging.
2) Implemented Control-C interrupts during lengthy procedures,
both for the TkCon console window and for the terminal-based
mode.
3) Created the scripted command "lvs" to do what the standalone
program "netcomp" used to do.
Version 1.3, Revision 0: November 13, 2004.
1) Implemented the GNU "autoconf" configure method in the same
manner as magic-7.3 and irsim-9.7.
For further revision information, see the automatically-generated list
of CVS check-in notes on http://opencircuitdesign.com/netgen/.
BUILDING NETGEN:
----------------
NETGEN version 1.4 uses the same "make" procedure as Magic version 7.5
and IRSIM version 9.7:
./configure
make
make install
IN CASE OF FAILURE
-------------------
Please contact me (tim@opencircuitdesign.com) to report compile-time and
run-time errors. The website at
http://opencircuitdesign.com/netgen/
has complete information about compiling, configuring, and using netgen
version 1.4.
RUNNING NETGEN UNDER TCL
------------------------
The normal procedure for doing a netlist comparison (LVS) is the following:
1) Build ".sim" files for the two netlists to be compared (e.g., run
"exttosim" on the magic layout, and generate sim output on an xcircuit
schematic.
2) Run netgen.
3) As of version 1.4, configuration of LVS is done by commands in a
command file which is passed to the "lvs" command (see below). This
file declares which device classes should be considered matching
between two circuits, which subcircuits should be considered
matching between two top-level circuits, and which ports of devices
or subcircuits permute.
4) As of version 1.2, netgen has a script-level procedure "lvs" which
takes care of the above sequence of commands, as well as dumping the
majority of the output to an output file, and reporting only the
final analysis in the console window. The syntax of this command is:
lvs <filename1> <filename2> [<setupfilename>] [<logfilename>]
If "setupfilename" is not specified, then the default filename "setup.tcl"
will be used. If this file does not exist, then a default setup is
assumed.
If "logfilename" is not specified, then the default filename "comp.out"
will be used.
"lvs" is equivalent to the following sequence of individual commands:
readnet sim <filename1>
readnet sim <filename2>
source <setupfilename>
compare <filename1> <filename2>
run converge
5) Interpreting the output:
The feedback from netgen is still rather crude but improving in each
generation. Illegal fragments are generated around areas where the
netlists cannot be resolved. The worst matches will be listed at the
top, which is usually the place to start looking.
Connectivity of elements and nodes is much easier to trace now, with
commands:
nodes <element_name> <cellname>
elements <node_name> <cellname>
Where "cellname" is the filename (one of the two files loaded for
comparison). The "elements" command prints all of the elements
(transistors, capacitors, resistors, etc.) connected to a specific
named node. The "nodes" command prints the node names for each
pin of the specified element. For ".sim" netlists containing
position information for each transistor, all transistor elements
(and some non-transistor elements such as poly-poly capacitors and
rpoly resistors extracted from magic) will have names like
"n@45,376" indicating an n-type transistor at position x=45, y=376
on the layout. This naming convention permits tracing errors back
to the layout and schematic.

37
TO_DO Normal file
View File

@ -0,0 +1,37 @@
TO_DO list for version 1.5
------------------------------
1) Parallel (transistors and capacitors) and serial (resistors)
device merging, plus methods for describing how any device
class may be merged.
Possible useful additions (not critical)
----------------------
1) Add new output style allowing netlists to be described by Tcl scripts
(similar to the C-Code format, but does not require compiling).
2) Add automatic file format guessing from file extension for "write" command
3) Add Tk GUI to match (and improve upon!) the original X11 GUI.
4) Incorporate into Tcl-based xcircuit
5) Extend 2-terminal device handling (namely R and C) to more formats
(where appropriate).
6) Generate feedback in the form of a .mag file to facilitate interactive
netlist comparison in conjunction with magic. This may be an error
file, but it may also make use of magic 7.2's "element" command to
build rat's nests or outline areas of interest or anything else that
might be helpful to interactive comparison.
7) Improve upon the readability of the netlist comparator output.
In particular, pinpoint situations in which an error does not show
up in an obvious way in either the element or node lists.
8) Handle the hierarchy of ".ext" files automatically.
9) Retain position information from ".ext" files for the purpose of writing
feedback information into magic and for matching devices in the element
list to their counterparts in the original layout [note---done for .sim
format, which contains position information. Usefulness of improving
the .ext parsing is questionable. Ditto for item 8].
10) Expand upon the details of format-to-format translation, (especially
ntk and ext formats, SPICE format writing, and sim format reading).
11) Add a "property" command to add/remove properties to check, and change
the slop values (done).
12) Add a "subcircuit" command to mimic a SPICE ".SUBCKT ... .ENDS" card.

1
VERSION Normal file
View File

@ -0,0 +1 @@
1.5.39

44
base/Depend Normal file
View File

@ -0,0 +1,44 @@
actel.o: actel.c config.h pdutils.h netgen.h objlist.h netfile.h hash.h \
print.h
ccode.o: ccode.c config.h pdutils.h netgen.h objlist.h hash.h netfile.h \
print.h
greedy.o: greedy.c config.h pdutils.h timing.h hash.h objlist.h netfile.h \
embed.h print.h dbug.h
ntk.o: ntk.c config.h pdutils.h netgen.h objlist.h hash.h netfile.h \
print.h
print.o: print.c config.h pdutils.h
actellib.o: actellib.c config.h pdutils.h netgen.h objlist.h
embed.o: embed.c config.h pdutils.h netgen.h objlist.h hash.h netfile.h \
print.h embed.h
hash.o: hash.c config.h pdutils.h netgen.h objlist.h hash.h
netfile.o: netfile.c config.h pdutils.h netgen.h objlist.h hash.h \
netfile.h print.h
objlist.o: objlist.c config.h pdutils.h netgen.h objlist.h hash.h \
regexp.h dbug.h print.h netfile.h netcmp.h
query.o: query.c config.h pdutils.h netgen.h objlist.h timing.h hash.h \
query.h netfile.h print.h dbug.h netcmp.h
anneal.o: anneal.c config.h pdutils.h hash.h objlist.h embed.h timing.h \
print.h dbug.h
ext.o: ext.c config.h pdutils.h netgen.h objlist.h hash.h netfile.h \
print.h
netcmp.o: netcmp.c config.h pdutils.h netgen.h objlist.h netcmp.h hash.h \
query.h netfile.h print.h dbug.h
netgen.o: netgen.c config.h pdutils.h netgen.h objlist.h hash.h netfile.h \
print.h netcmp.h
pdutils.o: pdutils.c config.h pdutils.h netgen.h objlist.h
random.o: random.c config.h pdutils.h hash.h objlist.h embed.h print.h \
dbug.h
timing.o: timing.c config.h pdutils.h timing.h
bottomup.o: bottomup.c config.h pdutils.h hash.h objlist.h timing.h \
embed.h dbug.h print.h
flatten.o: flatten.c config.h pdutils.h netgen.h objlist.h hash.h print.h \
netcmp.h
place.o: place.c config.h pdutils.h netgen.h objlist.h hash.h query.h \
netfile.h embed.h dbug.h print.h
spice.o: spice.c config.h pdutils.h netgen.h objlist.h hash.h netfile.h \
print.h
wombat.o: wombat.c config.h pdutils.h netgen.h objlist.h hash.h netfile.h \
print.h
xilinx.o: xilinx.c config.h pdutils.h netgen.h objlist.h netfile.h hash.h \
print.h
xillib.o: xillib.c config.h pdutils.h netgen.h objlist.h

16
base/Makefile Normal file
View File

@ -0,0 +1,16 @@
MODULE = base
NETGENDIR = ..
SRCS = actel.c ccode.c greedy.c ntk.c print.c actellib.c embed.c \
hash.c netfile.c objlist.c query.c anneal.c ext.c netcmp.c netgen.c \
pdutils.c random.c timing.c bottomup.c flatten.c place.c spice.c \
wombat.c xilinx.c xillib.c
X11_SRCS = xnetgen.c
include ${NETGENDIR}/defs.mak
SRCS += ${GR_SRCS}
DFLAGS += ${GR_DFLAGS}
DFLAGS += -DNETGEN_DATE="\"`date`\""
CFLAGS += ${GR_CFLAGS}
include ${NETGENDIR}/rules.mak

430
base/actel.c Normal file
View File

@ -0,0 +1,430 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* actel.c -- Output routines for ACTEL's .als format */
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
#ifdef IBMPC
#include <stdlib.h> /* for strtol on PC */
#endif
#ifdef TCL_NETGEN
#include <tcl.h>
#endif
#include "netgen.h"
#include "objlist.h"
#include "netfile.h"
#include "hash.h"
#include "print.h"
#define ACTELHASHSIZE 99
static long actelhashbase = 0xA00;
static struct hashlist *actelnametab[ACTELHASHSIZE];
static FILE *actelfile;
char *ActelName(char *Name);
int PrintActelName(struct hashlist *ptr)
{
fprintf(actelfile,"%s == %s\n",ActelName(ptr->name),ptr->name);
return(1);
}
void PrintActelNames(char *filename)
{
if (filename == NULL) actelfile = stdout;
else actelfile = fopen(filename,"w");
RecurseHashTable(actelnametab, ACTELHASHSIZE, PrintActelName);
if (actelfile != stdout) fclose(actelfile);
}
long ActelNameHash(char *name)
/* hashes name into nametab if necessary, then returns address of entry */
{
struct hashlist *p;
p = HashInstall(name, actelnametab, ACTELHASHSIZE);
if (p == NULL) return(0);
if (p->ptr != NULL) return ((long)(p->ptr));
actelhashbase++;
p->ptr = (void *)actelhashbase;
return(actelhashbase);
}
#define ACTELNAMESIZE 3
static char ActelNames[ACTELNAMESIZE][500] ;
static int ActelIndex = 0;
char *ActelName(char *Name)
/* returns a pointer to one of the elements in ActelNames,
which is a copy of 'name',
quoted according to the ACTEL requirements
*/
{
int index, index2;
int NeedsQuoting;
char name[500];
char *nm;
strcpy(name,Name);
/* strip physical-pin information, if it exists */
if ((nm = strrchr(name,PHYSICALPIN[0])) != NULL) *nm = '\0';
if (strlen(name) > 13) {
ActelIndex = (++ActelIndex) % ACTELNAMESIZE;
/* format the value of the hashed value of the string */
sprintf(ActelNames[ActelIndex], "$%lX", ActelNameHash(name));
if (Debug)
Printf("ActelNameHash returns %s on name %s\n",ActelNames[ActelIndex], name);
return(ActelNames[ActelIndex]);
}
NeedsQuoting = 0;
if (NULL != strpbrk(name, ".,:; \t\"'\n\r")) NeedsQuoting = 1;
ActelIndex = (++ActelIndex) % ACTELNAMESIZE;
if (!NeedsQuoting) {
strcpy(ActelNames[ActelIndex], name);
return(ActelNames[ActelIndex]);
}
/* else, needs quoting */
index2 = 0;
ActelNames[ActelIndex][index2++] = '"';
for (index = 0; index < strlen(name); index ++) {
if (name[index] == '"')
ActelNames[ActelIndex][index2++] = '"';
ActelNames[ActelIndex][index2++] = name[index];
}
ActelNames[ActelIndex][index2++] = '"';
ActelNames[ActelIndex][index2++] = '\0';
return(ActelNames[ActelIndex]);
}
void ActelPins(char *name, int format)
/* print out a pins file containing all nodes that:
1) connect to pad
2) have names of the format <name>(<int>)
if format = 0, just dump the list of pins
if format = 1, use the actel .pin file format
*/
{
struct nlist *tp;
struct objlist *ob, *ob2;
char *ptr;
char physicalpin[200];
tp = LookupCell(name);
if (tp == NULL) return;
if (tp->class != CLASS_SUBCKT) return;
if (format == 1) FlushString("DEF %s.\n", ActelName(name));
if (format == 0) FlushString("%20s %3s %s\n\n",
"Pad name","pin","Actel name");
for (ob = tp->cell; ob != NULL; ob = ob->next)
if (IsPortInPortlist(ob,tp) &&
strcasecmp(ob->name, "GND") &&
strcasecmp(ob->name, "VDD") )
/* scan entire list,
looking for same nodenum, but physical port assignment */
for (ob2 = tp->cell; ob2 != NULL; ob2 = ob2->next) {
if (ob->node == ob2->node &&
(ptr = strrchr(ob2->name,PHYSICALPIN[0])) != NULL) {
ptr++; /* point to next char */
strcpy(physicalpin, ptr);
ptr = strchr(physicalpin, ENDPHYSICALPIN[0]);
if (ptr == NULL)
Printf("Bad Actel Pin specification: %s\n", ob2->name);
else {
*ptr = '\0';
if (format == 0) FlushString("%20s %3s %s\n", ob->name,
physicalpin,ActelName(ob->name));
if (format == 1) FlushString("NET %s; ; PIN:%s.\n",
ActelName(ob->name),physicalpin);
break; /* out of for loop */
}
}
}
if (format == 1) FlushString("END.\n");
}
void actelCell(char *name)
{
struct nlist *tp, *tp2;
struct objlist *ob;
int maxnode; /* maximum node number assigned in cell */
int nodenum; /* node number currently being dumped in NET */
int nodedumped;/* flag set true when first element of net written */
int netdumped; /* flag set true when NET stmt. written for given nodenum */
int vddnode, gndnode; /* flags set to true when processing power rail */
tp = LookupCell(name);
if (tp == NULL) {
Printf ("No cell '%s' found.\n", name);
return;
}
/* do NOT dump primitive cells */
if (tp->class != CLASS_SUBCKT)
return;
/* check to see that all children have been dumped */
ob = tp->cell;
while (ob != NULL) {
tp2 = LookupCell(ob->model.class);
if ((tp2 != NULL) && !(tp2->dumped))
actelCell(tp2->name);
ob = ob->next;
}
/* print out header list */
FlushString("DEF %s", ActelName(tp->name));
netdumped = 0;
nodedumped = 0;
for (ob = tp->cell; ob != NULL; ob = ob->next) {
if (IsPortInPortlist(ob, tp) &&
strcasecmp(ob->name, "GND")&&
strcasecmp(ob->name, "VDD") ) {
/* unique port */
if (nodedumped)
FlushString (", ");
else
nodedumped = 1;
if (!netdumped)
FlushString("; ");
/* FlushString("%s", ActelName(ob->name)); */
FlushString("%s", ActelName(NodeAlias(tp, ob)));
netdumped = 1;
}
}
FlushString(".\n");
#if 0
/* I'm not sure whether this works. It is based on a reading of
the .adl syntax manual, and has never been tested.
*/
/* run through cell's contents, defining all global elements */
ob = tp->cell;
while (ob != NULL) {
if ((ob->type == GLOBAL)
&& match(ob->name, NodeAlias(tp, ob)))
FlushString ("SIG %s; GLOBAL.\n", ActelName(ob->name));
ob = ob->next;
}
#endif
/* now run through cell's contents, print instances */
ob = tp->cell;
while (ob != NULL) {
if (ob->type == FIRSTPIN) { /* this is an instance */
if ((LookupCell(ob->model.class))->class != CLASS_SUBCKT)
FlushString ("USE ADLIB:%s; %s.\n",
ActelName(ob->model.class), ActelName(ob->instance.name));
else
FlushString ("USE %s; %s.\n",
ActelName(ob->model.class), ActelName(ob->instance.name));
}
ob = ob->next;
}
/* now print out nets */
ob = tp->cell;
/* find maximum nodenumber in use */
maxnode = -1;
while (ob != NULL) {
if (ob->node > maxnode)
maxnode = ob->node;
ob = ob->next;
}
#if 1
for (nodenum = 1; nodenum <= maxnode; nodenum++) {
nodedumped = 0;
netdumped = 0;
vddnode = 0;
gndnode = 0;
for (ob = tp->cell; ob != NULL; ob = ob->next) {
if (ob->node == nodenum &&
(IsPortInPortlist(ob, tp) || ob->type >= FIRSTPIN)) {
char *nm;
nm = strchr(ob->name, SEPARATOR[0]);
/* suppress pins that are global connections to power rails */
/* i.e., all pins that are <instancename>/VDD */
if (nm == NULL || (strcasecmp(nm+1,"VDD") && strcasecmp(nm+1,"GND"))) {
if (!netdumped)
FlushString("NET %s; ", ActelName(NodeAlias(tp, ob)));
netdumped = 1;
/* print out the element in list */
if (!(strcasecmp(ob->name, "GND"))) gndnode = 1;
else if (!(strcasecmp(ob->name, "VDD"))) vddnode = 1;
else {
if (nodedumped)
FlushString(", ");
/* write it out if it is a REAL port or a PIN */
if (ob->type >= FIRSTPIN)
FlushString("%s:%s", ActelName(ob->instance.name),
/* was strchr below, but failed for FLATTENED objects 12/12/88 */
ActelName(strrchr(ob->name, SEPARATOR[0]) + 1));
else
FlushString("%s", ActelName(NodeAlias(tp, ob)));
nodedumped = 1;
}
}
}
}
/* changed from "if (nodedumped)" to "if (netdumped)"
to correctly terminate power and ground nets that have no pins
(i.e., they only connect to ports of cells that have their
own (internal) connections to these global resources */
if (netdumped) {
if (gndnode) {
if (nodedumped) FlushString("; ");
FlushString("GLOBAL, POWER:GND");
}
if (vddnode) {
if (nodedumped) FlushString("; ");
FlushString("GLOBAL, POWER:VCC");
}
FlushString(".\n");
}
}
#else
/* this code incorrectly wrote power and ground nets when these
nodes were only connected to VDD and GND pins of instances
(i.e., they were not connected to logic inputs) */
for (nodenum = 1; nodenum <= maxnode; nodenum++) {
nodedumped = 0;
netdumped = 0;
vddnode = 0;
gndnode = 0;
for (ob = tp->cell; ob != NULL; ob = ob->next) {
if (ob->node == nodenum &&
(IsPortInPortlist(ob, tp) || ob->type >= FIRSTPIN)) {
char *nm;
nm = strchr(ob->name, SEPARATOR[0]);
/* suppress pins that are global connections to power rails */
if (nm == NULL || (strcasecmp(nm+1,"VDD") && strcasecmp(nm+1,"GND"))) {
if (!netdumped)
FlushString("NET %s; ", ActelName(NodeAlias(tp, ob)));
netdumped = 1;
/* print out the element in list */
if (!(strcasecmp(ob->name, "GND"))) gndnode = 1;
else if (!(strcasecmp(ob->name, "VDD"))) vddnode = 1;
else {
if (nodedumped)
FlushString(", ");
/* write it out if it is a REAL port or a PIN */
if (ob->type >= FIRSTPIN)
FlushString("%s:%s", ActelName(ob->instance.name),
/* was strchr below, but failed for FLATTENED objects 12/12/88 */
ActelName(strrchr(ob->name, SEPARATOR[0]) + 1));
else
FlushString("%s", ActelName(NodeAlias(tp, ob)));
nodedumped = 1;
}
}
}
}
if (nodedumped) {
if (gndnode)
FlushString("; GLOBAL, POWER:GND");
if (vddnode)
FlushString("; GLOBAL, POWER:VCC");
FlushString(".\n");
}
}
#endif
#if 0
/* old style; one pin per net statement. Ok, but ugly (but doesn't
handle VDD and GND pins correctly */
ob = tp->cell;
while (ob != NULL) {
if (ob->type != NODE) {
FlushString ("NET NET%d; ", ob->node);
if (IsPort(ob))
FlushString("%s.\n",
ActelName(ob->name));
else if (ob->type >= FIRSTPIN)
FlushString("%s:%s.\n",
ActelName(ob->model.class),
/* was strchr below 12/12/88 */
ActelName(strrchr(ob->name, SEPARATOR[0]) + 1));
}
ob = ob->next;
}
#endif
FlushString ("END.\n\n");
tp->dumped = 1; /* set dumped flag */
}
void Actel(char *name, char *filename)
{
char Path[500];
char FileName[500];
if (LookupCell(name) == NULL) {
Printf("No such cell name: %s\n", name);
return;
}
if (filename == NULL || strlen(filename) == 0)
strcpy(Path, name);
else
strcpy(Path,filename);
SetExtension(FileName, Path, ACTEL_EXTENSION);
if (!OpenFile(FileName, 80)) {
Printf("Failed to open file named: %s\n",FileName);
perror("Actel(): Unable to open output file.");
return;
}
ClearDumpedList();
InitializeHashTable(actelnametab, ACTELHASHSIZE);
if (LookupCell(name) != NULL)
actelCell(name);
CloseFile(FileName);
SetExtension(FileName, Path, ".pin");
OpenFile(FileName, 80);
ActelPins(name,1);
CloseFile(FileName);
SetExtension(FileName, Path, ".pads");
OpenFile(FileName, 80);
ActelPins(name,0);
CloseFile(FileName);
SetExtension(FileName, Path, ".crt");
OpenFile(FileName, 80);
FlushString("DEF %s.\n", ActelName(name));
FlushString("END.\n");
CloseFile(FileName);
SetExtension(FileName, Path, ".nam");
PrintActelNames(FileName);
}

1275
base/actellib.c Normal file

File diff suppressed because it is too large Load Diff

257
base/anneal.c Normal file
View File

@ -0,0 +1,257 @@
/*
NETGEN -- Copyright 1989, Massimo A. Sivilotti, Caltech
*/
#include "config.h"
#include <stdio.h>
#include <math.h>
#include "hash.h"
#include "objlist.h"
#include "embed.h"
#include "timing.h"
#include "print.h"
#include "dbug.h"
int MaxCPUTime = 100; /* max number of seconds to burn */
#define MAX_SIM_ANNEAL_ITER 10
#define MAX_CHANGES_PER_ITER 2
#if 0
/* INLINE */
float RandomUniform(void)
{
/* DANGER! DANGER! Non-portable code below!! */
return ((float)(rand()) / ((1<<15) - 1.0));
}
#endif
int GenerateAnnealPartition(int left, int right, int level)
/* tries to find a balanced partition, as far as leaf cell usage */
{
int i;
int IncludedElements, partition;
int ChangesMade, Iterations;
int leftfanout, rightfanout;
float T;
level++; /* just to keep to compiler from whining about unused parameter */
IncludedElements = (right - left) / 2;
partition = left + IncludedElements - 1;
/* don't actually use {left,right}fanout, but need to
initialize leftnodes and rightnodes arrays */
leftfanout = PartitionFanout(left, partition, LEFT);
rightfanout = PartitionFanout(partition + 1, right, RIGHT);
#if 0
/* someday, need an escape clause here */
if (leftfanout <= TreeFanout[level] && rightfanout <= TreeFanout[level])
return(partition);
#endif
Printf("called generateannealpartition with left = %d, right = %d\n",left,right);
/* actually do the annealing now */
T = 3.0;
do {
int el1, el2;
int delta;
Iterations = 0;
ChangesMade = 0;
do {
el1 = Random(partition - left + 1) + left;
el2 = Random(right - partition) + partition + 1;
Iterations++;
delta = 0;
for (i = 1; i <= Nodes; i++) {
/* could do the following test with XOR */
if (CSTAR[permutation[el1]][i] == 0 && CSTAR[permutation[el2]][i] == 0)
continue;
if (CSTAR[permutation[el1]][i] != 0 && CSTAR[permutation[el2]][i] != 0)
continue;
/* only one of these is non-zero */
if (CSTAR[permutation[el1]][i] != 0) {
if (rightnodes[i] == 0) {
/* things are not good unless all the fanout is captured in el1 */
if (CSTAR[permutation[el1]][i] != leftnodes[i]) delta++;
}
else {
/* things are good if all fanout is captured in el1 */
if (CSTAR[permutation[el1]][i] == leftnodes[i]) delta--;
}
}
else {
if (leftnodes[i] == 0) {
/* things are not good unless all the fanout is captured in el2 */
if (CSTAR[permutation[el2]][i] != rightnodes[i]) delta++;
}
else {
/* things are good if all fanout is captured in el2 */
if (CSTAR[permutation[el2]][i] == rightnodes[i]) delta--;
}
}
}
DBUG_EXECUTE("place",
Printf("\n");
Printf("considering swapping %d and %d\n",permutation[el1],permutation[el2]);
Printf("E1: ");
for (i = 1; i <= Nodes; i++) Printf("%2d ",CSTAR[permutation[el1]][i]);
Printf("\nL: ");
for (i = 1; i <= Nodes; i++) Printf("%2d ",leftnodes[i]);
Printf("\nE2: ");
for (i = 1; i <= Nodes; i++) Printf("%2d ",CSTAR[permutation[el2]][i]);
Printf("\nR: ");
for (i = 1; i <= Nodes; i++) Printf("%2d ",rightnodes[i]);
Printf("\nC0: ");
for (i = 1; i <= Nodes; i++) Printf("%2d ",CSTAR[0][i]);
Printf("\ndelta = %d\n", delta);
);
if (delta < 0 || exp(-delta / T) > RandomUniform()) {
int tmp;
if (delta < 0) ChangesMade++;
/* update the {left, right}nodes arrays */
for (i = 1; i <= Nodes; i++) {
leftnodes[i] +=
CSTAR[permutation[el2]][i] - CSTAR[permutation[el1]][i];
rightnodes[i] -=
CSTAR[permutation[el2]][i] - CSTAR[permutation[el1]][i];
}
/* now swap the elements */
DBUG_EXECUTE("place",
Printf("swapping elements %d and %d\n",
permutation[el1],permutation[el2]);
);
tmp = permutation[el1];
permutation[el1] = permutation[el2];
permutation[el2] = tmp;
}
} while (ChangesMade <= MAX_CHANGES_PER_ITER &&
Iterations < MAX_SIM_ANNEAL_ITER);
T = 0.90 * T;
Printf("decreasing T to %.2f after %d iterations.\n",T,Iterations);
} while (ChangesMade > 0);
return (partition);
}
int AnnealPartition(int left, int right, int level)
/* return index of new element, if successful partition has been found */
{
int partition;
int iterations;
int found;
int OriginalNewN;
int leftelement, rightelement;
#define MAX_PARTITION_ITERATIONS 10
DBUG_ENTER("AnnealPartition");
OriginalNewN = NewN;
if (level < LEVEL(permutation[left])) {
Fprintf(stdout,"Failed at level %d; subtree too deep\n",level);
DBUG_RETURN(0);
}
if (left == right) DBUG_RETURN(permutation[left]);
if (right - left == 1) {
/* don't bother annealing, just add it to the list */
AddNewElement(permutation[left], permutation[right]);
DBUG_RETURN(NewN);
}
/* use simulated annealing to gather about 1/2 of the elements,
Then check to see if it is valid.
*/
DBUG_PRINT("place",("trying to partition %d, %d",left,right));
iterations = 0;
do {
int i;
int leftfanout, rightfanout;
iterations++;
partition = GenerateAnnealPartition(left, right, level);
if (partition == 0) DBUG_RETURN(0); /* no valid partition */
found = 0;
leftfanout = PartitionFanout(left,partition,LEFT);
rightfanout = PartitionFanout(partition+1, right, RIGHT);
if (leftfanout <= TreeFanout[level] && rightfanout <= TreeFanout[level])
found = 1;
if (!found || level > TopDownStartLevel - 2) {
for (i = MAX_TREE_DEPTH; i > level; i--) Fprintf(stdout, " ");
Fprintf(stdout,
"Level: %d; L (%d leaves) fanout %d; R (%d leaves) fanout %d (<= %d) %s\n",
level, (partition - left + 1), leftfanout,
(right - partition), rightfanout, TreeFanout[level],
found ? "SUCCESSFUL" : "UNSUCCESSFUL");
}
#if 0
if (!found) {
int IterationLimit;
for (IterationLimit = 0; IterationLimit < 20 &&
GradientDescent(left, right, partition); IterationLimit++);
found = 0;
leftfanout = PartitionFanout(left,partition,LEFT);
rightfanout = PartitionFanout(partition+1, right, RIGHT);
if (leftfanout <= TreeFanout[level] && rightfanout <= TreeFanout[level])
found = 1;
for (i = MAX_TREE_DEPTH; i > level; i--) Fprintf(stdout, " ");
Fprintf(stdout,
" Iteration %2d: L fanout %d; R fanout %d (<= %d) %s\n",
iterations, leftfanout, rightfanout, TreeFanout[level],
found ? "SUCCESSFUL" : "UNSUCCESSFUL");
}
#endif
DBUG_EXECUTE("place",
Fprintf(DBUG_FILE,"Level %d: ",level);
Dbug_print_cells(left,partition);
Dbug_print_cells(partition+1,right);
Fprintf(DBUG_FILE,"\n");
{
int i;
Fprintf(DBUG_FILE,"L ");
for (i = 1; i <= Nodes; i++)
Fprintf(DBUG_FILE,"%2d ",leftnodes[i]);
Fprintf(DBUG_FILE,"\nR ");
for (i = 1; i <= Nodes; i++)
Fprintf(DBUG_FILE,"%2d ",rightnodes[i]);
Fprintf(DBUG_FILE,"\n");
}
Fprintf(DBUG_FILE, "%s\n", found?"SUCCESSFUL":"UNSUCCESSFUL");
);
} while (iterations < MAX_PARTITION_ITERATIONS && !found);
if (!found) {
Fprintf(stdout,"Failed embedding at level %d; no partition\n",level);
goto fail;
}
leftelement = AnnealPartition(left, partition, level-1);
if (leftelement == 0) goto fail;
rightelement = AnnealPartition(partition+1, right, level-1);
if (rightelement == 0) goto fail;
/* add it to the list */
AddNewElement(leftelement, rightelement);
DBUG_RETURN(NewN);
fail:
NewN = OriginalNewN;
DBUG_RETURN(0);
}

691
base/bottomup.c Normal file
View File

@ -0,0 +1,691 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* bottomup.c -- Bottom-up graph partitioning algorithm for embedding
netlists on hierarchical prototyping chip.
*/
#include "config.h"
#include <stdio.h>
#include "hash.h"
#include "objlist.h"
#include "timing.h"
#include "embed.h"
#include "dbug.h"
#include "print.h"
/* count invokations of different test procedures */
int CountIndependent;
int CountFanoutOK;
int CountSwallowedElements;
INLINE
int Independent(int E1, int E2)
/* return 1 if E1 and E2 share no leaves in common */
{
int leafelement;
CountIndependent++;
for (leafelement = 0; leafelement <= PackedLeaves; leafelement++)
if (MSTAR[E1][leafelement] & MSTAR[E2][leafelement]) return (0);
return(1);
}
INLINE
int FanoutOK(int E1, int E2)
{
int approxfanout;
int node;
CountFanoutOK++;
/* trivial exclusion based on fanout upper bound */
/* remember, the current PROTOCHIP requires allocation of
an output even for swallowed nodes */
approxfanout = 0;
for (node = 1; node <= Nodes; node++)
if (C[E1][node] || C[E2][node]) approxfanout++;
if (approxfanout > TreeFanout[MAX(LEVEL(E1),LEVEL(E2)) + 1]) return(0);
return(1);
}
INLINE
int Swallowed(int Parent, int Child)
/* returns 1 if Child's fanout is contained in Parent's */
{
int node;
for (node = 1; node <= Nodes; node++)
if (C[Child][node] && !(C[Parent][node])) return(0);
#ifdef PLACE_DEBUG
Printf("Element %d swallowed by %d\n",Child,Parent);
#endif
return(1);
}
#if 1
#define SmallEnough(a,b) 0
#else
int SmallEnough(int E1, int E2)
/* returns 1 if fanout(E1+E2) is less than MAX(fanout(E1),fanout(E2)) */
{
int node;
int fanout;
return(0); /* for now */
fanout = 0;
for (node = 1; node <= Nodes; node++)
if (C[E1][node] || C[E2][node])
if (CSTAR[E1][node] + CSTAR[E2][node] < CSTAR[0][node]) fanout++;
return (fanout <= MAX(PINS(E1), PINS(E2)));
#ifdef PLACE_DEBUG
Printf("Element %d,%d is SmallEnough\n",E1,E2);
#endif
return(1);
}
#endif
INLINE
int SuccessfulEmbedding(int E)
/* returns 1 if element E is a successful embedding */
{
int testleaf;
#if 1
for (testleaf = 0; testleaf <= PackedLeaves; testleaf++)
if (MSTAR[E][testleaf] != MSTAR[0][testleaf]) return (0);
#else
for (testleaf = 1; testleaf <= Leaves; testleaf++)
if (!TestPackedArrayBit(MSTAR[E],testleaf)) return(0);
#endif
return(1);
}
void STARTPASS(FILE *f, int level1, int level2)
{
if (f == NULL) return;
Fprintf(f,"%2d: ",Pass);
if (Exhaustive)
Fprintf(f,"to level %d: (%d) ",level1,CountInLevel(level1,1));
else Fprintf(f,"(%d,%d) [%5d,%5d]",
level1,level2,CountInLevel(level1,0),CountInLevel(level2,0));
#ifdef PLACE_DEBUG
Fprintf(f,"\n");
#endif
Fflush(f);
}
void ENDPASS(FILE *f, int level1, int level2)
{
if (f == NULL) return;
Fprintf(f,"%5dA,%3dS,%5dT",
NewElements, NewSwallowed, Elements);
#if 1
if (NewElements) {
int level;
level = MAX(level1, level2) + 1;
Fprintf(f," (%4.1fP %4.1fC %4.1fL)(%2d %2d %2d)",
(float)SumPINS / NewElements, (float)SumCommonNodes / NewElements,
(float)SumUsedLeaves / NewElements,
TreeFanout[level], MinCommonNodes[level], MinUsedLeaves[level] );
}
#else
if (NewElements) Fprintf(f," (%4.1fP <= %2d, %4.1fC >= %2d, %4.1fL >= %2d)",
(float)SumPINS / (float)NewElements,
TreeFanout[MAX(level1,level2) + 1],
(float)SumCommonNodes / (float)NewElements,
MinCommonNodes[MAX(level1,level2) + 1],
(float)SumUsedLeaves / (float)NewElements,
MinUsedLeaves[MAX(level1,level2) + 1] );
#endif
Fprintf(f,"\n");
Fflush(f);
}
static float StartTime;
void EPILOG(FILE *f, int element)
{
if (f == NULL) return;
Fprintf(f,"Stats: Passes = %d, Elements = %d", Pass, Elements);
if (element) Fprintf(f, ", Level = %d",LEVEL(element));
Fprintf(f, ", Elapsed CPU time = %.2f s\n", ElapsedCPUTime(StartTime));
Fprintf(f,"Tests: Indep. = %d, Conn. = %d, Fanout = %d, Exists = %d\n",
CountIndependent, CountAnyCommonNodes, CountFanoutOK, CountExists);
PrintExistSetStats(f);
Fprintf(f,"Swallowed elements = %d", CountSwallowedElements);
if (Exhaustive) Fprintf(f,", EXHAUSTIVE");
Fprintf(f,"\n\n");
Fflush(f);
}
void SwallowSubTree(int E, int level)
{
if (E != 0 && !(SWALLOWED(E))) {
SWALLOWED(E) = level;
CountSwallowedElements++;
NewSwallowed++;
SwallowSubTree(L(E),level);
SwallowSubTree(R(E),level);
}
}
int Logging(int level1, int level2)
/* return 1 if we should log this level */
{
if (!logging) return(0);
if (!selectivelogging) return(1);
if (level2 == -1) return(level1 == LogLevel1);
if (LogLevel2 == -1) return(level1 == LogLevel1);
if (LogLevel1 == -1) return(level2 == LogLevel2);
return((level1 == LogLevel1) && (level2 == LogLevel2));
}
#if 0
int DoAPass(int Level1, int Level2)
/* tries to merge elements of level 'Level1' with elements of level 'Level2' */
/* returns element number if successful embedding found */
{
int E1, E2;
int PossiblyDone;
int MaxLevel, MinLevel, ThisLevel;
int MinDoneLevel, junk;
int found;
Pass++;
STARTPASS(stdout,Level1,Level2);
STARTPASS(outfile,Level1,Level2);
if (logging) STARTPASS(logfile,Level1,Level2);
/* determine the minimum embedding level */
MaxLevel = MAX(Level1, Level2);
MinLevel = MIN(Level1, Level2);
ThisLevel = MaxLevel + 1; /* level at which any new element will go */
junk = Leaves - 1;
for (MinDoneLevel = 0; junk; MinDoneLevel++) junk = junk >> 1;
PossiblyDone = (MaxLevel >= MinDoneLevel - 1);
NewElements = 0;
NewSwallowed = 0;
SumPINS = 0;
SumCommonNodes = 0;
SumUsedLeaves = 0;
found = 0;
/* make first pass to determine what we can swallow */
#if 1
for (E1 = 1; E1 <= Elements; E1++) {
#else
for (E1 = Elements; E1 > 0; E1--) {
#endif
if ((LEVEL(E1) != MaxLevel && LEVEL(E1) != MinLevel)) continue;
/* might exclude SWALLOWED elements as well */
if (SWALLOWED(E1) && SWALLOWED(E1) != Pass) continue;
for (E2 = E1 - 1; E2 > 0; E2--) {
if ((LEVEL(E2) != MaxLevel && LEVEL(E1) == MinLevel) ||
(LEVEL(E2) != MinLevel && LEVEL(E1) == MaxLevel)) continue;
/* might exclude SWALLOWED elements as well */
if (SWALLOWED(E2) && SWALLOWED(E2) != Pass) continue;
if (Independent(E1,E2)
#ifdef CHECK_MINUSEDLEAVES
&& UsedLeaves(E1,E2) >= MinUsedLeaves[MaxLevel + 1]
#endif
&& AnyCommonNodes(E1,E2)
&& FanoutOK(E1,E2)
&& !Exists(E1,E2)
&& (Swallowed(E1, E2) || Swallowed(E2, E1) || SmallEnough(E1,E2))) {
SwallowSubTree(E1, Pass);
SwallowSubTree(E2, Pass);
AddNewElement(E1,E2);
#ifdef PLACE_DEBUG
Printf("Swallowing (%d,%d) (%d common nodes) into element %d\n",
E1,E2,CommonNodes(E1,E2,1),NewN);
#endif
if (PossiblyDone && SuccessfulEmbedding(NewN)) {
found = NewN;
goto done;
}
if (NewN >= MAX_ELEMENTS) return(MAX_ELEMENTS);
if (FatalError) goto done;
/* break; do not consider E1 or E2 any further */
}
}
}
/* make second pass to consider merging everything else */
#if 1
for (E1 = 1; E1 <= Elements; E1++) {
#else
for (E1 = Elements; E1 > 0; E1--) {
#endif
if ((LEVEL(E1) != MinLevel && LEVEL(E1) != MaxLevel) ||
SWALLOWED(E1)) continue;
#ifdef CHECK_MINCOMMONNODES
if (PINS(E1) < MinCommonNodes[MaxLevel + 1]) continue;
#endif
for (E2 = E1 - 1; E2 > 0; E2--) {
if ((LEVEL(E2) != MaxLevel && LEVEL(E1) == MinLevel) ||
(LEVEL(E2) != MinLevel && LEVEL(E1) == MaxLevel) ||
SWALLOWED(E2)) continue;
#ifdef CHECK_MINCOMMONNODES
if (PINS(E2) < MinCommonNodes[MaxLevel + 1]) continue;
#endif
if (Independent(E1,E2)
#ifdef CHECK_MINUSEDLEAVES
&& UsedLeaves(E1,E2) >= MinUsedLeaves[MaxLevel + 1]
#endif
&& AnyCommonNodes(E1,E2)
&& FanoutOK(E1,E2)
&& !Exists(E1,E2)) {
#ifdef CHECK_MINCOMMONNODES
int commonnodes;
commonnodes = CommonNodes(E1, E2, 1);
if (commonnodes < MinCommonNodes[MaxLevel + 1])
continue;
Printf("Adding element (%d,%d) with %d common nodes\n",
E1,E2,commonnodes);
#endif
AddNewElement(E1,E2);
if (PossiblyDone && SuccessfulEmbedding(NewN)) {
found = NewN;
goto done;
}
if (NewN >= MAX_ELEMENTS) return(MAX_ELEMENTS);
if (FatalError) goto done;
}
}
}
done:
Elements = NewN;
ENDPASS(stdout, Level1, Level2);
#ifdef PLACE_DEBUG
EPILOG(stdout, found);
#endif
ENDPASS(outfile, Level1, Level2);
EPILOG(outfile, found);
if (logging) {
ENDPASS(logfile, Level1, Level2);
EPILOG(logfile, found);
if (NewElements && Logging(Level1,Level2)) {
PrintOwnership(logfile); PrintC(logfile);
PrintCSTAR(logfile); Fflush(logfile);
}
}
return(found);
}
#else
int DoAPass(int Level1, int Level2)
/* tries to merge elements of level 'Level1' with elements of level 'Level2' */
/* returns element number if successful embedding found */
{
int E1, E2;
int PossiblyDone;
int MaxLevel, MinLevel;
int MinDoneLevel, junk;
int found;
Pass++;
STARTPASS(stdout,Level1,Level2);
STARTPASS(outfile,Level1,Level2);
if (logging) STARTPASS(logfile,Level1,Level2);
/* determine the minimum embedding level */
MaxLevel = MAX(Level1, Level2);
MinLevel = MIN(Level1, Level2);
junk = Leaves - 1;
for (MinDoneLevel = 0; junk; MinDoneLevel++) junk = junk >> 1;
PossiblyDone = (MaxLevel >= MinDoneLevel - 1);
NewElements = 0;
NewSwallowed = 0;
SumPINS = 0;
SumCommonNodes = 0;
SumUsedLeaves = 0;
found = 0;
/* make single pass to consider merging and swallow */
#if 1
for (E1 = 1; E1 <= Elements; E1++) {
#else
for (E1 = Elements; E1 > 0; E1--) {
#endif
if ((LEVEL(E1) != MinLevel && LEVEL(E1) != MaxLevel) ||
/* (SWALLOWED(E1) && SWALLOWED(E1) != Pass)) */
SWALLOWED(E1))
continue;
#ifdef CHECK_MINCOMMONNODES
if (PINS(E1) < MinCommonNodes[MaxLevel + 1]) continue;
#endif
for (E2 = E1 - 1; E2 > 0; E2--) {
if ((LEVEL(E2) != MaxLevel && LEVEL(E1) == MinLevel) ||
(LEVEL(E2) != MinLevel && LEVEL(E1) == MaxLevel) ||
/* (SWALLOWED(E2) && SWALLOWED(E2) != Pass)) */
SWALLOWED(E2))
continue;
#ifdef CHECK_MINCOMMONNODES
if (PINS(E2) < MinCommonNodes[MaxLevel + 1]) continue;
#endif
if (Independent(E1,E2)
#ifdef CHECK_MINUSEDLEAVES
&& UsedLeaves(E1,E2) >= MinUsedLeaves[MaxLevel + 1]
#endif
&& AnyCommonNodes(E1,E2)
&& FanoutOK(E1,E2)
&& !Exists(E1,E2)) {
#ifdef CHECK_MINCOMMONNODES
int commonnodes;
commonnodes = CommonNodes(E1, E2, 1);
if (commonnodes < MinCommonNodes[MaxLevel + 1])
continue;
#ifdef PLACE_DEBUG
Printf("Adding element (%d,%d) with %d common nodes\n",
E1,E2,commonnodes);
#endif
#endif
AddNewElement(E1,E2);
if (Swallowed(E1, E2) || Swallowed(E2, E1) || SmallEnough(E1,E2)) {
SwallowSubTree(E1, Pass);
SwallowSubTree(E2, Pass);
#ifdef PLACE_DEBUG
Printf("Swallowing (%d,%d) (%d common nodes) into element %d\n",
E1,E2,CommonNodes(E1,E2,1),NewN);
#endif
}
if (PossiblyDone && SuccessfulEmbedding(NewN)) {
found = NewN;
goto done;
}
if (NewN >= MAX_ELEMENTS) return(MAX_ELEMENTS);
if (FatalError) goto done;
}
}
}
done:
Elements = NewN;
ENDPASS(stdout, Level1, Level2);
#ifdef PLACE_DEBUG
EPILOG(stdout, found);
#endif
ENDPASS(outfile, Level1, Level2);
EPILOG(outfile, found);
if (logging) {
ENDPASS(logfile, Level1, Level2);
EPILOG(logfile, found);
/* if (NewElements && Logging(Level1,Level2)) { */
if (Logging(Level1,Level2)) {
PrintOwnership(logfile); PrintC(logfile);
PrintCSTAR(logfile); Fflush(logfile);
}
}
return(found);
}
#endif
int ExhaustivePass(int Level)
/* tries to merge elements of level 'Level' and below */
/* returns element number if successful embedding found */
{
int E1, E2;
int found;
int PossiblyDone;
int MinDoneLevel, junk;
Pass++;
STARTPASS(stdout, Level, Level);
STARTPASS(outfile, Level, Level);
if (logging) STARTPASS(logfile, Level, Level);
/* determine the minimum embedding level */
junk = Leaves - 1;
for (MinDoneLevel = 0; junk; MinDoneLevel++) junk = junk >> 1;
PossiblyDone = (Level >= MinDoneLevel - 1);
NewElements = 0;
SumPINS = 0;
SumCommonNodes = 0;
SumUsedLeaves = 0;
found = 0;
for (E1 = 1; E1 <= Elements; E1++) {
if (LEVEL(E1) != Level) continue;
#if 1
for (E2 = E1 - 1; E2 > 0; E2--)
#else
for (E2 = 1; E2 < E1; E2++) /* statistically, slightly worse */
#endif
if (LEVEL(E2) <= LEVEL(E1)
&& Independent(E1,E2)
&& AnyCommonNodes(E1,E2)
&& FanoutOK(E1,E2)
&& !Exists(E1,E2)) {
AddNewElement(E1,E2);
if (PossiblyDone && SuccessfulEmbedding(NewN)) {
found = NewN;
goto done;
}
if (NewN >= MAX_ELEMENTS) return(MAX_ELEMENTS);
#if 0
if (Swallowed(E1,E2)) break; /* works OK, but makes csrlntk 5 deep*/
#endif
#if 0
if (Swallowed(E2,E1)) break; /* largely untested: csrlntk in 5 */
#endif
if (FatalError) goto done;
}
}
done:
Elements = NewN;
ENDPASS(stdout, Level, Level);
ENDPASS(outfile, Level, Level);
#ifdef PLACE_DEBUG
EPILOG(stdout, found);
EPILOG(outfile, found);
#endif
if (logging) {
ENDPASS(logfile, Level, Level);
EPILOG(logfile, found);
if (NewElements && Logging(Level,-1)) {
PrintOwnership(logfile); PrintC(logfile);
PrintCSTAR(logfile); Fflush(logfile);
}
}
return(found);
}
void PROLOG(FILE *f)
{
long totalsize;
int junk, MinDoneLevel;
/* determine the minimum embedding level */
junk = Leaves - 1;
for (MinDoneLevel = 0; junk; MinDoneLevel++) junk = junk >> 1;
Fprintf(f,"MAX_ELEMENTS = %d, ",MAX_ELEMENTS);
Fprintf(f,"MAX_LEAVES = %d, ",MAX_LEAVES);
Fprintf(f,"MAX_NODES = %d, ",MAX_NODES);
Fprintf(f,"MAX_TREE_DEPTH = %d\n",MAX_TREE_DEPTH);
Fprintf(f,"Matrix sizes: M = %ldK, MSTAR = %ldK, C = %ldK, CSTAR = %ldK\n",
(long)sizeof(M)/1024,(long)sizeof(MSTAR)/1024,
(long)sizeof(C)/1024, (long)sizeof(CSTAR)/1024);
totalsize = sizeof(M) + sizeof(MSTAR) + sizeof(C) + sizeof(CSTAR);
#ifdef EX_TREE_FOR_EXIST
totalsize += sizeof(ex_array);
Fprintf(f," ex_array = %ldK, total = %ldK\n",
(long)sizeof(ex_array)/1024, (long)totalsize/1024);
#else
Fprintf(f," total = %ldK\n", (long)totalsize/1024);
#endif
Fprintf(f,
" 0: %d elements, %d nodes, %d ports. Earliest embedding level = %d\n",
Elements, Nodes, PINS(0), MinDoneLevel);
Fflush(f);
}
void EmbedCell(char *cellname, char *filename)
{
int found;
int level1, level2;
int FillingLevel;
/* int SomeNewElements; */
if (!OpenEmbeddingFile(cellname, filename)) return;
StartTime = CPUTime();
if (!InitializeMatrices(cellname)) return;
if (!InitializeExistTest()) return;
FatalError = 0;
NewN = Elements;
Pass = 0;
CountIndependent = 0;
CountAnyCommonNodes = 0;
CountFanoutOK = 0;
CountExists = 0;
CountSwallowedElements = 0;
Fprintf(stdout,"Embedding cell: %s\n",cellname);
PROLOG(stdout);
Fprintf(outfile,"Embedding cell: %s\n",cellname);
PROLOG(outfile);
if (logging) {
Fprintf(logfile,"Embedding cell: %s\n",cellname);
PROLOG(logfile);
PrintOwnership(logfile);
PrintC(logfile);
PrintCSTAR(logfile);
Fflush(logfile);
}
if (Exhaustive) {
for (level1 = 0; level1 < MAX_TREE_DEPTH; level1++) {
found = ExhaustivePass(level1);
if (found || FatalError) goto done;
}
}
else {
#if 1
/* do not try to be clever about minimizing passes */
found = -1; /* fake-out to first call below */
for (FillingLevel = 0; FillingLevel < MAX_TREE_DEPTH; FillingLevel++) {
for (level1 = FillingLevel - 1; level1 >= 0 || found == -1; level1--){
if (found == -1) level1 = 0;
found = DoAPass(FillingLevel, level1);
if (found || FatalError) goto done;
/* now try to go up the ladder */
/* NewElements = 1; only do it if we added something in DoAPass */
for (level2 = FillingLevel + 1;
NewElements && level2 < MAX_TREE_DEPTH; level2++) {
found = DoAPass(level2, level2);
if (found || FatalError) goto done;
}
}
}
#else
/* try to minimize number of passes; only works for trees with
leaves at level 0 */
found = -1; /* fake-out to first call below */
SomeNewElements = 1;
for (FillingLevel = 0;
FillingLevel < MAX_TREE_DEPTH && SomeNewElements; FillingLevel++) {
SomeNewElements = 0;
for (level1 = FillingLevel - 1; level1 >= 0 || found == -1; level1--){
if (found == -1) level1 = 0;
found = DoAPass(FillingLevel, level1);
if (NewElements) SomeNewElements = 1;
if (found || FatalError) goto done;
/* now try to go up the ladder */
NewElements = 1;
for (level2 = FillingLevel + 1;
NewElements && level2 < MAX_TREE_DEPTH; level2++) {
found = DoAPass(level2, level2);
if (found || FatalError) goto done;
}
}
}
#endif
}
done:
if (FatalError) {
Fprintf(stdout,"Internal Fatal Error\n");
Fprintf(outfile,"Internal Fatal Error\n");
found = 0;
}
if (found >= MAX_ELEMENTS) found = 0;
if (found) {
struct nlist *tp;
tp = LookupCell(cellname);
FreeEmbeddingTree((struct embed *)(tp->embedding));
tp->embedding = EmbeddingTree(tp, found);
#if 0
PrintEmbedding(stdout,cellname,found);
PrintEmbedding(outfile,cellname,found);
if (logging) PrintEmbedding(logfile,cellname,found);
#endif
PrintEmbeddingTree(stdout,cellname,1);
PrintEmbeddingTree(outfile,cellname,1);
if (logging) PrintEmbeddingTree(logfile,cellname,1);
}
else {
Fprintf(stdout,"No embedding found. Sorry.\n");
Fprintf(outfile,"No embedding found. Sorry.\n");
if (logging) Fprintf(logfile,"No embedding found. Sorry.\n");
}
EPILOG(stdout, found);
EPILOG(outfile, found);
if (logging) EPILOG(logfile, found);
CloseEmbeddingFile();
}

111
base/ccode.c Normal file
View File

@ -0,0 +1,111 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ccode.c -- Output routines to write a cell as NETGEN embedded C code */
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#include "netgen.h"
#include "hash.h"
#include "objlist.h"
#include "netfile.h"
#include "print.h"
void ccodeCell(char *name)
{
struct nlist *tp, *tp2;
struct objlist *ob, *ob2;
tp = LookupCell(name);
if (tp == NULL) {
Printf("No cell '%s' found.\n", name);
return;
}
/* do NOT dump primitive cells */
if (tp->class != CLASS_SUBCKT) return;
/* check to see that all children have been dumped */
for (ob = tp->cell; ob != NULL; ob = ob->next) {
tp2 = LookupCell(ob->model.class);
if ((tp2 != NULL) && !(tp2->dumped))
ccodeCell(tp2->name);
}
/* print out header list */
FlushString("CellDef(\"%s\", -1);\n", tp->name);
for (ob = tp->cell; ob != NULL; ob = ob->next) {
switch (ob->type) {
case PORT: FlushString(" Port(\"%s\");\n", ob->name);
break;
case GLOBAL: FlushString(" Global(\"%s\");\n", ob->name);
break;
case UNIQUEGLOBAL: FlushString(" UniqueGlobal(\"%s\");\n", ob->name);
break;
default: break;
}
}
/* now run through cell's contents, print instances */
for (ob = tp->cell; ob != NULL; ob = ob->next) {
if (ob->type == FIRSTPIN) {
/* this is an instance, so print out a cell */
FlushString(" Cell(\"%s\"", ob->model.class);
ob2 = ob;
do {
FlushString(", \"%s\"", NodeAlias(tp, ob2));
ob2 = ob2->next;
} while ((ob2 != NULL) && (ob2->type > FIRSTPIN));
FlushString(");\n");
}
}
FlushString ("EndDef();\n\n");
tp->dumped = 1; /* set dumped flag */
}
void Ccode(char *name, char *filename)
{
char FileName[500];
if (filename == NULL || strlen(filename) == 0)
SetExtension(FileName, name, CCODE_EXTENSION);
else
SetExtension(FileName, filename, CCODE_EXTENSION);
if (!OpenFile(FileName, 80)) {
Printf("Unable to open CCODE file %s\n", FileName);
return;
}
ClearDumpedList();
/* create top level call */
if (LookupCell(name) != NULL) {
FlushString("/* Cell: %s; code generated by NETGEN */\n", name);
ccodeCell(name);
}
CloseFile(FileName);
}

188
base/config.h Normal file
View File

@ -0,0 +1,188 @@
#ifndef _CONFIG_H
#define _CONFIG_H
/* config.h -- Copyright 1990, Massimo A. Sivilotti, Caltech */
/* This file documents all the system-dependent configuration options.
It is probably better to supply these options on the command-line
by predefining preprocessor symbols, than by editing this file */
/******************************************************************/
/* define the following if your system does not provide the SYSV string
routines: strpbrk(), strcspn(), and strtok() */
/* #define NEED_STRING */
/* define the following if your system does not provide strstr() */
/* #define NEED_STRSTR */
/* define the following if your system does not provide strcasecmp() */
/* #define NEED_STRCASECMP */
/* define the following if your system does not provide strdup */
/* #define NEED_STRDUP */
/* define the following if your system does not provide strtol() */
/* #define NEED_STRTOL */
/* define the following if your system does not do so in values.h */
/* INT_MAX is only used by the random number generator in netcmp.h */
/* #define INT_MAX 31999 */ /* or some other largish number */
/* define the following if your system provides times(2) data */
/* #define HAVE_TIMES */
/* define the following if your system provides getrusage(2) data */
/* #define HAVE_GETRUSAGE */
/* define the following if your system has ANSI C: clock and CLOCKS_PER_SEC */
/* #define HAVE_CLOCK */
/* define the following if your (nominally BSD) system provides the SYSV
string functions: strchr, strrchr, memcpy, and memset */
/* #define HAVE_SYSV_STRING */
/* define the following if your system lacks vsprintf() and vfprintf() */
/* #define NEED_VPRINTF */
/* define the following to disable DBUG code */
/* #define DBUG_OFF */
/* define HAVE_GETOPT if your system has getopt(3) */
/* #define HAVE_GETOPT */
/***********************************************************/
/* REGULAR EXPRESSION STUFF */
/* define the following if your system provides REGCMP(3X) */
/* #define HAVE_REGCMP */
/* define the following if your system provides re_exec and re_comp */
/* #define HAVE_RE_COMP */
/* IF NEITHER HAVE_REGCMP nor HAVE_RE_COMP, use internal routines */
#if defined(BSD) && !defined(HAVE_SYSV_STRING)
#include <strings.h>
#else
#include <string.h>
#ifndef IBMPC
#include <memory.h>
#endif
#endif
#ifdef HAVE_MALLINFO
#include <malloc.h>
#endif
/* SOME GOOD DEFAULTS */
/* eventually, these should be independent of the standards... */
#ifdef VMUNIX
/* #define NEED_STRCASECMP */
#define HAVE_STRCASECMP
#define HAVE_GETOPT
#ifdef BSD
#ifndef ultrix
#define NEED_STRSTR
#endif /* ultrix */
#define NEED_STRDUP
#define HAVE_GETRUSAGE
#define NEED_STRING
#ifndef sun
#define NEED_STRTOL
#endif
#endif /* BSD */
#if !defined(HAVE_GETRUSAGE) && !defined(HAVE_CLOCK)
#define HAVE_TIMES
#endif /* not HAVE_GETRUSAGE or HAVE_CLOCK */
#endif /* VMUNIX */
/* some simple equivalences */
#if defined(BSD) && !defined(HAVE_SYSV_STRING)
#define strchr(s,c) index(s,c)
#define strrchr(s,c) rindex(s,c)
#define memcpy(to,from,len) bcopy((char *)(from), (char *)(to), len)
#define memzero(ptr, len) bzero((char *)(ptr),len)
#else
#define memzero(ptr, len) memset(ptr, 0, len)
#endif
#ifndef INLINE
#ifdef __GNUC__
#define INLINE inline
#else
#define INLINE
#endif /* __GNUC__ */
#endif
#ifdef HAVE_SYSV_STRING
#undef NEED_STRING
#endif
/* some standards !!!! */
#ifdef ANSI_LIBRARY
#undef NEED_STRSTR
#undef NEED_STRING
#undef NEED_STRTOL
#undef NEED_VPRINTF
#define HAVE_CLOCK
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef HPUX
extern int write(int filedes, void *buf, unsigned nbyte); /* SUN has this */
#endif
#ifndef HPUX
extern int open(char *path, int oflag, ...); /* HPUX has it in <sys/fcntl.h> */
#endif
#endif /* ANSI_LIBRARY */
#ifdef NEED_PROTOTYPES
/* proto.h contains prototypes for all undefined functions */
#include "proto.h"
#endif
/* get random number functions, and any string functions we are missing */
#include "pdutils.h"
/* Casting of allocation functions */
#ifdef TCL_NETGEN
#define CALLOC(a, s) tcl_calloc(a, s)
#define MALLOC(s) Tcl_Alloc(s)
#define FREE(a) Tcl_Free((char *)a)
extern char *Tcl_Strdup(const char *);
#define STRDUP(a) Tcl_Strdup((const char *)a)
#else
#include <stdlib.h>
#define CALLOC(a, s) calloc(a, s)
#define MALLOC(s) malloc(s)
#define FREE(a) free(a)
#define STRDUP(a) strdup(a)
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#endif /* _CONFIG_H */

137
base/dbug.h Normal file
View File

@ -0,0 +1,137 @@
/*
DBUG -- Copyright Abandoned, 1987, Fred Fish
This file has been modified by Mass Sivilotti, 1989.
Please see dbug/dbug.h for more details.
*/
/*
* FILE
*
* dbug.h user include file for programs using the dbug package
*
* SYNOPSIS
*
* #include "dbug.h"
*
* SCCS ID
*
* @(#)dbug.h 1.12 4/2/89
*
* DESCRIPTION
*
* Programs which use the dbug package must include this file.
* It contains the appropriate macros to call support routines
* in the dbug runtime library.
*
* To disable compilation of the macro expansions define the
* preprocessor symbol "DBUG_OFF". This will result in null
* macros expansions so that the resulting code will be smaller
* and faster. (The difference may be smaller than you think
* so this step is recommended only when absolutely necessary).
* In general, tradeoffs between space and efficiency are
* decided in favor of efficiency since space is seldom a
* problem on the new machines).
*
* All externally visible symbol names follow the pattern
* "_db_xxx..xx_" to minimize the possibility of a dbug package
* symbol colliding with a user defined symbol.
*
* The DBUG_<N> style macros are obsolete and should not be used
* in new code. Macros to map them to instances of DBUG_PRINT
* are provided for compatibility with older code. They may go
* away completely in subsequent releases.
*
* AUTHOR
*
* Fred Fish
* (Currently employed by Motorola Computer Division, Tempe, Az.)
* hao!noao!mcdsun!fnf
* (602) 438-3614
*
*/
/*
* Internally used dbug variables which must be global.
*/
#ifndef DBUG_OFF
extern int _db_on_; /* TRUE if debug currently enabled */
extern FILE *_db_fp_; /* Current debug output stream */
extern char *_db_process_; /* Name of current process */
extern int _db_keyword_ (char *s); /* Accept/reject keyword */
extern void _db_push_ (char *s); /* Push state, set up new state */
extern void _db_pop_ (void); /* Pop previous debug state */
extern void _db_enter_ (char *func, char *file, int line, char **sfunc,
char **sfile, int *slevel, char **sframe);
/* New user function entered */
extern void _db_return_ (int line, char **sfunc, char **sfile, int *lvl);
/* User function return */
extern void _db_pargs_ (int line, char *key); /* Remember args for line */
extern void _db_doprnt_ (char *format, ...); /* Print debug output */
extern void _db_setjmp_ (void); /* Save debugger environment */
extern void _db_longjmp_ (); /* Restore debugger environment */
# endif
/*
* These macros provide a user interface into functions in the
* dbug runtime support library. They isolate users from changes
* in the MACROS and/or runtime support.
*
* The symbols "__LINE__" and "__FILE__" are expanded by the
* preprocessor to the current source file line number and file
* name respectively.
*
* WARNING --- Because the DBUG_ENTER macro allocates space on
* the user function's stack, it must precede any executable
* statements in the user function.
*
*/
# ifdef DBUG_OFF
# define DBUG_ENTER(a1)
# define DBUG_RETURN(a1) return(a1)
# define DBUG_VOID_RETURN return
# define DBUG_EXECUTE(keyword,a1)
# define DBUG_PRINT(keyword,arglist)
# define DBUG_2(keyword,format) /* Obsolete */
# define DBUG_3(keyword,format,a1) /* Obsolete */
# define DBUG_4(keyword,format,a1,a2) /* Obsolete */
# define DBUG_5(keyword,format,a1,a2,a3) /* Obsolete */
# define DBUG_PUSH(a1)
# define DBUG_POP()
# define DBUG_PROCESS(a1)
# define DBUG_FILE (stderr)
# define DBUG_SETJMP setjmp
# define DBUG_LONGJMP longjmp
# else
# define DBUG_ENTER(a) \
auto char *_db_func_; auto char *_db_file_; auto int _db_level_; \
auto char *_db_framep_; \
_db_enter_ (a,__FILE__,__LINE__,&_db_func_,&_db_file_,&_db_level_, \
&_db_framep_)
# define DBUG_LEAVE \
(_db_return_ (__LINE__, &_db_func_, &_db_file_, &_db_level_))
# define DBUG_RETURN(a1) return (DBUG_LEAVE, (a1))
/* define DBUG_RETURN(a1) {DBUG_LEAVE; return(a1);} Alternate form */
# define DBUG_VOID_RETURN {DBUG_LEAVE; return;}
# define DBUG_EXECUTE(keyword,a1) \
{if (_db_on_) {if (_db_keyword_ (keyword)) { a1 }}}
# define DBUG_PRINT(keyword,arglist) \
{if (_db_on_) {_db_pargs_(__LINE__,keyword); _db_doprnt_ arglist;}}
# define DBUG_2(keyword,format) \
DBUG_PRINT(keyword,(format)) /* Obsolete */
# define DBUG_3(keyword,format,a1) \
DBUG_PRINT(keyword,(format,a1)) /* Obsolete */
# define DBUG_4(keyword,format,a1,a2) \
DBUG_PRINT(keyword,(format,a1,a2)) /* Obsolete */
# define DBUG_5(keyword,format,a1,a2,a3) \
DBUG_PRINT(keyword,(format,a1,a2,a3)) /* Obsolete */
# define DBUG_PUSH(a1) _db_push_ (a1)
# define DBUG_POP() _db_pop_ ()
# define DBUG_PROCESS(a1) (_db_process_ = a1)
# define DBUG_FILE (_db_fp_)
# define DBUG_SETJMP(a1) (_db_setjmp_ (), setjmp (a1))
# define DBUG_LONGJMP(a1,a2) (_db_longjmp_ (), longjmp (a1, a2))
# endif

766
base/embed.c Normal file
View File

@ -0,0 +1,766 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* embed.c -- efficient exhaustive embedding algorithm for PROTOCHIP */
/* define to get reams of extra output */
#undef EXTREE_DEBUG
/* define this to use ex_tree to test Exist() */
#undef EX_TREE_FOR_EXIST
#include "config.h"
#include <stdio.h>
#ifdef IBMPC
#include <stdlib.h>
#endif
#include "netgen.h"
#include "hash.h"
#include "objlist.h"
#include "netfile.h"
#include "print.h"
#include "embed.h"
int CountExists; /* count number of times test is performed */
#ifdef EX_TREE_FOR_EXIST
/* safe, but excessive */
/* #define EX_SIZE (MAX_ELEMENTS * (MAX_LEAVES+1)) */
#ifdef VMUNIX
#define EX_SIZE 250000
#else
#define EX_SIZE 60000
#endif
#endif /* EX_TREE_FOR_EXIST */
#ifdef EX_TREE_FOR_EXIST
#if EX_SIZE > 64000
#define EX_TREE_WITH_POINTERS
#else
#undef EX_TREE_WITH_POINTERS
#endif
#ifdef EX_TREE_WITH_POINTERS
struct ex {
struct ex *zero;
struct ex *one;
};
typedef struct ex *EX_LIST_PTR;
long free_list; /* index into ex_array */
#else
typedef unsigned short EX_LIST_PTR;
struct ex {
EX_LIST_PTR zero;
EX_LIST_PTR one;
};
unsigned short free_list; /* index into ex_array */
#endif /* EX_TREE_WITH_POINTERS */
struct ex ex_array[EX_SIZE];
EX_LIST_PTR tree_root;
#endif /* EX_TREE_FOR_EXIST */
#ifdef EX_TREE_FOR_EXIST
#ifdef EX_TREE_WITH_POINTERS
int InitializeExistTest(void)
{
#ifdef EXTREE_DEBUG
Printf("called InitializeExistTest\n");
#endif
tree_root = NULL;
free_list = 0;
memzero(ex_array, sizeof(ex_array));
return (1);
}
EX_LIST_PTR GetExListElement(void)
/* return index of next free element */
{
if (free_list >= EX_SIZE) {
Fprintf(stderr,"Too many ExListElements; garbage list exhausted\n");
FatalError = 1;
return(NULL);
}
return(&(ex_array[free_list++]));
}
void AddToExistSet(int E1, int E2)
{
char ownedleaves[MAX_LEAVES+1];
int i;
EX_LIST_PTR ptr;
#if 1
for (i = 1; i <= Leaves; i++)
ownedleaves[i] = TestPackedArrayBit(MSTAR[E1],i) ||
TestPackedArrayBit(MSTAR[E2],i);
#else
memzero(ownedleaves, sizeof(ownedleaves));
for (i = 1; i <= Leaves; i++)
if (TestPackedArrayBit(MSTAR[E1],i) ||
TestPackedArrayBit(MSTAR[E2],i)) ownedleaves[i] = 1;
#endif
if (tree_root == NULL)
if ((tree_root = GetExListElement()) == NULL) return;
ptr = tree_root;
for (i = 1; i <= Leaves; i++) {
if (ownedleaves[i] == 1) {
if (ptr->one == NULL)
if ((ptr->one = GetExListElement()) == NULL) return;
ptr = ptr->one;
}
else {
if (ptr->zero == NULL)
if ((ptr->zero = GetExListElement()) == NULL) return;
ptr = ptr->zero;
}
}
}
int Exists(int E1, int E2)
{
char ownedleaves[MAX_LEAVES+1];
int i;
EX_LIST_PTR ptr;
CountExists++;
if (tree_root == NULL) {
#ifdef EXTREE_DEBUG
Printf("(%d,%d) does not exist (empty list)\n",E1,E2);
#endif
return(0);
}
memzero(ownedleaves, sizeof(ownedleaves));
for (i = 1; i <= Leaves; i++)
if (TestPackedArrayBit(MSTAR[E1],i) ||
TestPackedArrayBit(MSTAR[E2],i)) ownedleaves[i] = 1;
#ifdef EXTREE_DEBUG
Printf("checking existence of :");
for (i = 1; i <= Leaves; i++) Printf(" %d",ownedleaves[i]);
Printf(" ");
#endif
ptr = tree_root;
for (i = 1; i <= Leaves; i++) {
if (ownedleaves[i] == 1) {
if (ptr->one == NULL) {
#ifdef EXTREE_DEBUG
Printf("(%d,%d) does not exist (i = %d)\n",E1,E2,i);
#endif
return(0);
}
ptr = ptr->one;
}
else {
if (ptr->zero == NULL) {
#ifdef EXTREE_DEBUG
Printf("(%d,%d) does not exist (i = %d)\n",E1,E2,i);
#endif
return(0);
}
ptr = ptr->zero;
}
}
#ifdef EXTREE_DEBUG
Printf("(%d,%d) already exists (i = %d)\n",E1,E2,i);
#endif
return (1);
}
#else
int InitializeExistTest(void)
{
#ifdef EXTREE_DEBUG
Printf("called InitializeExistTest\n");
#endif
tree_root = 0;
free_list = 1;
memzero(ex_array, sizeof(ex_array));
return (1);
}
EX_LIST_PTR GetExListElement(void)
/* return index of next free element */
{
if (free_list >= EX_SIZE) {
Pprintf(stderr,"Too many ExListElements; garbage list exhausted\n");
FatalError = 1;
return(NULL);
}
return(free_list++);
}
void AddToExistSet(int E1, int E2)
{
char ownedleaves[MAX_LEAVES+1];
int i;
EX_LIST_PTR ptr;
#if 1
for (i = 1; i <= Leaves; i++)
ownedleaves[i] = TestPackedArrayBit(MSTAR[E1],i) ||
TestPackedArrayBit(MSTAR[E2],i);
#else
memzero(ownedleaves, sizeof(ownedleaves));
for (i = 1; i <= Leaves; i++)
if (TestPackedArrayBit(MSTAR[E1],i) ||
TestPackedArrayBit(MSTAR[E2],i)) ownedleaves[i] = 1;
#endif
if (tree_root == 0)
if ((tree_root = GetExListElement()) == 0) return;
ptr = tree_root;
for (i = 1; i <= Leaves; i++) {
if (ownedleaves[i] == 1) {
if (ex_array[ptr].one == 0) {
/* add it to list */
if (i == Leaves) ex_array[ptr].one = ptr;
else if ((ex_array[ptr].one = GetExListElement()) == 0) return;
}
ptr = ex_array[ptr].one;
}
else {
if (ex_array[ptr].zero == 0) {
/* add it to list */
if (i == Leaves) ex_array[ptr].zero = ptr;
else if ((ex_array[ptr].zero = GetExListElement()) == 0) return;
}
ptr = ex_array[ptr].zero;
}
}
}
int Exists(int E1, int E2)
{
char ownedleaves[MAX_LEAVES+1];
int i;
EX_LIST_PTR ptr;
CountExists++;
if (tree_root == 0) {
#ifdef EXTREE_DEBUG
Printf("(%d,%d) does not exist (empty list)\n",E1,E2);
#endif
return(0);
}
memzero(ownedleaves, sizeof(ownedleaves));
for (i = 1; i <= Leaves; i++)
if (TestPackedArrayBit(MSTAR[E1],i) ||
TestPackedArrayBit(MSTAR[E2],i)) ownedleaves[i] = 1;
#ifdef EXTREE_DEBUG
Printf("checking existence of :");
for (i = 1; i <= Leaves; i++) Printf(" %d",ownedleaves[i]);
Printf(" ");
#endif
ptr = tree_root;
for (i = 1; i <= Leaves; i++) {
if (ownedleaves[i] == 1) {
if (ex_array[ptr].one == 0) {
#ifdef EXTREE_DEBUG
Printf("(%d,%d) does not exist (i = %d)\n",E1,E2,i);
#endif
return(0);
}
ptr = ex_array[ptr].one;
}
else {
if (ex_array[ptr].zero == 0) {
#ifdef EXTREE_DEBUG
Printf("(%d,%d) does not exist (i = %d)\n",E1,E2,i);
#endif
return(0);
}
ptr = ex_array[ptr].zero;
}
}
#ifdef EXTREE_DEBUG
Printf("(%d,%d) already exists (i = %d)\n",E1,E2,i);
#endif
return (1);
}
void PrintExistSetStats(FILE *f)
{
Fprintf(f,"Free list = %d of %d entries; ",free_list,EX_SIZE);
}
#endif /* EX_TREE_WITH_POINTERS */
#else /* EX_TREE_FOR_EXIST */
struct ex_entry {
unsigned long mstar[(MAX_LEAVES / BITS_PER_LONG) + 1];
struct ex_entry *next;
};
#if 1
struct ex_entry *ex_tab[MAX_ELEMENTS];
#else
#ifdef IBMPC
struct ex_entry *ex_tab[4100];
#else
struct ex_entry *ex_tab[66000];
#endif
#endif
void PRINTPACKED(unsigned long *mstar)
{
int i;
for (i = 0; i <= PackedLeaves; i++) Printf("%lX ",mstar[i]);
}
#ifdef IBMPC
static unsigned int lochash(unsigned long *mstar)
#else
INLINE
static unsigned long lochash(unsigned long *mstar)
#endif
{
int i;
unsigned long hashval;
hashval = *mstar;
for (i = 1; i <= PackedLeaves; i++) hashval ^= mstar[i];
/* we now have a 32 bit field that we want to collapse to 16 / 12 bits */
#ifdef EXTREE_DEBUG
Printf("hashval = %ld; ",(long)hashval);
#endif
#if 1
hashval = hashval % (MAX_ELEMENTS - 1);
#else
hashval = (hashval >> 16) ^ (hashval & 0x0000FFFFL);
#ifdef IBMPC
hasval = hashval >> 4;
#endif
#endif
#ifdef EXTREE_DEBUG
Printf("element hashed to %ld\n",(long)hashval);
#endif
#ifdef IBMPC
return((int)hashval);
#else
return(hashval);
#endif
}
struct ex_entry *hashlookup(unsigned long *mstar)
{
struct ex_entry *np;
int i;
for (np = ex_tab[lochash(mstar)]; np != NULL; np = np->next)
for (i = 0; i <= PackedLeaves && mstar[i] == (np->mstar)[i]; i++)
if (i == PackedLeaves) {
#ifdef EXTREE_DEBUG
Printf("element found in hash table\n");
#endif
return(np);
}
#ifdef EXTREE_DEBUG
Printf("element not in hash table\n");
#endif
return(NULL);
}
static struct ex_entry *hashinstall(unsigned long *mstar)
{
struct ex_entry *np;
#ifdef IBMPC
unsigned int hashval;
#else
unsigned long hashval;
#endif
int i;
hashval = lochash(mstar);
for (np = ex_tab[hashval]; np != NULL; np = np->next)
for (i = 0; i <= PackedLeaves && mstar[i] == (np->mstar)[i]; i++)
if (i == PackedLeaves) {
#ifdef EXTREE_DEBUG
Printf("element found in hash table\n");
#endif
return(np);
}
/* not found in hash table, so install it */
if ((np = (struct ex_entry *)CALLOC(1, sizeof(struct ex_entry))) == NULL)
return(NULL);
/* memcpy(np->mstar, mstar, (PackedLeaves + 1)*sizeof(long)); */
memcpy(np->mstar, mstar, sizeof(np->mstar));
np->next = ex_tab[hashval];
#ifdef EXTREE_DEBUG
Printf("Element installed in hash table\n");
#endif
return(ex_tab[hashval] = np);
}
/* INLINE */
int Exists(int E1, int E2)
{
int i;
unsigned long mstar[(MAX_LEAVES / BITS_PER_LONG) + 1];
CountExists++;
for (i = 0; i <= PackedLeaves; i++)
mstar[i] = MSTAR[E1][i] | MSTAR[E2][i];
#ifdef EXTREE_DEBUG
Printf("TESTING Existence of (%d,%d)",E1,E2);
PRINTPACKED(mstar);
Printf("\n");
#endif
return (hashlookup(mstar) != NULL);
}
int InitializeExistTest(void)
{
#ifdef IBMPC
int i;
#else
long i;
#endif
struct ex_entry *np;
struct ex_entry *npnext;
for (i = 0; i < sizeof(ex_tab) / sizeof(ex_tab[0]); i++)
for (np = ex_tab[i]; np != NULL; np = npnext) {
npnext = np->next;
FREE(np);
}
memzero(ex_tab, sizeof(ex_tab));
return(1);
}
/* INLINE */
void AddToExistSet(int E1, int E2)
{
int i;
unsigned long mstar[(MAX_LEAVES / BITS_PER_LONG) + 1];
for (i = 0; i <= PackedLeaves; i++)
mstar[i] = MSTAR[E1][i] | MSTAR[E2][i];
#ifdef EXTREE_DEBUG
Printf("Requesting installation of (%d,%d) in hash table\n",E1,E2);
#endif
hashinstall(mstar);
}
void PrintExistSetStats(FILE *f)
{
struct ex_entry *np;
#ifdef IBMPC
int i;
#else
long i;
#endif
long bins;
long nodes;
bins = 0;
nodes = 0;
for (i = 0; i < sizeof(ex_tab) / sizeof(ex_tab[0]); i ++)
if ((np = ex_tab[i]) != NULL) {
bins++;
while (np != NULL) {
nodes++;
np = np->next;
}
}
Fprintf(f,"Exist hash table stats: %ld of %ld bins used",
(long)bins, (long)(sizeof(ex_tab) / sizeof(ex_tab[0])));
if (bins != 0) Fprintf(f,", %ld nodes (%.2f nodes/bin)",
nodes, (float)nodes / (float)bins);
Fprintf(f,"\n");
Fprintf(f,"Exist hash table memory usage: %ld bytes\n",
(long)(sizeof(ex_tab) + nodes * sizeof(struct ex_entry)));
}
#endif /* EX_TREE_FOR_EXIST */
int linelength = 80;
void FreeEmbeddingTree(struct embed *E)
{
if (E == NULL) return;
if (E->left != NULL) FreeEmbeddingTree(E->left);
if (E->right != NULL) FreeEmbeddingTree(E->right);
FREE(E);
}
struct embed *EmbeddingTree(struct nlist *tp, int E)
/* return element E embedded in a tree of 'struct embed' */
{
struct embed *node;
if (E == 0) return(NULL);
if ((node = (struct embed *)CALLOC(1, sizeof(struct embed))) == NULL)
return(NULL);
node->cell = tp;
#if 0
if (LEVEL(E) == 0) {
#else
if (L(E) == 0 && R(E) == 0) {
#endif
/* root element */
node->instancenumber = E;
node->level = LEVEL(E);
return(node);
}
/* not a root element */
node->right = EmbeddingTree(tp, R(E));
node->left = EmbeddingTree(tp, L(E));
if (R(E) == 0) node->level = node->left->level + 1;
else if (L(E) == 0) node->level = node->right->level + 1;
else node->level = MAX(node->left->level, node->right->level) + 1;
return(node);
}
struct embed *FlattenEmbeddingTree(struct embed *E)
/* flattens a forest of trees, returning a copy */
{
struct embed *node;
int index;
if (E == NULL) return(NULL);
if ((node = (struct embed *)CALLOC(1, sizeof(struct embed))) == NULL)
return(NULL);
node->cell = E->cell;
node->level = E->level;
if (E->left == NULL && E->right == NULL) {
/* root element */
struct embed *tmp;
struct nlist *tp;
struct objlist *ob;
ob = InstanceNumber(E->cell,E->instancenumber);
tp = LookupCell(ob->model.class);
if (tp->embedding != NULL) {
tmp = FlattenEmbeddingTree((struct embed *)(tp->embedding));
node->left = tmp->left;
node->right = tmp->right;
node->level = E->level;
node->instancenumber = 0;
}
else memcpy(node, E, sizeof(struct embed));
return(node);
}
/* not a root element */
node->right = FlattenEmbeddingTree(E->right);
node->left = FlattenEmbeddingTree(E->left);
node->level = E->level;
/* make it a balanced tree */
for (index = E->right->level + 1; index < node->level; index++) {
struct embed *tmp;
if ((tmp = (struct embed *)CALLOC(1, sizeof(struct embed))) == NULL)
return(NULL);
tmp->level = index;
tmp->left = NULL;
tmp->right = node->right;
node->right = tmp;
}
for (index = E->right->level + 1; index < node->level; index++) {
struct embed *tmp;
if ((tmp = (struct embed *)CALLOC(1, sizeof(struct embed))) == NULL)
return(NULL);
tmp->level = index;
tmp->left = NULL;
tmp->right = node->right;
node->right = tmp;
}
return(node);
}
#define PRINT_INDENT 2
int LenEmbed(char *prefix, struct nlist *np, struct embed *E, int flatten)
/* return the number of characters required to print element E */
{
char longstr[200];
if (E == NULL) return(0);
if (E->left == NULL && E->right == NULL) {
/* this is a root in our cell's embedding heirarchy */
struct objlist *ob;
char *instancename;
char *model;
struct nlist *np2;
ob = InstanceNumber(np,E->instancenumber);
instancename = ob->instance.name;
model = ob->model.class;
np2 = LookupCell(model);
if (np2 == NULL) return(0);
sprintf(longstr, "%s%s", prefix, instancename);
if ((np2->class != CLASS_SUBCKT) || np2->embedding == NULL || !flatten)
return(strlen(longstr));
/* else, prepend model */
strcat(longstr,SEPARATOR);
return(LenEmbed(longstr, np2, (struct embed *)np2->embedding, flatten));
}
/* else it is a compound element (with 2 parentheses) */
return(PRINT_INDENT + 2 + LenEmbed(prefix, np, E->left, flatten) +
LenEmbed(prefix, np, E->right, flatten));
}
void PrintEmb(FILE *outfile, char *prefix, struct nlist *np,
struct embed *E, int indent, int flatten)
/* just print out the element on a single line */
/* assumes that we have been indented enough to print it directly */
{
if (E == NULL) return;
if (E->left == NULL && E->right == NULL) {
/* this is a root in our cell's embedding heirarchy */
struct objlist *ob;
char *instancename;
struct nlist *np2;
char name[200];
ob = InstanceNumber(np,E->instancenumber);
instancename = ob->instance.name;
np2 = LookupCell(ob->model.class);
if (np2 == NULL) return;
sprintf(name,"%s%s", prefix, instancename);
if ((np2->class != CLASS_SUBCKT) || np2->embedding == NULL || !flatten)
Fprintf(outfile, "%s", name);
else {
strcat(name,SEPARATOR);
PrintEmb(outfile, name, np2, (struct embed *)np2->embedding,
indent + 2*PRINT_INDENT, flatten);
}
return;
}
/* it is a compound element */
Fprintf(outfile,"(");
PrintEmb(outfile, prefix, np, E->left, indent, flatten);
Fprintf(outfile," ");
PrintEmb(outfile, prefix, np, E->right, indent, flatten);
Fprintf(outfile,")");
}
void PrintEmbed(FILE *outfile, char *prefix, struct nlist *np,
struct embed *E, int indent, int flatten)
/* assumes that cursor is on col. 1 of line at entry */
/* upon return, cursor is on col. 1 of next free line */
{
int i;
if (E == NULL) return;
if (E->right == NULL && E->left == NULL) {
/* it is a root element */
struct objlist *ob;
char *instancename;
struct nlist *np2;
char name[200];
ob = InstanceNumber(np,E->instancenumber);
instancename = ob->instance.name;
np2 = LookupCell(ob->model.class);
if (np2 == NULL) return;
if (np2->embedding != NULL && flatten) {
sprintf(name,"%s%s%s", prefix, instancename, SEPARATOR);
PrintEmbed(outfile, name, np2, (struct embed *)np2->embedding,
indent + PRINT_INDENT, flatten);
return;
}
else {
for (i = 0; i < indent; i++) Fprintf(outfile," ");
PrintEmb(outfile, prefix, np, E, indent, flatten);
Fprintf(outfile,"\n");
return;
}
}
if (indent + LenEmbed(prefix, np, E, flatten) >= linelength) {
for (i = 0; i < indent; i++) Fprintf(outfile," ");
Fprintf(outfile,"(\n");
PrintEmbed(outfile, prefix, np, E->left, indent + PRINT_INDENT, flatten);
PrintEmbed(outfile, prefix, np, E->right,indent + PRINT_INDENT, flatten);
for (i = 0; i < indent; i++) Fprintf(outfile," ");
Fprintf(outfile,")\n");
}
else {
for (i = 0; i < indent; i++) Fprintf(outfile," ");
Fprintf(outfile,"(");
PrintEmb(outfile, prefix, np, E->left, indent, flatten);
Fprintf(outfile," ");
PrintEmb(outfile, prefix, np, E->right, indent, flatten);
Fprintf(outfile,")\n");
}
}
void PrintEmbeddingTree(FILE *outfile, char *cellname, int flatten)
{
struct nlist *np;
if (outfile == NULL) return;
np = LookupCell(cellname);
if (np == NULL) return;
if (np->embedding == NULL)
Fprintf(outfile, "No embedding for '%s' has been determined.\n",cellname);
else {
Fprintf(outfile, "Embedding for %s (level %d):\n",cellname,
((struct embed *)(np->embedding))->level);
PrintEmbed(outfile, "", np, (struct embed *)(np->embedding), 0, flatten);
Fprintf(outfile, "\n");
}
}

172
base/embed.h Normal file
View File

@ -0,0 +1,172 @@
#define LEAFPINS 15
#define RENTEXP 0.3
/* #ifdef VMUNIX */
/* #define MAX_ELEMENTS 20000 */
/* #define MAX_NODES 72 */
/* #define MAX_LEAVES 64 */
#define MAX_ELEMENTS 5000
#define MAX_NODES 150
#define MAX_TREE_DEPTH 8
/* #define MAX_LEAVES 256 */
#define MAX_LEAVES (1<<MAX_TREE_DEPTH)
#define BITS_PER_LONG 32
/* #endif */ /* VMUNIX */
#ifdef IBMPC
#define MAX_ELEMENTS 100
#define MAX_NODES 20
#define MAX_LEAVES 16
#define MAX_TREE_DEPTH 4
#define BITS_PER_LONG 32
#endif /* IBMPC */
#define MAX(a,b) (((a)>(b))?(a):(b))
#define MIN(a,b) (((a)<(b))?(a):(b))
#define POW2(a) (1<<(a))
/* abridged ownership and connectivity matrices */
/* elements, nodes, leaves are indexed from 1 to N, nodes, leaves */
extern unsigned short M[][7];
/* height, L, R, SWALLOWED, PINS, LEAVES, USED */
#define LEVEL(e) (M[e][0])
#define L(e) (M[e][1])
#define R(e) (M[e][2])
#define SWALLOWED(e) (M[e][3])
#define PINS(e) (M[e][4]) /* originally C[e][0] */
#define LEAVES(e) (M[e][5])
#define USED(e) (M[e][6])
extern unsigned long MSTAR[MAX_ELEMENTS][(MAX_LEAVES / BITS_PER_LONG) + 1];
#define SetPackedArrayBit(A,B) \
(A [(B) / BITS_PER_LONG] |= (1L << ((B)%BITS_PER_LONG)))
#define TestPackedArrayBit(A,B) \
(A [(B) / BITS_PER_LONG] & (1L << ((B)%BITS_PER_LONG)))
extern unsigned char C[MAX_ELEMENTS][MAX_NODES + 1];
extern unsigned char CSTAR[MAX_ELEMENTS][MAX_NODES + 1];
extern int PackedLeaves;
extern int CountExists;
/* data structure to capture embedding */
struct embed {
struct embed *left;
struct embed *right;
struct nlist *cell;
int instancenumber;
int level;
};
extern int InitializeExistTest(void);
extern void AddToExistSet(int E1, int E2);
extern int Exists(int E1, int E2);
extern void PrintExistSetStats(FILE *f);
extern void FreeEmbeddingTree(struct embed *E);
extern struct embed *EmbeddingTree(struct nlist *tp, int E);
extern void PrintEmbeddingTree(FILE *outfile, char *cellname, int flatten);
/* different embedding strategies, found in random.c, anneal.c, greedy.c */
extern int RandomPartition(int left, int right, int level); /* random.c */
extern int AnnealPartition(int left, int right, int level); /* anneal.c */
extern int GreedyPartition(int left, int right, int level); /* greedy.c */
extern void EmbedCell(char *cellname, char *filename); /* bottomup.c */
extern int GradientDescent(int left, int right, int partition); /* place.c */
/* random data defined in greedy.c */
extern int permutation[];
extern int TopDownStartLevel;
extern int TreeFanout[];
extern int leftnodes[];
extern int rightnodes[];
enum EmbeddingStrategy {random_embedding, greedy, anneal, bottomup} ;
extern void TopDownEmbedCell(char *cellname, char *filename,
enum EmbeddingStrategy strategy);
#define LEFT 1
#define RIGHT 2
#define BOTH 3
/******************** variables in place.c *******************************/
#define IsLeaf(E) (L(E) == 0 && R(E) == 0)
/* abridged ownership and connectivity matrices */
/* elements, nodes, leaves are indexed from 1 to N, nodes, leaves */
extern unsigned short M[MAX_ELEMENTS][7];
/* height, L, R, SWALLOWED, PINS, LEAVES, USED */
extern unsigned long MSTAR[MAX_ELEMENTS][(MAX_LEAVES / BITS_PER_LONG) + 1];
extern unsigned char C[MAX_ELEMENTS][MAX_NODES + 1];
extern unsigned char CSTAR[MAX_ELEMENTS][MAX_NODES + 1];
/* elements at level i must have TreeFanout[i] or fewer ports */
extern int TreeFanout[MAX_TREE_DEPTH + 1]; /* tree fanout at each level */
/* elements at level i must share MinCommonNodes[i] nodes between their kids */
/* or swallow a child entirely */
extern int MinCommonNodes[MAX_TREE_DEPTH + 1];
/* elements at level i must contain at least MinUsedLeaves[i] leaves */
extern int MinUsedLeaves[MAX_TREE_DEPTH + 1];
extern int Nodes; /* number of nodes in the cell */
extern int Leaves; /* number of leaves in the cell */
extern int PackedLeaves; /* == Leaves / BITS_PER_LONG, just to save computation */
extern int Elements; /* number of elements */
extern int NewN, NewElements;
extern int SumPINS, SumCommonNodes, SumUsedLeaves;
extern int NewSwallowed;
extern int Pass;
extern int logging; /* generate output file LOG_FILE_EXT */
extern int selectivelogging;
extern int LogLevel1; /* automatically log if Level1 == LogLevel1 */
extern int LogLevel2;
extern int FatalError; /* internal error */
extern int Exhaustive; /* slow, methodical */
extern int PlaceDebug; /* interactive debug */
extern FILE *outfile; /* output file */
extern FILE *logfile; /* debugging log file */
/* count invokations of different test procedures */
extern int CountIndependent;
extern int CountAnyCommonNodes;
extern int CountFanoutOK;
extern int CountSwallowedElements;
/**************** procedures in place.c *********************************/
extern int CountInLevel(int i, int upto);
extern void AddNewElement (int E1, int E2);
extern int PartitionFanout(int left, int right, int side);
extern void Dbug_print_cells(int left, int right);
extern int AnyCommonNodes(int E1, int E2);
extern int InitializeMatrices(char *cellname);
extern int OpenEmbeddingFile(char *cellname, char *filename);
extern void CloseEmbeddingFile(void);
extern void ToggleLogging(void);
extern void ToggleDebug(void);
extern void ToggleExhaustive(void);
extern void DescribeCell(char *name, int detail);
extern void ProtoEmbed(char *name, char ch);
extern void ProtoPrintParameters(void);
extern void SetupMinUsedLeaves(char *string);
extern void SetupMinCommonNodes(char *string);
extern void SetupTreeFanout(char *string);
extern void SetupRentExp(char *string);
extern void SetupLeafPinout(char *string);
extern void PrintOwnership(FILE *outfile);
extern void PrintC(FILE *outfile);
extern void PrintCSTAR(FILE *outfile);
extern void PrintE(FILE *outfile, int E);

948
base/ext.c Normal file
View File

@ -0,0 +1,948 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ext.c -- Input/output routines for Berkeley .ext and .sim formats */
#include "config.h"
#include <stdio.h>
#include <stdlib.h> /* for strtod() */
#include <stdarg.h>
#include "netgen.h"
#include "hash.h"
#include "objlist.h"
#include "netfile.h"
#include "print.h"
void extCell(char *name, int filenum)
{
struct nlist *tp, *tp2;
struct objlist *ob, *ob2;
int i;
char FileName[500];
tp = LookupCellFile(name, filenum);
if (tp == NULL) {
Printf ("No cell '%s' found.\n", name);
return;
}
/* eliminate transistors as cells (EXT KLUGE) */
ob = tp->cell;
if (match(name, "n") || match(name, "p") || match(name, "e") ||
match(name, "b") || match(name, "r") || matchnocase(name, "c")) {
SetExtension(FileName, name, EXT_EXTENSION);
if (!OpenFile(FileName, 0)) {
Printf("ext(): Unable to open output file: %s.",FileName);
return;
}
FlushString("timestamp 500000000\n");
FlushString("version 4.0\n");
FlushString("tech scmos\n");
ob2 = ob;
for (i = 0; i < 3; i++) {
FlushString("node \"%s\" 1 1 0 0\n", ob2->name);
ob2 = ob2->next;
}
FlushString("fet %sfet 0 0 0 0 0 0 0 ", name);
ob2 = ob;
for (i = 0; i < 3; i++) {
FlushString("\"%s\" 4 0 ", ob2->name);
ob2 = ob2->next;
}
FlushString("\n");
CloseFile(FileName);
tp->dumped = 1; /* set dumped flag */
return;
}
/* check to see that all children have been dumped */
ob = tp->cell;
while (ob != NULL) {
if (ob->type == FIRSTPIN && ob->model.class) {
tp2 = LookupCellFile(ob->model.class, filenum);
if ((tp2 != NULL) && !(tp2->dumped))
extCell(tp2->name, filenum);
}
ob = ob->next;
}
SetExtension(FileName, name, EXT_EXTENSION);
if (!OpenFile(FileName, 0)) {
perror("ext(): Unable to open output file.");
return;
}
/* print out header list */
FlushString("timestamp 500000000\n");
FlushString("version 4.0\n");
FlushString("tech scmos\n");
/* run through cell's contents, defining all ports and nodes */
for (ob = tp->cell; ob != NULL; ob = ob->next)
if ((ob->type == NODE) || IsPort(ob)) {
char *nodename;
FlushString ("node \"%s\" 1 1 0 0\n", ob->name);
nodename = NodeAlias(tp,ob);
if (!match(ob->name, nodename))
FlushString ("merge \"%s\" \"%s\"\n", ob->name, nodename);
}
/* now run through cell's contents, print instances */
for (ob = tp->cell; ob != NULL; ob = ob->next) {
if (ob->type == FIRSTPIN) {
/* this is an instance */
/* print out cell, but special case transistors */
FlushString ("use %s %s 0 0 0 0 0 0\n",
ob->model.class, ob->instance.name);
/* print out parameter list */
ob2 = ob;
do {
char *nodename;
nodename = NodeAlias(tp, ob2);
if (!match(ob2->name, nodename))
FlushString ("merge \"%s\" \"%s\"\n", ob2->name, nodename);
ob2 = ob2->next;
} while ((ob2 != NULL) && (ob2->type > FIRSTPIN));
}
}
FlushString ("\n");
CloseFile(FileName);
Printf("Wrote file: %s\n",FileName);
tp->dumped = 1; /* set dumped flag */
}
void Ext(char *name, int filenum)
{
ClearDumpedList();
if (LookupCellFile(name, filenum) != NULL)
extCell(name, filenum);
}
void GetExtName(char *name, char *nexttok)
{
#ifndef TCL_NETGEN
char *p;
#endif
/* strip leading and trailing quotes, if any exist */
if (*nexttok == '"') {
strcpy(name, nexttok+1);
name[strlen(name) - 1] = '\0';
}
else strcpy(name, nexttok);
#ifndef TCL_NETGEN
/* Quick hack to circumvent problems parsing brackets from magic. */
/* Tcl version attempts to deal with arrays properly and has a */
/* command to suppress wildcard behavior. */
while ((p = strpbrk(name, "[]")) != NULL) *p = '_';
#endif
}
char *ReadExt(char *fname, int doflat, int *fnum)
{
int cdnum = 1, rdnum = 1;
int CellDefInProgress = 0;
int filenum;
if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
char name[100];
SetExtension(name, fname, EXT_EXTENSION);
if ((filenum = OpenParseFile(name, *fnum)) < 0) {
Printf("No file: %s\n",name);
*fnum = filenum;
return NULL;
}
}
else {
/* If "fname" had an extension on it, we don't want */
/* the extension in the cell name. */
char *pptr;
if ((pptr = strrchr(fname, '.')) != NULL) *pptr = '\0';
}
/* Make sure all .ext file reading is case sensitive */
matchfunc = match;
matchintfunc = matchfile;
hashfunc = hash;
if (LookupCellFile(fname, filenum) != NULL) {
Printf("Error: Duplicate cell name \"%s\"!\n", fname);
CloseParseFile();
*fnum = filenum;
return NULL;
}
while (!EndParseFile()) {
SkipTok();
if (EndParseFile()) break;
if (nexttok[0] == '#') SkipNewLine();
else if (match(nexttok, "timestamp")) SkipNewLine();
else if (match(nexttok, "version")) SkipNewLine();
else if (match(nexttok, "tech")) SkipNewLine();
else if (match(nexttok, "scale")) SkipNewLine();
else if (match(nexttok, "style")) SkipNewLine();
else if (match(nexttok, "resistclasses")) SkipNewLine();
else if (match(nexttok, "node")) {
char name[200];
/* No cell is generated until at least one valid "node" or "use" */
/* has been read in the file. */
if (!CellDefInProgress) {
CellDef(fname, filenum);
CellDefInProgress = 1;
}
SkipTok();
GetExtName(name, nexttok);
Node(name); /* Ports will be determined by context */
SkipNewLine();
}
else if (match(nexttok, "equiv")) {
char name[200];
char name2[200];
SkipTok();
GetExtName(name, nexttok);
if (LookupObject(name,CurrentCell) == NULL) Node(name);
SkipTok();
GetExtName(name2, nexttok);
if (LookupObject(name2,CurrentCell) == NULL) Node(name2);
join(name, name2);
SkipNewLine();
}
else if (match(nexttok, "device")) {
char dev_name[100], dev_class[100];
char gate[200], drain[200], source[200], subs[200];
char inststr[64];
SkipTok();
strcpy(dev_class, nexttok);
SkipTok();
strcpy(dev_name, nexttok);
SkipTok(); /* x coord of gate box */
strcpy(inststr, dev_class);
strcat(inststr, "@");
strcat(inststr, nexttok);
SkipTok(); /* y coord of gate box */
strcat(inststr, ",");
strcat(inststr, nexttok);
SkipTok(); /* skip coord of gate box */
SkipTok(); /* skip coord of gate box */
/* Device-dependent parameters */
if (match(dev_class, "mosfet")) {
SkipTok(); /* skip device length */
SkipTok(); /* skip device width */
SkipTok();
GetExtName(subs, nexttok);
}
else if (match(dev_class, "bjt")) {
SkipTok(); /* skip device length */
SkipTok(); /* skip device width */
SkipTok();
GetExtName(subs, nexttok);
}
else if (match(dev_class, "devcap")) {
SkipTok(); /* skip device length */
SkipTok(); /* skip device width */ /* or. . . */
}
else if (match(dev_class, "devres")) {
SkipTok(); /* skip device length */
SkipTok(); /* skip device width */ /* or. . . */
}
else if (match(dev_class, "diode")) {
SkipTok();
GetExtName(gate, nexttok);
SkipTok(); /* skip terminal length */
SkipTok(); /* skip terminal attributes */
SkipTok();
GetExtName(drain, nexttok);
SkipTok(); /* skip terminal length */
SkipTok(); /* skip terminal attributes */
}
else if (match(dev_class, "subckt")) {
SkipTok(); /* skip device length */
SkipTok(); /* skip device width */
SkipTok();
GetExtName(subs, nexttok);
while (nexttok != NULL) {
SkipTok();
GetExtName(gate, nexttok);
SkipTok(); /* skip terminal length */
SkipTok(); /* skip terminal attributes */
}
}
else if (match(dev_class, "rsubckt")) {
SkipTok(); /* skip device length */
SkipTok(); /* skip device width */
SkipTok();
GetExtName(subs, nexttok);
}
SkipTokNoNewline();
SkipNewLine();
}
else if (match(nexttok, "fet")) { /* old-style FET record */
char fet_class[100];
char gate[200], drain[200], source[200], subs[200];
char inststr[64];
SkipTok();
strcpy(fet_class, nexttok);
SkipTok(); /* x coord of gate box */
strcpy(inststr, fet_class);
strcat(inststr, "@");
strcat(inststr, nexttok);
SkipTok(); /* y coord of gate box */
strcat(inststr, ",");
strcat(inststr, nexttok);
SkipTok(); /* skip coord of gate box */
SkipTok(); /* skip coord of gate box */
SkipTok(); /* skip gate area */
SkipTok(); /* skip gate perimeter */
SkipTok();
GetExtName(subs, nexttok);
SkipTok();
GetExtName(gate, nexttok);
SkipTok(); /* skip terminal length */
SkipTok(); /* skip terminal attributes */
SkipTok();
GetExtName(drain, nexttok);
SkipTok(); /* skip terminal length */
SkipTok(); /* skip terminal attributes */
SkipTokNoNewline();
if (nexttok == NULL) {
/* This gets around a problem with the magic extractor in which */
/* transistors having shorted source-drain are written into the */
/* .ext file missing one terminal. This should be corrected in */
/* magic. */
strcpy(source, drain);
}
else
GetExtName(source, nexttok);
SkipNewLine();
/* remap transistors into things we know about */
if (match(fet_class, "nfet"))
N(fname, inststr, gate, drain, source);
else if (match(fet_class, "pfet"))
P(fname, inststr, gate, drain, source);
else if (match(fet_class, "ecap"))
E(fname, inststr, gate, drain, source);
else if (match(fet_class, "bnpn"))
B(fname, inststr, subs, gate, source);
else if (match(fet_class, "zpolyResistor"))
Res3(fname, inststr, gate, drain, source);
else {
Printf("Unknown fet type in ext: '%s'\n", fet_class);
InputParseError(stderr);
}
}
else if (match(nexttok, "cap")) {
if (IgnoreRC) {
/* ignore all capacitances */
SkipNewLine();
}
else {
char ctop[200], cbot[200], cdummy[200];
SkipTok();
GetExtName(ctop, nexttok);
SkipTok();
GetExtName(cbot, nexttok);
SkipNewLine(); /* Skip over capacitance value */
Cap(fname, NULL, ctop, cbot);
}
}
else if (match(nexttok, "use")) {
char name[200];
char instancename[200];
char *basename;
/* No cell is generated until at least one valid "node" or "use" */
/* has been read in the file. */
if (!CellDefInProgress) {
CellDef(fname, filenum);
CellDefInProgress = 1;
}
SkipTok();
GetExtName(name, nexttok);
if ((basename = strrchr(name,'/')) != NULL) {
char tmp[200];
strcpy(tmp, basename+1);
strcpy(name, tmp);
}
SkipTok();
GetExtName(instancename, nexttok);
Printf("Instancing %s as %s\n", name, instancename);
Instance(name, instancename);
if (doflat) {
Printf("Flattening %s in %s\n", instancename, fname);
flattenInstancesOf(NULL, filenum, name);
}
SkipNewLine();
}
else if (match(nexttok, "merge")) {
char name[200];
char name2[200];
SkipTok();
GetExtName(name, nexttok);
SkipTok();
GetExtName(name2, nexttok);
if (doflat)
join(name, name2);
else if ((strchr(name, '/') == NULL) && (strchr(name2, '/') == NULL))
join(name, name2);
else {
}
SkipNewLine();
}
else {
Printf("Strange token in ext: '%s'\n", nexttok);
InputParseError(stderr);
SkipNewLine();
}
}
CloseParseFile();
*fnum = filenum;
return (CellDefInProgress) ? CurrentCell->name : NULL;
}
/* Hierarchical and quasi-Flattened versions of the above */
char *ReadExtHier(char *fname, int *fnum)
{
return ReadExt(fname, 0, fnum);
}
char *ReadExtFlat(char *fname, int *fnum)
{
return ReadExt(fname, 1, fnum);
}
/*********************** .SIM FORMAT SUPPORT **************************/
void simCell(char *name, int filenum)
{
struct nlist *tp, *tp2;
struct objlist *ob, *ob2;
char FileName[500], simclass;
short i;
double l, w, v;
tp = LookupCellFile(name, filenum);
if (tp == NULL) {
Printf ("No cell '%s' found.\n", name);
return;
}
/* check to see that all children have been dumped */
ob = tp->cell;
while (ob != NULL) {
if (ob->type == FIRSTPIN && ob->model.class) {
tp2 = LookupCellFile(ob->model.class, filenum);
if ((tp2 != NULL) && !(tp2->dumped) && (tp2->class == CLASS_SUBCKT))
Printf("Cell must be flat before .SIM written. Found instance: %s\n",
tp2->name);
}
ob = ob->next;
}
SetExtension(FileName, name, SIM_EXTENSION);
if (!OpenFile(FileName, 0)) {
perror("sim(): Unable to open output file.");
return;
}
/* print out header list */
/* distance units are multiplied by 100 (distances are in um) */
FlushString("| units: 100 tech: scmos\n");
/* now run through cell's contents, print instances */
for (ob = tp->cell; ob != NULL; ob = ob->next) {
if (ob->type == FIRSTPIN) {
/* this is an instance */
tp2 = LookupCellFile(ob->model.class, filenum);
switch (tp2->class) {
case CLASS_NMOS: case CLASS_NMOS4:
simclass = 'n';
break;
case CLASS_PMOS: case CLASS_PMOS4:
simclass = 'p';
break;
case CLASS_FET4: case CLASS_FET3: case CLASS_FET:
/* take an educated guess. . . */
if (tolower(ob->model.class[0]) == 'p')
simclass = 'p';
else if (tolower(ob->model.class[0]) == 'n')
simclass = 'n';
else if (tolower(ob->model.class[strlen(ob->model.class) - 1]) == 'p')
simclass = 'p';
else
simclass = 'n';
break;
case CLASS_CAP:
simclass = 'c';
break;
case CLASS_RES:
simclass = 'r';
break;
case CLASS_NPN:
simclass = 'b';
break;
default:
simclass = 'x';
break;
}
if (simclass != 'x')
FlushString("%c", simclass);
switch (tp2->class) {
case CLASS_NMOS: case CLASS_NMOS4:
case CLASS_PMOS: case CLASS_PMOS4:
case CLASS_FET4: case CLASS_FET3: case CLASS_FET:
ob2 = ob->next;
/* write gate and drain */
FlushString(" %s", NodeAlias(tp, ob2));
FlushString(" %s", NodeAlias(tp, ob));
ob2 = ob2->next;
FlushString(" %s", NodeAlias(tp, ob2)); /* write source */
/* Skip any bulk node on 4-terminal devices */
while ((ob2 != NULL) && (ob2->type > FIRSTPIN)) ob2 = ob2->next;
/* default minimum L/W transistors (scale?) */
l = 2;
w = 4;
if (ob2 && ob2->type == PROPERTY) {
struct property *kl;
struct valuelist *vl;
kl = (struct property *)HashLookup("length", tp2->proptab, OBJHASHSIZE);
vl = (struct valuelist *)ob2->instance.name;
l = 1.0e6 * vl[kl->idx].value.dval; /* m -> um */
kl = (struct property *)HashLookup("width", tp2->proptab, OBJHASHSIZE);
w = 1.0e6 * vl[kl->idx].value.dval; /* m -> um */
}
FlushString(" %g %g\n", l, w);
break;
case CLASS_NPN: case CLASS_PNP: case CLASS_BJT:
ob2 = ob->next;
FlushString(" %s", NodeAlias(tp, ob2)); /* base */
ob2 = ob2->next;
/* emitter and collector */
FlushString(" %s\n", NodeAlias(tp, ob2));
FlushString(" %s\n", NodeAlias(tp, ob));
/* skip any other pins (there shouldn't be any. . .) */
while ((ob2 != NULL) && (ob2->type > FIRSTPIN)) ob2 = ob2->next;
break;
case CLASS_CAP: case CLASS_RES:
case CLASS_CAP3: case CLASS_RES3: case CLASS_ECAP:
v = 1;
ob2 = ob;
for (i = 0; i < 2; i++) {
FlushString(" %s", NodeAlias(tp, ob2));
ob2 = ob2->next;
if ((ob2 == NULL) || (ob2->type <= FIRSTPIN)) break;
}
while ((ob2 != NULL) && (ob2->type > FIRSTPIN))
ob2 = ob2->next; /* Skip dummy node on 3-terminal devices */
if (ob2 && ob2->type == PROPERTY) {
struct property *kl;
struct valuelist *vl;
kl = (struct property *)HashLookup("value", tp2->proptab, OBJHASHSIZE);
vl = (struct valuelist *)ob2->instance.name;
if (tp2->class == CLASS_CAP)
v = 1.0e15 * vl[kl->idx].value.dval; /* F -> fF */
else if (tp2->class == CLASS_RES)
v = vl->value.dval; /* Ohms (no conversion) */
}
FlushString(" %g\n", v);
break;
default:
FlushString("| unhandled component %s\n", tp2->name);
break;
}
}
}
FlushString ("\n");
CloseFile(FileName);
Printf("Wrote file: %s\n",FileName);
tp->dumped = 1; /* set dumped flag */
}
void Sim(char *name, int filenum)
{
ClearDumpedList();
if (LookupCellFile(name, filenum) != NULL)
simCell(name, filenum);
}
/*-------------------------------------------------*/
/* Check whether a string token is a valid integer */
/*-------------------------------------------------*/
int StrIsInt(char *s)
{
if (*s == '-' || *s == '+') s++;
while (*s)
if (!isdigit(*s++))
return (0);
return (1);
}
/*-------------------------*/
/* Read a .sim format file */
/*-------------------------*/
char *ReadSim(char *fname, int *fnum)
{
int cdnum = 1, rdnum = 1, filenum;
int has_lumped = 0;
char *vstr;
struct keyvalue *kvlist = NULL;
struct nlist *tp;
double simscale = 1.0;
if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
char name[100];
SetExtension(name, fname, SIM_EXTENSION);
if (OpenParseFile(name, *fnum) < 0) {
Printf("No file: %s\n",name);
*fnum = filenum;
return NULL;
}
}
/* Make sure all .sim file reading is case sensitive */
matchfunc = match;
matchintfunc = matchfile;
hashfunc = hash;
CellDef(fname, filenum);
while (!EndParseFile()) {
SkipTok();
if (EndParseFile()) break;
if (nexttok[0] == '|') {
SkipTok(); /* "units" */
if (!strcmp(nexttok, "units:")) {
SkipTok();
simscale = strtod(nexttok, NULL);
}
SkipNewLine();
}
else if (match(nexttok, "n")) {
char gate[200], drain[200], source[200];
char inststr[25], *instptr = NULL;
SkipTok();
GetExtName(gate, nexttok);
if (LookupObject(gate, CurrentCell) == NULL)
Node(gate); /* define the node if it does not already exist */
SkipTok();
GetExtName(drain, nexttok);
if (LookupObject(drain, CurrentCell) == NULL)
Node(drain); /* define the node if it does not already exist */
SkipTok();
GetExtName(source, nexttok);
if (LookupObject(source, CurrentCell) == NULL)
Node(source); /* define the node if it does not already exist */
SkipTokNoNewline(); /* length */
if ((nexttok != NULL) && (nexttok[0] != '\0')) {
vstr = ScaleStringFloatValue(&nexttok[0], simscale * 1e-8);
AddProperty(&kvlist, "length", vstr);
SkipTok(); /* width */
if ((nexttok != NULL) && (nexttok[0] != '\0')) {
vstr = ScaleStringFloatValue(&nexttok[0], simscale * 1e-8);
AddProperty(&kvlist, "width", vstr);
}
SkipTokNoNewline();
if (nexttok != NULL) {
if (StrIsInt(nexttok)) {
strcpy(inststr, "n@");
strcat(inststr, nexttok);
SkipTok();
strcat(inststr, ",");
strcat(inststr, nexttok);
instptr = inststr;
}
}
}
SkipNewLine(); /* skip any attributes */
N(fname, instptr, gate, drain, source);
LinkProperties("n", kvlist);
}
else if (match(nexttok, "p")) {
char gate[200], drain[200], source[200];
char inststr[25], *instptr = NULL;
SkipTok();
GetExtName(gate, nexttok);
if (LookupObject(gate, CurrentCell) == NULL)
Node(gate); /* define the node if it does not already exist */
SkipTok();
GetExtName(drain, nexttok);
if (LookupObject(drain, CurrentCell) == NULL)
Node(drain); /* define the node if it does not already exist */
SkipTok();
GetExtName(source, nexttok);
if (LookupObject(source, CurrentCell) == NULL)
Node(source); /* define the node if it does not already exist */
SkipTokNoNewline(); /* length */
if ((nexttok != NULL) && (nexttok[0] != '\0')) {
vstr = ScaleStringFloatValue(&nexttok[0], simscale * 1e-8);
AddProperty(&kvlist, "length", vstr);
SkipTok(); /* width */
if ((nexttok != NULL) && (nexttok[0] != '\0')) {
vstr = ScaleStringFloatValue(&nexttok[0], simscale * 1e-8);
AddProperty(&kvlist, "width", vstr);
}
SkipTokNoNewline();
if (nexttok != NULL) {
if (StrIsInt(nexttok)) {
strcpy(inststr, "p@");
strcat(inststr, nexttok);
SkipTok();
strcat(inststr, ",");
strcat(inststr, nexttok);
instptr = inststr;
}
}
}
SkipNewLine(); /* skip various attributes */
P(fname, instptr, gate, drain, source);
LinkProperties("p", kvlist);
}
else if (match(nexttok, "e")) { /* 3-port capacitors (poly/poly2) */
char gate[200], drain[200], source[200];
char inststr[25], *instptr = NULL;
SkipTok();
GetExtName(gate, nexttok);
if (LookupObject(gate, CurrentCell) == NULL)
Node(gate); /* define the node if it does not already exist */
SkipTok();
GetExtName(drain, nexttok);
if (LookupObject(drain, CurrentCell) == NULL)
Node(drain); /* define the node if it does not already exist */
SkipTok();
GetExtName(source, nexttok);
if (LookupObject(source, CurrentCell) == NULL)
Node(source); /* define the node if it does not already exist */
SkipTokNoNewline(); /* skip length */
if (nexttok != NULL) {
SkipTok(); /* skip width */
SkipTokNoNewline();
inststr[0] = '\0';
if (nexttok != NULL) {
if (StrIsInt(nexttok)) {
strcpy(inststr, "e@");
strcat(inststr, nexttok);
SkipTok();
strcat(inststr, ",");
strcat(inststr, nexttok);
instptr = inststr;
}
}
}
SkipNewLine(); /* skip various attributes */
E(fname, instptr, gate, drain, source);
}
else if (match(nexttok, "b")) { /* bipolars added by Tim 7/16/96 */
char base[200], emitter[200], collector[200];
char inststr[25], *instptr = NULL;
SkipTok();
GetExtName(base, nexttok);
if (LookupObject(base, CurrentCell) == NULL)
Node(base); /* define the node if it does not already exist */
SkipTok();
GetExtName(emitter, nexttok);
if (LookupObject(emitter, CurrentCell) == NULL)
Node(emitter); /* define the node if it does not already exist */
SkipTok();
GetExtName(collector, nexttok);
if (LookupObject(collector, CurrentCell) == NULL)
Node(collector); /* define the node if it does not already exist */
SkipTokNoNewline(); /* skip length */
if (nexttok != NULL) {
SkipTok(); /* skip width */
SkipTokNoNewline();
if (nexttok != NULL) {
if (StrIsInt(nexttok)) {
strcpy(inststr, "b@");
strcat(inststr, nexttok);
SkipTok();
strcat(inststr, ",");
strcat(inststr, nexttok);
instptr = inststr;
}
}
}
SkipNewLine(); /* skip various attributes */
B(fname, instptr, collector, base, emitter);
}
else if (matchnocase(nexttok, "c")) { /* 2-port capacitors */
if (IgnoreRC) {
/* ignore all capacitances */
SkipNewLine();
}
else {
char ctop[200], cbot[200], cdummy[200];
SkipTok();
GetExtName(ctop, nexttok);
if (LookupObject(ctop, CurrentCell) == NULL)
Node(ctop); /* define the node if it does not already exist */
SkipTok();
GetExtName(cbot, nexttok);
if (LookupObject(cbot, CurrentCell) == NULL)
Node(cbot); /* define the node if it does not already exist */
SkipTokNoNewline();
if (nexttok != NULL) {
vstr = ScaleStringFloatValue(&nexttok[0], 1e-15);
AddProperty(&kvlist, "value", vstr);
}
SkipNewLine();
Cap(fname, NULL, ctop, cbot);
LinkProperties("c", kvlist);
}
}
else if (match(nexttok, "r")) { /* 2-port resistors */
if (IgnoreRC) {
/* ignore all capacitances */
SkipNewLine();
}
else {
char rtop[200], rbot[200];
SkipTok();
GetExtName(rtop, nexttok);
if (LookupObject(rtop, CurrentCell) == NULL)
Node(rtop); /* define the node if it does not already exist */
SkipTok();
GetExtName(rbot, nexttok);
if (LookupObject(rbot, CurrentCell) == NULL)
Node(rbot); /* define the node if it does not already exist */
SkipTokNoNewline();
if (nexttok != NULL) {
AddProperty(&kvlist, "value", &nexttok[0]);
}
SkipNewLine(); /* skip various attributes */
Res(fname, NULL, rtop, rbot);
LinkProperties("r", kvlist);
}
}
else if (match(nexttok, "z")) { /* 3-port resistors from magic */
if (IgnoreRC) {
/* ignore all capacitances */
SkipNewLine();
}
else {
char rtop[200], rbot[200], rdummy[200];
char inststr[25], *instptr = NULL;
SkipTok();
GetExtName(rdummy, nexttok);
if (LookupObject(rdummy, CurrentCell) == NULL)
Node(rdummy); /* define the node if it does not already exist */
SkipTok();
GetExtName(rtop, nexttok);
if (LookupObject(rtop, CurrentCell) == NULL)
Node(rtop); /* define the node if it does not already exist */
SkipTok();
GetExtName(rbot, nexttok);
if (LookupObject(rbot, CurrentCell) == NULL)
Node(rbot); /* define the node if it does not already exist */
SkipTokNoNewline(); /* skip length */
if (nexttok != NULL) {
SkipTok(); /* skip width */
SkipTokNoNewline();
if (nexttok != NULL) {
if (StrIsInt(nexttok)) {
strcpy(inststr, "z@");
strcat(inststr, nexttok);
SkipTok();
strcat(inststr, ",");
strcat(inststr, nexttok);
instptr = inststr;
}
}
}
SkipNewLine(); /* skip various attributes */
Res3(fname, instptr, rdummy, rtop, rbot);
}
}
else if (match(nexttok, "N")) {
/* ignore this keyword */
SkipNewLine();
}
else if (match(nexttok, "A")) {
/* ignore this keyword */
SkipNewLine();
}
else if (match(nexttok, "=")) {
char node1[200], node2[200];
SkipTok();
GetExtName(node1, nexttok);
SkipTok();
GetExtName(node2, nexttok);
join(node1, node2);
}
else if (match(nexttok, "R")) {
if (has_lumped == 0) {
Printf("Ignoring lumped resistances (\"R\" records) in .sim.\n");
has_lumped = 1; /* Don't print this message more than once */
}
SkipNewLine();
}
else {
Printf("Strange token in .sim: '%s'\n", nexttok);
InputParseError(stderr);
SkipNewLine();
}
DeleteProperties(&kvlist);
}
EndCell();
CloseParseFile();
tp = LookupCellFile(fname, filenum);
if (tp) tp->flags |= CELL_TOP;
*fnum = filenum;
return fname;
}

1634
base/flatten.c Normal file

File diff suppressed because it is too large Load Diff

492
base/greedy.c Normal file
View File

@ -0,0 +1,492 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* greedy.c -- a greedy graph-partitioning algorithm for the PROTOCHIP */
#include "config.h"
#include <stdio.h>
#ifdef IBMPC
#include <mem.h> /* memset */
#endif
#include "timing.h"
#include "hash.h"
#include "objlist.h"
#include "netfile.h"
#include "embed.h"
#include "print.h"
#include "dbug.h"
/**************************************************************************/
/***** *****/
/***** Recursive top-down placement *****/
/***** *****/
/**************************************************************************/
static struct nlist *curcell;
int permutation[MAX_LEAVES+1];
int TopDownStartLevel;
int leftnodes[MAX_NODES + 1];
int rightnodes[MAX_NODES + 1];
int PartitionFanout(int left, int right, int side)
/* returns number of pins for partition (left,right) */
/* has side-effect of setting up the leftnodes and rightnodes arrays;
these represent the integrated node usages for the left and right
partitions */
{
int i, E;
int ports;
int sum;
ports = 0;
for (i = 1; i <= Nodes; i++) {
sum = 0;
for (E = left; E <= right; E++) sum += CSTAR[permutation[E]][i];
/* save total node usage in 'leftnodes' and 'rightnodes' */
if (side == LEFT) leftnodes[i] = sum;
else rightnodes[i] = sum;
if (sum && (sum < CSTAR[0][i] || C[0][i])) ports ++;
}
return(ports);
}
#ifndef DBUG_OFF
void Dbug_print_cells(int left, int right)
{
int i;
Fprintf(DBUG_FILE,"(");
for (i = left; i <= right; i++) {
Fprintf(DBUG_FILE,"%s",
(InstanceNumber(curcell, permutation[i]))->instance);
if (i != right) Fprintf(DBUG_FILE," ");
}
Fprintf(DBUG_FILE,") ");
}
#endif
int FindOptimum(int left, int right, int *mynodes, int *othernodes)
{
int E, max, choice, i;
int gain[MAX_LEAVES + 1];
/* find the left optimum */
for (E = left; E <= right; E++) {
gain[E] = 0;
for (i = 1; i <= Nodes; i++) {
#ifdef BAD
if (C[permutation[E]][i] && mynodes[i] == 1) gain[E]++;
#else
/* remember: left,rightnodes built up from CSTAR */
if (C[permutation[E]][i] && mynodes[i] == CSTAR[permutation[E]][i])
gain[E]++;
#endif
else if (C[permutation[E]][i] && othernodes[i] == 0) gain[E]--;
}
}
max = 0;
choice = 0;
for (E = left; E <= right; E++) {
DBUG_PRINT("place",("gain for %d is %d", E, gain[E]));
if (gain[E] >= max) {
max = gain[E];
choice = E;
}
}
DBUG_EXECUTE("place", {Fprintf(DBUG_FILE, "\n");} );
return(choice);
}
int GradientDescent(int left, int right, int partition)
/* try to exchange pairs in the (left..partition) (partition+1..right) sets
in order to reduce the number of cut nodes */
/* returns 1 if a swap was possible */
{
int leftchoice, rightchoice;
int tmp;
#if 1
int E, leftmax, rightmax, i;
int gain[MAX_LEAVES + 1];
/* find the left optimum */
for (E = left; E <= partition; E++) {
gain[E] = 0;
for (i = 1; i <= Nodes; i++) {
#ifdef BAD
if (C[permutation[E]][i] && leftnodes[i] == 1) gain[E]++;
#else
if (C[permutation[E]][i] && leftnodes[i] == CSTAR[permutation[E]][i])
gain[E]++;
#endif
else if (C[permutation[E]][i] && rightnodes[i] == 0) gain[E]--;
}
}
leftmax = 0;
leftchoice = 0;
for (E = left; E <= partition; E++) {
DBUG_PRINT("place",("gain for %d is %d", E, gain[E]));
if (gain[E] >= leftmax) {
leftmax = gain[E];
leftchoice = E;
}
}
DBUG_EXECUTE("place", Fprintf(DBUG_FILE, "\n"); );
/* find the right optimum */
for (E = partition+1; E <= right; E++) {
gain[E] = 0;
for (i = 1; i <= Nodes; i++) {
#ifdef BAD
if (C[permutation[E]][i] && rightnodes[i] == 1) gain[E]++;
#else
if (C[permutation[E]][i] && rightnodes[i] == CSTAR[permutation[E]][i])
gain[E]++;
#endif
else if (C[permutation[E]][i] && leftnodes[i] == 0) gain[E]--;
}
}
rightmax = 0;
rightchoice = 0;
for (E = partition+1; E <= right; E++) {
DBUG_PRINT("place",("gain for %d is %d", E, gain[E]));
if (gain[E] >= rightmax) {
rightmax = gain[E];
rightchoice = E;
}
}
DBUG_EXECUTE("place", Fprintf(DBUG_FILE, "\n"); );
if (leftmax == 0 && rightmax == 0) return(0);
#else
leftchoice = FindOptimum(left, partition, leftnodes, rightnodes);
if (leftchoice == 0) return(0);
rightchoice = FindOptimum(partition+1, right, rightnodes, leftnodes);
if (rightchoice == 0) return(0);
#endif
DBUG_PRINT("place",("Swapping %s and %s",
(InstanceNumber(curcell,permutation[leftchoice]))->instance,
(InstanceNumber(curcell,permutation[rightchoice]))->instance));
#ifdef BAD
tmp = permutation[leftchoice];
permutation[leftchoice] = permutation[rightchoice];
permutation[rightchoice] = tmp;
/* update node usage lists */
for (tmp = 1; tmp <= Nodes; tmp++) {
if (C[permutation[leftchoice]][tmp]) {
leftnodes[tmp] -= C[permutation[leftchoice]][tmp];
rightnodes[tmp] += C[permutation[leftchoice]][tmp];
}
if (C[permutation[rightchoice]][tmp]) {
leftnodes[tmp] += C[permutation[rightchoice]][tmp];
rightnodes[tmp] -= C[permutation[rightchoice]][tmp];
}
}
#else
/* update node usage lists, remembering that CSTAR goes into leftnodes */
for (tmp = 1; tmp <= Nodes; tmp++) {
if (CSTAR[permutation[leftchoice]][tmp]) {
leftnodes[tmp] -= CSTAR[permutation[leftchoice]][tmp];
rightnodes[tmp] += CSTAR[permutation[leftchoice]][tmp];
}
if (CSTAR[permutation[rightchoice]][tmp]) {
leftnodes[tmp] += CSTAR[permutation[rightchoice]][tmp];
rightnodes[tmp] -= CSTAR[permutation[rightchoice]][tmp];
}
}
/* THEN swap the elements */
tmp = permutation[leftchoice];
permutation[leftchoice] = permutation[rightchoice];
permutation[rightchoice] = tmp;
#endif
return(1);
}
int GenerateGreedyPartition(int left, int right, int level)
/* tries to find a balanced partition, as far as leaf cell usage */
{
int i;
int head, tail;
int queue[MAX_LEAVES + 1];
char status[MAX_LEAVES + 1];
int IncludedElements;
#define QUEUED 1
#define INSIDE 2
#define OUTSIDE 3
#if 0
Printf("before GreedyPermutation\n");
for (i = left; i <= right; i++) Printf(" %d",permutation[i]);
Printf("\n");
#endif
memzero(status, sizeof(status));
for (i = left; i <= right; i++) status[permutation[i]] = OUTSIDE;
head = 0;
tail = 0;
IncludedElements = 0;
while (IncludedElements <= (right - left) / 2) {
int element;
element = level; /* keep the compiler from bitching */
if (head != tail) element = queue[head++];
else {
/* start from some random element */
for (i = left; i <= right; i++) {
if (status[permutation[i]] == OUTSIDE) {
element = permutation[i];
break;
}
}
}
status[element] = INSIDE;
IncludedElements++;
for (i = left; i <= right; i++) {
/* check to see if an element should be added to the queue */
if (status[permutation[i]] == QUEUED) continue;
if (status[permutation[i]] == INSIDE) continue;
/* otherwise, add it to the queue, if it has common nodes with element */
if (AnyCommonNodes(element, permutation[i])) {
status[permutation[i]] = QUEUED;
queue[tail++] = permutation[i];
}
}
}
/* at this point, status contains the list of elements, classified
as either INSIDE, OUTSIDE, or QUEUED. It is now easy to generate
a permutation.
*/
head = left;
tail = right;
for (i = 1; i <= Leaves; i++) {
if (status[i] == INSIDE) permutation[head++] = i;
else if (status[i] != 0) permutation[tail--] = i;
}
return (left + IncludedElements - 1);
#if 0
{
int leftsum, rightsum;
leftsum = rightsum = 0;
while (left < right) {
if (leftsum < rightsum) leftsum += POW2(LEVEL(permutation[left++]));
else rightsum += POW2(LEVEL(permutation[right--]));
}
if (leftsum > POW2(level) || rightsum > POW2(level)) {
Fprintf(stdout,"No valid partition found at level %d\n",level);
return(0);
}
return(left);
}
#endif
}
int GreedyPartition(int left, int right, int level)
/* return index of new element, if successful partition has been found */
{
int partition;
int iterations;
int found;
int OriginalNewN;
int leftelement, rightelement;
#define MAX_PARTITION_ITERATIONS 10
DBUG_ENTER("GreedyPartition");
OriginalNewN = NewN;
#if 0
if (level < 0) DBUG_RETURN(0);
#else
if (level < LEVEL(permutation[left])) {
Fprintf(stdout,"Failed at level %d; subtree too deep\n",level);
DBUG_RETURN(0);
}
#endif
if (left == right) DBUG_RETURN(permutation[left]);
/* use a greedy algorithm to gather elements, starting at 'left',
until about 1/2 have been collected. Then check to see if
it is valid
*/
/* DBUG_PRINT("place",("trying to partition %d, %d",left,right)); */
iterations = 0;
do {
int i;
int leftfanout, rightfanout;
iterations++;
partition = GenerateGreedyPartition(left, right, level);
if (partition == 0) DBUG_RETURN(0); /* no valid partition */
found = 0;
leftfanout = PartitionFanout(left,partition,LEFT);
rightfanout = PartitionFanout(partition+1, right, RIGHT);
if (leftfanout <= TreeFanout[level] && rightfanout <= TreeFanout[level])
found = 1;
if (!found || level > TopDownStartLevel - 2) {
for (i = MAX_TREE_DEPTH; i > level; i--) Fprintf(stdout, " ");
Fprintf(stdout,
"Level: %d; L (%d leaves) fanout %d; R (%d leaves) fanout %d (<= %d) %s\n",
level, (partition - left + 1), leftfanout,
(right - partition), rightfanout, TreeFanout[level],
found ? "SUCCESSFUL" : "UNSUCCESSFUL");
}
if (!found) {
int IterationLimit;
for (IterationLimit = 0; IterationLimit < 20 &&
GradientDescent(left, right, partition); IterationLimit++);
found = 0;
leftfanout = PartitionFanout(left,partition,LEFT);
rightfanout = PartitionFanout(partition+1, right, RIGHT);
if (leftfanout <= TreeFanout[level] && rightfanout <= TreeFanout[level])
found = 1;
for (i = MAX_TREE_DEPTH; i > level; i--) Fprintf(stdout, " ");
Fprintf(stdout,
" Iteration %2d: L fanout %d; R fanout %d (<= %d) %s\n",
iterations, leftfanout, rightfanout, TreeFanout[level],
found ? "SUCCESSFUL" : "UNSUCCESSFUL");
}
DBUG_EXECUTE("place",
Fprintf(DBUG_FILE,"Level %d: ",level);
Dbug_print_cells(left,partition);
Dbug_print_cells(partition+1,right);
Fprintf(DBUG_FILE,"\n");
{
int i;
Fprintf(DBUG_FILE,"L ");
for (i = 1; i <= Nodes; i++)
Fprintf(DBUG_FILE,"%2d ",leftnodes[i]);
Fprintf(DBUG_FILE,"\nR ");
for (i = 1; i <= Nodes; i++)
Fprintf(DBUG_FILE,"%2d ",rightnodes[i]);
Fprintf(DBUG_FILE,"\n");
}
Fprintf(DBUG_FILE, "%s\n", found?"SUCCESSFUL":"UNSUCCESSFUL");
);
} while (iterations < MAX_PARTITION_ITERATIONS && !found);
if (!found) {
Fprintf(stdout,"Failed embedding at level %d; no partition\n",level);
goto fail;
}
leftelement = GreedyPartition(left, partition, level-1);
if (leftelement == 0) goto fail;
rightelement = GreedyPartition(partition+1, right, level-1);
if (rightelement == 0) goto fail;
/* add it to the list */
AddNewElement(leftelement, rightelement);
DBUG_RETURN(NewN);
fail:
NewN = OriginalNewN;
DBUG_RETURN(0);
}
void TopDownEmbedCell(char *cellname, char *filename,
enum EmbeddingStrategy strategy)
{
struct nlist *tp;
int i;
int Found;
float StartTime;
tp = LookupCell(cellname);
curcell = tp;
if (!OpenEmbeddingFile(cellname, filename)) return;
StartTime = CPUTime();
if (!InitializeMatrices(cellname)) return;
NewN = Elements;
for (i = 1; i <= Leaves; i++) permutation[i] = i;
RandomSeed(1);
Found = 0;
TopDownStartLevel = MAX_TREE_DEPTH;
switch (strategy) {
case random_embedding:
Found = RandomPartition(1, Leaves, TopDownStartLevel);
break;
case greedy:
Found = GreedyPartition(1, Leaves, TopDownStartLevel);
break;
case anneal:
Found = AnnealPartition(1, Leaves, TopDownStartLevel);
break;
case bottomup:
Fprintf(stderr,"ERROR: called TopDownEmbedCell with bottomup strategy\n");
break;
}
if (Found) {
Printf ("successful embedding (Element %d) (time = %.2f s):\n",
NewN, ElapsedCPUTime(StartTime));
#if 0
for (i = 1; i <= Leaves; i++) Printf("%d ",permutation[i]);
Printf("\n");
#endif
#if 1
PrintE(stdout,NewN);
Printf("\n");
#endif
FreeEmbeddingTree((struct embed *)(tp->embedding));
tp->embedding = EmbeddingTree(tp, Found);
PrintEmbeddingTree(stdout,cellname,1);
PrintEmbeddingTree(outfile,cellname,1);
if (logging) PrintEmbeddingTree(logfile,cellname,1);
}
else {
Fprintf(stdout,"No embedding found. Sorry.\n");
Fprintf(outfile,"No embedding found. Sorry.\n");
if (logging) Fprintf(logfile,"No embedding found. Sorry.\n");
}
CloseEmbeddingFile();
}

393
base/hash.c Normal file
View File

@ -0,0 +1,393 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* hash.c -- hash table support functions */
#include "config.h"
#include <stdio.h>
#ifdef IBMPC
#include <alloc.h>
#endif
#include "netgen.h"
#include "hash.h"
#include "objlist.h"
unsigned long (*hashfunc)(char *, int) = NULL;
int (*matchfunc)(char *, char *) = NULL;
int (*matchintfunc)(char *, char *, int, int) = NULL;
void InitializeHashTable(struct hashlist **tab, int size)
{
int i;
for (i = 0; i < size; i++) tab[i] = NULL;
}
int RecurseHashTable(struct hashlist **hashtab, int hashsize,
int (*func)(struct hashlist *elem))
/* returns the sum of the return values of (*func) */
{
int i, sum;
struct hashlist *p;
sum = 0;
for (i = 0; i < hashsize; i++)
for (p = hashtab[i]; p != NULL; p = p->next)
sum += (*func)(p);
return(sum);
}
/* Variation on RecurseHashTable() that passes an additional
* type int value to the function.
*/
int RecurseHashTableValue(struct hashlist **hashtab, int hashsize,
int (*func)(struct hashlist *elem, int), int value)
{
int i, sum;
struct hashlist *p;
sum = 0;
for (i = 0; i < hashsize; i++)
for (p = hashtab[i]; p != NULL; p = p->next)
sum += (*func)(p, value);
return(sum);
}
/* Another variation on RecurseHashTable() that passes one pointer
* type value to the function, so that the pointer may be to a
* structure, allowing any number of values to be passed to the
* function through that structure.
*/
struct nlist *RecurseHashTablePointer(struct hashlist **hashtab, int hashsize,
struct nlist *(*func)(struct hashlist *elem, void *),
void *pointer)
{
int i;
struct hashlist *p;
struct nlist *tp;
for (i = 0; i < hashsize; i++) {
for (p = hashtab[i]; p != NULL; p = p->next) {
tp = (*func)(p, pointer);
if (tp != NULL) return tp;
}
}
return NULL;
}
int CountHashTableEntries(struct hashlist *p)
{
/* not strictly needed, but stops compiler from bitching */
return ((p != NULL) ? 1:0);
}
int CountHashTableBinsUsed(struct hashlist *p)
{
if (p->next == NULL) return (1);
return(0);
}
static unsigned char uppercase[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
};
// Hash functions of the stupid-simple accumulate-the-character-codes
// method replaced by the more sophisticated SDBM hash. Otherwise
// horrible things can happen, as, for example, names AOI12 and OAI12
// have exactly the same hash result. Lousy for binning and even
// lousier for generating class magic numbers.
unsigned long hashnocase(char *s, int hashsize)
{
unsigned long hashval;
for (hashval = 0; *s != '\0'; )
hashval = uppercase[*s++]
+ (hashval << 6) + (hashval << 16) - hashval;
return (hashsize == 0) ? hashval : (hashval % hashsize);
}
unsigned long hash(char *s, int hashsize)
{
unsigned long hashval;
for (hashval = 0; *s != '\0'; )
hashval = (*s++) + (hashval << 6) + (hashval << 16) - hashval;
return (hashsize == 0) ? hashval : (hashval % hashsize);
}
/*----------------------------------------------------------------------*/
/* HashLookup -- */
/* return the 'ptr' field of the hash table entry, or NULL if not found */
/*----------------------------------------------------------------------*/
void *HashLookup(char *s, struct hashlist **hashtab, int hashsize)
{
struct hashlist *np;
unsigned long hashval;
hashval = (*hashfunc)(s, hashsize);
for (np = hashtab[hashval]; np != NULL; np = np->next)
if ((*matchfunc)(s, np->name)) return (np->ptr); /* correct match */
return (NULL); /* not found */
}
/*----------------------------------------------------------------------*/
/* HashIntLookup -- */
/* return the 'ptr' field of the hash table entry, or NULL if not found */
/* HashIntLookup treats *ptr as an integer and compares it to the */
/* passed integer value i */
/*----------------------------------------------------------------------*/
void *HashIntLookup(char *s, int i, struct hashlist **hashtab, int hashsize)
{
struct hashlist *np;
unsigned long hashval;
hashval = (*hashfunc)(s, hashsize);
for (np = hashtab[hashval]; np != NULL; np = np->next) {
if (np->ptr == NULL) {
if ((*matchintfunc)(s, np->name, i, -1))
return NULL;
}
else {
if ((*matchintfunc)(s, np->name, i, (int)(*((int *)np->ptr))))
return (np->ptr); /* correct match */
}
}
return (NULL); /* not found */
}
/*----------------------------------------------------------------------*/
/* return the hashlist entry, after (re)initializing its 'ptr' field */
/*----------------------------------------------------------------------*/
struct hashlist *HashPtrInstall(char *name, void *ptr,
struct hashlist **hashtab, int hashsize)
{
struct hashlist *np;
unsigned long hashval;
hashval = (*hashfunc)(name,hashsize);
for (np = hashtab[hashval]; np != NULL; np = np->next)
if ((*matchfunc)(name, np->name)) {
np->ptr = ptr;
return (np); /* match found in hash table */
}
/* not in table, so install it */
if ((np = (struct hashlist *) CALLOC(1,sizeof(struct hashlist))) == NULL)
return (NULL);
if ((np->name = strsave(name)) == NULL) return (NULL);
np->ptr = ptr;
np->next = hashtab[hashval];
return(hashtab[hashval] = np);
}
/*----------------------------------------------------------------------*/
/* Like HashLookup, a separate routine is needed when using an */
/* additional value for the matching. */
/*----------------------------------------------------------------------*/
struct hashlist *HashIntPtrInstall(char *name, int value, void *ptr,
struct hashlist **hashtab, int hashsize)
{
struct hashlist *np;
unsigned long hashval;
hashval = (*hashfunc)(name,hashsize);
for (np = hashtab[hashval]; np != NULL; np = np->next)
if ((*matchintfunc)(name, np->name, value, (int)(*((int *)np->ptr)))) {
np->ptr = ptr;
return (np); /* match found in hash table */
}
/* not in table, so install it */
if ((np = (struct hashlist *) CALLOC(1,sizeof(struct hashlist))) == NULL)
return (NULL);
if ((np->name = strsave(name)) == NULL) return (NULL);
np->ptr = ptr;
np->next = hashtab[hashval];
return(hashtab[hashval] = np);
}
/*----------------------------------------------------------------------*/
/* destroy a hash table, freeing associated memory */
/*----------------------------------------------------------------------*/
void *HashKill(struct hashlist **hashtab, int hashsize)
{
struct hashlist *np, *p;
int i;
for (i = 0; i < hashsize; i++) {
for (p = hashtab[i]; p != NULL; ) {
np = p->next;
FREE(p->name);
FREE(p);
p = np;
}
}
}
/*----------------------------------------------------------------------*/
/* Basic hash install, leaving a NULL pointer but returning a pointer */
/* to the new hash entry. */
/*----------------------------------------------------------------------*/
struct hashlist *HashInstall(char *name,
struct hashlist **hashtab, int hashsize)
{
struct hashlist *np;
unsigned long hashval;
hashval = (*hashfunc)(name,hashsize);
for (np = hashtab[hashval]; np != NULL; np = np->next)
if ((*matchfunc)(name, np->name)) return (np); /* match found in hash table */
/* not in table, so install it */
if ((np = (struct hashlist *) CALLOC(1,sizeof(struct hashlist))) == NULL)
return (NULL);
if ((np->name = strsave(name)) == NULL) return (NULL);
np->ptr = NULL;
np->next = hashtab[hashval];
return(hashtab[hashval] = np);
}
/*----------------------------------------------------------------------*/
/* frees a hash table entry, (but not the 'ptr' field) */
/*----------------------------------------------------------------------*/
void HashDelete(char *name, struct hashlist **hashtab, int hashsize)
{
unsigned long hashval;
struct hashlist *np;
struct hashlist *np2;
hashval = (*hashfunc)(name, hashsize);
np = hashtab[hashval];
if (np == NULL) return;
if ((*matchfunc)(name, np->name)) {
/* it is the first element in the list */
hashtab[hashval] = np->next;
FREE(np->name);
FREE(np);
return;
}
/* else, traverse the list, deleting the appropriate element */
while (np->next != NULL) {
if ((*matchfunc)(name, np->next->name)) {
np2 = np->next;
np->next = np2->next;
FREE(np2->name);
FREE(np2);
return;
}
np = np->next;
}
}
/*----------------------------------------------------------------------*/
/* HashDelete with additional integer value matching */
/*----------------------------------------------------------------------*/
void HashIntDelete(char *name, int value, struct hashlist **hashtab, int hashsize)
{
unsigned long hashval;
struct hashlist *np;
struct hashlist *np2;
hashval = (*hashfunc)(name, hashsize);
np = hashtab[hashval];
if (np == NULL) return;
if ((*matchintfunc)(name, np->name, value, (int)(*((int *)np->ptr)))) {
/* it is the first element in the list */
hashtab[hashval] = np->next;
FREE(np->name);
FREE(np);
return;
}
/* else, traverse the list, deleting the appropriate element */
while (np->next != NULL) {
if ((*matchintfunc)(name, np->next->name, value,
(int)(*((int *)np->next->ptr)))) {
np2 = np->next;
np->next = np2->next;
FREE(np2->name);
FREE(np2);
return;
}
np = np->next;
}
}
/*----------------------------------------------------------------------*/
static int hashfirstindex; /* was long */
static struct hashlist *hashfirstptr;
void *HashNext(struct hashlist **hashtab, int hashsize)
/* returns 'ptr' field of next element, NULL when done */
{
if (hashfirstptr != NULL && hashfirstptr->next != NULL) {
hashfirstptr = hashfirstptr->next;
return(hashfirstptr->ptr);
}
while (hashfirstindex < hashsize) {
if ((hashfirstptr = hashtab[hashfirstindex++]) != NULL) {
return(hashfirstptr->ptr);
}
}
hashfirstindex = 0;
hashfirstptr = NULL;
return(NULL);
}
void *HashFirst(struct hashlist **hashtab, int hashsize)
{
hashfirstindex = 0;
hashfirstptr = NULL;
return(HashNext(hashtab,hashsize));
}

49
base/hash.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef _HASH_H
#define _HASH_H
struct hashlist {
char *name;
void *ptr;
struct hashlist *next;
};
extern void InitializeHashTable(struct hashlist **tab, int size);
extern int RecurseHashTable(struct hashlist **hashtab, int hashsize,
int (*func)(struct hashlist *elem));
extern int RecurseHashTableValue(struct hashlist **hashtab, int hashsize,
int (*func)(struct hashlist *elem, int), int);
extern struct nlist *RecurseHashTablePointer(struct hashlist **hashtab,
int hashsize, struct nlist *(*func)(struct hashlist *elem,
void *), void *pointer);
extern int CountHashTableEntries(struct hashlist *p);
extern int CountHashTableBinsUsed(struct hashlist *p);
extern void HashDelete(char *name, struct hashlist **hashtab, int hashsize);
extern void HashIntDelete(char *name, int value, struct hashlist **hashtab,
int hashsize);
/* these functions return a pointer to a hash list element */
extern struct hashlist *HashInstall(char *name, struct hashlist **hashtab,
int hashsize);
extern struct hashlist *HashPtrInstall(char *name, void *ptr,
struct hashlist **hashtab, int hashsize);
extern struct hashlist *HashIntPtrInstall(char *name, int value, void *ptr,
struct hashlist **hashtab, int hashsize);
/* these functions return the ->ptr field of a struct hashlist */
extern void *HashLookup(char *s, struct hashlist **hashtab, int hashsize);
extern void *HashIntLookup(char *s, int i, struct hashlist **hashtab, int hashsize);
extern void *HashFirst(struct hashlist **hashtab, int hashsize);
extern void *HashNext(struct hashlist **hashtab, int hashsize);
extern unsigned long hashnocase(char *s, int hashsize);
extern unsigned long hash(char *s, int hashsize);
extern int (*matchfunc)(char *, char *);
/* matchintfunc() compares based on the name and the first */
/* entry of the pointer value, which is cast as an integer */
extern int (*matchintfunc)(char *, char *, int, int);
extern unsigned long (*hashfunc)(char *, int);
#endif /* _HASH_H */

47
base/inetcomp.c Normal file
View File

@ -0,0 +1,47 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* inetcomp.c -- a simple wrapper to the NETCOMP() function */
#include <stdio.h>
#include "netgen.h"
#ifdef HAVE_GETOPT
#include <unistd.h>
#endif /* HAVE_GETOPT */
void STRCPY(char *dest, char *source)
{
while ((*dest++ = *source++) != '\0') ;
}
int main(int argc, char *argv[])
{
char cell1[200], cell2[200];
Debug = 0;
if (argc != 1) {
printf ("usage: inetcomp\n");
return (-1);
}
Initialize();
NETCOMP();
return(1);
}

5273
base/netcmp.c Normal file

File diff suppressed because it is too large Load Diff

54
base/netcmp.h Normal file
View File

@ -0,0 +1,54 @@
/* Exported global variables */
extern struct ElementClass *ElementClasses;
extern struct NodeClass *NodeClasses;
extern struct nlist *Circuit1;
extern struct nlist *Circuit2;
extern int ExhaustiveSubdivision;
#ifdef TCL_NETGEN
extern int InterruptPending;
#endif
/* Exported procedures */
extern void PrintElementClasses(struct ElementClass *EC, int type, int dolist);
extern void PrintNodeClasses(struct NodeClass *NC, int type, int dolist);
extern void SummarizeNodeClasses(struct NodeClass *NC);
extern void PrintPropertyResults(void);
extern void PrintCoreStats(void);
extern void ResetState(void);
extern void CreateTwoLists(char *name1, int file1, char *name2, int file2);
extern int Iterate(void);
extern int VerifyMatching(void);
extern void PrintAutomorphisms(void);
extern int ResolveAutomorphisms(void);
extern void PermuteAutomorphisms(void);
extern int Permute(void);
extern int PermuteSetup(char *model, int filenum, char *pin1, char *pin2);
extern int PermuteForget(char *model, int filenum, char *pin1, char *pin2);
extern int EquivalenceElements(char *name1, int file1, char *name2, int file2);
extern int EquivalenceNodes(char *name1, int file1, char *name2, int file2);
extern int EquivalenceClasses(char *name1, int file1, char *name2, int file2);
extern int IgnoreClass(char *name, int file);
extern int MatchPins(struct nlist *tp1, struct nlist *tp2);
extern int CreateCompareQueue(char *, int, char *, int);
extern int GetCompareQueueTop(char **, int *, char **, int *);
extern int PeekCompareQueueTop(char **, int *, char **, int *);
extern void RemoveCompareQueue();
extern void PrintIllegalClasses();
extern void PrintIllegalNodeClasses();
extern void PrintIllegalElementClasses();
#ifdef TCL_NETGEN
extern int EquivalentNode();
extern int EquivalentElement();
extern void enable_interrupt();
extern void disable_interrupt();
#endif

879
base/netfile.c Normal file
View File

@ -0,0 +1,879 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* netfile.c -- support routines for reading/writing netlist files */
#include "config.h"
#define FILE_ACCESS_BITS 0777
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/fcntl.h> /* for SGI */
#ifdef IBMPC
#include <stdlib.h> /* for calloc */
#endif
#ifdef TCL_NETGEN
#include <tcl.h>
#endif
#include "netgen.h"
#include "hash.h"
#include "objlist.h"
#include "netfile.h"
#include "print.h"
static char buffer[LINELENGTH] = ""; /* buffer for FlushString */
int AutoFillColumn = LINELENGTH; /* enable wraparound at LINELENGTH */
static FILE *outfile;
static int Graph = 0;
int File;
extern char *SetExtension(char *buffer, char *path, char *extension)
/* add 'extension' to 'path' (overwriting previous extension, if any),
write it into buffer (if buffer is null, malloc a buffer).
return address of buffer. NOTE: it is SAFE to pass the same
address as 'path' and as 'buffer', since an internal buffer is used.
*/
{
char tmpbuf[500];
char *pt;
strcpy(tmpbuf, path);
/* step 1: find the last directory delimiter */
#ifdef IBMPC
pt = strrchr(tmpbuf, '\\');
#else
pt = strrchr(tmpbuf, '/');
#endif
/* if none exists, point to the start of the buffer */
if (pt == NULL) pt = tmpbuf;
/* step 2: search to the right, for a '.' */
pt = strrchr(pt, '.');
if (pt != NULL) *pt = '\0';
/* step 3: add on the desired extension */
strcat(tmpbuf, extension);
/* step 4: lower-case the entire name */
for (pt = tmpbuf; *pt != '\0'; pt++)
if (isupper(*pt)) *pt = tolower(*pt);
if (buffer != NULL) {
strcpy(buffer, tmpbuf);
return(buffer);
}
return (strsave(tmpbuf));
}
int IsPortInPortlist(struct objlist *ob, struct nlist *tp)
/* returns true if ob points to an object that
1) is the "best" name for that port
2) has the same node number as a port
*/
{
struct objlist *ob2;
#if 1
int node;
if (!match(ob->name, NodeAlias(tp, ob))) return (0);
node = ob->node;
for (ob2 = tp->cell; ob2 != NULL; ob2 = ob2->next)
if ((ob2->node == node) && IsPort(ob2)) return(1);
return (0);
#else
int isaport;
if (!match(ob->name, NodeName(tp, ob->node))) return (0);
isaport = 0;
ob2 = tp->cell;
while (ob2 != NULL) {
if ((ob2->node == ob->node) && IsPort(ob2)) isaport = 1;
ob2 = ob2->next;
}
return (isaport);
#endif
}
void FlushString (char *format, ...)
{
va_list argptr;
char tmpstr[1000];
va_start(argptr, format);
vsprintf(tmpstr, format, argptr);
va_end(argptr);
if (AutoFillColumn) {
if (strlen(buffer) + strlen(tmpstr) + 1 > AutoFillColumn) {
fprintf(outfile, "%s\n", buffer);
strcpy(buffer, " ");
}
strcat(buffer, tmpstr);
if (strchr(buffer, '\n') != NULL) {
fprintf(outfile, "%s", buffer);
strcpy(buffer, "");
}
}
else {
/* check to see if anything is buffered up first */
if (strlen(buffer)) {
fprintf(outfile, "%s", buffer);
strcpy(buffer,"");
}
fprintf(outfile, "%s", tmpstr);
}
}
int OpenFile(char *filename, int linelen)
{
if (linelen < LINELENGTH) AutoFillColumn = linelen;
else AutoFillColumn = LINELENGTH;
if (strlen(filename) > 0) {
outfile = fopen(filename, "w");
return (outfile != NULL);
}
outfile = stdout;
return(1);
}
void CloseFile(char *filename)
{
if (strlen(filename) > 0)
fclose(outfile);
}
/* STUFF TO READ INPUT FILES */
static char *line = NULL; /* actual line read in */
static char *linetok; /* line copied to this, then munged by strtok */
static int linesize = 0; /* amount of memory allocated for line */
static int linenum;
char *nexttok;
static FILE *infile = NULL;
/* For purposes of having "include" files, keep a stack of the open */
/* files. */
struct filestack {
FILE *file;
struct filestack *next;
};
static struct filestack *OpenFiles = NULL;
#define TOKEN_DELIMITER " \t\n\r"
/*----------------------------------------------------------------------*/
/* GetNextLineNoNewline() */
/* */
/* Fetch the next line, and grab the first token from the next line. */
/* If there is no next token (next line is empty, and ends with a */
/* newline), then place NULL in nexttok. */
/* */
/*----------------------------------------------------------------------*/
int GetNextLineNoNewline()
{
char *newbuf;
if (feof(infile)) return -1;
if (linesize == 0) {
/* Allocate memory for line */
linesize = 500;
line = (char *)MALLOC(linesize);
linetok = (char *)MALLOC(linesize);
}
fgets(line, linesize, infile);
while (strlen(line) == linesize - 1) {
newbuf = (char *)MALLOC(linesize + 500);
strcpy(newbuf, line);
FREE(line);
line = newbuf;
fgets(line + linesize - 1, 501, infile);
linesize += 500;
FREE(linetok);
linetok = (char *)MALLOC(linesize);
}
linenum++;
strcpy(linetok, line);
nexttok = strtok(linetok, TOKEN_DELIMITER);
return 0;
}
/*----------------------------------------------------------------------*/
/* Get the next line of input from file "infile", and find the first */
/* valid token. */
/*----------------------------------------------------------------------*/
void GetNextLine()
{
do {
if (GetNextLineNoNewline() == -1) return;
} while (nexttok == NULL);
}
/*----------------------------------------------------------------------*/
/* if nexttok is already NULL, force scanner to read new line */
/*----------------------------------------------------------------------*/
void SkipTok(void)
{
if (nexttok != NULL &&
(nexttok = strtok(NULL, TOKEN_DELIMITER)) != NULL) return;
GetNextLine();
}
/*----------------------------------------------------------------------*/
/* like SkipTok, but will not fetch a new line when the buffer is empty */
/* must be preceeded by at least one call to SkipTok() */
/*----------------------------------------------------------------------*/
void SkipTokNoNewline(void)
{
nexttok = strtok(NULL, TOKEN_DELIMITER);
}
/*----------------------------------------------------------------------*/
/* if the next token ends the line, then this routine will check the */
/* first character only of the next line. If "+", then it will pass */
/* that token and find the next token; otherwise, it backs up. */
/* Must be preceeded by at least one call to SkipTok() */
/* */
/* Modified 3/17/2015 to handle the case where a line may be followed */
/* by "+" (continuation line) but without anything on the continuation */
/* line. At each end-of-line, the next line must be checked for either */
/* a continuation line or a valid token. */
/* */
/* Modified 3/30/2015 to include the condition where a comment line is */
/* in the middle of a series of continuation lines. */
/*----------------------------------------------------------------------*/
void SpiceTokNoNewline(void)
{
int contline;
if ((nexttok = strtok(NULL, TOKEN_DELIMITER)) != NULL) return;
while (nexttok == NULL) {
contline = getc(infile);
if (contline == '*') {
GetNextLine();
SkipNewLine();
continue;
}
else if (contline != '+') {
ungetc(contline, infile);
return;
}
GetNextLineNoNewline();
}
}
/*----------------------------------------------------------------------*/
/* skip to the end of the current line */
/*----------------------------------------------------------------------*/
void SkipNewLine(void)
{
while (nexttok != NULL) nexttok = strtok(NULL, TOKEN_DELIMITER);
}
/*----------------------------------------------------------------------*/
/* skip to the end of the current line, also skipping over any */
/* continuation lines beginning with "+" (SPICE syntax) */
/*----------------------------------------------------------------------*/
void SpiceSkipNewLine(void)
{
int contline;
SkipNewLine();
contline = getc(infile);
while (contline == '+') {
ungetc(contline, infile);
GetNextLine();
SkipNewLine();
contline = getc(infile);
}
ungetc(contline, infile);
}
/*----------------------------------------------------------------------*/
void InputParseError(FILE *f)
{
char *ch;
Fprintf(f,"line number %d = '", linenum);
for (ch = line; *ch != '\0'; ch++) {
if (isprint(*ch)) Fprintf(f, "%c", *ch);
else if (*ch != '\n') Fprintf(f,"<<%d>>", (int)(*ch));
}
Fprintf(f,"'\n");
}
/*----------------------------------------------------------------------*/
int OpenParseFile(char *name, int fnum)
{
/* Push filestack */
FILE *locfile;
struct filestack *newfile;
locfile = fopen(name,"r");
linenum = 0;
/* reset the token scanner */
nexttok = NULL;
if (locfile != NULL) {
if (infile != NULL) {
newfile = (struct filestack *)MALLOC(sizeof(struct filestack));
newfile->file = infile;
newfile->next = OpenFiles;
OpenFiles = newfile;
}
infile = locfile;
if (fnum != -1)
return fnum;
else if (OpenFiles == NULL)
return Graph++;
else
return Graph;
}
return -1;
}
int EndParseFile(void)
{
return (feof(infile));
}
int CloseParseFile(void)
{
struct filestack *lastfile;
int rval;
rval = fclose(infile);
infile = (FILE *)NULL;
/* Pop filestack if not empty */
lastfile = OpenFiles;
if (lastfile != NULL) {
OpenFiles = lastfile->next;
infile = lastfile->file;
FREE(lastfile);
}
return rval;
}
/*************************** general file reader *******************/
char *ReadNetlist(char *fname, int *fnum)
{
int index, filenum;
struct filetype {
char *extension;
char *(*proc)(char *, int *);
};
#ifdef mips
struct filetype formats[6];
formats[0].extension = NTK_EXTENSION;
formats[0].proc = ReadNtk;
formats[1].extension = EXT_EXTENSION;
formats[1].proc = ReadExtHier;
formats[2].extension = SIM_EXTENSION;
formats[2].proc = ReadSim;
formats[3].extension = SPICE_EXTENSION;
formats[3].proc = ReadSpice;
formats[4].extension = NETGEN_EXTENSION;
formats[4].proc = ReadNetgenFile;
formats[5].extension = NULL;
formats[5].proc = NULL;
#else /* not mips (i.e. compiler with reasonable initializers) */
struct filetype formats[] =
{
{NTK_EXTENSION, ReadNtk},
{EXT_EXTENSION, ReadExtHier},
{SIM_EXTENSION, ReadSim},
{SPICE_EXTENSION, ReadSpice},
{SPICE_EXT2, ReadSpice},
{SPICE_EXT3, ReadSpice},
{NETGEN_EXTENSION, ReadNetgenFile},
{NULL, NULL}
};
#endif /* not mips */
/* make first pass looking for extension */
for (index = 0; formats[index].extension != NULL; index++) {
if (strstr(fname, formats[index].extension) != NULL) {
return (*(formats[index].proc))(fname, fnum);
}
}
/* try appending extensions in sequence, and testing for file existance */
for (index = 0; formats[index].extension != NULL; index++) {
char testname[200];
strcpy(testname, fname);
strcat(testname, formats[index].extension);
if (OpenParseFile(testname, *fnum) >= 0) {
CloseParseFile();
return (*(formats[index].proc))(testname, fnum);
}
}
/* Check to see if file exists */
if (OpenParseFile(fname, *fnum) >= 0) {
char test[3];
/* SPICE files have many extensions. Look for first character "*" */
if (fgets(test, 2, infile) == NULL) test[0] = '\0';
CloseParseFile();
if (test[0] == '*') { /* Probably a SPICE deck */
return ReadSpice(fname, fnum);
}
else if (test[0] == '|') { /* Probably a sim netlist */
return ReadSim(fname, fnum);
}
else {
Printf("ReadNetlist: don't know type of file '%s'\n",fname);
*fnum = -1;
return NULL;
}
}
Printf("ReadNetlist: unable to find file '%s'\n",fname);
*fnum = -1;
return NULL;
}
/*************************** simple NETGEN format ******************/
/* define the following for SLOW, but portable format */
/* #define USE_PORTABLE_FILE_FORMAT */
/* define the following if we are to buffer reads */
#define BUFFER_READS
#ifdef USE_PORTABLE_FILE_FORMAT
/* the following routines use streams, and are portable but slow */
void NetgenFileCell(char *name)
{
struct nlist *tp, *tp2;
struct objlist *ob;
tp = LookupCell(name);
if (tp == NULL) {
Printf("No cell '%s' found.\n", name);
return;
}
/* do NOT dump primitive cells */
if (tp->class != CLASS_SUBCKT)
return;
/* check to see that all children have been dumped */
for (ob = tp->cell; ob != NULL; ob = ob->next) {
tp2 = LookupCell(ob->model.class);
if ((tp2 != NULL) && !(tp2->dumped))
NetgenFileCell(tp2->name);
}
FlushString("Cell: %s\n", name);
for (ob = tp->cell; ob != NULL; ob = ob->next) {
FlushString(" %s %d %d ", ob->name, ob->node, ob->type);
if (ob->type >= FIRSTPIN) FlushString("%s %s",ob->model.class, ob->instance.name);
FlushString("\n");
}
FlushString("EndCell: %s\n\n", name);
tp->dumped = 1; /* set dumped flag */
}
void WriteNetgenFile(char *name, char *filename)
{
char FileName[500];
if (filename == NULL || strlen(filename) == 0)
SetExtension(FileName, name, NETGEN_EXTENSION);
else
SetExtension(FileName, filename, NETGEN_EXTENSION);
if (!OpenFile(FileName, 80)) {
Printf("Unable to open NETGEN file %s\n", FileName);
return;
}
ClearDumpedList();
/* create top level call */
if (LookupCell(name) != NULL) NetgenFileCell(name);
CloseFile(FileName);
}
char *ReadNetgenFile (char *fname, int *fnum)
{
char name[100];
char *LastCellRead = NULL;
int filenum;
if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
SetExtension(name, fname, NETGEN_EXTENSION);
if ((filenum = OpenParseFile(name, *fnum)) < 0) {
Printf("No file: %s\n",name);
*fnum = -1;
return NULL;
}
}
while (!feof(infile)) {
char string[400];
fscanf(infile, "%400s", string);
if (feof(infile)) break; /* out of while loop */
if (match(string,"Cell:")) {
fscanf(infile, "%400s", string);
CellDef(string, -1);
LastCellRead = CurrentCell->name;
while (1) {
struct objlist *ob;
fscanf(infile,"%400s",string);
if (match(string,"EndCell:")) {
fscanf(infile,"%400s", string); /* get extra cell name */
break; /* get out of inner while loop */
}
if (feof(infile)) break; /* something awful happened */
/* it must be an object */
ob = (struct objlist *)CALLOC(1,sizeof(struct objlist));
ob->name = strsave(string);
fscanf(infile,"%d",&(ob->node));
fscanf(infile,"%d",&(ob->type));
if (ob->type >= FIRSTPIN) {
fscanf(infile,"%400s",string);
ob->model.class = strsave(string);
fscanf(infile,"%400s",string);
ob->instance.name = strsave(string);
}
else {
ob->model.class = strsave(" ");
ob->instance.name = strsave(" ");
}
if (ob->type == FIRSTPIN) {
if (NULL == LookupCell(ob->model.class))
Printf("WARING: instance of non-existant cell: %s\n", ob->model.class);
AddInstanceToCurrentCell(ob);
CurrentCell->class = CLASS_SUBCKT; /* there is at least one instance */
}
AddToCurrentCell(ob);
}
EndCell();
}
}
CloseParseFile();
*fnum = filenum;
return LastCellRead;
}
#else /* don't use PORTABLE_FILE_FORMAT */
/* the following versions use binary files and are non-portable, but fast */
#ifdef IBMPC
#include <io.h> /* read, write */
#include <fcntl.h>
#else /* not IBMPC */
#ifdef VMUNIX
#ifdef BSD
#include <sys/file.h>
#include <sys/types.h>
#include <sys/uio.h>
#else /* not BSD */
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <fcntl.h>
#endif /* not BSD */
#endif /* VMUNIX */
#endif /* IBMPC */
#define END_OF_CELL 0x0fff
#define N_BYTE_ORDER 0x0102
void NetgenFileCell(char *name)
{
struct nlist *tp, *tp2;
struct objlist *ob;
int len;
tp = LookupCell(name);
if (tp == NULL) {
Printf("No cell '%s' found.\n", name);
return;
}
/* do NOT dump primitive cells */
if (tp->class != CLASS_SUBCKT)
return;
/* check to see that all children have been dumped */
for (ob = tp->cell; ob != NULL; ob = ob->next) {
tp2 = LookupCell(ob->model.class);
if ((tp2 != NULL) && !(tp2->dumped))
NetgenFileCell(tp2->name);
}
len = strlen(name) + 1;
write(File, &len, sizeof(len));
write(File, name, len);
for (ob = tp->cell; ob != NULL; ob = ob->next) {
len = strlen(ob->name) + 1;
write(File, &len, sizeof(len));
write(File, ob->name, len);
write(File, &(ob->node), sizeof(ob->node));
write(File, &(ob->type), sizeof(ob->type));
if (ob->type >= FIRSTPIN) {
len = strlen(ob->model.class) + 1;
write(File, &len, sizeof(len));
write(File, ob->model.class, len);
len = strlen(ob->instance.name) + 1;
write(File, &len, sizeof(len));
write(File, ob->instance.name, len);
}
}
len = END_OF_CELL;
write(File,&len, sizeof(len));
tp->dumped = 1; /* set dumped flag */
}
void WriteNetgenFile(char *name, char *filename)
{
char FileName[500];
int i, filenum;
if (filename == NULL || strlen(filename) == 0)
SetExtension(FileName, name, NETGEN_EXTENSION);
else
SetExtension(FileName, filename, NETGEN_EXTENSION);
if ((filenum = open(FileName, O_WRONLY | O_CREAT | O_TRUNC,
FILE_ACCESS_BITS)) == -1) {
Printf("Unable to open NETGEN file %s\n", FileName);
return;
}
ClearDumpedList();
/* write out a sanity check */
i = N_BYTE_ORDER;
write(filenum, &i, sizeof(i));
write(filenum, &i, sizeof(i));
/* create top level call */
if (LookupCell(name) != NULL) NetgenFileCell(name);
close(File);
}
#ifdef BUFFER_READS
#define READ_BUFSIZ 5000
char *readbuf;
int bytes_in_buffer;
char *bufptr;
INLINE
int READ(void *buf, int bytes)
{
if (bytes_in_buffer >= bytes) {
memcpy(buf, bufptr, bytes);
bufptr += bytes;
bytes_in_buffer -= bytes;
return(bytes);
}
else {
#if 1
int chars;
/* need to refill buffer */
if (bufptr > readbuf + bytes_in_buffer) {
/* shift to front of buffer only if no overlap */
memcpy(readbuf, bufptr, bytes_in_buffer);
bufptr = readbuf + bytes_in_buffer;
}
chars = read(File, bufptr, READ_BUFSIZ - bytes_in_buffer);
bytes_in_buffer += chars;
if (bytes_in_buffer >= bytes) {
memcpy(buf, readbuf, bytes);
bufptr = readbuf + bytes;
bytes_in_buffer -= bytes;
return(bytes);
}
else {
memcpy(buf, readbuf, bytes_in_buffer);
bufptr = readbuf;
bytes = bytes_in_buffer;
bytes_in_buffer = 0;
return(bytes);
}
#else
int chars;
char tmpbuf[READ_BUFSIZ];
/* need to refill buffer */
memcpy(tmpbuf, bufptr, bytes_in_buffer); /* shift to front of buffer */
memcpy(readbuf, tmpbuf, bytes_in_buffer); /* use tmpbuf for safety */
bufptr = readbuf + bytes_in_buffer;
chars = read(File, bufptr, READ_BUFSIZ - bytes_in_buffer);
bytes_in_buffer += chars;
if (bytes_in_buffer >= bytes) {
memcpy(buf, readbuf, bytes);
bufptr = readbuf + bytes;
bytes_in_buffer -= bytes;
return(bytes);
}
else {
memcpy(buf, readbuf, bytes_in_buffer);
bufptr = readbuf;
bytes = bytes_in_buffer;
bytes_in_buffer = 0;
return(bytes);
}
#endif
}
}
#else
#define READ(buf, bytes) read(File, (buf), (bytes))
#endif
char *ReadNetgenFile (char *fname, int *fnum)
{
char name[100];
int len, chars;
char *LastCellRead = NULL;
if ((File = open(fname, O_RDONLY, FILE_ACCESS_BITS)) == -1) {
SetExtension(name, fname, NETGEN_EXTENSION);
if ((File = open(name, O_RDONLY, FILE_ACCESS_BITS)) == -1) {
Printf("No file: %s\n",name);
return NULL;
}
}
#ifdef BUFFER_READS
readbuf = (char *)MALLOC(READ_BUFSIZ);
bytes_in_buffer = 0;
bufptr = readbuf;
#endif
READ(&len, sizeof(len));
if (len != N_BYTE_ORDER) {
Printf("Cannot read .ntg files created on different machines!\n");
Printf(" File has byte order %X, CPU has %X\n",len, N_BYTE_ORDER);
goto end;
}
READ(&len, sizeof(len));
if (len != N_BYTE_ORDER) {
Printf("Cannot read .ntg files created on different machines!\n");
Printf(" Machines have different word sized (CPU int = %d)\n",
sizeof(len));
goto end;
}
while (1) {
char string[400];
chars = READ(&len, sizeof(len));
if (chars != sizeof(len)) break; /* we must be done */
/* otherwise, read the cell name and continue */
chars = READ(string, len);
CellDef(string, -1);
LastCellRead = CurrentCell->name;
while (1) {
struct objlist *ob;
chars = READ(&len, sizeof(len));
if (chars != sizeof(len) || len == END_OF_CELL) break;
chars = READ(string, len);
ob = (struct objlist *)CALLOC(1,sizeof(struct objlist));
ob->name = (char *)MALLOC(len);
strcpy(ob->name, string);
READ(&(ob->node), sizeof(ob->node));
READ(&(ob->type), sizeof(ob->type));
if (ob->type >= FIRSTPIN) {
READ(&len, sizeof(len));
READ(string, len);
ob->model.class = (char *)MALLOC(len);
strcpy(ob->model.class,string);
READ(&len, sizeof(len));
READ(string, len);
ob->instance.name = (char *)MALLOC(len);
strcpy(ob->instance.name,string);
}
else {
ob->model.class = (char *)CALLOC(1,1);
ob->instance.name = (char *)CALLOC(1,1);
}
if (ob->type == FIRSTPIN) {
if (NULL == LookupCell(ob->model.class))
Printf("WARING: instance of non-existance cell: %s\n",
ob->model.class);
AddInstanceToCurrentCell(ob);
CurrentCell->class = CLASS_SUBCKT; /* there is at least one instance */
}
AddToCurrentCell(ob);
}
EndCell();
}
end:
#ifdef BUFFER_READS
FREE(readbuf);
#endif
close(File);
*fnum = Graph++;
return LastCellRead;
}
#endif /* !USE_PORTABLE_FILE_FORMAT */

41
base/netfile.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef _NETFILE_H
#define _NETFILE_H
#define NTK_EXTENSION ".ntk"
#define ACTEL_EXTENSION ".adl"
#define XILINX_EXTENSION ".xnf"
#define WOMBAT_EXTENSION ".wom"
#define EXT_EXTENSION ".ext"
#define SIM_EXTENSION ".sim"
#define SPICE_EXTENSION ".spice"
#define SPICE_EXT2 ".spc"
#define SPICE_EXT3 ".fspc"
#define NETGEN_EXTENSION ".ntg"
#define CCODE_EXTENSION ".c.code"
#define ESACAP_EXTENSION ".esa"
#define LINELENGTH 80
extern int OpenFile(char *filename, int linelen);
extern void CloseFile(char *filename);
extern int IsPortInPortlist(struct objlist *ob, struct nlist *tp);
extern void FlushString (char *format, ...);
extern char *SetExtension(char *buffer, char *path, char *extension);
extern int File;
/* input routines */
extern char *nexttok;
#define SKIPTO(a) do {SkipTok();} while (!match(nexttok,a))
extern void SkipTok(void);
extern void SkipTokNoNewline(void);
extern void SpiceTokNoNewline(void); /* handles SPICE "+" continuation line */
extern void SkipNewLine(void);
extern void SpiceSkipNewLine(void); /* handles SPICE "+" continuation line */
extern void InputParseError(FILE *f);
extern int OpenParseFile(char *name, int fnum);
extern int EndParseFile(void);
extern int CloseParseFile(void);
#endif /* _NETFILE_H */

2741
base/netgen.c Normal file

File diff suppressed because it is too large Load Diff

190
base/netgen.h Normal file
View File

@ -0,0 +1,190 @@
#define NETGEN_COPYRIGHT "Copyright 1990,1991,2002,2004,2005"
#define NETGEN_AUTHOR "Massimo A. Sivilotti, Caltech"
#define NETGEN_DEVELOPER "R. Timothy Edwards, MultiGiG, Inc."
#ifndef _NETGEN_H
#define _NETGEN_H
#ifndef _OBJLIST_H
#include "objlist.h"
#endif
#ifndef NULL
#define NULL 0
#endif
/* various Composition directions */
#define NONE 0
#define HORIZONTAL 1
#define VERTICAL 2
/* netgen.c */
extern void ReopenCellDef(char *name, int file);
extern void CellDef(char *name, int file);
extern void CellDefNoCase(char *name, int file);
extern void EndCell(void);
extern void Port(char *name);
extern int CountPorts(char *name, int file);
extern void SetClass(unsigned char class);
extern struct property *PropertyValue(char *name, int fnum, char *key,
double slop, double pdefault);
extern struct property *PropertyDouble(char *name, int fnum, char *key,
double slop, double pdefault);
extern struct property *PropertyInteger(char *name, int fnum, char *key,
int slop, int pdefault);
extern struct property *PropertyString(char *name, int fnum, char *key,
int range, char *pdefault);
extern int PropertyDelete(char *name, int fnum, char *key);
extern int PropertyTolerance(char *name, int fnum, char *key, int ival,
double dval);
extern void ResolveProperties(char *name1, int file1, char *name2, int file2);
extern void CopyProperties(struct objlist *obj_to, struct objlist *obj_from);
extern int PromoteProperty(struct property *, struct valuelist *);
extern struct objlist *LinkProperties(char *model, struct keyvalue *topptr);
extern int ReduceExpressions(struct objlist *instprop, struct nlist *parent,
int glob);
extern void Node(char *name);
extern void Global(char *name);
extern void UniqueGlobal(char *name);
extern void Instance(char *model, char *instancename);
extern void PortList(char *prefix, char *list_template);
extern char *Cell(char *inststr, char *model, ...);
extern int IsIgnored(char *, int);
/* netcmp.c */
extern struct nlist *LookupClassEquivalent(char *model, int file1, int file2);
extern void AssignCircuits(char *name1, int file1, char *name2, int file2);
/* flatten.c */
extern int PrematchLists(char *, int, char *, int);
/* Define (enumerate) various device classes, largely based on SPICE */
/* model types, mixed with some ext/sim types. */
#define CLASS_SUBCKT 0 /* Any cell containing components; default */
#define CLASS_NMOS 1 /* sim "n" */
#define CLASS_PMOS 2 /* sim "p" */
#define CLASS_FET3 3 /* unknown; 3-terminal NMOS or PMOS */
#define CLASS_NMOS4 4 /* 4-terminal NMOS */
#define CLASS_PMOS4 5 /* 4-terminal PMOS */
#define CLASS_FET4 6 /* unknown; 4-terminal NMOS or PMOS */
#define CLASS_FET 7 /* unknown; 3- or 4-terminal NMOS or PMOS */
#define CLASS_PNP 8
#define CLASS_NPN 9 /* sim "b" */
#define CLASS_BJT 10 /* unknown; PNP or NPN */
#define CLASS_RES 11 /* sim "r" */
#define CLASS_RES3 12 /* 3-terminal resistor */
#define CLASS_CAP 13 /* sim "c" */
#define CLASS_ECAP 14 /* moscap (3-terminal w/source, drain) */
#define CLASS_CAP3 15 /* cap with dummy terminal */
#define CLASS_DIODE 16 /* standard SPICE diode */
#define CLASS_INDUCTOR 17 /* standard SPICE inductor */
#define CLASS_XLINE 18 /* transmission line model */
#define CLASS_MODULE 19 /* sim "x"; black-box subcircuit */
#define CLASS_UNDEF 20 /* not defined; error */
extern char *P(char *fname, char *inststr, char *drain, char *gate, char *source);
extern char *P4(char *fname, char *inststr, char *drain, char *gate, char *source,
char *bulk);
extern char *N(char *fname, char *inststr, char *drain, char *gate, char *source);
extern char *N4(char *fname, char *inststr, char *drain, char *gate, char *source,
char *bulk);
extern char *B(char *fname, char *inststr, char *, char *, char *);
extern char *E(char *fname, char *inststr, char *, char *, char *);
extern char *Cap3(char *fname, char *inststr, char *, char *, char *);
extern char *Res3(char *fname, char *inststr, char *, char *, char *);
extern char *Cap(char *fname, char *inststr, char *, char *);
extern char *Res(char *fname, char *inststr, char *, char *);
extern char *XLine(char *fname, char *inststr, char *, char *, char *, char *);
extern char *Inductor(char *fname, char *inststr, char *, char *);
extern int StringIsValue(char *);
extern char *ConvertParam(char *);
extern int ConvertStringToFloat(char *, double *);
extern char *ScaleStringFloatValue(char *, double);
extern void join(char *node1, char *node2);
extern void Connect(char *tplt1, char *tplt2);
extern void Place(char *name);
extern void Array(char *Cell, int num);
extern void ActelLib(void);
extern void Flatten(char *name, int file);
extern void FlattenInstancesOf(char *model, int file);
extern int flattenInstancesOf(char *model, int file, char *instance);
extern void FlattenCurrent();
extern void ConvertGlobals(char *name, int fnum);
extern int CleanupPins(char *name, int fnum);
extern void ConnectAllNodes(char *model, int fnum);
extern int NoDisconnectedNodes;
extern int PropertyKeyMatch(char *, char *);
extern int PropertyValueMatch(char *, char *);
/* objlist.c */
extern void CellDelete(char *name, int file);
extern void InstanceRename(char *from, char *to, int file);
extern int Debug;
extern int VerboseOutput; /* set this to 1 to enable extra output */
extern int IgnoreRC; /* set this to 1 to ignore capacitance and resistance */
extern int NoOutput; /* set this to 1 to disable stdout output */
extern int Composition; /* direction of composition */
extern int UnixWildcards; /* TRUE if *,?,{},[] only; false if full REGEXP */
/* magic internal flag to restrict searches to recently placed cells */
extern int QuickSearch;
/* does re"CellDef"ing a cell add to it or overwrite it??? */
extern int AddToExistingDefinition;
/* procedure to facilitate generating file/cell/pin names */
char *Str(char *format, ...);
/* these are defined in data.h */
extern void Initialize(void);
extern void InitializeCommandLine(int argc, char **argv);
#ifdef TCL_NETGEN
extern void PrintAllElements(char *cell, int file);
#else
extern void PrintElement(char *cell, char *list_template);
#endif
extern void Fanout(char *cell, char *node, int filter);
extern void PrintCell(char *name, int file);
extern void Query(void);
/* this is defined in xnetgen.h */
void X_main_loop(int argc, char *argv[]);
/* output file formats; also defined in netfile.h */
extern void Ntk(char *name, char *filename);
extern void Actel(char *name, char *filename);
extern void Wombat(char *name, char *filename);
extern void Ext(char *name, int fnum);
extern void Sim(char *name, int fnum);
extern void SpiceCell(char *name, int fnum, char *filename);
extern void EsacapCell(char *name, char *filename);
extern void WriteNetgenFile(char *name, char *filename);
extern void Ccode(char *name, char *filename);
/* input file formats, these routines return the name of the top-level cell */
extern char *ReadNtk (char *fname, int *fnum);
extern char *ReadExtHier(char *fname, int *fnum);
extern char *ReadExtFlat(char *fname, int *fnum);
extern char *ReadSim(char *fname, int *fnum);
extern char *ReadSpice(char *fname, int *fnum);
extern char *ReadSpiceLib(char *fname, int *fnum);
extern char *ReadNetgenFile (char *fname, int *fnum);
extern char *ReadNetlist(char *fname, int *fnum);
/* these are defined in place.h */
extern void Embed(char *cellname);
extern void PROTOCHIP(void);
/* these are defined in netcmp.c */
extern void NETCOMP(void);
extern int Compare(char *cell1, char *cell2);
/* this is defined in tclnetgen.c */
#ifdef TCL_NETGEN
extern char *tcl_calloc(size_t, size_t);
#endif
#endif /* _NETGEN_H */

369
base/ntk.c Normal file
View File

@ -0,0 +1,369 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ntk.c -- Input / output routines for .NTK format */
/* define the following to permit the definition of any unrecognized
instances, as they are read in the .ntk file */
#define DEFINE_UNDEFINED_CELLS
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#include "netgen.h"
#include "hash.h"
#include "objlist.h"
#include "netfile.h"
#include "print.h"
void ntkCell(char *name)
{
struct nlist *tp, *tp2;
struct objlist *ob, *ob2;
tp = LookupCell(name);
if (tp == NULL) {
Printf("No cell '%s' found.\n", name);
return;
}
/* do NOT dump primitive cells */
if (tp->class != CLASS_SUBCKT)
return;
/* check to see that all children have been dumped */
for (ob = tp->cell; ob != NULL; ob = ob->next) {
tp2 = LookupCell(ob->model.class);
if ((tp2 != NULL) && !(tp2->dumped))
ntkCell(tp2->name);
}
/* print out header list */
FlushString("c %s ", tp->name);
for (ob = tp->cell; ob != NULL; ob = ob->next) {
if (IsPortInPortlist(ob, tp))
FlushString("%s ", ob->name); /* unique ports only */
}
FlushString(";\n");
/* run through cell's contents, defining all unique elements */
for (ob = tp->cell; ob != NULL; ob = ob->next) {
/* next test used to be reversed */
if (match(ob->name, NodeAlias(tp, ob)) &&
!IsPortInPortlist(ob,tp))
FlushString ("s 1 %s ;\n", ob->name);
}
/* now run through cell's contents, print instances */
for (ob = tp->cell; ob != NULL; ob = ob->next) {
if (ob->type == FIRSTPIN) {
/* this is an instance */
/* print out cell, but special case transistors */
if (match(ob->model.class, "n")) FlushString("N 2 ");
else if (match(ob->model.class, "p")) FlushString("P 2 ");
else FlushString ("h %s %s ", ob->model.class, ob->instance.name);
/* print out parameter list */
ob2 = ob;
tp2 = LookupCell(ob->model.class);
do {
char *nm;
/* assume a form <instancename>/<port name> */
/* was: strchr 12/12/88, but this was not right for FLATTENED things!*/
#if 1
struct objlist *newob;
nm = strrchr(ob2->name,SEPARATOR[0]) + 1;
newob = LookupObject(nm, tp2);
if (match(nm, NodeAlias(tp2, newob)))
FlushString ("%s ", NodeAlias(tp, ob2));
#else
int nodenum;
nm = strrchr(ob2->name,SEPARATOR[0]) + 1;
nodenum = LookupObject(nm, tp2)->node;
if ((nodenum == -1) ||
match(nm, NodeName(tp2, nodenum)))
FlushString ("%s ", NodeName(tp, ob2->node));
#endif
ob2 = ob2->next;
} while ((ob2 != NULL) && (ob2->type > FIRSTPIN));
FlushString(";\n");
}
}
FlushString (".\n");
tp->dumped = 1; /* set dumped flag */
}
void Ntk(char *name, char *filename)
{
struct objlist *ob;
struct nlist *tp;
int global_port;
char FileName[500];
if (filename == NULL || strlen(filename) == 0)
SetExtension(FileName, name, NTK_EXTENSION);
else
SetExtension(FileName, filename, NTK_EXTENSION);
if (!OpenFile(FileName, 80)) {
Printf("Unable to open NTK file %s\n", FileName);
return;
}
ClearDumpedList();
#if 1
/* create top level call */
if ((tp = LookupCell(name)) != NULL) {
ntkCell(name);
ob = tp->cell;
global_port = 1;
for (ob = tp->cell; ob != NULL; ob = ob->next)
if (IsPortInPortlist(ob, tp))
FlushString ("s 1 %s #%d ;\n",
NodeAlias(tp,ob), global_port++);
FlushString("h %s %s ", name, name);
for (ob = tp->cell; ob != NULL; ob = ob->next)
if (IsPortInPortlist(ob,tp))
FlushString ("%s ", NodeAlias(tp,ob));
FlushString(";\n.\n.\n");
}
#else
/* same as above, but uses while loops instead of for loops */
if (LookupCell(name) != NULL) {
ntkCell(name);
tp = LookupCell(name);
ob = tp->cell;
global_port = 1;
do {
if (IsPortInPortlist(ob, tp))
FlushString ("s 1 %s #%d ;\n",
NodeName(tp,ob->node), global_port++);
ob = ob->next;
} while (ob != NULL);
FlushString("h %s %s ", name, name);
ob = LookupCell(name)->cell;
do {
if (IsPortInPortlist(ob,tp))
FlushString ("%s ", NodeName(tp,ob->node));
ob = ob->next;
} while (ob != NULL);
FlushString(";\n.\n.\n");
}
#endif
CloseFile(FileName);
}
char *ReadNtk (char *fname, int *fnum)
{
char model[100], instancename[100], name[100];
struct objlist *ob;
int CellDefInProgress = 0;
int filenum;
char *LastCellRead = NULL;
if ((filenum = OpenParseFile(fname, *fnum)) < 0) {
SetExtension(name, fname, NTK_EXTENSION);
if ((filenum = OpenParseFile(name, *fnum)) < 0) {
Printf("No file: %s\n",name);
*fnum = filenum;
return NULL;
}
}
while (!EndParseFile()) {
SkipTok();
if (EndParseFile()) break;
if (nexttok[0] == '|') SKIPTO(";");
else if (match(nexttok, "c")) {
if (CellDefInProgress) {
Printf("Recursive cell definition: cell %s open.\n",
CurrentCell->name);
EndCell();
CellDefInProgress = 0;
}
SkipTok();
CellDef(nexttok, CurrentCell->file);
LastCellRead = CurrentCell->name;
CellDefInProgress = 1;
SkipTok();
while (!match(nexttok, ";")) {
Port(nexttok);
SkipTok();
}
}
else if (match(nexttok, "s")) {
char last[100];
*last = '\0';
if (!CellDefInProgress) {
/* fake cell declaration for top-level call */
if (LookupCell(fname) == NULL) CellDef(fname, CurrentCell->file);
else CellDef(NTK_EXTENSION, CurrentCell->file);
CellDefInProgress = 1;
if (LastCellRead == NULL)
LastCellRead = CurrentCell->name;
}
SkipTok();
SkipTok(); /* eat the 'size' of the node */
/* after the 'size', all names are synonyms */
while (!match(nexttok, ";")) {
#if 1
if (strrchr(nexttok, PHYSICALPIN[0]) == NULL) Node(nexttok);
else {
Printf("WARNING: internal node %-10s promoted to global port!\n",
nexttok);
Global(nexttok); /* make Actel pins in subcells visible */
}
#else
Node(nexttok);
#endif
if (strlen(last)) join(last, nexttok);
strcpy(last, nexttok);
SkipTok();
}
}
else if (match(nexttok, "h")) {
if (!CellDefInProgress) {
CellDef("_MAIN", CurrentCell->file);
CellDefInProgress = 1;
if (LastCellRead == NULL)
LastCellRead = CurrentCell->name;
}
SkipTok();
strcpy(model, nexttok);
strcpy(instancename, nexttok);
strcat(instancename, INSTANCE_DELIMITER);
SkipTok();
strcat(instancename, nexttok);
if (LookupCell(model) == NULL) {
#ifdef DEFINE_UNDEFINED_CELLS
char *previous_cell;
int args, i;
char *ports[100];
previous_cell = CurrentCell->name;
CellDef(model, CurrentCell->file);
SkipTok();
args = 0;
while (!match(nexttok, ";")) {
sprintf(name, "pin%d", args+1);
Port(name);
ports[args] = strsave(nexttok);
args++;
/* check for overflow */
if (args == (sizeof(ports) / sizeof(ports[0]))) {
while (!match(nexttok, ";")) SkipTok();
break; /* out of while loop */
}
/* if no overflow, get the next token */
SkipTok();
}
EndCell();
/* now, reopen previous cell, instance the new cell,
and wire it up */
ReopenCellDef(previous_cell, CurrentCell->file);
Instance(model, instancename);
for (i = 0; i < args; i++) {
sprintf(name, "%s%spin%d", instancename, SEPARATOR, i+1);
join(ports[i], name);
FREE(ports[i]);
}
#else
Printf("Unknown cell class: %s instanced in cell %s\n",
model, CurrentCell->name);
SKIPTO(";");
#endif
}
else {
Instance(model, instancename);
ob = LookupCell(model)->cell;
while ((ob != NULL) && !IsPort(ob))
ob = ob->next;
SkipTok();
while (!match(nexttok, ";")) {
strcpy(name, instancename);
strcat(name, SEPARATOR);
strcat(name, ob->name);
/* Connect(nexttok,name); */
join(nexttok, name);
do {
ob = ob->next;
} while ((ob != NULL) && !IsPort(ob)) ;
SkipTok();
}
}
}
else if (match(nexttok, "n") || match(nexttok,"N")) {
if (!CellDefInProgress) {
CellDef("_MAIN", CurrentCell->file);
CellDefInProgress = 1;
if (LastCellRead == NULL)
LastCellRead = CurrentCell->name;
}
SkipTok();
SkipTok(); /* skip the transistor size */
strcpy(name, nexttok);
SkipTok();
strcpy(model, nexttok);
SkipTok();
strcpy(instancename, nexttok);
N(fname, NULL, name, model, instancename);
SKIPTO(";");
}
else if (match(nexttok, "p") || match(nexttok,"P")) {
if (!CellDefInProgress) {
CellDef("_MAIN", CurrentCell->file);
CellDefInProgress = 1;
if (LastCellRead == NULL)
LastCellRead = CurrentCell->name;
}
SkipTok();
SkipTok(); /* skip the transistor size */
strcpy(name, nexttok);
SkipTok();
strcpy(model, nexttok);
SkipTok();
strcpy(instancename, nexttok);
P(fname, NULL, name, model, instancename);
SKIPTO(";");
}
else if (match(nexttok, ".")) {
EndCell();
CellDefInProgress = 0;
}
else {
Printf("Strange token in ntk: '%s'\n", nexttok);
InputParseError(stderr);
}
}
CloseParseFile();
*fnum = filenum;
return LastCellRead;
}

1294
base/objlist.c Normal file

File diff suppressed because it is too large Load Diff

280
base/objlist.h Normal file
View File

@ -0,0 +1,280 @@
/* objlist.h -- core allocation, list generation by regexps */
#ifndef _OBJLIST_H
#define _OBJLIST_H
#define SEPARATOR "/"
#define INSTANCE_DELIMITER "#"
#define PORT_DELIMITER "."
#define PHYSICALPIN "("
#define ENDPHYSICALPIN ")"
#define PORT (-1)
#define GLOBAL (-2)
#define UNIQUEGLOBAL (-3)
#define PROPERTY (-4) /* For element properties; e.g., length, width */
#define ALLELEMENTS (-5) /* for doing searches; e.g., Fanout() */
#define ALLOBJECTS (-6) /* for doing searches; e.g., Fanout() */
#define UNKNOWN (-7) /* for error checking */
#define NODE 0
#define FIRSTPIN 1
#define IsPort(a) ((a)->type == PORT)
#define IsNonProxyPort(a) (((a)->type == PORT) && ((a)->model.port != PROXY))
#define IsGlobal(a) (((a)->type == GLOBAL) || ((a)->type == UNIQUEGLOBAL))
#define PROXY (0) /* Used in model.port record of ports */
/* Lists of device properties. Order is defined at the time of */
/* the cell definition; values are sorted at the time instances */
/* are read. */
/* Part 1a: Define the types of tokens used in an expression */
#define TOK_NONE 0
#define TOK_DOUBLE 1
#define TOK_STRING 2
#define TOK_MULTIPLY 3
#define TOK_DIVIDE 4
#define TOK_PLUS 5
#define TOK_MINUS 6
#define TOK_FUNC_OPEN 7
#define TOK_FUNC_CLOSE 8
#define TOK_GT 9
#define TOK_LT 10
#define TOK_GE 11
#define TOK_LE 12
#define TOK_EQ 13
#define TOK_NE 14
#define TOK_GROUP_OPEN 15
#define TOK_GROUP_CLOSE 16
#define TOK_FUNC_IF 17
#define TOK_FUNC_THEN 18
#define TOK_FUNC_ELSE 19
/* Part 1b: Stack structure used to hold expressions in tokenized form */
struct tokstack {
int toktype;
union {
double dvalue;
char *string;
} data;
struct tokstack *next;
struct tokstack *last;
};
/* Part 1c: Define the types of property values */
#define PROP_STRING 0
#define PROP_EXPRESSION 1 /* Same as STRING, handled differently */
#define PROP_INTEGER 2
#define PROP_DOUBLE 3
#define PROP_VALUE 4 /* Same as DOUBLE, handled differently */
#define PROP_ENDLIST 5 /* End of the property record. */
/* Part 1d: Linked list of values for temporary unordered storage when */
/* reading a netlist. Values are string only, to be promoted later if */
/* needed. */
struct keyvalue {
char *key;
char *value;
struct keyvalue *next;
};
/* Part 2: Values (corresponding to the keys, and kept in the instance record) */
struct valuelist {
char *key;
unsigned char type; /* string, integer, double, value, expression */
union {
char *string;
double dval;
int ival;
struct tokstack *stack; /* expression in tokenized form */
} value;
};
/* Part 3: Keys & Defaults (kept in the cell record as a hash table) */
struct property {
char *key; /* name of the property */
unsigned char idx; /* index into valuelist */
unsigned char type; /* string, integer, double, value, expression */
union {
char *string;
double dval;
int ival;
struct tokstack *stack;
} pdefault; /* Default value */
union {
double dval;
int ival;
} slop; /* slop allowance in property */
};
/*-------------------------------*/
/* list of objects within a cell */
/*-------------------------------*/
struct objlist {
char *name; /* unique name for the port/node/pin/property */
int type; /* -1 for port, 0 for internal node,
else index of the pin on element */
union {
char *class; /* name of element class; nullstr for nodes */
int port; /* Port number, if type is a port */
} model;
union {
char *name; /* unique name for the instance, or */
/* (string) value of property for properties */
struct valuelist *props; /* Property record */
} instance;
int node; /* the electrical node number of the port/node/pin */
struct objlist *next;
};
extern struct objlist *LastPlaced;
/* Record structure for maintaining lists of cell classes to ignore */
struct IgnoreList {
char *class;
int file;
struct IgnoreList *next;
};
/* Record structure for handling pin permutations in a cell */
/* Linked list structure allows multiple permutations per cell. */
struct Permutation {
char *pin1;
char *pin2;
struct Permutation *next;
};
#define OBJHASHSIZE 997 /* the size of the object and instance hash lists */
/* prime numbers are good choices as hash sizes */
/* 101 is a good number for IBMPC */
/* cell definition for hash table */
/* NOTE: "file" must come first for the hash matching by name and file */
struct nlist {
int file; /* internally ordered file to which cell belongs, or -1 */
char *name;
int number; /* number of instances defined */
int dumped; /* instance count, and general-purpose marker */
unsigned char flags;
unsigned char class;
unsigned long classhash; /* randomized hash value for cell class */
struct Permutation *permutes; /* list of permuting pins */
struct objlist *cell;
struct hashlist **objtab; /* hash table of object names */
struct hashlist **insttab; /* hash table of instance names */
struct hashlist **proptab; /* hash table of property keys */
struct objlist **nodename_cache;
long nodename_cache_maxnodenum; /* largest node number in cache */
void *embedding; /* this will be cast to the appropriate data structure */
struct nlist *next;
};
/* Defined nlist structure flags */
#define CELL_MATCHED 0x01 /* cell matched to another */
#define CELL_NOCASE 0x02 /* cell is case-insensitive (e.g., SPICE) */
#define CELL_TOP 0x04 /* cell is a top-level cell */
#define CELL_PLACEHOLDER 0x08 /* cell is a placeholder cell */
#define CELL_PROPSMATCHED 0x10 /* properties matched to matching cell */
/* Flags for combination allowances */
#define COMB_SERIAL 0x20
#define COMB_PARALLEL 0x40
extern struct nlist *CurrentCell;
extern struct objlist *CurrentTail;
extern void AddToCurrentCell(struct objlist *ob);
extern void AddToCurrentCellNoHash(struct objlist *ob);
extern void AddInstanceToCurrentCell(struct objlist *ob);
extern void FreeObject(struct objlist *ob);
extern void FreeObjectAndHash(struct objlist *ob, struct nlist *ptr);
extern void FreePorts(char *cellname);
extern struct IgnoreList *ClassIgnore;
extern int NumberOfPorts(char *cellname);
extern struct objlist *InstanceNumber(struct nlist *tp, int inst);
extern struct objlist *List(char *list_template);
extern struct objlist *ListExact(char *list_template);
extern struct objlist *ListCat(struct objlist *ls1, struct objlist *ls2);
extern int ListLen(struct objlist *head);
extern int ListLength(char *list_template);
extern struct nlist *LookupPrematchedClass(struct nlist *, int);
extern struct objlist *LookupObject(char *name, struct nlist *WhichCell);
extern struct objlist *LookupInstance(char *name, struct nlist *WhichCell);
extern struct objlist *CopyObjList(struct objlist *oldlist);
extern void UpdateNodeNumbers(struct objlist *lst, int from, int to);
/* Function pointer to List or ListExact, allowing regular expressions */
/* to be enabled/disabled. */
extern struct objlist * (*ListPtr)();
extern void PrintCellHashTable(int full, int file);
extern struct nlist *LookupCell(char *s);
extern struct nlist *LookupCellFile(char *s, int f);
extern struct nlist *InstallInCellHashTable(char *name, int f);
extern void InitCellHashTable(void);
extern void ClearDumpedList(void);
extern int RecurseCellHashTable(int (*foo)(struct hashlist *np));
extern int RecurseCellFileHashTable(int (*foo)(struct hashlist *, int), int);
extern struct nlist *RecurseCellHashTable2(struct nlist *(*foo)(struct hashlist *,
void *), void *);
extern struct nlist *FirstCell(void);
extern struct nlist *NextCell(void);
extern char *NodeName(struct nlist *tp, int node);
extern char *NodeAlias(struct nlist *tp, struct objlist *ob);
extern void FreeNodeNames(struct nlist *tp);
extern void CacheNodeNames(struct nlist *tp);
/* enable the following line to debug the core allocator */
/* #define DEBUG_GARBAGE */
#ifdef DEBUG_GARBAGE
extern struct objlist *GetObject(void);
extern struct keyvalue *NewKeyValue(void);
extern struct property *NewProperty(void);
extern struct valuelist *NewPropValue(int entries);
extern void FreeString(char *foo);
extern char *strsave(char *s);
#else /* not DEBUG_GARBAGE */
#define GetObject() ((struct objlist*)CALLOC(1,sizeof(struct objlist)))
#define NewProperty() ((struct property*)CALLOC(1,sizeof(struct property)))
#define NewPropValue(a) ((struct valuelist*)CALLOC((a),sizeof(struct valuelist)))
#define NewKeyValue() ((struct keyvalue*)CALLOC(1,sizeof(struct keyvalue)))
#define FreeString(a) (FREE(a))
#define strsave(a) (STRDUP(a))
#endif /* not DEBUG_GARBAGE */
extern int freeprop(struct hashlist *p);
extern int match(char *, char *);
extern int matchnocase(char *, char *);
extern int matchfile(char *, char *, int, int);
extern int matchfilenocase(char *, char *, int, int);
extern void GarbageCollect(void);
extern void InitGarbageCollection(void);
extern void AddToGarbageList(struct objlist *head);
#ifdef HAVE_MALLINFO
void PrintMemoryStats(void);
#endif
#endif /* _OBJLIST_H */

625
base/pdutils.c Normal file
View File

@ -0,0 +1,625 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* pdutils.c -- various public-domain versions of useful functions */
#include "config.h"
#include <stdio.h>
#include <ctype.h>
#ifdef IBMPC
#include <alloc.h>
#endif
#if defined(__STDC__) || defined(IBMPC)
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include "netgen.h"
/*************************************************************************/
/* */
/* Random number generators */
/* */
/*************************************************************************/
/* See NUMERICAL RECIPES IN C */
#include <math.h>
#define M 714025L
#define IA 1366
#define IC 150889L
static long idum = -1; /* needs to be initialized to avoid seg fault if 0 */
float ran2(void)
{
static long iy,ir[98];
static int iff=0;
int j;
void nrerror();
if (idum < 0 || iff == 0) {
iff=1;
if ((idum=(IC-(idum)) % M) < 0) idum = -idum;
for (j=1;j<=97;j++) {
idum=(IA*idum+IC) % M;
ir[j]=idum;
}
idum=(IA*idum+IC) % M;
iy=idum;
}
j=(int)(1 + 97.0*iy/M); /* the cast was added by Glenn for C++ */
if (j > 97 || j < 1) perror("RAN2: This cannot happen.");
iy=ir[j];
idum=(IA*idum+IC) % M;
ir[j]=idum;
return (float) iy/M;
}
#undef M
#undef IA
#undef IC
#if 0
int Random(int max)
{
int i;
float f;
f = ran2();
i = f * max;
printf("Random(%d) computes %f, returns: %d\n", max, f, i);
return(i);
}
#else
int Random(int max)
{
return(ran2() * max);
}
#endif
long RandomSeed(long seed)
/* initialize idum to some negative integer */
{
long oldidum;
oldidum = idum;
if (seed == 0) seed = -1;
if (seed > 0) seed = -seed;
idum = seed;
return(oldidum);
}
float RandomUniform(void)
{
return(ran2());
}
/*************************************************************************/
/* */
/* String manipulation routines for deficient libraries */
/* */
/*************************************************************************/
#ifdef NEED_STRSTR
/* strstr - find first occurrence of wanted in s */
/* return pointer to found location, or NULL if none */
char *strstr(char *s, char *wanted)
{
register char *scan;
register int len;
register char firstc;
/* deleted by Glenn -- Not necessary (and conflict with declarations in .h)
extern int strcmp();
extern int strlen();
*/
/*
* The odd placement of the two tests is so "" is findable.
* Also, we inline the first char for speed.
* The ++ on scan has been moved down for optimization.
*/
firstc = *wanted;
len = strlen(wanted);
for (scan = s; *scan != firstc || strncmp(scan, wanted, len) != 0; )
if (*scan++ == '\0')
return(NULL);
return(scan);
}
#endif
#ifdef NEED_STRCASECMP
/* strcasecmp - compare string s1 to s2, case insensitive */
/* returns <0 for <, 0 for ==, >0 for > */
int strcasecmp(char *s1, char *s2)
{
register char *scan1;
register char *scan2;
scan1 = s1;
scan2 = s2;
while (*scan1 != '\0' && toupper(*scan1) == toupper(*scan2)) {
scan1++;
scan2++;
}
/*
* The following case analysis is necessary so that characters
* which look negative collate low against normal characters but
* high against the end-of-string NUL.
*/
if (*scan1 == '\0' && *scan2 == '\0')
return(0);
else if (*scan1 == '\0')
return(-1);
else if (*scan2 == '\0')
return(1);
else
return(*scan1 - *scan2);
}
#endif
#ifdef NEED_STRING
/*
* char *strtok(s,delim);
*
* Get next token from string s (NULL on 2nd, 3rd, etc. calls),
* where tokens are nonempty strings separated by runs of
* chars from delim. Writes NULs into s to end tokens. delim need not
* remain constant from call to call.
*/
static char *scanpoint = NULL;
char *strtok(char *s, char *delim)
{
register char *scan;
char *tok;
register char *dscan;
if (s == NULL && scanpoint == NULL)
return(NULL);
if (s != NULL)
scan = s;
else
scan = scanpoint;
/*
* Scan leading delimiters.
*/
for (; *scan != '\0'; scan++) {
for (dscan = delim; *dscan != '\0'; dscan++)
if (*scan == *dscan)
break;
if (*dscan == '\0')
break;
}
if (*scan == '\0') {
scanpoint = NULL;
return(NULL);
}
tok = scan;
/*
* Scan token.
*/
for (; *scan != '\0'; scan++) {
for (dscan = delim; *dscan != '\0';) /* ++ moved down. */
if (*scan == *dscan++) {
scanpoint = scan+1;
*scan = '\0';
return(tok);
}
}
/*
* Reached end of string.
*/
scanpoint = NULL;
return(tok);
}
/*
* strcspn - find length of initial segment of s consisting entirely
* of characters not from reject
*/
int strcspn(char *s, char *reject)
{
register char *scan;
register char *rscan;
register int count;
count = 0;
for (scan = s; *scan != '\0'; scan++) {
for (rscan = reject; *rscan != '\0';) /* ++ moved down. */
if (*scan == *rscan++)
return(count);
count++;
}
return(count);
}
/*
* strpbrk - find first occurrence of any char from breakat in s
*/
char *strpbrk(char *s, char *breakat)
/* found char, or NULL if none */
{
register char *sscan;
register char *bscan;
for (sscan = s; *sscan != '\0'; sscan++) {
for (bscan = breakat; *bscan != '\0';) /* ++ moved down. */
if (*sscan == *bscan++)
return(sscan);
}
return(NULL);
}
#endif
#ifdef NEED_STRTOL
long strtol(char *str, char **ptr, int base)
/* extremely poor emulator */
{
long result;
int fields;
if (ptr != NULL) *ptr = str;
fields = sscanf(str,"%ld",&result);
if (fields == 1) {
if (ptr != NULL) *ptr = str+1; /* bogus, but why not */
return(result);
}
return(0);
}
#endif
#ifdef NEED_VPRINTF
#if 1
/* Portable vsprintf by Robert A. Larson <blarson@skat.usc.edu> */
/* Copyright 1989 Robert A. Larson.
* Distribution in any form is allowed as long as the author
* retains credit, changes are noted by their author and the
* copyright message remains intact. This program comes as-is
* with no warentee of fitness for any purpouse.
*
* Thanks to Doug Gwen, Chris Torek, and others who helped clarify
* the ansi printf specs.
*
* Please send any bug fixes and improvments to blarson@skat.usc.edu .
* The use of goto is NOT a bug.
*/
/* Feb 7, 1989 blarson First usenet release */
/* This code implements the vsprintf function, without relying on
* the existance of _doprint or other system specific code.
*
* Define NOVOID if void * is not a supported type.
*
* Two compile options are available for efficency:
* INTSPRINTF should be defined if sprintf is int and returns
* the number of chacters formated.
* LONGINT should be defined if sizeof(long) == sizeof(int)
*
* They only make the code smaller and faster, they need not be
* defined.
*
* UNSIGNEDSPECIAL should be defined if unsigned is treated differently
* than int in argument passing. If this is definded, and LONGINT is not,
* the compiler must support the type unsingned long.
*
* Most quirks and bugs of the available sprintf fuction are duplicated,
* however * in the width and precision fields will work correctly
* even if sprintf does not support this, as will the n format.
*
* Bad format strings, or those with very long width and precision
* fields (including expanded * fields) will cause undesired results.
*/
#ifdef OSK /* os9/68k can take advantage of both */
#define LONGINT
#define INTSPRINTF
#endif
/* This must be a typedef not a #define! */
#ifdef NOVOID
typedef char *pointer;
#else
typedef void *pointer;
#endif
#ifdef INTSPRINTF
#define Sprintf(string,format,arg) (sprintf((string),(format),(arg)))
#else
#define Sprintf(string,format,arg) (\
sprintf((string),(format),(arg)),\
strlen(string)\
)
#endif
typedef int *intp;
int vsprintf(dest, format, args)
char *dest;
register char *format;
va_list args;
{
register char *dp = dest;
register char c;
register char *tp;
char tempfmt[64];
#ifndef LONGINT
int longflag;
#endif
tempfmt[0] = '%';
while(c = *format++) {
if(c=='%') {
tp = &tempfmt[1];
#ifndef LONGINT
longflag = 0;
#endif
continue_format:
switch(c = *format++) {
case 's':
*tp++ = c;
*tp = '\0';
dp += Sprintf(dp, tempfmt, va_arg(args, char *));
break;
case 'u':
case 'x':
case 'o':
case 'X':
#ifdef UNSIGNEDSPECIAL
*tp++ = c;
*tp = '\0';
#ifndef LONGINT
if(longflag)
dp += Sprintf(dp, tempfmt, va_arg(args, unsigned long));
else
#endif
dp += Sprintf(dp, tempfmt, va_arg(args, unsigned));
break;
#endif
case 'd':
case 'c':
case 'i':
*tp++ = c;
*tp = '\0';
#ifndef LONGINT
if(longflag)
dp += Sprintf(dp, tempfmt, va_arg(args, long));
else
#endif
dp += Sprintf(dp, tempfmt, va_arg(args, int));
break;
case 'f':
case 'e':
case 'E':
case 'g':
case 'G':
*tp++ = c;
*tp = '\0';
dp += Sprintf(dp, tempfmt, va_arg(args, double));
break;
case 'p':
*tp++ = c;
*tp = '\0';
dp += Sprintf(dp, tempfmt, va_arg(args, pointer));
break;
case '-':
case '+':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
case ' ':
case '#':
case 'h':
*tp++ = c;
goto continue_format;
case 'l':
#ifndef LONGINT
longflag = 1;
*tp++ = c;
#endif
goto continue_format;
case '*':
tp += Sprintf(tp, "%d", va_arg(args, int));
goto continue_format;
case 'n':
*va_arg(args, intp) = dp - dest;
break;
case '%':
default:
*dp++ = c;
break;
}
} else *dp++ = c;
}
*dp = '\0';
return dp - dest;
}
/* Portable vfprintf and vprintf by Robert A. Larson <blarson@skat.usc.edu> */
int vfprintf(dest, format, args)
FILE *dest;
register char *format;
va_list args;
{
register char c;
register char *tp;
register int count = 0;
char tempfmt[64];
#ifndef LONGINT
int longflag;
#endif
tempfmt[0] = '%';
while(c = *format++) {
if(c=='%') {
tp = &tempfmt[1];
#ifndef LONGINT
longflag = 0;
#endif
continue_format:
switch(c = *format++) {
case 's':
*tp++ = c;
*tp = '\0';
count += fprintf(dest, tempfmt, va_arg(args, char *));
break;
case 'u':
case 'x':
case 'o':
case 'X':
#ifdef UNSIGNEDSPECIAL
*tp++ = c;
*tp = '\0';
#ifndef LONGINT
if(longflag)
count += fprintf(dest, tempfmt, va_arg(args, unsigned long));
else
#endif
count += fprintf(dest, tempfmt, va_arg(args, unsigned));
break;
#endif
case 'd':
case 'c':
case 'i':
*tp++ = c;
*tp = '\0';
#ifndef LONGINT
if(longflag)
count += fprintf(dest, tempfmt, va_arg(args, long));
else
#endif
count += fprintf(dest, tempfmt, va_arg(args, int));
break;
case 'f':
case 'e':
case 'E':
case 'g':
case 'G':
*tp++ = c;
*tp = '\0';
count += fprintf(dest, tempfmt, va_arg(args, double));
break;
case 'p':
*tp++ = c;
*tp = '\0';
count += fprintf(dest, tempfmt, va_arg(args, pointer));
break;
case '-':
case '+':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
case ' ':
case '#':
case 'h':
*tp++ = c;
goto continue_format;
case 'l':
#ifndef LONGINT
longflag = 1;
*tp++ = c;
#endif
goto continue_format;
case '*':
tp += Sprintf(tp, "%d", va_arg(args, int));
goto continue_format;
case 'n':
*va_arg(args, intp) = count;
break;
case '%':
default:
putc(c, dest);
count++;
break;
}
} else {
putc(c, dest);
count++;
}
}
return count;
}
int vprintf(format, args)
char *format;
va_list args;
{
return vfprintf(stdout, format, args);
}
#else
/* this code works on machines that have _doprnt (Vaxes, etc) */
int vfprintf(FILE *fp, char *fmt, va_list args)
{
_doprnt(fmt, args, fp);
return(ferror(fp)? EOF: 0);
}
int vsprintf(char *str, char *fmt, va_list args)
{
struct _iobuf _strbuf;
_strbuf._flag = _IOWRT+_IOSTRG;
_strbuf._ptr = str;
_strbuf._cnt = 32767;
_doprnt(fmt, args, &_strbuf);
putc('\0', &_strbuf);
return(strlen(str));
}
#endif
#endif /* NEED_VPRINTF */

53
base/pdutils.h Normal file
View File

@ -0,0 +1,53 @@
/* emulator functions found in pdutils.c */
extern float RandomUniform(void);
extern long RandomSeed(long seed);
extern int Random(int max);
#ifdef NEED_STRING
extern char *strtok(char *s, char *delim);
extern int strcspn(char *s, char *reject);
extern char *strpbrk(char *s, char *breakat);
#endif /* NEED_STRING */
#ifdef NEED_STRSTR
extern char *strstr(char *s, char *wanted);
#endif
#ifdef NEED_STRCASECMP
extern int strcasecmp(char *s1, char *s2);
#endif
#ifdef NEED_STRDUP
#ifdef __STDC__
extern char *strdup(const char *s);
#else
extern char *strdup(char *s);
#endif
#endif /* NEED_STRDUP */
#ifdef NEED_STRTOL
extern long strtol(char *str, char **ptr, int base);
#endif
#ifdef NEED_VPRINTF
/* try to find out whether we use va_end, or ... */
#if defined(__STDC__) || defined(IBMPC)
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#ifdef va_end
#include <stdio.h>
extern int vsprintf(char *dest, char *format, va_list args);
extern int vfprintf(FILE *dest, char *format, va_list args);
extern int vprintf(char *format, va_list args);
#else
extern int vsprintf(char *dest, char *format, ...);
#endif /* va_end */
#endif /* NEED_VPRINTF */
#define MAX(a,b) (((a)>(b))?(a):(b))
#define MIN(a,b) (((a)<(b))?(a):(b))

1254
base/place.c Normal file

File diff suppressed because it is too large Load Diff

347
base/print.c Normal file
View File

@ -0,0 +1,347 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* print.c -- routines to format and buffer output */
#include "config.h"
#include <stdio.h>
#include <stdarg.h> /* what about varargs support, as in pdutils.h ??? */
#include <ctype.h>
#ifdef TCL_NETGEN
#include <tcl.h>
void tcl_stdflush(FILE *);
void tcl_vprintf(FILE *, char *, va_list);
extern int ColumnBase;
#endif
#define MAXFILES 4
struct filestr {
FILE *f;
char buffer[200];
int wrap; /* column to wrap around in, or 0 if no wrap */
} file_buffers[MAXFILES];
static int findfile(FILE *f)
/* return the index into file_buffers of the file, or -1 if not found */
{
int i;
for (i = 0; i < MAXFILES; i++)
if (file_buffers[i].f == f) return(i);
return(-1);
}
static int freefile(void)
/* return the index of next free slot in file_buffers, or -1 */
{
int i;
for (i = 0; i < MAXFILES; i++)
if (file_buffers[i].f == NULL) return(i);
return(-1);
}
FILE *LoggingFile = NULL; /* if LoggingFile is non-null, write to it as well */
int NoOutput = 0; /* by default, we allow stdout to be printed */
#ifdef HAVE_X11
#include "xnetgen.h"
void Output(FILE *f, char *s)
{
if (f == stderr) X_display_line(s);
else {
if (f == stdout) {
if (!NoOutput) X_display_line(s);
}
else fprintf(f,"%s",s);
}
if (LoggingFile != NULL) fprintf(LoggingFile, "%s", s);
}
#else
#ifndef TCL_NETGEN
void Output(FILE *f, char *s)
{
if (!NoOutput || f != stdout) fprintf(f,"%s",s);
if (LoggingFile != NULL) fprintf(LoggingFile, "%s", s);
}
#endif /* TCL_NETGEN */
#endif /* HAVE_X11 */
#ifdef TCL_NETGEN
void Fprintf(FILE *f, char *format, ...)
{
va_list ap;
va_start(ap, format);
if (!NoOutput) tcl_vprintf(f, format, ap);
if (LoggingFile != NULL) vfprintf(LoggingFile, format, ap);
va_end(ap);
}
#else
void Fprintf(FILE *f, char *format, ...)
{
va_list ap;
int FileIndex;
char tmpstr[200];
int bufferlongenough;
int linewrapexceeded;
va_start(ap, format);
vsprintf(tmpstr, format, ap);
va_end(ap);
FileIndex = findfile(f);
if (FileIndex == -1) {
fprintf(f, "%s", tmpstr);
return;
}
/* file is being buffered, so see if there is space in the buffer */
bufferlongenough = (strlen(file_buffers[FileIndex].buffer) +
strlen(tmpstr) < sizeof(file_buffers[0].buffer) - 3);
linewrapexceeded = (file_buffers[FileIndex].wrap &&
strlen(file_buffers[FileIndex].buffer) +
strlen(tmpstr) > file_buffers[FileIndex].wrap);
if (bufferlongenough && !linewrapexceeded) {
strcat(file_buffers[FileIndex].buffer, tmpstr);
if (strchr(tmpstr,'\n') != NULL) {
#if 0
int i;
i = strlen(file_buffers[FileIndex].buffer);
/* trim any trailing spaces */
for (i = i-1; i >= 0 &&
isspace((file_buffers[FileIndex].buffer)[i]); i--)
(file_buffers[FileIndex].buffer)[i] = '\0';
#endif
Output(f, file_buffers[FileIndex].buffer);
strcpy(file_buffers[FileIndex].buffer,"");
}
}
else {
/* string too long, or line wrap exceeded, so flush it all */
if (linewrapexceeded) {
#if 1
strcat(file_buffers[FileIndex].buffer, "\n");
#endif
Output(f, file_buffers[FileIndex].buffer);
strcpy(file_buffers[FileIndex].buffer," ");
strcat(file_buffers[FileIndex].buffer, tmpstr);
}
else {
/* buffer is too small, so flush buffer and new string */
#if 1
Output(f, file_buffers[FileIndex].buffer);
Output(f, tmpstr);
strcpy(file_buffers[FileIndex].buffer,"");
#else
strcat(file_buffers[FileIndex].buffer, tmpstr);
Output(f, file_buffers[FileIndex].buffer);
strcpy(file_buffers[FileIndex].buffer,"");
#endif
}
}
}
#endif
void Finsert(FILE *f)
{
/* try to insert f, if not alread present */
if (findfile(f) == -1) {
/* not found, so try to insert it */
int freeslot;
freeslot = freefile();
if (freeslot != -1) {
file_buffers[freeslot].f = f;
strcpy(file_buffers[freeslot].buffer,"");
}
fflush(f);
}
}
#ifdef TCL_NETGEN
void Printf(char *format, ...)
{
va_list ap;
va_start(ap, format);
tcl_vprintf(stdout, format, ap);
va_end(ap);
}
#else
void Printf(char *format, ...)
{
va_list ap;
char tmpstr[200];
va_start(ap, format);
vsprintf(tmpstr, format, ap);
va_end(ap);
/* insert stdout, if not already done */
Finsert(stdout);
Fprintf(stdout, "%s",tmpstr);
}
#endif
int Fcursor(FILE *f)
/* return the current column number of the cursor , or 0 if not known */
{
int i;
i = findfile(f);
if (i == -1) return(0);
return(strlen(file_buffers[i].buffer));
}
int Fwrap(FILE *f, int col)
/* set the wraparound column for this file */
/* returns the previous wrap around column */
{
int i;
int oldcol;
i = findfile(f);
if (i == -1) return(0);
oldcol = file_buffers[i].wrap;
file_buffers[i].wrap = col;
return(oldcol);
}
/* If "f" is NULL, then print to stdout and NOT */
/* to the log file. */
void Ftab(FILE *f, int col)
{
int i;
int spaces;
FILE *locf = (f == NULL) ? stdout : f;
i = findfile(locf);
if (i == -1) {
#ifdef TCL_NETGEN
char *padding;
if ((col - ColumnBase) <= 0) return;
padding = (char *)MALLOC(col - ColumnBase + 1);
for (i = 0; i < col - ColumnBase; i++)
padding[i] = ' ';
padding[i] = '\0';
if (f)
Fprintf(f, "%s", padding);
else
Printf("%s", padding);
#else
for (i = 0; i < col; i++)
if (f)
Fprintf(f, " ");
else
Printf(" ");
#endif
return;
}
/* try to pad the string with spaces */
spaces = col - strlen(file_buffers[i].buffer) - 1;
for (; spaces > 0; spaces--) strcat(file_buffers[i].buffer, " ");
return;
}
FILE *Fopen(char *name, char *mode)
{
FILE *ret;
int i;
ret = fopen(name,mode);
i = freefile();
if (i != -1) {
/* empty slot */
file_buffers[i].f = ret;
strcpy(file_buffers[i].buffer, "");
}
return(ret);
}
void Fflush(FILE *f)
{
int i;
#ifdef HAVE_X11
if (f == stdout || f == stderr) {
i = findfile(f);
if (i != -1) {
if (strlen(file_buffers[i].buffer))
Output(f, file_buffers[i].buffer);
strcpy(file_buffers[i].buffer,"");
}
X_display_refresh();
return;
}
#endif
#ifdef TCL_NETGEN
if (f == stdout || f == stderr) {
i = findfile(f);
if (i != -1) {
if (strlen(file_buffers[i].buffer))
Fprintf(f, file_buffers[i].buffer);
strcpy(file_buffers[i].buffer, "");
}
tcl_stdflush(f);
return;
}
#endif
i = findfile(f);
if (i != -1) {
if (strlen(file_buffers[i].buffer))
fprintf(f,"%s",file_buffers[i].buffer);
strcpy(file_buffers[i].buffer,"");
}
fflush(f);
}
int Fclose(FILE *f)
{
int i;
Fflush(f);
i = findfile(f);
if (i != -1) file_buffers[i].f = NULL;
return (fclose(f));
}

12
base/print.h Normal file
View File

@ -0,0 +1,12 @@
extern void Fprintf(FILE *f, char *format, ...);
extern void Printf(char *format, ...);
extern int Fcursor(FILE *f);
extern int Fwrap(FILE *f, int col);
extern void Ftab(FILE *f, int col);
extern FILE *Fopen(char *name, char *mode);
extern void Fflush(FILE *f);
extern int Fclose(FILE *f);
extern void Finsert(FILE *f);
extern FILE *LoggingFile;
extern int NoOutput;

65
base/proto.h Normal file
View File

@ -0,0 +1,65 @@
/* define prototypes for printf, etc. */
#ifndef FILE
#include <stdio.h>
#endif
#ifdef VMUNIX
/* common UNIX things that appear to be OS-independent */
extern void exit(int status);
extern int system(const char *s);
extern void perror(char *p);
extern int rand(void);
extern int atoi (const char *str);
extern char *calloc(unsigned num, unsigned size);
extern char *malloc(unsigned size);
extern void free(void *ptr);
extern long strtol (char *str, char **ptr, int base);
extern int fprintf(FILE *stream, char *fmt, ...);
extern int fclose(FILE *f);
extern int fflush(FILE *f);
extern int printf(char *fmt, ...);
#ifdef HPUX
/* library functions missing prototypes */
extern int fscanf(FILE *stream, char *fmt, ...);
extern int sprintf(char *s, char *fmt, ...);
#ifdef va_end
extern int vsprintf(char *s, char *fmt, va_list ap);
#endif
extern void srand(unsigned seed);
extern int memcmp(void *s1, void *s2, int n);
extern int tolower(int c);
extern int toupper(int c);
#endif /* HPUX */
#ifdef BSD
extern double atof(char *str);
extern char *getenv(char *name);
extern void longjmp(void *env, int val);
/* extern int longjmp(void *env, int val); this is correct for VAX */
extern int setjmp(void *env);
extern void srand(int seed);
extern bcopy(char *from, char *to, int len);
extern bzero(char *b, int len);
extern int close(int filedes);
extern int read(int filedes, void *buf, unsigned nbyte);
extern int sscanf(char *s, char *fmt, ...);
extern int fsscanf(FILE *f, char *s, char *fmt, ...);
#if defined(va_end) && !defined(NEED_VPRINTF)
extern char *vsprintf(char *s, char *fmt, va_list ap);
#endif
#endif /* BSD */
#endif /* VMUNIX */

1171
base/query.c Normal file

File diff suppressed because it is too large Load Diff

30
base/query.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef _QUERY_H
#define _QUERY_H
/* typeahead and prompt routines */
extern void typeahead(char *str);
extern void promptstring(char *prompt, char *buf);
extern FILE *promptstring_infile;
/* various printing routines */
#ifdef TCL_NETGEN
extern void PrintAllElements(char *cell, int fnum);
extern void ElementNodes(char *cell, char *element, int fnum);
#else
extern void PrintElement(char *cell, char *list_template);
#endif
extern void Fanout(char *cell, char *node, int filter);
extern void PrintNodes(char *name, int file);
extern void PrintCell(char *name, int file);
extern void PrintInstances(char *name, int file);
extern void DescribeInstance(char *name, int file);
extern void PrintPortsInCell(char *cellname, int file);
extern void PrintLeavesInCell(char *cellname, int file);
extern void PrintAllLeaves(void);
extern int ChangeScopeCurrent(char *pattern, int typefrom, int typeto);
extern int ChangeScope(int fnum, char *cellname, char *pattern,
int typefrom, int typeto);
#endif /* _QUERY_H */

230
base/random.c Normal file
View File

@ -0,0 +1,230 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* random.c -- random graph partitioning for PROTOCHIP */
#include <stdio.h>
#include "config.h"
#include "hash.h"
#include "objlist.h"
#include "embed.h"
#include "print.h"
#include "dbug.h"
void GeneratePermutation(int left, int right)
/* permute the elements between (and including) 'left' and 'right' */
{
int range;
int element;
int offset;
range = right - left + 1;
for (element = right; element > left; element--) {
int tmp;
offset = Random(range);
range--;
/* swap 'offset' and 'element' if they are not the same */
if (left+offset != element) {
tmp = permutation[left+offset];
permutation[left+offset] = permutation[element];
permutation[element] = tmp;
}
}
}
#if 0
#define GeneratePartition(left, right, level) ((left+right) / 2)
#else
int GeneratePartition(int left, int right, int level)
/* tries to find a balanced partition, as far as leaf cell usage */
{
int leftsum, rightsum;
#if 1
int i, greatest, greatestpos;
/* find highest element, make it first */
greatest = 0;
greatestpos = left;
for (i = left; i <= right; i++) {
if (LEVEL(permutation[i]) > greatest) {
greatest = LEVEL(permutation[i]);
greatestpos = i;
}
}
if (left != greatestpos) {
int tmp;
tmp = permutation[left];
permutation[left] = permutation[greatestpos];
permutation[greatestpos] = tmp;
}
#endif
leftsum = rightsum = 0;
while (left < right) {
if (leftsum < rightsum) leftsum += POW2(LEVEL(permutation[left++]));
else rightsum += POW2(LEVEL(permutation[right--]));
}
if (leftsum > POW2(level) || rightsum > POW2(level)) {
Fprintf(stdout,"No valid partition found at level %d\n",level);
return(0);
}
return(left);
}
#endif
int RandomPartition(int left, int right, int level)
/* return index of new element, if successful partition has bee achieved */
{
int partition;
int iterations;
int found;
int OriginalNewN;
int leftelement, rightelement;
#define MAX_PARTITION_ITERATIONS 10
DBUG_ENTER("Partition");
OriginalNewN = NewN;
#if 0
if (level < 0) DBUG_RETURN(0);
#else
if (level < LEVEL(permutation[left])) {
Fprintf(stdout,"Failed at level %d; subtree too deep\n",level);
DBUG_RETURN(0);
}
#endif
if (left == right) DBUG_RETURN(permutation[left]);
/* generate a permutation, then split it at
(left .. partition), (partition + 1 .. right)
and check and see if it is valid
*/
/* DBUG_PRINT("place",("trying to partition %d, %d",left,right)); */
iterations = 0;
do {
int i;
int leftfanout, rightfanout;
iterations++;
GeneratePermutation(left, right);
partition = GeneratePartition(left, right, level);
if (partition == 0) DBUG_RETURN(0); /* no valid partition */
found = 0;
#ifdef BAD
/* this is WRONG, as we need to set up {left,right}nodes */
rightfanout = -1;
leftfanout = PartitionFanout(left,partition,LEFT);
if (leftfanout <= TreeFanout[level]) {
rightfanout = PartitionFanout(partition+1, right, RIGHT);
if (rightfanout <= TreeFanout[level]) found = 1;
}
#else
leftfanout = PartitionFanout(left,partition,LEFT);
rightfanout = PartitionFanout(partition+1, right, RIGHT);
if (leftfanout <= TreeFanout[level] && rightfanout <= TreeFanout[level])
found = 1;
#endif
if (!found || level > TopDownStartLevel - 2) {
for (i = MAX_TREE_DEPTH; i > level; i--) Fprintf(stdout, " ");
Fprintf(stdout,
"Level: %d; L (%d leaves) fanout %d; R (%d leaves) fanout %d (<= %d) %s\n",
level, (partition - left + 1), leftfanout,
(right - partition), rightfanout, TreeFanout[level],
found ? "SUCCESSFUL" : "UNSUCCESSFUL");
}
if (!found) {
int IterationLimit;
for (IterationLimit = 0; IterationLimit < 20 &&
GradientDescent(left, right, partition); IterationLimit++);
found = 0;
#ifdef BAD
rightfanout = -1;
leftfanout = PartitionFanout(left,partition,LEFT);
if (leftfanout <= TreeFanout[level]) {
rightfanout = PartitionFanout(partition+1, right, RIGHT);
if (rightfanout <= TreeFanout[level]) found = 1;
}
#else
leftfanout = PartitionFanout(left,partition,LEFT);
rightfanout = PartitionFanout(partition+1, right, RIGHT);
if (leftfanout <= TreeFanout[level] && rightfanout <= TreeFanout[level])
found = 1;
#endif
for (i = MAX_TREE_DEPTH; i > level; i--) Fprintf(stdout, " ");
Fprintf(stdout,
" Iteration %2d: L fanout %d; R fanout %d (<= %d) %s\n",
iterations, leftfanout, rightfanout, TreeFanout[level],
found ? "SUCCESSFUL" : "UNSUCCESSFUL");
}
DBUG_EXECUTE("place",
Fprintf(DBUG_FILE,"Level %d: ",level);
Dbug_print_cells(left,partition);
Dbug_print_cells(partition+1,right);
Fprintf(DBUG_FILE,"\n");
{
int i;
Fprintf(DBUG_FILE,"L ");
for (i = 1; i <= Nodes; i++)
Fprintf(DBUG_FILE,"%2d ",leftnodes[i]);
Fprintf(DBUG_FILE,"\nR ");
for (i = 1; i <= Nodes; i++)
Fprintf(DBUG_FILE,"%2d ",rightnodes[i]);
Fprintf(DBUG_FILE,"\n");
}
Fprintf(DBUG_FILE, "%s\n", found?"SUCCESSFUL":"UNSUCCESSFUL");
);
#undef BIGLOOP
#ifdef BIGLOOP
if ((leftelement = RandomPartition(left, partition, level-1)) == 0 ||
(rightelement = RandomPartition(partition+1, right, level-1)) == 0)
found = 0;
#endif
} while (iterations < MAX_PARTITION_ITERATIONS && !found);
if (!found) {
Fprintf(stdout,"Failed embedding at level %d; no partition\n",level);
NewN = OriginalNewN;
DBUG_RETURN(0);
}
#ifndef BIGLOOP
leftelement = RandomPartition(left, partition, level-1);
if (leftelement == 0) goto fail;
rightelement = RandomPartition(partition+1, right, level-1);
if (rightelement == 0) goto fail;
#endif
/* add it to the list */
AddNewElement(leftelement, rightelement);
DBUG_RETURN(NewN);
#ifndef BIGLOOP
fail:
NewN = OriginalNewN;
DBUG_RETURN(0);
#endif
}

57
base/regexp.h Normal file
View File

@ -0,0 +1,57 @@
#ifdef HAVE_REGCMP
typedef char *Regexp;
Regexp regcmp(char *s, ...);
#define RegexpCompile(a) regcmp(a, (char *)0)
#define REGEXP_FREE_TEMPLATE
char *regex(char *re, char *s);
#define RegexpMatch(a,b) (regex((a),(b)) != NULL)
#endif /* HAVE_REGCMP */
#ifdef HAVE_RE_COMP
typedef char *Regexp;
Regexp re_comp(char *s);
#define RegexpCompile(a) re_comp(a)
/* re_comp returns an error code, not a regexp, so... */
#undef REGEXP_FREE_TEMPLATE
extern int re_exec(char *s);
#define RegexpMatch(a,b) re_exec(b)
#endif /* HAVE_RE_COMP */
#if !defined(HAVE_RE_COMP) && !defined(HAVE_REGCMP)
/*
* Definitions etc. for our own regexp(3) routines.
*
* THESE ARE SHAMELESSLY STOLEN FROM HENRY SPENCER'S UTZOO ROUTINES
* (prototypes added by MAS)
*/
#define NSUBEXP 10
typedef struct regexp {
char *startp[NSUBEXP];
char *endp[NSUBEXP];
char regstart; /* Internal use only. */
char reganch; /* Internal use only. */
char *regmust; /* Internal use only. */
int regmlen; /* Internal use only. */
char program[1]; /* Unwarranted chumminess with compiler. */
} regexp;
typedef struct regexp *Regexp;
#define RegexpCompile(a) regcomp(a)
#define RegexpMatch(a,b) regexec((a),(b))
Regexp regcomp(char *exp);
#define REGEXP_FREE_TEMPLATE
extern int regexec(regexp *prog, char *string);
extern void regsub(regexp *prog, char *source, char *dest);
extern void regerror(char *s);
#endif /* neither HAVE_RE_COMP nor HAVE_REGCMP */

2007
base/spice.c Normal file

File diff suppressed because it is too large Load Diff

263
base/test.c Normal file
View File

@ -0,0 +1,263 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* test.c -- top-level (main) routine wrapping a test suite */
#define TESTSHORTS 0
#define TESTNTK 0
#define TESTACTEL 0
#define TESTSCOPING 0
#define TESTEMBEDDED 0
#define TESTPRINT 0
#include <stdio.h>
#ifdef ANSI_LIBRARY
#include <stdlib.h> /* for getenv */
#endif
#include "netgen.h"
#ifdef TESTPRINT
#include "print.h"
#endif
void test_entry(void)
{
#if TESTPRINT
Printf("this is a test");
Ftab(stdout,50);
Printf("of the tab");
Printf(" facility\n");
printf("just testing\n");
#endif /* TESTPRINT */
#if TESTSCOPING
CellDef("leaf", -1);
Global("global");
UniqueGlobal("uniqueglobal");
Port("port");
Port("W.in");
Port("E.out");
N("leaf", "W.in","E.out","global");
Cell("p","W.in","port","uniqueglobal");
CellDef("twoleaves", -1);
Node("global");
Composition = HORIZONTAL;
Array("leaf",2);
Connect("leaf*/port","leaf1/port");
EndCell();
CellDef("fourleaves", -1);
Composition = HORIZONTAL;
Array("twoleaves",2);
EndCell();
#endif /* TESTSCOPING */
#if TESTNTK
CellDef ("test", -1);
Port("in");
Port("out");
Node("internal1");
Node("internal2");
join("in","internal1");
join("out","internal2");
Connect("in","out");
PrintCell("test");
CellDef("test2", -1);
Port("IN");
Port("OUT");
Instance("test","test1");
Instance("test","test2");
Instance("n","M1");
join("IN","test1.in");
join("test1.out","test2.in");
join("IN","M1.gate");
join("OUT","M1.drain");
join("test1.out","M1.source");
join("test2.out","OUT");
PrintCell("test2");
Ntk("test2","test2.ntk");
Fanout("test2","M1.gate", ALLOBJECTS);
ReadNtk("exphorn.ntk");
#endif /* TESTNTK */
#ifdef TESTEMBEDDED
CellDef("tcamp", -1);
Port("N.vdd");
Port("S.gnd");
Port("W.in");
Port("W.bias");
Port("E.out");
Port("E.bias");
Node("plusin");
Node("minusin");
Instance("n","bias");
Instance("n","plus");
Instance("n","minus");
Instance("p","mir");
Instance("p","load");
Connect("mir/gate","mir/drain");
Connect("mir/gate","load/gate");
Connect("mir/gate","plus/drain");
Connect("load/drain","minus/drain");
Connect("{p,min}*/s*","bias/drain");
Connect("N.vdd","{mir,load}/source");
Connect("bias/source","*.gnd");
Connect("bias/gate","*.bias");
Connect("minus/gate","minusin");
Connect("plus/gate","plusin");
Connect("plusin","*.in");
Connect("load/drain","*.out");
Connect("minusin","E.out");
EndCell();
CellDef("tcdelayline", -1);
Port("vdd.top");
Port("gnd.bot");
Port("left.in");
Port("left.bias");
Port("right.out");
Port("right.bias");
Instance("tcamp", "tc1");
Connect("tc1/W.in", "left.in");
Connect("tc1/W.bias", "left.bias");
Instance("tcamp", "tc2");
Connect("tc1/E*", "tc2/W*");
Instance("tcamp", "tc3");
Connect("tc2/E*", "tc3/W*");
#if 1
Instance("tcamp", "tc4");
Connect("tc3/E*", "tc4/W*");
Instance("tcamp", "tc5");
Connect("tc4/E*", "tc5/W*");
Instance("tcamp", "tc6");
Connect("tc5/E*", "tc6/W*");
Instance("tcamp", "tc7");
Connect("tc6/E*", "tc7/W*");
Instance("tcamp", "tc8");
Connect("tc7/E*", "tc8/W*");
#else
Instance("tcamp", "tc8");
Connect("tc3/E*", "tc8/W*");
#endif
Connect("tc8/E.out", "right.out");
Connect("tc8/E.bias", "right.bias");
Connect("tc*vdd", "vdd.top");
Connect("tc*gnd", "gnd.bot");
EndCell();
CellDef("wramp", -1);
Global("vdd");
Global("gnd");
Port("W.in");
Port("W.bias");
Port("E.out");
Port("E.bias");
Node("minusin");
Node("pmir");
Node("nmir");
Node("bias");
Node("minus");
N("wramp", "W.in", "pmir", "bias"); /* + input */
N("wramp", "minusin", "nmir", "bias"); /* - input */
N("wramp", "E.bias", "bias", "gnd"); /* bias */
P("wramp", "pmir", "pmir", "vdd");
P("wramp", "nmir", "nmir", "vdd");
P("wramp", "pmir", "E.out", "vdd");
P("wramp", "nmir", "minus", "vdd");
N("wramp", "minus", "minus", "gnd");
#if 0
N("wramp", "minus", "E.out", "gnd");
#else
/* test named parameter list */
N("wramp", "gate=minus", "drain=E.out", "source=gnd");
#endif
Connect("E.bias", "W.bias");
Connect("minusin", "E.out");
EndCell();
CellDef("wrdelayline", -1);
Composition = HORIZONTAL;
Place("wramp");
Place("wramp");
Place("wramp");
Place("wramp");
Place("wramp");
Place("wramp");
Place("wramp");
Place("wramp");
EndCell();
#endif /* TESTEMBEDDED */
#if TESTSHORTS
CellDef("short", -1);
Port("in");
Port("out");
Connect("in","out");
CellDef("top", -1);
Port("foo");
Port("bar");
Instance("short","short");
Connect("short/in", "foo");
Connect("short/out","bar");
#endif
#if TESTACTEL
ActelLib();
#endif /* TESTACTEL */
}
int main(int argc, char **argv)
{
Finsert(stderr);
InitializeCommandLine(argc, argv);
#ifdef TEST
test_entry();
#endif
#ifdef HAVE_X11
X_main_loop(argc, argv); /* does not return, if really running X */
#else
Query();
#endif
return(0);
}

119
base/timing.c Normal file
View File

@ -0,0 +1,119 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* timing.c -- routines to measure execution time of NETGEN commands */
/*************************************************************************/
/* */
/* General timing stuff: CPUTime returns process CPU time in seconds */
/* ElapsedCPUTime(t) returns time since t */
/* */
/*************************************************************************/
#include "config.h"
#include "timing.h"
#ifdef HAVE_CLOCK
#include <time.h>
#ifdef NEED_PROTOTYPES
extern clock_t clock(void); /* prototype */
#endif
float CPUTime(void)
/* return the process CPU time in seconds */
{
/* ANSI standard says CLK_TCK below, but this is not what HP says!!! */
return((float)(clock()) / (float) (CLOCKS_PER_SEC));
}
#else /* HAVE_CLOCK */
#ifdef HAVE_TIMES
#include <sys/types.h> /* for times(2) stuff */
#include <sys/param.h> /* for times(2) stuff */
#include <sys/times.h> /* for times(2) stuff */
/*
#ifndef HZ
#define HZ 60
#endif
*/
#ifdef NEED_PROTOTYPES
extern long times(struct tms *buf); /* prototype */
#endif
float CPUTime(void)
/* return the process CPU time in seconds */
{
struct tms buf;
times(&buf);
return((float)(buf.tms_utime) / (float) HZ);
}
#else /* not HAVE_TIMES */
#ifdef HAVE_GETRUSAGE
#include <sys/time.h>
#include <sys/resource.h>
#ifdef NEED_PROTOTYPES
extern int getrusage(int who, struct rusage *ruse);
#endif
float CPUTime(void)
{
struct rusage endtime;
getrusage(RUSAGE_SELF, &endtime);
/* user time is in a struct timeval endtime.ru_utime */
return(endtime.ru_utime.tv_sec + (float)(endtime.ru_utime.tv_usec)/1.0e6);
}
#else /* not HAVE_GETRUSAGE */
#include <time.h> /* for time() */
static long st;
float CPUTime(void)
/* return the elapsed CPU time in seconds (actually, elapsed wall time) */
{
long now;
time(&now);
/* keep start time offset in st, to prevent precision problems
when coercing to a float */
if (st == 0) st = now;
return((float)(now - st));
}
#endif /* HAVE_GETRUSAGE */
#endif /* HAVE_TIMES */
#endif /* HAVE_CLOCK */
float ElapsedCPUTime(float since)
{
return(CPUTime() - since);
}

3
base/timing.h Normal file
View File

@ -0,0 +1,3 @@
/* timing routines */
extern float CPUTime(void);
extern float ElapsedCPUTime(float since);

92
base/wombat.c Normal file
View File

@ -0,0 +1,92 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* wombat.c -- writing files for WOMBAT */
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#include "netgen.h"
#include "hash.h"
#include "objlist.h"
#include "netfile.h"
#include "print.h"
void Wombat(char *name, char *filename)
{
struct objlist *ob, *ob2;
struct nlist *tp, *tp2;
char FileName[500];
if (filename == NULL || strlen(filename) == 0)
SetExtension(FileName, name, WOMBAT_EXTENSION);
else strcpy(FileName, filename);
if (!OpenFile(FileName, 0)) {
SetExtension(FileName, FileName, WOMBAT_EXTENSION);
if (!OpenFile(FileName, 0)) {
perror("Wombat(): Unable to open output file.");
return;
}
}
tp = LookupCell(name);
if (tp == NULL) {
Printf ("No cell '%s' found.\n", name);
return;
}
/* now run through cell's contents, print instances */
ob = tp->cell;
while (ob != NULL) {
if (ob->type == FIRSTPIN) {
/* this is an instance */
FlushString ("%s %s ", ob->instance.name, ob->model.class);
/* print out parameter list */
ob2 = ob;
tp2 = LookupCell(ob->model.class);
do {
char *nm;
#if 1
struct objlist *newob;
/* was strchr 12/12/88 */
nm = strrchr(ob2->name, SEPARATOR[0]) + 1;
newob = LookupObject(nm, tp2);
if (match(nm, NodeAlias(tp2, newob)))
FlushString ("%s ", NodeAlias(tp, ob2));
#else
int nodenum;
nm = strrchr(ob2->name, SEPARATOR[0]) + 1;
nodenum = LookupObject(nm, tp2)->node;
if ((nodenum == -1) ||
match(nm, NodeName(tp2, nodenum)))
FlushString ("%s ", NodeName(tp, ob2->node));
#endif
ob2 = ob2->next;
} while ((ob2 != NULL) && (ob2->type > FIRSTPIN));
FlushString("\n");
}
ob = ob->next;
}
CloseFile(FileName);
}

368
base/xilinx.c Normal file
View File

@ -0,0 +1,368 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* xilinx.c -- Output routines for Xilinx's .xnf format */
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
#ifdef IBMPC
#include <stdlib.h> /* for strtol on PC */
#endif
#include "netgen.h"
#include "objlist.h"
#include "netfile.h"
#include "hash.h"
#include "print.h"
#define XILINXHASHSIZE 99
static long xilinxhashbase = 0xA00;
static struct hashlist *xilinxnametab[XILINXHASHSIZE];
static FILE *xilinxfile;
char *gndnet = "0";
char *vccnet = "1";
char *xilinx_pin(s)
char *s;
{
static char buf[80];
char *cp;
int inpar;
inpar = 0;
cp = NULL;
while(*s){
if(*s == '('){
cp = buf;
inpar++;
}else if(*s == ')'){
inpar++;
}else if(inpar){
*cp++ = *s;
}
s++;
}
if(cp){
*cp = '\0';
return(buf);
}else
return(NULL);
}
char *xilinx_name(prefix,s)
char *prefix;
char *s;
{
static char buf[80];
char *cp;
int inpar;
inpar = 0;
cp = buf;
while(*prefix)
*cp++ = *prefix++;
while(*s){
if(*s == '('){
inpar++;
}else if(*s == ')'){
inpar--;
}else if(*s >= 'a' && *s <= 'z'){
if(!inpar) *cp++ = *s;
}else if(*s >= 'A' && *s <= 'Z'){
if(!inpar) *cp++ = *s - 'A' + 'a';
}else if(*s >= '0' && *s <= '9'){
if(!inpar) *cp++ = *s;
}else{
if(!inpar) *cp++ = '$';
}
s++;
}
*cp = '\0';
return(buf);
}
struct cname {
int n;
char *actel;
char *xilinx;
} cname[] = {
{3, "DF1","DFF"},
{4, "DFC1","DFF"},
{3, "DFE","DFF"},
{6, "CLKBUF","ACLK"},
{5, "CLOCK","OSC"},
{5, "INBUF","IBUF"},
{6, "OUTBUF","OBUF"},
{5, "BIBUF","XXXX"},
{6, "TRIBUF","OBUFT"},
{2, "OR","OR"},
{3, "AND","AND"},
{3, "NOR","NOR"},
{4, "NAND","NAND"},
{0,NULL,NULL}
};
char *xilinx_class(model)
char *model;
{
struct cname *cnp;
cnp = cname;
while(cnp->n){
if(!strncmp(cnp->actel,model,cnp->n))
return(cnp->xilinx);
cnp++;
}
return(model);
}
Xilinx(cellname, filename)
char *cellname;
char *filename;
{
char Path[500];
char FileName[500];
if(LookupCell(cellname) == NULL){
Printf("No such cell name: %s\n", cellname);
return;
}
if(filename == NULL || strlen(filename) == 0)
strcpy(Path, cellname);
else
strcpy(Path, filename);
SetExtension(FileName, Path, XILINX_EXTENSION);
if (!OpenFile(FileName, 80)){
Printf("Failed to open file named: %s\n",FileName);
perror("Xilinx(): Unable to open output file.");
return;
}
ClearDumpedList();
InitializeHashTable(xilinxnametab, XILINXHASHSIZE);
if (LookupCell(cellname) != NULL)
xilinxCell(cellname);
CloseFile(FileName);
}
xilinxCell(cell)
char *cell;
{
struct nlist *nl;
struct objlist *ob;
struct objlist *xilinx_gate();
char *pname,dir;
int pin;
long t;
flattenCell(cell, -1);
nl = LookupCell(cell);
if(!nl)
return(0);
if (nl->class != CLASS_SUBCKT)
return(0);
time(&t);
FlushString("LCANET, 2\n");
FlushString("PROG, ntk2xnf, Created from %s %s",
nl->name,
ctime(&t)
);
ob = nl->cell;
while(ob){
/* a gate, collect the ports */
if(ob->type == FIRSTPIN){
ob = xilinx_gate(ob,nl);
}else
ob = ob->next;
}
ob = nl->cell;
while(ob){
if(ob->type == -91 || ob->type == -92 || ob->type == -93){
pname = xilinx_pin(ob->name);
switch(ob->type){
case -91: dir = 'I'; break;
case -92: dir = 'O'; break;
case -93: dir = 'B'; break;
default: dir = 'U'; break;
}
if(pname){
if(*pname){
FlushString("EXT,%s,%c,,LOC=%s\n",
xilinx_name("n$",ob->name),
dir,
pname
);
}else{
FlushString("EXT,%s,%c,,\n",
xilinx_name("n$",ob->name),
dir
);
}
}
}
ob = ob->next;
}
FlushString("PWR,1,%s\n",xilinx_name("n$",vccnet));
FlushString("PWR,0,%s\n",xilinx_name("n$",gndnet));
FlushString("EOF\n");
nl->dumped = 1;
return(1);
}
struct objlist *xilinx_gate(ob,nl)
struct objlist *ob;
struct nlist *nl;
{
struct nlist *gnl;
struct objlist *nob;
struct pins *pl,*npl;
nob = ob;
while(nob){
nob = nob->next;
if(nob && nob->type <= FIRSTPIN)
break;
}
xilinx_sym(nl,ob);
return(nob);
}
xilinx_sym(nl,gob)
struct nlist *nl;
struct objlist *gob;
{
struct objlist *ob;
char *cp,*rindex();
int pin;
struct objlist *xx;
char *inv,dir,*net;
FlushString("SYM,%s,%s\n",
xilinx_name("",gob->instance.name),
xilinx_class(gob->model.class)
);
ob = gob;
pin = 0;
while(ob){
if(ob->type <= pin)
break;
pin = ob->type;
cp = rindex(ob->name,'/');
cp++;
switch(*cp){
case '!':
inv = "INV"; cp++; break;
default:
inv = ""; break;
}
/*
XXX we need a better way to find out what direction
the pins is
*/
switch(*cp){
case 'Q':
case 'O':
dir = 'O'; break;
default:
dir = 'I'; break;
}
net = NodeAlias(nl,ob);
if(!strcmp(net,"Gnd"))
net = gndnet;
if(!strcmp(net,"Vcc"))
net = vccnet;
if(!strcmp(net,"Vdd"))
net = vccnet;
FlushString("PIN,%s,%c,%s,,%s\n",
cp,
dir,
xilinx_name("n$",net),
inv
);
ob = ob->next;
}
if(!strncmp(gob->model.class,"DF1",3)){
FlushString("PIN,RD,I,%s\n",xilinx_name("n$",gndnet));
FlushString("PIN,CE,I,%s\n",xilinx_name("n$",vccnet));
}
if(!strncmp(gob->model.class,"DFC1",4)){
FlushString("PIN,CE,I,%s\n",xilinx_name("n$",vccnet));
}
if(!strncmp(gob->model.class,"DFE",3)){
FlushString("PIN,RD,I,%s\n",xilinx_name("n$",gndnet));
}
FlushString("END\n");
ob = gob;
pin = 0;
while(ob){
if(ob->type <= pin)
break;
pin = ob->type;
net = NodeAlias(nl,ob);
cp = rindex(ob->name,'/');
xx = LookupObject(net,nl);
if(xx){
cp++;
switch(*cp){
case '!':
inv = "INV"; cp++; break;
default:
inv = ""; break;
}
switch(*cp){
case 'Q':
case 'O':
dir = 'O'; break;
default:
dir = 'I'; break;
}
if(IsPort(xx)){
if(dir == 'O')
xx->type = -92;
if(dir == 'I')
xx->type = -91;
}
if(xx->type == -92 && dir == 'I')
xx->type = -93;
if(xx->type == -91 && dir == 'O')
xx->type = -93;
}
ob = ob->next;
}
}

1264
base/xillib.c Normal file

File diff suppressed because it is too large Load Diff

2679
base/xnetgen.c Normal file

File diff suppressed because it is too large Load Diff

18
base/xnetgen.h Normal file
View File

@ -0,0 +1,18 @@
#ifdef __STDC__
void X_display_line(char *buf);
void X_display_cell(char *buf);
void X_display_refresh(void);
void X_clear_display(void);
void X_clear_cell(void);
void X_main_loop(int argc, char *argv[]); /* also in netgen.h */
#else
void X_display_line();
void X_display_cell();
void X_display_refresh();
void X_clear_display();
void X_clear_cell();
void X_main_loop(); /* also in netgen.h */
#endif

7
configure vendored Executable file
View File

@ -0,0 +1,7 @@
#!/bin/sh
#
# 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.
( CFLAGS="-g" ; export CFLAGS ; cd scripts ; ./configure $* )

211
dbug/Makefile Normal file
View File

@ -0,0 +1,211 @@
#
# FILE
#
# Makefile Makefile for dbug package
#
# SCCS ID
#
# @(#)Makefile 1.11 3/12/88
#
# DESCRIPTION
#
# Makefile for the dbug package (under UNIX system V or 4.2BSD).
#
# Interesting things to make are:
#
# lib => Makes the runtime support library in the
# current directory.
#
# lintlib => Makes the lint library in the current directory.
#
# install => Install pieces from current directory to
# where they belong.
#
# doc => Makes the documentation in the current
# directory.
#
# clean => Remove objects, temporary files, etc from
# current directory.
#
# superclean => Remove everything except sccs source files.
# Uses interactive remove for verification.
# Define NO_VARARGS if you have no <varargs.h> to include.
#VARARGS = -DNO_VARARGS
SH = /bin/sh
AR = ar
RM = rm
CFLAGS = -O $(VARARGS)
GFLAGS = -s
INSTALL = $(SH) install.sh
CHMOD = chmod
MAKE = make
INC = /usr/include/local
LIB = /usr/lib
RANLIB = $(SH) ranlib.sh
MODE = 664
# The following is provided for example only, it is set by "doinstall.sh".
LLIB = /usr/lib
.SUFFIXES: .r .r~ .c .c~
.c~.c:
$(GET) $(GFLAGS) -p $< >$*.c
.r~.r:
$(GET) $(GFLAGS) -p $< >$*.r
.c~.r:
$(GET) $(GFLAGS) -p $< >$*.c
sed "s/\\\/\\\e/" <$*.c >$*.r
$(RM) -f $*.c
.c.r:
sed "s/\\/\\e/" <$< >$*.r
# sed "s/\\\/\\\e/" <$< >$*.r
EXAMPLES = example1.r example2.r example3.r
OUTPUTS = output1.r output2.r output3.r output4.r output5.r
NROFF_INC = main.r factorial.r $(OUTPUTS) $(EXAMPLES)
#
# The default thing to do is remake the local runtime support
# library, local lint library, and local documentation as
# necessary.
#
all : lib lintlib analyze doc
lib : libdbug.a
lintlib : llib-ldbug.ln
doc : factorial user.t
#
# Make the local runtime support library "libdbug.a" from
# sources.
#
libdbug.a : dbug.o
rm -f $@
$(AR) cr $@ $?
$(RANLIB) $@
#
# Clean up the local directory.
#
clean :
$(RM) -f *.o *.ln *.a *.BAK nohup.out factorial $(NROFF_INC)
superclean :
$(RM) -i ?[!.]*
#
# Install the new header and library files. Since things go in
# different places depending upon the system (lint libraries
# go in /usr/lib under SV and /usr/lib/lint under BSD for example),
# the shell script "doinstall.sh" figures out the environment and
# does a recursive make with the appropriate pathnames set.
#
install :
$(SH) doinstall.sh $(MAKE) sysinstall
sysinstall: $(INC) $(INC)/dbug.h $(LIB)/libdbug.a \
$(LLIB)/llib-ldbug.ln $(LLIB)/llib-ldbug
$(INC) :
-if test -d $@ ;then true ;else mkdir $@ ;fi
$(INC)/dbug.h : dbug.h
$(INSTALL) $? $@
$(CHMOD) $(MODE) $@
$(LIB)/libdbug.a : libdbug.a
$(INSTALL) $? $@
$(CHMOD) $(MODE) $@
$(LLIB)/llib-ldbug.ln : llib-ldbug.ln
$(INSTALL) $? $@
$(CHMOD) $(MODE) $@
$(LLIB)/llib-ldbug : llib-ldbug
$(INSTALL) $? $@
$(CHMOD) $(MODE) $@
#
# Make the local lint library.
#
llib-ldbug.ln : llib-ldbug
$(SH) mklintlib.sh $? $@
#
# Make the test/example program "factorial".
#
# Note that the objects depend on the LOCAL dbug.h file and
# the compilations are set up to find dbug.h in the current
# directory even though the sources have "#include <dbug.h>".
# This allows the examples to look like the code a user would
# write but still be used as test cases for new versions
# of dbug.
factorial : main.o factorial.o libdbug.a
$(CC) -o $@ main.o factorial.o libdbug.a
main.o : main.c dbug.h
$(CC) $(CFLAGS) -c -I. main.c
factorial.o : factorial.c dbug.h
$(CC) $(CFLAGS) -c -I. factorial.c
#
# Make the analyze program for runtime profiling support.
#
analyze : analyze.o libdbug.a
$(CC) -o $@ analyze.o libdbug.a
analyze.o : analyze.c useful.h dbug.h
$(CC) $(CFLAGS) -c -I. analyze.c
#
# Rebuild the documentation
#
user.t : user.r $(NROFF_INC)
nroff -cm user.r >$@
#
# Run the factorial program to produce the sample outputs.
#
output1.r: factorial
./factorial 1 2 3 4 5 >$@
output2.r: factorial
./factorial -#t:o 2 3 >$@
output3.r: factorial
./factorial -#d:t:o 3 >$@
output4.r: factorial
./factorial -#d,result:o 4 >$@
output5.r: factorial
./factorial -#d:f,factorial:F:L:o 3 >$@
#
# All files included by user.r depend on user.r, thus
# forcing them to be remade if user.r changes.
#
$(NROFF_INC) : user.r

70
dbug/README.prof Normal file
View File

@ -0,0 +1,70 @@
Hi,
I'm sending you the modifications I made to your Dbug routines to
allow profiling in a (relatively) machine independent fashion.
I use your Dbug routines fairly extensively. Unfortunately, it's
a royal pain to have to keep profiled versions of various libraries
around. The modifications allow profiling without the need for this.
How it works.
------------
Basically, I just added code in the dbug routines to write out a file
called dbugmon.out (by default). This is an ascii file containing lines
of the form:
<function-name> E <time-entered>
<function-name> X <time-exited>
A second program (analyze) reads this file, and produces a report on
standard output.
Profiling is enabled through the `g' flag. It can take a list of
procedure names for which profiling is enabled. By default, it
profiles all procedures.
The code in ``dbug.c'' opens the profile file for appending. This
is in order that one can run a program several times, and get the
sum total of all the times, etc.
The only system dependent part that I'm aware of is the routine
Clock() at the end of dbug.c. This returns the elapsed user time
in milliseconds. The version which I have is for 4.3 BSD. As I
don't have access to other systems, I'm not certain how this would
change.
An example of the report generated follows:
Profile of Execution
Execution times are in milliseconds
Calls Time
----- ----
Times Percentage Time Spent Percentage
Function Called of total in Function of total Importance
======== ====== ========== =========== ========== ==========
factorial 5 83.33 30 100.00 8333
main 1 16.67 0 0.00 0
======== ====== ========== =========== ==========
Totals 6 100.00 30 100.00
As you can see, it's quite self-evident. The ``Importance'' column is a
metric obtained by multiplying the percentage of the calls and the percentage
of the time. Functions with higher 'importance' benefit the most from
being sped up.
I'm really not certain how to add support for setjmp/longjmp, or for
child processes, so I've ignored that for the time being. In most of
the code that I write, it isn't necessary. If you have any good ideas,
feel free to add them.
This has been very useful to me. If you can use it as part of your
dbug distribution, please feel free to do so.
Regards,
Binayak Banerjee
{allegra | astrovax | bpa | burdvax}!sjuvax!bbanerje
bbanerje%sjuvax.sju.edu@relay.cs.net
July 9, 1987

566
dbug/analyze.c Normal file
View File

@ -0,0 +1,566 @@
/*
* Analyze the profile file (cmon.out) written out by the dbug
* routines with profiling enabled.
*
* Copyright June 1987, Binayak Banerjee
* All rights reserved.
*
* This program may be freely distributed under the same terms and
* conditions as Fred Fish's Dbug package.
*
* Compile with -- cc -O -s -o %s analyze.c
*
* Analyze will read an trace file created by the dbug package
* (when run with traceing enabled). It will then produce a
* summary on standard output listing the name of each traced
* function, the number of times it was called, the percentage
* of total calls, the time spent executing the function, the
* proportion of the total time and the 'importance'. The last
* is a metric which is obtained by multiplying the proportions
* of calls and the proportions of time for each function. The
* greater the importance, the more likely it is that a speedup
* could be obtained by reducing the time taken by that function.
*
* Note that the timing values that you obtain are only rough
* measures. The overhead of the dbug package is included
* within. However, there is no need to link in special profiled
* libraries and the like.
*
* CHANGES:
*
* 2-Mar-89: fnf
* Changes to support tracking of stack usage. This required
* reordering the fields in the profile log file to make
* parsing of different record types easier. Corresponding
* changes made in dbug runtime library. Also used this
* opportunity to reformat the code more to my liking (my
* apologies to Binayak Banerjee for "uglifying" his code).
*
* 24-Jul-87: fnf
* Because I tend to use functions names like
* "ExternalFunctionDoingSomething", I've rearranged the
* printout to put the function name last in each line, so
* long names don't screw up the formatting unless they are
* *very* long and wrap around the screen width...
*
* 24-Jul-87: fnf
* Modified to put out table very similar to Unix profiler
* by default, but also puts out original verbose table
* if invoked with -v flag.
*/
#include <stdio.h>
#include "useful.h"
static char *my_name;
static int verbose;
/*
* Structure of the stack.
*/
#define PRO_FILE "dbugmon.out" /* Default output file name */
#define STACKSIZ 100 /* Maximum function nesting */
#define MAXPROCS 1000 /* Maximum number of function calls */
struct stack_t {
unsigned int pos; /* which function? */
unsigned long time; /* Time that this was entered */
unsigned long children; /* Time spent in called funcs */
};
static struct stack_t fn_stack[STACKSIZ+1];
static unsigned int stacktop = 0; /* Lowest stack position is a dummy */
static unsigned long tot_time = 0;
static unsigned long tot_calls = 0;
static unsigned long highstack = 0;
static unsigned long lowstack = ~0;
/*
* top() returns a pointer to the top item on the stack.
* (was a function, now a macro)
*/
#define top() &fn_stack[stacktop]
/*
* Push - Push the given record on the stack.
*/
void push (name_pos, time_entered)
register unsigned int name_pos;
register unsigned long time_entered;
{
register struct stack_t *t;
DBUG_ENTER("push");
if (++stacktop > STACKSIZ) {
fprintf (DBUG_FILE,"%s: stack overflow (%s:%d)\n",
my_name, __FILE__, __LINE__);
exit (EX_SOFTWARE);
}
DBUG_PRINT ("push", ("%d %ld",name_pos,time_entered));
t = &fn_stack[stacktop];
t -> pos = name_pos;
t -> time = time_entered;
t -> children = 0;
DBUG_VOID_RETURN;
}
/*
* Pop - pop the top item off the stack, assigning the field values
* to the arguments. Returns 0 on stack underflow, or on popping first
* item off stack.
*/
unsigned int pop (name_pos, time_entered, child_time)
register unsigned int *name_pos;
register unsigned long *time_entered;
register unsigned long *child_time;
{
register struct stack_t *temp;
register unsigned int rtnval;
DBUG_ENTER ("pop");
if (stacktop < 1) {
rtnval = 0;
} else {
temp = &fn_stack[stacktop];
*name_pos = temp->pos;
*time_entered = temp->time;
*child_time = temp->children;
DBUG_PRINT ("pop", ("%d %d %d",*name_pos,*time_entered,*child_time));
rtnval = stacktop--;
}
DBUG_RETURN (rtnval);
}
/*
* We keep the function info in another array (serves as a simple
* symbol table)
*/
struct module_t {
char *name;
unsigned long m_time;
unsigned long m_calls;
unsigned long m_stkuse;
};
static struct module_t modules[MAXPROCS];
/*
* We keep a binary search tree in order to look up function names
* quickly (and sort them at the end.
*/
struct bnode {
unsigned int lchild; /* Index of left subtree */
unsigned int rchild; /* Index of right subtree */
unsigned int pos; /* Index of module_name entry */
};
static struct bnode s_table[MAXPROCS];
static unsigned int n_items = 0; /* No. of items in the array so far */
/*
* Need a function to allocate space for a string and squirrel it away.
*/
char *strsave (s)
char *s;
{
register char *retval;
register unsigned int len;
extern char *malloc ();
DBUG_ENTER ("strsave");
DBUG_PRINT ("strsave", ("%s",s));
if (s == Nil (char) || (len = strlen (s)) == 0) {
DBUG_RETURN (Nil (char));
}
MALLOC (retval, ++len, char);
strcpy (retval, s);
DBUG_RETURN (retval);
}
/*
* add() - adds m_name to the table (if not already there), and returns
* the index of its location in the table. Checks s_table (which is a
* binary search tree) to see whether or not it should be added.
*/
unsigned int add (m_name)
char *m_name;
{
register unsigned int ind = 0;
register int cmp;
DBUG_ENTER ("add");
if (n_items == 0) { /* First item to be added */
s_table[0].pos = ind;
s_table[0].lchild = s_table[0].rchild = MAXPROCS;
addit:
modules[n_items].name = strsave (m_name);
modules[n_items].m_time = 0;
modules[n_items].m_calls = 0;
modules[n_items].m_stkuse = 0;
DBUG_RETURN (n_items++);
}
while (cmp = strcmp (m_name,modules[ind].name)) {
if (cmp < 0) { /* In left subtree */
if (s_table[ind].lchild == MAXPROCS) {
/* Add as left child */
if (n_items >= MAXPROCS) {
fprintf (DBUG_FILE,
"%s: Too many functions being profiled\n",
my_name);
exit (EX_SOFTWARE);
}
s_table[n_items].pos = s_table[ind].lchild = n_items;
s_table[n_items].lchild = s_table[n_items].rchild = MAXPROCS;
#ifdef notdef
modules[n_items].name = strsave (m_name);
modules[n_items].m_time = modules[n_items].m_calls = 0;
DBUG_RETURN (n_items++);
#else
goto addit;
#endif
}
ind = s_table[ind].lchild; /* else traverse l-tree */
} else {
if (s_table[ind].rchild == MAXPROCS) {
/* Add as right child */
if (n_items >= MAXPROCS) {
fprintf (DBUG_FILE,
"%s: Too many functions being profiled\n",
my_name);
exit (EX_SOFTWARE);
}
s_table[n_items].pos = s_table[ind].rchild = n_items;
s_table[n_items].lchild = s_table[n_items].rchild = MAXPROCS;
#ifdef notdef
modules[n_items].name = strsave (m_name);
modules[n_items].m_time = modules[n_items].m_calls = 0;
DBUG_RETURN (n_items++);
#else
goto addit;
#endif
}
ind = s_table[ind].rchild; /* else traverse r-tree */
}
}
DBUG_RETURN (ind);
}
/*
* process() - process the input file, filling in the modules table.
*/
void process (inf)
FILE *inf;
{
char buf[BUFSIZ];
char fn_name[64]; /* Max length of fn_name */
unsigned long fn_time;
unsigned long fn_sbot;
unsigned long fn_ssz;
unsigned long lastuse;
unsigned int pos;
unsigned long time;
unsigned int oldpos;
unsigned long oldtime;
unsigned long oldchild;
struct stack_t *t;
DBUG_ENTER ("process");
while (fgets (buf,BUFSIZ,inf) != NULL) {
switch (buf[0]) {
case 'E':
sscanf (buf+2, "%ld %64s", &fn_time, fn_name);
DBUG_PRINT ("erec", ("%ld %s", fn_time, fn_name));
pos = add (fn_name);
push (pos, fn_time);
break;
case 'X':
sscanf (buf+2, "%ld %64s", &fn_time, fn_name);
DBUG_PRINT ("xrec", ("%ld %s", fn_time, fn_name));
pos = add (fn_name);
/*
* An exited function implies that all stacked
* functions are also exited, until the matching
* function is found on the stack.
*/
while (pop (&oldpos, &oldtime, &oldchild)) {
DBUG_PRINT ("popped", ("%d %d", oldtime, oldchild));
time = fn_time - oldtime;
t = top ();
t -> children += time;
DBUG_PRINT ("update", ("%s", modules[t -> pos].name));
DBUG_PRINT ("update", ("%d", t -> children));
time -= oldchild;
modules[oldpos].m_time += time;
modules[oldpos].m_calls++;
tot_time += time;
tot_calls++;
if (pos == oldpos) {
goto next_line; /* Should be a break2 */
}
}
/*
* Assume that item seen started at time 0.
* (True for function main). But initialize
* it so that it works the next time too.
*/
t = top ();
time = fn_time - t -> time - t -> children;
t -> time = fn_time; t -> children = 0;
modules[pos].m_time += time;
modules[pos].m_calls++;
tot_time += time;
tot_calls++;
break;
case 'S':
sscanf (buf+2, "%lx %lx %64s", &fn_sbot, &fn_ssz, fn_name);
DBUG_PRINT ("srec", ("%lx %lx %s", fn_sbot, fn_ssz, fn_name));
pos = add (fn_name);
lastuse = modules[pos].m_stkuse;
#if 0
/*
* Needs further thought. Stack use is determined by
* difference in stack between two functions with DBUG_ENTER
* macros. If A calls B calls C, where A and C have the
* macros, and B doesn't, then B's stack use will be lumped
* in with either A's or C's. If somewhere else A calls
* C directly, the stack use will seem to change. Just
* take the biggest for now...
*/
if (lastuse > 0 && lastuse != fn_ssz) {
fprintf (stderr,
"warning - %s stack use changed (%lx to %lx)\n",
fn_name, lastuse, fn_ssz);
}
#endif
if (fn_ssz > lastuse) {
modules[pos].m_stkuse = fn_ssz;
}
if (fn_sbot > highstack) {
highstack = fn_sbot;
} else if (fn_sbot < lowstack) {
lowstack = fn_sbot;
}
break;
default:
fprintf (stderr, "unknown record type '%s'\n", buf[0]);
break;
}
next_line:;
}
/*
* Now, we've hit eof. If we still have stuff stacked, then we
* assume that the user called exit, so give everything the exited
* time of fn_time.
*/
while (pop (&oldpos,&oldtime,&oldchild)) {
time = fn_time - oldtime;
t = top ();
t -> children += time;
time -= oldchild;
modules[oldpos].m_time += time;
modules[oldpos].m_calls++;
tot_time += time;
tot_calls++;
}
DBUG_VOID_RETURN;
}
/*
* out_header () -- print out the header of the report.
*/
void out_header (outf)
FILE *outf;
{
DBUG_ENTER ("out_header");
if (verbose) {
fprintf (outf, "Profile of Execution\n");
fprintf (outf, "Execution times are in milliseconds\n\n");
fprintf (outf, " Calls\t\t\t Time\n");
fprintf (outf, " -----\t\t\t ----\n");
fprintf (outf, "Times\tPercentage\tTime Spent\tPercentage\n");
fprintf (outf, "Called\tof total\tin Function\tof total Importance\tFunction\n");
fprintf (outf, "======\t==========\t===========\t========== ==========\t========\t\n");
} else {
fprintf (outf, "%ld bytes of stack used, from %lx down to %lx\n\n",
highstack - lowstack, highstack, lowstack);
fprintf (outf,
" %%time sec #call ms/call %%calls weight stack name\n");
}
DBUG_VOID_RETURN;
}
/*
* out_trailer () - writes out the summary line of the report.
*/
void out_trailer (outf,sum_calls,sum_time)
FILE *outf;
unsigned long int sum_calls, sum_time;
{
DBUG_ENTER ("out_trailer");
if (verbose) {
fprintf (outf, "======\t==========\t===========\t==========\t========\n");
fprintf (outf, "%6d\t%10.2f\t%11d\t%10.2f\t\t%-15s\n",
sum_calls, 100.0, sum_time, 100.0, "Totals");
}
DBUG_VOID_RETURN;
}
/*
* out_item () - prints out the output line for a single entry,
* and sets the calls and time fields appropriately.
*/
void out_item (outf, m,called,timed)
FILE *outf;
register struct module_t *m;
unsigned long int *called, *timed;
{
char *name = m -> name;
register unsigned int calls = m -> m_calls;
register unsigned long time = m -> m_time;
register unsigned long stkuse = m -> m_stkuse;
unsigned int import;
double per_time = 0.0;
double per_calls = 0.0;
double ms_per_call, ftime;
DBUG_ENTER ("out_item");
if (tot_time > 0) {
per_time = (double) (time * 100) / (double) tot_time;
}
if (tot_calls > 0) {
per_calls = (double) (calls * 100) / (double) tot_calls;
}
import = (unsigned int) (per_time * per_calls);
if (verbose) {
fprintf (outf, "%6d\t%10.2f\t%11d\t%10.2f %10d\t%-15s\n",
calls, per_calls, time, per_time, import, name);
} else {
ms_per_call = time;
ms_per_call /= calls;
ftime = time;
ftime /= 1000;
fprintf (outf, "%8.2f%8.3f%8u%8.3f%8.2f%8u%8u %-s\n",
per_time, ftime, calls, ms_per_call, per_calls, import,
stkuse, name);
}
*called = calls;
*timed = time;
DBUG_VOID_RETURN;
}
/*
* out_body (outf, root,s_calls,s_time) -- Performs an inorder traversal
* on the binary search tree (root). Calls out_item to actually print
* the item out.
*/
void out_body (outf, root,s_calls,s_time)
FILE *outf;
register unsigned int root;
register unsigned long int *s_calls, *s_time;
{
unsigned long int calls, time;
DBUG_ENTER ("out_body");
DBUG_PRINT ("out_body", ("%d,%d",*s_calls,*s_time));
if (root == MAXPROCS) {
DBUG_PRINT ("out_body", ("%d,%d",*s_calls,*s_time));
} else {
while (root != MAXPROCS) {
out_body (outf, s_table[root].lchild,s_calls,s_time);
out_item (outf, &modules[s_table[root].pos],&calls,&time);
DBUG_PRINT ("out_body", ("-- %d -- %d --", calls, time));
*s_calls += calls;
*s_time += time;
root = s_table[root].rchild;
}
DBUG_PRINT ("out_body", ("%d,%d", *s_calls, *s_time));
}
DBUG_VOID_RETURN;
}
/*
* output () - print out a nice sorted output report on outf.
*/
void output (outf)
FILE *outf;
{
unsigned long int sum_calls = 0;
unsigned long int sum_time = 0;
DBUG_ENTER ("output");
if (n_items == 0) {
fprintf (outf, "%s: No functions to trace\n", my_name);
exit (EX_DATAERR);
}
out_header (outf);
out_body (outf, 0,&sum_calls,&sum_time);
out_trailer (outf, sum_calls,sum_time);
DBUG_VOID_RETURN;
}
#define usage() fprintf (DBUG_FILE,"Usage: %s [-v] [prof-file]\n",my_name)
main (argc, argv, environ)
int argc;
char *argv[], *environ[];
{
extern int optind, getopt ();
extern char *optarg;
register int c;
int badflg = 0;
FILE *infile;
FILE *outfile = {stdout};
DBUG_ENTER ("main");
DBUG_PROCESS (argv[0]);
my_name = argv[0];
while ((c = getopt (argc,argv,"#:v")) != EOF) {
switch (c) {
case '#': /* Debugging Macro enable */
DBUG_PUSH (optarg);
break;
case 'v': /* Verbose mode */
verbose++;
break;
default:
badflg++;
break;
}
}
if (badflg) {
usage ();
DBUG_RETURN (EX_USAGE);
}
if (optind < argc) {
FILEOPEN (infile, argv[optind], "r");
} else {
FILEOPEN (infile, PRO_FILE, "r");
}
process (infile);
output (outfile);
DBUG_RETURN (EX_OK);
}

1881
dbug/dbug.c Normal file

File diff suppressed because it is too large Load Diff

162
dbug/dbug.h Normal file
View File

@ -0,0 +1,162 @@
/******************************************************************************
* *
* N O T I C E *
* *
* Copyright Abandoned, 1987, Fred Fish *
* *
* *
* This previously copyrighted work has been placed into the public *
* domain by the author and may be freely used for any purpose, *
* private or commercial. *
* *
* Because of the number of inquiries I was receiving about the use *
* of this product in commercially developed works I have decided to *
* simply make it public domain to further its unrestricted use. I *
* specifically would be most happy to see this material become a *
* part of the standard Unix distributions by AT&T and the Berkeley *
* Computer Science Research Group, and a standard part of the GNU *
* system from the Free Software Foundation. *
* *
* I would appreciate it, as a courtesy, if this notice is left in *
* all copies and derivative works. Thank you. *
* *
* The author makes no warranty of any kind with respect to this *
* product and explicitly disclaims any implied warranties of mer- *
* chantability or fitness for any particular purpose. *
* *
******************************************************************************
*/
/*
* FILE
*
* dbug.h user include file for programs using the dbug package
*
* SYNOPSIS
*
* #include <local/dbug.h>
*
* SCCS ID
*
* @(#)dbug.h 1.12 4/2/89
*
* DESCRIPTION
*
* Programs which use the dbug package must include this file.
* It contains the appropriate macros to call support routines
* in the dbug runtime library.
*
* To disable compilation of the macro expansions define the
* preprocessor symbol "DBUG_OFF". This will result in null
* macros expansions so that the resulting code will be smaller
* and faster. (The difference may be smaller than you think
* so this step is recommended only when absolutely necessary).
* In general, tradeoffs between space and efficiency are
* decided in favor of efficiency since space is seldom a
* problem on the new machines).
*
* All externally visible symbol names follow the pattern
* "_db_xxx..xx_" to minimize the possibility of a dbug package
* symbol colliding with a user defined symbol.
*
* The DBUG_<N> style macros are obsolete and should not be used
* in new code. Macros to map them to instances of DBUG_PRINT
* are provided for compatibility with older code. They may go
* away completely in subsequent releases.
*
* AUTHOR
*
* Fred Fish
* (Currently employed by Motorola Computer Division, Tempe, Az.)
* hao!noao!mcdsun!fnf
* (602) 438-3614
*
*/
/*
* Internally used dbug variables which must be global.
*/
#ifndef DBUG_OFF
extern int _db_on_; /* TRUE if debug currently enabled */
extern FILE *_db_fp_; /* Current debug output stream */
extern char *_db_process_; /* Name of current process */
extern int _db_keyword_ (); /* Accept/reject keyword */
extern void _db_push_ (); /* Push state, set up new state */
extern void _db_pop_ (); /* Pop previous debug state */
extern void _db_enter_ (); /* New user function entered */
extern void _db_return_ (); /* User function return */
extern void _db_pargs_ (); /* Remember args for line */
extern void _db_setjmp_ (); /* Save debugger environment */
extern void _db_longjmp_ (); /* Restore debugger environment */
#ifndef NO_VARARGS
extern void _db_doprnt_ (char *, ...); /* Print debug output */
#else
extern void _db_doprnt_ ();
#endif
# endif
/*
* These macros provide a user interface into functions in the
* dbug runtime support library. They isolate users from changes
* in the MACROS and/or runtime support.
*
* The symbols "__LINE__" and "__FILE__" are expanded by the
* preprocessor to the current source file line number and file
* name respectively.
*
* WARNING --- Because the DBUG_ENTER macro allocates space on
* the user function's stack, it must precede any executable
* statements in the user function.
*
*/
# ifdef DBUG_OFF
# define DBUG_ENTER(a1)
# define DBUG_RETURN(a1) return(a1)
# define DBUG_VOID_RETURN return
# define DBUG_EXECUTE(keyword,a1)
# define DBUG_PRINT(keyword,arglist)
# define DBUG_2(keyword,format) /* Obsolete */
# define DBUG_3(keyword,format,a1) /* Obsolete */
# define DBUG_4(keyword,format,a1,a2) /* Obsolete */
# define DBUG_5(keyword,format,a1,a2,a3) /* Obsolete */
# define DBUG_PUSH(a1)
# define DBUG_POP()
# define DBUG_PROCESS(a1)
# define DBUG_FILE (stderr)
# define DBUG_SETJMP setjmp
# define DBUG_LONGJMP longjmp
# else
# define DBUG_ENTER(a) \
auto char *_db_func_; auto char *_db_file_; auto int _db_level_; \
auto char *_db_framep_; \
_db_enter_ (a,__FILE__,__LINE__,&_db_func_,&_db_file_,&_db_level_, \
&_db_framep_)
# define DBUG_LEAVE \
(_db_return_ (__LINE__, &_db_func_, &_db_file_, &_db_level_))
# define DBUG_RETURN(a1) return (DBUG_LEAVE, (a1))
/* define DBUG_RETURN(a1) {DBUG_LEAVE; return(a1);} Alternate form */
# define DBUG_VOID_RETURN {DBUG_LEAVE; return;}
# define DBUG_EXECUTE(keyword,a1) \
{if (_db_on_) {if (_db_keyword_ (keyword)) { a1 }}}
# define DBUG_PRINT(keyword,arglist) \
{if (_db_on_) {_db_pargs_(__LINE__,keyword); _db_doprnt_ arglist;}}
# define DBUG_2(keyword,format) \
DBUG_PRINT(keyword,(format)) /* Obsolete */
# define DBUG_3(keyword,format,a1) \
DBUG_PRINT(keyword,(format,a1)) /* Obsolete */
# define DBUG_4(keyword,format,a1,a2) \
DBUG_PRINT(keyword,(format,a1,a2)) /* Obsolete */
# define DBUG_5(keyword,format,a1,a2,a3) \
DBUG_PRINT(keyword,(format,a1,a2,a3)) /* Obsolete */
# define DBUG_PUSH(a1) _db_push_ (a1)
# define DBUG_POP() _db_pop_ ()
# define DBUG_PROCESS(a1) (_db_process_ = a1)
# define DBUG_FILE (_db_fp_)
# define DBUG_SETJMP(a1) (_db_setjmp_ (), setjmp (a1))
# define DBUG_LONGJMP(a1,a2) (_db_longjmp_ (), longjmp (a1, a2))
# endif

15
dbug/doinstall.sh Normal file
View File

@ -0,0 +1,15 @@
# Warning - first line left blank for sh/csh/ksh compatibility. Do not
# remove it. fnf@Unisoft
# doinstall.sh --- figure out environment and do recursive make with
# appropriate pathnames. Works under SV or BSD.
if [ -r /usr/include/search.h ]
then
# System V
$* LLIB=/usr/lib
else
# 4.2 BSD
$* LLIB=/usr/lib/lint
fi

12
dbug/example1.c Normal file
View File

@ -0,0 +1,12 @@
#include <stdio.h>
main (argc, argv)
int argc;
char *argv[];
{
printf ("argv[0] = %d\n", argv[0]);
/*
* Rest of program
*/
printf ("== done ==\n");
}

17
dbug/example2.c Normal file
View File

@ -0,0 +1,17 @@
#include <stdio.h>
int debug = 0;
main (argc, argv)
int argc;
char *argv[];
{
/* printf ("argv = %x\n", argv) */
if (debug) printf ("argv[0] = %d\n", argv[0]);
/*
* Rest of program
*/
#ifdef DEBUG
printf ("== done ==\n");
#endif
}

16
dbug/example3.c Normal file
View File

@ -0,0 +1,16 @@
#include <stdio.h>
main (argc, argv)
int argc;
char *argv[];
{
# ifdef DEBUG
printf ("argv[0] = %d\n", argv[0]);
# endif
/*
* Rest of program
*/
# ifdef DEBUG
printf ("== done ==\n");
# endif
}

15
dbug/factorial.c Normal file
View File

@ -0,0 +1,15 @@
#include <stdio.h>
/* User programs should use <local/dbug.h> */
#include "dbug.h"
int factorial (value)
register int value;
{
DBUG_ENTER ("factorial");
DBUG_PRINT ("find", ("find %d factorial", value));
if (value > 1) {
value *= factorial (value - 1);
}
DBUG_PRINT ("result", ("result is %d", value));
DBUG_RETURN (value);
}

64
dbug/install.sh Normal file
View File

@ -0,0 +1,64 @@
# WARNING -- first line intentionally left blank for sh/csh/ksh
# compatibility. Do not remove it! FNF, UniSoft Systems.
#
# Usage is:
# install <from> <to>
#
# The file <to> is replaced with the file <from>, after first
# moving <to> to a backup file. The backup file name is created
# by prepending the filename (after removing any leading pathname
# components) with "OLD".
#
# This script is currently not real robust in the face of signals
# or permission problems. It also does not do (by intention) all
# the things that the System V or BSD install scripts try to do
#
if [ $# -ne 2 ]
then
echo "usage: $0 <from> <to>"
exit 1
fi
# Now extract the dirname and basename components. Unfortunately, BSD does
# not have dirname, so we do it the hard way.
fd=`expr $1'/' : '\(/\)[^/]*/$' \| $1'/' : '\(.*[^/]\)//*[^/][^/]*//*$' \| .`
ff=`basename $1`
td=`expr $2'/' : '\(/\)[^/]*/$' \| $2'/' : '\(.*[^/]\)//*[^/][^/]*//*$' \| .`
tf=`basename $2`
# Now test to make sure that they are not the same files.
if [ $fd/$ff = $td/$tf ]
then
echo "install: input and output are same files"
exit 2
fi
# Save a copy of the "to" file as a backup.
if test -f $td/$tf
then
if test -f $td/OLD$tf
then
rm -f $td/OLD$tf
fi
mv $td/$tf $td/OLD$tf
if [ $? != 0 ]
then
exit 3
fi
fi
# Now do the copy and return appropriate status
cp $fd/$ff $td/$tf
if [ $? != 0 ]
then
exit 4
else
exit 0
fi

129
dbug/llib-ldbug Normal file
View File

@ -0,0 +1,129 @@
/*
******************************************************************************
* *
* N O T I C E *
* *
* Copyright Abandoned, 1987, Fred Fish *
* *
* *
* This previously copyrighted work has been placed into the public *
* domain by the author and may be freely used for any purpose, *
* private or commercial. *
* *
* Because of the number of inquiries I was receiving about the use *
* of this product in commercially developed works I have decided to *
* simply make it public domain to further its unrestricted use. I *
* specifically would be most happy to see this material become a *
* part of the standard Unix distributions by AT&T and the Berkeley *
* Computer Science Research Group, and a standard part of the GNU *
* system from the Free Software Foundation. *
* *
* I would appreciate it, as a courtesy, if this notice is left in *
* all copies and derivative works. Thank you. *
* *
* The author makes no warranty of any kind with respect to this *
* product and explicitly disclaims any implied warranties of mer- *
* chantability or fitness for any particular purpose. *
* *
******************************************************************************
*/
/*
* FILE
*
* llib-ldbug lint library source for debugging package
*
* SCCS ID
*
* @(#)llib-ldbug 1.9 6/12/89
*
* DESCRIPTION
*
* Function definitions for use in building lint library.
* Note that these must stay in syncronization with actual
* declarations in "dbug.c".
*
*/
/*LINTLIBRARY*/
#include <stdio.h>
#define VOID void
typedef int BOOLEAN;
#define FALSE 0
#define ARGLIST a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15
int _db_on_ = FALSE;
int _db_pon_ = FALSE;
FILE *_db_fp_ = stderr;
FILE *_db_pfp_ = stderr;
char *_db_process_ = "dbug";
VOID _db_push_ (control)
char *control;
{
}
VOID _db_pop_ ()
{
}
VOID _db_enter_ (_func_, _file_, _line_, _sfunc_, _sfile_, _slevel_, _sframep_)
char *_func_;
char *_file_;
int _line_;
char **_sfunc_;
char **_sfile_;
int *_slevel_;
char ***_sframep_;
{
}
VOID _db_return_ (_line_, _sfunc_, _sfile_, _slevel_)
int _line_;
char **_sfunc_;
char **_sfile_;
int *_slevel_;
{
}
VOID _db_pargs_ (_line_, keyword)
int _line_;
char *keyword;
{
}
/*VARARGS1*/
VOID _db_doprnt_ (format, ARGLIST)
char *format;
long ARGLIST;
{
}
/* WARNING -- the following function is obsolete and may not be supported */
/* in future releases... */
/*VARARGS3*/
VOID _db_printf_ (_line_, keyword, format, ARGLIST)
int _line_;
char *keyword, *format;
long ARGLIST;
{
}
BOOLEAN _db_keyword_ (keyword)
char *keyword;
{
return (0);
}
VOID _db_longjmp_ ()
{
}
VOID _db_setjmp_ ()
{
}

27
dbug/main.c Normal file
View File

@ -0,0 +1,27 @@
#include <stdio.h>
/* User programs should use <local/dbug.h> */
#include "dbug.h"
main (argc, argv)
int argc;
char *argv[];
{
register int result, ix;
extern int factorial (), atoi ();
DBUG_ENTER ("main");
DBUG_PROCESS (argv[0]);
for (ix = 1; ix < argc && argv[ix][0] == '-'; ix++) {
switch (argv[ix][1]) {
case '#':
DBUG_PUSH (&(argv[ix][2]));
break;
}
}
for (; ix < argc; ix++) {
DBUG_PRINT ("args", ("argv[%d] = %s", ix, argv[ix]));
result = factorial (atoi (argv[ix]));
printf ("%d\n", result);
}
DBUG_RETURN (0);
}

30
dbug/mklintlib.sh Normal file
View File

@ -0,0 +1,30 @@
# Warning - first line left blank for sh/csh/ksh compatibility. Do not
# remove it. fnf@Unisoft
# mklintlib --- make a lint library, under either System V or 4.2 BSD
#
# usage: mklintlib <infile> <outfile>
#
if test $# -ne 2
then
echo "usage: mklintlib <infile> <outfile>"
exit 1
fi
if grep SIGTSTP /usr/include/signal.h >/dev/null
then # BSD
if test -r /usr/include/whoami.h # 4.1
then
/lib/cpp -C -Dlint $1 >hlint
(/usr/lib/lint/lint1 <hlint >$2) 2>&1 | grep -v warning
else # 4.2
lint -Cxxxx $1
mv llib-lxxxx.ln $2
fi
else # USG
cc -E -C -Dlint $1 | /usr/lib/lint1 -vx -Hhlint >$2
rm -f hlint
fi
exit 0 # don't kill make

15
dbug/ranlib.sh Normal file
View File

@ -0,0 +1,15 @@
# Warning - first line left blank for sh/csh/ksh compatibility. Do not
# remove it. fnf@Unisoft
# ranlib --- do a ranlib if necessary
if [ -x /usr/bin/ranlib ]
then
/usr/bin/ranlib $*
elif [ -x /bin/ranlib ]
then
/bin/ranlib $*
else
:
fi

84
dbug/useful.h Normal file
View File

@ -0,0 +1,84 @@
/*
* Copyright June 1987, Binayak Banerjee
* All rights reserved.
*
* This program may be freely distributed under the same terms and
* conditions as Fred Fish's Dbug package.
*
* Useful macros which I use a lot.
*
* Conditionally include some useful files.
*/
# ifndef EOF
# include <stdio.h>
# endif
/*
* For BSD systems, you can include <sysexits.h> for more detailed
* exit information. For non-BSD systems (which also includes
* non-unix systems) just map everything to "failure" = 1 and
* "success" = 0. -Fred Fish 9-Sep-87
*/
# ifdef BSD
# include <sysexits.h>
# else
# define EX_SOFTWARE 1
# define EX_DATAERR 1
# define EX_USAGE 1
# define EX_OSERR 1
# define EX_IOERR 1
# define EX_OK 0
# endif
/*
* Fred Fish's debugging stuff. Define DBUG_OFF in order to disable if
* you don't have these.
*/
# ifndef DBUG_OFF
# include "dbug.h" /* Use local version */
# else
# define DBUG_ENTER(a1)
# define DBUG_RETURN(a1) return(a1)
# define DBUG_VOID_RETURN return
# define DBUG_EXECUTE(keyword,a1)
# define DBUG_2(keyword,format)
# define DBUG_3(keyword,format,a1)
# define DBUG_4(keyword,format,a1,a2)
# define DBUG_5(keyword,format,a1,a2,a3)
# define DBUG_PUSH(a1)
# define DBUG_POP()
# define DBUG_PROCESS(a1)
# define DBUG_PRINT(x,y)
# define DBUG_FILE (stderr)
# endif
#define __MERF_OO_ "%s: Malloc Failed in %s: %d\n"
#define Nil(Typ) ((Typ *) 0) /* Make Lint happy */
#define MALLOC(Ptr,Num,Typ) do /* Malloc w/error checking & exit */ \
if ((Ptr = (Typ *)malloc((Num)*(sizeof(Typ)))) == Nil(Typ)) \
{fprintf(stderr,__MERF_OO_,my_name,__FILE__,__LINE__);\
exit(EX_OSERR);} while(0)
#define Malloc(Ptr,Num,Typ) do /* Weaker version of above */\
if ((Ptr = (Typ *)malloc((Num)*(sizeof(Typ)))) == Nil(Typ)) \
fprintf(stderr,__MERF_OO_,my_name,__FILE__,__LINE__);\
while(0)
#define FILEOPEN(Fp,Fn,Mod) do /* File open with error exit */ \
if((Fp = fopen(Fn,Mod)) == Nil(FILE))\
{fprintf(stderr,"%s: Couldn't open %s\n",my_name,Fn);\
exit(EX_IOERR);} while(0)
#define Fileopen(Fp,Fn,Mod) do /* Weaker version of above */ \
if((Fp = fopen(Fn,Mod)) == Nil(FILE)) \
fprintf(stderr,"%s: Couldn't open %s\n",my_name,Fn);\
while(0)
extern char *my_name; /* The name that this was called as */

943
dbug/user.r Normal file
View File

@ -0,0 +1,943 @@
.\" @(#)user.r 1.16 8/7/88
.\"
.\" DBUG (Macro Debugger Package) nroff source
.\"
.\" nroff -mm user.r >user.t
.\"
.\" ===================================================
.\"
.\" === Some sort of black magic, but I forget...
.tr ~
.\" === Hyphenation control (1 = on)
.\".nr Hy 1
.\" === Force all first level headings to start on new page
.nr Ej 1
.\" === Set for breaks after headings for levels 1-3
.nr Hb 3
.\" === Set for space after headings for levels 1-3
.nr Hs 3
.\" === Set standard indent for one/half inch
.nr Si 10
.\" === Set page header
.PH "/DBUG User Manual//\*(DT/"
.\" === Set page footer
.PF "// - % - //"
.\" === Set page offset
.\".po 0.60i
.\" === Set line length
.\".ll 6.5i
.TL
D B U G
.P 0
C Program Debugging Package
.P 0
by
.AU "Fred Fish"
.AF ""
.SA 1
.\" === All paragraphs indented.
.nr Pt 1
.AS 1
This document introduces
.I dbug ,
a macro based C debugging
package which has proven to be a very flexible and useful tool
for debugging, testing, and porting C programs.
.P
All of the features of the
.I dbug
package can be enabled or disabled dynamically at execution time.
This means that production programs will run normally when
debugging is not enabled, and eliminates the need to maintain two
separate versions of a program.
.P
Many of the things easily accomplished with conventional debugging
tools, such as symbolic debuggers, are difficult or impossible with this
package, and vice versa.
Thus the
.I dbug
package should
.I not
be thought of as a replacement or substitute for
other debugging tools, but simply as a useful
.I addition
to the
program development and maintenance environment.
.AE
.MT 4
.SK
.B
INTRODUCTION
.R
.P
Almost every program development environment worthy of the name
provides some sort of debugging facility.
Usually this takes the form of a program which is capable of
controlling execution of other programs and examining the internal
state of other executing programs.
These types of programs will be referred to as external debuggers
since the debugger is not part of the executing program.
Examples of this type of debugger include the
.B adb
and
.B sdb
debuggers provided with the
.B UNIX\*F
.FS
UNIX is a trademark of AT&T Bell Laboratories.
.FE
operating system.
.P
One of the problems associated with developing programs in an environment
with good external debuggers is that developed programs tend to have
little or no internal instrumentation.
This is usually not a problem for the developer since he is,
or at least should be, intimately familiar with the internal organization,
data structures, and control flow of the program being debugged.
It is a serious problem for maintenance programmers, who
are unlikely to have such familiarity with the program being
maintained, modified, or ported to another environment.
It is also a problem, even for the developer, when the program is
moved to an environment with a primitive or unfamiliar debugger,
or even no debugger.
.P
On the other hand,
.I dbug
is an example of an internal debugger.
Because it requires internal instrumentation of a program,
and its usage does not depend on any special capabilities of
the execution environment, it is always available and will
execute in any environment that the program itself will
execute in.
In addition, since it is a complete package with a specific
user interface, all programs which use it will be provided
with similar debugging capabilities.
This is in sharp contrast to other forms of internal instrumentation
where each developer has their own, usually less capable, form
of internal debugger.
In summary,
because
.I dbug
is an internal debugger it provides consistency across operating
environments,
and because it is available to all developers it provides
consistency across all programs in the same environment.
.P
The
.I dbug
package imposes only a slight speed penalty on executing
programs, typically much less than 10 percent, and a modest size
penalty, typically 10 to 20 percent.
By defining a specific C preprocessor symbol both of these
can be reduced to zero with no changes required to the
source code.
.P
The following list is a quick summary of the capabilities
of the
.I dbug
package.
Each capability can be individually enabled or disabled
at the time a program is invoked by specifying the appropriate
command line arguments.
.SP 1
.ML o 1i
.LI
Execution trace showing function level control flow in a
semi-graphically manner using indentation to indicate nesting
depth.
.LI
Output the values of all, or any subset of, key internal variables.
.LI
Limit actions to a specific set of named functions.
.LI
Limit function trace to a specified nesting depth.
.LI
Label each output line with source file name and line number.
.LI
Label each output line with name of current process.
.LI
Push or pop internal debugging state to allow execution with
built in debugging defaults.
.LI
Redirect the debug output stream to standard output (stdout)
or a named file.
The default output stream is standard error (stderr).
The redirection mechanism is completely independent of
normal command line redirection to avoid output conflicts.
.LE
.SK
.B
PRIMITIVE DEBUGGING TECHNIQUES
.R
.P
Internal instrumentation is already a familiar concept
to most programmers, since it is usually the first debugging
technique learned.
Typically, "print\ statements" are inserted in the source
code at interesting points, the code is recompiled and executed,
and the resulting output is examined in an attempt to determine
where the problem is.
The procedure is iterative, with each iteration yielding more
and more output, and hopefully the source of the problem is
discovered before the output becomes too large to deal with
or previously inserted statements need to be removed.
Figure 1 is an example of this type of primitive debugging
technique.
.DS I N
.SP 2
.so example1.r
.SP 2
.ll -5
.ce
Figure 1
.ce
Primitive Debugging Technique
.ll +5
.SP 2
.DE
.P
Eventually, and usually after at least several iterations, the
problem will be found and corrected.
At this point, the newly inserted print statements must be
dealt with.
One obvious solution is to simply delete them all.
Beginners usually do this a few times until they have to
repeat the entire process every time a new bug pops up.
The second most obvious solution is to somehow disable
the output, either through the source code comment facility,
creation of a debug variable to be switched on or off, or by using the
C preprocessor.
Figure 2 is an example of all three techniques.
.DS I N
.SP 2
.so example2.r
.SP 2
.ll -5
.ce
Figure 2
.ce
Debug Disable Techniques
.ll +5
.SP 2
.DE
.P
Each technique has its advantages and disadvantages with respect
to dynamic vs static activation, source code overhead, recompilation
requirements, ease of use, program readability, etc.
Overuse of the preprocessor solution quickly leads to problems with
source code readability and maintainability when multiple
.B #ifdef
symbols are to be defined or undefined based on specific types
of debug desired.
The source code can be made slightly more readable by suitable indentation
of the
.B #ifdef
arguments to match the indentation of the code, but
not all C preprocessors allow this.
The only requirement for the standard
.B UNIX
C preprocessor is for the '#' character to appear
in the first column, but even this seems
like an arbitrary and unreasonable restriction.
Figure 3 is an example of this usage.
.DS I N
.SP 2
.so example3.r
.SP 2
.ll -5
.ce
Figure 3
.ce
More Readable Preprocessor Usage
.ll +5
.SP 2
.DE
.SK
.B
FUNCTION TRACE EXAMPLE
.R
.P
We will start off learning about the capabilities of the
.I dbug
package by using a simple minded program which computes the
factorial of a number.
In order to better demonstrate the function trace mechanism, this
program is implemented recursively.
Figure 4 is the main function for this factorial program.
.DS I N
.SP 2
.so main.r
.SP 2
.ll -5
.ce
Figure 4
.ce
Factorial Program Mainline
.ll +5
.SP 2
.DE
.P
The
.B main
function is responsible for processing any command line
option arguments and then computing and printing the factorial of
each non-option argument.
.P
First of all, notice that all of the debugger functions are implemented
via preprocessor macros.
This does not detract from the readability of the code and makes disabling
all debug compilation trivial (a single preprocessor symbol,
.B DBUG_OFF ,
forces the macro expansions to be null).
.P
Also notice the inclusion of the header file
.B dbug.h
from the local header file directory.
(The version included here is the test version in the dbug source
distribution directory).
This file contains all the definitions for the debugger macros, which
all have the form
.B DBUG_XX...XX .
.P
The
.B DBUG_ENTER
macro informs that debugger that we have entered the
function named
.B main .
It must be the very first "executable" line in a function, after
all declarations and before any other executable line.
The
.B DBUG_PROCESS
macro is generally used only once per program to
inform the debugger what name the program was invoked with.
The
.B DBUG_PUSH
macro modifies the current debugger state by
saving the previous state and setting a new state based on the
control string passed as its argument.
The
.B DBUG_PRINT
macro is used to print the values of each argument
for which a factorial is to be computed.
The
.B DBUG_RETURN
macro tells the debugger that the end of the current
function has been reached and returns a value to the calling
function.
All of these macros will be fully explained in subsequent sections.
.P
To use the debugger, the factorial program is invoked with a command
line of the form:
.DS CB N
factorial -#d:t 1 2 3
.DE
The
.B main
function recognizes the "-#d:t" string as a debugger control
string, and passes the debugger arguments ("d:t") to the
.I dbug
runtime support routines via the
.B DBUG_PUSH
macro.
This particular string enables output from the
.B DBUG_PRINT
macro with the 'd' flag and enables function tracing with the 't' flag.
The factorial function is then called three times, with the arguments
"1", "2", and "3".
Note that the DBUG_PRINT takes exactly
.B two
arguments, with the second argument (a format string and list
of printable values) enclosed in parenthesis.
.P
Debug control strings consist of a header, the "-#", followed
by a colon separated list of debugger arguments.
Each debugger argument is a single character flag followed
by an optional comma separated list of arguments specific
to the given flag.
Some examples are:
.DS CB N
-#d:t:o
-#d,in,out:f,main:F:L
.DE
Note that previously enabled debugger actions can be disabled by the
control string "-#".
.P
The definition of the factorial function, symbolized as "N!", is
given by:
.DS CB N
N! = N * N-1 * ... 2 * 1
.DE
Figure 5 is the factorial function which implements this algorithm
recursively.
Note that this is not necessarily the best way to do factorials
and error conditions are ignored completely.
.DS I N
.SP 2
.so factorial.r
.SP 2
.ll -5
.ce
Figure 5
.ce
Factorial Function
.ll +5
.SP 2
.DE
.P
One advantage (some may not consider it so) to using the
.I dbug
package is that it strongly encourages fully structured coding
with only one entry and one exit point in each function.
Multiple exit points, such as early returns to escape a loop,
may be used, but each such point requires the use of an
appropriate
.B DBUG_RETURN
or
.B DBUG_VOID_RETURN
macro.
.P
To build the factorial program on a
.B UNIX
system, compile and
link with the command:
.DS CB N
cc -o factorial main.c factorial.c -ldbug
.DE
The "-ldbug" argument tells the loader to link in the
runtime support modules for the
.I dbug
package.
Executing the factorial program with a command of the form:
.DS CB N
factorial 1 2 3 4 5
.DE
generates the output shown in figure 6.
.DS I N
.SP 2
.so output1.r
.SP 2
.ll -5
.ce
Figure 6
.ce
factorial 1 2 3 4 5
.ll +5
.SP 2
.DE
.P
Function level tracing is enabled by passing the debugger
the 't' flag in the debug control string.
Figure 7 is the output resulting from the command
"factorial\ -#t:o\ 3\ 2".
.DS I N
.SP 2
.so output2.r
.SP 2
.ll -5
.ce
Figure 7
.ce
factorial -#t:o 3 2
.ll +5
.SP 2
.DE
.P
Each entry to or return from a function is indicated by '>' for the
entry point and '<' for the exit point, connected by
vertical bars to allow matching points to be easily found
when separated by large distances.
.P
This trace output indicates that there was an initial call
to factorial from main (to compute 2!), followed by
a single recursive call to factorial to compute 1!.
The main program then output the result for 2! and called the
factorial function again with the second argument, 3.
Factorial called itself recursively to compute 2! and 1!, then
returned control to main, which output the value for 3! and exited.
.P
Note that there is no matching entry point "main>" for the
return point "<main" because at the time the
.B DBUG_ENTER
macro was reached in main, tracing was not enabled yet.
It was only after the macro
.B DBUG_PUSH
was executing that tracing became enabled.
This implies that the argument list should be processed as early as
possible since all code preceding the first call to
.B DBUG_PUSH
is
essentially invisible to
.B dbug
(this can be worked around by
inserting a temporary
.B DBUG_PUSH(argv[1])
immediately after the
.B DBUG_ENTER("main")
macro.
.P
One last note,
the trace output normally comes out on the standard error.
Since the factorial program prints its result on the standard
output, there is the possibility of the output on the terminal
being scrambled if the two streams are not synchronized.
Thus the debugger is told to write its output on the standard
output instead, via the 'o' flag character.
Note that no 'o' implies the default (standard error), a 'o'
with no arguments means standard output, and a 'o'
with an argument means used the named file.
I.E, "factorial\ -#t:o,logfile\ 3\ 2" would write the trace
output in "logfile".
Because of
.B UNIX
implementation details, programs usually run
faster when writing to stdout rather than stderr, though this
is not a prime consideration in this example.
.SK
.B
USE OF DBUG_PRINT MACRO
.R
.P
The mechanism used to produce "printf" style output is the
.B DBUG_PRINT
macro.
.P
To allow selection of output from specific macros, the first argument
to every
.B DBUG_PRINT
macro is a
.I dbug
keyword.
When this keyword appears in the argument list of the 'd' flag in
a debug control string, as in "-#d,keyword1,keyword2,...:t",
output from the corresponding macro is enabled.
The default when there is no 'd' flag in the control string is to
enable output from all
.B DBUG_PRINT
macros.
.P
Typically, a program will be run once, with no keywords specified,
to determine what keywords are significant for the current problem
(the keywords are printed in the macro output line).
Then the program will be run again, with the desired keywords,
to examine only specific areas of interest.
.P
The second argument to a
.B DBUG_PRINT
macro is a standard printf style
format string and one or more arguments to print, all
enclosed in parenthesis so that they collectively become a single macro
argument.
This is how variable numbers of printf arguments are supported.
Also note that no explicit newline is required at the end of the format string.
As a matter of style, two or three small
.B DBUG_PRINT
macros are preferable
to a single macro with a huge format string.
Figure 8 shows the output for default tracing and debug.
.DS I N
.SP 2
.so output3.r
.SP 2
.ll -5
.ce
Figure 8
.ce
factorial -#d:t:o 3
.ll +5
.SP 2
.DE
.P
The output from the
.B DBUG_PRINT
macro is indented to match the trace output
for the function in which the macro occurs.
When debugging is enabled, but not trace, the output starts at the left
margin, without indentation.
.P
To demonstrate selection of specific macros for output, figure
9 shows the result when the factorial program is invoked with
the debug control string "-#d,result:o".
.DS I N
.SP 2
.so output4.r
.SP 2
.ll -5
.ce
Figure 9
.ce
factorial -#d,result:o 4
.ll +5
.SP 2
.DE
.P
It is sometimes desirable to restrict debugging and trace actions
to a specific function or list of functions.
This is accomplished with the 'f' flag character in the debug
control string.
Figure 10 is the output of the factorial program when run with the
control string "-#d:f,factorial:F:L:o".
The 'F' flag enables printing of the source file name and the 'L'
flag enables printing of the source file line number.
.DS I N
.SP 2
.so output5.r
.SP 2
.ll -5
.ce
Figure 10
.ce
factorial -#d:f,factorial:F:L:o 3
.ll +5
.SP 2
.DE
.P
The output in figure 10 shows that the "find" macro is in file
"factorial.c" at source line 8 and the "result" macro is in the same
file at source line 12.
.SK
.B
SUMMARY OF MACROS
.R
.P
This section summarizes the usage of all currently defined macros
in the
.I dbug
package.
The macros definitions are found in the user include file
.B dbug.h
from the standard include directory.
.SP 2
.BL 20
.LI DBUG_ENTER\
Used to tell the runtime support module the name of the function
being entered.
The argument must be of type "pointer to character".
The
DBUG_ENTER
macro must precede all executable lines in the
function just entered, and must come after all local declarations.
Each
DBUG_ENTER
macro must have a matching
DBUG_RETURN
or
DBUG_VOID_RETURN
macro
at the function exit points.
DBUG_ENTER
macros used without a matching
DBUG_RETURN
or
DBUG_VOID_RETURN
macro
will cause warning messages from the
.I dbug
package runtime support module.
.SP 1
EX:\ DBUG_ENTER\ ("main");
.SP 1
.LI DBUG_RETURN\
Used at each exit point of a function containing a
DBUG_ENTER
macro
at the entry point.
The argument is the value to return.
Functions which return no value (void) should use the
DBUG_VOID_RETURN
macro.
It
is an error to have a
DBUG_RETURN
or
DBUG_VOID_RETURN
macro in a function
which has no matching
DBUG_ENTER
macro, and the compiler will complain
if the macros are actually used (expanded).
.SP 1
EX:\ DBUG_RETURN\ (value);
.br
EX:\ DBUG_VOID_RETURN;
.SP 1
.LI DBUG_PROCESS\
Used to name the current process being executed.
A typical argument for this macro is "argv[0]", though
it will be perfectly happy with any other string.
.SP 1
EX:\ DBUG_PROCESS\ (argv[0]);
.SP 1
.LI DBUG_PUSH\
Sets a new debugger state by pushing the current
.B dbug
state onto an
internal stack and setting up the new state using the debug control
string passed as the macro argument.
The most common usage is to set the state specified by a debug
control string retrieved from the argument list.
Note that the leading "-#" in a debug control string specified
as a command line argument must
.B not
be passed as part of the macro argument.
The proper usage is to pass a pointer to the first character
.B after
the "-#" string.
.SP 1
EX:\ DBUG_PUSH\ (\&(argv[i][2]));
.br
EX:\ DBUG_PUSH\ ("d:t");
.br
EX:\ DBUG_PUSH\ ("");
.SP 1
.LI DBUG_POP\
Restores the previous debugger state by popping the state stack.
Attempting to pop more states than pushed will be ignored and no
warning will be given.
The
DBUG_POP
macro has no arguments.
.SP 1
EX:\ DBUG_POP\ ();
.SP 1
.LI DBUG_FILE\
The
DBUG_FILE
macro is used to do explicit I/O on the debug output
stream.
It is used in the same manner as the symbols "stdout" and "stderr"
in the standard I/O package.
.SP 1
EX:\ fprintf\ (DBUG_FILE,\ "Doing my own I/O!\n");
.SP 1
.LI DBUG_EXECUTE\
The DBUG_EXECUTE macro is used to execute any arbitrary C code.
The first argument is the debug keyword, used to trigger execution
of the code specified as the second argument.
This macro must be used cautiously because, like the
DBUG_PRINT
macro,
it is automatically selected by default whenever the 'd' flag has
no argument list (I.E., a "-#d:t" control string).
.SP 1
EX:\ DBUG_EXECUTE\ ("abort",\ abort\ ());
.SP 1
.LI DBUG_N\
These macros, where N is in the range 2-5, are currently obsolete
and will be removed in a future release.
Use the new DBUG_PRINT macro.
.LI DBUG_PRINT\
Used to do printing via the "fprintf" library function on the
current debug stream,
DBUG_FILE.
The first argument is a debug keyword, the second is a format string
and the corresponding argument list.
Note that the format string and argument list are all one macro argument
and
.B must
be enclosed in parenthesis.
.SP 1
EX:\ DBUG_PRINT\ ("eof",\ ("end\ of\ file\ found"));
.br
EX:\ DBUG_PRINT\ ("type",\ ("type\ is\ %x", type));
.br
EX:\ DBUG_PRINT\ ("stp",\ ("%x\ ->\ %s", stp, stp\ ->\ name));
.LI DBUG_SETJMP\
Used in place of the setjmp() function to first save the current
debugger state and then execute the standard setjmp call.
This allows the debugger to restore its state when the
DBUG_LONGJMP macro is used to invoke the standard longjmp() call.
Currently all instances of DBUG_SETJMP must occur within the
same function and at the same function nesting level.
.SP 1
EX:\ DBUG_SETJMP\ (env);
.LI DBUG_LONGJMP\
Used in place of the longjmp() function to first restore the
previous debugger state at the time of the last DBUG_SETJMP
and then execute the standard longjmp() call.
Note that currently all DBUG_LONGJMP macros restore the state
at the time of the last DBUG_SETJMP.
It would be possible to maintain separate DBUG_SETJMP and DBUG_LONGJMP
pairs by having the debugger runtime support module use the first
argument to differentiate the pairs.
.SP 1
EX:\ DBUG_LONGJMP\ (env,val);
.LE
.SK
.B
DEBUG CONTROL STRING
.R
.P
The debug control string is used to set the state of the debugger
via the
.B DBUG_PUSH
macro.
This section summarizes the currently available debugger options
and the flag characters which enable or disable them.
Argument lists enclosed in '[' and ']' are optional.
.SP 2
.BL 22
.LI d[,keywords]
Enable output from macros with specified keywords.
A null list of keywords implies that all keywords are selected.
.LI D[,time]
Delay for specified time after each output line, to let output drain.
Time is given in tenths of a second (value of 10 is one second).
Default is zero.
.LI f[,functions]
Limit debugger actions to the specified list of functions.
A null list of functions implies that all functions are selected.
.LI F
Mark each debugger output line with the name of the source file
containing the macro causing the output.
.LI g
Turn on machine independent profiling.
A profiling data collection file, named dbugmon.out, will be written
for postprocessing by the "analyze" program.
The accuracy of this feature is relatively unknown at this time.
.LI i
Identify the process emitting each line of debug or trace output
with the process id for that process.
.LI L
Mark each debugger output line with the source file line number of
the macro causing the output.
.LI n
Mark each debugger output line with the current function nesting depth.
.LI N
Sequentially number each debugger output line starting at 1.
This is useful for reference purposes when debugger output is
interspersed with program output.
.LI o[,file]
Redirect the debugger output stream to the specified file.
The default output stream is stderr.
A null argument list causes output to be redirected to stdout.
.LI p[,processes]
Limit debugger actions to the specified processes.
A null list implies all processes.
This is useful for processes which run child processes.
Note that each debugger output line can be marked with the name of
the current process via the 'P' flag.
The process name must match the argument passed to the
.B DBUG_PROCESS
macro.
.LI P
Mark each debugger output line with the name of the current process
from argv[0].
Most useful when used with a process which runs child processes that
are also being debugged.
Note that the parent process must arrange for the debugger control
string to be passed to the child processes.
.LI r
Used in conjunction with the
.B DBUG_PUSH
macro to reset the current
indentation level back to zero.
Most useful with
.B DBUG_PUSH
macros used to temporarily alter the
debugger state.
.LI t[,N]
Enable function control flow tracing.
The maximum nesting depth is specified by N, and defaults to
200.
.LE
.SK
.B
HINTS AND MISCELLANEOUS
.R
.P
One of the most useful capabilities of the
.I dbug
package is to compare the executions of a given program in two
different environments.
This is typically done by executing the program in the environment
where it behaves properly and saving the debugger output in a
reference file.
The program is then run with identical inputs in the environment where
it misbehaves and the output is again captured in a reference file.
The two reference files can then be differentially compared to
determine exactly where execution of the two processes diverges.
.P
A related usage is regression testing where the execution of a current
version is compared against executions of previous versions.
This is most useful when there are only minor changes.
.P
It is not difficult to modify an existing compiler to implement
some of the functionality of the
.I dbug
package automatically, without source code changes to the
program being debugged.
In fact, such changes were implemented in a version of the
Portable C Compiler by the author in less than a day.
However, it is strongly encouraged that all newly
developed code continue to use the debugger macros
for the portability reasons noted earlier.
The modified compiler should be used only for testing existing
programs.
.SK
.B
CAVEATS
.R
.P
The
.I dbug
package works best with programs which have "line\ oriented"
output, such as text processors, general purpose utilities, etc.
It can be interfaced with screen oriented programs such as
visual editors by redefining the appropriate macros to call
special functions for displaying the debugger results.
Of course, this caveat is not applicable if the debugger output
is simply dumped into a file for post-execution examination.
.P
Programs which use memory allocation functions other than
.B malloc
will usually have problems using the standard
.I dbug
package.
The most common problem is multiply allocated memory.
.SP 2
.CS

1450
dbug/user.t Normal file

File diff suppressed because it is too large Load Diff

143
dbug/vargs.h Normal file
View File

@ -0,0 +1,143 @@
/******************************************************************************
* *
* N O T I C E *
* *
* Copyright Abandoned, 1987, Fred Fish *
* *
* *
* This previously copyrighted work has been placed into the public *
* domain by the author and may be freely used for any purpose, *
* private or commercial. *
* *
* Because of the number of inquiries I was receiving about the use *
* of this product in commercially developed works I have decided to *
* simply make it public domain to further its unrestricted use. I *
* specifically would be most happy to see this material become a *
* part of the standard Unix distributions by AT&T and the Berkeley *
* Computer Science Research Group, and a standard part of the GNU *
* system from the Free Software Foundation. *
* *
* I would appreciate it, as a courtesy, if this notice is left in *
* all copies and derivative works. Thank you. *
* *
* The author makes no warranty of any kind with respect to this *
* product and explicitly disclaims any implied warranties of mer- *
* chantability or fitness for any particular purpose. *
* *
******************************************************************************
*/
/*
* FILE
*
* vargs.h include file for environments without varargs.h
*
* SCCS
*
* @(#)vargs.h 1.2 5/8/88
*
* SYNOPSIS
*
* #include "vargs.h"
*
* DESCRIPTION
*
* This file implements a varargs macro set for use in those
* environments where there is no system supplied varargs. This
* generally works because systems which don't supply a varargs
* package are precisely those which don't strictly need a varargs
* package. Using this one then allows us to minimize source
* code changes. So in some sense, this is a "portable" varargs
* since it is only used for convenience, when it is not strictly
* needed.
*
*/
/*
* These macros allow us to rebuild an argument list on the stack
* given only a va_list. We can use these to fake a function like
* vfprintf, which gets a fixed number of arguments, the last of
* which is a va_list, by rebuilding a stack and calling the variable
* argument form fprintf. Of course this only works when vfprintf
* is not available in the host environment, and thus is not available
* for fprintf to call (which would give us an infinite loop).
*
* Note that ARGS_TYPE is a long, which lets us get several bytes
* at a time while also preventing lots of "possible pointer alignment
* problem" messages from lint. The messages are valid, because this
* IS nonportable, but then we should only be using it in very
* nonrestrictive environments, and using the real varargs where it
* really counts.
*
*/
#ifndef va_start
#define ARG0 a0
#define ARG1 a1
#define ARG2 a2
#define ARG3 a3
#define ARG4 a4
#define ARG5 a5
#define ARG6 a6
#define ARG7 a7
#define ARG8 a8
#define ARG9 a9
#define ARGS_TYPE long
#define ARGS_LIST ARG0,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7,ARG8,ARG9
#define ARGS_DCL auto ARGS_TYPE ARGS_LIST
/*
* A pointer of type "va_list" points to a section of memory
* containing an array of variable sized arguments of unknown
* number. This pointer is initialized by the va_start
* macro to point to the first byte of the first argument.
* We can then use it to walk through the argument list by
* incrementing it by the size of the argument being referenced.
*/
typedef char *va_list;
/*
* The first variable argument overlays va_alist, which is
* nothing more than a "handle" which allows us to get the
* address of the first argument on the stack. Note that
* by definition, the va_dcl macro includes the terminating
* semicolon, which makes use of va_dcl in the source code
* appear to be missing a semicolon.
*/
#define va_dcl ARGS_TYPE va_alist;
/*
* The va_start macro takes a variable of type "va_list" and
* initializes it. In our case, it initializes a local variable
* of type "pointer to char" to point to the first argument on
* the stack.
*/
#define va_start(list) list = (char *) &va_alist
/*
* The va_end macro is a null operation for our use.
*/
#define va_end(list)
/*
* The va_arg macro is the tricky one. This one takes
* a va_list as the first argument, and a type as the second
* argument, and returns a value of the appropriate type
* while advancing the va_list to the following argument.
* For our case, we first increment the va_list arg by the
* size of the type being recovered, cast the result to
* a pointer of the appropriate type, and then dereference
* that pointer as an array to get the previous arg (which
* is the one we wanted.
*/
#define va_arg(list,type) ((type *) (list += sizeof (type)))[-1]
#endif /* ifndef va_start */

82
defs.mak Normal file
View File

@ -0,0 +1,82 @@
# defs.mak.in --
# source file for autoconf-generated "defs.mak" for netgen
# defs.mak. Generated from defs.mak.in by configure.
# Feel free to change the values in here to suit your needs.
# Be aware that running scripts/configure again will overwrite
# any changes!
SHELL = /bin/sh
prefix = ${BUILDROOT}/usr/local
exec_prefix = ${prefix}
bindir = ${exec_prefix}/bin
libdir = ${exec_prefix}/lib
mandir = ${prefix}/share/man
VERSION =
SCRIPTS = ${NETGENDIR}/scripts
INSTALL = /bin/install -c
INSTALL_PROGRAM = ${INSTALL}
INSTALL_DATA = ${INSTALL} -m 644
INSTALL_SCRIPT = ${INSTALL}
# Override standard "make" target when compiling under TCL
ALL_TARGET = tcl
INSTALL_TARGET = install-tcl
# Change CADDIR to install in a different place
BINDIR = ${bindir}
MANDIR = ${mandir}
LIBDIR = ${libdir}
DOCDIR = ${libdir}/netgen/doc
TCLDIR = ${libdir}/netgen/tcl
MAIN_EXTRA_LIBS = ${NETGENDIR}/tcltk/libtcltk.o
LD_EXTRA_LIBS =
LD_SHARED =
TOP_EXTRA_LIBS =
SUB_EXTRA_LIBS =
MODULES += tcltk
UNUSED_MODULES +=
PROGRAMS += tcltk
INSTALL_CAD_DIRS += tcltk
RM = rm -f
CP = cp
AR = @AR@
ARFLAGS = crv
LINK = /bin/ld -r
LD = /bin/ld
M4 = /bin/m4
RANLIB = ranlib
SHDLIB_EXT = .so
LDDL_FLAGS = -shared -Wl,-soname,$@ -Wl,--version-script=${NETGENDIR}/netgen/symbol.map
LD_RUN_PATH =
LIB_SPECS = -L/usr/lib64 -ltk8.6 -L/usr/lib64 -ltcl8.6
WISH_EXE = /usr/bin/wish
TCL_LIB_DIR = /usr/lib
CC = gcc
CPP = gcc -E -x c
CXX = @CXX@
CPPFLAGS = -I. -I${NETGENDIR}
DFLAGS = -DCAD_DIR=\"${LIBDIR}\" -DTCL_DIR=\"${TCLDIR}\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG
CFLAGS = -g -m64 -fPIC -fPIC
DEPEND_FILE = Depend
DEPEND_FLAG = -MM
EXEEXT =
GR_CFLAGS =
GR_DFLAGS = -DX11 -DXLIB -DNDEBUG
GR_LIBS = -lX11
GR_SRCS = ${TK_SRCS}
OBJS = ${SRCS:.c=.o}
LIB_OBJS = ${LIB_SRCS:.c=.o}
CLEANS = ${OBJS} ${LIB_OBJS} lib${MODULE}.a lib${MODULE}.o ${MODULE}

30
doc/Makefile Normal file
View File

@ -0,0 +1,30 @@
NETGENDIR = ..
include ${NETGENDIR}/defs.mak
MANDIRS = $(DESTDIR)${MANDIR} $(DESTDIR)${MANDIR}/man1
DOCDIRS = $(DESTDIR)${DOCDIR}
MANFILES =
DOCFILES = $(DESTDIR)${DOCDIR}/netgen.doc
install-tcl: ${MANDIRS} ${MANFILES} ${DOCDIRS} ${DOCFILES}
install: ${MANDIRS} ${MANFILES} ${DOCDIRS} ${DOCFILES}
${MANDIRS}: make-man-dirs
${DOCDIRS}: make-doc-dirs
make-man-dirs:
${SCRIPTS}/mkdirs ${MANDIRS}
make-doc-dirs:
${SCRIPTS}/mkdirs ${DOCDIRS}
# This file does not actually exist. . .
$(DESTDIR)${MANDIR}/man1/netgen.1: netgen.1 ${MANDIRS}
${CP} netgen.1 $(DESTDIR)${MANDIR}/man1/netgen.1
$(DESTDIR)${DOCDIR}/netgen.doc: netgen.doc ${DOCDIRS}
${CP} netgen.doc $(DESTDIR)${DOCDIR}/netgen.doc

607
doc/netgen.doc Normal file
View File

@ -0,0 +1,607 @@
NETGEN -- An embedded-language netlist specification.
NETGEN consists of a set of C language subroutines intended to facilitate
the specification of netlists of circuits that are ill-suited to
conventional schematic-capture paradigms.
Some of the features of the NETGEN system:
1) full hierarchical specification of the circuit in question.
2) powerful list-based operators that permit rapid declaration
and subsequent connection of semantic structures such as busses,
signal vectors, port lists, etc.
3) optional topology-driven front end, providing connectivity of
cells according to a composition-by-abuttment paradigm.
4) dynamic scoping rules governing visibility of ports and nodes.
5) support for multiple output netlist file formats,
including .NTK, .EXT (and consequently .SIM), .ACTEL, and .WOMBAT.
In addition, hierarchical .NTK files can be read, providing an
alternate mechanism to input cells.
Hierarchical specification of circuits.
The basic unit in defining a circuit is a CELL. A cell, in turn, can
contain any number of other cells, called INSTANCES. A cell has some
special nodes, called PORTS, that are the connections that can be
made to the cell when it is instanced. When a cell is actually
instanced, these ports are called PINS within the context of the cell
being constructed. The ports (of the current cell) and pins (of
previously defined cells) may connect together directly, or through
optional NODES.
So much for the definitions. Now the good news: within a CELL, there
are 3 kinds of elements (PORTS, NODES, and PINS); these are treated
ABSOLUTELY IDENTICALLY from the user's perspective. NETGEN has a uniform
internal representation with a single operator: "connect". In defining
a cell, the user "connects" ports, nodes, and pins as required to construct
the desired circuit. In particular, there is no real notion of a "wire"
within NETGEN; situations where named signal lines would be useful can
be accomodated by using named internal nodes.
In it's simplest form, the user interface to NETGEN consists of
four procedures:
void CellDef(char *name);
Declares cell "name", and appends all future commands to the definition
of that cell.
void Port(char *name);
Declares a port node called "name" within the current cell.
void Node(char *name);
Declares an internal node called "name" within the current cell.
void Instance(char *cell, *instancename);
Incorporates an instance of cell "cell" into the current cell; the
instance is called "instancename", which must be a unique identifier
within the context of the current cell (the function Next(cell) is
often useful in generating this unique identifier). The Instance()
procedure generates a set of PINS corresponding to the ports of
"cell"; these pins are named "instancename"/"portname".
As a (trivial) example, consider the following definition of
the elements within a CMOS inverter:
CellDef("inv");
PortDef("in");
PortDef("out");
PortDef("vdd");
PortDef("gnd");
Instance("p","pullup");
Instance("n","pulldown");
Instance() also has some subtle side-effects. See the section
below on dynamic scoping for a discussion of how these can be used
to implicitly connect elements automatically.
Connecting up the circuit; (or, using wirelists effectively).
We must now specify how the above elements are to be interconnected.
The most general form of this operator is:
void Connect(char *list1, *list2);
In its simplest form, list1 and list2 are the names of two elements
to be connected together. In the above example,
Connect("pulldown/source", "gnd");
Connect("pullup/source", "vdd");
Connect("pulldown/gate", "in");
Connect("pullup/gate", "in");
Connect("pulldown/drain", "out");
Connect("pullup/drain", "out");
completes the specification of the inverter. However, the same result
can be obtained more simply by the use of WILDCARDS in the list-constructor
strings list1 and list2. Supported wildcards are the UNIX(TM) shell
wildcards (*,?,{},[]) where:
* matches 0 or more characters (unlike csh, "/" is treated
identically to any other character).
? matches any single character.
{} delimits alternate choices. For example "c{a,o}t" matches "cat"
and "cot".
[] delimits ranges for matching a single character. For example,
"cell[1-3]" matches "cell1", "cell2", and "cell3". Multiple
ranges can be specified (e.g. [a-mp-x]), as can excluded
ranges ([~a-m]).
Full regular expression pattern matching is also available. To use this
form, set the global flag UnixWildcards to 0, and see regexp(3) for
detailed syntax.
The result of Connecting two lists is the following:
a) if the lists are the same length, corresponding pairs of elements
are connected to each other,
b) if one of the lists has a single element, all elements of the
other list are connected to that element,
c) otherwise, the lists are of unequal lengths and an error is reported.
Thus, the inverter can be specified simply by:
Connect("*drain", "out");
Connect("*gate", "in");
Connect("*up/source", "vdd");
Connect("*down/source", "gnd");
The ORDER of generated list elements is the same as the order in which
the elements were added to the cell. In the above example,
"*gate" gets expanded to {"pullup/gate","pulldown/gate"}. It is possible
to take advantage of wildcards (and this bit of information) even
further:
Connect("*drain", "out");
Connect("*gate", "in");
Connect("*source","*d");
The user should, however, try to minimize the abuse of wildcards at
the expense of clarity. Wildcards are provided to expedite grouping
of elements with associated semantics (see the section below on
topological specification of interconnection), NOT to minimize the
keystrokes required to specify a netlist.
The relationship between placement and interconnect.
NETGEN provides a simple model for VLSI cell placement: cells are
rectangular and have ports along the perimeter on 4 sides (N,S,E,W).
Composition is by abuttment and can occur in either the horizontal
or vertical direction. When two cells are placed so that they share
an edge, the port lists along that edge of the respective cells are
generated, and the Connect operator is invoked on them. Ports along
the othogonal edges are propagated as ports of the cell being defined.
The (implied) order of ports in cells is bottom-to-top on vertical
edges, and left-to-right on horizontal edges, corresponding to the
order of placement of subsequent cells.
void Place(char *name);
An instance of cell "name" is generated, and placed in a direction
corresponding to the "Composition" flag (if Composition==HORIZONTAL,
the cell is placed to the right of any previously placed cells; if
Composition==VERTICAL, the cell is placed above; if
Composition==NONE, a call to Place(name) is equivalent to
Instance(name,Next(name))). A unique instance name is generated for
the cell, by appending an integer (starting at 1) to "name". Ports
along abutting edges are "sealed", and ports along orthogonal edges
are made ports of the cell being defined. In the first call to Place
within a cell, the leftmost (or bottom, if Composition==VERTICAL)
ports of cell "name" are defined to be the corresponding ports of the
cell being defined. In order to correctly generate the port list at
the other end of the cell, the procedure:
void EndCell();
must be called to end the current cell definition. It is good form to
always terminate cell definitions with this statement (even if you
did not use the implicit composition mechanism) -- one side-effect of
EndCell() is to arbitrarily connect all otherwise disconnected nodes
if the global variable NoDisconnectedNodes is set to 1 (the default is 0).
In order to understand the relationship between topology and connectivity,
the user must adhere to a particular NAMING CONVENTION. Ports must
be declared in the correct order (bottom-to-top and left-to-right),
and with the following syntax: the side of the port is prepended
to the port name, separated by a ".". For example, if the input
to the inverter is to be on the left (west) side, we would
replace the previous definition of port "in" by:
Port("W.in");
Corresponding changes are required for the other ports (for example,
"E.out", "N.vdd", "S.gnd"). Then, the specification for a chain of 4
inverters (perhaps an exponential horn for a pad driver) takes the
form:
CellDef("exphorn");
Composition = HORIZONTAL;
for (i=0; i<4; i++) Place("inv");
EndCell();
This code fragment specifies a cell "exphorn" that takes a single
input on the left (west) side, generates a single output on the
right side, and has 4 ports on the top (which should be connected
to vdd in the cell that calls "exphorn"), and 4 on the bottom (gnd).
To simplify code fragments such as the above, the procedure
void Array(char *name, int count)
is provided, and is equivalent to "for (i=0;i<count;i++) Place(name)".
Scoping rules for identifiers; Implicit (global) connections.
It is often inconvenient to have to continually declare high
connectivity nodes (e.g. power rails, bit/word lines, etc.) explicitly
as parameters to each cell. Also, the number of ports of generated
cells (see example above) can be kept managable.
The solution to this problem takes the form of scoping rules for
element names; when a cell is instantiated within the context of a
calling cell, particular elements within the CALLED cell are
implicitly connected to elements in the PARENT cell. This binding
process is exactly analogous to local/global variables within nested
PASCAL procedure declarations, but the process is slightly different:
instead of declaring LOCAL variables, and assuming all others to have
GLOBAL visibility, particular ports (i.e. explicitly global objects)
are declared to obey certain implicit connection rules by the
following:
void Global(char *name);
Semantically, "name" is a PORT that connects itself automatically
when the cell is instanced. In particular, a port obtained by a call
to Global("xxx") in cell B will automatically connect to an element
named "xxx" in cell A, whenever A instantiates B. If "xxx" does not
exist in A, the instantiation of B will CAUSE a global port named
"xxx" to be declared (by a call to Global("xxx") in A). The result
of this action is that the unbound variable "xxx" is now propagated
to the next level of the hierarchy. This dynamic scoping allows
cell B (which is instantiated within cell A) to be declared
BEFORE cell A.
An example is useful. Reconsider the "inv" cell above, but this
time change the definitions of the power ports to :
Global("vdd");
Global("gnd");
The previous code fragment for "exphorn" would now result
in a cell with 4 ports, named "vdd", "gnd", "W.inv1/W.in" and
"E.inv4/E.out" (instead of the previous exphorn, which had 10 ports).
Naming conventions:
Within the context of the calling cell:
1) Ports:
<instance name> SEPARATOR <port name>
2) Ports - Oriented:
<side> { PORT_DELIMITER <instance name> PORT_DELIMITER <side>}* \
PORT_DELIMITER <port name>
3) Ports - Global:
<port name> -- name propagates unchanged, but is bound to
locally-declared identifier of same name.
4) Ports - Unique Global:
<my class name> INSTANCE_DELIMITER <instance name> SEPARATOR <port name>
5) Flattened cells:
<instance name> { SEPARATOR <instance name> }* SEPARATOR <port name>
6) Cells read from NTK:
<instance class> INSTANCE_DELIMITER <instance name> SEPARATOR <port name>
Other Procedures (i.e. what else do I need to know?)
In order to use the NETGEN package, the user's program must include
the library, link the correct object module, and initialize the package.
The first is accomplished by the line:
#include "netgen.h"
at the top of every program. In practice, "netgen.h" is not likely
to be found in the current directory, so ask a system guru where it
is located. The same goes for the object file "netgen.a" that must
be linked in (via a command-line parameter in UNIX; if you are
running NETGEN on a PC (or maybe even someday on a chipmunk) talk
to a system mangler).
The NETGEN package is written in ANSI-standard C, and requires
an ANSI-C compiler. On many UNIX systems, the GNU C compiler
is known to work; the incantation to compile a user's main
program main.c is:
gcc -o main main.c netgen.a
The NETGEN package is initialized via a call to:
void Initialize();
This procedure sets up the internal data structures, and pre-defines
two types of cells: n- and p-channel transistors. These cells are
declared by the following code (which is actually inside Initialize()):
CellDef("p");
Primitive();
PortDef("gate");
PortDef("drain");
PortDef("source");
EndCell();
CellDef("n");
Primitive();
PortDef("gate");
PortDef("drain");
PortDef("source");
EndCell();
The procedure Primitive() in the above code fragment informs
NETGEN that the element is a primitive, and not to be further
decomposed when an output netlist file is written. This mechanism
assumes that the system READING the netlist understands the
meaning of the element.
A slightly more powerful initialization routine is:
void InitializeCommandLine(int argc, char *argv[]);
This routine parses any command-line arguements (interpreted as
commands to the Query() routine), and processes them first. A single
'-' in the command line indicates that interactive operation should
follow these commands.
For the user's convenience, an alternative to the Instance/Connect
mechanism is provided; when a cell is instantiated, explicit
connections may be specified to each of its ports via the procedure:
void Cell(char *CellName, char *PortNameList, ...);
The strings passed in PortNameList, and any subsequent (assumed char *)
are of one of two forms:
1) they are a list of "port=element" strings. In this case, their
order is unimportant; the ports of the cell are connected to the
corresponding element. For example,
Cell("n", "drain=n1", "gate=g1", "source=n2");
does the obvious thing.
2) arguements do not contain "=", but may contain wildcards, in which
case they are expanded into lists, and this list is sealed with the
port list obtained when CellName is instanced (and after any "=" ports
are matched). For example, an n-channel device in parallel with
another (named "tran1") can be obtained by:
Cell("n", "tran1/*");
In both of these cases, the portnames of CellName are also added to the
namespace of the current cell, so subsequent calls to Connect()
operate correctly.
Along the lines of Cell(), two other procedures are defined:
void N(char *PortNameList, ...);
void P(char *PortNameList, ...);
These are merely calls to Cell(), with the CellName arguement
hard-wired to "n" and "p", respectively.
A slight variant on Cell() is the Wire() procedure:
void Wire(char *instance_name, ...);
This procedure accepts the name of an instance, and a list of ports
identical to Cell(). The only difference is that for Wire(), the
instance name is explicitly required, while for Cell() it is
totally suppressed (in fact, the user cannot even find out what it was).
The "=" form of the parameter list can be used in Wire() as well.
Other Useful Functions
Because many element names are derived from others, NETGEN
provides some useful functions to manipulate temporary strings:
char *Str(char *format, ...);
This function takes a format string and a variable arguement list
in a manner identical to printf(), and returns a pointer to a
temporary string. There are only a small number of these (statically
allocated) strings available, so you must use the pointer quickly.
Typical use is in declaring a "subscripted" cell: CellDef(Str("array%d", i));
Finally, as a convenience to the user, a procedure:
void Query(void);
puts NETGEN in an interactive mode, where the user is permitted
to choose between output netlist formats, input files to read, and
various other things. It is a convenient way to end a program.
If your version of NETGEN was compiled with X11 support, a more
general command parser is available as:
void X_main_loop(int argc, char *argv[]);
Generating Output
The main output format currently supported is the Caltech NTK
format. An output file is created by calling:
void Ntk(char *cellname, char *filename);
All nodes are named, with the following priority given to nodes
with multiple elements connected to them. Highest priority
goes to port names, then to internal node names, and finally
to instance pin names. Certain shortcomings in the .NTK specification
(such as the inability to connect two ports within a cell) are
dealt with correctly. If filename is NULL, or an empty string,
a file name is generated by appending .ntk to "cellname".
Late news flash: the MAGIC hierarchical extract format
is now supported to a limited. To generate .EXT files, call
void Ext(char *cellname);
This procedure generates a .EXT file for EACH(!) cell class.
The only thing .EXT is good for is to run EXT2SIM on, in order to
get the other MAGIC netlist format (flattened list of
transistors only.). SIM output can be generated directly by:
void Sim(char *cellname);
NETGEN also supports the Actel(TM) cell libraries and netlist
file format. To access these cells, call the procedure:
void ActelLib();
These cells are then regular NETGEN objects, whose elements
are accessed by the names described in the Actel gate catalog.
For example, the pins on a 2-input NAND gate are
"thisgate/A", "thisgate/B", and "thisgate/Y", after a call
to Instance("NAND2","thisgate").
Actel .adl files are written by calling the procedure:
void Actel(char *cellname, char *filename);
As before, if filename is NULL, or an empty string, a file name is
generated by appending .adl to "cellname".
NETGEN supports the netlist format required by
the WOMBAT netlist comparison program. Such files
are written by the procedure:
void Wombat(char *cellname, char *filename);
WOMBAT requires flat (non-hierarchical) netlists. See the
Flatten() procedure below.
NETGEN also supports two popular circuit simulator formats:
void SpiceCell(char *cellname, char *filename);
void EsacapCell(char *cellname, char *filename);
Of course, because NETGEN only maintains topological information and
not device sizing information, writing circuit simulator input files
generally requires some manual post-processing.
NETGEN also supports an output format that is, in fact, the specification
of the netlist using the NETGEN C-language embedded interface:
void Ccode(char *cellname, char *filename);
This procedure creates a file that is suitable for inclusion and compilation
within a program that, when linked with the netgen libraries, will
re-create the netlist.
Finally, NETGEN provides a machine-dependent (i.e., nonportable)
but fast netlist format, based on a binary dump of its internal data
structures:
void WriteNetgenFile(char *cellname, char *filename);
Other Cell Manipulation commands
Two routines are also provided to manipulate the cell dictionary
(the list of defined cells):
void CellDelete(char *cellname);
This procedure deletes the definition of 'cellname' from the dictionary.
It does NOT care whether instances of 'cellname' exist within other cells.
This procedure is useful for remapping sub-cells within a design, by
deleting the original cells, then subsequently loading in new definitions.
void CellRename(char *from, char *to);
This procedure deletes the definition of cell 'from', and creates an
identical cell in 'to'. If cell 'to' already exists, that cell is overwritten.
void CellCopy(char *from, char *to);
Copy cell 'from', calling the new cell 'to'. If 'to' exists already,
its definition is overwritten.
NETGEN also supports some hierarchy-manipulation functions:
void Flatten(char *cellname);
The Flatten() procedure actually flattens the internal data
structure, and is consequently irreversible. Of course,
flattened cells can also be written out in any of the
other netlist formats.
void FlattenInstancesOf(char *classname);
This procedure flattens all instances of 'classname' within other
cells. However, any hierarchy within 'classname' remains.
Alternative Input Formats
In addition to the embedded procedural interface for declaring/defining
cells, NETGEN is able to read hierarchical .NTK files directly,
and convert them into the internal element list representation.
These cells can then be operated on identically to procedurally defined
cells. This process facilitates using a (separately generated, perhaps
by a graphical schematic capture system) cell library, then using
NETGEN as a composition tool.
In fact, many different input netlist formats are supported:
char *ReadNtk(char *filename);
char *ReadExt(char *filename);
char *ReadSim(char *filename);
char *ReadSpice(char *filename);
char *ReadNetgenFile(char *filename);
All of these procedures return the name of the top-level cell that
was read.
A general file-reading interface is provided by:
char *ReadNetlist(char *filename);
This procedure selects one of the above netlist formats, based on
the file extension of the 'filename' arguement.
Testing graph isomorphism.
NETGEN includes a fast, powerful probabilistic algorithm for
verifying whether two netlists represent isomorphic graphs.
The favored interface to this facility is the 'netcomp' program
that is built along with the 'netgen' interface. However, advanced
users may need the additional functionality provided by the C-language
interface:
void NETCOMP(void);
This is a primitive command-line interpreter (similar to Query())
that gives the user access to all the internal capabilities of netcomp.
A simpler interface is given by:
int Compare(char *cell1, char *cell2);
This procedure returns 1 if the two cells are isomorphic, and 0 otherwise.
If you consider MOS transistor sources and drains to be equivalent
(i.e., permutable), set the integer variable EquivalenceTransistors to 1.
This is appropriate for extracted outputs of VLSI circuits, but (typically)
not for asymmetrical circuit-simulator specifications.
Command-line interface and X-windows interface.
By default in UNIX, if the DISPLAY environment variable is set, netgen
starts an X-window application. Otherwise, a command-line interface
is executed, running the function Query() described above. In either case,
any command-line arguements are passed through Query(); if the last
command is a single dash ("-"), the regular command parser is started
AFTER the command-line commands are executed. Otherwise, netgen
terminates.
Future work:
* 1) have ntk generate file of output
* 2) capture wildcard query routine into library (returning a string, so
user can incorporate it into interactive programs).
* 3) add "internal ports" to implement scoping rules for variable names.
* 4) find out what output format WOMBAT requires and generate it.
5) add simple operators to act on element lists: move, delete, reverse
* 6) don't forget to mention Initialize() procedure
* 7) discuss alternatives to Instance() (e.g. Cell(), and N(), P())
* 8) ability to flatten cells
* 9) learn to write ACTEL format
* 10) more streamlined syntax for Global ports
* 11) don't forget to mention Primitive() procedure.

49
install.log Normal file
View File

@ -0,0 +1,49 @@
make[1]: Entering directory '/home/tim/gitsrc/netgen-1.5'
./scripts/mkdirs /usr/local/bin /usr/local/share/man \
/usr/local/lib/netgen/tcl
for dir in lib doc tcltk netgen tcltk; do \
(cd $dir && make install-tcl); done
make[2]: Entering directory '/home/tim/gitsrc/netgen-1.5/lib'
../scripts/mkdirs /usr/local/lib/netgen
rm -f /usr/local/lib/netgen/ntk2adl.sh
cp ntk2adl.sh /usr/local/lib/netgen/ntk2adl.sh
../scripts/mkdirs /usr/local/lib/netgen
rm -f /usr/local/lib/netgen/spice
cp spice /usr/local/lib/netgen/spice
../scripts/mkdirs /usr/local/lib/netgen
rm -f /usr/local/lib/netgen/spice.bot
cp spice.bot /usr/local/lib/netgen/spice.bot
../scripts/mkdirs /usr/local/lib/netgen
rm -f /usr/local/lib/netgen/spice.top
cp spice.top /usr/local/lib/netgen/spice.top
make[2]: Leaving directory '/home/tim/gitsrc/netgen-1.5/lib'
make[2]: Entering directory '/home/tim/gitsrc/netgen-1.5/doc'
../scripts/mkdirs /usr/local/share/man /usr/local/share/man/man1
../scripts/mkdirs /usr/local/lib/netgen/doc
cp netgen.doc /usr/local/lib/netgen/doc/netgen.doc
make[2]: Leaving directory '/home/tim/gitsrc/netgen-1.5/doc'
make[2]: Entering directory '/home/tim/gitsrc/netgen-1.5/tcltk'
rm -f /usr/local/bin/netgen.sh /usr/local/bin/netgen
cp netgen.sh /usr/local/bin/netgen
(cd /usr/local/bin; chmod 0755 netgen)
rm -f /usr/local/lib/netgen/tcl/tkcon.tcl
cp tkcon.tcl /usr/local/lib/netgen/tcl/tkcon.tcl
rm -f /usr/local/lib/netgen/tcl/console.tcl
cp console.tcl /usr/local/lib/netgen/tcl/console.tcl
rm -f /usr/local/lib/netgen/tcl/netgen.tcl
cp netgen.tcl /usr/local/lib/netgen/tcl/netgen.tcl
rm -f /usr/local/lib/netgen/tcl/netgenexec
cp netgenexec /usr/local/lib/netgen/tcl/netgenexec
make[2]: Leaving directory '/home/tim/gitsrc/netgen-1.5/tcltk'
make[2]: Entering directory '/home/tim/gitsrc/netgen-1.5/netgen'
rm -f /usr/local/lib/netgen/tcl/tclnetgen.so
cp tclnetgen.so /usr/local/lib/netgen/tcl/tclnetgen.so
make[2]: Leaving directory '/home/tim/gitsrc/netgen-1.5/netgen'
make[2]: Entering directory '/home/tim/gitsrc/netgen-1.5/tcltk'
rm -f /usr/local/bin/netgen.sh /usr/local/bin/netgen
cp netgen.sh /usr/local/bin/netgen
(cd /usr/local/bin; chmod 0755 netgen)
rm -f /usr/local/lib/netgen/tcl/netgenexec
cp netgenexec /usr/local/lib/netgen/tcl/netgenexec
make[2]: Leaving directory '/home/tim/gitsrc/netgen-1.5/tcltk'
make[1]: Leaving directory '/home/tim/gitsrc/netgen-1.5'

17
lib/Makefile Normal file
View File

@ -0,0 +1,17 @@
NETGENDIR = ..
include ${NETGENDIR}/defs.mak
LIB_FILES = ntk2adl.sh spice spice.bot spice.top
LIB_INST_FILES= $(LIB_FILES:%=$(DESTDIR)${LIBDIR}/netgen/%)
BIN_INST_FILES= $(BIN_FILES:%=$(DESTDIR)${BINDIR}/%)
install-tcl: ${LIB_INST_FILES}
install: ${LIB_INST_FILES}
$(DESTDIR)${LIBDIR}/netgen/%: %
../scripts/mkdirs $(DESTDIR)${LIBDIR}/netgen
${RM} $(DESTDIR)${LIBDIR}/netgen/$*
${CP} $* $(DESTDIR)${LIBDIR}/netgen/$*

3
lib/ntk2adl.sh Normal file
View File

@ -0,0 +1,3 @@
#!/bin/csh
echo ntk2adl $1 $2
netgen A K $1 a $2

102
lib/spice Normal file
View File

@ -0,0 +1,102 @@
#!/bin/sh
# this is a really trivial script intended to massage the simple .ckt
# files generated by netgen. It prepends a header file, and then
# appends a tail file to the specified .ckt file.
if [ "$SPICEHEAD" = "" ] # if environment variable is not set
then
head=spice.top # set it to the default
else
head=$SPICEHEAD # otherwise, use the environment variable
fi
if [ "$SPICETAIL" = "" ]
then
tail=spice.bot
else
tail=$SPICETAIL
fi
nmodel=n2 # default n-transistor model name
pmodel=p2 # default p-transistor model name
nsub=NSUB # default n-transistor substrate node
psub=PSUB # default p-transistor substrate node
output=spice.ckt # default output file name
case $# in
0) echo "Usage: $0 [-head={header file}] [-tail={tail file}]"
echo " [-nmodel={nmodel name}] [-pmodel={pmodel name}]"
echo " [-nsub={n-tran substrate name}] [-psub={p-tran substrate name}]"
echo " [-output={output file name}] {.ckt file name}"
echo " "
if [ "$SPICEHEAD" = "" ]
then
echo "Defaults: header = $head (or set environment variable SPICEHEAD)"
else
echo "Defaults: header = $head (set by environment variable SPICEHEAD)"
fi
if [ "$SPICETAIL" = "" ]
then
echo " tail file = $tail (or set environment variable SPICETAIL)"
else
echo " tail file = $tail (set by environment variable SPICETAIL)"
fi
echo " N model-name = $nmodel; P model-name = $pmodel"
echo " N substrate-name = $nsub; P substrate-name = $psub"
echo " Output file name = $output"
exit 1 ;;
*) ;;
esac
for arg do
case $arg in
-head=*)
head=`echo $arg | sed s/-head=//` ;;
-tail=*)
tail=`echo $arg | sed s/-tail=//` ;;
-nmodel=*)
nmodel=`echo $arg | sed s/-nmodel=//` ;;
-pmodel=*)
pmodel=`echo $arg | sed s/-pmodel=//` ;;
-nsub=*)
nsub=`echo $arg | sed s/-nsub=//` ;;
-psub=*)
psub=`echo $arg | sed s/-psub=//` ;;
-output=*)
output=`echo $arg | sed s/-output=//` ;;
*) file=$arg ;;
esac
done
echo "SPICE deck translation filter."
echo "Input from: $file; Header: $head; Trailer: $tail"
if [ -f $output ]
then
rm $output
fi
echo "SPICE deck created from file $file" > $output
if [ -f $head ]
then
cat $head >> $output
fi
if [ -f $file ]
then
sed -e "s/NTRAN/$nmodel/g" < $file | \
sed -e "s/PTRAN/$pmodel/g" | sed -e "s/NSUB/$nsub/g" | \
sed -e "s/PSUB/$psub/g" >> $output
fi
if [ -f $tail ]
then
cat $tail >> $output
fi
echo "SPICE deck written in file: $output"

5
lib/spice.bot Normal file
View File

@ -0,0 +1,5 @@
* End of SPICE deck. Put all simulation stuff here.
.END

22
lib/spice.top Normal file
View File

@ -0,0 +1,22 @@
*
*
* MODEL cards go here
* Old CMOS 3um process parameters from MOSIS run M46M
* CBPEM2 Telmos/Sierracin
.options defl=3um defw=3u defas=9pm^2 defad=9pm^2
.MODEL p2 pmos level=2 ld=0.51286u tox=500e-10
+nsub=2.971614e+14 vto=-0.844293 kp=1.048805e-5 gamma=0.723071
+phi=0.6 uo=100.0 uexp=0.145531 ucrit=18543.6
+delta=2.19030 vmax=100000. xj=2.583588e-2u lambda=5.274834e-2
+nfs=1.615644e+12 neff=1.001e-2 nss=0. tpg=-1.
+rsh=95 cgso=4e-10 cgdo=4e-10 cj=2e-4 mj=0.5 cjsw=4.5e-10 mjsw=0.33
.MODEL n2 nmos level=2 ld=0.245423u tox=500e-10
+nsub=1e+16 vto=0.932797 kp=2.696667e-5 gamma=1.28047
+phi=0.6 uo=381.905 uexp=1.001e-3 ucrit=999000
+delta=1.47242 vmax=55346.3 xj=0.145596u lambda=2.491255e-2
+nfs=3.727796e+11 neff=1.001e-2 nss=0 tpg=1
+rsh=25 cgso=5.2e-10 cgdo=5.2e-10 cj=3.2e-4 mj=0.5 cjsw=9e-10 mjsw=0.33

120
make.log Normal file
View File

@ -0,0 +1,120 @@
make[1]: Entering directory '/home/tim/gitsrc/netgen-1.5'
--- making modules
for dir in base tcltk; do \
(cd $dir && make module); done
make[2]: Entering directory '/home/tim/gitsrc/netgen-1.5/base'
../rules.mak:40: Depend: No such file or directory
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -MM actel.c ccode.c greedy.c ntk.c print.c actellib.c embed.c hash.c netfile.c objlist.c query.c anneal.c ext.c netcmp.c netgen.c pdutils.c random.c timing.c bottomup.c flatten.c place.c spice.c wombat.c xilinx.c xillib.c > Depend
--- compiling base/actel.o
rm -f actel.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c actel.c
--- compiling base/ccode.o
rm -f ccode.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c ccode.c
--- compiling base/greedy.o
rm -f greedy.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c greedy.c
--- compiling base/ntk.o
rm -f ntk.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c ntk.c
--- compiling base/print.o
rm -f print.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c print.c
--- compiling base/actellib.o
rm -f actellib.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c actellib.c
--- compiling base/embed.o
rm -f embed.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c embed.c
--- compiling base/hash.o
rm -f hash.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c hash.c
--- compiling base/netfile.o
rm -f netfile.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c netfile.c
--- compiling base/objlist.o
rm -f objlist.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c objlist.c
--- compiling base/query.o
rm -f query.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c query.c
--- compiling base/anneal.o
rm -f anneal.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c anneal.c
--- compiling base/ext.o
rm -f ext.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c ext.c
--- compiling base/netcmp.o
rm -f netcmp.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c netcmp.c
--- compiling base/netgen.o
rm -f netgen.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c netgen.c
--- compiling base/pdutils.o
rm -f pdutils.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c pdutils.c
--- compiling base/random.o
rm -f random.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c random.c
--- compiling base/timing.o
rm -f timing.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c timing.c
--- compiling base/bottomup.o
rm -f bottomup.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c bottomup.c
--- compiling base/flatten.o
rm -f flatten.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c flatten.c
--- compiling base/place.o
rm -f place.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c place.c
--- compiling base/spice.o
rm -f spice.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c spice.c
--- compiling base/wombat.o
rm -f wombat.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c wombat.c
--- compiling base/xilinx.o
rm -f xilinx.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c xilinx.c
--- compiling base/xillib.o
rm -f xillib.o
gcc -g -m64 -fPIC -fPIC -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c xillib.c
--- linking libbase.o
rm -f libbase.o
/bin/ld -r actel.o ccode.o greedy.o ntk.o print.o actellib.o embed.o hash.o netfile.o objlist.o query.o anneal.o ext.o netcmp.o netgen.o pdutils.o random.o timing.o bottomup.o flatten.o place.o spice.o wombat.o xilinx.o xillib.o -o libbase.o
make[2]: Leaving directory '/home/tim/gitsrc/netgen-1.5/base'
make[2]: Entering directory '/home/tim/gitsrc/netgen-1.5/tcltk'
../rules.mak:40: Depend: No such file or directory
gcc -g -m64 -fPIC -fPIC -I../base -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DNETGEN_DATE="\"`date`\"" -MM tclnetgen.c > Depend
--- compiling tcltk/tclnetgen.o
rm -f tclnetgen.o
gcc -g -m64 -fPIC -fPIC -I../base -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DNETGEN_DATE="\"`date`\"" -c tclnetgen.c
--- linking libtcltk.o
rm -f libtcltk.o
/bin/ld -r tclnetgen.o -o libtcltk.o
make[2]: Leaving directory '/home/tim/gitsrc/netgen-1.5/tcltk'
--- making Tcl shared-object libraries
for dir in netgen tcltk; do \
(cd $dir && make tcl-main); done
make[2]: Entering directory '/home/tim/gitsrc/netgen-1.5/netgen'
../rules.mak:40: Depend: No such file or directory
gcc -g -m64 -fPIC -fPIC -I../base -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DX11 -DXLIB -DNDEBUG -DNETGEN_DATE="\"`date`\"" -MM netgen_main.c > Depend
--- making netgen Tcl library (tclnetgen.so)
rm -f tclnetgen.so
gcc -g -m64 -fPIC -fPIC -I../base -I. -I.. -o tclnetgen.so -shared -Wl,-soname,tclnetgen.so -Wl,--version-script=../netgen/symbol.map \
../base/libbase.o ../tcltk/libtcltk.o -lc -lX11 -lm \
make[2]: Leaving directory '/home/tim/gitsrc/netgen-1.5/netgen'
make[2]: Entering directory '/home/tim/gitsrc/netgen-1.5/tcltk'
gcc -g -m64 -fPIC -fPIC -I../base -I. -I.. -DCAD_DIR=\"/usr/local/lib\" -DTCL_DIR=\"/usr/local/lib/netgen/tcl\" -DPACKAGE_NAME=\"netgen\" -DPACKAGE_TARNAME=\"netgen\" -DPACKAGE_VERSION=\"1.3\" -DPACKAGE_STRING=\"netgen\ 1.3\" -DPACKAGE_BUGREPORT=\"eda-dev@opencircuitdesign.com\" -DPACKAGE_URL=\"\" -DNETGEN_VERSION=\"1.5\" -DNETGEN_REVISION=\"39\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DSIZEOF_VOID_P=8 -DSIZEOF_UNSIGNED_INT=4 -DSIZEOF_UNSIGNED_LONG=8 -DSIZEOF_UNSIGNED_LONG_LONG=8 -DSTDC_HEADERS=1 -DHAVE_SETENV=1 -DHAVE_PUTENV=1 -DHAVE_DIRENT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1 -DSHDLIB_EXT=\".so\" -DNDEBUG -DNETGEN_DATE="\"`date`\"" netgenexec.c -o netgenexec \
-lm -L/usr/lib64 -ltk8.6 -L/usr/lib64 -ltcl8.6
sed -e /TCL_DIR/s%TCL_DIR%/usr/local/lib/netgen/tcl%g \
-e /SHDLIB_EXT/s%SHDLIB_EXT%.so%g \
netgen.tcl.in > netgen.tcl
sed -e /TCL_DIR/s%TCL_DIR%/usr/local/lib/netgen/tcl%g \
-e /TCLLIB_DIR/s%TCLLIB_DIR%/usr/lib%g \
-e /WISH_EXE/s%WISH_EXE%/usr/bin/wish%g \
netgen.sh.in > netgen.sh
make[2]: Leaving directory '/home/tim/gitsrc/netgen-1.5/tcltk'
make[1]: Leaving directory '/home/tim/gitsrc/netgen-1.5'

1
netgen/Depend Normal file
View File

@ -0,0 +1 @@
netgen_main.o: netgen_main.c ../base/netgen.h ../base/objlist.h

74
netgen/Makefile Normal file
View File

@ -0,0 +1,74 @@
MODULE = netgen
NETGENDIR = ..
SRCS = netgen_main.c
include ${NETGENDIR}/defs.mak
EXTRA_LIBS = ${NETGENDIR}/base/libbase.o \
${MAIN_EXTRA_LIBS}
DFLAGS += ${GR_DFLAGS}
DFLAGS += -DNETGEN_DATE="\"`date`\""
LIBS += ${GR_LIBS} -lm
CFLAGS += ${GR_CFLAGS} -I${NETGENDIR}/base
CLEANS += netgen netcomp ntk2adl inetcomp ntk2xnf
main: netgen netcomp inetcomp ntk2adl ntk2xnf
tcl-main: tclnetgen${SHDLIB_EXT}
tclnetgen${SHDLIB_EXT}: ${EXTRA_LIBS}
@echo --- making netgen Tcl library \(tclnetgen${SHDLIB_EXT}\)
${RM} tclnetgen${SHDLIB_EXT}
${CC} ${CFLAGS} ${CPPFLAGS} -o $@ ${LDDL_FLAGS} \
${LD_RUN_PATH} ${EXTRA_LIBS} ${LD_EXTRA_LIBS} -lc ${LIBS} \
${TCL_LIB_SPEC} ${LDFLAGS}
$(DESTDIR)${BINDIR}/netgen:
${RM} $@
${CP} netgen $@
$(DESTDIR)${BINDIR}/ntk2adl:
${RM} $@
${CP} ntk2adl $@
$(DESTDIR)${BINDIR}/ntk2xnf:
${RM} $@
${CP} ntk2xnf $@
$(DESTDIR)${BINDIR}/netcomp:
${RM} $@
${CP} netcomp $@
$(DESTDIR)${BINDIR}/inetcomp:
${RM} $@
${CP} inetcomp $@
netcomp: netcomp.c
${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} netcomp.c -o $@ ${EXTRA_LIBS} \
${LIBS} ${LDFLAGS}
inetcomp: inetcomp.c
${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} inetcomp.c -o $@ ${EXTRA_LIBS} \
${LIBS} ${LDFLAGS}
ntk2adl: ntk2adl.c
${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} ntk2adl.c -o $@ ${EXTRA_LIBS} \
${LIBS} ${LDFLAGS}
ntk2xnf: ntk2xnf.c
${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} ntk2xnf.c -o $@ ${EXTRA_LIBS} \
${LIBS} ${LDFLAGS}
install: $(DESTDIR)${BINDIR}/netgen $(DESTDIR)${BINDIR}/netcomp \
$(DESTDIR)${BINDIR}/inetcomp $(DESTDIR)${BINDIR}/ntk2adl \
$(DESTDIR)${BINDIR}/ntk2xnf
install-tcl: $(DESTDIR)${TCLDIR} $(DESTDIR)${TCLDIR}/tclnetgen${SHDLIB_EXT}
$(DESTDIR)${TCLDIR}/tclnetgen${SHDLIB_EXT}: tclnetgen${SHDLIB_EXT}
${RM} $(DESTDIR)${TCLDIR}/tclnetgen${SHDLIB_EXT}
${CP} tclnetgen${SHDLIB_EXT} $(DESTDIR)${TCLDIR}/tclnetgen${SHDLIB_EXT}
include ${NETGENDIR}/rules.mak

47
netgen/inetcomp.c Normal file
View File

@ -0,0 +1,47 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* inetcomp.c -- a simple wrapper to the NETCOMP() function */
#include <stdio.h>
#include "netgen.h"
#ifdef HAVE_GETOPT
#include <unistd.h>
#endif /* HAVE_GETOPT */
void STRCPY(char *dest, char *source)
{
while ((*dest++ = *source++) != '\0') ;
}
int main(int argc, char *argv[])
{
char cell1[200], cell2[200];
Debug = 0;
if (argc != 1) {
printf ("usage: inetcomp\n");
return (-1);
}
Initialize();
NETCOMP();
return(1);
}

127
netgen/netcomp.c Normal file
View File

@ -0,0 +1,127 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* netcomp.c -- a simple wrapper to provide netlist comparison functionality */
#include <stdio.h>
#include "netgen.h"
#ifdef HAVE_GETOPT
#include <unistd.h>
#endif /* HAVE_GETOPT */
#ifndef HAVE_X11
/* the following two procedures need to be defined to
* permit linking with netgen.o even if HAVE_X11 has
* been disabled
*/
void X_display_line(char *buf)
{
printf("%s", buf);
}
void X_display_refresh(void)
{
fflush(stdout);
}
#endif
void STRCPY(char *dest, char *source)
{
while ((*dest++ = *source++) != '\0') ;
}
int main(int argc, char *argv[])
{
#ifndef HAVE_GETOPT
char cell1[200], cell2[200];
Debug = 0;
if (argc < 3 || argc > 5) {
printf ("usage: netcomp <file 1> <file 2> [<cell 1> [<cell 2>]] \n");
return (-1);
}
Initialize();
STRCPY(cell1, ReadNetlist(argv[1]));
if (argc >= 4) STRCPY(cell1, argv[3]); /* if explicit cell name specified */
STRCPY(cell2, ReadNetlist(argv[2]));
if (argc == 5) STRCPY(cell2, argv[4]); /* if explicit cell name specified */
#else
char cell1[200], cell2[200];
int usage = 0;
int args;
int c;
Debug = 0;
VerboseOutput = 0;
IgnoreRC = 0;
while ((c = getopt(argc, argv, "ivq")) != EOF) {
switch (c) {
case 'i':
IgnoreRC = 1;
break;
case 'v':
VerboseOutput = 1;
break;
case 'q':
NoOutput = 1;
break;
default:
printf("Unknown flag: -%c\n", (char)c);
usage = 1;
}
}
args = argc - optind;
if (args < 2 || args > 4) {
printf("Wrong number of file/cell name arguments.\n");
usage = 1;
}
if (usage) {
printf ("usage: netcomp [-i] [-v] [-q] <file 1> <file 2> [<cell 1> [<cell 2>]]\n");
printf (" -i = don't try to match resistances and capacitances\n");
printf (" -v = verbose output\n");
printf (" -q = no output (only results and return code)\n");
return (-1);
}
Initialize();
/* NoDisconnectedNodes = 1; we now do this in Compare(), AFTER reading cells */
STRCPY(cell1, ReadNetlist(argv[optind]));
if (args >= 3) STRCPY(cell1, argv[optind + 2]);
STRCPY(cell2, ReadNetlist(argv[optind + 1]));
if (args == 4) STRCPY(cell2, argv[optind + 3]);
#endif
printf("Comparing cells: %s (circuit 1) and %s (circuit2).\n\n", cell1, cell2);
Flatten(cell1, -1);
Flatten(cell2, -1);
if (Compare(cell1, cell2)) {
printf("Cells are identical.\n");
return(0);
}
printf("Cells are different.\n");
return(1);
}

40
netgen/netgen_main.c Normal file
View File

@ -0,0 +1,40 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* netgen_main.c -- top-level (main) routine */
#include <stdio.h>
#ifdef ANSI_LIBRARY
#include <stdlib.h> /* for getenv */
#endif
#include "netgen.h"
int main(int argc, char **argv)
{
Finsert(stderr);
InitializeCommandLine(argc, argv);
#ifdef HAVE_X11
X_main_loop(argc, argv); /* does not return, if really running X */
#else
Query();
#endif
return(0);
}

63
netgen/ntk2adl.c Normal file
View File

@ -0,0 +1,63 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ntk2adl.c -- a simple wrapper to translate .ntk to ACTEL format */
#include <stdio.h>
#include "netgen.h"
#ifndef HAVE_X11
/* the following two procedures permit linking
* with netgen.a even if HAVE_X11 has been disabled
*/
void X_display_line(char *buf)
{
printf("%s", buf);
}
void X_display_refresh(void)
{
fflush(stdout);
}
#endif
void STRCPY(char *dest, char *source)
{
while ((*dest++ = *source++) != '\0') ;
}
int main(int argc, char *argv[])
{
char cellname[200];
Debug = 0;
if (argc < 2 || argc > 3) {
printf ("usage: ntk2adl <netlist file name> [<top level cell name>]\n");
return (-1);
}
Initialize();
ActelLib();
STRCPY(cellname, ReadNetlist(argv[1]));
if (argc == 3) STRCPY(cellname, argv[2]);
Actel(cellname, NULL);
return(0);
}

65
netgen/ntk2xnf.c Normal file
View File

@ -0,0 +1,65 @@
/* "NETGEN", a netlist-specification tool for VLSI
Copyright (C) 1989, 1990 Massimo A. Sivilotti
Author's address: mass@csvax.cs.caltech.edu;
Caltech 256-80, Pasadena CA 91125.
Xilinx generator extensions
Copyright (C) 1995, Ingo Cyliax, EZComm Consulting
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file copying. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ntk2xnf.c -- a simple wrapper to translate .ntk to Xilinx XNF format */
#include <stdio.h>
#include "netgen.h"
#ifdef HAVE_X11
/* the following two X procedures are to permit linking
with netgen.a even if HAVE_X11 has been enabled */
void X_display_line(char *buf)
{
printf("%s", buf);
}
void X_display_refresh(void)
{
fflush(stdout);
}
#endif
void STRCPY(char *dest, char *source)
{
while ((*dest++ = *source++) != '\0') ;
}
int main(int argc, char *argv[])
{
char cellname[200];
Debug = 0;
if (argc < 2 || argc > 3) {
printf ("usage: ntk2xnf <netlist file name> [<top level cell name>]\n");
return (-1);
}
Initialize();
XilinxLib();
STRCPY(cellname, ReadNetlist(argv[1]));
if (argc == 3) STRCPY(cellname, argv[2]);
Xilinx(cellname, NULL);
return(0);
}

4
netgen/symbol.map Normal file
View File

@ -0,0 +1,4 @@
NETGEN_1.1 {
global: Tclnetgen_Init;
local: *;
};

BIN
netgen/tclnetgen.so Executable file

Binary file not shown.

84
regexp/README Normal file
View File

@ -0,0 +1,84 @@
This is a nearly-public-domain reimplementation of the V8 regexp(3) package.
It gives C programs the ability to use egrep-style regular expressions, and
does it in a much cleaner fashion than the analogous routines in SysV.
Copyright (c) 1986 by University of Toronto.
Written by Henry Spencer. Not derived from licensed software.
Permission is granted to anyone to use this software for any
purpose on any computer system, and to redistribute it freely,
subject to the following restrictions:
1. The author is not responsible for the consequences of use of
this software, no matter how awful, even if they arise
from defects in it.
2. The origin of this software must not be misrepresented, either
by explicit claim or by omission.
3. Altered versions must be plainly marked as such, and must not
be misrepresented as being the original software.
Barring a couple of small items in the BUGS list, this implementation is
believed 100% compatible with V8. It should even be binary-compatible,
sort of, since the only fields in a "struct regexp" that other people have
any business touching are declared in exactly the same way at the same
location in the struct (the beginning).
This implementation is *NOT* AT&T/Bell code, and is not derived from licensed
software. Even though U of T is a V8 licensee. This software is based on
a V8 manual page sent to me by Dennis Ritchie (the manual page enclosed
here is a complete rewrite and hence is not covered by AT&T copyright).
The software was nearly complete at the time of arrival of our V8 tape.
I haven't even looked at V8 yet, although a friend elsewhere at U of T has
been kind enough to run a few test programs using the V8 regexp(3) to resolve
a few fine points. I admit to some familiarity with regular-expression
implementations of the past, but the only one that this code traces any
ancestry to is the one published in Kernighan & Plauger (from which this
one draws ideas but not code).
Simplistically: put this stuff into a source directory, copy regexp.h into
/usr/include, inspect Makefile for compilation options that need changing
to suit your local environment, and then do "make r". This compiles the
regexp(3) functions, compiles a test program, and runs a large set of
regression tests. If there are no complaints, then put regexp.o, regsub.o,
and regerror.o into your C library, and regexp.3 into your manual-pages
directory.
Note that if you don't put regexp.h into /usr/include *before* compiling,
you'll have to add "-I." to CFLAGS before compiling.
The files are:
Makefile instructions to make everything
regexp.3 manual page
regexp.h header file, for /usr/include
regexp.c source for regcomp() and regexec()
regsub.c source for regsub()
regerror.c source for default regerror()
regmagic.h internal header file
try.c source for test program
timer.c source for timing program
tests test list for try and timer
This implementation uses nondeterministic automata rather than the
deterministic ones found in some other implementations, which makes it
simpler, smaller, and faster at compiling regular expressions, but slower
at executing them. In theory, anyway. This implementation does employ
some special-case optimizations to make the simpler cases (which do make
up the bulk of regular expressions actually used) run quickly. In general,
if you want blazing speed you're in the wrong place. Replacing the insides
of egrep with this stuff is probably a mistake; if you want your own egrep
you're going to have to do a lot more work. But if you want to use regular
expressions a little bit in something else, you're in luck. Note that many
existing text editors use nondeterministic regular-expression implementations,
so you're in good company.
This stuff should be pretty portable, given appropriate option settings.
If your chars have less than 8 bits, you're going to have to change the
internal representation of the automaton, although knowledge of the details
of this is fairly localized. There are no "reserved" char values except for
NUL, and no special significance is attached to the top bit of chars.
The string(3) functions are used a fair bit, on the grounds that they are
probably faster than coding the operations in line. Some attempts at code
tuning have been made, but this is invariably a bit machine-specific.

17
regexp/fixtabs.c Normal file
View File

@ -0,0 +1,17 @@
#include <stdio.h>
char buffer[100];
int i;
main()
{
while (fgets(buffer,100,stdin) != NULL) {
for (i=0; i < strlen(buffer); i++) {
if (buffer[i] == ' ') {
putchar('\t');
while (buffer[i] == ' ') i++;
}
putchar(buffer[i]);
}
}
}

36
regexp/makefile.pc Normal file
View File

@ -0,0 +1,36 @@
ENV=-IC:\turboc\include -LC:\turboc\lib -DIBMPC -mh -w-pro
CFLAGS=$(ENV)
REGOBJ=regexp.obj regsub.obj regerror.obj
regexp.lib: $(REGOBJ)
rm regexp.lib
tlib /C regexp +regexp +regsub +regerror
fixtabs: fixtabs.c
tcc $(CFLAGS) -efixtabs fixtabs.c
regexp.obj: regexp.h regmagic.h
regsub.obj: regexp.h regmagic.h
try.obj: regexp.h
# generate REGEX stuff
try: try.obj regexp.lib
tcc $(CFLAGS) -etry try.obj regexp.lib
# Regression test.
r: try tests
@echo 'No news is good news...'
try <tests
clean:
rm *.obj
rm *.exe
rm *.lib
.c.obj:
tcc -c $(CFLAGS) $<

54
regexp/makefile.unx Normal file
View File

@ -0,0 +1,54 @@
# Things you might want to put in ENV and LENV:
# -Dvoid=int compilers that don't do void
# -DCHARBITS=0377 compilers that don't do unsigned char
# -DSTATIC=extern compilers that don't like "static foo();" as forward decl
# -DSTRCSPN library does not have strcspn()
# -Dstrchr=index library does not have strchr()
# -DERRAVAIL have utzoo-compatible error() function and friends
#ENV=-Dvoid=int -DCHARBITS=0377 -DSTATIC=extern
#ENV=-IC:\turboc\include -IC:\netgen -LC:\turboc\lib
ENV=
#LENV=-Dvoid=int -DCHARBITS=0377
# Things you might want to put in TEST:
# -DDEBUG debugging hooks
# -I. regexp.h from current directory, not /usr/include
TEST=
# Things you might want to put in PROF:
# -Dstatic='/* */' make everything global so profiler can see it.
# -p profiler
#PROF= -pg
PROF=
CFLAGS=$(ENV) $(TEST) $(PROF) -O
REGOBJ=regexp.o regsub.o regerror.o
CC=gcc
# generate REGEX stuff
regexp.a: regerror.o regexp.o regsub.o
ar r regexp.a regerror.o regsub.o regexp.o
ranlib regexp.a
try: try.o $(REGOBJ)
$(CC) $(CFLAGS) -o try try.o $(REGOBJ)
fixtabs: fixtabs.c
$(CC) $(CFLAGS) -o fixtabs fixtabs.c
regerror.o: regerror.c
regexp.o: regexp.c regexp.h regmagic.h
regsub.o: regsub.c regexp.h regmagic.h
try.o: regexp.h try.c
# Regression test.
r: try tests
echo 'No news is good news...'
try <tests
clean:
-rm *.o *.a

14
regexp/regerror.c Normal file
View File

@ -0,0 +1,14 @@
#include <stdio.h>
void
regerror(s)
char *s;
{
#ifdef ERRAVAIL
error("regexp: %s", s);
#else
fprintf(stderr, "regexp(3): %s", s);
exit(1);
#endif
/* NOTREACHED */
}

179
regexp/regexp.3 Normal file
View File

@ -0,0 +1,179 @@
.TH REGEXP 3 local
.DA 30 Nov 1985
.SH NAME
regcomp, regexec, regsub, regerror \- regular expression handler
.SH SYNOPSIS
.ft B
.nf
#include <regexp.h>
regexp *regcomp(exp)
char *exp;
int regexec(prog, string)
regexp *prog;
char *string;
regsub(prog, source, dest)
regexp *prog;
char *source;
char *dest;
regerror(msg)
char *msg;
.SH DESCRIPTION
These functions implement
.IR egrep (1)-style
regular expressions and supporting facilities.
.PP
.I Regcomp
compiles a regular expression into a structure of type
.IR regexp ,
and returns a pointer to it.
The space has been allocated using
.IR malloc (3)
and may be released by
.IR free .
.PP
.I Regexec
matches a NUL-terminated \fIstring\fR against the compiled regular expression
in \fIprog\fR.
It returns 1 for success and 0 for failure, and adjusts the contents of
\fIprog\fR's \fIstartp\fR and \fIendp\fR (see below) accordingly.
.PP
The members of a
.I regexp
structure include at least the following (not necessarily in order):
.PP
.RS
char *startp[NSUBEXP];
.br
char *endp[NSUBEXP];
.RE
.PP
where
.I NSUBEXP
is defined (as 10) in the header file.
Once a successful \fIregexec\fR has been done using the \fIregexp\fR,
each \fIstartp\fR-\fIendp\fR pair describes one substring
within the \fIstring\fR,
with the \fIstartp\fR pointing to the first character of the substring and
the \fIendp\fR pointing to the first character following the substring.
The 0th substring is the substring of \fIstring\fR that matched the whole
regular expression.
The others are those substrings that matched parenthesized expressions
within the regular expression, with parenthesized expressions numbered
in left-to-right order of their opening parentheses.
.PP
.I Regsub
copies \fIsource\fR to \fIdest\fR, making substitutions according to the
most recent \fIregexec\fR performed using \fIprog\fR.
Each instance of `&' in \fIsource\fR is replaced by the substring
indicated by \fIstartp\fR[\fI0\fR] and
\fIendp\fR[\fI0\fR].
Each instance of `\e\fIn\fR', where \fIn\fR is a digit, is replaced by
the substring indicated by
\fIstartp\fR[\fIn\fR] and
\fIendp\fR[\fIn\fR].
To get a literal `&' or `\e\f\In\fR' into \fIdest\fR, prefix it with `\e';
to get a literal `\e' preceeding `&' or `\e\fIn\fR', prefix it with
another `\e'.
.PP
.I Regerror
is called whenever an error is detected in \fIregcomp\fR, \fIregexec\fR,
or \fIregsub\fR.
The default \fIregerror\fR writes the string \fImsg\fR,
with a suitable indicator of origin,
on the standard
error output
and invokes \fIexit\fR(2).
.I Regerror
can be replaced by the user if other actions are desirable.
.SH "REGULAR EXPRESSION SYNTAX"
A regular expression is zero or more \fIbranches\fR, separated by `|'.
It matches anything that matches one of the branches.
.PP
A branch is zero or more \fIpieces\fR, concatenated.
It matches a match for the first, followed by a match for the second, etc.
.PP
A piece is an \fIatom\fR possibly followed by `*', `+', or `?'.
An atom followed by `*' matches a sequence of 0 or more matches of the atom.
An atom followed by `+' matches a sequence of 1 or more matches of the atom.
An atom followed by `?' matches a match of the atom, or the null string.
.PP
An atom is a regular expression in parentheses (matching a match for the
regular expression), a \fIrange\fR (see below), `.'
(matching any single character), `^' (matching the null string at the
beginning of the input string), `$' (matching the null string at the
end of the input string), a `\e' followed by a single character (matching
that character), or a single character with no other significance
(matching that character).
.PP
A \fIrange\fR is a sequence of characters enclosed in `[]'.
It normally matches any single character from the sequence.
If the sequence begins with `^',
it matches any single character \fInot\fR from the rest of the sequence.
If two characters in the sequence are separated by `\-', this is shorthand
for the full list of ASCII characters between them
(e.g. `[0-9]' matches any decimal digit).
To include a literal `]' in the sequence, make it the first character
(following a possible `^').
To include a literal `\-', make it the first or last character.
.SH AMBIGUITY
If a regular expression could match two different parts of the input string,
it will match the one which begins earliest.
If both begin in the same place but match different lengths, or match
the same length in different ways, life gets messier, as follows.
.PP
In general, the possibilities in a list of branches are considered in
left-to-right order, the possibilities for `*', `+', and `?' are
considered longest-first, nested constructs are considered from the
outermost in, and concatenated constructs are considered leftmost-first.
The match that will be chosen is the one that uses the earliest
possibility in the first choice that has to be made.
If there is more than one choice, the next will be made in the same manner
(earliest possibility) subject to the decision on the first choice.
And so forth.
.PP
For example, `(ab|a)b*c' could match `abc' in one of two ways.
The first choice is between `ab' and `a'; since `ab' is earlier, and does
lead to a successful overall match, it is chosen.
Since the `b' is already spoken for,
the `b*' must match its last possibility\(emthe empty string\(emsince
it must respect the earlier choice.
.PP
In the particular case where no `|'s are present and there is only one
`*', `+', or `?', the net effect is that the longest possible
match will be chosen.
So `ab*', presented with `xabbbby', will match `abbbb'.
Note that if `ab*' is tried against `xabyabbbz', it
will match `ab' just after `x', due to the begins-earliest rule.
(In effect, the decision on where to start the match is the first choice
to be made, hence subsequent choices must respect it even if this leads them
to less-preferred alternatives.)
.SH SEE ALSO
egrep(1), expr(1)
.SH DIAGNOSTICS
\fIRegcomp\fR returns NULL for a failure
(\fIregerror\fR permitting),
where failures are syntax errors, exceeding implementation limits,
or applying `+' or `*' to a possibly-null operand.
.SH HISTORY
Both code and manual page were
written at U of T.
They are intended to be compatible with the Bell V8 \fIregexp\fR(3),
but are not derived from Bell code.
.SH BUGS
Empty branches and empty regular expressions are not portable to V8.
.PP
The restriction against
applying `*' or `+' to a possibly-null operand is an artifact of the
simplistic implementation.
.PP
Does not support \fIegrep\fR's newline-separated branches;
neither does the V8 \fIregexp\fR(3), though.
.PP
Due to emphasis on
compactness and simplicity,
it's not strikingly fast.
It does give special attention to handling simple cases quickly.

1214
regexp/regexp.c Normal file

File diff suppressed because it is too large Load Diff

84
regexp/regexp.doc Normal file
View File

@ -0,0 +1,84 @@
This is a nearly-public-domain reimplementation of the V8 regexp(3) package.
It gives C programs the ability to use egrep-style regular expressions, and
does it in a much cleaner fashion than the analogous routines in SysV.
Copyright (c) 1986 by University of Toronto.
Written by Henry Spencer. Not derived from licensed software.
Permission is granted to anyone to use this software for any
purpose on any computer system, and to redistribute it freely,
subject to the following restrictions:
1. The author is not responsible for the consequences of use of
this software, no matter how awful, even if they arise
from defects in it.
2. The origin of this software must not be misrepresented, either
by explicit claim or by omission.
3. Altered versions must be plainly marked as such, and must not
be misrepresented as being the original software.
Barring a couple of small items in the BUGS list, this implementation is
believed 100% compatible with V8. It should even be binary-compatible,
sort of, since the only fields in a "struct regexp" that other people have
any business touching are declared in exactly the same way at the same
location in the struct (the beginning).
This implementation is *NOT* AT&T/Bell code, and is not derived from licensed
software. Even though U of T is a V8 licensee. This software is based on
a V8 manual page sent to me by Dennis Ritchie (the manual page enclosed
here is a complete rewrite and hence is not covered by AT&T copyright).
The software was nearly complete at the time of arrival of our V8 tape.
I haven't even looked at V8 yet, although a friend elsewhere at U of T has
been kind enough to run a few test programs using the V8 regexp(3) to resolve
a few fine points. I admit to some familiarity with regular-expression
implementations of the past, but the only one that this code traces any
ancestry to is the one published in Kernighan & Plauger (from which this
one draws ideas but not code).
Simplistically: put this stuff into a source directory, copy regexp.h into
/usr/include, inspect Makefile for compilation options that need changing
to suit your local environment, and then do "make r". This compiles the
regexp(3) functions, compiles a test program, and runs a large set of
regression tests. If there are no complaints, then put regexp.o, regsub.o,
and regerror.o into your C library, and regexp.3 into your manual-pages
directory.
Note that if you don't put regexp.h into /usr/include *before* compiling,
you'll have to add "-I." to CFLAGS before compiling.
The files are:
Makefile instructions to make everything
regexp.3 manual page
regexp.h header file, for /usr/include
regexp.c source for regcomp() and regexec()
regsub.c source for regsub()
regerror.c source for default regerror()
regmagic.h internal header file
try.c source for test program
timer.c source for timing program
tests test list for try and timer
This implementation uses nondeterministic automata rather than the
deterministic ones found in some other implementations, which makes it
simpler, smaller, and faster at compiling regular expressions, but slower
at executing them. In theory, anyway. This implementation does employ
some special-case optimizations to make the simpler cases (which do make
up the bulk of regular expressions actually used) run quickly. In general,
if you want blazing speed you're in the wrong place. Replacing the insides
of egrep with this stuff is probably a mistake; if you want your own egrep
you're going to have to do a lot more work. But if you want to use regular
expressions a little bit in something else, you're in luck. Note that many
existing text editors use nondeterministic regular-expression implementations,
so you're in good company.
This stuff should be pretty portable, given appropriate option settings.
If your chars have less than 8 bits, you're going to have to change the
internal representation of the automaton, although knowledge of the details
of this is fairly localized. There are no "reserved" char values except for
NUL, and no special significance is attached to the top bit of chars.
The string(3) functions are used a fair bit, on the grounds that they are
probably faster than coding the operations in line. Some attempts at code
tuning have been made, but this is invariably a bit machine-specific.

21
regexp/regexp.h Normal file
View File

@ -0,0 +1,21 @@
/*
* Definitions etc. for regexp(3) routines.
*
* Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
* not the System V one.
*/
#define NSUBEXP 10
typedef struct regexp {
char *startp[NSUBEXP];
char *endp[NSUBEXP];
char regstart; /* Internal use only. */
char reganch; /* Internal use only. */
char *regmust; /* Internal use only. */
int regmlen; /* Internal use only. */
char program[1]; /* Unwarranted chumminess with compiler. */
} regexp;
extern regexp *regcomp();
extern int regexec();
extern void regsub();
extern void regerror();

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