Initial commit at Mon May 18 09:27:46 EDT 2015 by tim on stravinsky
This commit is contained in:
commit
d5e9f81cb0
|
|
@ -0,0 +1,10 @@
|
||||||
|
*.*%
|
||||||
|
*.cdslck
|
||||||
|
.inca.db.*
|
||||||
|
inca.*.pak
|
||||||
|
*.swp
|
||||||
|
*~
|
||||||
|
*/av_extracted*/
|
||||||
|
.nfs*
|
||||||
|
*.cd-
|
||||||
|
*/mommdl/
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
@ -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!
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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);
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
@ -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 */
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 */
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
@ -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))
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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 */
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 */
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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 */
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
/* timing routines */
|
||||||
|
extern float CPUTime(void);
|
||||||
|
extern float ElapsedCPUTime(float since);
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||||
|
|
@ -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 $* )
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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");
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -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_ ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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 */
|
||||||
|
|
@ -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
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 */
|
||||||
|
|
@ -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}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -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'
|
||||||
|
|
@ -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/$*
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/csh
|
||||||
|
echo ntk2adl $1 $2
|
||||||
|
netgen A K $1 a $2
|
||||||
|
|
@ -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"
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
* End of SPICE deck. Put all simulation stuff here.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.END
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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'
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
netgen_main.o: netgen_main.c ../base/netgen.h ../base/objlist.h
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
NETGEN_1.1 {
|
||||||
|
global: Tclnetgen_Init;
|
||||||
|
local: *;
|
||||||
|
};
|
||||||
Binary file not shown.
|
|
@ -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.
|
||||||
|
|
@ -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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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) $<
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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 */
|
||||||
|
}
|
||||||
|
|
@ -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.
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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.
|
||||||
|
|
@ -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
Loading…
Reference in New Issue