From d5e9f81cb09503cc2f62b5259340c1dd2bd03452 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 18 May 2015 09:27:46 -0400 Subject: [PATCH] Initial commit at Mon May 18 09:27:46 EDT 2015 by tim on stravinsky --- .gitignore | 10 + Changes | 176 + Copying | 249 ++ Makefile | 104 + README | 158 + TO_DO | 37 + VERSION | 1 + base/Depend | 44 + base/Makefile | 16 + base/actel.c | 430 +++ base/actellib.c | 1275 ++++++ base/anneal.c | 257 ++ base/bottomup.c | 691 ++++ base/ccode.c | 111 + base/config.h | 188 + base/dbug.h | 137 + base/embed.c | 766 ++++ base/embed.h | 172 + base/ext.c | 948 +++++ base/flatten.c | 1634 ++++++++ base/greedy.c | 492 +++ base/hash.c | 393 ++ base/hash.h | 49 + base/inetcomp.c | 47 + base/netcmp.c | 5273 +++++++++++++++++++++++++ base/netcmp.h | 54 + base/netfile.c | 879 +++++ base/netfile.h | 41 + base/netgen.c | 2741 +++++++++++++ base/netgen.h | 190 + base/ntk.c | 369 ++ base/objlist.c | 1294 +++++++ base/objlist.h | 280 ++ base/pdutils.c | 625 +++ base/pdutils.h | 53 + base/place.c | 1254 ++++++ base/print.c | 347 ++ base/print.h | 12 + base/proto.h | 65 + base/query.c | 1171 ++++++ base/query.h | 30 + base/random.c | 230 ++ base/regexp.h | 57 + base/spice.c | 2007 ++++++++++ base/test.c | 263 ++ base/timing.c | 119 + base/timing.h | 3 + base/wombat.c | 92 + base/xilinx.c | 368 ++ base/xillib.c | 1264 ++++++ base/xnetgen.c | 2679 +++++++++++++ base/xnetgen.h | 18 + configure | 7 + dbug/Makefile | 211 + dbug/README.prof | 70 + dbug/analyze.c | 566 +++ dbug/dbug.c | 1881 +++++++++ dbug/dbug.h | 162 + dbug/doinstall.sh | 15 + dbug/example1.c | 12 + dbug/example2.c | 17 + dbug/example3.c | 16 + dbug/factorial.c | 15 + dbug/install.sh | 64 + dbug/llib-ldbug | 129 + dbug/main.c | 27 + dbug/mklintlib.sh | 30 + dbug/ranlib.sh | 15 + dbug/useful.h | 84 + dbug/user.r | 943 +++++ dbug/user.t | 1450 +++++++ dbug/vargs.h | 143 + defs.mak | 82 + doc/Makefile | 30 + doc/netgen.doc | 607 +++ install.log | 49 + lib/Makefile | 17 + lib/ntk2adl.sh | 3 + lib/spice | 102 + lib/spice.bot | 5 + lib/spice.top | 22 + make.log | 120 + netgen/Depend | 1 + netgen/Makefile | 74 + netgen/inetcomp.c | 47 + netgen/netcomp.c | 127 + netgen/netgen_main.c | 40 + netgen/ntk2adl.c | 63 + netgen/ntk2xnf.c | 65 + netgen/symbol.map | 4 + netgen/tclnetgen.so | Bin 0 -> 521888 bytes regexp/README | 84 + regexp/fixtabs.c | 17 + regexp/makefile.pc | 36 + regexp/makefile.unx | 54 + regexp/regerror.c | 14 + regexp/regexp.3 | 179 + regexp/regexp.c | 1214 ++++++ regexp/regexp.doc | 84 + regexp/regexp.h | 21 + regexp/regmagic.h | 5 + regexp/regsub.c | 81 + regexp/tests | 120 + regexp/tests.bad | 119 + regexp/timer.c | 182 + regexp/try.c | 238 ++ rules.mak | 40 + scripts/config.guess | 1314 +++++++ scripts/config.log | 765 ++++ scripts/config.status | 938 +++++ scripts/config.sub | 1410 +++++++ scripts/configure | 7724 +++++++++++++++++++++++++++++++++++++ scripts/configure.in | 1302 +++++++ scripts/configure.in.orig | 1307 +++++++ scripts/defs.mak | 82 + scripts/defs.mak.in | 82 + scripts/install-sh | 251 ++ scripts/makedbh | 187 + scripts/missing | 283 ++ scripts/mkdirs | 32 + scripts/netgen.spec.in | 45 + tcltk/Depend | 3 + tcltk/Makefile | 49 + tcltk/console.tcl | 4 + tcltk/netgen.sh.in | 54 + tcltk/netgen.tcl.in | 347 ++ tcltk/netgenexec.c | 86 + tcltk/tclnetgen.c | 3852 ++++++++++++++++++ tcltk/tkcon.tcl | 5275 +++++++++++++++++++++++++ 129 files changed, 65358 insertions(+) create mode 100644 .gitignore create mode 100644 Changes create mode 100644 Copying create mode 100644 Makefile create mode 100644 README create mode 100644 TO_DO create mode 100644 VERSION create mode 100644 base/Depend create mode 100644 base/Makefile create mode 100644 base/actel.c create mode 100644 base/actellib.c create mode 100644 base/anneal.c create mode 100644 base/bottomup.c create mode 100644 base/ccode.c create mode 100644 base/config.h create mode 100644 base/dbug.h create mode 100644 base/embed.c create mode 100644 base/embed.h create mode 100644 base/ext.c create mode 100644 base/flatten.c create mode 100644 base/greedy.c create mode 100644 base/hash.c create mode 100644 base/hash.h create mode 100644 base/inetcomp.c create mode 100644 base/netcmp.c create mode 100644 base/netcmp.h create mode 100644 base/netfile.c create mode 100644 base/netfile.h create mode 100644 base/netgen.c create mode 100644 base/netgen.h create mode 100644 base/ntk.c create mode 100644 base/objlist.c create mode 100644 base/objlist.h create mode 100644 base/pdutils.c create mode 100644 base/pdutils.h create mode 100644 base/place.c create mode 100644 base/print.c create mode 100644 base/print.h create mode 100644 base/proto.h create mode 100644 base/query.c create mode 100644 base/query.h create mode 100644 base/random.c create mode 100644 base/regexp.h create mode 100644 base/spice.c create mode 100644 base/test.c create mode 100644 base/timing.c create mode 100644 base/timing.h create mode 100644 base/wombat.c create mode 100644 base/xilinx.c create mode 100644 base/xillib.c create mode 100644 base/xnetgen.c create mode 100644 base/xnetgen.h create mode 100755 configure create mode 100644 dbug/Makefile create mode 100644 dbug/README.prof create mode 100644 dbug/analyze.c create mode 100644 dbug/dbug.c create mode 100644 dbug/dbug.h create mode 100644 dbug/doinstall.sh create mode 100644 dbug/example1.c create mode 100644 dbug/example2.c create mode 100644 dbug/example3.c create mode 100644 dbug/factorial.c create mode 100644 dbug/install.sh create mode 100644 dbug/llib-ldbug create mode 100644 dbug/main.c create mode 100644 dbug/mklintlib.sh create mode 100644 dbug/ranlib.sh create mode 100644 dbug/useful.h create mode 100644 dbug/user.r create mode 100644 dbug/user.t create mode 100644 dbug/vargs.h create mode 100644 defs.mak create mode 100644 doc/Makefile create mode 100644 doc/netgen.doc create mode 100644 install.log create mode 100644 lib/Makefile create mode 100644 lib/ntk2adl.sh create mode 100644 lib/spice create mode 100644 lib/spice.bot create mode 100644 lib/spice.top create mode 100644 make.log create mode 100644 netgen/Depend create mode 100644 netgen/Makefile create mode 100644 netgen/inetcomp.c create mode 100644 netgen/netcomp.c create mode 100644 netgen/netgen_main.c create mode 100644 netgen/ntk2adl.c create mode 100644 netgen/ntk2xnf.c create mode 100644 netgen/symbol.map create mode 100755 netgen/tclnetgen.so create mode 100644 regexp/README create mode 100644 regexp/fixtabs.c create mode 100644 regexp/makefile.pc create mode 100644 regexp/makefile.unx create mode 100644 regexp/regerror.c create mode 100644 regexp/regexp.3 create mode 100644 regexp/regexp.c create mode 100644 regexp/regexp.doc create mode 100644 regexp/regexp.h create mode 100644 regexp/regmagic.h create mode 100644 regexp/regsub.c create mode 100644 regexp/tests create mode 100644 regexp/tests.bad create mode 100644 regexp/timer.c create mode 100644 regexp/try.c create mode 100644 rules.mak create mode 100755 scripts/config.guess create mode 100644 scripts/config.log create mode 100755 scripts/config.status create mode 100755 scripts/config.sub create mode 100755 scripts/configure create mode 100644 scripts/configure.in create mode 100644 scripts/configure.in.orig create mode 100644 scripts/defs.mak create mode 100644 scripts/defs.mak.in create mode 100755 scripts/install-sh create mode 100755 scripts/makedbh create mode 100755 scripts/missing create mode 100755 scripts/mkdirs create mode 100644 scripts/netgen.spec.in create mode 100644 tcltk/Depend create mode 100644 tcltk/Makefile create mode 100644 tcltk/console.tcl create mode 100755 tcltk/netgen.sh.in create mode 100644 tcltk/netgen.tcl.in create mode 100644 tcltk/netgenexec.c create mode 100644 tcltk/tclnetgen.c create mode 100755 tcltk/tkcon.tcl diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..67222f7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*.*% +*.cdslck +.inca.db.* +inca.*.pak +*.swp +*~ +*/av_extracted*/ +.nfs* +*.cd- +*/mommdl/ diff --git a/Changes b/Changes new file mode 100644 index 0000000..d22c947 --- /dev/null +++ b/Changes @@ -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 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) + diff --git a/Copying b/Copying new file mode 100644 index 0000000..9a17037 --- /dev/null +++ b/Copying @@ -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. + + + Copyright (C) 19yy + + 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. + + , 1 April 1989 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..402b26d --- /dev/null +++ b/Makefile @@ -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 + diff --git a/README b/README new file mode 100644 index 0000000..b2d35b4 --- /dev/null +++ b/README @@ -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 [] [] + + 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 + readnet sim + source + compare + 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 + elements + + 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. + diff --git a/TO_DO b/TO_DO new file mode 100644 index 0000000..1786081 --- /dev/null +++ b/TO_DO @@ -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. + diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..9caff18 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1.5.39 diff --git a/base/Depend b/base/Depend new file mode 100644 index 0000000..e59865e --- /dev/null +++ b/base/Depend @@ -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 diff --git a/base/Makefile b/base/Makefile new file mode 100644 index 0000000..e3f7001 --- /dev/null +++ b/base/Makefile @@ -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 diff --git a/base/actel.c b/base/actel.c new file mode 100644 index 0000000..2b33e18 --- /dev/null +++ b/base/actel.c @@ -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 +#include +#include +#ifdef IBMPC +#include /* for strtol on PC */ +#endif + +#ifdef TCL_NETGEN +#include +#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 () + +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 /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); +} + diff --git a/base/actellib.c b/base/actellib.c new file mode 100644 index 0000000..1757ba9 --- /dev/null +++ b/base/actellib.c @@ -0,0 +1,1275 @@ +/* "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. */ + + +/* actellib.c -- definitions of all cells in ACTEL's cell library */ + + +/* define the following to make pads unique */ +/* this is necessary for ntk2adl, but is annoying for PLACE */ + +#undef USE_UNIQUE_GLOBALS + + +#include "config.h" +#include +#include "netgen.h" + +static int actel_lib_present = 0; + +int ActelLibPresent(void) +{ + return actel_lib_present; +} + +void ActelLib(void) +{ + int OldDebug; + + OldDebug = Debug; + Debug = 0; + + CellDef("OUTBUF", -1); +#ifdef USE_UNIQUE_GLOBALS + UniqueGlobal("PAD"); +#else + Port("PAD"); +#endif + Port("D"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("INBUF", -1); + Port("Y"); +#ifdef USE_UNIQUE_GLOBALS + UniqueGlobal("PAD"); +#else + Port("PAD"); +#endif + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("CLKBUF", -1); + Port("Y"); +#ifdef USE_UNIQUE_GLOBALS + UniqueGlobal("PAD"); +#else + Port("PAD"); +#endif + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("TRIBUFF", -1); +#ifdef USE_UNIQUE_GLOBALS + UniqueGlobal("PAD"); +#else + Port("PAD"); +#endif + Port("D"); + Port("E"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("BIBUF", -1); +#ifdef USE_UNIQUE_GLOBALS + UniqueGlobal("PAD"); +#else + Port("PAD"); +#endif + Port("D"); + Port("E"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND2", -1); + Port("A"); + Port("B"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND2A", -1); + Port("A"); + Port("B"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND2B", -1); + Port("A"); + Port("B"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND2", -1); + Port("A"); + Port("B"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND2A", -1); + Port("A"); + Port("B"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND2B", -1); + Port("A"); + Port("B"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR2", -1); + Port("A"); + Port("B"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR2A", -1); + Port("A"); + Port("B"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR2B", -1); + Port("A"); + Port("B"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR2", -1); + Port("A"); + Port("B"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR2A", -1); + Port("A"); + Port("B"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR2B", -1); + Port("A"); + Port("B"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND3", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND3A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND3B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND3C", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND3", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND3A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND3B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND3C", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR3", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR3A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR3B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR3C", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR3", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR3A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR3B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR3C", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND4", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND4A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND4B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND4C", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND4D", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND4", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND4A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND4B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND4C", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND4D", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR4", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR4A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR4B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR4C", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR4D", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR4", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR4A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR4B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR4C", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR4D", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + +/* +INBUF +CLKBUF +OUTBUF +TRIBUF +BIBUF +*/ + + + + + + CellDef("BUF", -1); + Port("A"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("BUFA", -1); + Port("A"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("INV", -1); + Port("A"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("INVA", -1); + Port("A"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("XOR", -1); + Port("A"); + Port("B"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("XNOR", -1); + Port("A"); + Port("B"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("XO1", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("X01A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("XA1", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("XA1A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AX1", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AX1A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AX1B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AO1", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AO1A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AO1B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AO1C", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AOI1A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AOI1B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + /* Added by Tim 12/8/99 */ + CellDef("AO3", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("MAJ3", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AO2", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AO2A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AOI2A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AOI2B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA1", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA1A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA1B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA1C", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA3", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA3A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA3B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA2", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA2A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("MX2", -1); + Port("A"); + Port("B"); + Port("S"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("MX2A", -1); + Port("A"); + Port("B"); + Port("S"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("MX2B", -1); + Port("A"); + Port("B"); + Port("S"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("MX2C", -1); + Port("A"); + Port("B"); + Port("S"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("MX4", -1); + Port("D0"); + Port("D1"); + Port("D2"); + Port("D3"); + Port("S1"); + Port("S0"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("GMX4", -1); + Port("D0"); + Port("D1"); + Port("D2"); + Port("D3"); + Port("G"); + Port("S0"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("MXT", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("S0A"); + Port("S0B"); + Port("S1"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("HA1", -1); + Port("A"); + Port("B"); + Port("CO"); + Port("S"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("HA1A", -1); + Port("A"); + Port("B"); + Port("CO"); + Port("S"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("HA1B", -1); + Port("A"); + Port("B"); + Port("CO"); + Port("S"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("HA1C", -1); + Port("A"); + Port("B"); + Port("CO"); + Port("S"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("FA1A", -1); + Port("A"); + Port("B"); + Port("CI"); + Port("CO"); + Port("S"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("FA1B", -1); + Port("A"); + Port("B"); + Port("CI"); + Port("CO"); + Port("S"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("FA2A", -1); + Port("A0"); + Port("A1"); + Port("B"); + Port("CI"); + Port("CO"); + Port("S"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DL1", -1); + Port("D"); + Port("G"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DL1A", -1); + Port("D"); + Port("G"); + Port("QN"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DL1B", -1); + Port("D"); + Port("G"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DL1C", -1); + Port("D"); + Port("G"); + Port("QN"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DLC", -1); + Port("D"); + Port("G"); + Port("Q"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DLCA", -1); + Port("D"); + Port("G"); + Port("Q"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DLE", -1); + Port("D"); + Port("G"); + Port("Q"); + Port("E"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DLEA", -1); + Port("D"); + Port("G"); + Port("Q"); + Port("E"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DLEB", -1); + Port("D"); + Port("G"); + Port("Q"); + Port("E"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DLEC", -1); + Port("D"); + Port("G"); + Port("Q"); + Port("E"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DLM", -1); + Port("A"); + Port("B"); + Port("S"); + Port("G"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DLMA", -1); + Port("A"); + Port("B"); + Port("S"); + Port("G"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("JKF", -1); + Port("J"); + Port("K"); + Port("CLK"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("JKFPC", -1); + Port("J"); + Port("K"); + Port("CLK"); + Port("Q"); + Port("PRE"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("TFC", -1); + Port("T"); + Port("CLK"); + Port("Q"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFM", -1); + Port("A"); + Port("B"); + Port("S"); + Port("CLK"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFMA", -1); + Port("A"); + Port("B"); + Port("S"); + Port("CLK"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFMB", -1); + Port("A"); + Port("B"); + Port("S"); + Port("CLK"); + Port("Q"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DF1", -1); + Port("D"); + Port("CLK"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DF1A", -1); + Port("D"); + Port("CLK"); + Port("QN"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DF1B", -1); + Port("D"); + Port("CLK"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DF1C", -1); + Port("D"); + Port("CLK"); + Port("QN"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFC1", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFC1A", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFC1B", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFC1C", -1); + Port("D"); + Port("CLK"); + Port("QN"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFC1D", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFC1E", -1); + Port("D"); + Port("CLK"); + Port("QN"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFC1F", -1); + Port("D"); + Port("CLK"); + Port("QN"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFC1G", -1); + Port("D"); + Port("CLK"); + Port("QN"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFP1", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFP1A", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFP1B", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFP1C", -1); + Port("D"); + Port("CLK"); + Port("QN"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFP1D", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFP1E", -1); + Port("D"); + Port("CLK"); + Port("QN"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFP1F", -1); + Port("D"); + Port("CLK"); + Port("QN"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFP1G", -1); + Port("D"); + Port("CLK"); + Port("QN"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFPC", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("CLR"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFPCA", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("CLR"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFE", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("E"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFEA", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("E"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFEB", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("E"); + Port("CLR"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFEC", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("E"); + Port("CLR"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFED", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("E"); + SetClass(CLASS_MODULE); + EndCell(); + + Debug = OldDebug; + + actel_lib_present = 1; +} + + diff --git a/base/anneal.c b/base/anneal.c new file mode 100644 index 0000000..b2ef531 --- /dev/null +++ b/base/anneal.c @@ -0,0 +1,257 @@ +/* + NETGEN -- Copyright 1989, Massimo A. Sivilotti, Caltech +*/ + +#include "config.h" + +#include +#include + +#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); +} + diff --git a/base/bottomup.c b/base/bottomup.c new file mode 100644 index 0000000..8eba883 --- /dev/null +++ b/base/bottomup.c @@ -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 + +#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(); +} + diff --git a/base/ccode.c b/base/ccode.c new file mode 100644 index 0000000..257e974 --- /dev/null +++ b/base/ccode.c @@ -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 +#include + +#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); +} + + + + diff --git a/base/config.h b/base/config.h new file mode 100644 index 0000000..dd58aa2 --- /dev/null +++ b/base/config.h @@ -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 +#else +#include +#ifndef IBMPC +#include +#endif +#endif + +#ifdef HAVE_MALLINFO +#include +#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 +#include +#include + + +#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 */ +#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 + #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 */ diff --git a/base/dbug.h b/base/dbug.h new file mode 100644 index 0000000..21f2a70 --- /dev/null +++ b/base/dbug.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_ 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 diff --git a/base/embed.c b/base/embed.c new file mode 100644 index 0000000..d2d8bb2 --- /dev/null +++ b/base/embed.c @@ -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 +#ifdef IBMPC +#include +#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"); + } +} + + + + diff --git a/base/embed.h b/base/embed.h new file mode 100644 index 0000000..8e156f1 --- /dev/null +++ b/base/embed.h @@ -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<(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); diff --git a/base/ext.c b/base/ext.c new file mode 100644 index 0000000..c440db7 --- /dev/null +++ b/base/ext.c @@ -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 +#include /* for strtod() */ +#include + +#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; +} diff --git a/base/flatten.c b/base/flatten.c new file mode 100644 index 0000000..529e748 --- /dev/null +++ b/base/flatten.c @@ -0,0 +1,1634 @@ +/* "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. */ + + +/* flatten.c -- flatten hierarchical netlists, either totally, or + just particular classes of subcells +*/ + +#include "config.h" + +#include + +#ifdef IBMPC +#include +#endif + +#ifdef TCL_NETGEN +#include +#endif + +#include "netgen.h" +#include "hash.h" +#include "objlist.h" +#include "print.h" +#include "netcmp.h" + +#define OLDPREFIX 1 + +void flattenCell(char *name, int file) +{ + struct objlist *ParentParams; + struct objlist *NextObj; + struct objlist *ChildObjList; + struct nlist *ThisCell; + struct nlist *ChildCell; + struct objlist *tmp, *ob2, *ob3; + int notdone, rnodenum; + char tmpstr[200]; + int nextnode, oldmax; +#if !OLDPREFIX + int prefixlength; +#endif + + if (Debug) + Printf("Flattening cell: %s\n", name); + if (file == -1) + ThisCell = LookupCell(name); + else + ThisCell = LookupCellFile(name, file); + if (ThisCell == NULL) { + Printf("No cell %s found.\n", name); + return; + } + FreeNodeNames(ThisCell); + + ParentParams = ThisCell->cell; + nextnode = 0; + for (tmp = ParentParams; tmp != NULL; tmp = tmp->next) + if (tmp->node >= nextnode) nextnode = tmp->node + 1; + + notdone = 1; + while (notdone) { + notdone = 0; + for (ParentParams = ThisCell->cell; ParentParams != NULL; + ParentParams = NextObj) { + if (Debug) Printf("Parent = %s, type = %d\n", + ParentParams->name, ParentParams->type); + NextObj = ParentParams->next; + if (ParentParams->type != FIRSTPIN) continue; + ChildCell = LookupCellFile(ParentParams->model.class, ThisCell->file); + if (Debug) Printf(" Flattening instance: %s, primitive = %s\n", + ParentParams->name, (ChildCell->class == CLASS_SUBCKT) ? + "no" : "yes"); + if (ChildCell->class != CLASS_SUBCKT) continue; + if (ChildCell == ThisCell) continue; // Avoid infinite loop + + /* not primitive, so need to flatten this instance */ + notdone = 1; + /* if this is a new instance, flatten it */ + if (ChildCell->dumped == 0) flattenCell(ParentParams->model.class, + ChildCell->file); + + ChildObjList = CopyObjList(ChildCell->cell); + + /* update node numbers in child to unique numbers */ + oldmax = 0; + for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next) + if (tmp->node > oldmax) oldmax = tmp->node; + if (nextnode <= oldmax) nextnode = oldmax + 1; + + for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next) + if (tmp->node <= oldmax && tmp->node != -1) { + UpdateNodeNumbers(ChildObjList, tmp->node, nextnode); + nextnode ++; + } + + /* copy nodenumbers of ports from parent */ + ob2 = ParentParams; + for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next) + if (IsPort(tmp)) { + if (tmp->node != -1) { + if (Debug) + Printf(" Sealing port: %d to node %d\n", tmp->node, ob2->node); + UpdateNodeNumbers(ChildObjList, tmp->node, ob2->node); + } + + /* in pathological cases, the lengths of the port lists may + change. This is an error, but that is no reason to allow + the code to core dump. We avoid this by placing a + superfluous check on ob2->type + */ + + if (ob2 != NULL) + ob2 = ob2->next; + } + + + /* delete all port elements from child */ + while (IsPort(ChildObjList)) { + /* delete all ports at beginning of list */ + if (Debug) Printf("deleting leading port from child\n"); + tmp = ChildObjList->next; + FreeObjectAndHash(ChildObjList, ChildCell); + ChildObjList = tmp; + } + tmp = ChildObjList; + while (tmp->next != NULL) { + if (IsPort(tmp->next)) { + ob2 = (tmp->next)->next; + if (Debug) Printf("deleting a port from child\n"); + FreeObjectAndHash(tmp->next, ChildCell); + tmp->next = ob2; + } + else tmp = tmp->next; + } + + /* for each element in child, prepend 'prefix' */ +#if !OLDPREFIX + /* replaces all the sprintf's below */ + strcpy(tmpstr,ParentParams->instance.name); + strcat(tmpstr,SEPARATOR); + prefixlength = strlen(tmpstr); +#endif + for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next) { + if (tmp->type == PROPERTY) continue; + else if (IsGlobal(tmp)) { + /* Keep the name but search for node of same name in parent */ + /* and replace the node number, if found. */ + + for (ob2 = ThisCell->cell; ob2 != NULL; ob2 = ob2->next) { + if (ob2->type == tmp->type) { + if ((*matchfunc)(tmp->name, ob2->name)) { + if (ob2->node >= 0) { + // Replace all child objects with this node number + rnodenum = tmp->node; + for (ob3 = ChildObjList; ob3 != NULL; ob3 = ob3->next) { + if (ob3->node == rnodenum) + ob3->node = ob2->node; + } + break; + } + } + } + } + HashPtrInstall(tmp->name, tmp, ThisCell->objtab, OBJHASHSIZE); + continue; + } + +#if OLDPREFIX + sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR, + tmp->name); +#else + strcpy(tmpstr+prefixlength,tmp->name); +#endif + if (Debug) Printf("Renaming %s to %s\n", tmp->name, tmpstr); + FreeString(tmp->name); + tmp->name = strsave(tmpstr); +#if OLDPREFIX + sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR, + tmp->instance.name); +#else + strcpy(tmpstr+prefixlength,tmp->instance.name); +#endif + FreeString(tmp->instance.name); + tmp->instance.name = strsave(tmpstr); + HashPtrInstall(tmp->name, tmp, ThisCell->objtab, OBJHASHSIZE); + if (tmp->type == FIRSTPIN) + HashPtrInstall(tmp->instance.name, tmp, ThisCell->insttab, OBJHASHSIZE); + } + + /* splice instance out of parent */ + if (ParentParams == ThisCell->cell) { + /* ParentParams are the very first thing in the list */ + ThisCell->cell = ChildObjList; + for (ob2 = ChildObjList; ob2->next != NULL; ob2 = ob2->next) ; + } + else { + /* find ParentParams in ThisCell list */ + for (ob2 = ThisCell->cell; ob2->next != ParentParams; ob2=ob2->next); + for (ob2->next = ChildObjList; ob2->next != NULL; ob2 = ob2->next) ; + } + /* now, ob2 is last element in child list, so skip and reclaim parent */ + tmp = ParentParams; + do { + tmp = tmp->next; + } while ((tmp != NULL) && (tmp->type > FIRSTPIN)); + ob2->next = tmp; + while (ParentParams != tmp) { + ob2 = ParentParams->next; + + /* ParentParams are PORTS */ + FreeObjectAndHash(ParentParams, ThisCell); + ParentParams = ob2; + } + NextObj = ParentParams; + } /* repeat until no more instances found */ + } + CacheNodeNames(ThisCell); + ThisCell->dumped = 1; /* indicate cell has been flattened */ +} + +/*--------------------------------------------------------------*/ +/* flattenInstancesOf -- */ +/* */ +/* Causes all instances of 'instance' within cell 'name' to be */ +/* flattened. For the purpose of on-the-fly flattening of .ext */ +/* files as they are read in, "name" can be NULL, in which case */ +/* CurrentCell (global variable) is taken as the parent. */ +/* */ +/* NOTE: do not flatten 'instance' itself !! */ +/* Return the number of instances flattened. */ +/*--------------------------------------------------------------*/ + +int flattenInstancesOf(char *name, int fnum, char *instance) +{ + struct objlist *ParentParams; + struct objlist *NextObj; + struct objlist *ChildObjList; + struct nlist *ThisCell; + struct nlist *ChildCell; + struct objlist *tmp, *ob2, *ob3; + int notdone, rnodenum; + char tmpstr[200]; + int nextnode, oldmax, numflat = 0; +#if !OLDPREFIX + int prefixlength; +#endif + + if (name == NULL) { + if (CurrentCell == NULL) { + Printf("Error: no current cell.\n"); + return 0; + } + else + ThisCell = CurrentCell; + } + else { + if (Debug) + Printf("Flattening instances of %s within cell: %s\n", instance, name); + if (fnum == -1) + ThisCell = LookupCell(name); + else + ThisCell = LookupCellFile(name, fnum); + if (ThisCell == NULL) { + Printf("No cell %s found.\n", name); + return 0; + } + } + FreeNodeNames(ThisCell); + + ParentParams = ThisCell->cell; + nextnode = 0; + for (tmp = ParentParams; tmp != NULL; tmp = tmp->next) + if (tmp->node >= nextnode) nextnode = tmp->node + 1; + + notdone = 1; + while (notdone) { + notdone = 0; + ParentParams = ThisCell->cell; + for (ParentParams = ThisCell->cell; ParentParams != NULL; + ParentParams = NextObj) { + if (Debug) Printf("Parent = %s, type = %d\n", + ParentParams->name, ParentParams->type); + NextObj = ParentParams->next; + if (ParentParams->type != FIRSTPIN) continue; + if (!(*matchfunc)(ParentParams->model.class, instance)) continue; + + ChildCell = LookupCellFile(ParentParams->model.class, ThisCell->file); + if (Debug) + Printf(" Flattening instance: %s, primitive = %s\n", + ParentParams->instance.name, (ChildCell->class == + CLASS_SUBCKT) ? "no" : "yes"); + if (ChildCell->class != CLASS_SUBCKT) continue; + if (ChildCell == ThisCell) continue; // Avoid infinite loop + + /* not primitive, so need to flatten this instance */ + notdone = 1; + /* if this is a new instance, flatten it */ + /* if (ChildCell->dumped == 0) flattenCell(ParentParams->model.class, file); */ + + ChildObjList = CopyObjList(ChildCell->cell); + numflat++; + + /* update node numbers in child to unique numbers */ + oldmax = 0; + for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next) + if (tmp->node > oldmax) oldmax = tmp->node; + if (nextnode <= oldmax) nextnode = oldmax + 1; + + for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next) + if (tmp->node <= oldmax && tmp->node > 0) { + if (Debug) Printf("Update node %d --> %d\n", tmp->node, nextnode); + UpdateNodeNumbers(ChildObjList, tmp->node, nextnode); + nextnode++; + } + + /* copy nodenumbers of ports from parent */ + ob2 = ParentParams; + for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next) + if (IsPort(tmp)) { + if (tmp->node > 0) { + if (ob2->node == -1) { + + // Before commiting to attaching to a unconnected node, see + // if there is another node in ParentParams with the same + // name and a valid node number. If so, connect them. In + // the broader case, it may be necessary to consider all + // nodes, not just those with node == -1, and call join() + // here to update all node numbers in the parent cell. + // In that case, a more efficient method is needed for + // tracking same-name ports. + + for (ob3 = ParentParams; ob3 && ob3->type >= FIRSTPIN; ob3 = ob3->next) { + if (ob3 == ob2) continue; + if ((*matchfunc)(ob3->name, ob2->name) && ob3->node != -1) { + ob2->node = ob3->node; + break; + } + } + } + if (Debug) { + // Printf(" Sealing port: %d to node %d\n", tmp->node, ob2->node); + Printf("Update node %d --> %d\n", tmp->node, ob2->node); + } + UpdateNodeNumbers(ChildObjList, tmp->node, ob2->node); + } + + /* in pathological cases, the lengths of the port lists may + change. This is an error, but that is no reason to allow + the code to core dump. We avoid this by placing a + superfluous check on ob2->type + */ + + if (ob2 != NULL) + ob2 = ob2->next; + + if (ob2 == NULL) break; + } + + /* Using name == NULL to indicate that a .ext file is being */ + /* flattened on the fly. This is quick & dirty. */ + + if (name != NULL) { + /* delete all port elements from child */ + while ((ChildObjList != NULL) && IsPort(ChildObjList)) { + /* delete all ports at beginning of list */ + if (Debug) Printf("deleting leading port from child\n"); + tmp = ChildObjList->next; + FreeObjectAndHash(ChildObjList, ChildCell); + ChildObjList = tmp; + } + tmp = ChildObjList; + while (tmp && (tmp->next != NULL)) { + if (IsPort(tmp->next)) { + ob2 = (tmp->next)->next; + if (Debug) Printf("deleting a port from child\n"); + FreeObjectAndHash(tmp->next, ChildCell); + tmp->next = ob2; + } + else tmp = tmp->next; + } + } + + /* for each element in child, prepend 'prefix' */ +#if !OLDPREFIX + /* replaces all the sprintf's below */ + strcpy(tmpstr,ParentParams->instance.name); + strcat(tmpstr,SEPARATOR); + prefixlength = strlen(tmpstr); +#endif + for (tmp = ChildObjList; tmp != NULL; tmp = tmp->next) { + if (tmp->type == PROPERTY) continue; + else if (IsGlobal(tmp)) { + /* Keep the name but search for node of same name in parent */ + /* and replace the node number, if found. */ + + for (ob2 = ThisCell->cell; ob2 != NULL; ob2 = ob2->next) { + /* Type in parent may be a port, not a global */ + if (ob2->type == tmp->type || ob2->type == PORT) { + if ((*matchfunc)(tmp->name, ob2->name)) { + if (ob2->node >= 0) { + // Replace all child objects with this node number + rnodenum = tmp->node; + for (ob3 = ChildObjList; ob3 != NULL; ob3 = ob3->next) { + if (ob3->node == rnodenum) + ob3->node = ob2->node; + } + break; + } + } + } + } + // Don't hash this if the parent had a port of this name + if (!ob2 || ob2->type != PORT) + HashPtrInstall(tmp->name, tmp, ThisCell->objtab, OBJHASHSIZE); + continue; + } + +#if OLDPREFIX + sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR, + tmp->name); +#else + strcpy(tmpstr+prefixlength,tmp->name); +#endif + if (Debug) Printf("Renaming %s to %s\n", tmp->name, tmpstr); + FreeString(tmp->name); + tmp->name = strsave(tmpstr); +#if OLDPREFIX + sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR, + tmp->instance.name); +#else + strcpy(tmpstr+prefixlength,tmp->instance.name); +#endif + FreeString(tmp->instance.name); + tmp->instance.name = strsave(tmpstr); + HashPtrInstall(tmp->name, tmp, ThisCell->objtab, OBJHASHSIZE); + if (tmp->type == FIRSTPIN) + HashPtrInstall(tmp->instance.name, tmp, ThisCell->insttab, OBJHASHSIZE); + } + + /* splice instance out of parent */ + if (ParentParams == ThisCell->cell) { + /* ParentParams are the very first thing in the list */ + ThisCell->cell = ChildObjList; + for (ob2 = ChildObjList; ob2 && ob2->next != NULL; ob2 = ob2->next) ; + } + else { + /* find ParentParams in ThisCell list */ + for (ob2 = ThisCell->cell; ob2 && ob2->next != ParentParams; ob2=ob2->next); + if (ob2) + for (ob2->next = ChildObjList; ob2->next != NULL; ob2 = ob2->next) ; + } + /* now, ob2 is last element in child list, so skip and reclaim parent */ + tmp = ParentParams; + do { + tmp = tmp->next; + } while ((tmp != NULL) && (tmp->type > FIRSTPIN)); + if (ob2) ob2->next = tmp; + while (ParentParams != tmp) { + ob2 = ParentParams->next; + FreeObjectAndHash(ParentParams, ThisCell); + ParentParams = ob2; + } + NextObj = ParentParams; + } /* repeat until no more instances found */ + } + CacheNodeNames(ThisCell); + ThisCell->dumped = 1; /* indicate cell has been flattened */ + return numflat; +} + + +void Flatten(char *name, int file) +{ + ClearDumpedList(); /* keep track of flattened cells */ + flattenCell(name, file); +} + + +static char *model_to_flatten; + +int flattenoneentry(struct hashlist *p, int file) +{ + struct nlist *ptr; + + ptr = (struct nlist *)(p->ptr); + if (file == ptr->file) + if (!(*matchfunc)(ptr->name, model_to_flatten) && (ptr->class == CLASS_SUBCKT)) + flattenInstancesOf(ptr->name, file, model_to_flatten); + return(1); +} + + +void FlattenInstancesOf(char *model, int file) +{ + if ((file == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + FlattenInstancesOf(model, Circuit1->file); + FlattenInstancesOf(model, Circuit2->file); + return; + } + ClearDumpedList(); /* keep track of flattened cells */ + model_to_flatten = strsave(model); + RecurseCellFileHashTable(flattenoneentry, file); + FREE(model_to_flatten); +} + +/* + *----------------------------------------------------------- + * convertGlobalsOf --- + * + * Called once for each cell that instantiates one or + * more cells "model_to_flatten" (global variable). A + * global variable has just been added to the front of + * the cell's master pin list. Get the global variable + * name. Find it in the parent cell or else create it + * if it does not exist. Add the new node to the pin + * list for each instance call. + * + *----------------------------------------------------------- + */ + +void convertGlobalsOf(char *name, int fnum, char *instance) +{ + struct objlist *ParentParams; + struct objlist *ChildOb, *Ob2, *Ob; + struct objlist *newpin, *newnode, *snode, *lnode; + struct nlist *ThisCell; + struct nlist *ChildCell; + int maxnode, maxpin; + + if (name == NULL) { + if (CurrentCell == NULL) { + Printf("Error: no current cell.\n"); + return; + } + else + ThisCell = CurrentCell; + } + else { + if (fnum == -1) + ThisCell = LookupCell(name); + else + ThisCell = LookupCellFile(name, fnum); + if (ThisCell == NULL) { + Printf("No cell %s found.\n", name); + return; + } + } + + FreeNodeNames(ThisCell); + + for (ParentParams = ThisCell->cell; ParentParams != NULL; + ParentParams = ParentParams->next) { + if (ParentParams->type != FIRSTPIN) continue; + if (!(*matchfunc)(ParentParams->model.class, instance)) continue; + + // Move forward to last pin in the pin list. The "type" record + // holds the pin numbering, so we want to find the maximum pin + // number and keep going from there. + + maxpin = 0; + while (ParentParams->next != NULL) { + if (ParentParams->type >= maxpin) maxpin = ParentParams->type + 1; + if (ParentParams->next->type < FIRSTPIN) break; + else if (!(*matchfunc)(ParentParams->instance.name, + ParentParams->next->instance.name)) + break; + ParentParams = ParentParams->next; + } + if (ParentParams->type >= maxpin) maxpin = ParentParams->type + 1; + + ChildCell = LookupCellFile(ParentParams->model.class, ThisCell->file); + ChildOb = ChildCell->cell; + + // The node to make local will be the last pin in the child + while (IsPort(ChildOb) && ChildOb->next != NULL + && IsPort(ChildOb->next)) + ChildOb = ChildOb->next; + + newpin = GetObject(); + if (newpin == NULL) return; /* Memory allocation error */ + + newpin->next = ParentParams->next; + ParentParams->next = newpin; + newpin->instance.name = (ParentParams->instance.name) ? + strsave(ParentParams->instance.name) : NULL; + newpin->name = (char *)MALLOC(strlen(newpin->instance.name) + + strlen(ChildOb->name) + 2); + sprintf(newpin->name, "%s/%s", newpin->instance.name, ChildOb->name); + newpin->model.class = strsave(ParentParams->model.class); + newpin->type = maxpin; + newpin->node = 0; /* placeholder */ + + // Find the next valid unused node number + + maxnode = -1; + for (Ob2 = ThisCell->cell; Ob2 != NULL; Ob2 = Ob2->next) + if (Ob2->node >= maxnode) maxnode = Ob2->node + 1; + + // Does the global node exist in the parent? Note that + // the node may have been declared as a port in the parent, + // which is fine; we just don't create a new node in the + // parent for it. + + for (Ob2 = ThisCell->cell; Ob2 != NULL; Ob2 = Ob2->next) { + if (IsGlobal(Ob2) || IsPort(Ob2)) + if ((*matchfunc)(Ob2->name, ChildOb->name)) { + // This node may never have been used in the parent. If + // so, give it a valid node number in the parent. + if (Ob2->node == -1) Ob2->node = maxnode; + newpin->node = Ob2->node; + break; + } + } + if (Ob2 == NULL) { // No such node; create it + newnode = GetObject(); + + // Place the node after the pin list of the parent cell. + lnode = NULL; + for (snode = ThisCell->cell; snode && IsPort(snode); + snode = snode->next) + lnode = snode; + if (lnode == NULL) { + newnode->next = ThisCell->cell; + ThisCell->cell = newnode; + } + else { + newnode->next = lnode->next; + lnode->next = newnode; + } + newnode->type = GLOBAL; + newnode->node = maxnode; + newnode->name = (ChildOb->name) ? strsave(ChildOb->name) : NULL; + // newnode->instance.name = (ParentParams->instance.name) ? + // strsave(ParentParams->instance.name) : NULL; + // newnode->model.class = strsave(ParentParams->model.class); + newnode->instance.name = NULL; + newnode->model.class = NULL; + newpin->node = maxnode; + HashPtrInstall(newnode->name, newnode, ThisCell->objtab, OBJHASHSIZE); + } + + // Remove any references to the net as a GLOBAL type in the instance + + /* + Ob2 = ParentParams; + for (Ob = ParentParams->next; Ob != NULL && Ob->type != FIRSTPIN;) { + if (IsGlobal(Ob)) { + Ob2->next = Ob->next; + FreeObjectAndHash(Ob, ThisCell); + Ob = Ob2->next; + } + else { + Ob2 = Ob; + Ob = Ob->next; + } + } + */ + + // Now there should be only one object of this name in the instance, + // which is the pin, and we will set the hash table to point to it. + + HashPtrInstall(newpin->name, newpin, ThisCell->objtab, OBJHASHSIZE); + + } + CacheNodeNames(ThisCell); +} + +/* + *----------------------------------------------------------- + * convertglobals --- + * + * Routine to search database for cells that instantiate + * cell "model_to_flatten". For each cell, call the routine + * convertGlobalsOf(). Do not call convertGlobalsOf() on + * self, and only call convertGlobalsOf() on cells in the + * same file. + * + *----------------------------------------------------------- + */ + +int convertglobals(struct hashlist *p, int file) +{ + struct nlist *ptr; + + ptr = (struct nlist *)(p->ptr); + if (file == ptr->file) + if (!(*matchfunc)(ptr->name, model_to_flatten)) + convertGlobalsOf(ptr->name, file, model_to_flatten); + return 1; +} + +/* + *----------------------------------------------------------- + * ConvertGlobals --- + * + * Remove global node references in a subcircuit by changing + * them to local nodes and adding a port. Check all parent + * cells, adding the global node if it does not exist, and + * connecting it to the port of the instance. + * + *----------------------------------------------------------- + */ + +void ConvertGlobals(char *name, int filenum) +{ + struct nlist *ThisCell; + struct objlist *ObjList, *Ob2, *NewObj; + int globalnet, result; + + if (Debug) + Printf("Converting globals in circuit: %s\n", name); + + if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + ConvertGlobals(name, Circuit1->file); + ConvertGlobals(name, Circuit2->file); + return; + } + + ThisCell = LookupCellFile(name, filenum); + + if (ThisCell == NULL) { + Printf("No circuit %s found.\n", name); + return; + } + + /* First check if this object has any ports. If not, it is a top- */ + /* level cell, and we do not need to process global nodes. */ + + for (ObjList = ThisCell->cell; ObjList != NULL; ObjList = ObjList->next) { + if (IsPort(ObjList)) + break; + else + return; + } + + /* Remove the cached node names, because we are changing them */ + FreeNodeNames(ThisCell); + + for (ObjList = ThisCell->cell; ObjList != NULL; ObjList = ObjList->next) { + if (IsGlobal(ObjList)) { + globalnet = ObjList->node; + + /* Make sure this node is not in the port list already */ + for (Ob2 = ThisCell->cell; Ob2 != NULL; Ob2 = Ob2->next) { + if (Ob2->type != PORT) break; + if (Ob2->node == globalnet) break; + } + if (Ob2 != NULL && IsPort(Ob2) && Ob2->node == globalnet) + continue; + + /* Add this node to the cell as a port */ + NewObj = GetObject(); + if (NewObj == NULL) return; /* Memory allocation error */ + + /* Find the last port and add the new net to the end */ + for (Ob2 = ThisCell->cell; Ob2 != NULL; Ob2 = Ob2->next) + if (IsPort(Ob2) && (Ob2->next == NULL || !IsPort(Ob2->next))) + break; + + if (Ob2 == NULL) { + NewObj->next = ThisCell->cell; + ThisCell->cell = NewObj; + } + else { + NewObj->next = Ob2->next; + Ob2->next = NewObj; + } + NewObj->type = PORT; + NewObj->node = globalnet; + NewObj->model.port = -1; + NewObj->instance.name = (ObjList->instance.name) ? + strsave(ObjList->instance.name) : NULL; + NewObj->name = (ObjList->name) ? strsave(ObjList->name) : NULL; + + HashPtrInstall(NewObj->name, NewObj, ThisCell->objtab, OBJHASHSIZE); + + /* Find all parent cells of this cell. Find the global node */ + /* if it exists or create it if it doesn't. Add the node to */ + /* the beginning of the list of pins for this device. */ + + ClearDumpedList(); /* keep track of flattened cells */ + model_to_flatten = strsave(name); + RecurseCellFileHashTable(convertglobals, filenum); + FREE(model_to_flatten); + } + } + + /* Now remove all global nodes from the cell. */ + /* Do not remove the hash entry, because we still have a */ + /* node (a pin) of the same name, and have reassigned the */ + /* hash table value to it. */ + + Ob2 = NULL; + for (ObjList = ThisCell->cell; ObjList != NULL;) { + if (IsGlobal(ObjList)) { + if (Ob2 == NULL) + ThisCell->cell = ObjList->next; + else + Ob2->next = ObjList->next; + + FreeObject(ObjList); /* not FreeObjectAndHash(), see above */ + + if (Ob2 == NULL) + ObjList = ThisCell->cell; + else + ObjList = Ob2->next; + } + else { + Ob2 = ObjList; + ObjList = ObjList->next; + } + } + + /* Regenerate the node name cache */ + CacheNodeNames(ThisCell); +} + +/*------------------------------------------------------*/ +/* Callback function for UniquePins */ +/*------------------------------------------------------*/ + +struct nlist *uniquepins(struct hashlist *p, void *clientdata) +{ + struct nlist *ptr; + struct objlist *ob, *tob, *ob2, *lob, *nob; + struct objlist *sob, *firstpin, *saveob; + struct nlist *tc = (struct nlist *)clientdata; + int refnode, i; + int modified = 0; + + ptr = (struct nlist *)(p->ptr); + if (tc->file == ptr->file) { + + /* Find each instance of cell tc used in cell ptr */ + + lob = NULL; + ob = ptr->cell; + while (ob != NULL) { + while (ob && ob->type != FIRSTPIN) { + lob = ob; + ob = ob->next; + } + if (ob && ob->model.class != NULL) { + firstpin = ob; + if (!(*matchfunc)(ob->model.class, tc->name)) { + lob = ob; + ob = ob->next; + continue; + } + } + if (ob == NULL) break; + + /* 1st pass---resolve node numbers in pin list */ + + tob = tc->cell; + ob = firstpin; + for (ob = firstpin; ob->type >= FIRSTPIN && ob->model.class != NULL; + ob = ob->next) { + if (tob->type == UNKNOWN) { + + /* If net is different from the net of the first */ + /* such pin, then merge the nets in cell tc. */ + + if (tob->model.port == FIRSTPIN) { + saveob = firstpin; + refnode = firstpin->node; + } + else { + i = FIRSTPIN + 1; + for (sob = firstpin->next; sob && sob->type > FIRSTPIN; + sob = sob->next) { + if (tob->model.port == i) { + saveob = sob; + refnode = sob->node; + break; + } + i++; + } + } + if (ob->node != refnode) { + if (refnode == -1) { + refnode = ob->node; + saveob->node = refnode; + } + else if (ob->node != -1) { + for (sob = ptr->cell; sob != NULL; sob = sob->next) + if (sob->node == ob->node) + sob->node = refnode; + } + } + modified = 1; + + // Check if the node we're about to remove is in the + // objtab hash table; if so, replace it with the one + // that we are going to keep. + + if (LookupObject(ob->name, ptr) == ob) { + HashPtrInstall(ob->name, saveob, ptr->objtab, OBJHASHSIZE); + } + } + tob = tob->next; + if (tob->type != PORT && tob->type != UNKNOWN) break; + } + + /* 2nd pass---remove the pins */ + + tob = tc->cell; + ob = firstpin; + while (ob->type >= FIRSTPIN && ob->model.class != NULL) { + if (tob->type == UNKNOWN) { + + // lob cannot be NULL here by definition; if there + // are duplicate pins, the first is kept, so the first + // pin is never removed. + + lob->next = ob->next; + FREE(ob->name); + if (ob->instance.name != NULL) + FREE(ob->instance.name); + FREE(ob); + ob = lob->next; + } + else { + lob = ob; + ob = ob->next; + } + tob = tob->next; + if (tob->type != PORT && tob->type != UNKNOWN) break; + } + + // Renumber the pins in order. Since when removing duplicates, the + // first entry is always kept, the first pin is never changed, so + // the insttab record is never corrupted. + + i = FIRSTPIN; + firstpin->type = i++; + for (sob = firstpin->next; sob && sob->type > FIRSTPIN; sob = sob->next) { + sob->type = i++; + } + } + } + if (modified) CacheNodeNames(ptr); + + return NULL; +} + +/*------------------------------------------------------*/ +/* Check a subcircuit for duplicate pins. If found, */ +/* remove the duplicate entry or entries, and merge */ +/* nets in all parent cells. Duplicate pins are */ +/* determined by net number, not by name. */ +/* */ +/* This routine must be run after CleanupPins(), */ +/* otherwise the unique pin may be left with no node */ +/* number. */ +/* */ +/* Return 0 if nothing was modified, 1 otherwise. */ +/*------------------------------------------------------*/ + +int UniquePins(char *name, int filenum) +{ + struct nlist *ThisCell; + struct objlist *ob, *lob, **firstport; + int maxnode, *nodecount, *firstpin, portcount; + int haspins = 0; + int needscleanup = 0; + + if (filenum == -1) + ThisCell = LookupCell(name); + else + ThisCell = LookupCellFile(name, filenum); + + if (ThisCell == NULL) { + Printf("No cell %s found.\n", name); + return 0; + } + + maxnode = 0; + for (ob = ThisCell->cell; ob != NULL; ob = ob->next) { + if (ob->type != PORT) break; + haspins = 1; + if (ob->node > maxnode) maxnode = ob->node; + } + if (haspins == 0) return 0; + + nodecount = (int *)CALLOC(maxnode + 1, sizeof(int)); + firstpin = (int *)CALLOC(maxnode + 1, sizeof(int)); + firstport = (struct objlist **)CALLOC(maxnode + 1, sizeof(struct objlist *)); + + portcount = FIRSTPIN; + for (ob = ThisCell->cell; ob != NULL; ob = ob->next) { + if (ob->type != PORT) break; + if (ob->node > 0) { + nodecount[ob->node]++; + if (nodecount[ob->node] == 2) { + Printf("Duplicate pin %s in cell %s\n", ob->name, ThisCell->name); + } + if (nodecount[ob->node] > 1) { + /* Remove this node; prep for removal by marking with UNKNOWN */ + ob->type = UNKNOWN; + /* Replace port number with first port number used */ + ob->model.port = firstpin[ob->node]; + needscleanup = 1; + } + else { + firstpin[ob->node] = portcount; + firstport[ob->node] = ob; + } + } + portcount++; + } + + if (needscleanup) + RecurseCellHashTable2(uniquepins, (void *)ThisCell); + + /* Remove all entries marked UNKNOWN */ + + lob = NULL; + for (ob = ThisCell->cell; ob != NULL; ) { + if (ob->type == UNKNOWN) { + struct objlist *testob; + + testob = LookupObject(ob->name, ThisCell); + if (testob == ob) { + // The hash table is pointing at the cell we are + // about to delete. Hash the one we're keeping instead. + + HashPtrInstall(ob->name, firstport[ob->node], + ThisCell->objtab, OBJHASHSIZE); + } + + if (lob == NULL) { + ThisCell->cell = ob->next; + if (ob->instance.name != NULL) + FREE(ob->instance.name); + FREE(ob); + ob = ThisCell->cell; + } + else { + lob->next = ob->next; + if (ob->instance.name != NULL) + FREE(ob->instance.name); + FREE(ob); + ob = lob->next; + } + } + else { + if (ob->type != PORT) break; + lob = ob; + ob = ob->next; + } + } + + if (needscleanup) CacheNodeNames(ThisCell); + + FREE(nodecount); + FREE(firstpin); + FREE(firstport); + return 1; +} + +/*------------------------------------------------------*/ +/* Callback function for CleanupPins */ +/* Note that if the first pin of the instance is a */ +/* disconnected node, then removing it invalidates the */ +/* insttab hash. */ +/*------------------------------------------------------*/ + +struct nlist *cleanuppins(struct hashlist *p, void *clientdata) +{ + struct nlist *ptr; + struct objlist *ob, *obt, *lob, *nob, *firstpin; + struct nlist *tc = (struct nlist *)clientdata; + int pinnum; + + ptr = (struct nlist *)(p->ptr); + if (tc->file != ptr->file) return NULL; + + /* Find each instance of cell tc used in cell ptr */ + + lob = NULL; + for (ob = ptr->cell; ob != NULL; ) { + while (ob && ob->type != FIRSTPIN) { + lob = ob; + ob = ob->next; + } + if (ob && ob->model.class != NULL) { + if (!(*matchfunc)(ob->model.class, tc->name)) { + lob = ob; + ob = ob->next; + continue; + } + if (ob == NULL) break; + + firstpin = ob; + pinnum = FIRSTPIN; + obt = tc->cell; + + while (ob && obt && (ob->type > FIRSTPIN || ob == firstpin) && + ob->model.class != NULL) { + nob = ob->next; + if ((obt->type == PORT) && (obt->node == -1)) { + + /* Remove this pin */ + + if (ob == firstpin) firstpin = nob; + + if (lob == NULL) { + ptr->cell = ob->next; + } + else { + lob->next = ob->next; + } + + // Check if the node we're about to remove is in the + // objtab hash table + if (LookupObject(ob->name, ptr) == ob) { + HashDelete(ob->name, ptr->objtab, OBJHASHSIZE); + } + + FREE(ob->name); + if (ob->instance.name != NULL) FREE(ob->instance.name); + if (ob->model.class != NULL) FREE(ob->model.class); + FREE(ob); + } + else { + lob = ob; + ob->type = pinnum++; // Renumber pins in order + } + ob = nob; + obt = obt->next; + } + + /* Rehash the insttab, in case the first pin got removed */ + if (firstpin && (firstpin->type == FIRSTPIN)) + HashPtrInstall(firstpin->instance.name, firstpin, ptr->insttab, + OBJHASHSIZE); + } + } + return NULL; /* Keep the search going */ +} + +/*------------------------------------------------------*/ +/* Check a circuit for pins that are not connected to */ +/* any real node, and remove them from the circuit and */ +/* all instances of that circuit. */ +/* */ +/* Return 0 if nothing was modified, 1 otherwise. */ +/*------------------------------------------------------*/ + +int CleanupPins(char *name, int filenum) +{ + struct nlist *ThisCell; + struct objlist *ob, *lob, *nob; + int needscleanup = 0; + + if (filenum == -1) + ThisCell = LookupCell(name); + else + ThisCell = LookupCellFile(name, filenum); + + if (ThisCell == NULL) { + Printf("No cell %s found.\n", name); + return 0; + } + + // Avoid a loop through all cells unless we have to do it. + + for (ob = ThisCell->cell; ob != NULL; ob = ob->next) { + if (ob->type != PORT) break; + if (ob->node == -1) { + needscleanup = 1; + break; + } + } + + if (needscleanup == 0) return 0; + + // If there is only one port in the cell, don't remove it + if (ob && ob == ThisCell->cell && ob->next && ob->next->type != PORT) + return 0; + + // Remove the disconnected nodes from all instances of the cell + + RecurseCellHashTable2(cleanuppins, (void *)ThisCell); + + // Remove the disconnected nodes from cell + + lob = NULL; + for (ob = ThisCell->cell; ob != NULL; ) { + if (ob->type == UNKNOWN) continue; + else if (ob->type != PORT) break; + nob = ob->next; + if (ob->node == -1) { + if (lob == NULL) { + ThisCell->cell = ob->next; + } + else { + lob->next = ob->next; + } + + // Check if the node we're about to remove is in the + // objtab hash table + if (LookupObject(ob->name, ThisCell) == ob) { + HashDelete(ob->name, ThisCell->objtab, OBJHASHSIZE); + } + + FREE(ob->name); + if (ob->instance.name != NULL) + FREE(ob->instance.name); + FREE(ob); + } + else + lob = ob; + ob = nob; + } + return 1; +} + +/*------------------------------------------------------*/ + +typedef struct ecompare { + struct nlist *cell1; + struct nlist *cell2; + int num1, num2; + int add1, add2; + char refcount; +} ECompare; + +/*------------------------------------------------------*/ +/* Survey the contents of a cell and +/*------------------------------------------------------*/ + +void +SurveyCell(struct nlist *tc, struct hashlist **comptab, int file1, int file2, int which) +{ + struct objlist *ob; + struct nlist *tsub, *teq; + ECompare *ecomp, *qcomp, *ncomp; + + for (ob = tc->cell; ob; ob = ob->next) { + if (ob->type == FIRSTPIN) { + tsub = LookupCellFile(ob->model.class, (which == 0) ? file1 : file2); + ecomp = (ECompare *)HashLookup(ob->model.class, comptab, OBJHASHSIZE); + if (ecomp == NULL) { + ncomp = (ECompare *)MALLOC(sizeof(ECompare)); + if (which == 0) { + ncomp->num1 = 1; + ncomp->num2 = 0; + ncomp->cell1 = tsub; + teq = LookupClassEquivalent(ob->model.class, file1, file2); + ncomp->cell2 = teq; + } + else { + ncomp->num1 = 0; + ncomp->num2 = 1; + ncomp->cell2 = tsub; + teq = LookupClassEquivalent(ob->model.class, file2, file1); + ncomp->cell1 = teq; + } + ncomp->add1 = 0; + ncomp->add2 = 0; + ncomp->refcount = (char)1; + + HashPtrInstall(ob->model.class, ncomp, comptab, OBJHASHSIZE); + if (teq != NULL) { + qcomp = (ECompare *)HashLookup(teq->name, comptab, OBJHASHSIZE); + if (qcomp == NULL) { + HashPtrInstall(teq->name, ncomp, comptab, OBJHASHSIZE); + ncomp->refcount++; + } + } + } + else { + if (which == 0) + ecomp->num1++; + else + ecomp->num2++; + } + } + } +} + +/*------------------------------------------------------*/ +/* Create a preliminary matchup of two cells. */ +/* For each type of cell in the instance lists, if */ +/* there is a mismatch between the total count of */ +/* instances, where the instances are subcells, then */ +/* determine whether decomposing the cells into their */ +/* constituent parts one or more times would make the */ +/* lists match better. If so, flatten those cells in */ +/* both parents. */ +/* */ +/* If there is a mismatch between instances of low- */ +/* level devices, determine if the mismatches can be */ +/* resolved by parallel/serial combining, accoring to */ +/* combination rules. */ +/* */ +/* Return the number of modifications made. */ +/*------------------------------------------------------*/ + +int +PrematchLists(char *name1, int file1, char *name2, int file2) +{ + struct nlist *tc1, *tc2, *teq, *tsub1, *tsub2; + struct objlist *ob1, *ob2, *lob; + struct hashlist **comptab; + ECompare *ecomp, *ncomp; + int match, modified = 0; + + if (file1 == -1) + tc1 = LookupCell(name1); + else + tc1 = LookupCellFile(name1, file1); + + if (file2 == -1) + tc2 = LookupCell(name2); + else + tc2 = LookupCellFile(name2, file2); + + if (tc1 == NULL || tc2 == NULL) return; + + comptab = (struct hashlist **)CALLOC(OBJHASHSIZE, + sizeof(struct hashlist *)); + + // Gather information about instances of cell "name1" + SurveyCell(tc1, comptab, file1, file2, 0); + + // Gather information about instances of cell "name2" + SurveyCell(tc2, comptab, file1, file2, 1); + + // Find all instances of one cell that have fewer in + // the compared circuit. Check whether subcircuits + // in the hierarchy of each instance contain devices + // or subcircuits that more in the compared circuit. + + ecomp = (ECompare *)HashFirst(comptab, OBJHASHSIZE); + while (ecomp != NULL) { + if ((ecomp->num1 != ecomp->num2) && (ecomp->cell2 != NULL) && + (ecomp->cell2->class == CLASS_SUBCKT)) { + ecomp->add2 = -ecomp->num2; + ecomp->add1 = -ecomp->num1; + match = 1; + for (ob2 = ecomp->cell2->cell; ob2; ob2 = ob2->next) { + if (ob2->type == FIRSTPIN) { + ncomp = (ECompare *)HashLookup(ob2->model.class, + comptab, OBJHASHSIZE); + if (ncomp != NULL) { + if ((ncomp->num1 > ncomp->num2) && + ((ncomp->add2 + ecomp->num2) >= + (ncomp->add1 + ecomp->num1))) { + ncomp->add2 += ecomp->num2; + ncomp->add1 += ecomp->num1; + } + else if ((ncomp->num1 < ncomp->num2) && + ((ncomp->add2 + ecomp->num2) <= + (ncomp->add1 + ecomp->num1))) { + ncomp->add2 += ecomp->num2; + ncomp->add1 += ecomp->num1; + } + else { + match = 0; + break; + } + } + else { + match = 0; + break; + } + } + } + if (match) { + flattenInstancesOf(name2, file2, ecomp->cell2->name); + flattenInstancesOf(name1, file1, ecomp->cell1->name); + modified++; + } + + /* Reset or apply the count adjustments */ + for (ob2 = ecomp->cell2->cell; ob2; ob2 = ob2->next) { + if (ob2->type == FIRSTPIN) { + ncomp = (ECompare *)HashLookup(ob2->model.class, + comptab, OBJHASHSIZE); + if (ncomp != NULL) { + if (match) { + ncomp->num1 += ncomp->add1; + ncomp->num2 += ncomp->add2; + } + ncomp->add1 = 0; + ncomp->add2 = 0; + } + } + } + if (match) { + ecomp->num1 = 0; + ecomp->num2 = 0; + } + ecomp->add1 = 0; + ecomp->add2 = 0; + } + ecomp = (ECompare *)HashNext(comptab, OBJHASHSIZE); + } + + // Remove non-matching zero-value devices. This can + // be done on a per-instance basis. + + ecomp = (ECompare *)HashFirst(comptab, OBJHASHSIZE); + while (ecomp != NULL) { + if ((ecomp->num1 != ecomp->num2) && (ecomp->cell1 != NULL) && + (ecomp->cell1->class == CLASS_RES)) { + int node1 = -1, node2 = -1; + lob = NULL; + for (ob1 = tc1->cell; ob1; ) { + if (ob1->type == FIRSTPIN) { + tsub1 = LookupCellFile(ob1->model.class, file1); + if (tsub1 == ecomp->cell1) { + node1 = ob1->node; + for (ob1 = ob1->next; ob1 && ob1->type != FIRSTPIN; ) { + if (ob1->type == FIRSTPIN + 1) + node2 = ob1->node; + if (ob1->type == PROPERTY && node1 != -1 && node2 != -1) { + if (ob1->instance.props != NULL) { + struct valuelist *kv; + int i; + int found = 0; + for (i = 0; ; i ++) { + kv = &(ob1->instance.props[i]); + if (kv->type == PROP_ENDLIST) break; + if ((*matchfunc)(kv->key, "value") || + (*matchfunc)(kv->key, "length")) { + switch(kv->type) { + case PROP_STRING: + if ((*matchfunc)(kv->value.string, + "0")) + found = 1; + break; + case PROP_INTEGER: + if (kv->value.ival == 0) + found = 1; + break; + case PROP_DOUBLE: + case PROP_VALUE: + if (kv->value.dval == 0.0) + found = 1; + break; + case PROP_EXPRESSION: + /* Unresolved expression */ + break; + } + } + if (found) break; + } + if (found) { + /* merge node of endpoints */ + for (ob2 = tc1->cell; ob2; ob2 = ob2->next) { + if (ob2->node == node2) + ob2->node = node1; + } + + /* snip, snip. Excise this device */ + if (lob == NULL) { + ob2 = tc1->cell; + tc1->cell = ob1->next; + } + else { + ob2 = lob->next; + lob->next = ob1->next; + } + + /* free the device */ + for (; ob2 && ob2 != ob1->next; ) { + struct objlist *nob; + nob = ob2->next; + FreeObjectAndHash(ob2, tc1); + ob2 = nob; + } + + /* Remove from list */ + ecomp->num1--; + modified++; + + ob1 = lob; + } + else + ob1 = ob1->next; + } + else + ob1 = ob1->next; + } + else + ob1 = ob1->next; + } + } + else { + lob = ob1; + ob1 = ob1->next; + } + } + else { + lob = ob1; + ob1 = ob1->next; + } + } + } + + // Repeat the last section for the other circuit + + if ((ecomp->num1 != ecomp->num2) && (ecomp->cell2 != NULL) && + (ecomp->cell2->class == CLASS_RES)) { + int node1 = -1, node2 = -1; + lob = NULL; + for (ob2 = tc2->cell; ob2; ) { + if (ob2->type == FIRSTPIN) { + tsub2 = LookupCellFile(ob2->model.class, file2); + if (tsub2 == ecomp->cell2) { + node1 = ob2->node; + for (ob2 = ob2->next; ob2 && ob2->type != FIRSTPIN; ) { + if (ob2->type == FIRSTPIN + 1) + node2 = ob2->node; + if (ob2->type == PROPERTY && node1 != -1 && node2 != -1) { + if (ob2->instance.props != NULL) { + struct valuelist *kv; + int i; + int found = 0; + for (i = 0; ; i ++) { + kv = &(ob2->instance.props[i]); + if (kv->type == PROP_ENDLIST) break; + if ((*matchfunc)(kv->key, "value") || + (*matchfunc)(kv->key, "length")) { + switch(kv->type) { + case PROP_STRING: + if ((*matchfunc)(kv->value.string, + "0")) + found = 1; + break; + case PROP_INTEGER: + if (kv->value.ival == 0) + found = 1; + break; + case PROP_DOUBLE: + case PROP_VALUE: + if (kv->value.dval == 0.0) + found = 1; + break; + case PROP_EXPRESSION: + /* Unresolved expression. */ + break; + } + } + if (found) break; + } + if (found) { + /* merge node of endpoints */ + for (ob1 = tc2->cell; ob1; ob1 = ob1->next) { + if (ob1->node == node2) + ob1->node = node1; + } + + /* snip, snip. Excise this device */ + if (lob == NULL) { + ob1 = tc2->cell; + tc2->cell = ob2->next; + } + else { + ob1 = lob->next; + lob->next = ob2->next; + } + + /* free the device */ + for (; ob1 && ob1 != ob2->next; ) { + struct objlist *nob; + nob = ob1->next; + FreeObjectAndHash(ob1, tc2); + ob1 = nob; + } + + /* Remove from list */ + ecomp->num1--; + modified++; + + ob2 = lob; + } + else + ob2 = ob2->next; + } + else + ob2 = ob2->next; + } + else + ob2 = ob2->next; + } + } + else { + lob = ob2; + ob2 = ob2->next; + } + } + else { + lob = ob2; + ob2 = ob2->next; + } + } + } + + ecomp = (ECompare *)HashNext(comptab, OBJHASHSIZE); + } + + // Free the hash table and its contents. + + ecomp = (ECompare *)HashFirst(comptab, OBJHASHSIZE); + while (ecomp != NULL) { + if (--ecomp->refcount == (char)0) FREE(ecomp); + ecomp = (ECompare *)HashNext(comptab, OBJHASHSIZE); + } + HashKill(comptab, OBJHASHSIZE); + FREE(comptab); + + return modified; +} diff --git a/base/greedy.c b/base/greedy.c new file mode 100644 index 0000000..91dd383 --- /dev/null +++ b/base/greedy.c @@ -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 +#ifdef IBMPC +#include /* 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(); +} diff --git a/base/hash.c b/base/hash.c new file mode 100644 index 0000000..d816fa7 --- /dev/null +++ b/base/hash.c @@ -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 +#ifdef IBMPC +#include +#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)); +} + + diff --git a/base/hash.h b/base/hash.h new file mode 100644 index 0000000..afc7f56 --- /dev/null +++ b/base/hash.h @@ -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 */ diff --git a/base/inetcomp.c b/base/inetcomp.c new file mode 100644 index 0000000..9ca13a6 --- /dev/null +++ b/base/inetcomp.c @@ -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 +#include "netgen.h" + +#ifdef HAVE_GETOPT +#include +#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); +} diff --git a/base/netcmp.c b/base/netcmp.c new file mode 100644 index 0000000..f04d17c --- /dev/null +++ b/base/netcmp.c @@ -0,0 +1,5273 @@ +/* "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. */ + +/* netcmp.c -- graph isomorphism testing */ + +#include "config.h" + +#include +#include +#include +#include /* for time() as a seed for random number generator */ +#include +#include /* for fabs() */ + +#ifdef IBMPC +#include +#include /* for exit() */ +/* #include for rand(), srand() */ +#endif + +#ifdef TCL_NETGEN +#include +#endif + +#include "netgen.h" +#include "netcmp.h" +#include "hash.h" +#include "objlist.h" +#include "query.h" +#include "netfile.h" +#include "print.h" +#include "dbug.h" + +#ifdef TCL_NETGEN +int InterruptPending = 0; +void (*oldinthandler)() = SIG_DFL; +extern Tcl_Interp *netgeninterp; +#endif + +/* define the following to debug core allocation */ +#undef DEBUG_ALLOC + +/* define the following to try to expedite initialization of + data structures by allocating some extra lookup tables */ +#define LOOKUP_INITIALIZATION + +/* The data-structures for NETCOMP are rather complicated: + + 1) A global variable ElementClasses points to a + linked-list of ElementClass. Similarly, a global variable NodeClasses + points to a linked-list of NodeClass. + + 2) Each ElementClass record points to a linked list of Element. + Each NodeClass points to a linked list of Node. + This list represents an equivalence class of Elements/Nodes, and + incorporates components from both graphs. A legal class has an + equal number of components from each graph. +*/ + + +struct NodeList { + struct NodeList *next; + struct Node *node; + struct Element *element; + /* pins in the same nodelist with equal 'pin_magic' are permutable */ + unsigned long pin_magic; +}; + +struct Element { + unsigned long hashval; + short graph; /* which graph did this element come from ? */ + struct objlist *object; /* points to the START of the object */ + struct Element *next; + struct ElementClass *elemclass; + struct NodeList *nodelist; +}; + +struct ElementClass { + unsigned long magic; + struct Element *elements; + struct ElementClass *next; + int count; + int legalpartition; +}; + +struct NodeClass { + unsigned long magic; + struct Node *nodes; + struct NodeClass *next; + int count; + int legalpartition; +}; + +struct Node { + unsigned long hashval; + short graph; /* which graph did this node come from ? */ + struct objlist *object; + struct ElementList *elementlist; + struct NodeClass *nodeclass; + struct Node *next; +}; + +struct ElementList { + struct NodeList *subelement; + struct Node *node; + struct ElementList *next; +}; + +struct Correspond { + char *class1; + int file1; + char *class2; + int file2; + struct Correspond *next; +}; + +struct ElementClass *ElementClasses = NULL; +struct NodeClass *NodeClasses = NULL; +struct Correspond *ClassCorrespondence = NULL; +struct Correspond *CompareQueue = NULL; +struct IgnoreList *ClassIgnore = NULL; + +/* global variables for return of lists from CreateLists */ +static struct Element *Elements; +static struct Node *Nodes; + +/* keep free lists of Elements and Nodes */ +static struct Element *ElementFreeList = NULL; +static struct Node *NodeFreeList = NULL; +static struct ElementClass *ElementClassFreeList = NULL; +static struct NodeClass *NodeClassFreeList = NULL; +static struct ElementList *ElementListFreeList = NULL; +static struct NodeList *NodeListFreeList = NULL; + +/* global variables to keep track of circuits */ +struct nlist *Circuit1; +struct nlist *Circuit2; + +/* if TRUE, always partition ALL classes */ +int ExhaustiveSubdivision = 0; + +#ifdef TEST +static void PrintElement_List(struct Element *E) +{ + struct NodeList *nl; + + for (; E != NULL; E = E->next) { + struct objlist *ob; + Fprintf(stdout, " Element %s, circuit: %hd hashval = %lX\n", + E->object->instance.name, E->graph, E->hashval); + ob = E->object; + for (nl = E->nodelist; nl != NULL; nl = nl->next) { +#if 1 + Fprintf(stdout, " %s: node: %s name: %d pin magic: %lX nodeclassmagic: %lX\n", + ob->name + strlen(ob->instance.name) + 1, + nl->node->object->name, nl->node->object->node, + nl->pin_magic, nl->node->nodeclass->magic); +#else + Fprintf(stdout, " %s: %lX node: %lX num: %d magic: %lX nodeclassmag: %lX\n", + ob->name + strlen(ob->instance.name) + 1, + (long)nl, (long)(nl->node), nl->node->object->node, + nl->magic, nl->node->nodeclass->magic); +#endif + ob = ob->next; + } + } +} + +static char *ElementList_Name(struct ElementList *e) +/* returns a pointer to the name of the pin that a particular + ElementList element contacts. */ +{ + struct objlist *ob; + struct NodeList *nl; + + ob = e->subelement->element->object; + nl = e->subelement->element->nodelist; + while (nl != e->subelement) { + nl = nl->next; + ob = ob->next; + } + return(ob->name); +} + + + +static void PrintNode_List(struct Node *N) +{ + struct ElementList *el; + + for (; N != NULL; N = N->next) { + Fprintf(stdout, " Node %s circuit: %hd (num = %d) addr = %lX, hashval = %lX\n", + N->object->name, N->graph, N->object->node, (long)N, N->hashval); + for (el = N->elementlist; el != NULL; el = el->next) { +#if 1 + Fprintf(stdout, " name: %10s pin magic: %lX element class magic: %lX\n", + ElementList_Name(el), el->subelement->pin_magic, + el->subelement->element->elemclass->magic); +#else + Fprintf(stdout, " %lX element: %lX name: %s pin magic: " + "%lX class magic: %lX\n", + (long)el, (long)(el->subelement), +/* el->subelement->element->object->instance.name, */ + ElementList_Name(el), + el->subelement->magic, + el->subelement->element->elemclass->magic); +#endif + } + } +} + +/* For PrintElementClasses() and PrintNodeClasses(), type is: */ +/* 0 -> Print legal partitions (matching groups) */ +/* 1 -> Print illegal partitions (nonmatching groups) */ +/* -1 -> Print all partitions */ + +/* Ignore "dolist" in test version */ + +void PrintElementClasses(struct ElementClass *EC, int type, int dolist) +{ + while (EC != NULL) { +#ifdef TCL_NETGEN + if (check_interrupt()) break; +#endif + if (EC->legalpartition) { + if (type != 1) { + Fprintf(stdout, "Device class: count = %d; magic = %lX", + EC->count, EC->magic); + Fprintf(stdout, " -- matching group\n"); + PrintElement_List(EC->elements); + } + } + else { + if (type != 0) { + Fprintf(stdout, "Device class: count = %d; magic = %lX", + EC->count, EC->magic); + Fprintf(stdout, " -- nonmatching group\n"); + PrintElement_List(EC->elements); + } + } + Fprintf(stdout, "\n"); + EC = EC->next; + } +} + +void PrintNodeClasses(struct NodeClass *NC, int type, int dolist) +{ + while (NC != NULL) { +#ifdef TCL_NETGEN + if (check_interrupt()) break; +#endif + if (NC->legalpartition) { + if (type != 1) { + Fprintf(stdout, "Net class: count = %d; magic = %lX", + NC->count, NC->magic); + Fprintf(stdout, " -- matching group\n"); + PrintNode_List(NC->nodes); + } + } + else { + if (type != 0) { + Fprintf(stdout, "Net class: count = %d; magic = %lX", + NC->count, NC->magic); + Fprintf(stdout, " -- nonmatching group\n"); + PrintNode_List(NC->nodes); + } + } + Fprintf(stdout, "\n"); + NC = NC->next; + } +} + +#else /* NOT TEST */ + +/* For PrintElementClasses() and PrintNodeClasses(), type is: */ +/* 0 -> Print legal partitions */ +/* 1 -> Print illegal partitions */ +/* -1 -> Print all partitions */ + +void PrintElementClasses(struct ElementClass *EC, int type, int dolist) +{ + struct Element *E; +#ifdef TCL_NETGEN + Tcl_Obj *plist; + + plist = Tcl_NewListObj(0, NULL); +#endif + + while (EC != NULL) { +#ifdef TCL_NETGEN + if (check_interrupt()) break; +#endif + if (EC->legalpartition) { + if (type != 1) { + if (dolist == 0) { + Printf("Device class: count = %d; magic = %lX", EC->count, EC->magic); + Printf(" -- matching group\n"); + + for (E = EC->elements; E != NULL; E = E->next) + Printf(" %-20s (circuit %hd) hash = %lX\n", + E->object->instance.name, E->graph, E->hashval); + } +#ifdef TCL_NETGEN + else { + Tcl_Obj *elist, *epart1, *epart2; + elist = Tcl_NewListObj(0, NULL); + epart1 = Tcl_NewListObj(0, NULL); + epart2 = Tcl_NewListObj(0, NULL); + for (E = EC->elements; E != NULL; E = E->next) + Tcl_ListObjAppendElement(netgeninterp, + (E->graph == Circuit1->file) ? epart1 : epart2, + Tcl_NewStringObj(E->object->instance.name, -1)); + + Tcl_ListObjAppendElement(netgeninterp, elist, epart1); + Tcl_ListObjAppendElement(netgeninterp, elist, epart2); + Tcl_ListObjAppendElement(netgeninterp, plist, elist); + } +#endif + } + } + else { + if (type != 0) { + if (dolist == 0) { + Printf("Device class: count = %d; magic = %lX", EC->count, EC->magic); + Printf(" -- nonmatching group\n"); + + for (E = EC->elements; E != NULL; E = E->next) + Printf(" %-20s (circuit %hd) hash = %lX\n", + E->object->instance.name, E->graph, E->hashval); + } +#ifdef TCL_NETGEN + else { + Tcl_Obj *elist, *epart1, *epart2; + elist = Tcl_NewListObj(0, NULL); + epart1 = Tcl_NewListObj(0, NULL); + epart2 = Tcl_NewListObj(0, NULL); + for (E = EC->elements; E != NULL; E = E->next) + Tcl_ListObjAppendElement(netgeninterp, + (E->graph == Circuit1->file) ? epart1 : epart2, + Tcl_NewStringObj(E->object->instance.name, -1)); + + Tcl_ListObjAppendElement(netgeninterp, elist, epart1); + Tcl_ListObjAppendElement(netgeninterp, elist, epart2); + Tcl_ListObjAppendElement(netgeninterp, plist, elist); + } +#endif + } + } + EC = EC->next; + } +#ifdef TCL_NETGEN + Tcl_SetObjResult(netgeninterp, plist); +#endif +} + +void PrintNodeClasses(struct NodeClass *NC, int type, int dolist) +{ + struct Node *N; +#ifdef TCL_NETGEN + Tcl_Obj *plist; + + plist = Tcl_NewListObj(0, NULL); +#endif + + while (NC != NULL) { +#ifdef TCL_NETGEN + if (check_interrupt()) break; +#endif + if (NC->legalpartition) { + if (type != 1) { + if (dolist == 0) { + Printf("Net class: count = %d; magic = %lX", NC->count, NC->magic); + Printf(" -- matching group\n"); + for (N = NC->nodes; N != NULL; N = N->next) + Printf(" %-20s (circuit %hd) hash = %lX\n", + N->object->name, N->graph, N->hashval); + } +#ifdef TCL_NETGEN + else { + Tcl_Obj *nlist, *npart1, *npart2; + nlist = Tcl_NewListObj(0, NULL); + npart1 = Tcl_NewListObj(0, NULL); + npart2 = Tcl_NewListObj(0, NULL); + for (N = NC->nodes; N != NULL; N = N->next) + Tcl_ListObjAppendElement(netgeninterp, + (N->graph == Circuit1->file) ? npart1 : npart2, + Tcl_NewStringObj(N->object->name, -1)); + + Tcl_ListObjAppendElement(netgeninterp, nlist, npart1); + Tcl_ListObjAppendElement(netgeninterp, nlist, npart2); + Tcl_ListObjAppendElement(netgeninterp, plist, nlist); + } +#endif + } + } + else { + if (type != 0) { + if (dolist == 0) { + Printf("Net class: count = %d; magic = %lX", NC->count, NC->magic); + Printf(" -- nonmatching group\n"); + for (N = NC->nodes; N != NULL; N = N->next) + Printf(" %-20s (circuit %hd) hash = %lX\n", + N->object->name, N->graph, N->hashval); + } +#ifdef TCL_NETGEN + else { + Tcl_Obj *nlist, *npart1, *npart2; + nlist = Tcl_NewListObj(0, NULL); + npart1 = Tcl_NewListObj(0, NULL); + npart2 = Tcl_NewListObj(0, NULL); + for (N = NC->nodes; N != NULL; N = N->next) + Tcl_ListObjAppendElement(netgeninterp, + (N->graph == Circuit1->file) ? npart1 : npart2, + Tcl_NewStringObj(N->object->name, -1)); + + Tcl_ListObjAppendElement(netgeninterp, nlist, npart1); + Tcl_ListObjAppendElement(netgeninterp, nlist, npart2); + Tcl_ListObjAppendElement(netgeninterp, plist, nlist); + } +#endif + } + } + NC = NC->next; + } +#ifdef TCL_NETGEN + Tcl_SetObjResult(netgeninterp, plist); +#endif +} +#endif /* TEST */ + +/* + *--------------------------------------------------------------------- + *--------------------------------------------------------------------- + */ + +void SummarizeNodeClasses(struct NodeClass *NC) +{ + while (NC != NULL) { +#ifdef TCL_NETGEN + if (check_interrupt()) break; +#endif + Printf("Net class: count = %d; magic = %lX; hash = %ld", + NC->count, NC->magic, NC->nodes->hashval); + if (NC->legalpartition) Printf(" -- matching group\n"); + else Printf(" -- nonmatching group\n"); + NC = NC->next; + } +} + +/* + *--------------------------------------------------------------------- + *--------------------------------------------------------------------- + */ + +void SummarizeElementClasses(struct ElementClass *EC) +{ + while (EC != NULL) { +#ifdef TCL_NETGEN + if (check_interrupt()) break; +#endif + Printf("Device class: count = %d; magic = %lX; hash = %ld", + EC->count, EC->magic, EC->elements->hashval); + if (EC->legalpartition) Printf(" -- matching group\n"); + else Printf(" -- nonmatching group\n"); + EC = EC->next; + } +} + +/* + *--------------------------------------------------------------------- + *--------------------------------------------------------------------- + */ + +void SummarizeDataStructures(void) +{ + struct ElementClass *EC; + struct NodeClass *NC; + struct Element *E; + struct Node *N; + int cell1, cell2, orphan1, orphan2; + + cell1 = cell2 = 0; + for (EC = ElementClasses; EC != NULL; EC = EC->next) + for (E = EC->elements; E != NULL; E = E->next) { + if (E->graph == Circuit1->file) cell1++; + else cell2++; + } + Printf("Circuit 1 contains %d elements, Circuit 2 contains %d elements.", + cell1, cell2); + if (cell1 != cell2) Printf(" *** MISMATCH ***"); + Printf("\n"); + + cell1 = cell2 = 0; + orphan1 = orphan2 = 0; + for (NC = NodeClasses; NC != NULL; NC = NC->next) + for (N = NC->nodes; N != NULL; N = N->next) { + if (N->graph == Circuit1->file) { + cell1++; + if (N->elementlist == NULL) orphan1++; + } + else { + cell2++; + if (N->elementlist == NULL) orphan2++; + } + } + Printf("Circuit 1 contains %d nodes, Circuit 2 contains %d nodes.", + cell1, cell2); + if (cell1 != cell2) Printf(" *** MISMATCH ***"); + Printf("\n"); + if (orphan1 || orphan2) { + Printf("Circuit 1 contains %d orphan nodes, Circuit 2 contains %d orphans."); + if (orphan1 != orphan2) Printf(" *** MISMATCH ***"); + Printf("\n"); + } + Printf("\n"); +} + +/* + *----------------------------------------------------------------------- + * Structures used by FormatBadElementFragment and FormatBadNodeFragment + *----------------------------------------------------------------------- + */ + +struct FanoutList { + char *model; + char *name; + char permute; + int count; +}; + +struct FormattedList { + char *name; + int fanout; + struct FanoutList *flist; +}; + +/* Forward declaration */ +void FreeFormattedLists(struct FormattedList **nlists, int numlists); + +/* + *--------------------------------------------------------------------- + * FormatBadElementFragment + * + * formats the numbers of nets that a particular bad element pin + * fragment contacts + *--------------------------------------------------------------------- + */ + +struct FormattedList *FormatBadElementFragment(struct Element *E) +{ + struct NodeList **nodes; + int fanout; + struct NodeList *nl; + struct objlist *ob; + int count, i, j, k, m; + struct FormattedList *elemlist; + + elemlist = (struct FormattedList *)MALLOC(sizeof(struct FormattedList)); + if (elemlist == NULL) { + Fprintf(stdout, "Unable to allocated memory to print element fanout.\n"); + return; + } + + fanout = 0; + for (nl = E->nodelist; nl != NULL; nl = nl->next) fanout++; + nodes = (struct NodeList **)CALLOC(fanout, sizeof(struct NodeList *)); + if (nodes == NULL) { + Fprintf(stderr, "Unable to allocate memory to print element fanout.\n"); + FREE(elemlist); + return; + } + + elemlist->flist = (struct FanoutList *)CALLOC(fanout, sizeof(struct FanoutList)); + elemlist->fanout = fanout; + elemlist->name = E->object->instance.name; + + fanout = 0; + for (nl = E->nodelist; nl != NULL; nl = nl->next) + nodes[fanout++] = nl; + + ob = E->object; + k = 0; + for (i = 0; i < fanout; i++) { + if (nodes[i] == NULL) { + ob = ob->next; + continue; + } + + count = 1; + for (j = i+1; j < fanout; j++) { + /* count the number of pins with the same magic number (permutable pins) */ + if (nodes[j] != NULL && nodes[i]->pin_magic == nodes[j]->pin_magic) { + count++; + } + } + if (count == 1) { /* pin is unique */ + struct ElementList *elems; + + count = 0; + if (nodes[i]->node != NULL) { + for (elems = nodes[i]->node->elementlist; elems != NULL; + elems = elems->next) + count++; + + elemlist->flist[k].count = count; + elemlist->flist[k].name = ob->name + strlen(ob->instance.name) + 1; + elemlist->flist[k].permute = (char)1; + k++; + } + } + else { /* handle multiple permutable pins */ + struct objlist *ob2; + int maxindex, maxcount; + unsigned long oldmagic; + + ob2 = ob; + m = k; + for (j = i; j < fanout; j++) { + if (nodes[j] != NULL && nodes[i]->pin_magic == nodes[j]->pin_magic) { + elemlist->flist[k].name = ob2->name + strlen(ob2->instance.name) + 1; + elemlist->flist[k].permute = (char)0; + elemlist->flist[k].count = -1; // Put total count at end + k++; + } + ob2 = ob2->next; + } + k = m; + + /* sort fanouts in DECREASING order */ + maxindex = i; + maxcount = -1; + oldmagic = nodes[i]->pin_magic; /* allows us to nuke pins[i] */ + + while (maxindex >= 0) { + maxcount = -1; + maxindex = -1; + + for (j = i; j < fanout; j++) { + if (nodes[j] != NULL && oldmagic == nodes[j]->pin_magic) { + struct ElementList *elems; + + count = 0; + if (nodes[j]->node == NULL) continue; // ? + for (elems = nodes[j]->node->elementlist; elems != NULL; + elems = elems->next) + count++; + if (count >= maxcount) { + maxcount = count; + maxindex = j; + } + } + } + if (maxindex >= 0) { + elemlist->flist[k].count = maxcount; + nodes[maxindex] = NULL; /* So we don't double-count */ + k++; + } + } + if (k > 0) + elemlist->flist[k - 1].permute = (char)1; /* Denotes end of list */ + + } + nodes[i] = NULL; + ob = ob->next; /* point to next name in list */ + } + elemlist->fanout = k; + + FREE(nodes); + return elemlist; +} + +/* + *--------------------------------------------------------------------- + *--------------------------------------------------------------------- + */ + +void PrintBadElementFragment(struct Element *E) +{ + struct NodeList **nodes; + int fanout; + struct NodeList *nl; + struct objlist *ob; + int count, i, j; + + Fprintf(stdout, " (%d): %s",E->graph, E->object->instance.name); + Ftab(stdout, 20); + + fanout = 0; + for (nl = E->nodelist; nl != NULL; nl = nl->next) fanout++; + nodes = (struct NodeList **)CALLOC(fanout, sizeof(struct NodeList *)); + if (nodes == NULL) { + Fprintf(stderr, "Unable to allocate memory to print element fanout.\n"); + return; + } + + Ftab(stdout, 20); + Fprintf(stdout, " ==> "); + + Fwrap(stdout, 80); /* set wrap-around */ + fanout = 0; + for (nl = E->nodelist; nl != NULL; nl = nl->next) + nodes[fanout++] = nl; + + + ob = E->object; + for (i = 0; i < fanout; i++) { + if (nodes[i] == NULL) { + ob = ob->next; + continue; + } + + count = 1; + for (j = i+1; j < fanout; j++) { + /* count the number of pins with the same magic number */ + if (nodes[j] != NULL && nodes[i]->pin_magic == nodes[j]->pin_magic) + count++; + } + if (count == 1) { + struct ElementList *elems; + + count = 0; + if (nodes[i]->node != NULL) + for (elems = nodes[i]->node->elementlist; elems != NULL; + elems = elems->next) + count++; + if (i != 0) Fprintf(stdout, "; "); + Fprintf(stdout, "%s = %d", ob->name + strlen(ob->instance.name) + 1, count); + } + else { + struct objlist *ob2; + int maxindex, maxcount, someprinted; + unsigned long oldmagic; + + if (i != 0) Fprintf(stdout, "; "); + Fprintf(stdout, "("); + ob2 = ob; + for (j = i; j < fanout; j++) { + if (nodes[j] != NULL && nodes[i]->pin_magic == nodes[j]->pin_magic) { + if (i != j) Fprintf(stdout, ", "); + Fprintf(stdout, "%s", ob2->name + strlen(ob2->instance.name) + 1); + } + ob2 = ob2->next; + } + Fprintf(stdout, ") = ("); + + /* sort fanouts in DECREASING order */ + someprinted = 0; + maxindex = i; + maxcount = -1; + oldmagic = nodes[i]->pin_magic; /* allows us to nuke pins[i] */ + + while (maxindex >= 0) { + maxcount = -1; + maxindex = -1; + + for (j = i; j < fanout; j++) { + if (nodes[j] != NULL && oldmagic == nodes[j]->pin_magic) { + struct ElementList *elems; + + count = 0; + for (elems = nodes[j]->node->elementlist; elems != NULL; + elems = elems->next) + count++; + if (count >= maxcount) { + maxcount = count; + maxindex = j; + } + } + } + if (maxindex >= 0) { + if (someprinted) Fprintf(stdout, ", "); + Fprintf(stdout, "%d", maxcount); + someprinted = 1; + nodes[maxindex] = NULL; + } + } + Fprintf(stdout, ")"); + } + nodes[i] = NULL; + ob = ob->next; /* point to next name in list */ + } + + Fprintf(stdout, "\n"); + FREE(nodes); +} + +/* + *--------------------------------------------------------------------- + * FormatBadNodeFragment -- + * + * formats the numbers and types of pins that a particular bad node + * fragment contacts; e.g. NODE2 5 p:gate 10 n:source + *--------------------------------------------------------------------- + */ + +struct FormattedList *FormatBadNodeFragment(struct Node *N) +{ + struct ElementList **pins; + int fanout; + struct ElementList *e; + int i, j, k; + struct FormattedList *nodelist; + + fanout = 0; + for (e = N->elementlist; e != NULL; e = e->next) fanout++; + /* there are at most 'fanout' different types of pins contacted */ + + pins = (struct ElementList **)CALLOC(fanout, sizeof(struct ElementList *)); + if (pins == NULL) { + Fprintf(stdout, "Unable to allocate memory to print node fanout.\n"); + return; + } + + nodelist = (struct FormattedList *)MALLOC(sizeof(struct FormattedList)); + if (nodelist == NULL) { + Fprintf(stdout, "Unable to allocate memory to print node fanout.\n"); + FREE(pins); + return; + } + nodelist->flist = (struct FanoutList *)CALLOC(fanout, sizeof(struct FanoutList)); + nodelist->fanout = fanout; + nodelist->name = (N->object == NULL) ? NULL : N->object->name; + + fanout = 0; + for (e = N->elementlist; e != NULL; e = e->next) + pins[fanout++] = e; + + /* process pins in sequence, NULLing out pins as they are processed */ + k = 0; + for (i = 0; i < fanout; i++) + if (pins[i] != NULL) { + int count; + char *model, *pinname, permute; + struct NodeList *n; + struct objlist *ob; + + count = 1; /* remember: pins[i] contacts it */ + permute = (char)0; + model = pins[i]->subelement->element->object->model.class; + /* find the first pin on that element with the same magic number */ + pinname = "can't happen"; + ob = pins[i]->subelement->element->object; + for (n = pins[i]->subelement->element->nodelist; n != NULL; n = n->next){ + if (n->pin_magic == pins[i]->subelement->pin_magic) { + if (permute == 0) { + pinname = ob->name + strlen(ob->instance.name) + 1; + } + else { + char *pinsave = pinname; + pinname = (char *)MALLOC(strlen(pinsave) + strlen(ob->name + + strlen(ob->instance.name) + 1) + 2); + sprintf(pinname, "%s|%s", pinsave, ob->name + strlen(ob->instance.name) + 1); + if (permute > 1) FREE(pinsave); + } + permute++; + } + ob = ob->next; + } + + /* now see if any other pins from elements of the same class, + WITH THE SAME HASH NUMBER, are on this node */ + for (j = i+1; j < fanout; j++) { + if (pins[j] != NULL && + (*matchfunc) (model, + pins[j]->subelement->element->object->model.class) && + pins[i]->subelement->pin_magic == pins[j]->subelement->pin_magic) { + count++; + nodelist->fanout--; + pins[j] = NULL; + } + } + + nodelist->flist[k].model = model; + nodelist->flist[k].name = pinname; + nodelist->flist[k].count = count; + nodelist->flist[k].permute = permute; + k++; + + pins[i] = NULL; /* not really necessary */ + } + FREE(pins); + return nodelist; +} + +/* + *--------------------------------------------------------------------- + *--------------------------------------------------------------------- + */ + +void PrintBadNodeFragment(struct Node *N) +/* prints out the numbers and types of pins that a particular bad node + fragment contacts; e.g. NODE2 5 p:gate 10 n:source +*/ +{ + struct ElementList **pins; + int fanout; + struct ElementList *e; + int i, j; + + Fprintf(stdout, " (%d): %s",N->graph, (N->object == NULL) ? + "(unknown)" : N->object->name); + + fanout = 0; + for (e = N->elementlist; e != NULL; e = e->next) fanout++; + /* there are at most 'fanout' different types of pins contacted */ + + pins = (struct ElementList **)CALLOC(fanout, sizeof(struct ElementList *)); + if (pins == NULL) { + Fprintf(stdout, "Unable to allocate memory to print node fanout.\n"); + return; + } + Ftab(stdout, 25); + Fprintf(stdout, " ==> "); + + Fwrap(stdout, 80); /* set wrap-around */ + fanout = 0; + for (e = N->elementlist; e != NULL; e = e->next) + pins[fanout++] = e; + + + /* process pins in sequence, NULLing out pins as they are processed */ + for (i = 0; i < fanout; i++) + if (pins[i] != NULL) { + int count; + char *model, *pinname; + struct NodeList *n; + struct objlist *ob; + + count = 1; /* remember: pins[i] contacts it */ + model = pins[i]->subelement->element->object->model.class; + /* find the first pin on that element with the same magic number */ + pinname = "can't happen"; + ob = pins[i]->subelement->element->object; + for (n = pins[i]->subelement->element->nodelist; n != NULL; n = n->next){ + if (n->pin_magic == pins[i]->subelement->pin_magic) { + pinname = ob->name + strlen(ob->instance.name) + 1; + break; /* MAS 3/13/91 */ + } + ob = ob->next; + } + + /* now see if any other pins from elements of the same class, + WITH THE SAME HASH NUMBER, are on this node */ + for (j = i+1; j < fanout; j++) { + if (pins[j] != NULL && + (*matchfunc)(model, + pins[j]->subelement->element->object->model.class) && + pins[i]->subelement->pin_magic == pins[j]->subelement->pin_magic) { + count++; + pins[j] = NULL; + } + } + + if (i != 0) Fprintf(stdout, ";"); + Fprintf(stdout, " %s:%s = %d", model, pinname, count); + pins[i] = NULL; /* not really necessary */ + } + Fprintf(stdout, "\n"); + Fwrap(stdout, 0); /* unset wrap-around */ + FREE(pins); +} + +/* + *--------------------------------------------------------------------- + *--------------------------------------------------------------------- + */ + +void FormatIllegalElementClasses(void) +{ + struct FormattedList **elist1, **elist2; + struct ElementClass *escan; + int found, numlists1, numlists2, n1, n2, n, f1, f2, i, maxf; + char ostr[89]; + char *estr; + char permname[80]; + char permcount[80]; + int bytesleft; + + found = 0; + for (escan = ElementClasses; escan != NULL; escan = escan->next) + if (!(escan->legalpartition)) { + struct Element *E; + + if (!found) { + Fprintf(stdout, "DEVICE mismatches: "); + Fprintf(stdout, "Class fragments follow (with node fanout counts):\n"); + + /* Print in side-by-side format */ + + *(ostr + 43) = '|'; + *(ostr + 87) = '\n'; + *(ostr + 88) = '\0'; + for (i = 0; i < 43; i++) *(ostr + i) = ' '; + for (i = 44; i < 87; i++) *(ostr + i) = ' '; + snprintf(ostr, 43, "Circuit 1: %s", Circuit1->name); + snprintf(ostr + 44, 43, "Circuit 2: %s", Circuit2->name); + for (i = 0; i < 88; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' '; + Fprintf(stdout, ostr); + } + found = 1; + + numlists1 = numlists2 = 0; + for (E = escan->elements; E != NULL; E = E->next) + { + if (E->graph == Circuit1->file) + numlists1++; + else + numlists2++; + } + elist1 = (struct FormattedList **)CALLOC(numlists1, + sizeof(struct FormattedList *)); + elist2 = (struct FormattedList **)CALLOC(numlists2, + sizeof(struct FormattedList *)); + + n1 = n2 = 0; + + for (E = escan->elements; E != NULL; E = E->next) { +#ifdef TCL_NETGEN + if (check_interrupt()) { + FreeFormattedLists(elist1, n1); + FreeFormattedLists(elist2, n2); + return; + } +#endif + if (E->graph == Circuit1->file) { + elist1[n1] = FormatBadElementFragment(E); + n1++; + } + else { + elist2[n2] = FormatBadElementFragment(E); + n2++; + } + } + Fprintf(stdout, "\n"); + + for (n = 0; n < ((n1 > n2) ? n1 : n2); n++) { + if (n != 0) { + for (i = 0; i < 43; i++) *(ostr + i) = ' '; + for (i = 44; i < 87; i++) *(ostr + i) = ' '; + Fprintf(stdout, ostr); + } else { + for (i = 0; i < 87; i++) *(ostr + i) = '-'; + Fprintf(stdout, ostr); + *(ostr + 43) = '|'; + } + for (i = 0; i < 43; i++) *(ostr + i) = ' '; + for (i = 44; i < 87; i++) *(ostr + i) = ' '; + if (n < n1) { + estr = elist1[n]->name; + if (*estr == '/') estr++; // Remove leading slash, if any + snprintf(ostr, 43, "Instance: %s", estr); + } + else + snprintf(ostr, 43, "(no matching instance)"); + if (n < n2) { + estr = elist2[n]->name; + if (*estr == '/') estr++; // Remove leading slash, if any + snprintf(ostr + 44, 43, "Instance: %s", estr); + } + else + snprintf(ostr + 44, 43, "(no matching instance)"); + for (i = 0; i < 88; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' '; + Fprintf(stdout, ostr); + + if (n >= n1) + maxf = elist2[n]->fanout; + else if (n >= n2) + maxf = elist1[n]->fanout; + else + maxf = (elist1[n]->fanout > elist2[n]->fanout) ? + elist1[n]->fanout : elist2[n]->fanout; + + f1 = f2 = 0; + while ((f1 < maxf) || (f2 < maxf)) { + for (i = 0; i < 43; i++) *(ostr + i) = ' '; + for (i = 44; i < 87; i++) *(ostr + i) = ' '; + if (n < n1) { + if (f1 < elist1[n]->fanout) { + if (elist1[n]->flist[f1].permute == (char)1) { + snprintf(ostr, 43, " %s = %d", elist1[n]->flist[f1].name, + elist1[n]->flist[f1].count); + } + else { + bytesleft = 76; + char value[10]; + sprintf(permname, "("); + sprintf(permcount, "("); + while (elist1[n]->flist[f1].permute == (char)0) { + strncat(permname, elist1[n]->flist[f1].name, bytesleft); + bytesleft -= strlen(elist1[n]->flist[f1].name); + strcat(permname, ","); + sprintf(value, "%d", elist1[n]->flist[f1].count); + strcat(permcount, value); + strcat(permcount, ","); + f1++; + } + strncat(permname, elist1[n]->flist[f1].name, bytesleft); + strcat(permname, ")"); + sprintf(value, "%d", elist1[n]->flist[f1].count); + strcat(permcount, value); + strcat(permcount, ")"); + snprintf(ostr, 43, " %s = %s", permname, permcount); + } + } + } + f1++; + if (n < n2) { + if (f2 < elist2[n]->fanout) { + if (elist2[n]->flist[f2].permute == (char)1) { + snprintf(ostr + 44, 43, " %s = %d", elist2[n]->flist[f2].name, + elist2[n]->flist[f2].count); + } + else { + bytesleft = 76; + char value[10]; + sprintf(permname, "("); + sprintf(permcount, "("); + while (elist2[n]->flist[f2].permute == (char)0) { + strncat(permname, elist2[n]->flist[f2].name, bytesleft); + bytesleft -= strlen(elist2[n]->flist[f2].name); + strcat(permname, ","); + sprintf(value, "%d", elist2[n]->flist[f2].count); + strcat(permcount, value); + strcat(permcount, ","); + f2++; + } + strncat(permname, elist2[n]->flist[f2].name, bytesleft); + strcat(permname, ")"); + sprintf(value, "%d", elist2[n]->flist[f2].count); + strcat(permcount, value); + strcat(permcount, ")"); + snprintf(ostr + 44, 43, " %s = %s", permname, permcount); + } + } + } + f2++; + for (i = 0; i < 88; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' '; + Fprintf(stdout, ostr); + } + } + + FreeFormattedLists(elist1, numlists1); + FreeFormattedLists(elist2, numlists2); + for (i = 0; i < 87; i++) *(ostr + i) = '-'; + Fprintf(stdout, ostr); + *(ostr + 43) = '|'; + } +} + +/* + *--------------------------------------------------------------------- + *--------------------------------------------------------------------- + */ + +void PrintIllegalElementClasses(void) +{ + struct ElementClass *escan; + int found; + + found = 0; + for (escan = ElementClasses; escan != NULL; escan = escan->next) + if (!(escan->legalpartition)) { + struct Element *E; + + if (!found) { + Fprintf(stdout, "DEVICE mismatches: "); + Fprintf(stdout, "Class fragments follow (with node fanout counts):\n"); + } + found = 1; + for (E = escan->elements; E != NULL; E = E->next) + { +#ifdef TCL_NETGEN + if (check_interrupt()) return; +#endif + PrintBadElementFragment(E); + } + Fprintf(stdout, "---------------------------\n"); + } +} + +/* + *--------------------------------------------------------------------- + *--------------------------------------------------------------------- + */ + +void FreeFormattedLists(struct FormattedList **nlists, int numlists) +{ + int n; + for (n = 0; n < numlists; n++) { + FREE(nlists[n]->flist); + FREE(nlists[n]); + } + FREE(nlists); +} + +/* + *--------------------------------------------------------------------- + *--------------------------------------------------------------------- + */ + +void FormatIllegalNodeClasses(void) +{ + struct FormattedList **nlists1, **nlists2; + struct NodeClass *nscan; + int found, numlists1, numlists2, n1, n2, n, f, i, maxf; + char ostr[89]; + + found = 0; + + for (nscan = NodeClasses; nscan != NULL; nscan = nscan->next) + if (!(nscan->legalpartition)) { + struct Node *N; + + if (!found) { + Fprintf(stdout, "NET mismatches: "); + Fprintf(stdout, "Class fragments follow (with fanout counts):\n"); + + /* Print in side-by-side format */ + *(ostr + 43) = '|'; + *(ostr + 87) = '\n'; + *(ostr + 88) = '\0'; + for (i = 0; i < 43; i++) *(ostr + i) = ' '; + for (i = 44; i < 87; i++) *(ostr + i) = ' '; + snprintf(ostr, 43, "Circuit 1: %s", Circuit1->name); + snprintf(ostr + 44, 43, "Circuit 2: %s", Circuit2->name); + for (i = 0; i < 88; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' '; + Fprintf(stdout, ostr); + } + found = 1; + + numlists1 = numlists2 = 0; + for (N = nscan->nodes; N != NULL; N = N->next) { + if (N->graph == Circuit1->file) + numlists1++; + else + numlists2++; + } + nlists1 = (struct FormattedList **)CALLOC(numlists1, + sizeof(struct FormattedNodeList *)); + nlists2 = (struct FormattedList **)CALLOC(numlists2, + sizeof(struct FormattedList *)); + + n1 = n2 = 0; + for (N = nscan->nodes; N != NULL; N = N->next) { +#ifdef TCL_NETGEN + if (check_interrupt()) { + FreeFormattedLists(nlists1, n1); + FreeFormattedLists(nlists2, n2); + return; + } +#endif + if (N->graph == Circuit1->file) { + nlists1[n1] = FormatBadNodeFragment(N); + n1++; + } + else { + nlists2[n2] = FormatBadNodeFragment(N); + n2++; + } + } + Fprintf(stdout, "\n"); + + for (n = 0; n < ((n1 > n2) ? n1 : n2); n++) { + if (n != 0) { + for (i = 0; i < 43; i++) *(ostr + i) = ' '; + for (i = 44; i < 87; i++) *(ostr + i) = ' '; + Fprintf(stdout, ostr); + } else { + for (i = 0; i < 87; i++) *(ostr + i) = '-'; + Fprintf(stdout, ostr); + *(ostr + 43) = '|'; + } + for (i = 0; i < 43; i++) *(ostr + i) = ' '; + for (i = 44; i < 87; i++) *(ostr + i) = ' '; + if (n < n1) + snprintf(ostr, 43, "Net: %s", nlists1[n]->name); + else + snprintf(ostr, 43, "(no matching net)"); + if (n < n2) + snprintf(ostr + 44, 43, "Net: %s", nlists2[n]->name); + else + snprintf(ostr + 44, 43, "(no matching net)"); + for (i = 0; i < 88; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' '; + Fprintf(stdout, ostr); + + if (n >= n1) + maxf = nlists2[n]->fanout; + else if (n >= n2) + maxf = nlists1[n]->fanout; + else + maxf = (nlists1[n]->fanout > nlists2[n]->fanout) ? + nlists1[n]->fanout : nlists2[n]->fanout; + + for (f = 0; f < maxf; f++) { + for (i = 0; i < 43; i++) *(ostr + i) = ' '; + for (i = 44; i < 87; i++) *(ostr + i) = ' '; + if (n < n1) + if (f < nlists1[n]->fanout) { + if (nlists1[n]->flist[f].permute <= 1) + snprintf(ostr, 43, " %s/%s = %d", + nlists1[n]->flist[f].model, + nlists1[n]->flist[f].name, + nlists1[n]->flist[f].count); + else { + snprintf(ostr, 43, " %s/(%s) = %d", + nlists1[n]->flist[f].model, + nlists1[n]->flist[f].name, + nlists1[n]->flist[f].count); + FREE(nlists1[n]->flist[f].name); + } + } + if (n < n2) + if (f < nlists2[n]->fanout) { + if (nlists2[n]->flist[f].permute <= 1) + snprintf(ostr + 44, 43, " %s/%s = %d", + nlists2[n]->flist[f].model, + nlists2[n]->flist[f].name, + nlists2[n]->flist[f].count); + else { + snprintf(ostr + 44, 43, " %s/(%s) = %d", + nlists2[n]->flist[f].model, + nlists2[n]->flist[f].name, + nlists2[n]->flist[f].count); + FREE(nlists2[n]->flist[f].name); + } + } + for (i = 0; i < 88; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' '; + Fprintf(stdout, ostr); + } + } + + FreeFormattedLists(nlists1, numlists1); + FreeFormattedLists(nlists2, numlists2); + for (i = 0; i < 87; i++) *(ostr + i) = '-'; + Fprintf(stdout, ostr); + *(ostr + 43) = '|'; + } +} + +/* + *--------------------------------------------------------------------- + *--------------------------------------------------------------------- + */ + +void PrintIllegalNodeClasses(void) +{ + struct NodeClass *nscan; + int found; + + found = 0; + for (nscan = NodeClasses; nscan != NULL; nscan = nscan->next) + if (!(nscan->legalpartition)) { + struct Node *N; + + if (!found) { + Fprintf(stdout, "\n"); + Fprintf(stdout, "NET mismatches: "); + Fprintf(stdout, "Class fragments follow (with fanouts):\n"); + } + found = 1; + for (N = nscan->nodes; N != NULL; N = N->next) { +#ifdef TCL_NETGEN + if (check_interrupt()) return; +#endif + PrintBadNodeFragment(N); + } + Fprintf(stdout, "---------------------------\n"); + } +} + +/* + *--------------------------------------------------------------------- + *--------------------------------------------------------------------- + */ + +void PrintIllegalClasses(void) +{ + PrintIllegalElementClasses(); + PrintIllegalNodeClasses(); +} + +/**************************** Free lists ***************************/ + +#ifdef DEBUG_ALLOC +int ElementAllocated; +int NodeAllocated; +int NodeClassAllocated; +int ElementClassAllocated; +int ElementListAllocated; +int NodeListAllocated; +#endif + +INLINE +struct Element *GetElement(void) +{ + struct Element *new_element; + if (ElementFreeList != NULL) { + new_element = ElementFreeList; + ElementFreeList = ElementFreeList->next; + memzero(new_element, sizeof(struct Element)); + } + else { + new_element = (struct Element *)CALLOC(1,sizeof(struct Element)); +#ifdef DEBUG_ALLOC + ElementAllocated++; +#endif + } + return(new_element); +} + +INLINE +void FreeElement(struct Element *old) +{ + old->next = ElementFreeList; + ElementFreeList = old; +} + +INLINE +struct Node *GetNode(void) +{ + struct Node *new_node; + if (NodeFreeList != NULL) { + new_node = NodeFreeList; + NodeFreeList = NodeFreeList->next; + memzero(new_node, sizeof(struct Node)); + } + else { + new_node = (struct Node *)CALLOC(1,sizeof(struct Node)); +#ifdef DEBUG_ALLOC + NodeAllocated++; +#endif + } + return(new_node); +} + +INLINE +void FreeNode(struct Node *old) +{ + old->next = NodeFreeList; + NodeFreeList = old; +} + +INLINE +struct ElementClass *GetElementClass(void) +{ + struct ElementClass *new_elementclass; + if (ElementClassFreeList != NULL) { + new_elementclass = ElementClassFreeList; + ElementClassFreeList = ElementClassFreeList->next; + memzero(new_elementclass, sizeof(struct ElementClass)); + } + else { + new_elementclass = + (struct ElementClass *)CALLOC(1,sizeof(struct ElementClass)); +#ifdef DEBUG_ALLOC + ElementClassAllocated++; +#endif + } + new_elementclass->legalpartition = 1; + return(new_elementclass); +} + +INLINE +void FreeElementClass(struct ElementClass *old) +{ + old->next = ElementClassFreeList; + ElementClassFreeList = old; +} + +INLINE +struct NodeClass *GetNodeClass(void) +{ + struct NodeClass *new_nodeclass; + if (NodeClassFreeList != NULL) { + new_nodeclass = NodeClassFreeList; + NodeClassFreeList = NodeClassFreeList->next; + memzero(new_nodeclass, sizeof(struct NodeClass)); + } + else { + new_nodeclass = + (struct NodeClass *)CALLOC(1,sizeof(struct NodeClass)); +#ifdef DEBUG_ALLOC + NodeClassAllocated++; +#endif + } + new_nodeclass->legalpartition = 1; + return(new_nodeclass); +} + +INLINE +void FreeNodeClass(struct NodeClass *old) +{ + old->next = NodeClassFreeList; + NodeClassFreeList = old; +} + +INLINE +struct ElementList *GetElementList(void) +{ + struct ElementList *new_elementlist; + if (ElementListFreeList != NULL) { + new_elementlist = ElementListFreeList; + ElementListFreeList = ElementListFreeList->next; + memzero(new_elementlist, sizeof(struct ElementList)); + } + else { + new_elementlist = + (struct ElementList *)CALLOC(1,sizeof(struct ElementList)); +#ifdef DEBUG_ALLOC + ElementListAllocated++; +#endif + } + return(new_elementlist); +} + +INLINE +void FreeElementList(struct ElementList *old) +{ + old->next = ElementListFreeList; + ElementListFreeList = old; +} + +INLINE +struct NodeList *GetNodeList(void) +{ + struct NodeList *new_nodelist; + if (NodeListFreeList != NULL) { + new_nodelist = NodeListFreeList; + NodeListFreeList = NodeListFreeList->next; + memzero(new_nodelist, sizeof(struct NodeList)); + } + else { + new_nodelist = (struct NodeList *)CALLOC(1,sizeof(struct NodeList)); +#ifdef DEBUG_ALLOC + NodeListAllocated++; +#endif + } + return(new_nodelist); +} + +INLINE +void FreeNodeList(struct NodeList *old) +{ + old->next = NodeListFreeList; + NodeListFreeList = old; +} + +#ifdef DEBUG_ALLOC +void PrintCoreStats(void) +{ + Fprintf(stdout, "DeviceClass records allocated = %d, size = %d\n", + ElementClassAllocated, sizeof(struct ElementClass)); + Fprintf(stdout, "Device records allocated = %d, size = %d\n", + ElementAllocated, sizeof(struct Element)); + Fprintf(stdout, "NetList records allocated = %d, size = %d\n", + NodeListAllocated, sizeof(struct NodeList)); + Fprintf(stdout, "NetClass records allocated = %d, size = %d\n", + NodeClassAllocated, sizeof(struct NodeClass)); + Fprintf(stdout, "Net records allocated = %d, size = %d\n", + NodeAllocated, sizeof(struct Node)); + Fprintf(stdout, "DeviceList records allocated = %d, size = %d\n", + ElementListAllocated, sizeof(struct ElementList)); + Fprintf(stdout, "Total accounted-for memory: %d\n", + ElementClassAllocated * sizeof(struct ElementClass) + + ElementAllocated * sizeof(struct Element) + + NodeListAllocated * sizeof(struct NodeList) + + NodeClassAllocated * sizeof(struct NodeClass) + + NodeAllocated * sizeof(struct Node) + + ElementListAllocated * sizeof(struct ElementList)); +} +#endif + + +static int OldNumberOfEclasses; +static int OldNumberOfNclasses; +static int NewNumberOfEclasses; +static int NewNumberOfNclasses; + +static int Iterations; + +void FreeEntireElementClass(struct ElementClass *ElementClasses) +{ + struct ElementClass *next; + struct Element *E, *Enext; + struct NodeList *n, *nnext; + + while (ElementClasses != NULL) { + next = ElementClasses->next; + E = ElementClasses->elements; + while (E != NULL) { + Enext = E->next; + n = E->nodelist; + while (n != NULL) { + nnext = n->next; + FreeNodeList(n); + n = nnext; + } + FreeElement(E); + E = Enext; + } + FreeElementClass(ElementClasses); + ElementClasses = next; + } +} + + +void FreeEntireNodeClass(struct NodeClass *NodeClasses) +{ + struct NodeClass *next; + struct Node *N, *Nnext; + struct ElementList *e, *enext; + + while (NodeClasses != NULL) { + next = NodeClasses->next; + N = NodeClasses->nodes; + while (N != NULL) { + Nnext = N->next; + e = N->elementlist; + while (e != NULL) { + enext = e->next; + FreeElementList(e); + e = enext; + } + FreeNode(N); + N = Nnext; + } + FreeNodeClass(NodeClasses); + NodeClasses = next; + } +} + +int BadMatchDetected; +int PropertyErrorDetected; +int NewFracturesMade; + + +void ResetState(void) +{ + if (NodeClasses != NULL) + FreeEntireNodeClass(NodeClasses); + if (ElementClasses != NULL) + FreeEntireElementClass(ElementClasses); + NodeClasses = NULL; + ElementClasses = NULL; + Circuit1 = NULL; + Circuit2 = NULL; + Elements = NULL; + Nodes = NULL; + NewNumberOfEclasses = OldNumberOfEclasses = 0; + NewNumberOfNclasses = OldNumberOfNclasses = 0; + Iterations = 0; + BadMatchDetected = 0; + PropertyErrorDetected = 0; + NewFracturesMade = 0; + ExhaustiveSubdivision = 0; /* why not ?? */ + /* maybe should free up free lists ??? */ +} + + + +struct Element *CreateElementList(char *name, short graph) +/* create a list of the correct 'shape' for Elements, but with empty records*/ +{ + struct objlist *ob; + struct nlist *tp; + struct Element *head, *tail; + + /* get a pointer to the cell */ + tp = LookupCellFile(name, graph); + if (tp == NULL) { + Fprintf(stderr, "No cell '%s' found.\n", name); + return(NULL); + } + + head = tail = NULL; + for (ob = tp->cell; ob != NULL; ob = ob->next) { + if (ob->type == FIRSTPIN) { + struct Element *new_element; + + new_element = GetElement(); + if (new_element == NULL) { + Fprintf(stderr,"Memory allocation error\n"); +#ifdef DEBUG_ALLOC + PrintCoreStats(); +#endif + ResetState(); + return NULL; + } + new_element->object = ob; + new_element->graph = graph; + /* append to list */ + if (head == NULL) head = new_element; + else tail->next = new_element; + tail = new_element; + } + if (ob->type >= FIRSTPIN) { + struct NodeList *tmp; + tmp = GetNodeList(); + tmp->element = tail; + tmp->next = tail->nodelist; + tail->nodelist = tmp; + } + } + return(head); +} + +#ifdef LOOKUP_INITIALIZATION + +struct ElementList **LookupElementList; + +struct Node *CreateNodeList(char *name, short graph) +/* create a list of the correct 'shape' of the Node list */ +/* for now, all the records are blank */ +{ + struct objlist *ob, *newobj; + struct nlist *tp; + struct Node *head, *tail, *new_node; + int maxnode, i; + struct ElementList *tmp; + + /* get a pointer to the cell */ + tp = LookupCellFile(name, graph); + if (tp == NULL) { + Fprintf(stderr, "No cell '%s' found.\n", name); + return(NULL); + } + + /* find the max. node number */ + maxnode = 0; + for (ob = tp->cell; ob != NULL; ob = ob->next) + if (ob->type >= FIRSTPIN && ob->node > maxnode) maxnode = ob->node; + + /* now allocate the lookup table */ + LookupElementList = + (struct ElementList **)CALLOC(maxnode + 1, sizeof(struct ElementList *)); + if (LookupElementList == NULL) { + Fprintf(stderr, "Unable to allocate space for lookup table\n"); + return(NULL); + } + + for (ob = tp->cell; ob != NULL; ob = ob->next) { + // Requirement that ob->node be greater than zero eliminates + // unconnected nodes (value -1) and dummy nodes (value 0) + if (ob->type >= FIRSTPIN && (ob->node > 0)) { + tmp = GetElementList(); + if (tmp == NULL) { + Fprintf(stderr,"Memory allocation error\n"); +#ifdef DEBUG_ALLOC + PrintCoreStats(); +#endif + ResetState(); + return NULL; + } + tmp->next = LookupElementList[ob->node]; + LookupElementList[ob->node] = tmp; + } + } + + /* now generate a list of Nodes */ + head = tail = NULL; + for (i = 0; i <= maxnode; i++) { + if (LookupElementList[i] != NULL) { + newobj = LookupObject(NodeName(tp, i), tp); + if (newobj != NULL) { /* NULL objects may be element property records */ + new_node = GetNode(); + if (new_node == NULL) { + Fprintf(stderr,"Memory allocation error\n"); +#ifdef DEBUG_ALLOC + PrintCoreStats(); +#endif + ResetState(); + return NULL; + } + new_node->object = newobj; + new_node->graph = graph; + new_node->elementlist = LookupElementList[i]; + for (tmp = new_node->elementlist; tmp != NULL; tmp = tmp->next) + tmp->node = new_node; + if (head == NULL) head = new_node; + else tail->next = new_node; + tail = new_node; + } + } + } + return (head); +} + +void CreateLists(char *name, short graph) +/* creates two lists of the correct 'shape', then traverses nodes + in sequence to link up 'subelement' field of ElementList, + then 'node' field of NodeList structures. +*/ +{ + struct Element *ElementScan; + struct ElementList *EListScan; + struct NodeList *NListScan; + struct objlist *ob; + struct nlist *tp; + + /* get a pointer to the cell */ + tp = LookupCellFile(name, graph); + if (tp == NULL) { + Fprintf(stderr, "No cell '%s' found.\n", name); + return; + } + + if (Circuit1 == NULL) Circuit1 = tp; + else if (Circuit2 == NULL) Circuit2 = tp; + else { + Fprintf(stderr, "Error: CreateLists() called more than twice without a reset.\n"); + return; + } + + Elements = CreateElementList(name, graph); + Nodes = CreateNodeList(name, graph); + if (LookupElementList == NULL) return; + + ElementScan = NULL; + NListScan = NULL; /* just to stop the compiler from bitching */ + for (ob = tp->cell; ob != NULL; ob = ob->next) { + if (ob->type == FIRSTPIN) { + if (ElementScan == NULL) ElementScan = Elements; + else ElementScan = ElementScan->next; + NListScan = ElementScan->nodelist; + } + /* now hook up node */ + if (ob->type >= FIRSTPIN && (ob->node > 0)) { + EListScan = LookupElementList[ob->node]; + + /* write it into the EListScan slot */ + EListScan->subelement = NListScan; + NListScan->node = EListScan->node; + + /* point to next available ElementList unit */ + LookupElementList[ob->node] = EListScan->next; + NListScan = NListScan->next; + } + } + + FREE(LookupElementList); + LookupElementList = NULL; +} + +#else + +struct Node *CreateNodeList(char *name, short graph) +/* create a list of the correct 'shape' of the Node list */ +/* for now, all the records are blank */ +{ + struct objlist *ob; + struct nlist *tp; + struct Node *head, *tail, *new_node; + int maxnode, i; + + /* get a pointer to the cell */ + tp = LookupCellFile(name, graph); + if (tp == NULL) { + Fprintf(stderr, "No cell '%s' found.\n", name); + return(NULL); + } + + /* find the max. node number */ + maxnode = 0; + for (ob = tp->cell; ob != NULL; ob = ob->next) + if (ob->type >= FIRSTPIN && ob->node > maxnode) maxnode = ob->node; + + /* now sequence through these node numbers, looking for existance only */ + head = tail = NULL; + for (i = 1; i <= maxnode; i++) { + new_node = NULL; + for (ob = tp->cell; ob != NULL; ob = ob->next) { + if (ob->type >= FIRSTPIN && ob->node == i) { + struct ElementList *tmp; + if (new_node == NULL) { + /* it is the first */ + new_node = GetNode(); + if (new_node == NULL) { + Fprintf(stderr,"Memory allocation error\n"); +#ifdef DEBUG_ALLOC + PrintCoreStats(); +#endif + ResetState(); + return NULL; + } + /* probably want something like LookupObject(NodeNumber(i)) */ + new_node->object = ob; + new_node->graph = graph; + if (head == NULL) head = new_node; + else tail->next = new_node; + tail = new_node; + } + /* prepend this element to the front of the sublist */ + tmp = GetElementList(); + if (new_node == NULL) { + Fprintf(stderr,"Memory allocation error\n"); +#ifdef DEBUG_ALLOC + PrintCoreStats(); +#endif + ResetState(); + return NULL; + } + tmp->node = new_node; + tmp->next = new_node->elementlist; + new_node->elementlist = tmp; + } + } + } + return (head); +} + +void CreateLists(char *name, short graph) +/* creates two lists of the correct 'shape', then traverses nodes + in sequence to link up 'subelement' field of ElementList, + then 'node' field of NodeList structures. +*/ +{ + struct Element *E, *ElementScan; + struct Node *N, *NodeScan; + struct ElementList *EListScan; + struct NodeList *NListScan; + struct objlist *ob, *obscan; + struct nlist *tp; + int node; + + /* get a pointer to the cell */ + tp = LookupCellFile(name, graph); + if (tp == NULL) { + Fprintf(stderr, "No cell '%s' found.\n", name); + return; + } + + if (Circuit1 == NULL) Circuit1 = tp; + else if (Circuit2 == NULL) Circuit2 = tp; + else { + Fprintf(stderr, "Error: CreateLists() called more than twice without a reset.\n"); + return; + } + + ConnectAllNodes(name, graph); + + E = CreateElementList(name, graph); + N = CreateNodeList(name, graph); + NodeScan = N; + node = 1; + while (NodeScan != NULL) { + int foundone; + + foundone = 0; + /* look for all instances of 'node' */ + EListScan = NodeScan->elementlist; + obscan = NULL; + for (ob = tp->cell; ob != NULL; ob = ob->next) { + if (ob->type == FIRSTPIN) obscan = ob; + + if (ob->node == node && ob->type >= FIRSTPIN) { + struct objlist *tmp; + foundone = 1; + + /* find object in Element list */ + for (ElementScan = E; ElementScan->object != obscan; + ElementScan = ElementScan->next) ; + NListScan = ElementScan->nodelist; + for (tmp = obscan; tmp != ob; tmp = tmp->next) + NListScan = NListScan->next; + + /* write it into the EListScan slot */ + EListScan->subelement = NListScan; + NListScan->node = EListScan->node; + + EListScan = EListScan->next; + } + } + if (foundone) NodeScan = NodeScan->next; /* for non-contiguous nodes */ + node++; + } + Elements = E; + Nodes = N; +} + +#endif /* LOOKUP_INITIALIZATION */ + +int +CheckLegalElementPartition(struct ElementClass *head) +{ + int found; + struct ElementClass *scan; + struct Element *E; + int C1, C2; + + /* now check for bad element classes */ + found = 0; + for (scan = head; scan != NULL; scan = scan->next) { + + if (scan->count == 2) continue; + C1 = C2 = 0; + for (E = scan->elements; E != NULL; E = E->next) { + if (E->graph == Circuit1->file) C1++; + else C2++; + } + scan->count = C1 + C2; + if (C1 != C2) { + found = 1; + BadMatchDetected = 1; + scan->legalpartition = 0; + } + } + return found; +} + + +struct ElementClass *MakeElist(struct Element *E) +/* traverses a list of elements. Puts all elements having the + same hashval into the same class. Returns a pointer to a list + of element classes, each of which contains a list of elements. +*/ +{ + struct ElementClass *head, *new_elementclass, *scan, + *bad_elementclass, *tail; + struct Element *enext; + int found; + + head = NULL; + while (E != NULL) { + found = 0; + enext = E->next; + for (scan = head; scan != NULL && !found; scan = scan->next) + if (scan->magic == E->hashval) { + found = 1; + break; /* get out of for loop without changing scan */ + } + if (!found) { + /* need to create a new one, and prepend to list */ + new_elementclass = GetElementClass(); + if (new_elementclass == NULL) { + Fprintf(stderr,"Memory allocation error\n"); +#ifdef DEBUG_ALLOC + PrintCoreStats(); +#endif + ResetState(); + return NULL; + } + new_elementclass->magic = E->hashval; + new_elementclass->next = head; + head = new_elementclass; + scan = head; + } + /* prepend to list already present */ + E->next = scan->elements; + E->elemclass = scan; + scan->elements = E; + scan->count++; /* just added by MAS */ + + E = enext; + } + + if (!CheckLegalElementPartition(head)) + return(head); /* we are done */ + + /* now regroup all the illegal partitions into a single class */ + bad_elementclass = GetElementClass(); + bad_elementclass->legalpartition = 0; + for (scan = head; scan != NULL; scan = scan->next) { + struct Element *E, *enext; + + if (!(scan->legalpartition)) { + for (E = scan->elements; E != NULL; ) { + enext = E->next; + /* prepend to list already present */ + E->next = bad_elementclass->elements; + E->elemclass = bad_elementclass; + bad_elementclass->elements = E; + bad_elementclass->count++; /* just added by MAS */ + + E = enext; + } + } + } + /* eat all empty element classes */ + tail = bad_elementclass; + for (scan = head; scan != NULL; ) { + struct ElementClass *badclass; + + if (!(scan->legalpartition)) { + badclass = scan; + scan = scan->next; + FreeElementClass(badclass); + } + else { + tail->next = scan; + scan = scan->next; + tail->next->next = NULL; + tail = tail->next; + } + } + head = bad_elementclass; + + if (head->next != NULL) + NewFracturesMade = 1; /* list did fracture into more than one class */ + + + return (head); +} + +int +CheckLegalNodePartition(struct NodeClass *head) +{ + struct NodeClass *scan; + int found; + struct Node *N; + int C1, C2; + + /* now check for bad node classes */ + found = 0; + for (scan = head; scan != NULL; scan = scan->next) { + + if (scan->count == 2) continue; + C1 = C2 = 0; + for (N = scan->nodes; N != NULL; N = N->next) { + if (N->graph == Circuit1->file) C1++; + else C2++; + } + scan->count = C1 + C2; + if (C1 != C2) { + /* we have an illegal partition */ + found = 1; + BadMatchDetected = 1; + scan->legalpartition = 0; + } + } + return found; +} + +struct NodeClass *MakeNlist(struct Node *N) +{ + struct NodeClass *head, *new_nodeclass, *scan, *bad_nodeclass, *tail; + struct Node *nnext; + int found; + + head = NULL; + while (N != NULL) { + found = 0; + nnext = N->next; + for (scan = head; scan != NULL && !found; scan = scan->next) + if (scan->magic == N->hashval) { + found = 1; + break; /* get out of for loop without changing scan */ + } + if (!found) { + /* need to create a new one, and prepend to list */ + new_nodeclass = GetNodeClass(); + if (new_nodeclass == NULL) { + Fprintf(stderr,"Memory allocation error\n"); +#ifdef DEBUG_ALLOC + PrintCoreStats(); +#endif + ResetState(); + return NULL; + } + new_nodeclass->magic = N->hashval; + new_nodeclass->next = head; + head = new_nodeclass; + scan = head; + } + /* prepend to list already present */ + N->next = scan->nodes; + N->nodeclass = scan; + scan->nodes = N; + scan->count++; + + N = nnext; + } + + if (!CheckLegalNodePartition(head)) + return(head); /* we are done */ + + /* now regroup all the illegal partitions into a single class */ + bad_nodeclass = GetNodeClass(); + bad_nodeclass->legalpartition = 0; + for (scan = head; scan != NULL; scan = scan->next) { + struct Node *N, *nnext; + + if (!(scan->legalpartition)) { + for (N = scan->nodes; N != NULL; ) { + nnext = N->next; + /* prepend to list already present */ + N->next = bad_nodeclass->nodes; + N->nodeclass = bad_nodeclass; + bad_nodeclass->nodes = N; + bad_nodeclass->count++; /* just added by MAS */ + + N = nnext; + } + } + } + /* eat all empty element classes */ + tail = bad_nodeclass; + for (scan = head; scan != NULL; ) { + struct NodeClass *badclass; + + if (!(scan->legalpartition)) { + badclass = scan; + scan = scan->next; + FreeNodeClass(badclass); + } + else { + tail->next = scan; + scan = scan->next; + tail->next->next = NULL; + tail = tail->next; + } + } + head = bad_nodeclass; + + if (head->next != NULL) + NewFracturesMade = 1; /* list did fracture into more than one class */ + return (head); +} + + +/* need to choose MAX_RANDOM to fit inside an 'int' field */ +#define MAX_RANDOM (INT_MAX) +/* #define MAX_RANDOM ((1L << 19) - 1) */ + +#define Magic(a) (a = Random(MAX_RANDOM)) +#define MagicSeed(a) RandomSeed(a) + +int FractureElementClass(struct ElementClass **Elist) +/* returns the number of new classes that were created */ +{ + struct ElementClass *Eclass, *Ehead, *Etail, *Enew, *Enext; + + Ehead = Etail = NULL; + /* traverse the list, fracturing as required, and freeing EC to recycle */ + Eclass = *Elist; + while (Eclass != NULL) { + Enext = Eclass->next; + if (Eclass->count != 2 || ExhaustiveSubdivision) { + Enew = MakeElist(Eclass->elements); + FreeElementClass(Eclass); + if (Ehead == NULL) { + Ehead = Etail = Enew; + Magic(Etail->magic); + } + else Etail->next = Enew; + while (Etail->next != NULL) { + Etail = Etail->next; + /* don't forget to assign new magic numbers to the new elements */ + Magic(Etail->magic); + } + } + else { + Enew = Eclass; + Enew->next = NULL; + if (Ehead == NULL) Ehead = Etail = Enew; + else Etail->next = Enew; + Etail = Enew; + } + Eclass = Enext; + } + *Elist = Ehead; + NewNumberOfEclasses = 0; + for (Eclass = *Elist; Eclass != NULL; Eclass = Eclass->next) + NewNumberOfEclasses++; + + if (Debug == TRUE) { + if (Iterations == 0) Fprintf(stdout, "\n"); + Fprintf(stdout, "Iteration: %3d: Element classes = %4d (+%d);", Iterations, + NewNumberOfEclasses, NewNumberOfEclasses - OldNumberOfEclasses); + Ftab(stdout, 50); + } + + /* make the New* things deltas */ + NewNumberOfEclasses -= OldNumberOfEclasses; + OldNumberOfEclasses += NewNumberOfEclasses; + return(NewNumberOfEclasses); +} + +int FractureNodeClass(struct NodeClass **Nlist) +/* returns the number of new classes that were created */ +{ struct NodeClass *Nclass, *Nhead, *Ntail, *Nnew, *Nnext; + Nhead = Ntail = NULL; + /* traverse the list, fracturing as required, and freeing NC to recycle */ + Nclass = *Nlist; + while (Nclass != NULL) { + Nnext = Nclass->next; + if (Nclass->count != 2 || ExhaustiveSubdivision) { + Nnew = MakeNlist(Nclass->nodes); + FreeNodeClass(Nclass); + if (Nhead == NULL) { + Nhead = Ntail = Nnew; + Magic(Ntail->magic); + } + else Ntail->next = Nnew; + while (Ntail->next != NULL) { + Ntail = Ntail->next; + /* don't forget to assign new magic numbers to the new elements */ + Magic(Ntail->magic); + } + } + else { + Nnew = Nclass; + Nnew->next = NULL; + if (Nhead == NULL) Nhead = Ntail = Nnew; + else Ntail->next = Nnew; + Ntail = Nnew; + } + Nclass = Nnext; + } + *Nlist = Nhead; + NewNumberOfNclasses = 0; + for (Nclass = *Nlist; Nclass != NULL; Nclass = Nclass->next) + NewNumberOfNclasses++; + + if (Debug == TRUE) { + Fprintf(stdout, "Net groups = %4d (+%d)\n", + NewNumberOfNclasses, NewNumberOfNclasses - OldNumberOfNclasses); + } + + /* make the New* things deltas */ + NewNumberOfNclasses -= OldNumberOfNclasses; + OldNumberOfNclasses += NewNumberOfNclasses; + return(NewNumberOfNclasses); +} + +/* Structure used by lookupclass */ + +typedef struct _chd { + int file; + unsigned long classhash; +} chdata; + +/*----------------------------------------------------------------------*/ +/* Callback function used by LookupClassEquivalent */ +/*----------------------------------------------------------------------*/ + +struct nlist *lookupclass(struct hashlist *p, void *clientdata) +{ + struct nlist *ptr; + chdata *chd = (chdata *)clientdata; + + ptr = (struct nlist *)(p->ptr); + + if (ptr->file == chd->file) + if (ptr->classhash == chd->classhash) + return ptr; + + return NULL; +} + +/*----------------------------------------------------------------------*/ +/* Given the class (cellname) "model" in file "file1", find the */ +/* equivalent class in "file2". This is done by exhaustively searching */ +/* the cell database for a matching classhash number. It is therefore */ +/* not intended to be run often; it should be only run when choosing */ +/* two cells to compare. */ +/*----------------------------------------------------------------------*/ + +struct nlist *LookupClassEquivalent(char *model, int file1, int file2) +{ + struct nlist *tp, *tp2; + chdata chd; + + tp = LookupCellFile(model, file1); + if (tp == NULL) return NULL; + + chd.file = file2; + chd.classhash = tp->classhash; + + tp2 = RecurseCellHashTable2(lookupclass, (void *)(&chd)); + return tp2; +} + +/*----------------------------------------------------------------------*/ +/* Look up the cell in file2 which has been specified as a match for */ +/* cell tc1 using the "equate classes" command. If there is no match, */ +/* then return NULL. If there is a match, then set the classhash */ +/* values to be equal to each other. */ +/*----------------------------------------------------------------------*/ + +struct nlist *LookupPrematchedClass(struct nlist *tc1, int file2) +{ + struct Correspond *crec; + struct nlist *tc2; + + for (crec = ClassCorrespondence; crec != NULL; crec = crec->next) { + if (crec->file1 == tc1->file) { + if ((*matchfunc)(tc1->name, crec->class1)) + if (crec->file2 == file2 || crec->file2 == -1) + tc2 = LookupCellFile(crec->class2, file2); + } + else if (crec->file1 == file2) { + if ((*matchfunc)(tc1->name, crec->class2)) + if (crec->file2 == tc1->file || crec->file2 == -1) + tc2 = LookupCellFile(crec->class1, file2); + } + else if (crec->file2 == tc1->file) { + if ((*matchfunc)(tc1->name, crec->class2)) + if (crec->file1 == -1) + tc2 = LookupCellFile(crec->class1, file2); + } + else if (crec->file2 == file2) { + if ((*matchfunc)(tc1->name, crec->class1)) + if (crec->file1 == -1) + tc2 = LookupCellFile(crec->class2, file2); + } + else if (crec->file1 == -1 && crec->file2 == -1) { + if ((*matchfunc)(tc1->name, crec->class1)) + tc2 = LookupCell(crec->class2); + else if ((*matchfunc)(tc1->name, crec->class2)) + tc2 = LookupCell(crec->class1); + } + } + if (tc2 != NULL) tc2->classhash = tc1->classhash; + return tc2; +} + +/*----------------------------------------------------------------------*/ +/* Attempt to define FirstElementPass that will generate element */ +/* classes by names of pins, which will allow elements with different */ +/* cell names in different circuits to be grouped. Ultimately we want */ +/* a solution that allows classes to be forced to be equated. */ +/* */ +/* During the pass, element lists are checked for subcircuits that have */ +/* no equivalent in the other circuit. If so, they are marked for */ +/* flattening by setting the hashval entry to -1 and the routine */ +/* returns -1. If every cell had at least one match, or all non- */ +/* matching cells were fundamental devices or black-box subcircuits, */ +/* then the setup for comparison continues, and the routine returns 0. */ +/* However, if "noflat" is set to 1, then the circuits are compared */ +/* as-is, even if one or more non-matching elements could be flattened. */ +/*----------------------------------------------------------------------*/ + +int FirstElementPass(struct Element *E, int noflat) +{ + struct Element *Esrch, *Ecorr; + struct NodeList *n; + struct nlist *tp1, *tp2, *tp; + int C1, C2, i; + char ostr[89]; + int needflat = 0; + + if (Debug == 0) { + Fprintf(stdout, "\nSubcircuit summary:\n"); + *(ostr + 43) = '|'; + *(ostr + 87) = '\n'; + *(ostr + 88) = '\0'; + for (i = 0; i < 43; i++) *(ostr + i) = ' '; + for (i = 44; i < 87; i++) *(ostr + i) = ' '; + + snprintf(ostr, 43, "Circuit 1: %s", Circuit1->name); + snprintf(ostr + 44, 43, "Circuit 2: %s", Circuit2->name); + for (i = 0; i < 88; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' '; + Fprintf(stdout, ostr); + for (i = 0; i < 43; i++) *(ostr + i) = '-'; + for (i = 44; i < 87; i++) *(ostr + i) = '-'; + Fprintf(stdout, ostr); + } + + // Print side-by-side comparison of elements based on class correspondence + // Use the hashval record to mark what entries have been processed already. + + for (Esrch = E; Esrch != NULL; Esrch = Esrch->next) { + if (Esrch->graph == Circuit1->file && Esrch->hashval == 0) { + Esrch->hashval = 1; + C1 = 1; + C2 = 0; + tp1 = LookupCellFile(Esrch->object->model.class, Circuit1->file); + tp2 = LookupClassEquivalent(Esrch->object->model.class, Circuit1->file, + Circuit2->file); + for (Ecorr = E; Ecorr != NULL; Ecorr = Ecorr->next) { + if (Ecorr->hashval == 0) { + if (Ecorr->graph == Circuit2->file) { + tp = LookupCellFile(Ecorr->object->model.class, Circuit2->file); + if (tp == tp2) { + Ecorr->hashval = 1; + C2++; + } + } + else if (Ecorr->graph == Circuit1->file) { + tp = LookupCellFile(Ecorr->object->model.class, Circuit1->file); + if (tp == tp1) { + Ecorr->hashval = 1; + C1++; + } + } + } + } + + if (C2 == 0) + if (tp1->class == CLASS_SUBCKT) + if (!noflat) { + Esrch->hashval = -1; /* Mark for flattening */ + needflat = 1; + } + + if (Debug == 0) { + + for (i = 0; i < 43; i++) *(ostr + i) = ' '; + for (i = 44; i < 87; i++) *(ostr + i) = ' '; + snprintf(ostr, 43, "%s (%d)", Esrch->object->model.class, C1); + if (C2 > 0) + snprintf(ostr + 44, 43, "%s (%d)%s", tp2->name, C2, + (C2 == C1) ? "" : " **Mismatch**"); + else { + snprintf(ostr + 44, 43, "(no matching element)"); + } + for (i = 0; i < 88; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' '; + Fprintf(stdout, ostr); + } + } + } + for (Esrch = E; Esrch != NULL; Esrch = Esrch->next) { + if (Esrch->graph == Circuit2->file && Esrch->hashval == 0) { + Esrch->hashval = 1; + C2 = 1; + tp2 = LookupCellFile(Esrch->object->model.class, Circuit2->file); + tp1 = LookupClassEquivalent(Esrch->object->model.class, Circuit2->file, + Circuit1->file); + for (Ecorr = E; Ecorr != NULL; Ecorr = Ecorr->next) { + if (Ecorr->hashval == 0) { + if (Ecorr->graph == Circuit2->file) { + tp = LookupCellFile(Ecorr->object->model.class, Circuit2->file); + if (tp == tp2) { + Ecorr->hashval = 1; + C2++; + } + } + } + } + + if (tp2->class == CLASS_SUBCKT) + if (!noflat) { + Esrch->hashval = -1; /* Mark for flattening */ + needflat = 1; + } + + if (Debug == 0) { + for (i = 0; i < 43; i++) *(ostr + i) = ' '; + for (i = 44; i < 87; i++) *(ostr + i) = ' '; + snprintf(ostr, 43, "(no matching element)"); + snprintf(ostr + 44, 43, "%s (%d)", Esrch->object->model.class, C2); + for (i = 0; i < 88; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' '; + Fprintf(stdout, ostr); + } + } + } + + C1 = C2 = 0; + while (E != NULL) { + + /* initialize random no. gen. to model-specific number */ + tp = LookupCellFile(E->object->model.class, E->graph); + MagicSeed(tp->classhash); + + for (n = E->nodelist; n != NULL; n = n->next) + Magic(n->pin_magic); + + E->hashval = tp->classhash; + if (E->graph == Circuit1->file) C1++; + else C2++; + E = E->next; + } + if (Debug == TRUE) { + if (C1 != C2) + Fprintf(stderr, "Device Mismatch: Circuit 1 has %d, Circuit 2 has %d.\n", + C1, C2); + } + else { + for (i = 0; i < 43; i++) *(ostr + i) = ' '; + for (i = 44; i < 87; i++) *(ostr + i) = ' '; + snprintf(ostr, 43, "Number of devices: %d%s", C1, (C1 == C2) ? "" : + " **Mismatch**"); + snprintf(ostr + 44, 43, "Number of devices: %d%s", C2, (C1 == C2) ? "" : + " **Mismatch**"); + for (i = 0; i < 88; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' '; + Fprintf(stdout, ostr); + } + + return 0; +} + +void FirstNodePass(struct Node *N) +{ + struct ElementList *E; + int fanout; + int C1, C2; + + C1 = C2 = 0; + while (N != NULL) { + fanout = 0; + for (E = N->elementlist; E != NULL; E = E->next) fanout++; + N->hashval = fanout; + if (N->graph == Circuit1->file) C1++; + else C2++; + N = N->next; + } + if (Debug == TRUE) { + if (C1 != C2) + Fprintf(stderr, "Net Mismatch: Circuit 1 has %d, Circuit 2 has %d.\n",C1,C2); + } + else { + char ostr[89]; + int i; + + *(ostr + 43) = '|'; + *(ostr + 87) = '\n'; + *(ostr + 88) = '\0'; + + for (i = 0; i < 43; i++) *(ostr + i) = ' '; + for (i = 44; i < 87; i++) *(ostr + i) = ' '; + snprintf(ostr, 43, "Number of nets: %d%s", C1, (C1 == C2) ? "" : + " **Mismatch**"); + snprintf(ostr + 44, 43, "Number of nets: %d%s", C2, (C1 == C2) ? "" : + " **Mismatch**"); + for (i = 0; i < 88; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' '; + Fprintf(stdout, ostr); + + for (i = 0; i < 87; i++) *(ostr + i) = '-'; + Fprintf(stdout, ostr); + } +} + +/*--------------------------------------------------------------*/ +/* Declare cells to be non-matching by clearing the */ +/* CELL_MATCHED flag in both cells. This will force cell */ +/* flattening during hierarchical LVS. */ +/*--------------------------------------------------------------*/ + +void MatchFail(char *name1, char *name2) +{ + struct nlist *tc1, *tc2; + + tc1 = LookupCell(name1); + tc2 = LookupCell(name2); + + tc1->flags &= ~CELL_MATCHED; + tc2->flags &= ~CELL_MATCHED; +} + +/*--------------------------------------------------------------*/ + +int FlattenUnmatched(struct nlist *tc, char *parent, int stoplevel, int loclevel) +{ + struct nlist *tcsub; + struct objlist *ob; + int changed = 0; + + if (loclevel == stoplevel && !(tc->flags & CELL_MATCHED)) { + ClearDumpedList(); + if (Debug == TRUE) Fprintf(stdout, "Level %d ", loclevel); + Fprintf(stdout, "Flattening unmatched subcell %s in circuit %s ", + tc->name, parent); + changed = flattenInstancesOf(parent, tc->file, tc->name); + Fprintf(stdout, "(%d instances)\n", changed); + return 1; + } + + if (tc->cell == NULL) return 0; + + changed = 1; + while (changed) { + for (ob = tc->cell; ob != NULL; ob = ob->next) { + changed = 0; + tcsub = NULL; + if (ob->type == FIRSTPIN) { + /* First check if there is a class equivalent */ + tcsub = LookupCellFile(ob->model.class, tc->file); + if (!tcsub || (tcsub->class != CLASS_SUBCKT)) continue; + else if (tcsub == tc) continue; + if (FlattenUnmatched(tcsub, tc->name, stoplevel, loclevel + 1)) { + changed = 1; + break; + } + } + } + } + + return 0; +} + +/*--------------------------------------------------------------*/ + +void DescendCountQueue(struct nlist *tc, int *level, int loclevel) +{ + struct nlist *tcsub; + struct objlist *ob; + + if (loclevel > *level) *level = loclevel; + + for (ob = tc->cell; ob != NULL; ob = ob->next) { + tcsub = NULL; + if (ob->type == FIRSTPIN) { + /* First check if there is a class equivalent */ + tcsub = LookupCellFile(ob->model.class, tc->file); + if (!tcsub || (tcsub->class != CLASS_SUBCKT)) continue; + else if (tcsub == tc) continue; + DescendCountQueue(tcsub, level, loclevel + 1); + } + } +} + +/*--------------------------------------------------------------*/ + +void DescendCompareQueue(struct nlist *tc, struct nlist *tctop, int stoplevel, + int loclevel, int flip) +{ + struct nlist *tcsub, *tc2; + struct objlist *ob; + struct Correspond *scomp, *newcomp; + + if (loclevel == stoplevel && !(tc->flags & CELL_MATCHED)) { + + // Find exact-name equivalents or cells that have been specified + // as equivalent using the "equate class" command. + + tc2 = LookupClassEquivalent(tc->name, tc->file, tctop->file); + if (tc2 == NULL) { + // Check if cell names were forced to be matched using the + // "equate classes" command. + tc2 = LookupPrematchedClass(tc, tctop->file); + } + if (tc2 != NULL) { + newcomp = (struct Correspond *)CALLOC(1, sizeof(struct Correspond)); + newcomp->next = NULL; + if (flip) { + newcomp->class1 = tc2->name; + newcomp->file1 = tc2->file; + newcomp->class2 = tc->name; + newcomp->file2 = tc->file; + } + else { + newcomp->class1 = tc->name; + newcomp->file1 = tc->file; + newcomp->class2 = tc2->name; + newcomp->file2 = tc2->file; + } + + if (Debug == TRUE) + Fprintf(stdout, "Level %d Appending %s %s to compare queue\n", + loclevel, tc->name, tc2->name); + + /* Add this pair to the end of the list of cells to compare */ + if (CompareQueue == NULL) + CompareQueue = newcomp; + else { + for (scomp = CompareQueue; scomp->next; scomp = scomp->next); + scomp->next = newcomp; + } + tc->flags |= CELL_MATCHED; + tc2->flags |= CELL_MATCHED; + } + else if (Debug == TRUE) + Fprintf(stdout, "Level %d Class %s is unmatched and will be flattened\n", + loclevel, tc->name); + return; + } + + /* Now work through the subcircuits of tc */ + + for (ob = tc->cell; ob != NULL; ob = ob->next) { + tcsub = NULL; + if (ob->type == FIRSTPIN) { + tcsub = LookupCellFile(ob->model.class, tc->file); + if (!tcsub || (tcsub->class != CLASS_SUBCKT)) continue; + else if (tcsub == tc) continue; + DescendCompareQueue(tcsub, tctop, stoplevel, loclevel + 1, flip); + } + } +} + +/*--------------------------------------------------------------*/ +/* Routine that assigns Circuit1 and Circuit2. This will be */ +/* done by CreateLists, but doing it earlier allows one to use */ +/* the names "-circuit1" and "-circuit2" in the setup file. */ +/*--------------------------------------------------------------*/ + +void AssignCircuits(char *name1, int file1, char *name2, int file2) +{ + struct nlist *tc1, *tc2; + + tc1 = LookupCellFile(name1, file1); + tc2 = LookupCellFile(name2, file2); + + if (tc1 != NULL) Circuit1 = tc1; + if (tc2 != NULL) Circuit2 = tc2; +} + +/*--------------------------------------------------------------*/ +/* Parse the top-level cells for hierarchical structure, and */ +/* generate a stack of cells to compare. This is done */ +/* carefully from bottom up so as to raise the likelihood that */ +/* we are comparing two circuits that really are supposed to */ +/* be equivalent. Comparisons are then done from bottom up so */ +/* that anything that isn't matched can be flattened as we go; */ +/* in the worst case, if no subcells can be definitively */ +/* matched, then we will end up running a comparison on two */ +/* completely flattened netlists. */ +/* */ +/* Return 0 on success, 1 on failure to look up cell name1, */ +/* and 2 on failure to look up cell name2. */ +/*--------------------------------------------------------------*/ + + +int CreateCompareQueue(char *name1, int file1, char *name2, int file2) +{ + struct nlist *tc1, *tc2, *tcsub1, *tcsub2; + struct Correspond *newcomp, *scomp; + int level; + + tc1 = LookupCellFile(name1, file1); + tc2 = LookupCellFile(name2, file2); + + if (tc1 == NULL) return 1; + if (tc2 == NULL) return 2; + + level = 0; + + /* Recurse the hierarchies of tc1 and tc2 and find the deepest level */ + DescendCountQueue(tc1, &level, 0); + DescendCountQueue(tc2, &level, 0); + + /* Starting at the deepest level, compare each circuit to the other */ + /* When each level has put as many cells as it can find on the */ + /* compare queue, then flatten all the unmatched cells in that level */ + + while (level > 0) { + if (Debug == TRUE) + Fprintf(stdout, "Descend level %d circuit 1\n", level); + DescendCompareQueue(tc1, tc2, level, 0, 0); + if (Debug == TRUE) + Fprintf(stdout, "Descend level %d circuit 2\n", level); + DescendCompareQueue(tc2, tc1, level, 0, 1); + + if (Debug == TRUE) + Fprintf(stdout, "Flatten level %d circuit 1\n", level); + FlattenUnmatched(tc1, name1, level, 0); + if (Debug == TRUE) + Fprintf(stdout, "Flatten level %d circuit 2\n", level); + FlattenUnmatched(tc2, name2, level, 0); + level--; + } + + /* Add the topmost cells to the end of the compare queue */ + + newcomp = (struct Correspond *)CALLOC(1, sizeof(struct Correspond)); + newcomp->next = NULL; + newcomp->class1 = tc1->name; + newcomp->file1 = tc1->file; + newcomp->class2 = tc2->name; + newcomp->file2 = tc2->file; + + if (CompareQueue == NULL) + CompareQueue = newcomp; + else { + for (scomp = CompareQueue; scomp->next; scomp = scomp->next); + scomp->next = newcomp; + } + + tc1->flags |= CELL_MATCHED; + tc2->flags |= CELL_MATCHED; + + return 0; +} + +/*----------------------------------------------*/ +/* Read the top of the compare queue, but do */ +/* not alter the stack. */ +/*----------------------------------------------*/ + +int PeekCompareQueueTop(char **name1, int *file1, char **name2, int *file2) +{ + if (CompareQueue == NULL) + return -1; + + *name1 = CompareQueue->class1; + *file1 = CompareQueue->file1; + *name2 = CompareQueue->class2; + *file2 = CompareQueue->file2; + + return 0; +} + +/*----------------------------------------------*/ +/* Return the top of the compare queue stack, */ +/* and pop the topmost entry. Return 0 on */ +/* success, -1 if the compare queue is empty. */ +/*----------------------------------------------*/ + +int GetCompareQueueTop(char **name1, int *file1, char **name2, int *file2) +{ + struct Correspond *nextcomp; + + if (PeekCompareQueueTop(name1, file1, name2, file2) < 0) + return -1; + + nextcomp = CompareQueue->next; + FREE(CompareQueue); + CompareQueue = nextcomp; + return 0; +} + +/*--------------------------------------*/ +/* Delete the comparison queue */ +/*--------------------------------------*/ + +void RemoveCompareQueue() +{ + struct Correspond *comp, *nextcomp; + + for (comp = CompareQueue; comp != NULL;) { + nextcomp = comp->next; + FREE(comp); + comp = nextcomp; + } + CompareQueue = NULL; +} + +/*----------------------------------*/ +/* create an initial data structure */ +/*----------------------------------*/ + +void CreateTwoLists(char *name1, int file1, char *name2, int file2) +{ + struct Element *El1; + struct Node *N1; + struct nlist *tc1, *tc2, *tcf; + + ResetState(); + + /* print preliminary statistics */ + Printf("Contents of circuit 1: "); + DescribeInstance(name1, file1); + Printf("Contents of circuit 2: "); + DescribeInstance(name2, file2); + Printf("\n"); + + if (file1 == -1) + tc1 = LookupCell(name1); + else + tc1 = LookupCellFile(name1, file1); + + if (file2 == -1) + tc2 = LookupCell(name2); + else + tc2 = LookupCellFile(name2, file2); + + /* determine if matching will be case sensitive or case insensitive */ + matchfunc = match; + matchintfunc = matchfile; + hashfunc = hash; + if (tc1 != NULL && tc2 != NULL) { + if ((tc1->flags & CELL_NOCASE) && (tc2->flags & CELL_NOCASE)) { + matchfunc = matchnocase; + matchintfunc = matchfilenocase; + hashfunc = hashnocase; + } + } + + CreateLists(name1, file1); + if (Elements == NULL) { + Printf("Circuit %s contains no devices.\n", name1); + return; + } + if (Nodes == NULL) { + Printf("Circuit %s contains no nets.\n", name1); + return; + } + + ElementClasses = GetElementClass(); + if (ElementClasses == NULL) { + Fprintf(stderr, "Memory allocation error\n"); +#ifdef DEBUG_ALLOC + PrintCoreStats(); +#endif + ResetState(); + return; + } + ElementClasses->elements = Elements; + Magic(ElementClasses->magic); + + for (El1 = Elements; El1->next != NULL; El1 = El1->next) { + El1->elemclass = ElementClasses; + } + /* El1 now points to last element of list */ + + NodeClasses = GetNodeClass(); + if (NodeClasses == NULL) { + Fprintf(stderr,"Memory allocation error\n"); +#ifdef DEBUG_ALLOC + PrintCoreStats(); +#endif + ResetState(); + return; + } + NodeClasses->nodes = Nodes; + Magic(NodeClasses->magic); + + for (N1 = Nodes; N1->next != NULL; N1 = N1->next) { + N1->nodeclass = NodeClasses; + } + /* N1 now points to last element of list */ + + + CreateLists(name2, file2); + if (Elements == NULL) { + Printf("Circuit %s contains no devices.\n", name2); + ResetState(); + return; + } + + if (Nodes == NULL) { + Printf("Circuit %s contains no nets.\n", name2); + ResetState(); + return; + } + + /* splice new lists into existing lists */ + El1->next = Elements; + for (El1 = Elements; El1->next != NULL; El1 = El1->next) { + El1->elemclass = ElementClasses; + } + + N1->next = Nodes; + for (N1 = Nodes; N1->next != NULL; N1 = N1->next) { + N1->nodeclass = NodeClasses; + } + + /* print preliminary statistics */ + SummarizeDataStructures(); + + /* perform first set of fractures */ + FirstElementPass(ElementClasses->elements, FALSE); + + FirstNodePass(NodeClasses->nodes); + FractureElementClass(&ElementClasses); + FractureNodeClass(&NodeClasses); +} + +void RegroupDataStructures(void) +{ + struct ElementClass *EC; + struct Element *El1, *Etail; + struct NodeClass *NC; + struct Node *N1, *Ntail; + + + if (ElementClasses == NULL || NodeClasses == NULL) { + Fprintf(stderr, "Need to initialize data structures first!\n"); + return; + } + + Elements = Etail = NULL; + for (EC = ElementClasses; EC != NULL; ) { + struct ElementClass *ECnext; + ECnext = EC->next; + if (Elements == NULL) Elements = EC->elements; + else Etail->next = EC->elements; + for (El1= EC->elements; El1 != NULL && El1->next != NULL; El1 = El1->next); + Etail = El1; + FreeElementClass(EC); + EC = ECnext; + } + + ElementClasses = GetElementClass(); + if (ElementClasses == NULL) { + Fprintf(stderr,"Memory allocation error\n"); +#ifdef DEBUG_ALLOC + PrintCoreStats(); +#endif + ResetState(); + return; + } + ElementClasses->elements = Elements; + + for (El1 = Elements; El1->next != NULL; El1 = El1->next) { + El1->elemclass = ElementClasses; + } + /* El1 now points to last element of list */ + + + Nodes = Ntail = NULL; + for (NC = NodeClasses; NC != NULL; ) { + struct NodeClass *NCnext; + NCnext = NC->next; + if (Nodes == NULL) Nodes = NC->nodes; + else Ntail->next = NC->nodes; + for (N1 = NC->nodes; N1 != NULL && N1->next != NULL; N1 = N1->next); + Ntail = N1; + FreeNodeClass(NC); + NC = NCnext; + } + + + NodeClasses = GetNodeClass(); + if (NodeClasses == NULL) { + Fprintf(stderr,"Memory allocation error\n"); +#ifdef DEBUG_ALLOC + PrintCoreStats(); +#endif + ResetState(); + return; + } + NodeClasses->nodes = Nodes; + + for (N1 = Nodes; N1->next != NULL; N1 = N1->next) { + N1->nodeclass = NodeClasses; + } + + /* reset magic numbers */ + NewNumberOfEclasses = OldNumberOfEclasses = 0; + NewNumberOfNclasses = OldNumberOfNclasses = 0; + Iterations = 0; + + /* perform first set of fractures */ + FirstElementPass(ElementClasses->elements, TRUE); + FirstNodePass(NodeClasses->nodes); + FractureElementClass(&ElementClasses); + FractureNodeClass(&NodeClasses); +} + +unsigned long ElementHash(struct Element *E) +{ + struct NodeList *N; + unsigned long hashval = 0; + + for (N = E->nodelist; N != NULL; N = N->next) + if (N->node != NULL) + hashval += (N->pin_magic ^ N->node->nodeclass->magic); + + // Added by Tim 10/10/2012. Cannot ignore own hashval, or else + // two instances of different cells can be swapped and although + // the netlist will report as not matching, the illegal partition + // will be recast as legal, and no information will be generated + // about the mismatched elements. + hashval ^= E->hashval; + + return(hashval); +} + +unsigned long NodeHash(struct Node *N) +{ + struct ElementList *E; + unsigned long hashval = 0; + + for (E = N->elementlist; E != NULL; E = E->next) + hashval += (E->subelement->pin_magic ^ + E->subelement->element->hashval ^ // Added by Tim + E->subelement->element->elemclass->magic); + + return(hashval); +} + +int Iterate(void) +/* does one iteration, and returns TRUE if we are done */ +{ + int notdone; + struct ElementClass *EC; + struct NodeClass *NC; + + if (ElementClasses == NULL || NodeClasses == NULL) { + Fprintf(stderr, "Need to initialize data structures first!\n"); + return(1); + } + + for (EC = ElementClasses; EC != NULL; EC = EC->next) + Magic(EC->magic); + for (NC = NodeClasses; NC != NULL; NC = NC->next) + Magic(NC->magic); + + Iterations++; + NewFracturesMade = 0; + + for (EC = ElementClasses; EC != NULL; EC = EC->next) { + struct Element *E; + for (E = EC->elements; E != NULL; E = E->next) + E->hashval = ElementHash(E); + + // Check for partitions of two elements, not balanced + if (EC->count == 2 && EC->elements->graph == + EC->elements->next->graph) + EC->legalpartition = 0; + } + + notdone = FractureElementClass(&ElementClasses); + + for (NC = NodeClasses; NC != NULL; NC = NC->next) { + struct Node *N; + for (N = NC->nodes; N != NULL; N = N->next) + N->hashval = NodeHash(N); + + // Check for partitions of two nodes, not balanced + if (NC->count == 2 && NC->nodes->graph == + NC->nodes->next->graph) + NC->legalpartition = 0; + } + notdone = notdone | FractureNodeClass(&NodeClasses); + + +#if 0 + if (NewFracturesMade) Printf("New fractures made; "); + else Printf("No new fractures made; "); + if (BadMatchDetected) Printf("Matching error has been detected."); + if (PropertyErrorDetected) Printf("Property error has been detected."); + Printf("\n"); +#endif + + return(!notdone); +} + +/*--------------------------------------------------------------*/ +/* Compare the properties of two objects. The passed values */ +/* ob1 and ob2 are pointers to the first entry (firstpin) of */ +/* each object. */ +/* */ +/* Return -1 on complete failure (should not happen), or */ +/* return the number of mismatched properties (0 = perfect */ +/* match of all properties, or there were no properties to */ +/* compare). */ +/*--------------------------------------------------------------*/ + +int PropertyMatch(struct objlist *ob1, struct objlist *ob2, int do_print) +{ + struct nlist *tc1, *tc2; + struct objlist *tp1, *tp2; + char *key1, *key2; + struct property *kl1, *kl2; + struct valuelist *vl1, *vl2; + int mismatches = 0, i, j; + int vlstart, islop, t1type, t2type; + int mult1, mult2, ival1, ival2; + double pd, dslop, dval1, dval2; + + tc1 = LookupCellFile(ob1->model.class, Circuit1->file); + tc2 = LookupCellFile(ob2->model.class, Circuit2->file); + + if (tc1->classhash != tc2->classhash) return -1; + + for (tp1 = ob1; (tp1 != NULL) && tp1->type >= FIRSTPIN; tp1 = tp1->next); + for (tp2 = ob2; (tp2 != NULL) && tp2->type >= FIRSTPIN; tp2 = tp2->next); + + /* Check if there are any properties to match */ + + if ((tp1 == NULL) && (tp2 == NULL)) return 0; + if (tp1 != NULL) t1type = tp1->type; + if (tp2 != NULL) t2type = tp2->type; + + if (tp1 == NULL) + if (t2type != PROPERTY) return 0; + + if (tp2 == NULL) + if (t1type != PROPERTY) return 0; + + // Sanity check---shouldn't happen + if ((t1type == PROPERTY) && (tp1->instance.props == NULL)) t1type = UNKNOWN; + if ((t2type == PROPERTY) && (tp2->instance.props == NULL)) t2type = UNKNOWN; + + if ((t1type != PROPERTY) && (t2type != PROPERTY)) return 0; + + if (t1type != PROPERTY) { + // t1 has no properties. See if t2's properties are required + // to be checked. If so, flag t1 as missing required properties + + for (i = 0;; i++) { + vl2 = &(tp2->instance.props[i]); + if (vl2->type == PROP_ENDLIST) break; + if (vl2 == NULL) continue; + if (vl2->key == NULL) continue; + kl2 = (struct property *)HashLookup(vl2->key, tc2->proptab, OBJHASHSIZE); + if (kl2 != NULL) break; // Property is required + else if ((*matchfunc)(vl2->key, "M")) { + if (vl2->type == PROP_INTEGER) + mult2 = vl2->value.ival; + } + } + if (vl2->type != PROP_ENDLIST) { + if (do_print) Fprintf(stdout, "Circuit 2 %s instance %s does not" + " define required properties.\n", + Circuit2->name, ob2->instance.name); + return -1; + } + else + return 0; + } + else if (t2type != PROPERTY) { + // t2 has no properties. See if t1's properties are required + // to be checked. If so, flag t1 as missing required properties + + for (i = 0;; i++) { + vl1 = &(tp1->instance.props[i]); + if (vl1->type == PROP_ENDLIST) break; + if (vl1 == NULL) continue; + if (vl1->key == NULL) continue; + kl1 = (struct property *)HashLookup(vl1->key, tc1->proptab, OBJHASHSIZE); + if (kl1 != NULL) break; // Property is required + else if ((*matchfunc)(vl1->key, "M")) { + if (vl1->type == PROP_INTEGER) + mult1 = vl1->value.ival; + } + } + if (vl1->type != PROP_ENDLIST) { + if (do_print) Fprintf(stdout, "Circuit 1 %s instance %s does not" + " define required properties.\n", + Circuit1->name, ob1->instance.name); + return -1; + } + else + return 0; + } + + vlstart = 0; + for (i = 0;; i++) { + vl1 = &(tp1->instance.props[i]); + if (vl1->type == PROP_ENDLIST) break; + if (vl1 == NULL) continue; + if (vl1->key == NULL) continue; + + /* Check if this is a "property of interest". */ + kl1 = (struct property *)HashLookup(vl1->key, tc1->proptab, OBJHASHSIZE); + if (kl1 == NULL) continue; + + /* Find the matching property in vl2. With luck, they're in order. */ + + for (j = vlstart;; j++) { + vl2 = &(tp2->instance.props[j]); + if (vl2->type == PROP_ENDLIST) break; + if ((*matchfunc)(vl1->key, vl2->key)) break; + } + if (vl2->type == PROP_ENDLIST) continue; + if (j == vlstart) vlstart++; + + if (vl2 == NULL) continue; + if (vl2->key == NULL) continue; + + /* Both device classes must agree on the properties to compare */ + kl2 = (struct property *)HashLookup(vl2->key, tc2->proptab, OBJHASHSIZE); + if (kl2 == NULL) continue; + + if (vl1->type != vl2->type) { + if (kl1->type != vl1->type) PromoteProperty(kl1, vl1); + if (kl2->type != vl2->type) PromoteProperty(kl2, vl2); + if (vl1->type != vl2->type) PromoteProperty(kl1, vl2); + if (vl1->type != vl2->type) PromoteProperty(kl2, vl1); + if (do_print && (vl1->type != vl2->type)) { + if (mismatches == 0) + Fprintf(stdout, "%s vs. %s:\n", + ob1->instance.name, ob2->instance.name); + + Fprintf(stdout, " %s circuit1: ", kl1->key); + switch (vl1->type) { + case PROP_DOUBLE: + case PROP_VALUE: + Fprintf(stdout, "%g", vl1->value.dval); + break; + case PROP_INTEGER: + Fprintf(stdout, "%d", vl1->value.ival); + break; + case PROP_STRING: + Fprintf(stdout, "\"%s\"", vl1->value.string); + break; + case PROP_EXPRESSION: + Fprintf(stdout, "(unresolved expression)"); + break; + } + Fprintf(stdout, " "); + switch (vl2->type) { + case PROP_DOUBLE: + case PROP_VALUE: + Fprintf(stdout, "%g", vl2->value.dval); + break; + case PROP_INTEGER: + Fprintf(stdout, "%d", vl2->value.ival); + break; + case PROP_STRING: + Fprintf(stdout, "\"%s\"", vl2->value.string); + break; + case PROP_EXPRESSION: + Fprintf(stdout, "(unresolved expression)"); + break; + } + Fprintf(stdout, " (property type mismatch)\n"); + } + if (vl1->type != vl2->type) mismatches++; + } + else switch (kl1->type) { + case PROP_DOUBLE: + case PROP_VALUE: + dval1 = vl1->value.dval; + dval2 = vl2->value.dval; + + dslop = MAX(kl1->slop.dval, kl2->slop.dval); + pd = 2 * fabs(dval1 - dval2) / (dval1 + dval2); + if (pd > dslop) { + if (do_print) { + if (mismatches == 0) + Fprintf(stdout, "%s vs. %s:\n", + ob1->instance.name, ob2->instance.name); + Fprintf(stdout, " %s circuit1: %g circuit2: %g ", + kl1->key, dval1, dval2); + if (vl1->value.dval > 0.0 && vl2->value.dval > 0.0) + Fprintf(stdout, "(delta=%.3g%%, cutoff=%.3g%%)\n", + 100 * pd, 100 * dslop); + else + Fprintf(stdout, "\n"); + } + mismatches++; + } + break; + case PROP_INTEGER: + ival1 = vl1->value.ival; + ival2 = vl2->value.ival; + + islop = MAX(kl1->slop.ival, kl2->slop.ival); + if (abs(ival1 - ival2) > islop) { + if (do_print) { + if (mismatches == 0) + Fprintf(stdout, "%s vs. %s:\n", + ob1->instance.name, ob2->instance.name); + Fprintf(stdout, " %s circuit1: %d circuit2: %d ", + kl1->key, ival1, ival2); + if (ival1 > 0 && ival2 > 0) + Fprintf(stdout, "(delta=%d, cutoff=%d)\n", + abs(ival1 - ival2), islop); + else + Fprintf(stdout, "\n"); + } + mismatches++; + } + break; + case PROP_STRING: + islop = MAX(kl1->slop.ival, kl2->slop.ival); + if (islop == 0) { + if (strcasecmp(vl1->value.string, vl2->value.string)) { + if (do_print) { + if (mismatches == 0) + Fprintf(stdout, "%s vs. %s:\n", + ob1->instance.name, ob2->instance.name); + Fprintf(stdout, " %s circuit1: \"%s\" circuit2: \"%s\" " + "(exact match req'd)\n", + kl1->key, vl1->value.string, vl2->value.string); + } + mismatches++; + } + } + else { + if (strncasecmp(vl1->value.string, vl2->value.string, islop)) { + if (do_print) { + if (mismatches == 0) + Fprintf(stdout, "%s vs. %s:\n", + ob2->instance.name, ob2->instance.name); + Fprintf(stdout, " %s circuit1: \"%s\" circuit2: \"%s\" " + "(check to %d chars.)\n", + kl1->key, vl1->value.string, vl2->value.string, islop); + } + mismatches++; + } + } + break; + case PROP_EXPRESSION: + /* Expressions could potentially be compared. . . */ + if (do_print) + Fprintf(stdout, " %s (unresolved expressions.)\n", kl1->key); + mismatches++; + break; + } + if ((vl1 == NULL && vl2 != NULL) || (vl1 != NULL && vl2 == NULL)) + return -1; /* Different number of properties of interest */ + } + return mismatches; +} + +/*--------------------------------------------------------------*/ +/* Check device properties of one element class against the */ +/* other. Use graph1 for the reference property names. */ +/* EC is assumed to have only one element from each class. */ +/* Automorphisms (element classes with multiple entries) are */ +/* handled separately by re-partitioning the element class */ +/* based on the property values. */ +/* */ +/* Return -1 on complete failure (bad element class), or else */ +/* return the mismatch number determined by PropertyMatch() */ +/*--------------------------------------------------------------*/ + +int PropertyCheck(struct ElementClass *EC, int do_print) +{ + struct Element *E1, *E2, *Etmp; + + /* This element class should contain exactly two entries, */ + /* one belonging to each graph. */ + + if ((E1 = EC->elements) == NULL) return -1; + if ((E2 = EC->elements->next) == NULL) return -1; + if (E2->next != NULL) return -1; + if (E1->graph == E2->graph) return -1; + + if (E1->graph != Circuit1->file) { /* Ensure that E1 is Circuit1 */ + Etmp = E1; + E1 = E2; + E2 = Etmp; + } + return PropertyMatch(E1->object, E2->object, do_print); +} + +/*--------------------------------------------------------------*/ +/* Print results of property checks */ +/*--------------------------------------------------------------*/ + +void PrintPropertyResults(void) +{ + struct ElementClass *EC; + + for (EC = ElementClasses; EC != NULL; EC = EC->next) + PropertyCheck(EC, 1); +} + +/*----------------------------------------------------------------------*/ +/* Return 0 if perfect matching found, else return number of */ +/* automorphisms, and return -1 if invalid matching found. */ +/*----------------------------------------------------------------------*/ + +int VerifyMatching(void) +{ + int ret; + struct ElementClass *EC; + struct NodeClass *NC; + struct Element *E; + struct Node *N; + int C1, C2, result; + + if (BadMatchDetected) return(-1); + + ret = 0; + for (EC = ElementClasses; EC != NULL; EC = EC->next) { + C1 = C2 = 0; + for (E = EC->elements; E != NULL; E = E->next) + (E->graph == Circuit1->file) ? C1++ : C2++; + if (C1 != C2) return(-1); + if (C1 != 1) + ret++; + else if (PropertyErrorDetected != 1) { + result = PropertyCheck(EC, 0); + if (result > 0) + PropertyErrorDetected = 1; + else if (result < 0) + PropertyErrorDetected = -1; + } + } + + for (NC = NodeClasses; NC != NULL; NC = NC->next) { + C1 = C2 = 0; + for (N = NC->nodes; N != NULL; N = N->next) { + (N->graph == Circuit1->file) ? C1++ : C2++; + } + if (C1 != C2) return(-1); + if (C1 != 1) ret++; + } + return(ret); +} + +void PrintAutomorphisms(void) +{ + struct ElementClass *EC; + struct NodeClass *NC; + struct Element *E; + struct Node *N; + int C1, C2; + + for (EC = ElementClasses; EC != NULL; EC = EC->next) { + C1 = C2 = 0; + for (E = EC->elements; E != NULL; E = E->next) + (E->graph == Circuit1->file) ? C1++ : C2++; + if (C1 != C2) continue; + if (C1 != 1) { + Printf("Device Automorphism:\n"); + for (E = EC->elements; E != NULL; E = E->next) + Printf(" Circuit %d: %s\n",E->graph, E->object->instance.name); + Printf("------------------\n"); + } + } + + for (NC = NodeClasses; NC != NULL; NC = NC->next) { + C1 = C2 = 0; + for (N = NC->nodes; N != NULL; N = N->next) + (N->graph == Circuit1->file) ? C1++ : C2++; + if (C1 != C2) continue; + if (C1 != 1) { + Printf("Net Automorphism:\n"); + for (N = NC->nodes; N != NULL; N = N->next) + Printf(" Circuit %d: %s\n",N->graph, N->object->name); + Printf("------------------\n"); + } + } +} + +/* + *------------------------------------------------------------------------- + * ResolveAutomorphsByPin + * + * Equivalence as many device pairs within an automorphic class by + * comparing pin names of those devices connected to pins, and + * separating out those devices that are connected to matching pins + * in each circuit. + * + * Return value is the same as VerifyMatching() + *------------------------------------------------------------------------- + */ + +int ResolveAutomorphsByPin() +{ + struct NodeClass *NC; + struct Node *N; + int C1, C2; + unsigned long newhash, orighash; + struct nlist *tc1, *tc2; + struct objlist *tob, *ob1, *ob2; + int portnum; + + for (NC = NodeClasses; NC != NULL; NC = NC->next) { + struct Node *N1, *N2; + C1 = C2 = 0; + N1 = N2 = NULL; + for (N = NC->nodes; N != NULL; N = N->next) { + if (N->graph == Circuit1->file) { + C1++; + } + else { + C2++; + } + } + if (C1 == C2 && C1 != 1) { + + /* This is an automorphic class. For each node in */ + /* the class, determine if it is a pin. If so, */ + /* give it a new hash value, then find the */ + /* corresponding pin name for the other circuit. */ + + orighash = NC->nodes->hashval; + for (N1 = NC->nodes; N1 != NULL; N1 = N1->next) { + if (N1->hashval != orighash) continue; + ob1 = N1->object; + for (N2 = N1->next; N2 != NULL; N2 = N2->next) { + if ((N2->graph != N1->graph) && + (*matchfunc)(N2->object->name, N1->object->name)) { + Magic(newhash); + N1->hashval = newhash; + N2->hashval = newhash; + break; + } + } + } + } + } + + FractureElementClass(&ElementClasses); + FractureNodeClass(&NodeClasses); + ExhaustiveSubdivision = 1; + while (!Iterate() && VerifyMatching() != -1); + return(VerifyMatching()); +} + +/* + *------------------------------------------------------------------------- + * ResolveAutomorphsByProperty + * + * Equivalence as many device pairs within an automorphic class by + * comparing properties and matching devices with matching properties. + * + *------------------------------------------------------------------------- + */ + +int ResolveAutomorphsByProperty() +{ + struct ElementClass *EC; + struct Element *E; + int C1, C2, result, badmatch; + unsigned long orighash, newhash; + + for (EC = ElementClasses; EC != NULL; EC = EC->next) { + struct Element *E1, *E2; + C1 = C2 = 0; + E1 = E2 = NULL; + for (E = EC->elements; E != NULL; E = E->next) { + + if (E->graph == Circuit1->file) + C1++; + else + C2++; + } + if (C1 == C2 && C1 != 1) { + + /* This is an automorphic class. For each */ + /* device, assign a new hash value, then assign */ + /* the same hash value to all devices with */ + /* matching properties in either circuit. */ + /* Continue until all elements have received */ + /* new hash values. */ + + orighash = EC->elements->hashval; + + /* Properties that fail to match for any reason */ + /* will only result in the automorphic group being */ + /* unresolved at this stage. */ + + for (E1 = EC->elements; E1 != NULL; E1 = E1->next) { + if (E1->hashval != orighash) continue; + Magic(newhash); + E1->hashval = newhash; + C1 = 1; + C2 = 0; + + badmatch = FALSE; + for (E2 = E1->next; E2 != NULL; E2 = E2->next) { + if (E2->hashval != orighash) continue; + result = PropertyMatch(E1->object, E2->object, FALSE); + if (result == 0) { + E2->hashval = newhash; + if (E2->graph == E1->graph) + C1++; + else + C2++; + } + } + + // If devices don't match equally in Circuit1 and Circuit2. + // Since we don't want a property error to force the whole + // circuit to be declared mismatched, arbitrarily revert + // some of the components back to the original hashval + // until the list lengths match. The non-matching portions + // will appear in the report of propery errors. + + while (C2 > C1) { + for (E2 = EC->elements; E2 != NULL; E2 = E2->next) { + if ((E2->graph != E1->graph) && (E2->hashval == newhash)) { + E2->hashval = orighash; + C2--; + } + } + } + while (C1 > C2) { + for (E2 = EC->elements; E2 != NULL; E2 = E2->next) { + if ((E2->graph == E1->graph) && (E2->hashval == newhash)) { + E2->hashval = orighash; + C1--; + } + } + } + } + } + } + + FractureElementClass(&ElementClasses); + FractureNodeClass(&NodeClasses); + ExhaustiveSubdivision = 1; + while (!Iterate() && VerifyMatching() != -1); + return(VerifyMatching()); +} + +/* + *------------------------------------------------------------------------- + * + * ResolveAutormorphisms -- + * + * Arbitrarily equivalence one pair of elements within an automorphic class + * + * Return value is the same as VerifyMatching() + * + *------------------------------------------------------------------------- + */ + +int ResolveAutomorphisms() +{ + struct ElementClass *EC; + struct NodeClass *NC; + struct Element *E; + struct Node *N; + int C1, C2; + + for (EC = ElementClasses; EC != NULL; EC = EC->next) { + struct Element *E1, *E2; + C1 = C2 = 0; + E1 = E2 = NULL; + for (E = EC->elements; E != NULL; E = E->next) { + if (E->graph == Circuit1->file) { + C1++; + E1 = E; + } + else { + C2++; + E2 = E; + } + } + if (C1 == C2 && C1 != 1) { + unsigned long newhash; + Magic(newhash); + E1->hashval = newhash; + E2->hashval = newhash; + goto converge; + } + } + + for (NC = NodeClasses; NC != NULL; NC = NC->next) { + struct Node *N1, *N2; + C1 = C2 = 0; + N1 = N2 = NULL; + for (N = NC->nodes; N != NULL; N = N->next) { + if (N->graph == Circuit1->file) { + C1++; + N1 = N; + } + else { + C2++; + N2 = N; + } + } + if (C1 == C2 && C1 != 1) { + unsigned long newhash; + Magic(newhash); + N1->hashval = newhash; + N2->hashval = newhash; + goto converge; + } + } + + converge: + FractureElementClass(&ElementClasses); + FractureNodeClass(&NodeClasses); + ExhaustiveSubdivision = 1; + while (!Iterate() && VerifyMatching() != -1); + return(VerifyMatching()); +} + +/*------------------------------------------------------*/ +/* CombineSetup -- */ +/* Add an entry to a cell describing the combination */ +/* allowances. */ +/* Return 1 if OK, 0 if error */ +/*------------------------------------------------------*/ + +int CombineSetup(char *model, int filenum, int comb_type) +{ + struct nlist *tp; + + // If -1 is passed as filenum, then re-run this routine on + // each of Circuit1 and Circuit2 models. + + if (filenum == -1) { + if ((Circuit1 != NULL) && (Circuit1->file != -1)) + CombineSetup(model, Circuit1->file, comb_type); + if ((Circuit2 != NULL) && (Circuit2->file != -1)) + CombineSetup(model, Circuit2->file, comb_type); + return 1; + } + + tp = LookupCellFile(model, filenum); + if (tp == NULL) { + Printf("No such model %s\n", model); + return 0; + } + + tp->flags |= comb_type; + return 1; +} + +/*------------------------------------------------------*/ +/* CombineForget -- */ +/* Remove combination allowances for a cell */ +/* */ +/* Return 1 if OK, 0 if error */ +/* */ +/* If comb_type is 0, then forget all allowed */ +/* combinations of the device. */ +/*------------------------------------------------------*/ + +int CombineForget(char *model, int filenum, int comb_type) +{ + struct nlist *tp; + + // If -1 is passed as filenum, then re-run this routine on + // each of Circuit1 and Circuit2 models. + + if (filenum == -1) { + if ((Circuit1 != NULL) && (Circuit1->file != -1)) + CombineForget(model, Circuit1->file, comb_type); + if ((Circuit2 != NULL) && (Circuit2->file != -1)) + CombineForget(model, Circuit2->file, comb_type); + return 1; + } + + tp = LookupCellFile(model, filenum); + if (tp == NULL) { + Printf("No such model %s\n", model); + return 0; + } + + if (comb_type != 0) { + /* Remove this specific combination allowance */ + tp->flags &= ~comb_type; + } + else { + /* Blanket remove all combinations for this device */ + tp->flags &= ~(COMB_SERIAL | COMB_PARALLEL); + } + return 1; +} + +/*------------------------------------------------------*/ +/* PermuteSetup -- */ +/* Add an entry to a cell's "permutes" linked list. */ +/* Return 1 if OK, 0 if error */ +/* */ +/* NOTE: When comparing two netlists, it is only */ +/* necessary to permute pins on devices of one of them. */ +/* So if a device has the same name in two circuits, */ +/* e.g., "pmos", and is defined as a subcircuit so that */ +/* it is not automatically permuted according to the */ +/* default rules, then it is valid to use LookupCell, */ +/* which returns the first one encountered, mark those */ +/* pins as permuted, and not touch the other "pmos". */ +/*------------------------------------------------------*/ + +int PermuteSetup(char *model, int filenum, char *pin1, char *pin2) +{ + struct Permutation *newperm, *perm; + struct nlist *tp; + struct objlist *obj1, *obj2; + + // If -1 is passed as filenum, then re-run this routine on + // each of Circuit1 and Circuit2 models. + + if (filenum == -1) { + if ((Circuit1 != NULL) && (Circuit1->file != -1)) + PermuteSetup(model, Circuit1->file, pin1, pin2); + if ((Circuit2 != NULL) && (Circuit2->file != -1)) + PermuteSetup(model, Circuit2->file, pin1, pin2); + return 1; + } + + tp = LookupCellFile(model, filenum); + if (tp == NULL) { + Printf("No such model %s\n", model); + return 0; + } + obj1 = LookupObject(pin1, tp); + if (obj1 == NULL) { + Printf("No such pin %s in model %s\n", pin1, model); + return 0; + } + obj2 = LookupObject(pin2, tp); + if (obj2 == NULL) { + Printf("No such pin %s in model %s\n", pin2, model); + return 0; + } + + /* Now check that this permutation is not already in the list. */ + + for (perm = tp->permutes; perm != NULL; perm = perm->next) + if ((*matchfunc)(perm->pin1, pin1) && (*matchfunc)(perm->pin2, pin2)) + return 1; + + newperm = (struct Permutation *)CALLOC(1, sizeof(struct Permutation)); + newperm->pin1 = obj1->name; + newperm->pin2 = obj2->name; + newperm->next = tp->permutes; + tp->permutes = newperm; + return 1; +} + +/*------------------------------------------------------*/ +/* PermuteForget -- */ +/* Remove an entry from a cell's "permutes" linked */ +/* list. This makes it more convenient to use the */ +/* default permutations and declare individual */ +/* exceptions. */ +/* */ +/* Return 1 if OK, 0 if error */ +/* */ +/* If pin1 and pin2 are NULL, then forget all */ +/* permutations on all pins. */ +/*------------------------------------------------------*/ + +int PermuteForget(char *model, int filenum, char *pin1, char *pin2) +{ + struct Permutation *lastperm, *perm, *nextperm; + struct nlist *tp; + struct objlist *obj1, *obj2; + + // If -1 is passed as filenum, then re-run this routine on + // each of Circuit1 and Circuit2 models. + + if (filenum == -1) { + if ((Circuit1 != NULL) && (Circuit1->file != -1)) + PermuteForget(model, Circuit1->file, pin1, pin2); + if ((Circuit2 != NULL) && (Circuit2->file != -1)) + PermuteForget(model, Circuit2->file, pin1, pin2); + return 1; + } + + tp = LookupCellFile(model, filenum); + if (tp == NULL) { + Printf("No such model %s\n", model); + return 0; + } + + if ((pin1 != NULL) && (pin2 != NULL)) { + obj1 = LookupObject(pin1, tp); + if (obj1 == NULL) { + Printf("No such pin %s in model %s\n", pin1, model); + return 0; + } + obj2 = LookupObject(pin2, tp); + if (obj2 == NULL) { + Printf("No such pin %s in model %s\n", pin2, model); + return 0; + } + + /* Now remove this permutation from the list, if it's there. */ + + lastperm = NULL; + for (perm = tp->permutes; perm != NULL;) { + nextperm = perm->next; + if (((*matchfunc)(perm->pin1, pin1) && + (*matchfunc)(perm->pin2, pin2)) || + ((*matchfunc)(perm->pin1, pin2) && + (*matchfunc)(perm->pin2, pin1))) { + if (lastperm == NULL) + tp->permutes = perm->next; + else + lastperm->next = perm->next; + FREE(perm); + break; + } + else + lastperm = perm; + perm = nextperm; + } + } + else { + + /* Blanket remove all permutations for this device */ + + lastperm = NULL; + for (perm = tp->permutes; perm != NULL;) { + nextperm = perm->next; + FREE(perm); + perm = nextperm; + } + } + return 1; +} + +/*------------------------------------------------------*/ +/* Permute -- */ +/* For each entry in a cell's "permutes" linked list, */ +/* set the magic numbers of pin1 and pin2 to be the */ +/* same. */ +/* Return 1 if OK, 0 if error */ +/*------------------------------------------------------*/ + +int Permute() +{ + struct Permutation *perm; + struct ElementClass *EC; + struct Element *E; + struct NodeList *NL; + struct objlist *ob; + struct nlist *tp; + unsigned long one, two; + + for (EC = ElementClasses; EC != NULL; EC = EC->next) { + for (E = EC->elements; E != NULL; E = E->next) { + tp = LookupCellFile(E->object->model.class, E->graph); + for (perm = tp->permutes; perm != NULL; perm = perm->next) { + one = two = 0; + ob = E->object; + for (NL = E->nodelist; NL != NULL && !one; NL = NL->next) { + if ((*matchfunc)(perm->pin1, ob->name + + strlen(ob->instance.name) + 1)) + one = NL->pin_magic; + ob = ob->next; + } + ob = E->object; + for (NL = E->nodelist; NL != NULL && !two; NL = NL->next) { + if ((*matchfunc)(perm->pin2, ob->name + + strlen(ob->instance.name) + 1)) + two = NL->pin_magic; + ob = ob->next; + } + if (one == 0) { + Fprintf(stderr, "Class %s does not have pin %s.\n", + tp->name, perm->pin1); + if (two == 0) + Fprintf(stderr, "Class %s does not have pin %s.\n", + tp->name, perm->pin2); + return (0); + } + if (two == 0) { + Fprintf(stderr, "Class %s does not have pin %s.\n", + tp->name, perm->pin2); + return (0); + } + + /* update magic numbers */ + for (NL = E->nodelist; NL != NULL; NL = NL->next) + if (NL->pin_magic == one) + NL->pin_magic = two; + } + } + } + return(1); +} + +/*------------------------------------------------------*/ +/* Force two elements two be declared matching between */ +/* the two circuits being compared */ +/* Return 1 on success, 0 on failure */ +/*------------------------------------------------------*/ + +int EquivalenceElements(char *name1, int file1, char *name2, int file2) +{ + struct ElementClass *EC; + struct Element *E, *E1, *E2; + + if (Circuit1 == NULL || Circuit2 == NULL) { + Printf("Circuits not being compared!\n"); + return 1; + } + + for (EC = ElementClasses; EC != NULL; EC = EC->next) { + E1 = E2 = NULL; + for (E = EC->elements; E != NULL; E = E->next) { + if (E->graph==file1 && E1==NULL && + (*matchfunc)(E->object->instance.name, name1)) E1=E; + if (E->graph==file2 && E2==NULL && + (*matchfunc)(E->object->instance.name, name2)) E2=E; + } + if (E1 != NULL || E2 != NULL) { + struct ElementClass *NewList, *EndOfNewList; + if (E1 == NULL || E2 == NULL) + return 0; /* did not find both in same equivalence class */ + /* otherwise, create a new equivalence class */ + for (E = EC->elements; E != NULL; E = E->next) { + if (E == E1 || E == E2) E->hashval = 1; + else E->hashval = 0; + } + + /* now make new equivalence classes, and tear EC out of old list */ + + NewList = MakeElist(EC->elements); + for (EndOfNewList = NewList; EndOfNewList->next != NULL; + EndOfNewList = EndOfNewList->next) ; + EndOfNewList->next = EC->next; + if (EC == ElementClasses) { + FreeElementClass (ElementClasses); + ElementClasses = NewList; + } + else { + struct ElementClass *EC3; + for (EC3 = ElementClasses; EC3->next != EC; EC3 = EC3->next) ; + EC3->next = NewList; + FreeElementClass(EC); + } + return 1; + } + } + return 0; +} + +/*------------------------------------------------------*/ +/* Force two nodes to be declared matching between the */ +/* two circuits being compared. */ +/* Return 1 on success, 0 on failure */ +/*------------------------------------------------------*/ + +int EquivalenceNodes(char *name1, int file1, char *name2, int file2) +{ + int node1, node2; + struct objlist *ob; + struct NodeClass *NC; + struct Node *N, *N1, *N2; + struct nlist *np1, *np2; + + if (Circuit1 == NULL || Circuit2 == NULL) { + Fprintf(stderr, "Circuits not being compared!\n"); + return 1; + } + + if (file1 == Circuit1->file) { + np1 = Circuit1; + np2 = Circuit2; + } + else { + np1 = Circuit2; + np2 = Circuit1; + } + + ob = LookupObject(name1, np1); + if (ob == NULL) return 0; + node1 = ob->node; + + ob = LookupObject(name2, np2); + if (ob == NULL) return 0; + node2 = ob->node; + + for (NC = NodeClasses; NC != NULL; NC = NC->next) { + N1 = N2 = NULL; + for (N = NC->nodes; N != NULL; N = N->next) { + if (N->graph== file1 && N1==NULL && N->object->node == node1) N1=N; + if (N->graph== file2 && N2==NULL && N->object->node == node2) N2=N; + } + if (N1 != NULL || N2 != NULL) { + struct NodeClass *NewList, *EndOfNewList; + if (N1 == NULL || N2 == NULL) + return(0); /* did not find both in same equivalence class */ + /* otherwise, create a new equivalence class */ + for (N = NC->nodes; N != NULL; N = N->next) { + if (N == N1 || N == N2) N->hashval = 1; + else N->hashval = 0; + } + /* now make new equivalence classes, and tear NC out of old list */ + NewList = MakeNlist(NC->nodes); + for (EndOfNewList = NewList; EndOfNewList->next != NULL; + EndOfNewList = EndOfNewList->next) ; + EndOfNewList->next = NC->next; + if (NC == NodeClasses) { + FreeNodeClass (NodeClasses); + NodeClasses = NewList; + } + else { + struct NodeClass *NC3; + for (NC3 = NodeClasses; NC3->next != NC; NC3 = NC3->next) ; + NC3->next = NewList; + FreeNodeClass(NC); + } + return 1; + } + } + return 0; +} + +/*------------------------------------------------------*/ +/* Ignore any class named "name" in the input. If */ +/* netlists exist at the time this routine is called, */ +/* then remove all elements of this class from the */ +/* database. */ +/*------------------------------------------------------*/ + +int IgnoreClass(char *name, int file) +{ + struct IgnoreList *newIgnore; + + if ((file == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + IgnoreClass(name, Circuit1->file); + IgnoreClass(name, Circuit2->file); + return; + } + + newIgnore = (struct IgnoreList *)MALLOC(sizeof(struct IgnoreList)); + newIgnore->next = ClassIgnore; + ClassIgnore = newIgnore; + newIgnore->class = (char *)MALLOC(1 + strlen(name)); + strcpy(newIgnore->class, name); + newIgnore->file = file; + + /* Remove existing classes from database */ + ClassDelete(name, file); + + return 0; +} + +/*------------------------------------------------------*/ +/* Declare that the device class "name1" in file1 */ +/* is the same as the device class "name2" in file2 */ +/* */ +/* If file1 and file2 are -1, then these are names to */ +/* be checked as netcmp works through the hierarchy. */ +/* Otherwise, look up the structure for each file and */ +/* set the classhash of the second to that of the first */ +/* */ +/* Return 1 on success, 0 on failure */ +/*------------------------------------------------------*/ + +int EquivalenceClasses(char *name1, int file1, char *name2, int file2) +{ + char *class1, *class2; + struct Correspond *newc; + struct nlist *tp, *tp2; + + if (file1 != -1 && file2 != -1) { + + tp = LookupClassEquivalent(name1, file1, file2); + if (tp && (*matchfunc)(tp->name, name2)) + return 1; /* Already equivalent */ + + tp = LookupCellFile(name1, file1); + tp2 = LookupCellFile(name2, file2); + tp2->classhash = tp->classhash; + return 1; + } + + /* Create a new class correspondence entry. Use the names in the */ + /* records found by Lookup() so that the don't need to allocate and */ + /* free the string records. */ + + newc = (struct Correspond *)CALLOC(1, sizeof(struct Correspond)); + newc->class1 = strsave(name1); + newc->file1 = file1; + newc->class2 = strsave(name2); + newc->file2 = file2; + + newc->next = ClassCorrespondence; + ClassCorrespondence = newc; + + return 1; +} + +#ifdef TCL_NETGEN + +/*----------------------------------------------------------------------*/ +/* Callback function used by MatchPins */ +/*----------------------------------------------------------------------*/ + +int reorderpins(struct hashlist *p, int file) +{ + struct nlist *ptr; + struct nlist *tc2 = Circuit2; + struct objlist *ob, *ob2, *firstpin; + int i, numports, *nodes; + char **names; + + ptr = (struct nlist *)(p->ptr); + + if (ptr->file != file) return 1; /* Keeps the search going */ + + /* Pull the port order from the cell and put it in a list */ + /* NOTE: This method requires the use of "CleanupPins()" */ + /* to make sure that there are no unconnected ports, and */ + /* that there is a 1:1 match between the port lists of all */ + /* instances of both cells. */ + + numports = 0; + ob2 = tc2->cell; + while (ob2 && ob2->type == PORT) { + numports++; + ob2 = ob2->next; + } + nodes = (int *)CALLOC(numports, sizeof(int)); + names = (char **)CALLOC(numports, sizeof(char *)); + + for (ob = ptr->cell; ob != NULL; ) { + if (ob->type == FIRSTPIN) { + if ((*matchfunc)(ob->model.class, tc2->name)) { + char *sptr = ob->instance.name; + if (*sptr == '/') sptr++; + if (Debug == TRUE) + Fprintf(stdout, "Reordering pins on instance %s\n", sptr); + + firstpin = ob; + ob2 = tc2->cell; + for (i = 0; i < numports; i++) { + nodes[ob2->model.port] = ob->node; + names[ob2->model.port] = ob->name; + ob = ob->next; + ob2 = ob2->next; + } + + ob = firstpin; + for (i = 0; i < numports; i++) { + if (names[i] == NULL) { + ob->name = strsave("port_match_error"); + ob->node = -1; + } + else { + ob->node = nodes[i]; + ob->name = names[i]; + } + HashPtrInstall(ob->name, ob, ptr->objtab, OBJHASHSIZE); + ob = ob->next; + names[i] = NULL; + } + } + else + ob = ob->next; + } + else + ob = ob->next; + } + + FREE(nodes); + FREE(names); + return 1; /* Continue the search. . . */ +} + +/*----------------------------------------------------------------------*/ +/* Another callback function used by MatchPins */ +/* Search through all instances of each cell, find matches for the */ +/* cell passed through "clientdata", and add extra pins whereever an */ +/* "UNKNOWN" type is found in the cell's pin list. */ +/* */ +/* Always return NULL to keep the search going. */ +/*----------------------------------------------------------------------*/ + +struct nlist *addproxies(struct hashlist *p, void *clientdata) +{ + struct nlist *ptr; + struct nlist *tc = (struct nlist *)clientdata; + struct objlist *ob, *lob, *tob, *obn, *firstpin; + int i, numnodes, maxnode; + + ptr = (struct nlist *)(p->ptr); + if (ptr->file != tc->file) return NULL; /* Keep going */ + + // Count the largest node number used in the cell + maxnode = -1; + for (ob = ptr->cell; ob; ob = ob->next) + if (ob->type >= FIRSTPIN || ob->type == NODE) + if (ob->node >= maxnode) + maxnode = ob->node + 1; + numnodes = maxnode; + + lob = NULL; + ob = ptr->cell; + while (ob != NULL) { + while (ob && ob->type != FIRSTPIN) { + lob = ob; + ob = ob->next; + } + if (ob && ob->model.class != NULL) { + if (!(*matchfunc)(ob->model.class, tc->name)) { + lob = ob; + ob = ob->next; + continue; + } + } + if (ob == NULL) break; + + tob = tc->cell; + i = FIRSTPIN; + firstpin = ob; + while (ob && (tob->type == PORT || tob->type == UNKNOWN)) { + if (tob->type == UNKNOWN) { + obn = (struct objlist *)CALLOC(1, sizeof(struct objlist)); + obn->name = (char *)MALLOC(strlen(firstpin->instance.name) + + strlen(tob->name) + 2); + sprintf(obn->name, "%s/%s", firstpin->instance.name, tob->name); + obn->instance.name = strsave(firstpin->instance.name); + obn->model.class = strsave(tc->name); + obn->type = i++; + obn->node = numnodes++; + obn->next = ob; // Splice into object list + lob->next = obn; + lob = obn; + + // Hash the new pin record for "LookupObject()" + HashPtrInstall(obn->name, obn, ptr->objtab, OBJHASHSIZE); + + if (tob == tc->cell) { + // Rehash the instance in insttab + HashPtrInstall(firstpin->instance.name, firstpin, + ptr->insttab, OBJHASHSIZE); + } + } + else { + lob = ob; + ob->type = i++; + ob = ob->next; + } + tob = tob->next; + } + } + + /* Insert a record for each new node added to the cell */ + for (i = maxnode; i < numnodes; i++) { + obn = (struct objlist *)CALLOC(1, sizeof(struct objlist)); + obn->node = i; + obn->type = NODE; + obn->model.class = NULL; + obn->instance.name = NULL; + obn->name = (char *)MALLOC(12); + sprintf(obn->name, "dummy_%d", i); + obn->next = NULL; + lob->next = obn; + lob = obn; + HashPtrInstall(obn->name, obn, ptr->objtab, OBJHASHSIZE); + } + + // We messed with the node name list, so have to re-cache them + if (maxnode < numnodes) CacheNodeNames(ptr); + + return NULL; /* Keep the search going */ +} + +/*------------------------------------------------------*/ +/* Declare that the device class "name1" is equivalent */ +/* to class "name2". This is the same as the above */ +/* routine, except that the cells must be at the top */ +/* of the compare queue, and must already be proven */ +/* equivalent by LVS. Determine a pin correspondence, */ +/* then modify all instances of "name2" to match all */ +/* instances of "name1" by pin reordering. If either */ +/* cell has disconnected pins, they are shuffled to the */ +/* end of the pin list. If two or more pins correspond */ +/* to net automorphisms, then they are added to the */ +/* list of permuted pins. */ +/* */ +/* NOTE: This routine must not be called on any */ +/* circuit pair that has not been matched. If a */ +/* circuit pair has been matched with automorphisms, */ +/* then some pins may be matched arbitrarily. */ +/* */ +/* Return 1 on success, 0 on failure */ +/*------------------------------------------------------*/ + +int MatchPins(struct nlist *tc1, struct nlist *tc2) +{ + char *cover, *ctemp; + struct objlist *ob1, *ob2, *obn, *obp, *ob1s, *ob2s, *obt; + struct NodeClass *NC; + struct Node *N1, *N2; + int i, j, k, m, a, b, swapped, numnodes, numorig; + int result = 1, haspins = 0; + int hasproxy1 = 0, hasproxy2 = 0; + int needclean1 = 0, needclean2 = 0; + char ostr[89]; + + if (tc1 == NULL) tc1 = Circuit1; + if (tc2 == NULL) tc2 = Circuit2; + + for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) { + if (ob2->type != PORT) break; + else haspins = 1; + ob2->model.port = -1; + } + numnodes = 0; + for (ob1 = tc1->cell; ob1 != NULL; ob1 = ob1->next) { + if (ob1->type != PORT) break; + else haspins = 1; + numnodes++; + } + + if (haspins == 0) { + // Neither cell has any ports, so this is probably a top-level + // cell and there is nothing to do. + return 1; + } + + cover = (char *)CALLOC(numnodes, sizeof(char)); + numorig = numnodes; + + if (Debug == 0) { + /* Format side-by-side comparison of pins */ + Fprintf(stdout, "\nSubcircuit pins:\n"); + *(ostr + 43) = '|'; + *(ostr + 87) = '\n'; + *(ostr + 88) = '\0'; + for (i = 0; i < 43; i++) *(ostr + i) = ' '; + for (i = 44; i < 87; i++) *(ostr + i) = ' '; + snprintf(ostr, 43, "Circuit 1: %s", tc1->name); + snprintf(ostr + 44, 43, "Circuit 2: %s", tc2->name); + for (i = 0; i < 88; i++) if (*(ostr + i) == '\0') *(ostr + i) = ' '; + Fprintf(stdout, ostr); + for (i = 0; i < 43; i++) *(ostr + i) = '-'; + for (i = 44; i < 87; i++) *(ostr + i) = '-'; + Fprintf(stdout, ostr); + } + + for (NC = NodeClasses; NC != NULL; NC = NC->next) { + a = 0; + for (N1 = NC->nodes; N1 != NULL; N1 = N1->next) { + if (N1->graph == Circuit1->file) { + obn = N1->object; + if (IsPort(obn)) { + i = 0; + for (ob1 = tc1->cell; ob1 != NULL; ob1 = ob1->next, i++) { + if ((IsPort(ob1)) + && (*matchfunc)(ob1->name, obn->name)) { + b = 0; + for (N2 = NC->nodes; N2 != NULL; N2 = N2->next) { + if (N2->graph != Circuit1->file) { + if (b == a) break; + else b++; + } + } + if (N2 == NULL) return 0; + obp = N2->object; + j = 0; + for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next, j++) { + if ((IsPort(ob2)) + && (*matchfunc)(ob2->name, obp->name)) { + if (Debug == 0) { + for (m = 0; m < 43; m++) *(ostr + m) = ' '; + for (m = 44; m < 87; m++) *(ostr + m) = ' '; + sprintf(ostr, "%s", obn->name); + sprintf(ostr + 44, "%s", obp->name); + for (m = 0; m < 88; m++) + if (*(ostr + m) == '\0') *(ostr + m) = ' '; + Fprintf(stdout, ostr); + } + else { + Fprintf(stdout, "Circuit %s port %d \"%s\"" + " = cell %s port %d \"%s\"\n", + tc1->name, i, obn->name, + tc2->name, j, obp->name); + } + ob2->model.port = i; /* save order */ + *(cover + i) = (char)1; + break; + } + } + if (ob2 == NULL) { + if (Debug == 0) { + for (m = 0; m < 43; m++) *(ostr + m) = ' '; + for (m = 44; m < 87; m++) *(ostr + m) = ' '; + sprintf(ostr, "%s", obn->name); + sprintf(ostr + 44, "(no matching pin)"); + for (m = 0; m < 88; m++) + if (*(ostr + m) == '\0') *(ostr + m) = ' '; + Fprintf(stdout, ostr); + } + else { + Fprintf(stderr, "No matching pin in cell %s for " + "cell %s pin %s\n", + tc2->name, tc1->name, obn->name); + } + result = 0; + + /* Make a pass through circuit 1 to find out if */ + /* the pin really is connected to anything, or */ + /* has been left orphaned after flattening. If */ + /* disconnected, set its node number to -1. */ + + for (obt = ob1->next; obt; obt = obt->next) { + if (obt->type >= FIRSTPIN) + if (obt->node == ob1->node) + break; + } + if (obt == NULL) { + ob1->node = -1; // Will run this through cleanuppins + needclean1 = 1; + } + } + break; + } + } + + if (ob1 == NULL) { + if (Debug == 0) { + for (m = 0; m < 43; m++) *(ostr + m) = ' '; + for (m = 44; m < 87; m++) *(ostr + m) = ' '; + sprintf(ostr, "%s", obn->name); + sprintf(ostr + 44, "(no matching pin)"); + for (m = 0; m < 88; m++) + if (*(ostr + m) == '\0') *(ostr + m) = ' '; + Fprintf(stdout, ostr); + } + else { + Fprintf(stderr, "No netlist match for cell %s pin %s\n", + tc1->name, obn->name); + } + result = 0; + } + } + a++; + } + } + } + + /* Find the end of the pin list in tc1 */ + + for (ob1 = tc1->cell; ob1 != NULL; ob1 = ob1->next) { + if (ob1 && ob1->next && ob1->next->type != PORT) + break; + } + + /* Assign non-matching pins in tc2 with real node */ + /* connections in the cell to the end. Create pins */ + /* in tc1 to match. */ + + for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) { + if (ob2->type != PORT) break; + if (ob2->model.port == -1) { + + if (Debug == 0) { + for (m = 0; m < 43; m++) *(ostr + m) = ' '; + for (m = 44; m < 87; m++) *(ostr + m) = ' '; + sprintf(ostr, "(no matching pin)"); + sprintf(ostr + 44, "%s", ob2->name); + for (m = 0; m < 88; m++) + if (*(ostr + m) == '\0') *(ostr + m) = ' '; + Fprintf(stdout, ostr); + } + else { + Fprintf(stderr, "No netlist match for cell %s pin %s\n", + tc2->name, ob2->name); + } + result = 0; + + /* Before making a proxy pin, check to see if */ + /* flattening instances has left a port with a */ + /* net number that doesn't connect to anything */ + + for (obt = ob2->next; obt; obt = obt->next) { + if (obt->type >= FIRSTPIN) + if (obt->node == ob2->node) + break; + } + if (obt == NULL) { + ob2->node = -1; // Will run this through cleanuppins + needclean2 = 1; + continue; + } + ob2->model.port = numnodes++; // Assign a port order + + /* Add a proxy pin to tc1 */ + /* Technically, this should have a matching net number. */ + /* But nothing connects to it, so it is only needed to */ + /* make sure the "pin magic" numbers are correctly */ + /* assigned to both cells. */ + + obn = (struct objlist *)CALLOC(1, sizeof(struct objlist)); + obn->name = (char *)MALLOC(6 + strlen(ob2->name)); + sprintf(obn->name, "proxy%s", ob2->name); + obn->type = UNKNOWN; + obn->model.port = -1; + obn->instance.name = NULL; + obn->node = -1; + obn->next = ob1->next; + ob1->next = obn; + ob1 = obn; + hasproxy1 = 1; + + HashPtrInstall(obn->name, obn, tc1->objtab, OBJHASHSIZE); + } + } + + /* If cell 2 has fewer nodes than cell 1, then add dummy (unconnected) */ + /* pins to cell 2. If these correspond to numbers missing in the match */ + /* sequence, then fill in the missing numbers. Otherwise, add the */ + /* extra nodes to the end. */ + + j = 0; + for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) { + j++; + if (ob2->next->type != PORT) break; + } + + if (numnodes > numorig) { + ctemp = (char *)CALLOC(numnodes, sizeof(char)); + for (i = 0; i < numorig; i++) + ctemp[i] = cover[i]; + FREE(cover); + cover = ctemp; + } + + i = 0; + while (j < numnodes) { + while (*(cover + i) != (char)0) i++; + if (i >= numnodes) break; + + /* If the equivalent node in tc1 is not disconnected */ + /* (node != -1) then we should report a match error, */ + /* although this does not necessarily imply an error in */ + /* netlist connectivity. */ + + ob1 = tc1->cell; + for (k = i; k > 0 && ob1 != NULL; k--) + ob1 = ob1->next; + + if (ob1 == NULL || ob1->type != PORT || ob1->node >= 0) { + + /* Add a proxy pin to tc2 */ + obn = (struct objlist *)CALLOC(1, sizeof(struct objlist)); + if (ob1 == NULL) { + obn->name = (char *)MALLOC(15); + sprintf(obn->name, "proxy%d", rand() & 0x3ffffff); + } + else { + obn->name = (char *)MALLOC(6 + strlen(ob1->name)); + sprintf(obn->name, "proxy%s", ob1->name); + } + obn->type = UNKNOWN; + obn->model.port = i; + obn->instance.name = NULL; + obn->node = -1; + obn->next = ob2->next; + ob2->next = obn; + ob2 = obn; + hasproxy2 = 1; + + HashPtrInstall(obn->name, obn, tc2->objtab, OBJHASHSIZE); + + j++; + i++; + } + } + FREE(cover); + + if (Debug == 0) { + for (i = 0; i < 87; i++) *(ostr + i) = '-'; + Fprintf(stdout, ostr); + } + + /* Run cleanuppins on circuit 1 */ + if (needclean1) { + CleanupPins(tc1->name, tc1->file); + } + + /* Add proxy pins to all instances of Circuit1 */ + + if (hasproxy1) { + RecurseCellHashTable2(addproxies, (void *)(tc1)); + CacheNodeNames(tc1); + } + + /* Clean up "UNKNOWN" records from Circuit1 */ + + for (obn = tc1->cell; ; obn = obn->next) { + if (obn->type == UNKNOWN) obn->type = PORT; + else if (obn->type != PORT) break; + } + + /* Run cleanuppins on circuit 2 */ + if (needclean2) { + CleanupPins(tc2->name, tc2->file); + } + + /* Add proxy pins to all instances of Circuit2 */ + + if (hasproxy2) { + RecurseCellHashTable2(addproxies, (void *)(tc2)); + CacheNodeNames(tc2); + } + + /* Clean up "UNKNOWN" records from Circuit2 */ + + for (obn = tc2->cell; ; obn = obn->next) { + if (obn->type == UNKNOWN) obn->type = PORT; + else if (obn->type != PORT) break; + } + + /* Check for ports that did not get ordered */ + for (obn = tc2->cell; obn->type == PORT; obn = obn->next) { + if (obn->model.port == -1) { + if (obn->node == -1) { + // This only happens when pins have become separated from any net. + } + else { + // This should not happen. . . + Fprintf(stderr, "Error: Connected pin %s (node %d) did not get " + "ordered!\n", obn->name, obn->node); + } + } + } + + /* Reorder pins in Circuit2 instances to match Circuit1 */ + + RecurseCellFileHashTable(reorderpins, Circuit2->file); + + /* Reorder pins in Circuit2 cell to match Circuit1 */ + /* Unlike the instance records, the structures are swapped, */ + /* so the object hash pointers don't become invalid. */ + + do { + swapped = 0; + obn = NULL; + for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) { + if (ob2->next != NULL && IsPort(ob2) && IsPort(ob2->next)) { + if (ob2->model.port > ob2->next->model.port) { + swapped++; + if (obn != NULL) { + obn->next = ob2->next; + ob2->next = ob2->next->next; + obn->next->next = ob2; + } + else { + tc2->cell = ob2->next; + ob2->next = ob2->next->next; + tc2->cell->next = ob2; + } + break; + } + } + obn = ob2; + } + } while (swapped > 0); + + /* Whether or not pins matched, reset ob2's pin indexes to 0 */ + + for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) { + if (ob2->type != PORT) break; + ob2->model.port = -1; + } + + return result; +} + +/*------------------------------------------------------*/ +/* Find the equivalent node to object "ob" in the other */ +/* circuit. Return a pointer to the object structure */ +/* of the equivalent node or NULL if there is no */ +/* equivalent. */ +/* */ +/* It is the responsibility of the calling function to */ +/* decide what to do about automorphisms. */ +/* */ +/* Return 1 if a match is found, 0 if a match is not */ +/* found, and -1 if the node itself is not found. */ +/*------------------------------------------------------*/ + +int EquivalentNode(char *name, struct nlist *circuit, struct objlist **retobj) +{ + short ckt1; + struct NodeClass *NC; + struct Node *N1, *N2; + struct objlist *ob; + int retval = -1; + + if (Circuit1 == NULL || Circuit2 == NULL) return retval; + + if (circuit != NULL) { + ob = LookupObject(name, circuit); + if (ob == NULL) return retval; + } + else { + ob = LookupObject(name, Circuit1); + if (ob == NULL) { + ob = LookupObject(name, Circuit2); + if (ob == NULL) return retval; + } + } + + for (NC = NodeClasses; NC != NULL; NC = NC->next) { + for (N1 = NC->nodes; N1 != NULL; N1 = N1->next) { + if (N1->object == ob) { + retval = 0; /* Node exists. . . */ + ckt1 = N1->graph; + for (N2 = NC->nodes; N2 != NULL; N2 = N2->next) + if (N2->graph != ckt1) { + *retobj = N2->object; + return 1; + } + } + } + } + return retval; +} + +/*------------------------------------------------------*/ +/* Find the equivalent element to object "ob" in the */ +/* other circuit. Return a pointer to the object */ +/* structure of the equivalent element or NULL if there */ +/* is no equivalent. */ +/* */ +/* It is the responsibility of the calling function to */ +/* decide what to do about automorphisms. */ +/* */ +/* Return 1 if a match was found, 0 if the element has */ +/* no match, and -1 if the element was not found. */ +/*------------------------------------------------------*/ + +int EquivalentElement(char *name, struct nlist *circuit, struct objlist **retobj) +{ + short ckt1; + struct ElementClass *EC; + struct Element *E1, *E2; + struct objlist *ob; + int retval = -1; + + if (Circuit1 == NULL || Circuit2 == NULL) return retval; + + if (circuit != NULL) { + ob = LookupInstance(name, circuit); + if (ob == NULL) return retval; + } + else { + ob = LookupInstance(name, Circuit1); + if (ob == NULL) { + ob = LookupInstance(name, Circuit2); + if (ob == NULL) return retval; + } + } + + for (EC = ElementClasses; EC != NULL; EC = EC->next) { + for (E1 = EC->elements; E1 != NULL; E1 = E1->next) { + if (E1->object == ob) { + retval = 0; + ckt1 = E1->graph; + for (E2 = EC->elements; E2 != NULL; E2 = E2->next) + if (E2->graph != ckt1) { + *retobj = E2->object; + return 1; + } + } + } + } + return retval; +} + +/*------------------------------------------------------*/ +/* Flatten the two cells at the top of the compare */ +/* queue. */ +/*------------------------------------------------------*/ + +void FlattenCurrent() +{ + if (Circuit1 != NULL && Circuit2 != NULL) { + Fprintf(stdout, "Flattening subcell %s\n", Circuit1->name); + FlattenInstancesOf(Circuit1->name, Circuit1->file); + + Fprintf(stdout, "Flattening subcell %s\n", Circuit2->name); + FlattenInstancesOf(Circuit2->name, Circuit2->file); + } +} + +/*------------------------------------------------------*/ +/* Handler is only used when netgen is run from a */ +/* terminal, not the Tk console. */ +/*------------------------------------------------------*/ + +void handler(int sig) +{ + /* Don't do anything else here! */ + InterruptPending = 1; +} + +/*------------------------------------------------------*/ +/* Set up the interrupt flag (both methods) and signal */ +/* handler (terminal-based method only). */ +/*------------------------------------------------------*/ + +void enable_interrupt() +{ + InterruptPending = 0; + oldinthandler = signal(SIGINT, handler); +} + +void disable_interrupt() +{ + if (InterruptPending) + InterruptPending = 0; + signal(SIGINT, oldinthandler); +} + +#else + +static jmp_buf jmpenv; + +/* static void handler(void) */ +static void handler(int sig) +{ + Fprintf(stderr,"\nInterrupt (%d)!!\n", sig); + Fflush(stderr); + longjmp(jmpenv,1); +} + +/*----------------------------------------------------------------------*/ +/* Note that this cover-all routine is not called from the Tcl/Tk */ +/* version, which replaces it with the script "lvs". */ +/* return 1 if the two are identical. Try to resolve automorphisms. */ +/*----------------------------------------------------------------------*/ + +int Compare(char *cell1, char *cell2) +{ + int automorphisms; + + CreateTwoLists(cell1, -1, cell2, -1); + Permute(); + while (!Iterate()); + ExhaustiveSubdivision = 1; + while (!Iterate()); + + automorphisms = VerifyMatching(); + if (automorphisms == -1) { + MatchFail(cell1, cell2); + Fprintf(stderr, "Circuits do not match.\n"); + PrintIllegalClasses(); + return(0); + } + if (automorphisms == 0) Fprintf(stdout, "Circuits match correctly.\n"); + if (PropertyErrorDetected == 1) { + Fprintf(stdout, "There were property errors.\n"); + PrintPropertyResults(); + } + else if (PropertyErrorDetected == -1) { + Fprintf(stdout, "There were missing properties.\n"); + PrintPropertyResults(); + } + if (automorphisms == 0) return(1); + + Fprintf(stdout, "Circuits match with %d automorphisms.\n", automorphisms); + if (VerboseOutput) PrintAutomorphisms(); + + /* arbitrarily resolve automorphisms */ + Fprintf(stdout, "\n"); + Fprintf(stdout, "Arbitrarily resolving automorphisms:\n"); + while ((automorphisms = ResolveAutomorphisms()) > 0) ; + if (automorphisms == -1) { + MatchFail(cell1, cell2); + Fprintf(stdout, "Circuits do not match.\n"); + return(0); + } + Fprintf(stdout, "Circuits match correctly.\n"); + return(1); +} + + +void NETCOMP(void) +/* a simple command interpreter to manage embedding/routing */ +{ + char name[100]; + char name2[100]; + char ch; + + setjmp(jmpenv); + signal(SIGINT,handler); + MagicSeed(time(NULL)); + + do { + promptstring("NETCMP command: ", name); + ch = name[0]; + + switch (ch) { + case 'c': + promptstring("Enter cell 1: ",name); + promptstring("Enter cell 2: ",name2); + CreateTwoLists(name, -1, name2, -1); +#ifdef DEBUG_ALLOC + PrintCoreStats(); +#endif + break; + case 'i': + if (!Iterate()) Printf("Please iterate again.\n"); + else Printf("No fractures made: we're done.\n"); + break; + case 's': + SummarizeElementClasses(ElementClasses); + SummarizeNodeClasses(NodeClasses); + break; + case 'P': + PrintElementClasses(ElementClasses, -1, 0); + PrintNodeClasses(NodeClasses, -1, 0); + break; + case 'r': + while (!Iterate()) ; + /* fall through to 'v' below */ + case 'v': + if (ElementClasses == NULL || NodeClasses == NULL) + Printf("Must initialize data structures first.\n"); + else { + int automorphisms; + automorphisms = VerifyMatching(); + if (automorphisms == -1) { + PrintIllegalClasses(); + Fprintf(stdout, "Netlists do not match.\n"); + } + else { + if (automorphisms) + Printf("Circuits match with %d automorphisms.\n", automorphisms); + else Printf("Circuits match correctly.\n"); + } + } + break; + case 'R': + if (ElementClasses == NULL || NodeClasses == NULL) + Printf("Must initialize data structures first.\n"); + else { + int automorphisms; + while (!Iterate()) ; + automorphisms = VerifyMatching(); + if (automorphisms == -1) Fprintf(stdout, "Netlists do not match.\n"); + else { + Printf("Netlists match with %d automorphisms.\n", automorphisms); + while ((automorphisms = ResolveAutomorphisms()) > 0) + Printf(" automorphisms = %d.\n", automorphisms); + if (automorphisms == -1) Fprintf(stdout, "Netlists do not match.\n"); + else Printf("Circuits match correctly.\n"); + } + } + break; + case 'a': + PrintAutomorphisms(); + break; + case 'd': + /* equivalence two devices */ + Printf("Force matching of two devices.\n"); + promptstring("Enter device in circuit 1: ",name); + promptstring("Enter device in circuit 2: ",name2); + if (EquivalenceElements(name, Circuit1->file, name2, Circuit2->file)) + Printf("Devices %s and %s are now equivalent.\n", name, name2); + else Printf("Unable to match devices %s and %s.\n",name, name2); + break; + case 'n': + /* equivalence two nodes */ + Printf("Force matching of two nets.\n"); + promptstring("Enter net in circuit 1: ",name); + promptstring("Enter net in circuit 2: ",name2); + if (EquivalenceNodes(name, Circuit1->file, name2, Circuit2->file)) + Printf("Nets %s and %s are now equivalent.\n", name, name2); + else Printf("Unable to match nets %s and %s.\n",name, name2); + break; + case 'p': + { + char model[100]; + /* equivalence two pins on a given class of element */ + Printf("Allow permutation of two pins.\n"); + promptstring("Enter cellname: ",model); + promptstring("Enter pin 1: ",name); + promptstring("Enter pin 2: ",name2); + if (PermuteSetup(model, -1, name, name2)) + Printf("%s == %s\n",name, name2); + else Printf("Unable to permute pins %s, %s.\n",name, name2); + break; + } + case 't': + if (PermuteSetup("n", -1, "drain", "source")) + Printf("n-channel: source == drain.\n"); + if (PermuteSetup("p", -1, "drain", "source")) + Printf("p-channel: source == drain.\n"); + if (PermuteSetup("e", -1, "bottom_a", "bottom_b")) + Printf("poly cap: permuting poly1 regions.\n"); + if (PermuteSetup("r", -1, "end_a", "end_b")) + Printf("resistor: permuting endpoints.\n"); + if (PermuteSetup("c", -1, "top", "bottom")) + Printf("capacitor: permuting sides.\n"); + break; + case 'x': + ExhaustiveSubdivision = !ExhaustiveSubdivision; + Printf("Exhaustive subdivision %s.\n", + ExhaustiveSubdivision ? "ENABLED" : "DISABLED"); + break; + case 'o': + RegroupDataStructures(); + break; + case 'q': break; + case 'Q' : exit(0); + default: + Printf("(c)reate internal data structure\n"); + Printf("do an (i)teration\n"); + Printf("(r)un to completion (convergence)\n"); + Printf("(R)un to completion (resolve automorphisms)\n"); + Printf("(v)erify results\n"); + Printf("print (a)utomorphisms\n"); + Printf("equate two (d)evices\n"); + Printf("equate two (n)ets\n"); + Printf("(p)ermute pins on elements\n"); + Printf("enable (t)ransistor permutations\n"); + Printf("toggle e(x)haustive subdivision\n"); + Printf("(P)rint internal data structure\n"); + Printf("(s)ummarize internal data structure\n"); + Printf("start (o)ver (reset data structures)\n"); + Printf("(q)uit NETCMP, (Q)uit NETGEN\n"); + break; + } + } while (ch != 'q'); + signal(SIGINT,SIG_DFL); +} + +/* endif TCL_NETGEN */ +#endif + diff --git a/base/netcmp.h b/base/netcmp.h new file mode 100644 index 0000000..240e822 --- /dev/null +++ b/base/netcmp.h @@ -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 + diff --git a/base/netfile.c b/base/netfile.c new file mode 100644 index 0000000..2873ce0 --- /dev/null +++ b/base/netfile.c @@ -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 +#include +#include +#include +#include /* for SGI */ +#ifdef IBMPC +#include /* for calloc */ +#endif + +#ifdef TCL_NETGEN +#include +#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 /* read, write */ +#include +#else /* not IBMPC */ +#ifdef VMUNIX +#ifdef BSD +#include +#include +#include +#else /* not BSD */ +#include +#include +#include +#include +#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 */ diff --git a/base/netfile.h b/base/netfile.h new file mode 100644 index 0000000..721d18c --- /dev/null +++ b/base/netfile.h @@ -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 */ diff --git a/base/netgen.c b/base/netgen.c new file mode 100644 index 0000000..84b8d4a --- /dev/null +++ b/base/netgen.c @@ -0,0 +1,2741 @@ +/* "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.c -- most of the netlist manipulation routines and + embedded-language specification routines. +*/ + +#include "config.h" + +#include +#include /* for strtof() */ +#include +#include /* toupper() */ +#ifdef IBMPC +#include +#endif + +#include "netgen.h" +#include "hash.h" +#include "objlist.h" +#include "netfile.h" +#include "print.h" +#include "netcmp.h" + +int Debug = 0; +int VerboseOutput = 1; /* by default, we get verbose output */ +int IgnoreRC = 0; + +int NextNode; + +int Composition = NONE; +int QuickSearch = 0; + +int AddToExistingDefinition = 0; /* default: overwrite cell when reopened */ + +extern int errno; /* Defined in stdlib.h */ + +#define MAX_STATIC_STRINGS 5 +static char staticstrings[MAX_STATIC_STRINGS][200]; +static int laststring; + +extern struct hashlist **spiceparams; /* From spice.c */ + +char *Str(char *format, ...) +{ + va_list ap; + + laststring++; + laststring = laststring % MAX_STATIC_STRINGS; + + va_start(ap, format); + vsprintf(staticstrings[laststring], format, ap); + va_end(ap); + return(staticstrings[laststring]); +} + +/*--------------------------------------------------------------*/ +/* Push a token on to the expression stack */ +/*--------------------------------------------------------------*/ + +void PushTok(int toktype, void *tval, struct tokstack **top) +{ + struct tokstack *newstack; + double dval; + char *string; + + newstack = (struct tokstack *)CALLOC(1, sizeof(struct tokstack)); + newstack->toktype = toktype; + + switch (toktype) { + case TOK_DOUBLE: + newstack->data.dvalue = *((double *)tval); + break; + case TOK_STRING: + newstack->data.string = strsave((char *)tval); + break; + case TOK_FUNC_OPEN: + case TOK_FUNC_CLOSE: + case TOK_GROUP_OPEN: + case TOK_GROUP_CLOSE: + case TOK_FUNC_IF: + case TOK_FUNC_THEN: + case TOK_FUNC_ELSE: + newstack->data.dvalue = 0.0; + break; + default: + newstack->data.string = NULL; + break; + } + newstack->last = NULL; + newstack->next = *top; + if (*top != NULL) + (*top)->last = newstack; + *top = newstack; +} + +/*--------------------------------------------------------------*/ +/* Pop a token off of the expression stack, freeing the memory */ +/* associated with it. */ +/*--------------------------------------------------------------*/ + +void PopTok(struct tokstack **top) +{ + struct tokstack *stackptr; + + stackptr = *top; + if (!stackptr) return; + *top = stackptr->next; + (*top)->last = NULL; + + /* Free the memory allocated to the popped entry */ + if (stackptr->toktype == TOK_STRING) + FREE(stackptr->data.string); + FREE(stackptr); +} + +/*--------------------------------------------------------------*/ +/* Make a copy of an expression */ +/*--------------------------------------------------------------*/ + +struct tokstack *CopyTokStack(struct tokstack *stack) +{ + struct tokstack *stackptr, *newstack, *newptr; + + newptr = NULL; + if (stack == NULL) return NULL; /* Shouldn't happen. . . */ + for (stackptr = stack; stackptr->next; stackptr = stackptr->next); + for (; stackptr; stackptr = stackptr->last) { + newstack = (struct tokstack *)CALLOC(1, sizeof(struct tokstack)); + newstack->last = NULL; + newstack->toktype = stackptr->toktype; + switch (stackptr->toktype) { + case TOK_STRING: + newstack->data.string = strsave(stackptr->data.string); + break; + default: + newstack->data.dvalue = stackptr->data.dvalue; + break; + } + newstack->next = newptr; + if (newptr) newptr->last = newstack; + newptr = newstack; + } + return newptr; +} + +/*--------------------------------------------------------------*/ +/* Get a value from a token by converting a string, potentially */ +/* using unit suffixes, into a double floating-point value. */ +/* Return the value in "dval", and return a result of 1 if the */ +/* value was successfully converted, 0 if there was no value to */ +/* convert (empty string), and -1 if unable to convert the */ +/* string to a value (e.g., unknown parameter name). */ +/*--------------------------------------------------------------*/ + +int TokGetValue(char *estr, struct nlist *parent, int glob, double *dval) +{ + struct property *kl = NULL; + int result; + + if (*estr == '\0') return 0; + + /* Grab the last numerical value */ + + if (StringIsValue(estr)) { + result = ConvertStringToFloat(estr, dval); + if (result == 1) return 1; + } + + /* No numerical value found. Try substituting parameters */ + + if (glob == TRUE) { + /* Check global parameters */ + if (spiceparams != NULL) { + kl = (struct property *)HashLookup(estr, + spiceparams, OBJHASHSIZE); + if (kl != NULL) { + result = ConvertStringToFloat(kl->pdefault.string, dval); + } + } + } + else { + /* Check local parameters */ + kl = (struct property *)HashLookup(estr, + parent->proptab, OBJHASHSIZE); + if (kl != NULL) { + switch(kl->type) { + case PROP_STRING: + result = ConvertStringToFloat(kl->pdefault.string, dval); + break; + case PROP_DOUBLE: + case PROP_VALUE: + *dval = kl->pdefault.dval; + result = 1; + break; + case PROP_INTEGER: + *dval = (double)kl->pdefault.ival; + result = 1; + break; + } + } + } + return ((result == 0) ? -1 : 1); +} + +/*--------------------------------------------------------------*/ +/* Work through the property list of an instance, looking for */ +/* properties that are marked as expressions. For each */ +/* expression, parse and attempt to reduce to a simpler */ +/* expression, preferably a single value. "glob" is TRUE when */ +/* reading in a netlist, and substitutions should be made from */ +/* the global parameter list. "glob" is FALSE when elaborating */ +/* the netlist, and substitutions should be made from the */ +/* property list of the parent. If an expression resolves to a */ +/* single value, then replace the property type. */ +/*--------------------------------------------------------------*/ + +int ReduceExpressions(struct objlist *instprop, + struct nlist *parent, int glob) { + + struct tokstack *expstack, *stackptr, *lptr, *nptr; + struct valuelist *kv; + struct property *kl = NULL; + char *estr, *tstr, *sstr; + int toktype, functype, i, result, modified, numlast; + double dval; + + if (instprop == NULL) return 0; // Nothing to do + if (instprop->type != PROPERTY) return -1; // Shouldn't happen + + for (i = 0;; i++) { + + kv = &(instprop->instance.props[i]); + + if (kv->type == PROP_EXPRESSION) { + expstack = kv->value.stack; + } + else if (kv->type == PROP_STRING) { + expstack = NULL; + estr = kv->value.string; + tstr = estr; + + numlast = 0; + while (*tstr != '\0') { + switch(*tstr) { + + case '+': + if (numlast == 0) { + /* This is part of a number */ + dval = strtod(estr, &sstr); + if (sstr > estr && sstr > tstr) { + tstr = sstr - 1; + numlast = 1; + } + break; + } + /* Not a number, so must be arithmetic */ + *tstr = '\0'; + result = TokGetValue(estr, parent, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_PLUS, NULL, &expstack); + estr = tstr + 1; + numlast = 0; + break; + + case '-': + if (numlast == 0) { + /* This is part of a number */ + dval = strtod(estr, &sstr); + if (sstr > estr && sstr > tstr) { + tstr = sstr - 1; + numlast = 1; + } + break; + } + /* Not a number, so must be arithmetic */ + *tstr = '\0'; + result = TokGetValue(estr, parent, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_MINUS, NULL, &expstack); + estr = tstr + 1; + numlast = 0; + break; + + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': case '0': + /* Numerical value. Use strtod() to capture */ + if (numlast == 1) break; + dval = strtod(estr, &sstr); + if (sstr > estr && sstr > tstr) { + tstr = sstr - 1; + numlast = 1; + } + break; + + case '/': + *tstr = '\0'; + result = TokGetValue(estr, parent, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_DIVIDE, NULL, &expstack); + estr = tstr + 1; + numlast = 0; + break; + + case '*': + *tstr = '\0'; + result = TokGetValue(estr, parent, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_MULTIPLY, NULL, &expstack); + estr = tstr + 1; + numlast = 0; + break; + + case '(': + *tstr = '\0'; + + /* Check for predefined function keywords */ + + if (!strcmp(estr, "IF")) { + PushTok(TOK_FUNC_IF, NULL, &expstack); + } + else { + /* Treat as a parenthetical grouping */ + + result = TokGetValue(estr, parent, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_FUNC_OPEN, NULL, &expstack); + } + estr = tstr + 1; + numlast = 0; + break; + + case ')': + *tstr = '\0'; + if (expstack == NULL) break; + switch (expstack->toktype) { + case TOK_FUNC_THEN: + PushTok(TOK_FUNC_ELSE, NULL, &expstack); + break; + default: + PushTok(TOK_FUNC_CLOSE, NULL, &expstack); + break; + } + numlast = 1; + estr = tstr + 1; + break; + + case '{': + *tstr = '\0'; + result = TokGetValue(estr, parent, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_GROUP_OPEN, NULL, &expstack); + estr = tstr + 1; + numlast = 0; + break; + + case '}': + *tstr = '\0'; + result = TokGetValue(estr, parent, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + PushTok(TOK_GROUP_CLOSE, NULL, &expstack); + estr = tstr + 1; + numlast = 1; + break; + + case '!': + if (*(tstr + 1) == '=') { + *tstr = '\0'; + result = TokGetValue(estr, parent, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_NE, NULL, &expstack); + } + numlast = 0; + break; + + case '=': + if (*(tstr + 1) == '=') { + *tstr = '\0'; + result = TokGetValue(estr, parent, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_EQ, NULL, &expstack); + numlast = 0; + } + break; + + case '>': + *tstr = '\0'; + result = TokGetValue(estr, parent, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + + if (*(tstr + 1) == '=') { + PushTok(TOK_GE, NULL, &expstack); + tstr++; + } + else + PushTok(TOK_GT, NULL, &expstack); + estr = tstr + 1; + numlast = 0; + break; + + case '<': + *tstr = '\0'; + result = TokGetValue(estr, parent, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + + if (*(tstr + 1) == '=') { + PushTok(TOK_LE, NULL, &expstack); + tstr++; + } + else + PushTok(TOK_LT, NULL, &expstack); + estr = tstr + 1; + numlast = 0; + break; + + case ',': + *tstr = '\0'; + result = TokGetValue(estr, parent, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + if (expstack == NULL) break; + lptr = expstack; + while (lptr->next) { + lptr = lptr->next; + if (lptr->toktype == TOK_FUNC_THEN) { + PushTok(TOK_FUNC_ELSE, NULL, &expstack); + break; + } + else if (lptr->toktype == TOK_FUNC_IF) { + PushTok(TOK_FUNC_THEN, NULL, &expstack); + break; + } + } + estr = tstr + 1; + numlast = 0; + break; + + default: + break; + } + tstr++; + } + result = TokGetValue(estr, parent, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + + FREE(kv->value.string); + kv->value.stack = expstack; + kv->type = PROP_EXPRESSION; + } + + // Find the beginning of the expression, which is the bottom of + // the stack. + for (stackptr = kv->value.stack; stackptr != NULL && + stackptr->next != NULL; stackptr = stackptr->next); + + // For each pass, start at the bottom and work forward + expstack = stackptr; + + modified = 1; + while (modified) { + double dval1, dval2; + + modified = 0; + + // Reduce conditionals + + for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { + switch (stackptr->toktype) { + case TOK_LE: + case TOK_LT: + case TOK_GE: + case TOK_GT: + case TOK_EQ: + case TOK_NE: + lptr = stackptr->last; + nptr = stackptr->next; + if (lptr && nptr && (lptr->toktype == TOK_DOUBLE) && + (nptr->toktype == TOK_DOUBLE)) { + + switch (stackptr->toktype) { + case TOK_LE: + if (nptr->data.dvalue <= lptr->data.dvalue) { + stackptr->data.dvalue = 1.0; + } + else { + stackptr->data.dvalue = 0.0; + } + break; + case TOK_LT: + if (nptr->data.dvalue < lptr->data.dvalue) { + stackptr->data.dvalue = 1.0; + } + else { + stackptr->data.dvalue = 0.0; + } + break; + case TOK_GE: + if (nptr->data.dvalue >= lptr->data.dvalue) { + stackptr->data.dvalue = 1.0; + } + else { + stackptr->data.dvalue = 0.0; + } + break; + case TOK_GT: + if (nptr->data.dvalue > lptr->data.dvalue) { + stackptr->data.dvalue = 1.0; + } + else { + stackptr->data.dvalue = 0.0; + } + break; + case TOK_EQ: + if (nptr->data.dvalue == lptr->data.dvalue) { + stackptr->data.dvalue = 1.0; + } + else { + stackptr->data.dvalue = 0.0; + } + break; + case TOK_NE: + if (nptr->data.dvalue != lptr->data.dvalue) { + stackptr->data.dvalue = 1.0; + } + else { + stackptr->data.dvalue = 0.0; + } + break; + } + modified = 1; + stackptr->toktype = TOK_DOUBLE; + stackptr->last = lptr->last; + if (lptr->last) lptr->last->next = stackptr; + else kv->value.stack = stackptr; + stackptr->next = nptr->next; + if (nptr->next) nptr->next->last = stackptr; + if (expstack == nptr) expstack = stackptr; + + FREE(nptr); + FREE(lptr); + } + } + } + + // Reduce IF(a,b,c) + + for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { + struct tokstack *ifptr, *thenptr; + if (stackptr->toktype == TOK_FUNC_IF) { + ifptr = stackptr->last; + if (ifptr->toktype == TOK_DOUBLE) { + stackptr->toktype = TOK_FUNC_OPEN; + if (ifptr->data.dvalue == 0.0) { + /* Keep ELSE value, remove IF and THEN */ + for (thenptr = ifptr; thenptr->toktype != + TOK_FUNC_ELSE; ) { + lptr = thenptr->last; + nptr = thenptr->next; + lptr->next = nptr; + nptr->last = lptr; + if (thenptr->toktype == TOK_STRING) + FREE(thenptr->data.string); + FREE(thenptr); + thenptr = lptr; + } + /* Free the TOK_FUNC_ELSE record */ + lptr = thenptr->last; + nptr = thenptr->next; + lptr->next = nptr; + nptr->last = lptr; + FREE(thenptr); + modified = 1; + } + else { + /* Keep THEN value, remove IF and ELSE */ + /* Free the conditional result value record */ + lptr = ifptr->last; + nptr = ifptr->next; + lptr->next = nptr; + nptr->last = lptr; + FREE(ifptr); + thenptr = nptr; + + /* Free the TOK_FUNC_THEN record */ + lptr = thenptr->last; + nptr = thenptr->next; + lptr->next = nptr; + nptr->last = lptr; + FREE(thenptr); + + /* Free to end of IF block */ + for (thenptr = nptr->last; thenptr->toktype != + TOK_FUNC_CLOSE; ) { + lptr = thenptr->last; + nptr = thenptr->next; + lptr->next = nptr; + nptr->last = lptr; + if (thenptr->toktype == TOK_STRING) + FREE(thenptr->data.string); + FREE(thenptr); + thenptr = lptr; + } + modified = 1; + } + } + } + } + + // Reduce (value) * (value) and (value) / (value) + + for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { + switch (stackptr->toktype) { + case TOK_MULTIPLY: + case TOK_DIVIDE: + lptr = stackptr->last; + nptr = stackptr->next; + if (lptr && nptr && (lptr->toktype == TOK_DOUBLE) && + (nptr->toktype == TOK_DOUBLE)) { + + if (stackptr->toktype == TOK_MULTIPLY) + stackptr->data.dvalue = nptr->data.dvalue * + lptr->data.dvalue; + else + stackptr->data.dvalue = nptr->data.dvalue / + lptr->data.dvalue; + + modified = 1; + stackptr->toktype = TOK_DOUBLE; + stackptr->last = lptr->last; + if (lptr->last) lptr->last->next = stackptr; + else kv->value.stack = stackptr; + stackptr->next = nptr->next; + if (nptr->next) nptr->next->last = stackptr; + if (expstack == nptr) expstack = stackptr; + + FREE(nptr); + FREE(lptr); + } + } + } + + // Reduce (value) + (value) and (value) - (value) + + for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { + switch (stackptr->toktype) { + case TOK_PLUS: + case TOK_MINUS: + lptr = stackptr->last; + nptr = stackptr->next; + if (lptr && nptr && (lptr->toktype == TOK_DOUBLE) && + (nptr->toktype == TOK_DOUBLE)) { + + if (stackptr->toktype == TOK_PLUS) + stackptr->data.dvalue = nptr->data.dvalue + + lptr->data.dvalue; + else + stackptr->data.dvalue = nptr->data.dvalue - + lptr->data.dvalue; + + modified = 1; + stackptr->toktype = TOK_DOUBLE; + stackptr->last = lptr->last; + if (lptr->last) lptr->last->next = stackptr; + else kv->value.stack = stackptr; + stackptr->next = nptr->next; + if (nptr->next) nptr->next->last = stackptr; + if (expstack == nptr) expstack = stackptr; + + FREE(nptr); + FREE(lptr); + } + } + } + + // Reduce {value} and (value) + + for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { + switch (stackptr->toktype) { + case TOK_DOUBLE: + lptr = stackptr->last; + nptr = stackptr->next; + if (lptr && nptr && + (((nptr->toktype == TOK_FUNC_OPEN) && + (lptr->toktype == TOK_FUNC_CLOSE)) || + ((nptr->toktype == TOK_GROUP_OPEN) && + (lptr->toktype == TOK_GROUP_CLOSE)))) { + + modified = 1; + stackptr->last = lptr->last; + if (lptr->last) lptr->last->next = stackptr; + else kv->value.stack = stackptr; + stackptr->next = nptr->next; + if (nptr->next) nptr->next->last = stackptr; + if (expstack == nptr) expstack = stackptr; + + FREE(nptr); + FREE(lptr); + } + break; + } + } + + // Replace value if string can be substituted with a number + + for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { + switch (stackptr->toktype) { + case TOK_STRING: + result = TokGetValue(stackptr->data.string, parent, + glob, &dval); + if (result == 1) { + stackptr->toktype = TOK_DOUBLE; + FREE(stackptr->data.string); + stackptr->data.dvalue = dval; + modified = 1; + } + break; + } + } + } + + // Replace the expression with the reduced expression or + // value. + + expstack = kv->value.stack; // Now pointing at the end + + if (expstack && expstack->next == NULL) { + if (expstack->toktype == TOK_DOUBLE) { + kv->type = PROP_DOUBLE; + kv->value.dval = expstack->data.dvalue; + } + else if (expstack->toktype == TOK_STRING) { + kv->type = PROP_STRING; + kv->value.string = strsave(expstack->data.string); + } + } + else { + // Still an expression; do nothing + } + + // Free up the stack if it's not being used + + if (kv->type != PROP_EXPRESSION) + { + while (expstack != NULL) { + nptr = expstack->next; + if (expstack->toktype == TOK_STRING) + FREE(expstack->data.string); + FREE(expstack); + expstack = nptr; + } + } + + if (kv->type == PROP_ENDLIST) + break; + } + + return 0; +} + +/*----------------------------------------------------------------------*/ +/* Delete a property from the master cell record. */ +/*----------------------------------------------------------------------*/ + +int +PropertyDelete(char *name, int fnum, char *key) +{ + struct property *kl = NULL; + struct nlist *tc; + int result; + + if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + result = PropertyDelete(name, Circuit1->file, key); + result = PropertyDelete(name, Circuit2->file, key); + return result; + } + + tc = LookupCellFile(name, fnum); + if (tc == NULL) { + Printf("No device %s found for PropertyDelete()\n", name); + return -1; + } + else if (key == NULL) { + + /* key == NULL means delete all properties. */ + + RecurseHashTable(tc->proptab, OBJHASHSIZE, freeprop); + HashKill(tc->proptab, OBJHASHSIZE); + FREE(tc->proptab); + tc->proptab = (struct hashlist **)CALLOC(OBJHASHSIZE, + sizeof(struct hashlist *)); + } + else { + kl = (struct property *)HashLookup(key, tc->proptab, OBJHASHSIZE); + if (kl != NULL) { + if (kl->type == PROP_STRING || kl->type == PROP_EXPRESSION) + FREE(kl->pdefault.string); + FREE(kl->key); + HashDelete(key, tc->proptab, OBJHASHSIZE); + } + else { + Printf("No property %s found for device %s\n", key, name); + return -1; + } + } + return 0; +} + +/*----------------------------------------------------------------------*/ +/* Set the tolerance of a property in the master cell record. */ +/*----------------------------------------------------------------------*/ + +int +PropertyTolerance(char *name, int fnum, char *key, int ival, double dval) +{ + struct property *kl = NULL; + struct nlist *tc; + int result; + + if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + result = PropertyTolerance(name, Circuit1->file, key, ival, dval); + result = PropertyTolerance(name, Circuit2->file, key, ival, dval); + return result; + } + + tc = LookupCellFile(name, fnum); + if (tc == NULL) { + Printf("No device %s found for PropertyTolerance()\n", name); + return -1; + } + + kl = (struct property *)HashLookup(key, tc->proptab, OBJHASHSIZE); + if (kl == NULL) { + Printf("No property %s found for device %s\n", key, name); + return -1; + } + else { + switch (kl->type) { + case PROP_DOUBLE: + case PROP_VALUE: + kl->slop.dval = dval; + break; + case PROP_INTEGER: + case PROP_STRING: + case PROP_EXPRESSION: + kl->slop.ival = ival; + break; + } + } + return 0; +} + +/*----------------------------------------------------------------------*/ +/* Add a new value property to the indicated cell */ +/* Value properties are used for resistors and capacitors in SPICE */ +/* netlists where the value is not syntactically like other properties. */ +/* For the purpose of netgen, it is treated like a PROP_DOUBLE except */ +/* when reading and writing netlist files. */ +/*----------------------------------------------------------------------*/ + +struct property *PropertyValue(char *name, int fnum, char *key, + double slop, double pdefault) +{ + struct property *kl = NULL; + struct nlist *tc; + + if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + PropertyValue(name, Circuit1->file, key, slop, pdefault); + PropertyValue(name, Circuit2->file, key, slop, pdefault); + return; + } + + tc = LookupCellFile(name, fnum); + if (tc == NULL) + Printf("No device %s found for PropertyValue()\n", name); + else if ((kl = (struct property *)HashLookup(key, tc->proptab, + OBJHASHSIZE)) != NULL) { + Printf("Device %s already has property named \"%s\"\n", name, key); + } + else { + kl = NewProperty(); + kl->key = strsave(key); + kl->idx = 0; + kl->type = PROP_VALUE; + kl->slop.dval = slop; + kl->pdefault.dval = pdefault; + HashPtrInstall(kl->key, kl, tc->proptab, OBJHASHSIZE); + } + return kl; +} + +/*----------------------------------------------------------------------*/ +/* Add a new double-valued property key to the current cell */ +/*----------------------------------------------------------------------*/ + +struct property *PropertyDouble(char *name, int fnum, char *key, + double slop, double pdefault) +{ + struct property *kl = NULL; + struct nlist *tc; + + if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + PropertyDouble(name, Circuit1->file, key, slop, pdefault); + PropertyDouble(name, Circuit2->file, key, slop, pdefault); + return; + } + + tc = LookupCellFile(name, fnum); + if (tc == NULL) + Printf("No device %s found for PropertyDouble()\n", name); + else if ((kl = (struct property *)HashLookup(key, tc->proptab, + OBJHASHSIZE)) != NULL) { + Printf("Device %s already has property named \"%s\"\n", name, key); + } + else { + kl = NewProperty(); + kl->key = strsave(key); + kl->idx = 0; + kl->type = PROP_DOUBLE; + kl->slop.dval = slop; + kl->pdefault.dval = pdefault; + HashPtrInstall(kl->key, kl, tc->proptab, OBJHASHSIZE); + } + return kl; +} + +/*----------------------------------------------------------------------*/ + +struct property *PropertyInteger(char *name, int fnum, char *key, + int slop, int pdefault) +{ + struct property *kl = NULL; + struct nlist *tc; + + if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + PropertyInteger(name, Circuit1->file, key, slop, pdefault); + PropertyInteger(name, Circuit2->file, key, slop, pdefault); + return; + } + + tc = LookupCellFile(name, fnum); + if (tc == NULL) + Printf("No device %s found for PropertyInteger()\n", name); + else if ((kl = (struct property *)HashLookup(key, tc->proptab, + OBJHASHSIZE)) != NULL) { + Printf("Device %s already has property named \"%s\"\n", name, key); + } + else { + kl = NewProperty(); + kl->key = strsave(key); + kl->idx = 0; + kl->type = PROP_INTEGER; + kl->slop.ival = slop; + kl->pdefault.ival = pdefault; + HashPtrInstall(kl->key, kl, tc->proptab, OBJHASHSIZE); + } + return kl; +} + +/*----------------------------------------------------------------------*/ + +struct property *PropertyString(char *name, int fnum, char *key, int range, + char *pdefault) +{ + struct property *kl = NULL; + struct nlist *tc; + + if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + PropertyString(name, Circuit1->file, key, range, pdefault); + PropertyString(name, Circuit2->file, key, range, pdefault); + return; + } + + tc = LookupCellFile(name, fnum); + if (tc == NULL) + Printf("No device %s found for PropertyString()\n", name); + else if ((kl = (struct property *)HashLookup(key, tc->proptab, + OBJHASHSIZE)) != NULL) { + Printf("Device %s already has property named \"%s\"\n", name, key); + } + else { + kl = NewProperty(); + kl->key = strsave(key); + kl->idx = 0; + kl->type = PROP_STRING; + kl->slop.ival = (range >= 0) ? range : 0; + if (pdefault != NULL) + kl->pdefault.string = strsave(pdefault); + else + kl->pdefault.string = NULL; + HashPtrInstall(kl->key, kl, tc->proptab, OBJHASHSIZE); + } + return kl; +} + +/*----------------------------------------------------------------------*/ +/* Find all instances of type "instance" in cell "name". For each one, */ +/* determine if it can be combined in parallel with other devices. */ +/* Capacitors add area or value. Resistors add width, or run a */ +/* parallel calculation on value. Transistors add width. */ +/* If "aggressive" is FALSE, then combinations may be made only if */ +/* the devices have the same properties (except "M"), and will combine */ +/* by incrementing "M". If "aggressive" is TRUE, then the device */ +/* properties (width, area, etc.) will be modified in combination. */ +/* Devices with pin permutations are parallel if nodes match when */ +/* permuted. */ +/*----------------------------------------------------------------------*/ + +void CombineParallel(char *name, int fnum, char *instance, int aggressive) +{ + struct nlist *tc, *tp; + struct objlist *ob1, *ob2; + + if ((tc = LookupCellFile(name, fnum)) == NULL) return; + if ((tp = LookupCellFile(instance, fnum)) == NULL) return; + + for (ob1 = tc->cell; ob1; ob1 = ob1->next) { + if (ob1->type == FIRSTPIN && (*matchfunc)(ob1->model.class, tc->name)) { + for (ob2 = ob1->next; ob2; ob2 = ob2->next) { + if (ob2->type == FIRSTPIN && (*matchfunc)(ob2->model.class, + tc->name)) { + /* To-do: Handle permutations! */ + while (ob1->node == ob2->node) { + ob1 = ob1->next; + ob2 = ob2->next; + if (ob1 == NULL || ob1->type <= FIRSTPIN) break; + if (ob2 == NULL || ob2->type <= FIRSTPIN) break; + } + if ((ob1 && ob1->type == PROPERTY) && + (ob2 && ob2->type == PROPERTY)) { + if (PropertyMatch(ob1, ob2, FALSE)) { + /* WIP */ + } + } + } + } + } + } +} + +/*----------------------------------------------------------------------*/ +/* Declare the element class of the current cell */ +/*----------------------------------------------------------------------*/ + +void SetClass(unsigned char class) +{ + if (CurrentCell == NULL) + Printf("No current cell for SetClass()\n"); + else + CurrentCell->class = class; +} + +/*----------------------------------------------------------------------*/ + +void ReopenCellDef(char *name, int fnum) +{ + struct objlist *ob; + + if (Debug) Printf("Reopening cell definition: %s\n",name); + GarbageCollect(); + if ((CurrentCell = LookupCellFile(name, fnum)) == NULL) { + Printf("Undefined cell: %s\n", name); + return; + } + /* cell exists, so append to the end of it */ + NextNode = 1; + CurrentTail = CurrentCell->cell; + for (ob = CurrentTail; ob != NULL; ob = ob->next) { + CurrentTail = ob; + if (ob->node >= NextNode) NextNode = ob->node + 1; + } +} + +/*----------------------------------------------------------------------*/ + +void CellDef(char *name, int fnum) +{ + struct nlist *np; + + if (Debug) Printf("Defining cell: %s\n",name); + GarbageCollect(); + if ((CurrentCell = LookupCellFile(name, fnum)) != NULL) { + if (AddToExistingDefinition) { + ReopenCellDef(name, fnum); + return ; + } + else { + Printf("Cell: %s exists already, and will be overwritten.\n", name); + CellDelete(name, fnum); + } + } + /* install a new cell in lookup table (hashed) */ + np = InstallInCellHashTable(name, fnum); + CurrentCell = LookupCellFile(name, fnum); + CurrentCell->class = CLASS_SUBCKT; /* default */ + CurrentCell->flags = 0; + + LastPlaced = NULL; + CurrentTail = NULL; + FreeNodeNames(CurrentCell); + NextNode = 1; +} + +/*----------------------------------------------------------------------*/ +/* Same as CellDef() above, but mark cell as case-insensitive. */ +/* This routine is used only by the ReadSpice() function. */ +/*----------------------------------------------------------------------*/ + +void CellDefNoCase(char *name, int file) +{ + CellDef(name, file); + CurrentCell->file = file; + CurrentCell->flags |= CELL_NOCASE; +} + +/*----------------------------------------------------------------------*/ + +int IsIgnored(char *name, int file) +{ + struct IgnoreList *ilist; + char *nptr = name; + + for (ilist = ClassIgnore; ilist; ilist = ilist->next) + { + if ((file == -1) || (ilist->file == -1) || (file == ilist->file)) + if ((*matchfunc)(ilist->class, nptr)) + return 1; + } + return 0; +} + +/*----------------------------------------------------------------------*/ + +void Port(char *name) +{ + struct objlist *tp; + + if (Debug) Printf(" Defining port: %s\n",name); + if ((tp = GetObject()) == NULL) { + perror("Failed GetObject in Port"); + return; + } + tp->type = PORT; /* port type */ + if (name == NULL) { + // Name becomes "no pins" and shows up in the pin matching + // output for both devices. + tp->name = strsave("(no pins)"); + tp->model.port = PROXY; + } + else { + tp->name = strsave(name); + tp->model.port = PORT; + } + tp->instance.name = NULL; + tp->node = -1; /* null node */ + tp->next = NULL; + AddToCurrentCell (tp); +} + +/*----------------------------------------------------------------------*/ + +int CountPorts(char *name, int fnum) +{ + struct nlist *tc; + struct objlist *ob; + int ports = 0; + + tc = LookupCellFile(name, fnum); + if (tc != NULL) { + for (ob = tc->cell; ob; ob = ob->next) { + if (ob->type != PORT) break; + ports++; + } + } + return ports; +} + +/*----------------------------------------------------------------------*/ + +void Node(char *name) +{ + struct objlist *tp; + + if (Debug) Printf(" Defining internal node: %s\n",name); + if ((tp = GetObject()) == NULL) { + perror("Failed GetObject in Node"); + return; + } + tp->name = strsave(name); + tp->type = NODE; /* internal node type */ + tp->model.class = NULL; + tp->instance.name = NULL; + tp->node = -1; /* null node */ + tp->next = NULL; + AddToCurrentCell (tp); +} + +/*----------------------------------------------------------------------*/ + +void Global(char *name) +{ + struct objlist *tp; + + // Check if "name" is already in the current cell as a global node + // or a port. If it is, then we're done. Otherwise, add "name" as + // a new global in CurrentCell. + + for (tp = CurrentCell->cell; tp; tp = tp->next) + if (tp->type == GLOBAL || tp->type == UNIQUEGLOBAL || tp->type == PORT) + if ((*matchfunc)(tp->name, name)) + return; + + if (Debug) Printf(" Defining global node: %s\n",name); + if ((tp = GetObject()) == NULL) { + perror("Failed GetObject in Global"); + return; + } + tp->name = strsave(name); + tp->type = GLOBAL; /* internal node type */ + tp->model.class = NULL; + tp->instance.name = NULL; + tp->node = -1; /* null node */ + tp->next = NULL; + AddToCurrentCell (tp); +} + +/*----------------------------------------------------------------------*/ + +void UniqueGlobal(char *name) +{ + struct objlist *tp; + + if (Debug) Printf(" Defining unique global node: %s\n",name); + if ((tp = GetObject()) == NULL) { + perror("Failed GetObject in UniqueGlobal"); + return; + } + + tp->name = strsave(name); + tp->type = UNIQUEGLOBAL; /* internal node type */ + tp->model.class = NULL; + tp->instance.name = NULL; + tp->node = -1; /* null node */ + tp->next = NULL; + AddToCurrentCell (tp); +} + +/*----------------------------------------------------------------------*/ + +void Instance(char *model, char *instancename) +{ + struct objlist *tp, *tp2; + struct nlist *instanced_cell; + int portnum; + char tmpname[512], tmpname2[512]; + int firstobj, fnum; + + if (Debug) Printf(" Instance: %s of class: %s\n", + instancename, model); + if (CurrentCell == NULL) { + Printf("No current cell for Instance(%s,%s)\n", model,instancename); + return; + } + fnum = CurrentCell->file; + if (IsIgnored(model, fnum)) { + Printf("Class '%s' instanced in input but is being ignored.\n", model); + return; + } + instanced_cell = LookupCellFile(model, fnum); + if (instanced_cell == NULL) { + Printf("Attempt to instance undefined model '%s'\n", model); + return; + } + /* class exists */ + instanced_cell->number++; /* one more allocated */ + portnum = 1; + firstobj = 1; + for (tp2 = instanced_cell->cell; tp2 != NULL; tp2 = tp2->next) + if (IsPort(tp2)) { + /* it is a port */ + tp = GetObject(); + if (tp == NULL) { + perror("Failed GetObject in Instance()"); + return; + } + strcpy(tmpname,instancename); + strcat(tmpname,SEPARATOR); + strcat(tmpname,tp2->name); + tp->name = strsave(tmpname); + tp->model.class = strsave(model); + tp->instance.name = strsave(instancename); + tp->type = portnum++; /* instance type */ + tp->node = -1; /* null node */ + tp->next = NULL; + AddToCurrentCell (tp); + if (firstobj) { + AddInstanceToCurrentCell(tp); + firstobj = 0; + } + } + /* now run through list of new objects, processing global ports */ + for (tp2 = instanced_cell->cell; tp2 != NULL; tp2 = tp2->next) { + /* check to see if it is a global port */ + if (tp2->type == GLOBAL) { + if (Debug) Printf(" processing global port: %s\n", + tp2->name); + strcpy(tmpname,instancename); + strcat(tmpname,SEPARATOR); + strcat(tmpname,tp2->name); + /* see if element already exists */ + if (LookupObject(tp2->name,CurrentCell) != NULL) + join(tp2->name, tmpname); + else { + /* define global node if not already there */ + Global(tp2->name); + join(tp2->name, tmpname); + } + } + else if (tp2->type == UNIQUEGLOBAL) { + if (Debug) Printf(" processing unique global port: %s\n", + tp2->name); + strcpy(tmpname,CurrentCell->name); + strcat(tmpname,INSTANCE_DELIMITER); + strcat(tmpname,instancename); + strcat(tmpname,SEPARATOR); + strcat(tmpname,tp2->name); + /* make this element UniqueGlobal */ + UniqueGlobal(tmpname); + strcpy(tmpname2,instancename); + strcat(tmpname2,SEPARATOR); + strcat(tmpname2,tp2->name); + Connect(tmpname,tmpname2); + } + } + /* now run through list of new objects, checking for shorted ports */ + for (tp2 = instanced_cell->cell; tp2 != NULL; tp2 = tp2->next) { + /* check to see if it is a unique port */ + /* remember to NOT consider unconnected ports (node = -1) + as being shorted out */ + + if (IsPort(tp2)) { + struct objlist *ob; + + ob = LookupObject(tp2->name, instanced_cell); + if (ob->node != -1 && !(*matchfunc)(tp2->name, + NodeAlias(instanced_cell, ob))) { + if (Debug) Printf("shorted ports found on Instance\n"); + strcpy(tmpname,instancename); + strcat(tmpname,SEPARATOR); + strcat(tmpname,tp2->name); + strcpy(tmpname2,instancename); + strcat(tmpname2,SEPARATOR); + strcat(tmpname2, NodeAlias(instanced_cell, ob)); + join(tmpname,tmpname2); + } + } + } +} + +/*----------------------------------------------------------------------*/ + +char *Next(char *name) +{ + int filenum = CurrentCell->file; + + /* generate a unique instance name with 'name') */ + char buffer[1024]; + int n; + + n = 0; + if (QuickSearch) { + struct nlist *tp; + tp = LookupCellFile(name, filenum); + if (tp != NULL) + n = tp->number; /* was +1, but would miss #2 */ + } + do { + n++; + sprintf(buffer, "%s%d", name, n); + } while (LookupInstance(buffer,CurrentCell) != NULL); + return (strsave(buffer)); +} + +/* + *--------------------------------------------------------------------- + * This procedure provides a versatile interface to Instance/Connect. + * Cell() accepts a variable length list of arguments, in either of + * two forms: (i) named arguments -- take the form "port=something" + * (ii) unnamed arguments, which are bound to ports in the order they + * appear. Arguments are read until all cell ports have been connected, + * or until a NULL is encountered. + * + * Returns the name of the instance, which remains valid at least + * until the next call to Cell(). + *--------------------------------------------------------------------- + */ + +char *Cell(char *inststr, char *model, ...) +{ + va_list ap; + char *nodelist; + char tmpname[512]; + struct nlist *instanced_cell; + struct objlist *head, *tp, *tp2; + struct objlist *namedporthead, *namedportp, *namedlisthead, *namedlistp; + int portnum, portlist, done; + char namedport[512]; /* tmp buffers */ + int filenum; + + static char *instancename = NULL; + char *instnameptr; + + if (CurrentCell == NULL) { + Printf("No current cell defined for call to Cell().\n"); + return NULL; + } + else + filenum = CurrentCell->file; + + if (Debug) Printf(" calling cell: %s\n",model); + if (IsIgnored(model, filenum)) { + Printf("Class '%s' instanced in input but is being ignored.\n", model); + return NULL; + } + instanced_cell = LookupCellFile(model, filenum); + if (instanced_cell == NULL) { + Printf("Attempt to instance undefined class '%s'\n", model); + return NULL; + } + /* class exists */ + tp2 = instanced_cell->cell; + portnum = 0; + while (tp2 != NULL) { + if (IsPort(tp2)) portnum++; + tp2 = tp2->next; + } + + /* now generate lists of nodes using variable length parameter list */ + va_start(ap, model); + head = NULL; + namedporthead = namedlisthead = NULL; + done = 0; + portlist = 0; + while (!done && portlist < portnum) { + struct objlist *tmp; + char *equals; + + nodelist = va_arg(ap, char *); + if (nodelist == NULL) break; /* out of while loop */ + + if (strchr(nodelist,'=') != NULL) { + /* we have a named element */ + struct objlist *tmpport, *tmpname; + struct nlist *oldCurCell; + int ports; + + strcpy(namedport, nodelist); + equals = strchr(namedport, '='); + *equals = '\0'; + equals++; /* point to first char of node */ + + /* need to get list out of cell: 'model' */ + oldCurCell = CurrentCell; + CurrentCell = instanced_cell; + tmpport = List(namedport); + CurrentCell = oldCurCell; + tmpname = List(equals); + + if ((ports = ListLen(tmpport)) != ListLen(tmpname)) { + Printf("List %s has %d elements, list %s has %d\n", + namedport, ListLen(tmpport), equals, ListLen(tmpname)); + done = 1; + } + else if (tmpport == NULL) { + Printf("List %s has no elements\n", namedport); + done = 1; + } + else if (tmpname == NULL) { + Printf("List %s has no elements\n", equals); + done = 1; + } + else { + portlist += ports; + namedporthead = ListCat(namedporthead, tmpport); + namedlisthead = ListCat(namedlisthead, tmpname); + } + } + else { + /* unnamed element, so add it to the list */ + tmp = List(nodelist); + if (tmp == NULL) { + Printf("No such pin '%s' in Cell(%s); Current cell = %s\n", + nodelist, model, CurrentCell->name); + done = 1; + } + else { + portlist += ListLen(tmp); + head = ListCat(head, tmp); + } + } + } + va_end(ap); + + if (inststr == NULL) { + if (instancename != NULL) + FreeString(instancename); + QuickSearch = 1; + instancename = Next(model); + QuickSearch = 0; + instnameptr = instancename; + } + else + instnameptr = inststr; + + Instance(model, instnameptr); + tp = head; + for (tp2 = instanced_cell->cell; tp2 != NULL; tp2 = tp2->next) { + if (IsPort(tp2)) { + strcpy(tmpname, instnameptr); + strcat(tmpname, SEPARATOR); + strcat(tmpname, tp2->name); + namedlistp = namedlisthead; + namedportp = namedporthead; + while (namedportp != NULL) { + if ((*matchfunc)(namedportp->name, tp2->name)) { + join(namedlistp->name, tmpname); + break; /* out of while loop */ + } + namedlistp = namedlistp->next; + namedportp = namedportp->next; + } + if (namedportp == NULL) { + /* port was NOT a named port, so connect to unnamed list */ + if (tp == NULL) { + Printf( "Not enough ports in Cell().\n"); + break; /* out of for loop */ + } + else { + join(tp->name, tmpname); + tp = tp->next; + } + } + } + } + return instnameptr; +} + +/*----------------------------------------------------------------------*/ +/* These default classes correspond to .sim file format types and other */ +/* basic classes, and may be used by any netlist-reading routine to */ +/* define basic types. The classes are only defined when called (in */ +/* contrast to netgen v. 1.3 and earlier, where they were pre-defined) */ +/*----------------------------------------------------------------------*/ + +char *P(char *fname, char *inststr, char *gate, char *drain, char *source) +{ + int fnum = CurrentCell->file; + + if (LookupCellFile("p", fnum) == NULL) { + CellDef("p", fnum); + Port("drain"); + Port("gate"); + Port("source"); + PropertyDouble("p", fnum, "length", 0.01, 0.0); + PropertyDouble("p", fnum, "width", 0.01, 0.0); + SetClass(CLASS_PMOS); + EndCell(); + if (fname) ReopenCellDef(fname, fnum); /* Reopen */ + } + return Cell(inststr, "p", drain, gate, source); +} + +/*----------------------------------------------------------------------*/ + +char *P4(char *fname, char *inststr, char *drain, char *gate, char *source, char *bulk) +{ + int fnum = CurrentCell->file; + + if (LookupCellFile("p4", fnum) == NULL) { + CellDef("p4", fnum); + Port("drain"); + Port("gate"); + Port("source"); + Port("well"); + PropertyDouble("p4", fnum, "length", 0.01, 0.0); + PropertyDouble("p4", fnum, "width", 0.01, 0.0); + SetClass(CLASS_PMOS4); + EndCell(); + if (fname) ReopenCellDef(fname, fnum); /* Reopen */ + } + return Cell(inststr, "p4", drain, gate, source, bulk); +} + +/*----------------------------------------------------------------------*/ + +char *N(char *fname, char *inststr, char *gate, char *drain, char *source) +{ + int fnum = CurrentCell->file; + + if (LookupCellFile("n", fnum) == NULL) { + CellDef("n", fnum); + Port("drain"); + Port("gate"); + Port("source"); + PropertyDouble("n", fnum, "length", 0.01, 0.0); + PropertyDouble("n", fnum, "width", 0.01, 0.0); + SetClass(CLASS_NMOS); + EndCell(); + if (fname) ReopenCellDef(fname, fnum); /* Reopen */ + } + return Cell(inststr, "n", drain, gate, source); +} + +/*----------------------------------------------------------------------*/ + +char *N4(char *fname, char *inststr, char *drain, char *gate, char *source, char *bulk) +{ + int fnum = CurrentCell->file; + + if (LookupCellFile("n4", fnum) == NULL) { + CellDef("n4", fnum); + Port("drain"); + Port("gate"); + Port("source"); + Port("bulk"); + PropertyDouble("n4", fnum, "length", 0.01, 0.0); + PropertyDouble("n4", fnum, "width", 0.01, 0.0); + SetClass(CLASS_NMOS4); + EndCell(); + if (fname) ReopenCellDef(fname, fnum); /* Reopen */ + } + return Cell(inststr, "n4", drain, gate, source, bulk); +} + +/*----------------------------------------------------------------------*/ + +char *E(char *fname, char *inststr, char *top, char *bottom_a, char *bottom_b) +{ + int fnum = CurrentCell->file; + + if (LookupCellFile("e", fnum) == NULL) { + CellDef("e", fnum); + Port("top"); + Port("bottom_a"); + Port("bottom_b"); + PropertyDouble("e", fnum, "length", 0.01, 0.0); + PropertyDouble("e", fnum, "width", 0.01, 0.0); + SetClass(CLASS_ECAP); + EndCell(); + if (fname) ReopenCellDef(fname, fnum); /* Reopen */ + } + return Cell(inststr, "e", top, bottom_a, bottom_b); +} + +/*----------------------------------------------------------------------*/ + +char *B(char *fname, char *inststr, char *collector, char *base, char *emitter) +{ + int fnum = CurrentCell->file; + + if (LookupCellFile("b", fnum) == NULL) { + CellDef("b", fnum); + Port("collector"); + Port("base"); + Port("emitter"); + SetClass(CLASS_NPN); + EndCell(); + if (fname) ReopenCellDef(fname, fnum); /* Reopen */ + } + return Cell(inststr, "b", collector, base, emitter); +} + +/*----------------------------------------------------------------------*/ + +char *Res(char *fname, char *inststr, char *end_a, char *end_b) +{ + int fnum = CurrentCell->file; + + if (LookupCellFile("r", fnum) == NULL) { + CellDef("r", fnum); + Port("end_a"); + Port("end_b"); + PropertyDouble("r", fnum, "value", 0.01, 0.0); + SetClass(CLASS_RES); + EndCell(); + if (fname) ReopenCellDef(fname, fnum); /* Reopen */ + } + return Cell(inststr, "r", end_a, end_b); +} + +/*----------------------------------------------------------------------*/ + +char *Res3(char *fname, char *inststr, char *rdummy, char *end_a, char *end_b) +{ + int fnum = CurrentCell->file; + + if (LookupCellFile("r3", fnum) == NULL) { + CellDef("r3", fnum); + Port("dummy"); + Port("end_a"); + Port("end_b"); + PropertyDouble("r3", fnum, "value", 0.01, 0.0); + SetClass(CLASS_RES3); + EndCell(); + if (fname) ReopenCellDef(fname, fnum); /* Reopen */ + } + return Cell(inststr, "r3", rdummy, end_a, end_b); +} + +/*----------------------------------------------------------------------*/ + +char *XLine(char *fname, char *inststr, char *node1, char *node2, + char *node3, char *node4) +{ + int fnum = CurrentCell->file; + + if (LookupCellFile("t", fnum) == NULL) { + CellDef("t", fnum); + Port("node1"); + Port("node2"); + Port("node3"); + Port("node4"); + SetClass(CLASS_XLINE); + EndCell(); + if (fname) ReopenCellDef(fname, fnum); /* Reopen */ + } + return Cell(inststr, "t", node1, node2, node3, node4); +} + +/*----------------------------------------------------------------------*/ + +char *Cap(char *fname, char *inststr, char *top, char *bottom) +{ + int fnum = CurrentCell->file; + + if (LookupCellFile("c", fnum) == NULL) { + CellDef("c", fnum); + Port("top"); + Port("bottom"); + PropertyDouble("c", fnum, "value", 0.01, 0.0); + SetClass(CLASS_CAP); + EndCell(); + if (fname) ReopenCellDef(fname, fnum); /* Reopen */ + } + return Cell(inststr, "c", top, bottom); +} + +/*----------------------------------------------------------------------*/ + +char *Cap3(char *fname, char *inststr, char *top, char *bottom, char *cdummy) +{ + int fnum = CurrentCell->file; + + if (LookupCellFile("c3", fnum) == NULL) { + CellDef("c3", fnum); + Port("top"); + Port("bottom"); + Port("dummy"); + PropertyDouble("c3", fnum, "value", 0.01, 0.0); + SetClass(CLASS_CAP3); + EndCell(); + if (fname) ReopenCellDef(fname, fnum); /* Reopen */ + } + return Cell(inststr, "c3", top, bottom, cdummy); +} + +/*----------------------------------------------------------------------*/ + +char *Inductor(char *fname, char *inststr, char *end_a, char *end_b) +{ + int fnum = CurrentCell->file; + + if (LookupCellFile("l", fnum) == NULL) { + CellDef("l", fnum); + Port("end_a"); + Port("end_b"); + PropertyDouble("l", fnum, "value", 0.01, 0.0); + SetClass(CLASS_INDUCTOR); + EndCell(); + if (fname) ReopenCellDef(fname, fnum); /* Reopen */ + } + return Cell(inststr, "l", end_a, end_b); +} + +/*----------------------------------------------------------------------*/ +/* Determine if two property keys are matching strings */ +/* Return 1 on match, 0 on failure to match */ +/*----------------------------------------------------------------------*/ + +int PropertyKeyMatch(char *key1, char *key2) +{ + /* For now, an unsophisticated direct string match */ + + if (!strcasecmp(key1, key2)) return 1; + return 0; +} + +/*----------------------------------------------------------------------*/ +/* Determine if two property values are matching. */ +/* Return 1 on match, 0 on failure to match */ +/*----------------------------------------------------------------------*/ + +int PropertyValueMatch(char *value1, char *value2) +{ + /* For now, an unsophisticated direct string match */ + + if (!strcasecmp(value1, value2)) return 1; + return 0; +} + +/*----------------------------------------------------------------------*/ +/* Add a key:value property pair to the list of property pairs */ +/*----------------------------------------------------------------------*/ + +void AddProperty(struct keyvalue **topptr, char *key, char *value) +{ + struct keyvalue *kv; + + if (Debug) Printf(" Defining key:value property pair: %s:%s\n", key, value); + if ((kv = NewKeyValue()) == NULL) { + perror("Failed NewKeyValue in Property"); + return; + } + kv->key = strsave(key); + kv->value = strsave(value); + kv->next = *topptr; + *topptr = kv; +} + +/*----------------------------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +void AddScaledProperty(struct keyvalue **topptr, char *key, char *value, double scale) +{ + struct keyvalue *kv; + + if (Debug) Printf(" Defining key:value property pair: %s:%s\n", key, value); + if ((kv = NewKeyValue()) == NULL) { + perror("Failed NewKeyValue in Property"); + return; + } + kv->key = strsave(key); + kv->value = strsave(value); + kv->next = *topptr; + *topptr = kv; +} + +/*----------------------------------------------------------------------*/ +/* Free up a property list */ +/*----------------------------------------------------------------------*/ + +void DeleteProperties(struct keyvalue **topptr) +{ + struct keyvalue *kv, *nextkv; + + kv = *topptr; + while (kv != NULL) + { + nextkv = kv->next; + FreeString(kv->key); + FreeString(kv->value); + FREE(kv); + kv = nextkv; + } + *topptr = NULL; +} + +/*----------------------------------------------------------------------*/ +/* LinkProperties() --- */ +/* */ +/* Add a list of properties to the current cell (instance). */ +/* This just keeps a record of key:value pairs; it does not attempt */ +/* to relate them to the cell that is being instanced. Because this */ +/* is used to link the same properties multiple times for parallel */ +/* devices, copy the list (a refcount would work better. . .) */ +/* */ +/* If "isdefault" is "true", then the record is installed in the */ +/* object hash under the name "defaults"; otherwise, it gets the */ +/* name "properties" and is not added to the object hash. */ +/*----------------------------------------------------------------------*/ + +struct objlist *LinkProperties(char *model, struct keyvalue *topptr) +{ + int filenum = -1; + struct nlist *cell; + struct objlist *tp; + struct keyvalue *kv; + struct valuelist *newkv; + int entries; + + if (topptr == NULL) return NULL; + + if (CurrentCell == NULL) { + Printf("LinkProperties() called with no current cell.\n"); + return NULL; + } + else + filenum = CurrentCell->file; + + if (IsIgnored(model, filenum)) { + Printf("Class '%s' instanced in input but is being ignored.\n", model); + return NULL; + } + cell = LookupCellFile(model, filenum); + if (cell == NULL) { + Printf("No cell '%s' found to link properties to.\n", model); + return NULL; + } + + tp = GetObject(); + tp->type = PROPERTY; + tp->name = strsave("properties"); + tp->node = -2; /* Don't report as disconnected node */ + tp->next = NULL; + tp->model.class = strsave(model); + + /* Save a copy of the key:value pairs in tp->instance.props */ + + for (entries = 0, kv = topptr; kv != NULL; kv = kv->next, entries++); + tp->instance.props = NewPropValue(entries + 1); + + for (entries = 0, kv = topptr; kv != NULL; kv = kv->next, entries++) + { + newkv = &(tp->instance.props[entries]); + newkv->key = strsave(kv->key); + /* No promotion to types other than string at this point */ + newkv->type = PROP_STRING; + newkv->value.string = strsave(kv->value); + } + + /* Final entry marks the end of the list */ + newkv = &(tp->instance.props[entries]); + newkv->key = NULL; + newkv->type = PROP_ENDLIST; + newkv->value.ival = 0; + + AddToCurrentCellNoHash(tp); + return tp; +} + +/*----------------------------------------------------------------------*/ +/* PromoteProperty() --- */ +/* */ +/* Instances have all properties recorded as strings. If the cell */ +/* record has an integer or double type, then attempt to convert the */ +/* instance record into that type. */ +/* */ +/* Do not attempt to promote properties that cannot be promoted */ +/* without altering the content. Fractional values cannot be converted */ +/* to integers, and strings that are not numbers must be left as */ +/* strings. Return 1 if the property was promoted successfully, and 0 */ +/* if no promotion was possible, and -1 if passed a bad argument. */ +/*----------------------------------------------------------------------*/ + +int PromoteProperty(struct property *prop, struct valuelist *vl) +{ + char tstr[256]; + int ival, result; + double dval; + + if (prop == NULL || vl == NULL) return -1; + if (prop->type == vl->type) return 1; /* Nothing to do */ + result = 0; + switch (prop->type) { + case PROP_STRING: + switch (vl->type) { + case PROP_INTEGER: + vl->type = PROP_STRING; + sprintf(tstr, "%d", vl->value.ival); + vl->value.string = strsave(tstr); + result = 1; + break; + case PROP_DOUBLE: + case PROP_VALUE: + vl->type = PROP_STRING; + sprintf(tstr, "%g", vl->value.dval); + vl->value.string = strsave(tstr); + result = 1; + break; + } + break; + case PROP_INTEGER: + switch (vl->type) { + case PROP_STRING: + if (StringIsValue(vl->value.string)) { + result = ConvertStringToFloat(vl->value.string, &dval); + if (result != 0) { + if ((double)((int)dval) == dval) { + vl->type = PROP_INTEGER; + FREE(vl->value.string); + vl->value.ival = (int)dval; + result = 1; + } + } + } + break; + case PROP_DOUBLE: + case PROP_VALUE: + vl->type = PROP_INTEGER; + dval = vl->value.dval; + if ((double)((int)dval) == dval) { + vl->value.ival = (int)dval; + result = 1; + } + break; + } + break; + case PROP_DOUBLE: + case PROP_VALUE: + switch (vl->type) { + case PROP_STRING: + if (StringIsValue(vl->value.string)) { + result = ConvertStringToFloat(vl->value.string, &dval); + if (result != 0) { + vl->type = PROP_DOUBLE; + FREE(vl->value.string); + vl->value.dval = dval; + result = 1; + } + } + break; + case PROP_INTEGER: + vl->type = PROP_DOUBLE; + vl->value.dval = (double)vl->value.ival; + result = 1; + break; + } + break; + } + return result; +} + +/*----------------------------------------------------------------------*/ +/* Structure used by resolveprops() */ +/*----------------------------------------------------------------------*/ + +typedef struct _propdata { + struct nlist *cell; + int entries; +} PropData; + +/*----------------------------------------------------------------------*/ +/* resolveprops() --- */ +/* */ +/* Match instance property lists to the cell it's an instance of */ +/*----------------------------------------------------------------------*/ + +struct nlist *resolveprops(struct hashlist *p, void *clientdata) +{ + struct nlist *ptr, *pmod; + struct objlist *ob; + struct valuelist *vl, vtemp, *vlnew; + struct property *prop; + struct nlist *tc; + int entries, i, j; + PropData *pdp = (PropData *)clientdata; + + tc = pdp->cell; + entries = pdp->entries; + + ptr = (struct nlist *)(p->ptr); + if (ptr->file != tc->file) return NULL; + + for (ob = ptr->cell; ob; ob = ob->next) { + if (ob->type == PROPERTY) { + if ((*matchfunc)(ob->model.class, tc->name)) { + /* Check length of the record, resize if necessary */ + for (i = 0;; i++) { + vl = &(ob->instance.props[i]); + if (vl->type == PROP_ENDLIST) break; + } + if (i > entries) { + Printf("Warning: Instance defines more properties than cell.\n"); + Printf("This shouldn't happen.\n"); + } + + /* Create new structure in the correct order, and replace */ + /* the old property structure with it. */ + + vlnew = NewPropValue(entries + 1); + for (i = 0;; i++) { + vl = &(ob->instance.props[i]); + if (vl->type == PROP_ENDLIST) break; + prop = (struct property *)HashLookup(vl->key, tc->proptab, OBJHASHSIZE); + + /* Warning: prop should never be null, but condition */ + /* should be handled. */ + + if (prop != NULL) { + j = prop->idx; + vlnew[j].key = vl->key; + vlnew[j].type = vl->type; + vlnew[j].value = vl->value; + } + } + vlnew[entries].key = NULL; + vlnew[entries].type = PROP_ENDLIST; + vlnew[entries].value.ival = 0; + FREE(ob->instance.props); + ob->instance.props = vlnew; + } + } + } + return ptr; +} + +/*----------------------------------------------------------------------*/ +/* ResolveProperties() --- */ +/* */ +/* This routine does the greatest part of the work for the property- */ +/* handling mechanism. It determines which properties are common to */ +/* two models, and arranges the lists of properties in both models */ +/* such that the lists are in the same order. Properties that exist in */ +/* one cell but not the other are floated to the end of the list. All */ +/* instances of both models are checked and their property lists also */ +/* arranged in order. */ +/*----------------------------------------------------------------------*/ + +void ResolveProperties(char *name1, int file1, char *name2, int file2) +{ + PropData pdp; + struct property *kl1, *kl2; + struct nlist *tp1, *tp2; + int i; + + struct valuelist *kv, *newkv; + struct valuelist *vl, *lastvl; + int isnum, filenum; + + if ((tp1 = LookupCellFile(name1, file1)) == NULL) return; + if ((tp2 = LookupCellFile(name2, file2)) == NULL) return; + + /* Find all properties defined in the cell tp1, and index them in */ + /* numerical order. For each property, find the equivalent */ + /* property in the cell to be matched, and give them both the same */ + /* index. If the property does not exist in the second cell, then */ + /* create it. */ + + kl1 = (struct property *)HashFirst(tp1->proptab, OBJHASHSIZE); + /* If indexes are not zero, then properties have already been matched. */ + if (kl1 == NULL) return; /* Cell has no properties */ + if (kl1->idx != 0) return; + i = 1; + + while (kl1 != NULL) { + kl1->idx = i; + + kl2 = (struct property *)HashLookup(kl1->key, tp2->proptab, OBJHASHSIZE); + if (kl2 == NULL) { + /* No such property in tp2 */ + switch (kl1->type) { + case PROP_STRING: + kl2 = PropertyString(tp2->name, tp2->file, kl1->key, + kl1->slop.ival, kl1->pdefault.string); + break; + case PROP_INTEGER: + kl2 = PropertyInteger(tp2->name, tp2->file, kl1->key, + kl1->slop.ival, kl1->pdefault.ival); + break; + case PROP_DOUBLE: + kl2 = PropertyDouble(tp2->name, tp2->file, kl1->key, + kl1->slop.dval, kl1->pdefault.dval); + break; + case PROP_VALUE: + kl2 = PropertyValue(tp2->name, tp2->file, kl1->key, + kl1->slop.dval, kl1->pdefault.dval); + break; + } + } + if (kl2 != NULL) kl2->idx = i; + kl1 = (struct property *)HashNext(tp1->proptab, OBJHASHSIZE); + i++; + } + + /* Now check tp2 for properties not in tp1 */ + + kl2 = (struct property *)HashFirst(tp2->proptab, OBJHASHSIZE); + + while (kl2 != NULL) { + kl1 = (struct property *)HashLookup(kl2->key, tp1->proptab, OBJHASHSIZE); + if (kl1 == NULL) { + /* No such property in tp1 */ + switch (kl2->type) { + case PROP_STRING: + kl1 = PropertyString(tp1->name, tp1->file, kl2->key, + kl2->slop.ival, kl2->pdefault.string); + break; + case PROP_INTEGER: + kl1 = PropertyInteger(tp1->name, tp1->file, kl2->key, + kl2->slop.ival, kl2->pdefault.ival); + break; + case PROP_DOUBLE: + kl1 = PropertyDouble(tp1->name, tp1->file, kl2->key, + kl2->slop.dval, kl2->pdefault.dval); + break; + case PROP_VALUE: + kl1 = PropertyValue(tp1->name, tp1->file, kl2->key, + kl2->slop.dval, kl2->pdefault.dval); + break; + } + } + if (kl1 != NULL) kl1->idx = i; + kl2 = (struct property *)HashNext(tp1->proptab, OBJHASHSIZE); + i++; + } + + /* Now that the properties of the two cells are ordered, find all */ + /* instances of both cells, and order their properties to match. */ + + pdp.cell = tp1; + pdp.entries = i; + RecurseCellHashTable2(resolveprops, (void *)(&pdp)); + pdp.cell = tp2; + RecurseCellHashTable2(resolveprops, (void *)(&pdp)); +} + +/*--------------------------------------------------------------*/ +/* Copy properties from one object to another (used when */ +/* flattening cells). */ +/*--------------------------------------------------------------*/ + +void CopyProperties(struct objlist *obj_to, struct objlist *obj_from) +{ + int i; + struct valuelist *kv, *kvcopy, *kvcur; + + if (obj_from->instance.props != NULL) { + for (i = 0;; i++) { + kv = &(obj_from->instance.props[i]); + if (kv->type == PROP_ENDLIST) + break; + } + kvcopy = NewPropValue(i + 1); + + for (i = 0;; i++) { + kv = &(obj_from->instance.props[i]); + kvcur = &(kvcopy[i]); + kvcur->type = kv->type; + if (kv->type == PROP_ENDLIST) break; + kvcur->key = strsave(kv->key); + switch (kvcur->type) { + case PROP_STRING: + kvcur->value.string = strsave(kv->value.string); + break; + case PROP_INTEGER: + kvcur->value.ival = kv->value.ival; + break; + case PROP_DOUBLE: + case PROP_VALUE: + kvcur->value.dval = kv->value.dval; + break; + case PROP_EXPRESSION: + kvcur->value.stack = CopyTokStack(kv->value.stack); + break; + } + } + kvcur->key = NULL; + kvcur->value.ival = 0; + + obj_to->instance.props = kvcopy; + obj_to->model.class = strsave(obj_from->model.class); + } +} + +/*--------------------------------------------------------------*/ +/* Convert a string to an integer. */ +/* At the moment, we do nothing with error conditions. */ +/*--------------------------------------------------------------*/ + +int ConvertStringToInteger(char *string, int *ival) +{ + long lval; + char *eptr = NULL; + + lval = strtol(string, &eptr, 10); + if (eptr > string) { + *ival = (int)lval; + return 1; + } + else if (eptr == string) + return 0; /* No conversion */ +} + +/*--------------------------------------------------------------*/ +/* Check if a string is a valid number (with optional metric */ +/* unit suffix). */ +/* Returns 1 if the string is a proper value, 0 if not. */ +/*--------------------------------------------------------------*/ + +int StringIsValue(char *string) +{ + double fval; + char *eptr = NULL; + + fval = strtod(string, &eptr); + if (eptr > string) + { + while (isspace(*eptr)) eptr++; + switch (tolower(*eptr)) { + case 'g': /* giga */ + case 'k': /* kilo */ + case 'c': /* centi */ + case 'm': /* milli */ + case 'u': /* micro */ + case 'n': /* nano */ + case 'p': /* pico */ + case 'f': /* femto */ + case 'a': /* atto */ + case '\0': /* no units */ + return 1; + } + } + return 0; +} + +/*--------------------------------------------------------------*/ +/* Convert a string with possible metric notation into a float. */ +/* This follows SPICE notation with case-insensitive prefixes, */ +/* using "meg" to distinguish 1x10^6 from "m" 1x10^-3 */ +/* */ +/* Put the result in "dval". Return 1 if successful, 0 if */ +/* unsuccessful. */ +/*--------------------------------------------------------------*/ + +int ConvertStringToFloat(char *string, double *dval) +{ + long double fval; + char *eptr = NULL; + + fval = strtold(string, &eptr); + if (eptr > string) + { + while (isspace(*eptr)) eptr++; + switch (tolower(*eptr)) { + case 'g': /* giga */ + fval *= 1.0e9L; + eptr++; + break; + case 'k': /* kilo */ + fval *= 1.0e3L; + eptr++; + break; + case 'c': /* centi */ + fval *= 1.0e-2L; + eptr++; + break; + case 'm': /* milli */ + if (tolower(*(eptr + 1)) == 'e' && + tolower(*(eptr + 2)) == 'g') { + fval *= 1.0e6L; + eptr += 2; + } + else + fval *= 1.0e-3L; + eptr++; + break; + case 'u': /* micro */ + fval *= 1.0e-6L; + eptr++; + break; + case 'n': /* nano */ + fval *= 1.0e-9L; + eptr++; + break; + case 'p': /* pico */ + fval *= 1.0e-12L; + eptr++; + break; + case 'f': /* femto */ + fval *= 1.0e-15L; + eptr++; + break; + case 'a': /* atto */ + fval *= 1.0e-18L; + eptr++; + break; + default: + break; /* No units, no adjustment */ + } + if (*eptr != '\0') { + switch (tolower(*eptr)) { + case 'f': /* Farads */ + if (!strncasecmp(eptr, "farad", 5)) { + eptr += 5; + if (tolower(*eptr) == 's') eptr++; + } + else eptr++; + if (*eptr != '\0') return 0; /* Unknown units */ + break; + case 'm': /* Meters */ + if (!strncasecmp(eptr, "meter", 5)) { + eptr += 5; + if (tolower(*eptr) == 's') eptr++; + } + else eptr++; + if (*eptr != '\0') return 0; /* Unknown units */ + break; + case 'h': /* Henrys */ + if (!strncasecmp(eptr, "henr", 4)) { + eptr += 4; + if (tolower(*eptr) == 'y') { + eptr++; + if (*eptr == 's') eptr++; + } + else if (!strncasecmp(eptr, "ies", 3)) + eptr += 3; + } + else eptr++; + if (*eptr != '\0') return 0; /* Unknown units */ + break; + case 's': /* Seconds */ + if (!strncasecmp(eptr, "second", 6)) { + eptr += 6; + if (tolower(*eptr) == 's') eptr++; + } + else eptr++; + if (*eptr != '\0') return 0; /* Unknown units */ + break; + case 'o': /* Ohms */ + if (!strncasecmp(eptr, "ohm", 3)) { + eptr += 3; + if (tolower(*eptr) == 's') eptr++; + } + else eptr++; + if (*eptr != '\0') return 0; /* Unknown units */ + break; + case 'v': /* Volts */ + if (!strncasecmp(eptr, "volt", 4)) { + eptr += 4; + if (tolower(*eptr) == 's') eptr++; + } + else eptr++; + if (*eptr != '\0') return 0; /* Unknown units */ + break; + case 'a': /* Amps */ + if (!strncasecmp(eptr, "amp", 3)) { + eptr += 3; + if (tolower(*eptr) == 's') eptr++; + } + else eptr++; + if (*eptr != '\0') return 0; /* Unknown units */ + break; + default: + return 0; /* Unknown units; no conversion */ + } + } + } + else if (eptr == string) return 0; /* No conversion */ + *dval = (double)fval; + return 1; +} + +/*--------------------------------------------------------------*/ +/* Convert a string into a double, scale it, and pass it back */ +/* as another string value. */ +/*--------------------------------------------------------------*/ + +char *ScaleStringFloatValue(char *vstr, double scale) +{ + static char newstr[32]; + double fval, afval; + int result; + + result = ConvertStringToFloat(vstr, &fval); + if (result == 1) { + fval *= scale; + + snprintf(newstr, 31, "%g", fval); + return newstr; + } + else + return vstr; +} + +/*----------------------------------------------------------------------*/ +/* Workhorse subroutine for the Connect() function */ +/*----------------------------------------------------------------------*/ + +void join(char *node1, char *node2) +{ + struct objlist *tp1, *tp2, *tp3; + int nodenum, oldnode; + + if (CurrentCell == NULL) { + Printf( "No current cell for join(%s,%s)\n", + node1,node2); + return; + } + tp1 = LookupObject(node1, CurrentCell); + if (tp1 == NULL) { + Printf("No node '%s' found in current cell '%s'\n", + node1, CurrentCell->name); + return; + } + tp2 = LookupObject(node2, CurrentCell); + if (tp2 == NULL) { + Printf("No node '%s' found in current cell '%s'\n", + node2, CurrentCell->name); + return; + } + if (Debug) Printf(" joining: %s == %s (", + tp1->name,tp2->name); + + /* see if either node has an assigned node number */ + if ((tp1->node == -1) && (tp2->node == -1)) { + tp1->node = NextNode; + tp2->node = NextNode++; + if (Debug) Printf("New "); + } + else if (tp1->node == -1) tp1->node = tp2->node; + else if (tp2->node == -1) tp2->node = tp1->node; + else { + if (tp1->node < tp2->node) { + nodenum = tp1->node; + oldnode = tp2->node; + } else { + nodenum = tp2->node; + oldnode = tp1->node; + } + /* now search through entire list, updating nodes as needed */ + for (tp3 = CurrentCell->cell; tp3 != NULL; tp3 = tp3->next) + if (tp3->node == oldnode) tp3->node = nodenum; + } + if (Debug) Printf("Node = %d)\n",tp1->node); +} + +/*----------------------------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +void Connect(char *tplt1, char *tplt2) +{ + struct objlist *list1, *list2; + int n1, n2; /* lengths of two lists */ + + if (Debug) Printf(" Connect(%s,%s)\n",tplt1,tplt2); + if (CurrentCell == NULL) { + Printf( "No current cell for Connect(%s,%s)\n", + tplt1,tplt2); + return; + } + list1 = List(tplt1); + n1 = ListLen(list1); + list2 = List(tplt2); + n2 = ListLen(list2); + if (n1==n2) { + while (list1 != NULL) { + join(list1->name,list2->name); + list1 = list1->next; + list2 = list2->next; + } + } + else if (n1==1 && n2>0) { + while (list2 != NULL) { + join(list1->name,list2->name); + list2 = list2->next; + } + } + else if (n2==1 && n1>0) { + while (list1 != NULL) { + join(list1->name,list2->name); + list1 = list1->next; + } + } + else Printf("Unequal element lists: '%s' has %d, '%s' has %d.\n", + tplt1,n1,tplt2,n2); +} + +/*----------------------------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +void PortList(char *prefix, char *list_template) +{ + struct objlist *list; + char buffer[1024]; + int buflen; + int i; + + for (list = List(list_template); list != NULL; list = list->next) { + strcpy(buffer,prefix); + strcat(buffer,list->name); + buflen = strlen(buffer); + for (i=0; i < buflen; i++) + if (buffer[i] == SEPARATOR[0]) buffer[i] = PORT_DELIMITER[0]; + Port(buffer); + join(buffer,list->name); + } +} + +/*----------------------------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +void Place(char *name) +{ + char *freename; + char buffer1[1024], buffer2[1024]; + char prefix[20]; + + QuickSearch = (LastPlaced != NULL); + freename = Next(name); + Instance(name,freename); + if (Composition == HORIZONTAL) { + sprintf(buffer2,"%s%s%s%s%s", freename, SEPARATOR, "W", PORT_DELIMITER, "*"); + if (LastPlaced != NULL) { + sprintf(buffer1,"%s%s%s%s%s", + LastPlaced->instance.name, SEPARATOR, "E", PORT_DELIMITER, "*"); + Connect (buffer1,buffer2); + } + else { /* promote left-hand ports */ + sprintf(prefix,"%s%s","W", PORT_DELIMITER); + PortList(prefix,buffer2); + } + buffer2[strlen(buffer2)-3] = 'N'; + sprintf(prefix,"%s%s", "N", PORT_DELIMITER); + PortList(prefix,buffer2); + buffer2[strlen(buffer2)-3] = 'S'; + sprintf(prefix,"%s%s", "S", PORT_DELIMITER); + PortList(prefix,buffer2); + } + else if (Composition == VERTICAL) { + sprintf(buffer2,"%s%s%s%s%s", + freename, SEPARATOR, "S", PORT_DELIMITER, "*"); + if (LastPlaced != NULL) { + sprintf(buffer1,"%s%s%s%s%s", + LastPlaced->instance.name, SEPARATOR, "N", PORT_DELIMITER, "*"); + Connect (buffer1,buffer2); + } + else { /* promote bottom ports */ + sprintf(prefix,"%s%s","S", PORT_DELIMITER); + PortList(prefix,buffer2); + } + buffer2[strlen(buffer2)-3] = 'E'; + sprintf(prefix,"%s%s", "E", PORT_DELIMITER); + PortList(prefix,buffer2); + buffer2[strlen(buffer2)-3] = 'W'; + sprintf(prefix,"%s%s", "W", PORT_DELIMITER); + PortList(prefix,buffer2); + } + LastPlaced = LookupInstance(freename,CurrentCell); + QuickSearch = 0; + FreeString(freename); +} + +/*----------------------------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +void Array(char *Cell, int num) +{ + int i; + + for (i=0; icell; ob != NULL; ob = ob->next) + if (ob->node >= nodenum) nodenum = ob->node + 1; + + for (ob = tp->cell; ob != NULL; ob = ob->next) + if (ob->node == -1) ob->node = nodenum++; +} + +/*----------------------------------------------------------------------*/ +/*----------------------------------------------------------------------*/ + +void EndCell(void) +{ + char buffer1[1024]; + char prefix[10]; + + if (CurrentCell == NULL) return; + + if (Composition == HORIZONTAL) { + if (LastPlaced != NULL) { + sprintf(buffer1,"%s%s%s%s%s", + LastPlaced->instance.name, SEPARATOR, "E", PORT_DELIMITER, "*"); + sprintf(prefix,"%s%s", "E", PORT_DELIMITER); + PortList(prefix,buffer1); + } + } + else if (Composition == VERTICAL) { /* vcomposing */ + if (LastPlaced != NULL) { + sprintf(buffer1,"%s%s%s%s%s", + LastPlaced->instance.name, SEPARATOR, "N", PORT_DELIMITER, "*"); + sprintf(prefix,"%s%s", "N", PORT_DELIMITER); + PortList(prefix,buffer1); + } + } + LastPlaced = NULL; + CacheNodeNames(CurrentCell); + if (NoDisconnectedNodes) ConnectAllNodes(CurrentCell->name, CurrentCell->file); + CurrentCell = NULL; + CurrentTail = NULL; +} diff --git a/base/netgen.h b/base/netgen.h new file mode 100644 index 0000000..9d6ea5a --- /dev/null +++ b/base/netgen.h @@ -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 */ diff --git a/base/ntk.c b/base/ntk.c new file mode 100644 index 0000000..36a7c9e --- /dev/null +++ b/base/ntk.c @@ -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 +#include + +#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 / */ + /* 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; +} + + + + diff --git a/base/objlist.c b/base/objlist.c new file mode 100644 index 0000000..36e5e58 --- /dev/null +++ b/base/objlist.c @@ -0,0 +1,1294 @@ +/* "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. */ + +/* objlist.c -- manipulating lists of elements */ + +#include "config.h" + +#include +#include +#ifdef IBMPC +#include +#endif + +#ifdef TCL_NETGEN +#include +#endif + +#include "netgen.h" +#include "hash.h" +#include "objlist.h" +#include "regexp.h" +#include "dbug.h" +#include "print.h" +#include "netfile.h" +#include "netcmp.h" + +#ifdef TCL_NETGEN +extern Tcl_Interp *netgeninterp; +#endif + +struct nlist *CurrentCell = NULL; +struct objlist *CurrentTail = NULL; + +/* shortcut pointer to last-placed object in list; used in netgen.c */ +struct objlist *LastPlaced = NULL; + +/* used to narrow list of cells to those belonging to a specific file */ +int TopFile = -1; + +/* global variable to enable/disable translation of UNIX wildcards */ +int UnixWildcards = 1; +/* define the following to minimize use of regcomp/regexp stuff */ +#define OPTIMIZE_WILDCARDS + +/***************************************************************************/ +/* */ +/* NETGEN garbage collection / monitoring stuff */ +/* */ +/***************************************************************************/ + + +#define GARBAGESIZE 100 +/* list of allocated nodes awaiting garbage collection */ +static struct objlist *garbage[GARBAGESIZE]; +static int nextfree; +static int ObjectsAllocated = 0; +#ifdef DEBUG_GARBAGE +static int StringsAllocated = 0; +#endif + +void GarbageCollect() +{ +} + +void InitGarbageCollection() +{ + int i; + + for (i=0; i < GARBAGESIZE; i++) + garbage[i] = NULL; + nextfree = 0; +} + +void ThrowOutGarbage(int i) +{ + struct objlist *tp, *tpnext; + + tp = garbage[i]; + while (tp != NULL) { + tpnext = tp->next; + FREE(tp); + ObjectsAllocated--; + tp = tpnext; + } +#ifdef DEBUG_GARBAGE + Printf("ThrowOutGarbage: objects left = %d\n",ObjectsAllocated); +#endif + garbage[i] = NULL; +} + + +void AddToGarbageList(struct objlist *head) +{ + if (garbage[nextfree] != NULL) ThrowOutGarbage(nextfree); + garbage[nextfree] = head; + nextfree = (nextfree + 1) % GARBAGESIZE; +} + +#ifdef DEBUG_GARBAGE +/* otherwise, inline these functions with macros */ + +struct keyvalue *NewKeyValue(void) +{ + struct keyvalue *kv; + + kv = (struct keyvalue *)CALLOC(1,sizeof(struct keyvalue)); + if (kv == NULL) Fprintf(stderr,"NewKeyValue: Core allocation error\n"); + return (kv); +} + +struct property *NewProperty(void) +{ + struct property *kl; + + kl = (struct property *)CALLOC(1,sizeof(struct property)); + if (kl == NULL) Fprintf(stderr,"NewProperty: Core allocation error\n"); + return (kl); +} + +struct valuelist *NewPropValue(int entries) +{ + struct valuelist *vl; + + vl = (struct valuelist *)CALLOC(entries, sizeof(struct valuelist)); + if (vl == NULL) Fprintf(stderr,"NewPropValue: Core allocation error\n"); + return (vl); +} + +struct objlist *GetObject(void) +{ + struct objlist *tp; + +#ifdef IBMPC + Printf("GetObject(): num = %d; mem left = %ld\n", + ++ObjectsAllocated, (long)coreleft()); +#endif + tp = (struct objlist *)CALLOC(1,sizeof(struct objlist)); + if (tp == NULL) Fprintf(stderr,"GetObject: Core allocation error\n"); + return (tp); +} + +void FreeString(char *foo) +{ + Printf("Freeing string: %s, number = %d\n", foo, --StringsAllocated); + FREE(foo); +} + +char *strsave(char *s) +{ + char *p; + +#ifdef DEBUG_GARBAGE + Printf("\tstrsave(%s), num = %d\n",s,++StringsAllocated); +#endif + if ((p = (char *)MALLOC(strlen(s)+1)) == NULL) + Fprintf(stderr,"strsave: core allocation failure\n"); + else strcpy(p, s); + return (p); +} +#endif /* DEBUG_GARBAGE */ + +/* Case-sensitive matching */ + +int match(char *st1, char *st2) +{ + if (0==strcmp(st1,st2)) return(1); + else return(0); +} + +/* Case-insensitive matching */ + +int matchnocase(char *st1, char *st2) +{ + char *sp1 = st1; + char *sp2 = st2; + + while (*sp1 != '\0' && *sp2 != '\0') { + if (tolower(*sp1) != tolower(*sp2)) break; + sp1++; + sp2++; + } + if ((*sp1 != '\0') || (*sp2 != '\0')) return 0; + return 1; +} + +/* Case-sensitive matching with file matching */ + +int matchfile(char *st1, char *st2, int f1, int f2) +{ + if (f1 != f2) return 0; + else if (strcmp(st1,st2)) return(0); + else return(1); +} + +/* Case-insensitive matching with file matching */ + +int matchfilenocase(char *st1, char *st2, int f1, int f2) +{ + char *sp1 = st1; + char *sp2 = st2; + + if (f1 != f2) return 0; + while (*sp1 != '\0' && *sp2 != '\0') { + if (tolower(*sp1) != tolower(*sp2)) break; + sp1++; + sp2++; + } + if ((*sp1 != '\0') || (*sp2 != '\0')) return 0; + return 1; +} + +#ifdef HAVE_MALLINFO +void PrintMemoryStats(void) +{ + struct mallinfo minfo; + + /* HPUX 7.0 defines mallinfo(void); use mallinfo(0) for HPUX 6.5 */ + minfo = mallinfo(); + + Printf("total space = %d\n", minfo.arena); + Printf("small blocks = %5d, space = %7d, free space = %7d\n", + minfo.smblks, minfo.usmblks, minfo.fsmblks); + Printf("ordinary blocks = %5d, space = %7d, free space = %7d\n", + minfo.ordblks, minfo.uordblks, minfo.fordblks); + Printf("holding blocks = %5d, size of header = %d\n", + minfo.hblks, minfo.hblkhd); +} +#endif + + +/************************************************************************** + + NETGEN cell hash table + +**************************************************************************/ + + +#define CELLHASHSIZE 1000 +static struct hashlist *cell_hashtab[CELLHASHSIZE]; + +void InitCellHashTable(void) +{ + hashfunc = hash; + matchfunc = match; + InitializeHashTable(cell_hashtab, CELLHASHSIZE); +} + +struct nlist *LookupCell(char *s) +{ + return((struct nlist *)HashLookup(s, cell_hashtab, CELLHASHSIZE)); +} + +/* Similar hash lookup to the above, but will check if the matching */ +/* record has a file equal to "f". If not, prepends underscores until */ +/* either a matching record is found, or there is no hash result. */ + +struct nlist *LookupCellFile(char *s, int f) +{ + struct nlist *he; + + if (f == -1) return LookupCell(s); + return HashIntLookup(s, f, cell_hashtab, CELLHASHSIZE); +} + +struct nlist *InstallInCellHashTable(char *name, int fnum) +{ + struct hashlist *ptr; + struct nlist *p; + + p = LookupCellFile(name, fnum); + if (p != NULL) return(p); + + /* It is not present, so add it to list */ + + p = (struct nlist *)CALLOC(1, sizeof(struct nlist)); + if (p == NULL) return(NULL); + if ((p->name = strsave(name)) == NULL) goto fail; + p->file = fnum; + if ((p->objtab = (struct hashlist **)CALLOC(OBJHASHSIZE, + sizeof(struct hashlist *))) == NULL) goto fail; + if ((p->insttab = (struct hashlist **)CALLOC(OBJHASHSIZE, + sizeof(struct hashlist *))) == NULL) goto fail; + if ((p->proptab = (struct hashlist **)CALLOC(OBJHASHSIZE, + sizeof(struct hashlist *))) == NULL) goto fail; + p->permutes = NULL; + + // Hash size 0 indicates to hash function that no binning is being done + p->classhash = (*hashfunc)(name, 0); + + ptr = HashIntPtrInstall(name, fnum, p, cell_hashtab, CELLHASHSIZE); + if (ptr == NULL) return(NULL); + return(p); + fail: + if (p->name != NULL) FREE(p->name); + if (p->objtab != NULL) { + HashKill(p->objtab, OBJHASHSIZE); + FREE(p->objtab); + } + if (p->insttab != NULL) { + HashKill(p->insttab, OBJHASHSIZE); + FREE(p->insttab); + } + if (p->proptab != NULL) { + HashKill(p->proptab, OBJHASHSIZE); + FREE(p->proptab); + } + FREE(p); + return(NULL); +} + +/* Rename the cell named "name" to "newname". Find the hash entry for + * cell "name", remove it from the hash table, generate a new hash entry + * for "newname", and set its pointer to the original cell. + */ + +void CellRehash(char *name, char *newname, int file) +{ + struct nlist *tp; + struct hashlist *ptr; + + if (file == -1) + tp = LookupCell(name); + else + tp = LookupCellFile(name, file); + + FREE(tp->name); + tp->name = strsave(newname); + + ptr = HashIntPtrInstall(newname, file, (void *)tp, cell_hashtab, CELLHASHSIZE); + if (ptr != NULL) + HashIntDelete(name, file, cell_hashtab, CELLHASHSIZE); +} + +struct nlist *OldCell; + +int deleteclass(struct hashlist *p, int file) +{ + struct nlist *ptr; + struct objlist *ob, *lob, *nob; + + ptr = (struct nlist *)(p->ptr); + + if ((file != -1) && (ptr->file != file)) return; + + lob = NULL; + for (ob = ptr->cell; ob != NULL;) { + nob = ob->next; + if ((ob->type == FIRSTPIN) && (ob->model.class != NULL)) { + if ((*matchfunc)(ob->model.class, OldCell->name)) { + HashDelete(ob->instance.name, ptr->insttab, OBJHASHSIZE); + while (1) { + FreeObjectAndHash(ob, ptr); + ob = nob; + if (ob == NULL) break; + nob = ob->next; + if (ob->type <= FIRSTPIN) break; + } + if (lob == NULL) + ptr->cell = ob; + else + lob->next = ob; + } + else { + lob = ob; + ob = nob; + } + } + else { + lob = ob; + ob = nob; + } + } +} + +/* Remove all instances of class "class" from the database */ + +void ClassDelete(char *class, int file) +{ + if (file == -1) + OldCell = LookupCell(class); + else + OldCell = LookupCellFile(class, file); + + if (OldCell == NULL) return; + RecurseCellFileHashTable(deleteclass, file); +} + +/* Find all instances of the cell named "name" in the database, and */ +/* change their model and instance information to "newname". */ + +char *NewName; + +int renameinstances(struct hashlist *p, int file) +{ + struct nlist *ptr; + struct objlist *ob, *ob2, *obp; + + ptr = (struct nlist *)(p->ptr); + + if ((file != -1) && (ptr->file != file)) return; + + for (ob = ptr->cell; ob != NULL; ob = ob->next) { + if ((ob->type >= FIRSTPIN) && (ob->model.class != NULL)) { + if ((*matchfunc)(ob->model.class, OldCell->name)) { + FreeString(ob->model.class); + ob->model.class = strsave(NewName); + } + } + } +} + +void InstanceRename(char *from, char *to, int file) +{ + if (file == -1) + OldCell = LookupCell(from); + else + OldCell = LookupCellFile(from, file); + + if (OldCell == NULL) return; + NewName = to; + + RecurseCellFileHashTable(renameinstances, file); +} + +/* Delete contents of a hashed property structure */ + +int freeprop(struct hashlist *p) +{ + struct property *prop; + + prop = (struct property *)(p->ptr); + if (prop->type == PROP_STRING) + if (prop->pdefault.string != NULL) + FREE(prop->pdefault.string); + else if (prop->type == PROP_EXPRESSION) { + struct tokstack *stackptr, *nptr; + stackptr = prop->pdefault.stack; + while (stackptr != NULL) { + nptr = stackptr->next; + if (stackptr->toktype == TOK_STRING) + FREE(stackptr->data.string); + FREE(stackptr); + stackptr = nptr; + } + } + FREE(prop->key); + FREE(prop); + return 1; +} + +void CellDelete(char *name, int fnum) +{ + /* delete all the contents of cell 'name', and remove 'name' from + the cell hash table. NOTE: this procedure does not care or check + if 'name' has been instanced anywhere. It is assumed that if this + is the case, the user will (quickly) define a new cell of that name. + */ + struct objlist *ob, *obnext; + struct nlist *tp; + + tp = LookupCellFile(name, fnum); + if (tp == NULL) { + Printf ("No cell '%s' found.\n", name); + return; + } + + HashIntDelete(name, fnum, cell_hashtab, CELLHASHSIZE); + /* now make sure that we free all the fields of the nlist struct */ + if (tp->name != NULL) FREE(tp->name); + if (tp->objtab != NULL) { + HashKill(tp->objtab, OBJHASHSIZE); + FREE(tp->objtab); + } + if (tp->insttab != NULL) { + HashKill(tp->insttab, OBJHASHSIZE); + FREE(tp->insttab); + } + if (tp->proptab != NULL) { + RecurseHashTable(tp->proptab, OBJHASHSIZE, freeprop); + HashKill(tp->proptab, OBJHASHSIZE); + FREE(tp->proptab); + } + FreeNodeNames(tp); + ob = tp->cell; + while (ob != NULL) { + obnext = ob->next; + FreeObject (ob); + ob = obnext; + } +} + +static int PrintCellHashTableElement(struct hashlist *p) +{ + struct nlist *ptr; + + ptr = (struct nlist *)(p->ptr); + if ((TopFile >= 0) && (ptr->file != TopFile)) return 1; + + if (ptr->class != CLASS_SUBCKT) { + /* only print primitive cells if Debug is enabled */ + if (Debug == 1) Printf("Cell: %s (instanced %d times); Primitive\n", + ptr->name, ptr->number); + } + else if (Debug == 2) { /* list only */ +#ifdef TCL_NETGEN + Tcl_AppendElement(netgeninterp, ptr->name); +#else + Printf("%s ", ptr->name); +#endif + } + else + Printf("Cell: %s (instanced %d times)\n",ptr->name,ptr->number); + return(1); +} + +/* Print the contents of the cell hash table. */ +/* if full == 1, print primitive elements also */ +/* if full == 2, just output the cell names. */ + +void PrintCellHashTable(int full, int filenum) +{ + int total, bins; + int OldDebug; + + if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + PrintCellHashTable(full, Circuit1->file); + PrintCellHashTable(full, Circuit2->file); + return; + } + + TopFile = filenum; + + bins = RecurseHashTable(cell_hashtab, CELLHASHSIZE, CountHashTableBinsUsed); + total = RecurseHashTable(cell_hashtab, CELLHASHSIZE, CountHashTableEntries); + if (full != 2) + Printf("Hash table: %d of %d bins used; %d cells total (%.2f per bin)\n", + bins, CELLHASHSIZE, total, (bins == 0) ? 0 : + (float)((float)total / (float)bins)); + + OldDebug = Debug; + Debug = full; + RecurseHashTable(cell_hashtab, CELLHASHSIZE, PrintCellHashTableElement); + Debug = OldDebug; +#ifndef TCL_NETGEN + if (full == 2) Printf("\n"); +#endif +} + +struct nlist *FirstCell(void) +{ + return((struct nlist *)HashFirst(cell_hashtab, CELLHASHSIZE)); +} + +struct nlist *NextCell(void) +{ + return((struct nlist *)HashNext(cell_hashtab, CELLHASHSIZE)); +} + +static int ClearDumpedElement(struct hashlist *np) +{ + struct nlist *p; + + p = (struct nlist *)(np->ptr); + p->dumped = 0; + return(1); +} + +void ClearDumpedList(void) +{ + RecurseHashTable(cell_hashtab, CELLHASHSIZE, ClearDumpedElement); +} + +int RecurseCellHashTable(int (*foo)(struct hashlist *np)) +{ + return RecurseHashTable(cell_hashtab, CELLHASHSIZE, foo); +} + +int RecurseCellFileHashTable(int (*foo)(struct hashlist *, int), int value) +{ + return RecurseHashTableValue(cell_hashtab, CELLHASHSIZE, foo, value); +} + +/* Yet another version, passing one parameter that is a pointer */ + +struct nlist *RecurseCellHashTable2(struct nlist *(*foo)(struct hashlist *, + void *), void *pointer) +{ + return RecurseHashTablePointer(cell_hashtab, CELLHASHSIZE, foo, pointer); +} + +/************************** WILD-CARD STUFF *******************************/ + +char *FixTemplate(char *t) +{ + char buffer[200]; + char *rstr; + int i,j; + int InsideBrace; + + /* if we do not have to translate wildcards, just return input */ + if (!UnixWildcards) return(strsave(t)); + + buffer[0] = '^'; + InsideBrace=0; + for (i=0,j=1; i < strlen(t); i++) + switch (t[i]) { + case '{' : buffer[j++]='('; + InsideBrace++; + break; + case '}' : buffer[j++]=')'; + InsideBrace--; + break; + case ',' : if (InsideBrace) { + buffer[j++]='|'; +#if defined(HAVE_REGCMP) || defined(HAVE_RE_COMP) + Fprintf(stderr, + "Regular expression package unable to handle ',' operator.\n"); + Fprintf(stderr,"Template = %s\n", t); +#endif + } + else buffer[j++]=','; + break; + case '*' : buffer[j++]='.'; + buffer[j++]='*'; break; + case '?' : buffer[j++]='.'; break; + /* escape various characters */ + case '^' : + case '.' : + case '(' : + case ')' : + case '+' : + case '|' : + case '$' : + buffer[j++]='\\'; + buffer[j++]=t[i]; break; + /* escaped characters */ + case '\\' : buffer[j++]='\\'; + buffer[j++] = t[++i]; break; + /* subranges */ + case '[' : buffer[j++]='['; + if (t[i+1] == '~') { + buffer[j++] = '^'; + i++; + } + break; + case ']' : buffer[j++]=']'; break; + default : buffer[j++] = t[i]; break; + } + buffer[j++] = '$'; /* end of line delimeter */ + buffer[j] = '\0'; /* null-terminated string */ + + /* printf ("Translated template = '%s'\n",buffer); */ + rstr = strsave(buffer); + return(rstr); +} + +#ifndef TCL_NETGEN + +/* + *------------------------------------------------------------------- + * returns a list of objects in CurrentCell whose names match the + * regular expression in the 'list_template' + *------------------------------------------------------------------- + */ + +struct objlist *List(char *list_template) +{ + Regexp RegularExpression; + struct objlist *head, *tail; + struct objlist *test, *tmp; + char *template2; + int itmp; + + if (CurrentCell == NULL) { + Fprintf(stderr,"No current cell in List()\n"); + return (NULL); + } + if (QuickSearch) + test = LastPlaced; + else + test = CurrentCell->cell; + + head = NULL; + tail = NULL; + +#ifdef OPTIMIZE_WILDCARDS + if (strpbrk(list_template,"*?[{") == NULL && UnixWildcards) { + + /* just find element, forget about regular expressions */ + test = LookupObject(list_template, CurrentCell); + if (test != NULL) { + /* insert it directly into list (list has only this element) */ + head = GetObject(); + memcpy(head, test, sizeof(struct objlist)); + head->next = NULL; + AddToGarbageList(head); + return(head); + } + } + /* otherwise, need to deal with wildcards */ + +#endif /* OPTIMIZE_WILDCARDS */ + + template2 = FixTemplate(list_template); + DBUG_PRINT("regex",("Compiling regular expression: %s => %s", + list_template, template2)); + RegularExpression = RegexpCompile(template2); + DBUG_PRINT("regex",(" Result = %ld",(long)RegularExpression)); + FreeString(template2); + for ( ; test != NULL; test = test->next) { + itmp = RegexpMatch(RegularExpression,test->name); + DBUG_PRINT("regex",("Testing string %s, result = %d", test->name, itmp)); + if (itmp) { + tmp = GetObject(); + memcpy(tmp, test, sizeof(struct objlist)); + tmp->next = NULL; + + /* now insert it into list */ + + if (head == NULL) { + head = tmp; + tail = tmp; + } + else { /* append it to list 'head' */ + tail->next = tmp; + tail = tmp; + } + } + } + +#ifdef REGEXP_FREE_TEMPLATE + FREE(RegularExpression); +#endif + + AddToGarbageList(head); + return(head); +} + + +#else + +/* + *------------------------------------------------------------------- + * Version of the above (List) with wildcards disabled. + * + * Returns (a copy of) the object in CurrentCell whose name + * matches the 'obj_name'. For Tcl, we use Tcl's built-in + * regexp function to do template matching. + *------------------------------------------------------------------- + */ + +struct objlist *List(char *obj_name) +{ + struct objlist *head, *test; + + if (CurrentCell == NULL) { + Fprintf(stderr,"No current cell in List()\n"); + return (NULL); + } + if (QuickSearch) + test = LastPlaced; + else + test = CurrentCell->cell; + + head = NULL; + + test = LookupObject(obj_name, CurrentCell); + if (test != NULL) { + /* insert it directly into list (list has only this element) */ + head = GetObject(); + memcpy(head, test, sizeof(struct objlist)); + head->next = NULL; + } + AddToGarbageList(head); + return(head); +} + +#endif /* TCL_NETGEN */ + +/****************** LIST MANIPULATION STUFF *****************************/ + +struct objlist *ListCat(struct objlist *ls1, struct objlist *ls2) +{ + struct objlist *head, *tail, *tmp; + + head = NULL; + tail = NULL; + if (ls1 == NULL) { + ls1 = ls2; + ls2 = NULL; + } + while (ls1 != NULL) { + tmp = GetObject(); +#if 1 + memcpy(tmp, ls1, sizeof(struct objlist)); + tmp->next = NULL; +#else + tmp->name = ls1->name; + tmp->type = ls1->type; + tmp->model.class = ls1->model.class; + tmp->instance.name = ls1->instance.name; + tmp->node = ls1->node; + tmp->next = NULL; +#endif + /* now insert it into list */ + if (head == NULL) { + head = tmp; + tail = head; + } + else { /* append it to list 'head' */ + tail->next = tmp; + tail = tmp; + } + if (ls1->next == NULL) { + ls1 = ls2; + ls2 = NULL; + } + else ls1 = ls1->next; + } + AddToGarbageList(head); + return(head); +} + +int ListLen(struct objlist *head) +{ + int n; + + n = 0; + while (head != NULL) { + head = head->next; + n++; + } + return (n); +} + +int ListLength(char *list_template) +{ + struct objlist *head; + int n; + + head = List(list_template); + n = ListLen(head); + return (n); +} + + + +struct objlist *CopyObjList(struct objlist *oldlist) +/* copies list pointed to by oldlist, creating + a list whose head pointer is returned */ +{ + struct objlist *head, *tail, *tmp, *newob; + + tmp = oldlist; + head = NULL; + tail = NULL; + while (tmp != NULL) { + if ((newob = GetObject()) == NULL) { + Fprintf(stderr,"CopyObjList: core allocation failure\n"); +#ifdef HAVE_MALLINFO + PrintMemoryStats(); +#endif + return(NULL); + } + newob->name = (tmp->name) ? strsave(tmp->name) : NULL; + newob->type = tmp->type; + if (newob->type == PROPERTY) + CopyProperties(newob, tmp); + else { + if (tmp->model.class == NULL || IsPort(tmp)) + newob->model.class = NULL; + else + newob->model.class = strsave(tmp->model.class); + newob->instance.name = (tmp->instance.name) ? + strsave(tmp->instance.name) : NULL; + } + newob->node = tmp->node; + newob->next = NULL; + if (head == NULL) + head = newob; + else + tail->next = newob; + tail = newob; + tmp = tmp->next; + } + return (head); +} + + +/********************* LIST SEARCHING STUFF ******************************/ + +/*--------------------------------------------------------------*/ +/* Search for exact match of object 'name' in cell 'WhichCell' */ +/* This search excludes object properties. */ +/*--------------------------------------------------------------*/ + +struct objlist *LookupObject(char *name, struct nlist *WhichCell) +{ + return((struct objlist *)HashLookup(name, WhichCell->objtab, OBJHASHSIZE)); +} + +struct objlist *LookupInstance(char *name, struct nlist *WhichCell) +/* searches for exact match of instance 'name' in cell 'WhichCell' */ +{ + return((struct objlist *)HashLookup(name, WhichCell->insttab, OBJHASHSIZE)); +} + + +void UpdateNodeNumbers(struct objlist *lst, int from, int to) +{ + while (lst != NULL) { + if (lst->node == from) + lst->node = to; + lst = lst->next; + } +} + +void AddToCurrentCell(struct objlist *ob) +{ + AddToCurrentCellNoHash(ob); + + /* add to object hash table for this cell */ + if (CurrentCell != NULL) { + HashPtrInstall(ob->name, ob, CurrentCell->objtab, OBJHASHSIZE); + } +} + +void AddToCurrentCellNoHash(struct objlist *ob) +{ + if (CurrentCell == NULL) { + Fprintf(stderr,"No current cell for "); + switch (ob->type) { + case PORT: Fprintf(stderr,"Port(%s)\n",ob->name); break; + case PROPERTY: Fprintf(stderr,"Property\n"); break; + case GLOBAL: Fprintf(stderr,"Global(%s)\n",ob->name); break; + case UNIQUEGLOBAL: Fprintf(stderr,"UniqueGlobal(%s)\n",ob->name); break; + default: Fprintf(stderr,"pin: %s\n",ob->name); break; + } + return; + } + + if (CurrentCell->cell == NULL) CurrentCell->cell = ob; + else CurrentTail->next = ob; + CurrentTail = ob; + ob->next = NULL; +} + +void AddInstanceToCurrentCell(struct objlist *ob) +{ + /* add to instance hash table for this cell */ + HashPtrInstall(ob->instance.name, ob, CurrentCell->insttab, OBJHASHSIZE); +} + +void FreeObject(struct objlist *ob) +{ + /* This just frees the object record. Beware of pointer left */ + /* in the objtab hash table. Hash table records should be */ + /* removed first. */ + + if (ob->name != NULL) FreeString(ob->name); + + if (ob->type == PROPERTY) { + if (ob->instance.props != NULL) { + struct valuelist *kv; + int i; + for (i = 0; ; i++) { + kv = &(ob->instance.props[i]); + if (kv->type == PROP_ENDLIST) break; + FreeString(kv->key); + if (kv->type == PROP_STRING && kv->value.string != NULL) + FreeString(kv->value.string); + else if (kv->type == PROP_EXPRESSION) { + struct tokstack *stackptr, *nptr; + stackptr = kv->value.stack; + while (stackptr != NULL) { + nptr = stackptr->next; + if (stackptr->toktype == TOK_STRING) + FREE(stackptr->data.string); + FREE(stackptr); + stackptr = nptr; + } + } + } + FREE(ob->instance.props); + } + } + else { + /* All other records */ + if (ob->instance.name != NULL) FreeString(ob->instance.name); + } + if (ob->model.class != NULL) FreeString(ob->model.class); + FREE(ob); +} + + +void FreeObjectAndHash(struct objlist *ob, struct nlist *ptr) +{ + HashDelete(ob->name, ptr->objtab, OBJHASHSIZE); + FreeObject(ob); +} + +/*************** GENERAL UTILITIES ****************************/ + +int NumberOfPorts(char *cellname) +{ + struct nlist *tp; + struct objlist *ob; + int ports; + + tp = LookupCell(cellname); + if (tp == NULL) return(0); + ports = 0; + for (ob = tp->cell; ob != NULL; ob = ob->next) + if (IsPort(ob)) ports++; + return(ports); +} + +void FreePorts(char *cellname) +{ + struct nlist *tp; + struct objlist *ob, *obnext, *oblast; + + tp = LookupCell(cellname); + if (tp == NULL) return; + ob = tp->cell; + if (ob == NULL) return; + tp->cell = NULL; + + while (ob && IsPort(ob)) { + obnext = ob->next; + if (ob->name != NULL) FreeString(ob->name); + if (ob->instance.name != NULL) FreeString(ob->instance.name); + FREE(ob); + ob = obnext; + } + tp->cell = ob; + + oblast = ob; + while (ob) { + obnext = ob->next; + if (IsPort(ob)) { + if (ob->name != NULL) FreeString(ob->name); + if (ob->instance.name != NULL) FreeString(ob->instance.name); + FREE(ob); + oblast->next = obnext; + } + else + oblast = ob; + ob = obnext; + } +} + + +struct objlist *InstanceNumber(struct nlist *tp, int inst) +{ + struct objlist *ob; + int count; + + count = 1; + for (ob = tp->cell; ob != NULL; ob = ob->next) { + if (ob->type == FIRSTPIN) { + if (count == inst) return(ob); + count ++; + } + } + return(NULL); +} + + + +/**********************************************************************/ +/* NodeName cacheing stuff */ +/**********************************************************************/ + + + +static char *OldNodeName(struct nlist *tp, int node) +{ + /* return a legitimate node name for node number 'node' in cell *tp */ + /* Order of preference: + 1) Named ports of cells + 2) Named internal nodes of cells + 3) Unique global ports (these names are descriptive, but long) + 4) Global ports + 5) Pins on instances + */ + + struct objlist *ob; + struct objlist *firstport; + struct objlist *firstnode; + struct objlist *firstuniqueglobal; + struct objlist *firstglobal; + struct objlist *firstpin; + static char StrBuffer[100]; + +#if 0 + /* make second pass, looking for ports */ + ob = tp->cell; + while (ob != NULL) { + if ((node == ob->node) && IsPort(ob)) { + strcpy(StrBuffer, ob->name); + return(StrBuffer); + } + ob = ob->next; + } + + /* make third pass, looking for named internal nodes */ + ob = tp->cell; + while (ob != NULL) { + if ((node == ob->node) && (ob->type == NODE)) { + strcpy(StrBuffer, ob->name); + return(StrBuffer); + } + ob = ob->next; + } + + /* make zeroth pass, looking for unique global ports */ + ob = tp->cell; + while (ob != NULL) { + if ((node == ob->node) && (ob->type == UNIQUEGLOBAL)) { + strcpy(StrBuffer, ob->name); + return(StrBuffer); + } + ob = ob->next; + } + + /* make first pass, looking for global ports */ + ob = tp->cell; + while (ob != NULL) { + if ((node == ob->node) && (ob->type == GLOBAL)) { + strcpy(StrBuffer, ob->name); + return(StrBuffer); + } + ob = ob->next; + } + + /* make fourth pass, looking for first pin */ + ob = tp->cell; + while (ob != NULL) { + if (node == ob->node) { + strcpy(StrBuffer, ob->name); + return(StrBuffer); + } + ob = ob->next; + } +#endif + + firstport = NULL; + firstnode = NULL; + firstuniqueglobal = NULL; + firstglobal = NULL; + firstpin = NULL; + if (node < 1) { + sprintf(StrBuffer, "Disconnected(%d)",node); + return(StrBuffer); + } + for (ob = tp->cell; ob != NULL; ob = ob->next) { + if (node == ob->node) { + if (ob->type >= FIRSTPIN) firstpin = ob; + else if (IsPort(ob)) { + firstport = ob; + strcpy(StrBuffer,ob->name); + return(StrBuffer); + } + else if (ob->type == NODE) firstnode = ob; + else if (ob->type == UNIQUEGLOBAL) firstuniqueglobal = ob; + else if (ob->type == GLOBAL) firstglobal = ob; + else + Fprintf(stderr,"??? ob->type = %d on %s\n",ob->type,ob->name); + } + } + + if (firstport != NULL) ob = firstport; + else if (firstnode != NULL) ob = firstnode; + else if (firstuniqueglobal != NULL) ob = firstuniqueglobal; + else if (firstglobal != NULL) ob = firstglobal; + else if (firstpin != NULL) ob = firstpin; + else { + /* if we got to here, we have a serious problem */ + Fprintf (stderr, "NodeName(%d) called with bogus parameter\n", node); + sprintf(StrBuffer, "bogus(%d)",node); + return(StrBuffer); + } + strcpy(StrBuffer,ob->name); + return(StrBuffer); +} + + +char *NodeName(struct nlist *tp, int node) +{ + if (node == -1) return("Disconnected"); + if (tp->nodename_cache != NULL) { + if (node > tp->nodename_cache_maxnodenum || + tp->nodename_cache[node] == NULL) + return ("IllegalNode"); + else + return (tp->nodename_cache[node]->name); + } + return (OldNodeName(tp, node)); +} + +char *NodeAlias(struct nlist *tp, struct objlist *ob) +/* return the best name for 'ob'; safer than calling NodeName, + as it correctly handles disconnected nodes */ +{ + if (ob == NULL) return("NULL"); + if (ob->node == -1) { +/* Fprintf(stderr,"Disconnected node in NodeAlias: %s\n",ob->name); */ + return(ob->name); + } + if ((ob->node >= 0) && (tp->nodename_cache != NULL) && + (ob->node <= tp->nodename_cache_maxnodenum)) + return (tp->nodename_cache[ob->node]->name); + return (OldNodeName(tp, ob->node)); +} + +void FreeNodeNames(struct nlist *tp) +{ + if (tp == NULL) return; + if (tp->nodename_cache != NULL) + FREE(tp->nodename_cache); + tp->nodename_cache = NULL; + tp->nodename_cache_maxnodenum = 0; +} + +void CacheNodeNames(struct nlist *tp) +{ + int nodes; + struct objlist *ob; + + if (tp == NULL) return; + if (tp->nodename_cache != NULL) FreeNodeNames(tp); + nodes = 0; + + for (ob = tp->cell; ob != NULL; ob = ob->next) + if (ob->node > nodes) nodes = ob->node; + + if (nodes == 0) return; + + tp->nodename_cache = + (struct objlist **)CALLOC(nodes+1, sizeof(*(tp->nodename_cache))); + if (tp->nodename_cache == NULL) return; + tp->nodename_cache_maxnodenum = nodes; + + for (ob = tp->cell; ob != NULL; ob = ob->next) { + int present, new_type; + + if (ob->node < 0) continue; /* do not cache it */ + if ((tp->nodename_cache)[ob->node] == NULL) + (tp->nodename_cache)[ob->node] = ob; + + present = ((tp->nodename_cache)[ob->node])->type; + new_type = ob->type; + + if (new_type == present) continue; + if (new_type >= FIRSTPIN && present >= FIRSTPIN) continue; + + switch (new_type) { + case PORT: + (tp->nodename_cache)[ob->node] = ob; + break; + case NODE: + if (present != PORT) + (tp->nodename_cache)[ob->node] = ob; + break; + case UNIQUEGLOBAL: + if (present != PORT && present != NODE) + (tp->nodename_cache)[ob->node] = ob; + break; + case GLOBAL: + if (present != PORT && present != NODE && present != UNIQUEGLOBAL) + (tp->nodename_cache)[ob->node] = ob; + break; + default: /* we have a pin or property, which we can ignore */ + break; + } + } +} + diff --git a/base/objlist.h b/base/objlist.h new file mode 100644 index 0000000..7c60a81 --- /dev/null +++ b/base/objlist.h @@ -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 */ + + + diff --git a/base/pdutils.c b/base/pdutils.c new file mode 100644 index 0000000..5cd7ad1 --- /dev/null +++ b/base/pdutils.c @@ -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 +#include +#ifdef IBMPC +#include +#endif + +#if defined(__STDC__) || defined(IBMPC) +#include +#else +#include +#endif + +#include "netgen.h" + +/*************************************************************************/ +/* */ +/* Random number generators */ +/* */ +/*************************************************************************/ + +/* See NUMERICAL RECIPES IN C */ + +#include + +#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 */ + +/* 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 */ + +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 */ diff --git a/base/pdutils.h b/base/pdutils.h new file mode 100644 index 0000000..fe91158 --- /dev/null +++ b/base/pdutils.h @@ -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 +#else +#include +#endif + +#ifdef va_end +#include +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)) diff --git a/base/place.c b/base/place.c new file mode 100644 index 0000000..2488546 --- /dev/null +++ b/base/place.c @@ -0,0 +1,1254 @@ +/* "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. */ + +/* place.c -- more embedding routines for PROTOCHIP */ + + +/* define the following to enable checking of minimum leaf usage */ +#define CHECK_MINUSEDLEAVES + +/* define the following to enable checking of minimum common nodes */ +#undef CHECK_MINCOMMONNODES + +/* define to avoid merging elements that share only global nodes */ +#define DISCOUNT_GLOBAL_NODES + +/* define to get reams of extra output */ +#undef PLACE_DEBUG + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "netgen.h" +#include "hash.h" +#include "objlist.h" +#include "query.h" +#include "netfile.h" +#include "embed.h" +#include "dbug.h" +#include "print.h" + +#ifdef IBMPC +#include /* system */ +#include /* atoi */ +#include /* bioskey */ +#include /* memset */ +#endif /* IBMPC */ + +/* count invokations of different test procedures */ +int CountAnyCommonNodes; + + +/* abridged ownership and connectivity matrices */ +/* elements, nodes, leaves are indexed from 1 to N, nodes, leaves */ +unsigned short M[MAX_ELEMENTS][7]; +/* height, L, R, SWALLOWED, PINS, LEAVES, USED */ + +unsigned long MSTAR[MAX_ELEMENTS][(MAX_LEAVES / BITS_PER_LONG) + 1]; + +unsigned char C[MAX_ELEMENTS][MAX_NODES + 1]; +unsigned char CSTAR[MAX_ELEMENTS][MAX_NODES + 1]; + +/* elements at level i must have TreeFanout[i] or fewer ports */ +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 */ +int MinCommonNodes[MAX_TREE_DEPTH + 1]; + +/* elements at level i must contain at least MinUsedLeaves[i] leaves */ +int MinUsedLeaves[MAX_TREE_DEPTH + 1]; + +int Nodes; /* number of nodes in the cell */ +int Leaves; /* number of leaves in the cell */ +int PackedLeaves; /* == Leaves / BITS_PER_LONG, just to save computation */ +int Elements; /* number of elements */ +int NewN, NewElements; +int SumPINS, SumCommonNodes, SumUsedLeaves; +int NewSwallowed; +int Pass; +int logging = 0; /* generate output file LOG_FILE_EXT */ +int selectivelogging = 0; +int LogLevel1 = -1; /* automatically log if Level1 == LogLevel1 */ +int LogLevel2 = -1; +int FatalError = 0; /* internal error */ +int Exhaustive = 0; /* slow, methodical */ +int PlaceDebug = 0; /* interactive debug */ + +FILE *outfile; /* output file */ +FILE *logfile; /* debugging log file */ + +static int LeafPins = LEAFPINS; /* was 10.0 */ +static float RentExp = RENTEXP; + +/* Initialize TreeFanout array to contain the actual fanouts of the chip */ +void InitializeFanout(void) +{ + int i; + + for (i = 1; i <= MAX_TREE_DEPTH; i++) + TreeFanout[i] = (int)(LeafPins * pow(2.0, i*RentExp)); +} + +void InitializeMinCommonNodes(void) +{ + int i; + for (i = 1; i <= MAX_TREE_DEPTH; i++) + MinCommonNodes[i] = (int)((TreeFanout[i] - TreeFanout[1] + 2) / 2); +/* MinCommonNodes[i] = (TreeFanout[i] - TreeFanout[1] + 2) / 2; */ +} + +void InitializeMinUsedLeaves(void) +{ + int i; + MinUsedLeaves[1] = 2; + MinUsedLeaves[2] = 2; + for (i = 3; i <= MAX_TREE_DEPTH; i++) + MinUsedLeaves[i] = 2*MinUsedLeaves[i-1]; +} + +int RenumberNodes(char *cellname) +/* returns number of nodes in 'cellname', numbered from 1 */ +{ + struct nlist *tp; + struct objlist *ob; + int maxnode, newnode, oldnode; + + tp = LookupCell(cellname); + if (tp == NULL) return(0); + if (tp->class != CLASS_SUBCKT) return(0); + ob = tp->cell; + maxnode = -1; + while (ob != NULL) { + if (ob->node > maxnode) + maxnode = ob->node; + ob = ob->next; + } + /* renumber all the nodes contiguously from 1 */ + newnode = 1; + for (oldnode = 1; oldnode <= maxnode; oldnode++) { + int found; + found = 0; + for (ob = tp->cell; ob != NULL; ob = ob->next) + if (ob->node == oldnode) { + found = 1; + ob->node = newnode; + } + if (found) newnode++; + } + return(newnode - 1); +} + +void EraseMatrices(void) +{ + memzero(C, sizeof(C)); + memzero(CSTAR, sizeof(CSTAR)); + memzero(M, sizeof(M)); + memzero(MSTAR, sizeof(MSTAR)); +} + +int InitializeMatrices(char *cellname) +/* return 1 if OK; upon exit: 'Leaves', 'Nodes', 'Elements' are initialized */ +{ + struct nlist *tp; + struct objlist *ob; + int i, j; + + tp = LookupCell(cellname); + if (tp == NULL) return(0); + if (tp->class != CLASS_SUBCKT) return(0); + + if ((Nodes = RenumberNodes(cellname)) > MAX_NODES) { + Fprintf(stderr,"Too many nodes in cell: %s (%d > MAX_NODES(%d))\n", + cellname, Nodes, MAX_NODES); + return(0); + } + EraseMatrices(); /* all elements are set to 0 */ + + /* create connectivity matrix C */ + Leaves = 0; + for (ob = tp->cell; ob != NULL; ob = ob->next) { + if (ob->type == FIRSTPIN) { + struct nlist *tp; + + Leaves++; + if (Leaves > MAX_LEAVES) continue; /* keep going within the for loop */ + + tp = LookupCell(ob->model.class); + if (tp == NULL || (tp->class != CLASS_SUBCKT) || tp->embedding == NULL) + LEVEL(Leaves) = 0; + else LEVEL(Leaves) = ((struct embed *)(tp->embedding))->level; + /* remember, L(Leaves) = R(Leaves) = 0 by EraseMatrices above */ + } + if (ob->type >= FIRSTPIN) C[Leaves][ob->node] = 1; + } + if (Leaves > MAX_LEAVES) { + Fprintf(stderr, "Too many leaves in cell: %s (%d > MAX_LEAVES(%d))\n", + cellname, Leaves, MAX_LEAVES); + return(0); + } + PackedLeaves = Leaves / BITS_PER_LONG; + + /* row 0 of C is special, containing the port list of the entire cell */ + for (ob = tp->cell; ob != NULL; ob = ob->next) + if (IsPortInPortlist(ob, tp)) C[0][ob->node] = 1; + + /* matrix M partially init. by EraseMatrices, and by Leaves loop above; */ + /* column PINS of matrix M is special, containing fanout of each element */ + for (i = 0; i <= Leaves; i++) + for (j = 1; j <= Nodes; j++) PINS(i) += C[i][j]; + + /* initialize the number of leaves contained by each element */ + LEAVES(0) = Leaves; + for (i = 1; i <= Leaves; i++) LEAVES(i) = 1; + + /* create transitive closure of M */ + for (i = 1; i <= Leaves; i++) + SetPackedArrayBit(MSTAR[i],i); /* each leaf owns itself */ + for (i = 1; i <= Leaves; i++) /* used to be i = 0 ??? */ + SetPackedArrayBit(MSTAR[0],i); /* portlist owns all leaves */ + + /* create nodal connectivity transitive closure matrix CSTAR */ + i = 0; + for (ob = tp->cell; ob != NULL; ob = ob->next) { + if (ob->type == FIRSTPIN) i++; + if (ob->type >= FIRSTPIN) CSTAR[i][ob->node]++; + } + for (j = 1; j <= Nodes; j++){ + CSTAR[0][j] = 0; + for (i = 1; i <= Leaves; i++) CSTAR[0][j] += CSTAR[i][j]; + if (C[0][j]) CSTAR[0][j]++; /* increment usage of ports */ + } + + /* initially, number of elements == number of leaves */ + Elements = Leaves; + return(1); +} + +void PrintC(FILE *outfile) +{ + int i, j; + + if (outfile == NULL) return; + Fprintf(outfile,"C:\n"); + for (i = 0; i <= Elements; i++) { + Fprintf(outfile,"%4d: %3d | ",i,PINS(i)); + for (j = 1; j <= Nodes; j++) Fprintf(outfile," %d",C[i][j]); + Fprintf(outfile,"\n"); + } + Fprintf(outfile,"\n"); +} + +void PrintCSTAR(FILE *outfile) +{ + int i, j; + + if (outfile == NULL) return; + Fprintf(outfile,"C*:\n"); + for (i = 0; i <= Elements; i++) { + Fprintf(outfile,"%4d: ",i); + for (j=1; j <= Nodes; j++) Fprintf(outfile,"%3d",CSTAR[i][j]); + Fprintf(outfile,"\n"); + } + Fprintf(outfile,"\n"); +} + +void PrintOwnership(FILE *outfile) +{ + int i,j; + + if (outfile == NULL) return; + Fprintf(outfile,"Ownership matrices M, MSTAR:\n"); + Fprintf(outfile,"element height L R S Pins Leaves Used\n"); + for (i = 0; i <= Elements; i++) { + Fprintf(outfile,"%4d: %4d %4d %4d %2d %3d %5d %5d: ",i, + LEVEL(i), L(i), R(i), SWALLOWED(i), PINS(i), LEAVES(i), USED(i)); + + for (j = 1; j <= Leaves; j++) { + if (TestPackedArrayBit(MSTAR[i],j)) Fprintf(outfile,"1"); + else Fprintf(outfile,"0"); + } +#if 0 + /* debugging stuff for packed arrays */ + Fprintf(outfile," : "); + for(j = 0; j <= PackedLeaves; j++) + Fprintf(outfile," %ld",MSTAR[i][j]); +#endif + Fprintf(outfile,"\n"); + } + Fprintf(outfile,"\n"); +} + + +void PrintE(FILE *outfile, int E) +{ + if (IsLeaf(E)) Fprintf(outfile, "%d", E); + else { + Fprintf(outfile,"("); + PrintE(outfile,L(E)); + Fprintf(outfile," "); + PrintE(outfile,R(E)); + Fprintf(outfile,")"); + } +} + + +#if 0 +INLINE +int UsedLeaves(int E1, int E2) +/* returns the number of leaves in E1 + E2, which are assumed independent */ +{ + return(LEAVES(E1) + LEAVES(E2)); +} +#else +/* returns the number of leaves in E1 + E2, which are assumed independent */ +#define UsedLeaves(A,B) (LEAVES(A) + LEAVES(B)) +#endif + + +INLINE +int CommonNodes(int E1, int E2, int IncludeGlobals) +/* returns the number of nodes that E1 and E2 share */ +/* if IncludeGlobals == 0, do not count large connectivity nodes */ +{ + int result, node; + + result = 0; + if (IncludeGlobals) { + for (node = 1; node <= Nodes; node++) + if (C[E1][node] && C[E2][node]) result++; + } + else { + for (node = 1; node <= Nodes; node++) + if (C[E1][node] && C[E2][node] && !C[0][node]) result++; + } +#ifdef PLACE_DEBUG + Printf("CommonNodes(%d,%d) (%s globals) gives %d\n", + E1,E2, IncludeGlobals?"including":"excluding", result); +#endif + return(result); +} + +INLINE +int GlobalNodes(int E) +/* return the number of global nodes that E contacts */ +/* for now, global nodes are just cell ports */ +{ + int node; + int count; + + count = 0; + for (node = 1; node <= Nodes; node++) + if (C[E][node] && C[0][node]) count++; + return(count); +} + +#ifdef DISCOUNT_GLOBAL_NODES +int AnyCommonNodes(int E1, int E2) +/* returns 1 if E1 and E2 share a node */ +/* if DISCOUNT_GLOBAL_NODES, do not count large connectivity nodes, + unless these are the only connections */ +{ + int node; + int nodesincommon; + + CountAnyCommonNodes++; + nodesincommon = 0; + for (node = 1; node <= Nodes; node++) { + /* do not count it if it is a port for the entire cell */ + if (C[E1][node] && C[E2][node]) { + if (!(C[0][node])) return(1); + nodesincommon = 1; + } + } + +#if 1 + if (!nodesincommon) return(0); + /* if ANY nodes exist that are not ports, return NO_COMMON_NODES */ + for (node = 1; node <= Nodes; node++) + if ((C[E1][node] || C[E2][node]) && !(C[0][node])) return (0); + + /* all nodes are global, and some are shared, so return 1 */ + return(1); + +#else + /* if E1 is contained in E2, or E2 is contained in E1, all is OK */ + /* this is extremely inadequate for merging cells whose pins are all global*/ + return(Swallowed(E2,E1) || Swallowed(E1,E2)); +#endif +} + +#else +int AnyCommonNodes(int E1, int E2) +/* returns 1 if E1 and E2 share a node */ +/* any node, including a global node, is OK */ +{ + int node; + int nodesincommon; + + CountAnyCommonNodes++; + for (node = 1; node <= Nodes; node++) + if (C[E1][node] && C[E2][node]) return(1); + return(0); +} +#endif /* DISCOUNT_GLOBAL_NODES */ + + +void IncrementUsedCount(int E) +{ +#if 0 + if (E == 0) return; + USED(E)++; +#else + USED(E)++; + if (IsLeaf(E)) return; +#endif + IncrementUsedCount(L(E)); + IncrementUsedCount(R(E)); +} + +void AddNewElement(int E1, int E2) +{ + int i; + + NewN++; + if (NewN >= MAX_ELEMENTS) { + Fprintf(stderr,"Too many elements (%d)\n",NewN); + if (outfile != NULL) + Fprintf(outfile,"Too many elements (%d)\n",NewN); + return; + } + NewElements++; + + /* update ownership matrix */ + LEVEL(NewN) = MAX(LEVEL(E1), LEVEL(E2)) + 1; + L(NewN) = E1; R(NewN) = E2; + + /* update leaf ownership matrix */ + for (i = 0; i <= PackedLeaves; i++) + MSTAR[NewN][i] = MSTAR[E1][i] | MSTAR[E2][i]; + + /* update connectivity matrix with actual portlist */ + for (i = 1; i <= Nodes; i++) + if ((C[E1][i] || C[E2][i]) && + (CSTAR[E1][i] + CSTAR[E2][i] < CSTAR[0][i])) + C[NewN][i] = 1; + + /* update number of leaves contained by new element */ + /* for (i = 1; i <= Leaves; i++) + if (TestPackedArrayBit(MSTAR[NewN],i)) LEAVES(NewN)++; */ + LEAVES(NewN) = LEAVES(E1) + LEAVES(E2); + + /* increment the instance count for tree rooted by NewN */ + IncrementUsedCount(E1); + IncrementUsedCount(E2); + + for (i = 1; i <= Nodes; i++) if (C[NewN][i]) PINS(NewN)++; + SumPINS += PINS(NewN); + SumCommonNodes += PINS(E1) + PINS(E2) - PINS(NewN); + SumUsedLeaves += LEAVES(NewN); + + /* update node usage matrix */ + for (i = 1; i <= Nodes; i++) + CSTAR[NewN][i] = CSTAR[E1][i] + CSTAR[E2][i]; + + /* add to exist-checking data structure */ + AddToExistSet(E1, E2); + + if (PlaceDebug) { + if (NewN == Elements + 1) Printf("\n"); + Printf("Adding new element: "); + PrintE(stdout,NewN); + Printf(" pins = %d, commonnodes = %d", + PINS(NewN), PINS(E1)+PINS(E2)-PINS(NewN)); + Printf("\n"); + } +} + + +int CountInLevel(int i, int upto) +/* if upto == 1, count elements of level <= i */ +{ + int elem; + int count; + + count = 0; + if (upto) { + for (elem = 1; elem <= Elements; elem++) + if (LEVEL(elem) <= i) count++; + } + else { + for (elem = 1; elem <= Elements; elem++) + if (LEVEL(elem) == i) count++; + } + return(count); +} + + +/* file extensions of embedding file and log file */ +#define OUT_FILE_EXT ".out" +#define LOG_FILE_EXT ".log" + +int OpenEmbeddingFile(char *cellname, char *filename) +/* returns 1 if OK */ +{ + struct nlist *tp; + char outfilename[200]; + char logfilename[200]; + + tp = LookupCell(cellname); + if (tp == NULL) { + Fprintf(stderr, "No cell: '%s'\n",cellname); + return(0); + } + if (tp->class != CLASS_SUBCKT) { + Fprintf(stderr, "Cell: '%s' is primitive, and cannot be embedded.\n"); + return(0); + } + tp->dumped = 1; + + if (filename == NULL || strlen(filename) == 0) + strcpy(outfilename, cellname); + else + strcpy(outfilename, filename); + if (strstr(outfilename, OUT_FILE_EXT) == NULL) + strcat(outfilename, OUT_FILE_EXT); + + outfile = fopen(outfilename,"w"); + if (outfile == NULL) { + Fprintf(stderr,"Unable to open embedding file %s\n", outfilename); + return(0); + } + + logfile = NULL; + if (logging) { + if (filename == NULL || strlen(filename) == 0) + strcpy(logfilename, cellname); + else + strcpy(logfilename, cellname); + if (strstr(logfilename, LOG_FILE_EXT) == NULL) + strcat(logfilename, LOG_FILE_EXT); + logfile = fopen(logfilename,"w"); + if (logfile == NULL) { + Fprintf(stderr,"Unable to open log file %s\n", logfilename); + logging = 0; + } + } + return(1); +} + +void CloseEmbeddingFile(void) +{ + fclose(outfile); + outfile = NULL; + if (logfile != NULL) fclose(logfile); + logfile = NULL; +} + + + + + + +void EmbedCells(char *cellname, enum EmbeddingStrategy strategy) +{ + struct nlist *tp; + struct objlist *ob; + + tp = LookupCell(cellname); + if (tp == NULL) { + Fprintf(stderr, "No cell: '%s'\n",cellname); + return; + } + if (tp->class != CLASS_SUBCKT) { + Fprintf(stderr, "Cell: '%s' is primitive, and cannot be embedded.\n"); + return; + } + for (ob = tp->cell; ob != NULL; ob = ob->next) + if (ob->type == FIRSTPIN) { + struct nlist *tp2; + tp2 = LookupCell(ob->model.class); + if (!(tp2->dumped) && (tp2->class == CLASS_SUBCKT)) + EmbedCells(ob->model.class,strategy); + } + switch (strategy) { + case bottomup: EmbedCell(cellname, NULL); + break; + default: + TopDownEmbedCell(cellname, NULL, strategy); + break; + } +} + + +void Embed(char *cellname) +/* use the "best" strategy */ +{ + ClearDumpedList(); + EmbedCells(cellname, greedy); +} + +void DoEmbed(char *cellname, enum EmbeddingStrategy strategy) +{ +Printf("embedding using strategy %d\n",strategy); + ClearDumpedList(); + EmbedCells(cellname, strategy); +} + + +int CountSubGraphs(char *cellname) +{ + struct nlist *tp; + int i; + int groups[MAX_LEAVES+1]; + int contact[MAX_LEAVES+1]; + + tp = LookupCell(cellname); + if (tp == NULL) { + Fprintf(stderr, "No cell: '%s'\n",cellname); + return(0); + } + if (tp->class != CLASS_SUBCKT) { + Fprintf(stderr, "Cell: '%s' is primitive, and cannot be embedded.\n"); + return(0); + } + + if (!InitializeMatrices(cellname)) return(0); + memzero(groups, sizeof(groups)); + + for (i = 1; i <= Leaves; i++) groups[i] = i; + + for (i = 1; i <= Leaves; i++) { + int node; + int j; + int mingroup; + + memzero(contact, sizeof(contact)); + contact[i] = 1; + for (j = i + 1; j <= Leaves; j++) { + /* else, find all elements that contact this node */ + for (node = 1; node <= Nodes; node++) { + if ((C[i][node] && C[j][node]) && !(C[0][node])) { + contact[j] = 1; + break; + } + } + } + mingroup = MAX_LEAVES+2; + for (j = 1; j <= Leaves; j++) { + if (contact[j] && groups[j] < mingroup) mingroup = groups[j]; + } + for (j = 1; j <= Leaves; j++) + if (contact[j]) groups[j] = mingroup; + } + + Printf("ownership groups: "); + for (i = 1; i <= Leaves; i++) Printf(" %d",groups[i]); + Printf("\n"); + return(0); +} + + + + + + + + + +int NumberOfInstances(char *cellname) +{ + struct nlist *tp; + struct objlist *ob; + int instances; + + tp = LookupCell(cellname); + if (tp == NULL) return(0); + if (tp->class != CLASS_SUBCKT) return(0); + instances = 0; + for (ob = tp->cell; ob != NULL; ob = ob->next) + if (ob->type == FIRSTPIN) instances++; + return(instances); +} + +int UniquePorts(struct objlist *pt) +/* assuming that pt points to the beginning of an instance, + return the number of output ports of the instance, counting + ports that are connected to the same node as 1 +*/ +{ + int outputs, found; + struct objlist *scan; + + outputs = 0; + do { + scan = pt; + found = 0; + do { + if (pt != scan && pt->node == scan->node) found = 1; + scan = scan->next; + } while (!found && scan->type > FIRSTPIN); + if (!found) outputs++; + pt = pt->next; + } while (pt->type > FIRSTPIN); + return (outputs); +} + +int NodesInCommon(struct objlist *pt1, struct objlist *pt2) +/* assuming that pt1 and pt2 point to the beginning of instances, + return the number of nodes the two instances share +*/ +{ + int common, found; + struct objlist *scan; + + common = 0; + do { + /* make sure there are no other pins connected to this node */ + found = 0; + scan = pt1; + do { + if (scan != pt1 && scan->node == pt1->node) found = 1; + scan = scan->next; + } while (!found && scan->type > FIRSTPIN); + if (!found) { + scan = pt2; + found = 0; + do { + if (scan->node == pt1->node) found = 1; + scan = scan->next; + } while (!found && scan->type > FIRSTPIN); + if (found) common++; + } + pt1 = pt1->next; + } while (pt1->type > FIRSTPIN); + return(common); +} + +void OldEmbed(char *cellname, char *filename) +{ + struct nlist *tp; + struct objlist *ob1, *ob2; + + tp = LookupCell(cellname); + if (tp == NULL) return; + if (tp->class != CLASS_SUBCKT) return; + + Printf("OldEmbed of element: %s into file %s\n",cellname,filename); + /* print out element list */ + for (ob1 = tp->cell; ob1 != NULL; ob1 = ob1->next) + if (ob1->type == FIRSTPIN) + Printf("element: %s, Unique ports = %d\n",ob1->instance, + UniquePorts(ob1)); + + /* print out shared node matrix */ + for (ob1 = tp->cell; ob1 != NULL; ob1 = ob1->next) { + if (ob1->type == FIRSTPIN) { + for (ob2 = tp->cell; ob2 != NULL; ob2 = ob2->next) + if (ob2->type == FIRSTPIN) Printf("%d ",NodesInCommon(ob1, ob2)); + Printf("\n"); + } + } +} + +static jmp_buf jmpenv; + +/* static void handler(void) */ +static void handler(int sig) +{ + Fprintf(stderr,"\nInterrupt (%d)!!\n", sig); + fflush(stderr); + longjmp(jmpenv,1); +} + +void SetupArray(char *prompt1, char *prompt2, char *prompt3, int *data, + void (*proc)(void)) +{ + int i, oldfanout; + char name[100]; + + Printf(prompt1); + for (i = 1; i <= MAX_TREE_DEPTH; i++) + Printf(" %d", data[i]); + Printf("\n"); + + oldfanout = 1; + for (i = 1; i <= MAX_TREE_DEPTH; i++) { + char prompt[100]; + int newfanout; + sprintf(prompt, prompt2, i); + promptstring(prompt, name); + newfanout = atoi(name); + if (i == 1 && newfanout == 0) { + proc(); /* reset to original */ + i = MAX_TREE_DEPTH; + } + else { + if (newfanout == 0) /* fill out MinCommonNodes */ + for (; i <= MAX_TREE_DEPTH; i++) + data[i] = oldfanout; + else { + data[i] = newfanout; + oldfanout = newfanout; + } + } + } + Printf(prompt3); + for (i = 1; i <= MAX_TREE_DEPTH; i++) + Printf(" %d", data[i]); + Printf("\n"); + return; +} + +void SetupArrayFromString(char *prompt1, char *prompt3, int *data, + void (*proc)(void), char *text) +{ + int i, oldfanout, newfanout; + char string[100]; + char *ch; + char *endch; + + strcpy(string, text); + Printf(prompt1); + for (i = 1; i <= MAX_TREE_DEPTH; i++) + Printf(" %d", data[i]); + Printf("\n"); + + ch = strtok(string, " "); + if (ch == NULL) return; + oldfanout = (int)strtol(ch, &endch, 10); + if (endch == ch) return; + if (oldfanout == 0) { + proc(); + return; + } + /* it is a valid non-zero number */ + for (i = 1; i <= MAX_TREE_DEPTH; i++) { + data[i] = oldfanout; + /* look at next element in string */ + if (ch != NULL) { + ch = strtok(NULL, " "); + if (ch == NULL) newfanout = 0; + else newfanout = (int)strtol(ch, NULL, 10); + if (newfanout == 0) ch = NULL; + else oldfanout = newfanout; + } + } + Printf(prompt3); + for (i = 1; i <= MAX_TREE_DEPTH; i++) + Printf(" %d", data[i]); + Printf("\n"); + return; +} + +void SetupTreeFanout(char *string) +{ + SetupArrayFromString("Old fanout:", "New fanout: ", + TreeFanout, InitializeFanout, string); +} + +void SetupMinCommonNodes(char *string) +{ + SetupArrayFromString("Old common node requrements:", + "New common node requrements:", MinCommonNodes, + InitializeMinCommonNodes, string); +} + +void SetupMinUsedLeaves(char *string) +{ + SetupArrayFromString("Old leaf containment requirements:", + "New leaf usage requrements:", MinUsedLeaves, + InitializeMinUsedLeaves, string); +} + +void SetupLeafPinout(char *string) +{ + int i; + + LeafPins = atoi(string); + if (LeafPins == 0) LeafPins = LEAFPINS; + InitializeFanout(); + Printf("New Fanout:\n"); + for (i = 1; i <= MAX_TREE_DEPTH; i++) + Printf(" %d", TreeFanout[i]); + Printf("\n"); +} + +void SetupRentExp(char *string) +{ + int i; + + RentExp = atof(string); + InitializeFanout(); + Printf("New Fanout:\n"); + for (i = 1; i <= MAX_TREE_DEPTH; i++) + Printf(" %d", TreeFanout[i]); + Printf("\n"); +} + + +void ToggleLogging(void) +{ + logging = !logging; + if (logging) Printf("Log file (%s) will be generated\n",LOG_FILE_EXT); + else Printf("No log file will be written.\n"); +} + +void ToggleExhaustive(void) +{ + Exhaustive = !Exhaustive; + if (Exhaustive) Printf("Exhaustive element consideration enabled.\n"); + else Printf("Accelerating heuristics enabled.\n"); +} + +void ToggleDebug(void) +{ + PlaceDebug = !PlaceDebug; + if (PlaceDebug) Printf("Verbose output will be generated.\n"); + else Printf("Silent output.\n"); +} + +void DescribeCell(char *name, int detail) +{ + Printf("Cell: %s contains %d instances, %d nodes and %d ports\n", name, + NumberOfInstances(name), RenumberNodes(name), NumberOfPorts(name)); + PrintEmbeddingTree(stdout,name,detail); +} + +void ProtoEmbed(char *name, char ch) +{ + enum EmbeddingStrategy strategy; + + strategy = greedy; + if (toupper(ch) == 'A') strategy = anneal; + if (toupper(ch) == 'G') strategy = greedy; + if (toupper(ch) == 'O') strategy = bottomup; + if (toupper(ch) == 'R') strategy = random_embedding; + if (LookupCell(name) == NULL) + Fprintf(stderr,"No cell '%s' found.\n",name); + else { + if (islower(ch)) DoEmbed(name, strategy); + else TopDownEmbedCell(name,NULL,strategy); + } +} + +void ProtoPrintParameters(void) +{ + Printf("PROTOCHIP embedder compiled with:\n"); + Printf("MAX_LEAVES = %d; (MAX_TREE_DEPTH = %d)\n", + MAX_LEAVES, MAX_TREE_DEPTH); + Printf("MAX_ELEMENTS = %d, MAX_NODES = %d\n", + MAX_ELEMENTS, MAX_NODES); +} + +void PROTOCHIP(void) +/* a simple command interpreter to manage embedding/routing */ +{ + char name[100]; + char ch; + + InitializeFanout(); + InitializeMinCommonNodes(); + InitializeMinUsedLeaves(); + setjmp(jmpenv); + signal(SIGINT,handler); + do { + promptstring("PROTOCHIP command: ", name); + ch = name[0]; + + switch (ch) { + case 'p': + ProtoPrintParameters(); + break; + case 'l': + ToggleLogging(); + break; + case 'L': + promptstring("Log if level1 == ",name); + LogLevel1 = atoi(name); + promptstring("Log if level2 == ",name); + LogLevel2 = atoi(name); + selectivelogging = ((LogLevel1 != -1) || (LogLevel2 != -1)); + if (selectivelogging) logging = 1; + break; + case 'x': + ToggleExhaustive(); + break; + case 'V': + ToggleDebug(); + break; + case '#': + if (strlen(name) > 1) { + char *command; + command = name+1; + DBUG_PUSH(command); + } + else { + promptstring("Dbug command? ",name); + DBUG_PUSH(name); + } + break; + case 'd': + case 'D': + promptstring("Describe cell: ", name); + if (LookupCell(name) == NULL) + Fprintf(stderr,"No cell '%s' found.\n",name); + else DescribeCell(name,(ch == 'd')); + break; + + /* different embedding strategies -- see enum EmbeddingStrategy above */ + case 'e': + case 'E': + promptstring("Cell to embed: ", name); + if (LookupCell(name) == NULL) + Fprintf(stderr,"No cell '%s' found.\n",name); + else + Embed(name); + break; +#if 0 + case 'r': + case 'R': + promptstring("Cell to embed: ", name); + if (LookupCell(name) == NULL) + Fprintf(stderr,"No cell '%s' found.\n",name); + else { + if (ch == 'e') DoEmbed(name, random_embedding); + else TopDownEmbedCell(name,NULL, random_embedding); + } + break; + case 'o': + case 'O': + promptstring("Cell to embed: ", name); + if (LookupCell(name) == NULL) + Fprintf(stderr,"No cell '%s' found.\n",name); + else { + if (ch == 'o') DoEmbed(name, bottomup); + else EmbedCell(name,NULL); + } + break; + case 'G': + case 'g': + promptstring("Cell to embed: ", name); + if (LookupCell(name) == NULL) + Fprintf(stderr,"No cell '%s' found.\n",name); + else { + if (ch == 'g') DoEmbed(name, greedy); + else TopDownEmbedCell(name,NULL, greedy); + } + break; + case 'A': + case 'a': + promptstring("Cell to embed: ", name); + if (LookupCell(name) == NULL) + Fprintf(stderr,"No cell '%s' found.\n",name); + else { + if (ch == 'a') DoEmbed(name, anneal); + else TopDownEmbedCell(name,NULL, anneal); + } + break; +#else + case 'r': + case 'R': + case 'o': + case 'O': + case 'G': + case 'g': + case 'A': + case 'a': + promptstring("Cell to embed: ", name); + ProtoEmbed(name, ch); + break; +#endif + + case 's': + promptstring("Cell to count sub-graphs: ",name); + CountSubGraphs(name); + break; + case 'h': PrintCellHashTable(0, -1); break; + case 'H': PrintCellHashTable(1, -1); break; + case 'F': + promptstring("Enter leaf pinout: ",name); + LeafPins = atoi(name); + if (LeafPins == 0) LeafPins = 10; + Printf("New Fanout:\n"); + { + int i; + for (i = 1; i <= MAX_TREE_DEPTH; i++) + Printf(" %d", TreeFanout[i]); + } + Printf("\n"); + break; + case 'X': + promptstring("Enter Rent's Rule exponent: ",name); + RentExp = atof(name); + InitializeFanout(); + Printf("New Fanout:\n"); + { + int i; + for (i = 1; i <= MAX_TREE_DEPTH; i++) + Printf(" %d", TreeFanout[i]); + } + Printf("\n"); + break; +#if 1 + case 'f': + SetupArray("Fanout is currently:", + "Fanout for level %d (0 to quit): ", + "New fanout: ", TreeFanout, InitializeFanout); + break; + case 'c': + SetupArray("Common node requrements are currently:", + "Common nodes for level %d (0 to quit): ", + "New common node requrements:", MinCommonNodes, + InitializeMinCommonNodes); + break; + case 'C': + SetupArray("Leaf containment requirements are currently:", + "Used leaves for level %d (0 to quit): ", + "New leaf usage requrements:", MinUsedLeaves, + InitializeMinUsedLeaves); + break; + +#else + case 'f': + Printf("Fanout is currently:"); + for (i = 1; i <= MAX_TREE_DEPTH; i++) + Printf(" %d", TreeFanout[i]); + Printf("\n"); + + oldfanout = 1; + for (i = 1; i <= MAX_TREE_DEPTH; i++) { + char prompt[100]; + int newfanout; + sprintf(prompt,"Fanout for level %d (0 to quit): ",i); + promptstring(prompt, name); + newfanout = atoi(name); + if (i == 1 && newfanout == 0) { + InitializeFanout(); /* reset to original */ + i = MAX_TREE_DEPTH; + } + else { + if (newfanout == 0) /* fill out TreeFanout */ + for (; i <= MAX_TREE_DEPTH; i++) + TreeFanout[i] = oldfanout; + else { + TreeFanout[i] = newfanout; + oldfanout = newfanout; + } + } + } + Printf("New fanout:"); + for (i = 1; i <= MAX_TREE_DEPTH; i++) + Printf(" %d", TreeFanout[i]); + Printf("\n"); + break; + case 'c': + Printf("Common node requrements are currently:"); + for (i = 1; i <= MAX_TREE_DEPTH; i++) + Printf(" %d", MinCommonNodes[i]); + Printf("\n"); + + oldfanout = 1; + for (i = 1; i <= MAX_TREE_DEPTH; i++) { + char prompt[100]; + int newfanout; + sprintf(prompt,"Common nodes for level %d (0 to quit): ",i); + promptstring(prompt, name); + newfanout = atoi(name); + if (i == 1 && newfanout == 0) { + InitializeMinCommonNodes(); /* reset to original */ + i = MAX_TREE_DEPTH; + } + else { + if (newfanout == 0) /* fill out MinCommonNodes */ + for (; i <= MAX_TREE_DEPTH; i++) + MinCommonNodes[i] = oldfanout; + else { + MinCommonNodes[i] = newfanout; + oldfanout = newfanout; + } + } + } + Printf("New common node requrements:"); + for (i = 1; i <= MAX_TREE_DEPTH; i++) + Printf(" %d", MinCommonNodes[i]); + Printf("\n"); + break; + case 'C': + Printf("Leaf containment requirements are currently:"); + for (i = 1; i <= MAX_TREE_DEPTH; i++) + Printf(" %d", MinUsedLeaves[i]); + Printf("\n"); + + oldfanout = 1; + for (i = 1; i <= MAX_TREE_DEPTH; i++) { + char prompt[100]; + int newfanout; + sprintf(prompt,"Used leaves for level %d (0 to quit): ",i); + promptstring(prompt, name); + newfanout = atoi(name); + if (i == 1 && newfanout == 0) { + InitializeMinUsedLeaves(); /* reset to original */ + i = MAX_TREE_DEPTH; + } + else { + if (newfanout == 0) /* fill out MinCommonNodes */ + for (; i <= MAX_TREE_DEPTH; i++) + MinUsedLeaves[i] = oldfanout; + else { + MinUsedLeaves[i] = newfanout; + oldfanout = newfanout; + } + } + } + Printf("New leaf usage requrements:"); + for (i = 1; i <= MAX_TREE_DEPTH; i++) + Printf(" %d", MinUsedLeaves[i]); + Printf("\n"); + break; +#endif + case '!': +#ifdef IBMPC + system(""); +#else + system("/bin/csh"); +#endif + break; + case 'q': break; + case 'Q' : exit(0); + default: + Printf("Embed: (e)mbed (E); (o)ld embed (O); e(x)haustive old embed\n"); + Printf(" (r)andom cut embedding algorithm\n"); + Printf(" (g)reedy embedding algorithm, simulated (a)nnealing\n"); + Printf("Embed parameters: (f)anout, (c)ommon nodes, leaf (C)ontainment.\n"); + Printf(" Leaf (F)anout, Rent's rule e(X)ponent\n"); + Printf("(d)escribe cell; print (h)ash table (H); toggle primiti(v)e bit\n"); + Printf("count (s)ub-graphs, (p)rint embedding constants\n"); + Printf("toggle (l)ogging (L = single level); toggle (V)erbose output\n"); + Printf("(q)uit; (Q)uit immediately; (!) push shell, (#) set dbug\n"); + break; + } + } while (ch != 'q'); + signal(SIGINT,SIG_DFL); +} diff --git a/base/print.c b/base/print.c new file mode 100644 index 0000000..cf6b80c --- /dev/null +++ b/base/print.c @@ -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 +#include /* what about varargs support, as in pdutils.h ??? */ +#include + +#ifdef TCL_NETGEN +#include + +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)); +} + + + + diff --git a/base/print.h b/base/print.h new file mode 100644 index 0000000..25b6291 --- /dev/null +++ b/base/print.h @@ -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; diff --git a/base/proto.h b/base/proto.h new file mode 100644 index 0000000..b16dfc8 --- /dev/null +++ b/base/proto.h @@ -0,0 +1,65 @@ +/* define prototypes for printf, etc. */ + +#ifndef FILE +#include +#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 */ + diff --git a/base/query.c b/base/query.c new file mode 100644 index 0000000..78e5786 --- /dev/null +++ b/base/query.c @@ -0,0 +1,1171 @@ +/* "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. */ + +/* query.c -- simple command-line interpreter */ + +#include "config.h" + +#include +#include +#include +#include + +#ifdef HAVE_MALLINFO +#include +#endif + +#ifdef IBMPC +#include +#include /* for system() */ +#include /* for bioskey() */ +#endif + +#include "netgen.h" +#include "timing.h" +#include "hash.h" +#include "objlist.h" +#include "query.h" +#include "netfile.h" +#include "print.h" +#include "dbug.h" +#include "netcmp.h" + +/*************************************************************************/ +/* */ +/* I/O support for Query() routine */ +/* */ +/*************************************************************************/ + +static int SuppressPrompts = 0; +static char InputLine[200]; + +void typeahead(char *str) +{ + if (strlen(str) + strlen(InputLine) + 3 < sizeof(InputLine)) { + strcat(InputLine," "); + strcat(InputLine,str); + } + else fprintf(stderr, "InputLine too long: ignored command '%s'\n",str); +} + +/* change the following to redirect the input stream */ +FILE *promptstring_infile = NULL; + +void promptstring(char *prompt, char *buf) +/* tries to get a token out of 'line' variable, +but reads from 'promptstring_infile' if nec. */ +/* copy it to buffer, when found */ +/* If interactive, puts out 'prompt' */ +{ + char *nexttok; + char tmpstr[200]; + int echo; + + if (promptstring_infile == NULL) + promptstring_infile = stdin; + + if (!SuppressPrompts) { + Printf("%s",prompt); + Fflush(stdout); + } + echo = 1; /* assume we got it from typeahead */ + nexttok = InputLine; + while (isspace(*nexttok) && *nexttok != '\0') nexttok++; + if (*nexttok == '\0') { + fgets(InputLine, sizeof(InputLine), promptstring_infile); + if (promptstring_infile == stdin) echo = 0; + nexttok = InputLine; + while (isspace(*nexttok) && *nexttok != '\0') nexttok++; + if (*nexttok == '\0') { + *buf = '\0'; + return; + } + } + /* nexttok points to beginning of valid token */ + strcpy(tmpstr,nexttok); + nexttok = tmpstr; + while (*nexttok != '\0' && !isspace(*nexttok)) nexttok++; + strcpy(InputLine, nexttok); + *nexttok = '\0'; + strcpy(buf, tmpstr); + if (echo && !SuppressPrompts) Printf("%s\n",buf); +} + + +void InitializeCommandLine(int argc, char **argv) +{ + /* neither of the two Inits below are strictly necessary, */ + /* as static objects are initialized to 0 (NULL) automatically */ + + InitCellHashTable(); + InitGarbageCollection(); + + RemoveCompareQueue(); + +#ifdef TCL_NETGEN + return; + +#else + if (argv == NULL) return; /* Don't run Query() */ + + /* initialize command-line parser, including dbug code */ + DBUG_PROCESS(argv[0]); + if (argc > 1) { + int start; + int usekbd, forceinteractive; + usekbd = 1; /* assume we are interactive */ + forceinteractive = 0; /* try to figure it out from cmd line */ + + /* quiet prompting if program name is not netgen */ + SuppressPrompts = (strstr(argv[0], "netgen") == NULL); + + for (start = 1; start < argc; start++) { + if (argv[start][0] == '-') { + switch (argv[start][1]) { + case '#': DBUG_PUSH(&(argv[start][2])); + break; + case '\0': forceinteractive = 1; + break; + default: Fprintf(stderr,"Unrecognized switch: %s\n",argv[start]); + break; + } + } + else { + typeahead(argv[start]); + usekbd = 0; + } + } + if (!usekbd && !forceinteractive) typeahead("Q"); /* exit when done */ + } + + /* permit command-line typeahead even for X-windows */ + if (getenv("DISPLAY")) { + int oldSuppressPrompts = SuppressPrompts; + SuppressPrompts = 1; + typeahead("q"); /* get out of one level of query */ + Query(); + SuppressPrompts = oldSuppressPrompts; + } + +#endif /* TCL_NETGEN */ +} + +void Initialize(void) +{ +#ifdef HAVE_MALLINFO + char *wasted; + + wasted = (char *)MALLOC(2); /* need to initialize memory allocator */ +#endif + + InitializeCommandLine(0, NULL); +} + + +/* Print the type of object (mostly diagnostic) */ + +void PrintObjectType(int type) +{ + switch(type) { + case UNIQUEGLOBAL: + Printf("Unique Global"); + break; + case GLOBAL: + Printf("Global"); + break; + case PORT: + Printf("Port"); + break; + case PROPERTY: + Printf("Properties"); + break; + case NODE: + Printf("Net"); + break; + default: + if (type < 0) + Printf("Error!"); + else + Printf("Pin %d", type); + break; + } +} + + + +/*************************************************************************/ +/* */ +/* Some convenient routines for printing internal data structures */ +/* */ +/*************************************************************************/ + +#ifndef TCL_NETGEN + +/*--------------------------------------------------------------*/ +/* generate and print a list of elements that match a regexp */ +/*--------------------------------------------------------------*/ + +void PrintElement(char *cell, char *list_template) +{ + + struct objlist *list; + + if (strlen(cell)) CurrentCell = LookupCell(cell); + list = List(list_template); + Printf("Devices matching template: %s\n",list_template); + while (list != NULL) { + Printf (" %s\n",list->name); + list = list->next; + } +} + +#else + +/*--------------------------------------------------------------*/ +/* PrintElement() for use with Tcl---return all elements, */ +/* let Tcl sort them out. */ +/*--------------------------------------------------------------*/ + +void PrintAllElements(char *cell, int filenum) +{ + struct nlist *np; + struct objlist *ob; + char *sfx; + + if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + PrintAllElements(cell, Circuit1->file); + PrintAllElements(cell, Circuit2->file); + return; + } + + if (((cell == NULL) || (*cell == '\0')) && (CurrentCell != NULL)) + np = CurrentCell; + else + np = LookupCellFile(cell, filenum); + + if (np == NULL) { + Printf("Circuit '%s' not found.\n",cell); + return; + } + + ob = np->cell; + for (ob = np->cell; ob != NULL; ob = ob->next) { + if (ob->type == FIRSTPIN) { + if ((sfx = strrchr(ob->name, '/')) != NULL) *sfx = '\0'; + Printf("%s\n", ob->name); + if (sfx != NULL) *sfx = '/'; + } + } +} + +#endif + +/*--------------------------------------------------------------*/ +/* Print connectivity between objects belonging to a specific */ +/* node. 'filter' may be used to restrict the returned list to */ +/* a specific type of object (node, element, port, pin, etc.). */ +/*--------------------------------------------------------------*/ + +void Fanout(char *cell, char *node, int filter) +{ + struct nlist *np; + struct objlist *ob; + int nodenum; + + if (*cell == '\0') np = CurrentCell; + else np = LookupCell(cell); + + if (np == NULL) { + Printf("Cell '%s' not found.\n",cell); + return; + } + + nodenum = -999; + for (ob = np->cell; ob != NULL; ob = ob->next) { + if ((*matchfunc)(node, ob->name)) { + nodenum = ob->node; + break; + } + } + + /* now print out all elements that connect to that node */ + + if (nodenum == -999) + Printf("Net '%s' not found in circuit '%s'.\n", node, cell); + else if (nodenum < 0) + Printf("Net '%s' is disconnected.\n", node); + else { + if (ob != NULL) + PrintObjectType(ob->type); + else + Printf("Object"); + Printf (" '%s' in circuit '%s' connects to:\n", node, cell); + ob = np->cell; + while (ob != NULL) { + char *obname = ob->name; + if (*obname == '/') obname++; + if (ob->node == nodenum) + if (filter == ALLOBJECTS) { + Printf(" %s (", obname); + PrintObjectType(ob->type); + Printf(")\n"); + } + else if ((filter == ALLELEMENTS) && (ob->type >= FIRSTPIN)) { + Printf(" %s\n", obname); + } + else if (ob->type == filter) { + Printf(" %s\n", obname); + } + ob = ob->next; + } + } +} + +#ifdef TCL_NETGEN + +/* Print the nodes connected to each pin of the specified element */ + +void ElementNodes(char *cell, char *element, int fnum) +{ + struct nlist *np; + struct objlist *ob, *nob, *nob2; + int ckto; + char *elementname; + + if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + ElementNodes(cell, element, Circuit1->file); + ElementNodes(cell, element, Circuit2->file); + return; + } + + if (((cell == NULL) || (*cell == '\0')) && (CurrentCell != NULL)) + np = CurrentCell; + else + np = LookupCellFile(cell, fnum); + + if (np == NULL) { + Printf("Circuit '%s' not found.\n",cell); + return; + } + + elementname = element; + if (*elementname == '/') elementname++; + + ckto = strlen(elementname); + for (ob = np->cell; ob != NULL; ob = ob->next) { + if (!strncmp(elementname, ob->name, ckto)) + if (*(ob->name + ckto) == '/' || *(ob->name + ckto) == '\0') + break; + } + if (ob == NULL) { + Printf("Device '%s' not found in circuit '%s'.\n", elementname, cell); + return; + } + + Printf("Device '%s' Pins:\n", elementname); + for (; ob != NULL; ob = ob->next) { + if (!strncmp(elementname, ob->name, ckto)) { + if (*(ob->name + ckto) != '/' && *(ob->name + ckto) != '\0') + continue; + + Printf(" "); + PrintObjectType(ob->type); + Printf(" (%s)", ob->name + ckto + 1); + for (nob = np->cell; nob != NULL; nob = nob->next) { + if (nob->node == ob->node) { + if (nob->type == NODE) { + Printf(" = %s", nob->name); + break; + } + else if (nob->type == PORT) { + Printf(" = %s (port of %s)", nob->name, cell); + break; + } + else if (nob->type == GLOBAL) { + Printf(" = %s (global)", nob->name); + break; + } + else if (nob->type == UNIQUEGLOBAL) { + Printf(" = %s (unique global)", nob->name); + break; + } + } + } + Printf("\n"); + } + } +} + +#endif /* TCL_NETGEN */ + +/*----------------------------------------------------------------------*/ +/* Find all nodes by name or wildcard pattern match, in the scope of */ +/* the cell "cellname", and change them to the type given by "type". */ +/* Changes are only allowed among nodes of type NODE, GLOBAL or */ +/* UNIQUEGLOBAL. */ +/*----------------------------------------------------------------------*/ + +int ChangeScopeCurrent(char *pattern, int typefrom, int typeto) +{ + /* Note that List() is supposed to operate on CurrentCell */ + /* but we want to be able to change scope on any cell. */ + + struct objlist *plist, *psrch; + struct nlist *tp; + int numchanged = 0; + + plist = List(pattern); + while (plist != NULL) { + if (plist->type == typefrom) { + for (psrch = CurrentCell->cell; psrch != NULL; psrch = psrch->next) { + if (psrch->type == typefrom && (*matchfunc)(psrch->name, plist->name)) { + psrch->type = typeto; + Printf("Cell %s: Net %s changed to %s\n", + CurrentCell->name, psrch->name, psrch->type == NODE ? + "local" : psrch->type == GLOBAL ? "global" : + psrch->type == UNIQUEGLOBAL ? "unique global" : "unknown"); + numchanged++; + } + } + } + plist = plist->next; + } + + /* Recursively search descendants, if they exist */ + + if (CurrentCell != NULL) { + for (psrch = CurrentCell->cell; psrch != NULL; psrch = psrch->next) { + if (psrch->type == FIRSTPIN) { + numchanged += ChangeScope(CurrentCell->file, psrch->model.class, + pattern, typefrom, typeto); + } + } + } + + return numchanged; +} + +/* Structure to pass information to doglobalscope() */ + +typedef struct _gsd { + int fnum; + char *pattern; + int typefrom; + int typeto; + int *numchanged; +} gsdata; + +/*----------------------------------------------------------------------*/ +/* Function called by hash search on cells, to call ChangeScopeCurrent */ +/*----------------------------------------------------------------------*/ + +struct nlist *doglobalscope(struct hashlist *p, void *clientdata) +{ + struct nlist *ptr; + struct objlist *ob, *lob, *nob; + int file, numchanged; + gsdata *gsd = (gsdata *)clientdata; + + ptr = (struct nlist *)(p->ptr); + file = gsd->fnum; + + if ((file != -1) && (ptr->file != file)) return NULL; + + CurrentCell = ptr; + numchanged = ChangeScopeCurrent(gsd->pattern, gsd->typefrom, gsd->typeto); + *(gsd->numchanged) += numchanged; + + return ptr; +} + +/*----------------------------------------------------------------------*/ +/* Wrapper for ChangeScopeCurrent(). Takes a cellname as an */ +/* argument, instead of assuming the existance of a valid CurrentCell */ +/*----------------------------------------------------------------------*/ + +int ChangeScope(int fnum, char *cellname, char *pattern, int typefrom, int typeto) +{ + struct nlist *SaveCell, *tp; + int numchanged = 0; + + if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + numchanged += ChangeScope(Circuit1->file, cellname, + pattern, typefrom, typeto); + numchanged += ChangeScope(Circuit2->file, cellname, + pattern, typefrom, typeto); + return numchanged; + } + + SaveCell = CurrentCell; + + if (cellname == NULL) { + /* No cellname given, so search all cells in file fnum */ + gsdata locdata; + + locdata.fnum = fnum; + locdata.pattern = pattern; + locdata.typefrom = typefrom; + locdata.typeto = typeto; + locdata.numchanged = &numchanged; + + RecurseCellHashTable2(doglobalscope, (void *)(&locdata)); + } + else { + + CurrentCell = LookupCellFile(cellname, fnum); + if (CurrentCell != NULL) { + numchanged = ChangeScopeCurrent(pattern, typefrom, typeto); + } + else { + Printf("No circuit '%s' found.\n", cellname); + } + } + CurrentCell = SaveCell; + return numchanged; +} + +/*--------------------------------------------------------------------*/ +/* print all nodes in cell 'name', together with their connectivities */ +/*--------------------------------------------------------------------*/ + +typedef struct _noderecord { + char *name; /* node name */ + int uniqueglobal, global, port, node, pin; /* counts */ +} noderecord; + +void PrintNodes(char *name, int filenum) +{ + int nodenum, nodemax; + struct nlist *tp; + struct objlist *ob; + int maxnamelen; + noderecord *nodelist; + int uniqueglobals, globals, ports, nodes, pins; + + if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + PrintNodes(name, Circuit1->file); + PrintNodes(name, Circuit2->file); + return; + } + + tp = LookupCellFile(name, filenum); + + if (tp == NULL) { + Printf ("No circuit '%s' found.\n",name); + return; + } + Printf("Circuit: '%s'\n",tp->name); + + nodemax = 0; + maxnamelen = 0; + for (ob = tp->cell; ob != NULL; ob = ob->next) { + int len = strlen(NodeAlias(tp, ob)); + if (len > maxnamelen) maxnamelen = len; + if (ob->node > nodemax) nodemax = ob->node; + } + nodelist = (noderecord *) CALLOC((nodemax + 1), sizeof(noderecord)); + + for (ob = tp->cell; ob != NULL; ob = ob->next) { + nodenum = ob->node; + if (nodenum < 0) continue; + /* repeat bits of objlist.c here for speed */ + if (tp->nodename_cache != NULL) { + nodelist[nodenum].name = tp->nodename_cache[nodenum]->name; + } + else { + /* Overwrite name, in order of precedence */ + if ((nodelist[nodenum].port == 0) && + ((IsPort(ob)) || + ((nodelist[nodenum].node == 0) && + ((ob->type == NODE) || + ((nodelist[nodenum].uniqueglobal == 0) && + ((ob->type == UNIQUEGLOBAL) || + ((nodelist[nodenum].global == 0) && + ((ob->type == GLOBAL) || + ((nodelist[nodenum].pin == 0) && + (ob->type >= FIRSTPIN)))))))))) + nodelist[nodenum].name = ob->name; + + } + switch (ob->type) { + case UNIQUEGLOBAL: + nodelist[nodenum].uniqueglobal++; break; + case GLOBAL: + nodelist[nodenum].global++; break; + case PORT: + nodelist[nodenum].port++; break; + case NODE: + nodelist[nodenum].node++; break; + case PROPERTY: + break; + default: + nodelist[nodenum].pin++; break; + } + } + + for (nodenum = 0; nodenum <= nodemax; nodenum++) { + if (nodelist[nodenum].name == NULL) continue; + + pins = nodelist[nodenum].pin; + ports = nodelist[nodenum].port; + globals = nodelist[nodenum].global; + uniqueglobals = nodelist[nodenum].uniqueglobal; + nodes = nodelist[nodenum].node; + + Printf("Net %d (%s):", nodenum, nodelist[nodenum].name); + Ftab(NULL, maxnamelen + 15); + Printf("Total = %d,", pins + ports + nodes + globals + uniqueglobals); + if (ports) + Printf(" Ports = %d,", ports); + Ftab(NULL, maxnamelen + 40); + if (pins) + Printf("Pins = %d,", pins); + Ftab(NULL, maxnamelen + 52); + if (nodes) + Printf("Nets = %d,", nodes); + Ftab(NULL, maxnamelen + 63); + if (globals) + Printf("Globals = %d,", globals); + Ftab(NULL, maxnamelen + 80); + if (uniqueglobals) + Printf("UniqueGlobals = %d", uniqueglobals); + Printf("\n"); + } + + FREE(nodelist); +} + +void PrintCell(char *name, int fnum) +{ + struct nlist *tp; + struct objlist *ob; + int maxnamelen; + + if ((fnum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + PrintCell(name, Circuit1->file); + PrintCell(name, Circuit2->file); + return; + } + + tp = LookupCellFile(name, fnum); + if (tp == NULL) { + Printf ("No circuit '%s' found.\n",name); + return; + } + maxnamelen = 0; + for (ob = tp->cell; ob != NULL; ob = ob->next) { + int len; + if ((len = strlen(ob->name)) > maxnamelen) maxnamelen = len; + } + + Printf("Circuit: '%s'\n", tp->name); + for (ob = tp->cell; ob != NULL; ob = ob->next) { + Printf ("%s ", ob->name[1] == ':' ? ob->name : ob->name); + Ftab(NULL, maxnamelen + 2); + switch (ob->type) { + case UNIQUEGLOBAL: + Printf("unique global"); break; + case GLOBAL: + Printf("global"); break; + case PORT: + Printf("port"); break; + case NODE: + Printf("node"); break; + case PROPERTY: + Printf("properties"); break; + default: + Printf("pin %d", ob->type); + break; + } + Ftab(NULL, 40); + if (ob->type != PROPERTY) + Printf(" Net #: %d", ob->node); + Printf("\n"); + } +} + +void PrintInstances(char *name, int filenum) +{ + struct nlist *tp; + struct objlist *ob; + int instancecount; + + if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + PrintInstances(name, Circuit1->file); + PrintInstances(name, Circuit2->file); + return; + } + + tp = LookupCellFile(name, filenum); + if (tp == NULL) { + Printf ("No circuit '%s' found.\n",name); + return; + } + Printf("Circuit: '%s'\n",tp->name); + instancecount = 0; + for (ob = tp->cell; ob != NULL; ob = ob->next) { + if (ob->type == FIRSTPIN) { + struct objlist *ob2; + int port, node, global, uniqueglobal, pin; + int ports, nodes, globals, uniqueglobals, pins; + + port = node = global = uniqueglobal = pin = 0; + instancecount++; + + ob2 = ob; + do { + struct objlist *ob3; + + ports = nodes = globals = uniqueglobals = pins = 0; + for (ob3 = tp->cell; ob3 != NULL; ob3 = ob3->next) + if (ob3->node == ob2->node) + switch (ob3->type) { + case UNIQUEGLOBAL: uniqueglobals++; break; + case GLOBAL: globals++; break; + case PORT: ports++; break; + case NODE: nodes++; break; + case PROPERTY: break; + default: pins++; break; + } + pin++; + if (uniqueglobals) uniqueglobal++; + else if (globals) global++; + else if (ports) port++; + else if (nodes) node++; + ob2 = ob2->next; + } while (ob2 != NULL && ob2->type > FIRSTPIN); +/* Fflush(stdout); */ + Printf("%s (class: %s)", ob->instance, ob->model.class); + Ftab(NULL,35); + Printf("%2d pins ->",pin); + if (port) Printf("%2d ports,",port); + Ftab(NULL,55); + if (node) Printf("%2d nodes,",node); + Ftab(NULL,65); + if (global) Printf("%2d globals,",global); + Ftab(NULL,75); + if (uniqueglobal) Printf("%2d ug",uniqueglobal); + Printf("\n"); + } + } + Printf("Cell %s contains %d instances.\n",name,instancecount); +} + +void DescribeInstance(char *name, int file) +{ + struct nlist *tp, *tp2; + struct objlist *ob; + unsigned char *instlist; + int nodemax, nodenum; + + int instancecount; + int node, nodenumber, morenodes, disconnectednodes; + + if ((file == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + DescribeInstance(name, Circuit1->file); + DescribeInstance(name, Circuit2->file); + return; + } + + tp = LookupCellFile(name, file); + + if (tp == NULL) { + Printf("No circuit '%s' found.\n",name); + return; + } + Printf("Circuit: '%s'\n",tp->name); + + /* First pass counts total number of entries */ + nodemax = 0; + disconnectednodes = 0; + for (ob = tp->cell; ob != NULL; ob = ob->next) + { + if (ob->node > nodemax) nodemax = ob->node; + else if ((ob->node == -1) && (ob->model.port != PROXY)) { + disconnectednodes++; + Fprintf(stderr, " disconnected node: %s\n", ob->name); + } + } + instlist = (unsigned char *) CALLOC((nodemax + 1), sizeof(unsigned char)); + + /* Second pass finds total number of unique nodes */ + for (ob = tp->cell; ob != NULL; ob = ob->next) + if (ob->node > 0) + instlist[ob->node] = (unsigned char) 1; + + /* Now add them all together */ + nodenumber = 0; + for (nodenum = 1; nodenum <= nodemax; nodenum++) + if (instlist[nodenum] == (unsigned char) 1) nodenumber++; + + /* And we're done with this record */ + FREE(instlist); + + /* Now collect the relevant information per node */ + + ClearDumpedList(); + + instancecount = 0; + for (ob = tp->cell; ob != NULL; ob = ob->next) { + if (ob->type == FIRSTPIN) { + instancecount++; + tp2 = LookupCellFile(ob->model.class, tp->file); + tp2->dumped++; + } + } + Printf("Circuit %s contains %d device instances.\n", name, instancecount); + + /* print out results */ + tp = FirstCell(); + while (tp != NULL) { + if (tp->dumped) { + Printf(" Class: %s", tp->name); + Ftab(NULL, 30); + Printf(" instances: %3d\n", tp->dumped); + } + tp = NextCell(); + } + Printf("Circuit contains %d nets", nodenumber); + if (disconnectednodes) + Printf(", and %d disconnected pin%s", disconnectednodes, + ((disconnectednodes == 1) ? "" : "s")); + Printf(".\n"); + +} + +void PrintPortsInCell(char *cellname, int filenum) +{ + struct nlist *np; + struct objlist *ob; + int portcount; + + if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + PrintPortsInCell(cellname, Circuit1->file); + PrintPortsInCell(cellname, Circuit2->file); + return; + } + + np = LookupCellFile(cellname, filenum); + if (np == NULL) { + Printf("No circuit: %s\n",cellname); + return; + } + portcount = 0; + for (ob = np->cell; ob != NULL; ob = ob->next) + if (IsPort(ob)) { + portcount++; + Printf("%s\n", ob->name); + } + Printf("Cell %s contains %d ports.\n",cellname, portcount); +} + +void PrintLeavesInCell(char *cellname, int filenum) +{ + struct nlist *np; + struct objlist *ob; + int am_a_leaf; + + if ((filenum == -1) && (Circuit1 != NULL) && (Circuit2 != NULL)) { + PrintLeavesInCell(cellname, Circuit1->file); + PrintLeavesInCell(cellname, Circuit2->file); + return; + } + + np = LookupCellFile(cellname, filenum); + if (np == NULL) { + Printf("No circuit: %s\n",cellname); + return; + } + if (np->dumped) return; + np->dumped = 1; + + if (np->class != CLASS_SUBCKT) { + Printf("%s; %d ports; Primitive.\n", cellname, NumberOfPorts(cellname)); + return; + } + + /* otherwise, consider it's children */ + am_a_leaf = 1; /* assume I am a leaf */ + for (ob = np->cell; ob != NULL; ob = ob->next) + if (ob->type == FIRSTPIN) { + /* if I contain an instance, I cannot be a leaf */ + PrintLeavesInCell(ob->model.class, filenum); + am_a_leaf = 0; + } + + if (am_a_leaf) Printf("%s; %d ports\n", cellname, NumberOfPorts(cellname)); + return; +} + +static int PrintLeavesInCellHash(struct hashlist *p) +/* print leaves in hash table that are INSTANCED by other cells */ +{ + struct nlist *ptr; + + ptr = (struct nlist *)(p->ptr); + if ((ptr->class == CLASS_SUBCKT)) PrintLeavesInCell(ptr->name, ptr->file); + return(0); +} + +void PrintAllLeaves(void) +{ + ClearDumpedList(); + RecurseCellHashTable(PrintLeavesInCellHash); +} + +static jmp_buf jmpenv; + +/* static void handler(void) */ +static void handler(int sig) +{ + fprintf(stderr,"\nInterrupt (%d)!!\n", sig); + fflush(stderr); + longjmp(jmpenv,1); +} + +#ifndef TCL_NETGEN + +void Query(void) +{ + /* little interactive debugger */ + char reply; + char repstr[100]; + char repstr2[100]; + float StartTime; /* for elapsed CPU times */ + int Timing; /* if true, print times of each command */ + + if (!SuppressPrompts) + Printf("Netgen %s.%s: %s, %s, %s\n", NETGEN_VERSION, NETGEN_REVISION, + NETGEN_COPYRIGHT, NETGEN_AUTHOR, NETGEN_DEVELOPER); + setjmp(jmpenv); + signal(SIGINT,handler); + Timing = 0; + StartTime = 0.0; + do { + promptstring("NETGEN command: ",repstr); + if (Timing) StartTime = CPUTime(); + reply = repstr[0]; + switch (reply) { + case 'h' : PrintCellHashTable(0, -1); break; + case 'H' : PrintCellHashTable(1, -1); break; + case 'N' : + promptstring("Enter circuit name: ", repstr); + PrintNodes(repstr, -1); + break; + case 'n' : + promptstring("Enter element name: ", repstr); + if (CurrentCell == NULL) + promptstring("Enter circuit name: ", repstr2); + else strcpy(repstr2, CurrentCell->name); + Fanout(repstr2, repstr, ALLOBJECTS); + break; + case 'e' : + promptstring("Enter element name: ", repstr); + if (CurrentCell == NULL) + promptstring("Enter circuit name: ", repstr2); + else strcpy(repstr2, CurrentCell->name); + PrintElement(repstr2,repstr); + break; + case 'c' : + promptstring("Enter circuit name: ", repstr); + PrintCell(repstr); + break; + case 'i' : + promptstring("Enter circuit name: ", repstr); + PrintInstances(repstr, -1); + break; + case 'd': + promptstring("Enter circuit name: ", repstr); + DescribeInstance(repstr, -1); + break; +/* output file formats */ + case 'k' : + promptstring("Write NTK: Enter circuit name: ", repstr); + Ntk(repstr,""); + break; + case 'x' : + promptstring("Write EXT: Enter circuit name: ", repstr); + Ext(repstr); + break; + case 'z' : + promptstring("Write SIM: Enter circuit name: ", repstr); + Sim(repstr); + break; + case 'w' : + promptstring("Write WOMBAT: circuit name: ", repstr); + Wombat(repstr,NULL); + break; + case 'a' : + promptstring("Write ACTEL: circuit name: ", repstr); + Actel(repstr,""); + break; + case 's': + promptstring("Write SPICE: circuit name: ", repstr); + SpiceCell(repstr, -1, ""); + break; + case 'E': + promptstring("Write ESACAP: circuit name: ", repstr); + EsacapCell(repstr,""); + break; + case 'g': + promptstring("Write NETGEN: circuit name: ", repstr); + WriteNetgenFile(repstr,""); + break; + case 'C': + promptstring("Write C code: circuit name: ", repstr); + Ccode(repstr,""); + break; +/* input file formats */ + case 'r': + case 'R': + promptstring("Read file: ",repstr); + ReadNetlist(repstr); + break; + case 'X' : + promptstring("Read EXT: Enter file name: ", repstr); + ReadExtHier(repstr); + break; + case 'Z' : + promptstring("Read SIM: Enter file name: ", repstr); + ReadSim(repstr); + break; + case 'K' : + promptstring("Read NTK: file? ", repstr); + ReadNtk(repstr); + break; + case 'A' : + printf("Reading ACTEL library.\n"); + ActelLib(); + break; + case 'S': + promptstring("Read SPICE (.ckt) file? ", repstr); + ReadSpice(repstr); + break; + case 'G' : + promptstring("Read NETGEN: file? ", repstr); + ReadNetgenFile(repstr); + break; + + case 'f' : + promptstring("Enter circuit name to flatten: ", repstr); + Flatten(repstr, -1); + break; + case 'F' : + promptstring("Enter class of circuit to flatten: ", repstr); + FlattenInstancesOf(repstr, -1); + break; + case 'p' : + promptstring("Enter circuit name: ", repstr); + PrintPortsInCell(repstr, -1); + break; + case 'T' : + NETCOMP(); + break; + case 'l' : + ClearDumpedList(); + promptstring("Enter circuit name: ", repstr); + PrintLeavesInCell(repstr, -1); + break; + case 'L' : + printf("List of all leaf circuits:\n"); + PrintAllLeaves(); + break; + case 'D' : Debug = !Debug; + printf("Debug mode is %s\n", Debug?"ON":"OFF"); + break; + case 't': StartTime = CPUTime(); + Timing = !Timing; + printf("Timing of commands %s.\n", Timing?"enabled":"disabled"); + break; + case '#': + if (strlen(repstr) > 1) { + char *command; + command = repstr+1; + DBUG_PUSH(command); + } + else { + promptstring("Dbug command? ",repstr); + DBUG_PUSH(repstr); + } + break; + case '!': +#ifdef IBMPC + system(""); +#else + system("/bin/csh"); +#endif + break; + case 'I' : Initialize(); break; + case 'q' : break; + case 'Q' : exit(0); + case 'P' : PROTOCHIP(); break; +#ifdef HAVE_MALLINFO + case 'm': PrintMemoryStats(); break; +#endif + case '<' : + { + FILE *oldfile; + promptstring("Read from file? ",repstr); + oldfile = promptstring_infile; + promptstring_infile = fopen(repstr,"r"); + if (promptstring_infile == NULL) + Printf("Unable to open command file: %s\n", repstr); + else { + Query(); + fclose(promptstring_infile); + } + promptstring_infile = oldfile; + break; + } + default : + fflush(stdout); + if (strlen(repstr)) fprintf(stderr,"Unknown command: %c\n",reply); + fflush(stderr); + printf( +"WRITE: nt(k),e(x)t,sim (z),(w)ombat,(a)ctel,net(g)en,(s)pice,(E)sacap,(C)\n"); + printf( +"READ: (r)ead, nt(K), e(X)t, sim (Z), (A)ctel library, net(G)en, (S)pice\n"); + printf( +"Print LISTS: (d)escribe circuit (c)ontents, (i)nstances, (p)orts, (l)eaves (L)\n" + ); + printf( +"PRINT: (n)ode connectivity (N), (e)lement list, (h)ash table entries (H))\n"); + printf( +"CELL OPS: (f)latten circuit, (F)latten instance, make circuit primiti(v)e (V=all)\n" + ); + + printf("toggle (D)ebug, (t)ime commands, embed (P)rotochip, ne(T)cmp\n"); + printf("(!) push shell, (<) read input file"); + +#ifdef HAVE_MALLINFO + printf(", show (m)emory usage"); +#endif + printf("\n"); + printf("(q)uit, (Q)uit immediately, re-(I)nitialize \n"); + break; + } + if (Timing) { + printf("CPU time used by last operation = %0.2f s\n", + ElapsedCPUTime(StartTime)); + fflush(stdout); /* just in case we have been redirected */ + } + } while (reply != 'q'); + signal(SIGINT,SIG_DFL); +} + +#endif diff --git a/base/query.h b/base/query.h new file mode 100644 index 0000000..338e6f5 --- /dev/null +++ b/base/query.h @@ -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 */ diff --git a/base/random.c b/base/random.c new file mode 100644 index 0000000..705a89b --- /dev/null +++ b/base/random.c @@ -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 + +#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 +} + diff --git a/base/regexp.h b/base/regexp.h new file mode 100644 index 0000000..c97308d --- /dev/null +++ b/base/regexp.h @@ -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 */ diff --git a/base/spice.c b/base/spice.c new file mode 100644 index 0000000..2c16c04 --- /dev/null +++ b/base/spice.c @@ -0,0 +1,2007 @@ +/* "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. */ + +/* spice.c -- Input / output for SPICE and ESACAP formats */ + +#include "config.h" + +#include +#if 0 +#include /* what about varargs, like in pdutils.c ??? */ +#endif + +#ifdef IBMPC +#include /* for calloc(), free() */ +#endif + +#ifdef TCL_NETGEN +#include +#endif + +#include "netgen.h" +#include "hash.h" +#include "objlist.h" +#include "netfile.h" +#include "print.h" + +// Global storage for parameters from .PARAM +struct hashlist **spiceparams; + +void SpiceSubCell(struct nlist *tp, int IsSubCell) +{ + struct objlist *ob; + int node, maxnode; + char *model; + struct tokstack *stackptr; + + /* check to see that all children have been dumped */ + for (ob = tp->cell; ob != NULL; ob = ob->next) { + if (ob->type == FIRSTPIN) { + struct nlist *tp2; + + tp2 = LookupCellFile(ob->model.class, tp->file); + if ((tp2 != NULL) && !(tp2->dumped) && (tp2->class == CLASS_SUBCKT)) + SpiceSubCell(tp2, 1); + } + } + + /* print preface, if it is a subcell */ + if (IsSubCell) { + FlushString(".SUBCKT %s ",tp->name); + for (ob = tp->cell; ob != NULL; ob = ob->next) + if (IsPortInPortlist(ob, tp)) FlushString("%d ", ob->node); + FlushString("\n"); + } + + /* print names of all nodes, prefixed by comment character */ + maxnode = 0; + for (ob = tp->cell; ob != NULL; ob = ob->next) + if (ob->node > maxnode) maxnode = ob->node; + +/* was: for (node = 0; node <= maxnode; node++) */ + for (node = 1; node <= maxnode; node++) + FlushString("# %3d = %s\n", node, NodeName(tp, node)); + + /* traverse list of objects */ + for (ob = tp->cell; ob != NULL; ob = ob->next) { + if (ob->type == FIRSTPIN) { + int drain_node, gate_node, source_node; + char spice_class; + struct nlist *tp2; + + tp2 = LookupCellFile(ob->model.class, tp->file); + model = tp2->name; + + /* Convert class numbers (defined in netgen.h) to SPICE classes */ + switch (tp2->class) { + case CLASS_NMOS4: case CLASS_PMOS4: case CLASS_FET4: + case CLASS_NMOS: case CLASS_PMOS: case CLASS_FET3: + case CLASS_FET: case CLASS_ECAP: + spice_class = 'M'; + break; + case CLASS_NPN: case CLASS_PNP: case CLASS_BJT: + spice_class = 'Q'; + break; + case CLASS_RES: case CLASS_RES3: + spice_class = 'R'; + break; + case CLASS_DIODE: + spice_class = 'D'; + break; + case CLASS_INDUCTOR: + spice_class = 'L'; + break; + case CLASS_CAP: case CLASS_CAP3: + spice_class = 'C'; + break; + case CLASS_SUBCKT: case CLASS_MODULE: + spice_class = 'X'; + break; + case CLASS_XLINE: + spice_class = 'T'; + break; + default: + Printf ("Bad device class found.\n"); + continue; /* ignore it. . . */ + } + + FlushString("%c%s", spice_class, ob->instance.name); + + /* Print out nodes. FETs switch node order */ + + switch (tp2->class) { + + /* 3-terminal FET devices---handled specially */ + case CLASS_NMOS: case CLASS_PMOS: case CLASS_FET3: + ob = ob->next; + FlushString(" %s", ob->name); /* drain */ + ob = ob->next; + FlushString(" %s", ob->name); /* gate */ + ob = ob->next; + FlushString(" %s", ob->name); /* source */ + ob = ob->next; + if (tp2->class == CLASS_NMOS) + FlushString(" GND!"); /* default substrate */ + else if (tp2->class == CLASS_PMOS) + FlushString(" VDD!"); /* default well */ + else + FlushString(" BULK"); /* default bulk---unknown */ + break; + + /* All other devices have nodes in order of SPICE syntax */ + default: + while (ob->next != NULL && ob->next->type >= FIRSTPIN) { + ob = ob->next; + FlushString(" %s", ob->name); + } + break; + } + + /* caps and resistors, print out device value */ + + + /* print out device type (model/subcircuit name) */ + + switch (tp2->class) { + case CLASS_CAP: + if (matchnocase(model, "c")) { + ob = ob->next; + if (ob->type == PROPERTY) { + struct valuelist *vl; + int i; + for (i == 0;; i++) { + vl = &(ob->instance.props[i]); + if (vl->type == PROP_ENDLIST) break; + else if (vl->type == PROP_VALUE) { + FlushString(" %g", vl->value.dval); + break; + } + } + } + } + else + FlushString(" %s", model); /* semiconductor capacitor */ + break; + + case CLASS_RES: + if (matchnocase(model, "r")) { + ob = ob->next; + if (ob->type == PROPERTY) { + struct valuelist *vl; + int i; + for (i == 0;; i++) { + vl = &(ob->instance.props[i]); + if (vl->type == PROP_ENDLIST) break; + else if (vl->type == PROP_VALUE) { + FlushString(" %g", vl->value.dval); + break; + } + } + } + } + else + FlushString(" %s", model); /* semiconductor resistor */ + break; + + default: + FlushString(" %s", model); /* everything else */ + } + + /* write properties (if any) */ + if (ob) ob = ob->next; + if (ob && ob->type == PROPERTY) { + struct valuelist *kv; + int i; + for (i = 0; ; i++) { + kv = &(ob->instance.props[i]); + if (kv->type == PROP_ENDLIST) break; + switch (kv->type) { + case PROP_STRING: + FlushString(" %s=%s", kv->key, kv->value.string); + break; + case PROP_INTEGER: + FlushString(" %s=%d", kv->key, kv->value.ival); + break; + case PROP_DOUBLE: + case PROP_VALUE: + FlushString(" %s=%g", kv->key, kv->value.dval); + break; + case PROP_EXPRESSION: + FlushString(" %s=", kv->key); + stackptr = kv->value.stack; + while (stackptr->next != NULL) + stackptr = stackptr->next; + + while (stackptr != NULL) { + switch (stackptr->toktype) { + case TOK_STRING: + FlushString("%s", stackptr->data.string); + break; + case TOK_DOUBLE: + FlushString("%d", stackptr->data.dvalue); + break; + case TOK_MULTIPLY: + FlushString("*"); + break; + case TOK_DIVIDE: + FlushString("/"); + break; + case TOK_PLUS: + FlushString("+"); + break; + case TOK_MINUS: + FlushString("-"); + break; + case TOK_FUNC_OPEN: + FlushString("("); + break; + case TOK_FUNC_CLOSE: + FlushString(")"); + break; + case TOK_GT: + FlushString(">"); + break; + case TOK_LT: + FlushString("<"); + break; + case TOK_GE: + FlushString(">="); + break; + case TOK_LE: + FlushString("<="); + break; + case TOK_EQ: + FlushString("=="); + break; + case TOK_NE: + FlushString("!="); + break; + case TOK_GROUP_OPEN: + FlushString("{"); + break; + case TOK_GROUP_CLOSE: + FlushString("}"); + break; + case TOK_FUNC_IF: + FlushString("IF("); + break; + case TOK_FUNC_THEN: + case TOK_FUNC_ELSE: + FlushString(","); + break; + } + stackptr = stackptr->last; + } + FlushString(" "); + break; + } + } + } + FlushString("\n"); + } + } + + if (IsSubCell) FlushString(".ENDS\n"); + tp->dumped = 1; +} + + +void SpiceCell(char *name, int fnum, char *filename) +{ + struct nlist *tp; + char FileName[500]; + + tp = LookupCellFile(name, fnum); + + if (tp == NULL) { + Printf ("No cell '%s' found.\n", name); + return; + } + + if (filename == NULL || strlen(filename) == 0) + SetExtension(FileName, name, SPICE_EXTENSION); + else + SetExtension(FileName, filename, SPICE_EXTENSION); + + if (!OpenFile(FileName, 80)) { + perror("ext(): Unable to open output file."); + return; + } + ClearDumpedList(); + /* all spice decks begin with comment line */ + FlushString("SPICE deck for cell %s written by Netgen %s.%s\n\n", + name, NETGEN_VERSION, NETGEN_REVISION); + SpiceSubCell(tp, 0); + CloseFile(FileName); +} + +/*------------------------------------------------------*/ +/* Routine to update instances with proper pin names, */ +/* if the instances were called before the cell */ +/* definition. */ +/*------------------------------------------------------*/ + +int renamepins(struct hashlist *p, int file) +{ + struct nlist *ptr, *tc; + struct objlist *ob, *ob2, *obp; + + ptr = (struct nlist *)(p->ptr); + + if (ptr->file != file) + return 1; + + for (ob = ptr->cell; ob != NULL; ob = ob->next) { + if (ob->type == FIRSTPIN) { + tc = LookupCellFile(ob->model.class, file); + obp = ob; + for (ob2 = tc->cell; ob2 != NULL; ob2 = ob2->next) { + if (ob2->type != PORT) break; + if (!matchnocase(ob2->name, obp->name + strlen(obp->instance.name) + 1)) { + // Printf("Cell %s pin correspondence: %s vs. %s\n", + // tc->name, obp->name, ob2->name); + FREE(obp->name); + obp->name = (char *)MALLOC(strlen(obp->instance.name) + + strlen(ob2->name) + 2); + sprintf(obp->name, "%s/%s", obp->instance.name, ob2->name); + } + obp = obp->next; + if (obp == NULL) break; + } + } + } +} + +/*------------------------------------------------------*/ +/* Structure for stacking nested subcircuit definitions */ +/*------------------------------------------------------*/ + +struct cellstack { + char *cellname; + struct cellstack *next; +}; + +/*------------------------------------------------------*/ +/* Push a subcircuit name onto the stack */ +/*------------------------------------------------------*/ + +void PushStack(char *cellname, struct cellstack **top) +{ + struct cellstack *newstack; + + newstack = (struct cellstack *)CALLOC(1, sizeof(struct cellstack)); + newstack->cellname = cellname; + newstack->next = *top; + *top = newstack; +} + +/*------------------------------------------------------*/ +/* Pop a subcircuit name off of the stack */ +/*------------------------------------------------------*/ + +void PopStack(struct cellstack **top) +{ + struct cellstack *stackptr; + + stackptr = *top; + if (!stackptr) return; + *top = stackptr->next; + FREE(stackptr); +} + +/* Forward declaration */ +extern void IncludeSpice(char *, int, struct cellstack **, int); + +/*------------------------------------------------------*/ +/* Read a SPICE deck */ +/*------------------------------------------------------*/ + +void ReadSpiceFile(char *fname, int filenum, struct cellstack **CellStackPtr, + int blackbox) +{ + int cdnum = 1, rdnum = 1, ndev, multi; + int warnings = 0, update = 0, hasports = 0; + char *eqptr, devtype; + struct keyvalue *kvlist = NULL; + char inst[256], model[256], instname[256]; + struct nlist *tp; + struct objlist *parent, *sobj, *nobj, *lobj, *pobj; + + inst[255] = '\0'; + model[255] = '\0'; + instname[255] = '\0'; + + while (!EndParseFile()) { + SkipTok(); /* get the next token */ + if (EndParseFile()) break; + + if (nexttok[0] == '*') SkipNewLine(); + + else if (matchnocase(nexttok, ".SUBCKT")) { + SpiceTokNoNewline(); + if (nexttok == NULL) { + Fprintf(stderr, "Badly formed .subkt line\n"); + goto skip_ends; + } + + /* Save pointer to current cell */ + if (CurrentCell != NULL) + parent = CurrentCell->cell; + else + parent = NULL; + + /* Check for existence of the cell. We may need to rename it. */ + + snprintf(model, 99, "%s", nexttok); + tp = LookupCellFile(nexttok, filenum); + + /* Check for name conflict with duplicate cell names */ + /* This may mean that the cell was used before it was */ + /* defined, but CDL files sometimes just redefine the */ + /* same cell over and over. So check if it's empty. */ + + if ((tp != NULL) && (tp->class != CLASS_MODULE)) { + int n; + char *ds; + + ds = strrchr(model, '['); + if ((ds != NULL) && (*(ds + 1) == '[')) + sscanf(ds + 2, "%d", &n); + else { + ds = model + strlen(model); + sprintf(ds, "[[0]]"); + n = -1; + } + + Printf("Duplicate cell %s in file; renaming.\n", nexttok); + while (tp != NULL) { + n++; + /* Append "[[n]]" to the preexisting model name to force uniqueness */ + sprintf(ds, "[[%d]]", n); + tp = LookupCellFile(model, filenum); + } + InstanceRename(nexttok, model, filenum); + CellRehash(nexttok, model, filenum); + CellDefNoCase(nexttok, filenum); + tp = LookupCellFile(nexttok, filenum); + } + else if (tp != NULL) { /* Make a new definition for an empty cell */ + FreePorts(nexttok); + CellDelete(nexttok, filenum); /* This removes any PLACEHOLDER flag */ + CellDefNoCase(model, filenum); + tp = LookupCellFile(model, filenum); + update = 1; /* Will need to update existing instances */ + } + else if (tp == NULL) { /* Completely new cell, no name conflict */ + CellDefNoCase(model, filenum); + tp = LookupCellFile(model, filenum); + } + + hasports = 0; + if (tp != NULL) { + + PushStack(tp->name, CellStackPtr); + + /* Tokens on the rest of the line are ports or */ + /* properties. Treat everything with an "=" as a */ + /* property, all others as ports. "M=" is *not* a */ + /* valid property meaning "number of" in a SUBCKT */ + /* line, and if it exists, it should be recorded as */ + /* a property, and (to be done) NOT treated as */ + /* referring to number of devices in a subcircuit */ + /* call. */ + + SpiceTokNoNewline(); + while (nexttok != NULL) { + + // Because of somebody's stupid meddling with + // SPICE syntax, we have to check for and ignore + // any use of the keyword "PARAMS:" + + if (!strcasecmp(nexttok, "PARAMS:")) { + SpiceTokNoNewline(); + continue; + } + + if ((eqptr = strchr(nexttok, '=')) != NULL) { + *eqptr = '\0'; + // Only String properties allowed + PropertyString(tp->name, filenum, nexttok, 0, eqptr + 1); + } + else { + Port(nexttok); + hasports = 1; + } + SpiceTokNoNewline(); + } + SetClass((blackbox) ? CLASS_MODULE : CLASS_SUBCKT); + + if (hasports == 0) { + // If the cell defines no ports, then create a proxy + Port((char *)NULL); + } + + /* Copy all global nodes from parent into child cell */ + for (sobj = parent; sobj != NULL; sobj = sobj->next) { + if (IsGlobal(sobj)) { + Global(sobj->name); + } + } + + /* In the blackbox case, don't read the cell contents */ + if (blackbox) goto skip_ends; + } + else { + +skip_ends: + /* There was an error, so skip to the end of the */ + /* subcircuit definition */ + + while (1) { + SpiceSkipNewLine(); + SkipTok(); + if (EndParseFile()) break; + if (matchnocase(nexttok, ".ENDS")) break; + } + } + } + else if (matchnocase(nexttok, ".ENDS")) { + /* If any pins are marked unconnected, see if there are */ + /* other pins of the same name that have connections. */ + /* Also remove any unconnected globals (just for cleanup) */ + + int maxnode = 0; + for (sobj = CurrentCell->cell; sobj; sobj = sobj->next) + if (sobj->node > maxnode) + maxnode = sobj->node + 1; + + lobj = NULL; + for (sobj = CurrentCell->cell; sobj != NULL;) { + nobj = sobj->next; + if (sobj->node < 0) { + if (IsGlobal(sobj)) { + if (lobj != NULL) + lobj->next = sobj->next; + else + CurrentCell->cell = sobj->next; + FreeObjectAndHash(sobj, CurrentCell); + } + else if (IsPort(sobj) && sobj->model.port == PROXY) + sobj->node = maxnode++; + else if (IsPort(sobj)) { + for (pobj = CurrentCell->cell; pobj && (pobj->type == PORT); + pobj = pobj->next) { + if (pobj == sobj) continue; + if (matchnocase(pobj->name, sobj->name) && pobj->node >= 0) { + sobj->node = pobj->node; + break; + } + } + lobj = sobj; + } + else + lobj = sobj; + } + else + lobj = sobj; + sobj = nobj; + } + + EndCell(); + + // This condition will be true if no nodes or components were + // created in the top-level cell before the first subcircuit + // definition, so it is not necessarily an error. . . + + // if (*(CellStackPtr) && ((*CellStackPtr)->next == NULL)) + // Printf(".ENDS encountered outside of a subcell.\n"); + // else + + if (*CellStackPtr) PopStack(CellStackPtr); + if (*CellStackPtr) ReopenCellDef((*CellStackPtr)->cellname, filenum); + SkipNewLine(); + } + else if (matchnocase(nexttok, ".MODEL")) { + unsigned char class = CLASS_SUBCKT; + struct nlist *ncell; + + /* A .MODEL statement can refine our knowledge of whether a Q or */ + /* M device is type "n" or "p", allowing us to properly translate */ + /* to other formats (e.g., .sim). If there are no .MODEL */ + /* statements, the "equate classes" command must be used. */ + + SpiceTokNoNewline(); + if (nexttok == NULL) continue; /* Ignore if no model name */ + snprintf(model, 99, "%s", nexttok); + SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + + if (!strcasecmp(nexttok, "NMOS")) { + class = CLASS_NMOS; + } + else if (!strcasecmp(nexttok, "PMOS")) { + class = CLASS_PMOS; + } + else if (!strcasecmp(nexttok, "PNP")) { + class = CLASS_PNP; + } + else if (!strcasecmp(nexttok, "NPN")) { + class = CLASS_NPN; + } + else if (!strcasecmp(nexttok, "NPN")) { + class = CLASS_NPN; + } + else if (!strcasecmp(nexttok, "D")) { + class = CLASS_DIODE; + } + else if (!strcasecmp(nexttok, "R")) { + class = CLASS_RES; + } + else if (!strcasecmp(nexttok, "C")) { + class = CLASS_CAP; + } + else if (!strcasecmp(nexttok, "L")) { + class = CLASS_INDUCTOR; + } + + /* Convert class of "model" to "class" */ + if (class != CLASS_SUBCKT) { + ncell = LookupCellFile(model, filenum); + if (ncell) ncell->class = class; + } + + SpiceSkipNewLine(); + } + + // Handle some commonly-used cards + + else if (matchnocase(nexttok, ".GLOBAL")) { + while (nexttok != NULL) { + int numnodes = 0; + SpiceTokNoNewline(); + if ((nexttok == NULL) || (nexttok[0] == '\0')) break; + + // First handle backward references + if (CurrentCell != NULL) + numnodes = ChangeScopeCurrent(nexttok, NODE, GLOBAL); + + /* If there are no backward references, then treat it */ + /* as a forward reference */ + + if (numnodes == 0) { + // If there is no current cell, make one + if (!(*CellStackPtr)) { + CellDefNoCase(fname, filenum); + PushStack(fname, CellStackPtr); + } + Global(nexttok); + } + } + SpiceSkipNewLine(); + } + else if (matchnocase(nexttok, ".INCLUDE")) { + char *iname, *iptr, *quotptr, *pathend; + + SpiceTokNoNewline(); + if (nexttok == NULL) continue; /* Ignore if no filename */ + + // Any file included in another SPICE file needs to be + // interpreted relative to the path of the parent SPICE file, + // unless it's an absolute pathname. + + pathend = strrchr(fname, '/'); + iptr = nexttok; + while (*iptr == '\'' || *iptr == '\"' || *iptr == '`') iptr++; + if ((pathend != NULL) && (*iptr != '/')) { + *pathend = '\0'; + iname = (char *)MALLOC(strlen(fname) + strlen(iptr) + 2); + sprintf(iname, "%s/%s", fname, iptr); + *pathend = '/'; + } + else + iname = STRDUP(iptr); + + // Eliminate any single or double quotes around the filename + iptr = iname; + quotptr = iptr; + while (*quotptr != '\'' && *quotptr != '\"' && *quotptr != '`' && + *quotptr != '\0' && *quotptr != '\n') quotptr++; + if (*quotptr == '\'' || *quotptr == '\"' || *quotptr == '`') *quotptr = '\0'; + + IncludeSpice(iptr, filenum, CellStackPtr, blackbox); + FREE(iname); + SpiceSkipNewLine(); + } + + else if (matchnocase(nexttok, ".PARAM")) { + + // Pick up key:value pairs and store in current cell + while (nexttok != NULL) + { + /* Parse for parameters used in expressions. Save */ + /* parameters in the "spiceparams" hash table. */ + + SpiceTokNoNewline(); + if ((nexttok == NULL) || (nexttok[0] == '\0')) break; + if ((eqptr = strchr(nexttok, '=')) != NULL) + { + struct property *kl = NULL; + + *eqptr = '\0'; + kl = NewProperty(); + kl->key = strsave(nexttok); + kl->idx = 0; + kl->type = PROP_STRING; + kl->slop.ival = 0; + kl->pdefault.string = strsave(eqptr + 1); + HashPtrInstall(nexttok, kl, spiceparams, OBJHASHSIZE); + } + } + } + + // Blackbox (library) mode---parse only subcircuits and models; + // ignore all components. + + else if (blackbox) { + SpiceSkipNewLine(); + } + + else if (toupper(nexttok[0]) == 'Q') { + char emitter[100], base[100], collector[100]; + emitter[99] = '\0'; + base[99] = '\0'; + collector[99] = '\0'; + + if (!(*CellStackPtr)) { + CellDefNoCase(fname, filenum); + PushStack(fname, CellStackPtr); + } + strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(collector, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(base, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(emitter, nexttok, 99); SpiceTokNoNewline(); + /* make sure all the nodes exist */ + if (LookupObject(collector, CurrentCell) == NULL) Node(collector); + if (LookupObject(base, CurrentCell) == NULL) Node(base); + if (LookupObject(emitter, CurrentCell) == NULL) Node(emitter); + + /* Read the device model */ + snprintf(model, 99, "%s", nexttok); + + ndev = 1; + while (nexttok != NULL) + { + /* Parse for M and other parameters */ + + SpiceTokNoNewline(); + if ((nexttok == NULL) || (nexttok[0] == '\0')) break; + if ((eqptr = strchr(nexttok, '=')) != NULL) + { + *eqptr = '\0'; + if (!strcasecmp(nexttok, "M")) + sscanf(eqptr + 1, "%d", &ndev); + else + AddProperty(&kvlist, nexttok, eqptr + 1); + } + } + + if (LookupCellFile(model, filenum) == NULL) { + CellDefNoCase(model, filenum); + Port("collector"); + Port("base"); + Port("emitter"); + SetClass(CLASS_BJT); + EndCell(); + ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */ + } + else if (CountPorts(model, filenum) != 3) { + /* Modeled device: Make sure it has the right number of ports */ + Fprintf(stderr, "Device \"%s\" has wrong number of ports for a BJT.\n"); + goto baddevice; + } + + multi = (ndev > 1) ? 1 : 0; + if (!multi) snprintf(instname, 255, "%s%s", model, inst); + while (ndev > 0) + { + if (multi) snprintf(instname, 255, "%s%s.%d", model, inst, ndev); + Cell(instname, model, collector, base, emitter); + pobj = LinkProperties(model, kvlist); + ReduceExpressions(pobj, CurrentCell, TRUE); + ndev--; + } + DeleteProperties(&kvlist); + } + else if (toupper(nexttok[0]) == 'M') { + char drain[100], gate[100], source[100], bulk[100]; + drain[99] = '\0'; + gate[99] = '\0'; + source[99] = '\0'; + bulk[99] = '\0'; + + if (!(*CellStackPtr)) { + CellDefNoCase(fname, filenum); + PushStack(fname, CellStackPtr); + } + strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(drain, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(gate, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(source, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + /* make sure all the nodes exist */ + if (LookupObject(drain, CurrentCell) == NULL) Node(drain); + if (LookupObject(gate, CurrentCell) == NULL) Node(gate); + if (LookupObject(source, CurrentCell) == NULL) Node(source); + + /* handle the substrate node */ + strncpy(bulk, nexttok, 99); SpiceTokNoNewline(); + if (LookupObject(bulk, CurrentCell) == NULL) Node(bulk); + + /* Read the device model */ + snprintf(model, 99, "%s", nexttok); + + ndev = 1; + while (nexttok != NULL) + { + /* Parse for parameters; treat "M" separately */ + + SpiceTokNoNewline(); + if ((nexttok == NULL) || (nexttok[0] == '\0')) break; + if ((eqptr = strchr(nexttok, '=')) != NULL) + { + *eqptr = '\0'; + if (!strcasecmp(nexttok, "M")) + sscanf(eqptr + 1, "%d", &ndev); + else if (!strcasecmp(nexttok, "L")) + AddProperty(&kvlist, "length", eqptr + 1); + else if (!strcasecmp(nexttok, "W")) + AddProperty(&kvlist, "width", eqptr + 1); + else + AddProperty(&kvlist, nexttok, eqptr + 1); + } + } + + /* Treat each different model name as a separate device class */ + /* The model name is prefixed with "M/" so that we know this is a */ + /* SPICE transistor. */ + + if (LookupCellFile(model, filenum) == NULL) { + CellDefNoCase(model, filenum); + Port("drain"); + Port("gate"); + Port("source"); + Port("bulk"); + PropertyDouble(model, filenum, "length", 0.01, 0.0); + PropertyDouble(model, filenum, "width", 0.01, 0.0); + SetClass(CLASS_FET); + EndCell(); + ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */ + } + else if (CountPorts(model, filenum) != 4) { + /* Modeled device: Make sure it has the right number of ports */ + Fprintf(stderr, "Device \"%s\" has wrong number of ports for a MOSFET.\n"); + goto baddevice; + } + + multi = (ndev > 1) ? 1 : 0; + if (!multi) snprintf(instname, 255, "%s%s", model, inst); + while (ndev > 0) + { + if (multi) snprintf(instname, 255, "%s%s.%d", model, inst, ndev); + Cell(instname, model, drain, gate, source, bulk); + pobj = LinkProperties(model, kvlist); + ReduceExpressions(pobj, CurrentCell, TRUE); + ndev--; + } + DeleteProperties(&kvlist); + SpiceSkipNewLine(); + } + else if (toupper(nexttok[0]) == 'C') { /* 2-port capacitors */ + int usemodel = 0; + + if (IgnoreRC) { + SpiceSkipNewLine(); + } + else { + char ctop[100], cbot[100]; + ctop[99] = '\0'; + cbot[99] = '\0'; + + if (!(*CellStackPtr)) { + CellDefNoCase(fname, filenum); + PushStack(fname, CellStackPtr); + } + strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(ctop, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(cbot, nexttok, 99); SpiceTokNoNewline(); + + /* make sure all the nodes exist */ + if (LookupObject(ctop, CurrentCell) == NULL) Node(ctop); + if (LookupObject(cbot, CurrentCell) == NULL) Node(cbot); + + /* Get capacitor value (if present), save as property "value" */ + if (nexttok != NULL) { + if (StringIsValue(nexttok)) { + AddProperty(&kvlist, "value", nexttok); + SpiceTokNoNewline(); + } + } + + /* Semiconductor (modeled) capacitor. But first need to make */ + /* sure that this does not start the list of parameters. */ + + model[0] = '\0'; + if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL)) + snprintf(model, 99, "%s", nexttok); + + /* Any other device properties? */ + ndev = 1; + while (nexttok != NULL) + { + SpiceTokNoNewline(); + if ((nexttok == NULL) || (nexttok[0] == '\0')) break; + if ((eqptr = strchr(nexttok, '=')) != NULL) { + *eqptr = '\0'; + if (!strcasecmp(nexttok, "M")) + sscanf(eqptr + 1, "%d", &ndev); + else + AddProperty(&kvlist, nexttok, eqptr + 1); + } + else if (!strncmp(nexttok, "$[", 2)) { + // Support for CDL modeled capacitor format + snprintf(model, 99, "%s", nexttok + 2); + if ((eqptr = strchr(model, ']')) != NULL) + *eqptr = '\0'; + } + else if (StringIsValue(nexttok)) { + // Suport for value passed to modeled capacitor + AddProperty(&kvlist, "value", nexttok); + } + } + + if (model[0] == '\0') + strcpy(model, "c"); /* Use default capacitor model */ + else + { + if (LookupCellFile(model, filenum) == NULL) { + CellDefNoCase(model, filenum); + Port("top"); + Port("bottom"); + PropertyValue(model, filenum, "value", 0.01, 0.0); + SetClass(CLASS_CAP); + EndCell(); + ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */ + } + else if (CountPorts(model, filenum) != 2) { + /* Modeled device: Make sure it has the right number of ports */ + Fprintf(stderr, "Device \"%s\" has wrong number of ports for a " + "capacitor.\n"); + goto baddevice; + } + usemodel = 1; + } + + multi = (ndev > 1) ? 1 : 0; + if (!multi) snprintf(instname, 255, "%s%s", model, inst); + + while (ndev > 0) { + if (multi) snprintf(instname, 255, "%s%s.%d", model, inst, ndev); + if (usemodel) + Cell(instname, model, ctop, cbot); + else + Cap((*CellStackPtr)->cellname, instname, ctop, cbot); + pobj = LinkProperties(model, kvlist); + ReduceExpressions(pobj, CurrentCell, TRUE); + ndev--; + } + DeleteProperties(&kvlist); + } + } + else if (toupper(nexttok[0]) == 'R') { /* 2-port resistors */ + int usemodel = 0; + + if (IgnoreRC) { + SpiceSkipNewLine(); + } + else { + char rtop[100], rbot[100]; + rtop[99] = '\0'; + rbot[99] = '\0'; + + if (!(*CellStackPtr)) { + CellDefNoCase(fname, filenum); + PushStack(fname, CellStackPtr); + } + strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(rtop, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(rbot, nexttok, 99); SpiceTokNoNewline(); + /* make sure all the nodes exist */ + if (LookupObject(rtop, CurrentCell) == NULL) Node(rtop); + if (LookupObject(rbot, CurrentCell) == NULL) Node(rbot); + + /* Get resistor value (if present); save as property "value" */ + + if (nexttok != NULL) { + if (StringIsValue(nexttok)) { + AddProperty(&kvlist, "value", nexttok); + SpiceTokNoNewline(); + } + } + + /* Semiconductor (modeled) resistor. But first need to make */ + /* sure that this does not start the list of parameters. */ + + model[0] = '\0'; + if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL)) + snprintf(model, 99, "%s", nexttok); + + /* Any other device properties? */ + ndev = 1; + while (nexttok != NULL) { + SpiceTokNoNewline(); + if ((nexttok == NULL) || (nexttok[0] == '\0')) break; + if ((eqptr = strchr(nexttok, '=')) != NULL) { + *eqptr = '\0'; + if (!strcasecmp(nexttok, "M")) + sscanf(eqptr + 1, "%d", &ndev); + else + AddProperty(&kvlist, nexttok, eqptr + 1); + } + else if (!strncmp(nexttok, "$[", 2)) { + // Support for CDL modeled resistor format + snprintf(model, 99, "%s", nexttok + 2); + if ((eqptr = strchr(model, ']')) != NULL) + *eqptr = '\0'; + } + else if (StringIsValue(nexttok)) { + // Suport for value passed to modeled resistor + AddProperty(&kvlist, "value", nexttok); + } + } + + if (model[0] != '\0') + { + if (LookupCellFile(model, filenum) == NULL) { + CellDefNoCase(model, filenum); + Port("end_a"); + Port("end_b"); + PropertyValue(model, filenum, "value", 0.01, 0.0); + SetClass(CLASS_RES); + EndCell(); + ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */ + } + else if (CountPorts(model, filenum) != 2) { + /* Modeled device: Make sure it has the right number of ports */ + Fprintf(stderr, "Device \"%s\" has wrong number of ports for a " + "resistor.\n"); + goto baddevice; + } + usemodel = 1; + } + else + strcpy(model, "r"); /* Use default resistor model */ + + multi = (ndev > 1) ? 1 : 0; + if (!multi) snprintf(instname, 255, "%s%s", model, inst); + + while (ndev > 0) { + if (multi) snprintf(instname, 255, "%s%s.%d", model, inst, ndev); + if (usemodel) + Cell(instname, model, rtop, rbot); + else + Res((*CellStackPtr)->cellname, instname, rtop, rbot); + pobj = LinkProperties(model, kvlist); + ReduceExpressions(pobj, CurrentCell, TRUE); + ndev--; + } + DeleteProperties(&kvlist); + } + } + else if (toupper(nexttok[0]) == 'D') { /* diode */ + char cathode[100], anode[100]; + cathode[99] = '\0'; + anode[99] = '\0'; + + if (!(*CellStackPtr)) { + CellDefNoCase(fname, filenum); + PushStack(fname, CellStackPtr); + } + strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(anode, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(cathode, nexttok, 99); SpiceTokNoNewline(); + /* make sure all the nodes exist */ + if (LookupObject(anode, CurrentCell) == NULL) Node(anode); + if (LookupObject(cathode, CurrentCell) == NULL) Node(cathode); + + /* Read the device model */ + snprintf(model, 99, "%s", nexttok); + + ndev = 1; + while (nexttok != NULL) + { + /* Parse for M and other parameters */ + + SpiceTokNoNewline(); + if ((nexttok == NULL) || (nexttok[0] == '\0')) break; + if ((eqptr = strchr(nexttok, '=')) != NULL) + { + *eqptr = '\0'; + if (!strcasecmp(nexttok, "M")) + sscanf(eqptr + 1, "%d", &ndev); + else + AddProperty(&kvlist, nexttok, eqptr + 1); + } + } + + if (LookupCellFile(model, filenum) == NULL) { + CellDefNoCase(model, filenum); + Port("anode"); + Port("cathode"); + SetClass(CLASS_DIODE); + EndCell(); + ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */ + } + else if (CountPorts(model, filenum) != 2) { + /* Modeled device: Make sure it has the right number of ports */ + Fprintf(stderr, "Device \"%s\" has wrong number of ports for a diode.\n"); + goto baddevice; + } + multi = (ndev > 1) ? 1 : 0; + if (!multi) snprintf(instname, 255, "%s%s", model, inst); + while (ndev > 0) + { + if (multi) snprintf(instname, 255, "%s%s.%d", model, inst, ndev); + Cell(instname, model, anode, cathode); + pobj = LinkProperties(model, kvlist); + ReduceExpressions(pobj, CurrentCell, TRUE); + ndev--; + } + DeleteProperties(&kvlist); + } + else if (toupper(nexttok[0]) == 'T') { /* transmission line */ + int usemodel = 0; + + if (IgnoreRC) { + SpiceSkipNewLine(); + } + else { + char node1[100], node2[100], node3[100], node4[100]; + node1[99] = '\0'; + node2[99] = '\0'; + node3[99] = '\0'; + node4[99] = '\0'; + + if (!(*CellStackPtr)) { + CellDefNoCase(fname, filenum); + PushStack(fname, CellStackPtr); + } + strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(node1, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(node2, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(node3, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(node4, nexttok, 99); SpiceTokNoNewline(); + /* make sure all the nodes exist */ + if (LookupObject(node1, CurrentCell) == NULL) Node(node1); + if (LookupObject(node2, CurrentCell) == NULL) Node(node2); + if (LookupObject(node3, CurrentCell) == NULL) Node(node3); + if (LookupObject(node4, CurrentCell) == NULL) Node(node4); + + /* Lossy (modeled) transmission line. But first need to make */ + /* sure that this does not start the list of parameters. */ + + model[0] = '\0'; + if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL)) + snprintf(model, 99, "%s", nexttok); + + /* Any other device properties? */ + ndev = 1; + while (nexttok != NULL) { + SpiceTokNoNewline(); + if ((nexttok == NULL) || (nexttok[0] == '\0')) break; + if ((eqptr = strchr(nexttok, '=')) != NULL) { + *eqptr = '\0'; + if (!strcasecmp(nexttok, "M")) + sscanf(eqptr + 1, "%d", &ndev); + else + AddProperty(&kvlist, nexttok, eqptr + 1); + } + } + + if (model[0] != '\0') + { + if (LookupCellFile(model, filenum) == NULL) { + CellDefNoCase(model, filenum); + Port("node1"); + Port("node2"); + Port("node3"); + Port("node4"); + SetClass(CLASS_XLINE); + EndCell(); + ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */ + } + else if (CountPorts(model, filenum) != 4) { + /* Modeled device: Make sure it has the right number of ports */ + Fprintf(stderr, "Device \"%s\" has wrong number of ports for a " + "transmission line.\n"); + goto baddevice; + } + usemodel = 1; + } + else + strcpy(model, "t"); /* Use default xline model */ + + multi = (ndev > 1) ? 1 : 0; + if (!multi) snprintf(instname, 255, "%s%s", model, inst); + + while (ndev > 0) { + if (multi) snprintf(instname, 255, "%s%s.%d", model, inst, ndev); + if (usemodel) + Cell(instname, model, node1, node2, node3, node4); + else + XLine((*CellStackPtr)->cellname, instname, node1, node2, + node3, node4); + pobj = LinkProperties(model, kvlist); + ReduceExpressions(pobj, CurrentCell, TRUE); + ndev--; + } + DeleteProperties(&kvlist); + } + } + else if (toupper(nexttok[0]) == 'L') { /* inductor */ + char end_a[100], end_b[100]; + int usemodel = 0; + end_a[99] = '\0'; + end_b[99] = '\0'; + + if (!(*CellStackPtr)) { + CellDefNoCase(fname, filenum); + PushStack(fname, CellStackPtr); + } + strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(end_a, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(end_b, nexttok, 99); SpiceTokNoNewline(); + /* make sure all the nodes exist */ + if (LookupObject(end_a, CurrentCell) == NULL) Node(end_a); + if (LookupObject(end_b, CurrentCell) == NULL) Node(end_b); + + /* Get inductance value (if present); save as property "value" */ + + if (nexttok != NULL) { + if (StringIsValue(nexttok)) { + AddProperty(&kvlist, "value", nexttok); + SpiceTokNoNewline(); + } + } + + /* Semiconductor (modeled) inductor. But first need to make */ + /* sure that this does not start the list of parameters. */ + + model[0] = '\0'; + if ((nexttok != NULL) && ((eqptr = strchr(nexttok, '=')) == NULL)) + snprintf(model, 99, "%s", nexttok); + + /* Any other device properties? */ + ndev = 1; + while (nexttok != NULL) + { + /* Parse for M and other parameters */ + + SpiceTokNoNewline(); + if ((nexttok == NULL) || (nexttok[0] == '\0')) break; + if ((eqptr = strchr(nexttok, '=')) != NULL) + { + *eqptr = '\0'; + if (!strcasecmp(nexttok, "M")) + sscanf(eqptr + 1, "%d", &ndev); + else + AddProperty(&kvlist, nexttok, eqptr + 1); + } + } + + if (model[0] != '\0') + { + if (LookupCellFile(model, filenum) == NULL) { + CellDefNoCase(model, filenum); + Port("end_a"); + Port("end_b"); + SetClass(CLASS_INDUCTOR); + EndCell(); + ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */ + } + else if (CountPorts(model, filenum) != 2) { + /* Modeled device: Make sure it has the right number of ports */ + Fprintf(stderr, "Device \"%s\" has wrong number of ports for an " + "inductor.\n"); + goto baddevice; + } + usemodel = 1; + } + else + strcpy(model, "l"); /* Use default inductor model */ + + multi = (ndev > 1) ? 1 : 0; + if (!multi) snprintf(instname, 255, "%s%s", model, inst); + while (ndev > 0) + { + if (multi) snprintf(instname, 255, "%s%s.%d", model, inst, ndev); + if (usemodel) + Cell(instname, model, end_a, end_b); + else + Inductor((*CellStackPtr)->cellname, instname, end_a, end_b); + pobj = LinkProperties(model, kvlist); + ReduceExpressions(pobj, CurrentCell, TRUE); + ndev--; + } + DeleteProperties(&kvlist); + } + + /* The following SPICE components are treated as */ + /* black-box subcircuits (class MODULE): V, I, E */ + + else if (toupper(nexttok[0]) == 'V') { /* voltage source */ + char pos[100], neg[100]; + pos[99] = '\0'; + neg[99] = '\0'; + + if (!(*CellStackPtr)) { + CellDefNoCase(fname, filenum); + PushStack(fname, CellStackPtr); + } + strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(pos, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(neg, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + /* make sure all the nodes exist */ + if (LookupObject(pos, CurrentCell) == NULL) Node(pos); + if (LookupObject(neg, CurrentCell) == NULL) Node(neg); + + /* Any device properties? */ + while (nexttok != NULL) + { + SpiceTokNoNewline(); + if ((nexttok == NULL) || (nexttok[0] == '\0')) break; + if ((eqptr = strchr(nexttok, '=')) != NULL) + { + *eqptr = '\0'; + AddProperty(&kvlist, nexttok, eqptr + 1); + } + else if (StringIsValue(nexttok)) { + AddProperty(&kvlist, "value", nexttok); + SpiceTokNoNewline(); + } + } + strcpy(model, "vsrc"); /* Default voltage source */ + if (LookupCellFile(model, filenum) == NULL) { + CellDefNoCase(model, filenum); + Port("pos"); + Port("neg"); + SetClass(CLASS_MODULE); + EndCell(); + ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */ + } + else if (CountPorts(model, filenum) != 2) { + /* Modeled device: Make sure it has the right number of ports */ + Fprintf(stderr, "Device \"%s\" has wrong number of ports for a " + "voltage source.\n"); + goto baddevice; + } + Cell(instname, model, pos, neg); + pobj = LinkProperties(model, kvlist); + ReduceExpressions(pobj, CurrentCell, TRUE); + DeleteProperties(&kvlist); + } + else if (toupper(nexttok[0]) == 'I') { /* current source */ + char pos[100], neg[100]; + pos[99] = '\0'; + neg[99] = '\0'; + + if (!(*CellStackPtr)) { + CellDefNoCase(fname, filenum); + PushStack(fname, CellStackPtr); + } + strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(pos, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(neg, nexttok, 99); SpiceTokNoNewline(); + /* make sure all the nodes exist */ + if (LookupObject(pos, CurrentCell) == NULL) Node(pos); + if (LookupObject(neg, CurrentCell) == NULL) Node(neg); + + /* Any device properties? */ + while (nexttok != NULL) + { + SpiceTokNoNewline(); + if ((nexttok == NULL) || (nexttok[0] == '\0')) break; + if ((eqptr = strchr(nexttok, '=')) != NULL) + { + *eqptr = '\0'; + AddProperty(&kvlist, nexttok, eqptr + 1); + } + else if (StringIsValue(nexttok)) { + AddProperty(&kvlist, "value", nexttok); + SpiceTokNoNewline(); + } + } + strcpy(model, "isrc"); /* Default current source */ + if (LookupCellFile(model, filenum) == NULL) { + CellDefNoCase(model, filenum); + Port("pos"); + Port("neg"); + SetClass(CLASS_MODULE); + EndCell(); + ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */ + } + else if (CountPorts(model, filenum) != 2) { + /* Modeled device: Make sure it has the right number of ports */ + Fprintf(stderr, "Device \"%s\" has wrong number of ports for a " + "current source.\n"); + goto baddevice; + } + Cell(instname, model, pos, neg); + pobj = LinkProperties(model, kvlist); + ReduceExpressions(pobj, CurrentCell, TRUE); + DeleteProperties(&kvlist); + } + else if (toupper(nexttok[0]) == 'E') { /* controlled voltage source */ + char pos[100], neg[100], ctrlp[100], ctrln[100]; + pos[99] = '\0'; + neg[99] = '\0'; + ctrlp[99] = '\0'; + ctrln[99] = '\0'; + + if (!(*CellStackPtr)) { + CellDefNoCase(fname, filenum); + PushStack(fname, CellStackPtr); + } + strncpy(inst, nexttok + 1, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(pos, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(neg, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(ctrlp, nexttok, 99); SpiceTokNoNewline(); + if (nexttok == NULL) goto baddevice; + strncpy(ctrln, nexttok, 99); SpiceTokNoNewline(); + + /* make sure all the nodes exist */ + if (LookupObject(pos, CurrentCell) == NULL) Node(pos); + if (LookupObject(neg, CurrentCell) == NULL) Node(neg); + if (LookupObject(ctrlp, CurrentCell) == NULL) Node(neg); + if (LookupObject(ctrln, CurrentCell) == NULL) Node(neg); + + /* Any device properties? */ + while (nexttok != NULL) + { + SpiceTokNoNewline(); + if ((nexttok == NULL) || (nexttok[0] == '\0')) break; + if ((eqptr = strchr(nexttok, '=')) != NULL) + { + *eqptr = '\0'; + AddProperty(&kvlist, nexttok, eqptr + 1); + } + else if (StringIsValue(nexttok)) { + AddProperty(&kvlist, "value", nexttok); + SpiceTokNoNewline(); + } + } + strcpy(model, "vcvs"); /* Default controlled voltage source */ + if (LookupCellFile(model, filenum) == NULL) { + CellDefNoCase(model, filenum); + Port("pos"); + Port("neg"); + Port("ctrlp"); + Port("ctrln"); + SetClass(CLASS_MODULE); + EndCell(); + ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */ + } + else if (CountPorts(model, filenum) != 4) { + /* Modeled device: Make sure it has the right number of ports */ + Fprintf(stderr, "Device \"%s\" has wrong number of ports for a " + "controlled voltage source.\n"); + goto baddevice; + } + Cell(instname, model, pos, neg, ctrlp, ctrln); + pobj = LinkProperties(model, kvlist); + ReduceExpressions(pobj, CurrentCell, TRUE); + DeleteProperties(&kvlist); + } + + else if (toupper(nexttok[0]) == 'X') { /* subcircuit instances */ + char instancename[100], subcktname[100]; + instancename[99] = '\0'; + subcktname[99] = '\0'; + + struct portelement { + char *name; + struct portelement *next; + }; + + struct portelement *head, *tail, *scan, *scannext; + struct objlist *obptr; + + snprintf(instancename, 99, "%s", nexttok + 1); + strncpy(instancename, nexttok + 1, 99); + if (!(*CellStackPtr)) { + CellDefNoCase(fname, filenum); + PushStack(fname, CellStackPtr); + } + + head = NULL; + tail = NULL; + SpiceTokNoNewline(); + ndev = 1; + while (nexttok != NULL) { + /* must still be a node or a parameter */ + struct portelement *new_port; + + // CDL format compatibility: Ignore "/" before the subcircuit name + if (matchnocase(nexttok, "/")) { + SpiceTokNoNewline(); + continue; + } + // And (why do they have to keep messing with a perfectly good syntax?!) + // prepended to the name without a space: + else if (*nexttok == '/') nexttok++; + + // Ignore token called "PARAMS:" + if (!strcasecmp(nexttok, "PARAMS:")) { + SpiceTokNoNewline(); + continue; + } + + // We need to look for parameters of the type "name=value" BUT + // we also need to make sure that what we think is a parameter + // is actually a circuit name with an equals sign character in it. + + if (((eqptr = strchr(nexttok, '=')) != NULL) && + ((tp = LookupCellFile(nexttok, filenum)) == NULL)) + { + *eqptr = '\0'; + if (!strcasecmp(nexttok, "M")) + sscanf(eqptr + 1, "%d", &ndev); + else + AddProperty(&kvlist, nexttok, eqptr + 1); + } + else + { + new_port = (struct portelement *)CALLOC(1, sizeof(struct portelement)); + new_port->name = strsave(nexttok); + if (head == NULL) head = new_port; + else tail->next = new_port; + new_port->next = NULL; + tail = new_port; + } + SpiceTokNoNewline(); + } + + /* find the last element of the list, which is not a port, + but the class type */ + scan = head; + while (scan != NULL && scan->next != tail && scan->next != NULL) + scan = scan->next; + tail = scan; + if (scan == NULL) goto baddevice; + if (scan->next != NULL) scan = scan->next; + tail->next = NULL; + + /* Create cell name and revise instance name based on the cell name */ + /* For clarity, if "instancename" does not contain the cellname, */ + /* then prepend the cellname to the instance name. HOWEVER, if any */ + /* netlist is using instancename/portname to name nets, then we */ + /* will have duplicate node names with conflicting records. So at */ + /* very least prepend an "/" to it. . . */ + + /* NOTE: Previously an 'X' was prepended to the name, but this */ + /* caused serious and common errors where, for example, the circuit */ + /* defined cells NOR and XNOR, causing confusion between node */ + /* names. */ + + if (strncmp(instancename, scan->name, strlen(scan->name))) { + snprintf(subcktname, 99, "%s%s", scan->name, instancename); + strcpy(instancename, subcktname); + } + else { + snprintf(subcktname, 99, "/%s", instancename); + strcpy(instancename, subcktname); + } + snprintf(subcktname, 99, "%s", scan->name); + + if (scan == head) { + head = NULL; + Fprintf(stderr, "Warning: Cell %s has no pins\n", scan->name); + } + FREE (scan->name); + FREE (scan); + + /* Check that the subcell exists. If not, print a warning and */ + /* generate an empty subcircuit entry matching the call. */ + + tp = LookupCellFile(subcktname, filenum); + if (tp == NULL) { + char defport[8]; + int i; + + Fprintf(stdout, "Call to undefined subcircuit %s\n" + "Creating placeholder cell definition.\n", subcktname); + CellDefNoCase(subcktname, filenum); + CurrentCell->flags |= CELL_PLACEHOLDER; + for (scan = head, i = 1; scan != NULL; scan = scan->next, i++) { + sprintf(defport, "%d", i); + Port(defport); + } + if (head == NULL) { + Port((char *)NULL); // Must have something for pin 1 + } + SetClass(CLASS_MODULE); + EndCell(); + ReopenCellDef((*CellStackPtr)->cellname, filenum); /* Reopen */ + update = 1; + } + + /* nexttok is now NULL, scan->name points to class */ + multi = (ndev > 1) ? 1 : 0; + if (multi) strcat(instancename, "."); + while (ndev > 0) { + if (multi) { + char *dotptr = strrchr(instancename, '.'); + sprintf(dotptr + 1, "%d", ndev); + } + Instance(subcktname, instancename); + pobj = LinkProperties(subcktname, kvlist); + ReduceExpressions(pobj, CurrentCell, TRUE); + ndev--; + + /* (Diagnostic) */ + /* Fprintf(stderr, "instancing subcell: %s (%s):", subcktname, instancename); */ + /* + for (scan = head; scan != NULL; scan = scan->next) + Fprintf(stderr," %s", scan->name); + Fprintf(stderr,"\n"); + */ + + obptr = LookupInstance(instancename, CurrentCell); + if (obptr != NULL) { + scan = head; + if (scan != NULL) + do { + if (LookupObject(scan->name, CurrentCell) == NULL) Node(scan->name); + join(scan->name, obptr->name); + obptr = obptr->next; + scan = scan->next; + } while (obptr != NULL && obptr->type > FIRSTPIN && scan != NULL); + + if ((obptr == NULL && scan != NULL) || + (obptr != NULL && scan == NULL && obptr->type > FIRSTPIN)) { + if (warnings <= 100) { + Fprintf(stderr,"Parameter list mismatch in %s: ", instancename); + + if (obptr == NULL) + Fprintf(stderr, "Too many parameters in call!\n"); + else if (scan == NULL) + Fprintf(stderr, "Not enough parameters in call!\n"); + InputParseError(stderr); + if (warnings == 100) + Fprintf(stderr, "Too many warnings. . . will not report any more.\n"); + } + warnings++; + } + } // repeat over ndev + } + DeleteProperties(&kvlist); + + /* free up the allocated list */ + scan = head; + while (scan != NULL) { + scannext = scan->next; + FREE(scan->name); + FREE(scan); + scan = scannext; + } + } + else if (matchnocase(nexttok, ".END")) { + /* Well, don't take *my* word for it. But we won't flag a warning. */ + } + else { + int ntotal; + char *sstr; + ntotal = 0; + for (sstr = nexttok; *sstr != '\0'; sstr++) if (!isascii(*sstr)) ntotal++; + if ((int)(sstr - nexttok) < (ntotal << 2)) { + Fprintf(stderr, "Input file \"%s\" appears to be binary" + ". . . bailing out\n", fname); + while (*CellStackPtr) PopStack(CellStackPtr); + return; + } + + if (warnings <= 100) { + Fprintf(stderr, "Ignoring line starting with token: %s\n", nexttok); + InputParseError(stderr); + if (warnings == 100) + Fprintf(stderr, "Too many warnings. . . will not report any more.\n"); + } + warnings++; + SpiceSkipNewLine(); + } + continue; + +baddevice: + Fprintf(stderr, "Badly formed line in input.\n"); + } + if (update != 0) RecurseCellFileHashTable(renamepins, filenum); + + if (warnings) + Fprintf(stderr, "File %s read with %d warning%s.\n", fname, + warnings, (warnings == 1) ? "" : "s"); +} + +/*----------------------------------------------*/ +/* Top-level SPICE file read routine */ +/*----------------------------------------------*/ + +char *ReadSpiceTop(char *fname, int *fnum, int blackbox) +{ + struct cellstack *CellStack = NULL; + struct nlist *tp; + int filenum; + + // Make sure CurrentCell is clear + CurrentCell = NULL; + + if ((filenum = OpenParseFile(fname, *fnum)) < 0) { + char name[100]; + + SetExtension(name, fname, SPICE_EXTENSION); + if ((filenum = OpenParseFile(name, *fnum)) < 0) { + Fprintf(stderr,"No file: %s\n",name); + *fnum = filenum; + return NULL; + } + } + + /* Make sure all SPICE file reading is case insensitive */ + matchfunc = matchnocase; + matchintfunc = matchfilenocase; + hashfunc = hashnocase; + + spiceparams = (struct hashlist **)CALLOC(OBJHASHSIZE, + sizeof(struct hashlist *)); + + /* All spice files should start with a comment line, */ + /* but we won't depend upon it. Any comment line */ + /* will be handled by the main SPICE file processing. */ + + ReadSpiceFile(fname, filenum, &CellStack, blackbox); + CloseParseFile(); + + // Cleanup + while (CellStack != NULL) PopStack(&CellStack); + + RecurseHashTable(spiceparams, OBJHASHSIZE, freeprop); + HashKill(spiceparams, OBJHASHSIZE); + FREE(spiceparams); + spiceparams = NULL; + + // Important: If the file is a library, containing subcircuit + // definitions but no components, then it needs to be registered + // as an empty cell. Otherwise, the filename is lost and cells + // cannot be matched to the file! + + if (LookupCellFile(fname, filenum) == NULL) CellDefNoCase(fname, filenum); + + tp = LookupCellFile(fname, filenum); + if (tp) tp->flags |= CELL_TOP; + + *fnum = filenum; + return fname; +} + +/*--------------------------------------*/ +/* Wrappers for ReadSpiceTop() */ +/*--------------------------------------*/ + +char *ReadSpice(char *fname, int *fnum) +{ + return ReadSpiceTop(fname, fnum, 0); +} + +/*--------------------------------------*/ + +char *ReadSpiceLib(char *fname, int *fnum) +{ + return ReadSpiceTop(fname, fnum, 1); +} + +/*--------------------------------------*/ +/* SPICE file include routine */ +/*--------------------------------------*/ + +void IncludeSpice(char *fname, int parent, struct cellstack **CellStackPtr, + int blackbox) +{ + int filenum = -1; + char name[256]; + + /* If fname does not begin with "/", then assume that it is */ + /* in the same relative path as its parent. */ + + if (fname[0] != '/') { + char *ppath; + if (*CellStackPtr && ((*CellStackPtr)->cellname != NULL)) { + strcpy(name, (*CellStackPtr)->cellname); + ppath = strrchr(name, '/'); + if (ppath != NULL) + strcpy(ppath + 1, fname); + else + strcpy(name, fname); + filenum = OpenParseFile(name, parent); + } + } + + /* If we failed the path relative to the parent, then try the */ + /* filename alone (relative to the path where netgen was */ + /* executed). */ + + if (filenum < 0) { + if ((filenum = OpenParseFile(fname, parent)) < 0) { + + /* If that fails, see if a standard SPICE extension */ + /* helps. But really, we're getting desperate at this */ + /* point. */ + + SetExtension(name, fname, SPICE_EXTENSION); + if ((filenum = OpenParseFile(name, parent)) < 0) { + Fprintf(stderr,"No file: %s\n",name); + return; + } + } + } + ReadSpiceFile(fname, parent, CellStackPtr, blackbox); + CloseParseFile(); +} + +/*--------------------------------------*/ +/*--------------------------------------*/ + +void EsacapSubCell(struct nlist *tp, int IsSubCell) +{ + struct objlist *ob; + int node, maxnode; + + /* check to see that all children have been dumped */ + for (ob = tp->cell; ob != NULL; ob = ob->next) { + if (ob->type == FIRSTPIN) { + struct nlist *tp2; + + tp2 = LookupCellFile(ob->model.class, tp->file); + if ((tp2 != NULL) && !(tp2->dumped) && (tp2->class == CLASS_SUBCKT)) + EsacapSubCell(tp2, 1); + } + } + + /* print preface, if it is a subcell */ + if (IsSubCell) { + FlushString("# %s doesn't know how to generate ESACAP subcells\n"); + FlushString("# Look in spice.c \n\n"); + FlushString(".SUBCKT %s ",tp->name); + for (ob = tp->cell; ob != NULL; ob = ob->next) + if (IsPortInPortlist(ob, tp)) FlushString("%d ", ob->node); + FlushString("# End of bogus ESACAP subcell\n"); + FlushString("\n"); + } + + /* print names of all nodes, prefixed by comment character */ + maxnode = 0; + for (ob = tp->cell; ob != NULL; ob = ob->next) + if (ob->node > maxnode) maxnode = ob->node; + +/* was: for (node = 0; node <= maxnode; node++) */ + for (node = 1; node <= maxnode; node++) + FlushString("# %3d = %s\n", node, NodeName(tp, node)); + + + /* traverse list of objects */ + for (ob = tp->cell; ob != NULL; ob = ob->next) { + if (ob->type == FIRSTPIN) { + int drain_node, gate_node, source_node; + /* print out element, but special-case transistors */ + if (match (ob->model.class, "n") || matchnocase(ob->model.class, "p")) { + FlushString("X%s ",ob->instance.name); + /* note: this code is dependent on the order defined in Initialize()*/ + gate_node = ob->node; + ob = ob->next; + drain_node = ob->node; + ob = ob->next; + source_node = ob->node; + FlushString("(%d %d %d ",drain_node, gate_node, source_node); + /* write fake substrate connections: NSUB and PSUB */ + /* write fake transistor sizes: NL, NW, PL and PW */ + /* write fake transistor classes: NCHANNEL and PCHANNEL */ + if (matchnocase(ob->model.class, "n")) + FlushString("NSUB)=SMOS(TYPE=NCHANNEL,W=NW,L=NL);\n"); + else FlushString("PSUB)=SMOS(TYPE=PCHANNEL,W=PW,L=PL);\n"); + } + else { + /* it must be a subckt */ + FlushString("### BOGUS SUBCKT: X%s %d ", ob->instance.name, ob->node); + while (ob->next != NULL && ob->next->type > FIRSTPIN) { + ob = ob->next; + FlushString("%d ",ob->node); + } + FlushString("X%s\n", ob->model.class); + } + } + } + + if (IsSubCell) FlushString(".ENDS\n"); + tp->dumped = 1; +} + +/*--------------------------------------*/ +/*--------------------------------------*/ + +void EsacapCell(char *name, char *filename) +{ + struct nlist *tp; + char FileName[500]; + + tp = LookupCellFile(name, -1); + if (tp == NULL) { + Printf ("No cell '%s' found.\n", name); + return; + } + + if (filename == NULL || strlen(filename) == 0) + SetExtension(FileName, name, ESACAP_EXTENSION); + else + SetExtension(FileName, filename, ESACAP_EXTENSION); + + if (!OpenFile(FileName, 80)) { + perror("ext(): Unable to open output file."); + return; + } + ClearDumpedList(); + /* all Esacap decks begin with the following comment line */ + FlushString("# ESACAP deck for cell %s written by Netgen %s.%s\n\n", + name, NETGEN_VERSION, NETGEN_REVISION); + EsacapSubCell(tp, 0); + FlushString("# end of ESACAP deck written by Netgen %s.%s\n\n", + NETGEN_VERSION, NETGEN_REVISION); + CloseFile(FileName); +} diff --git a/base/test.c b/base/test.c new file mode 100644 index 0000000..f515be8 --- /dev/null +++ b/base/test.c @@ -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 +#ifdef ANSI_LIBRARY +#include /* 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); +} + diff --git a/base/timing.c b/base/timing.c new file mode 100644 index 0000000..518e89d --- /dev/null +++ b/base/timing.c @@ -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 + +#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 /* for times(2) stuff */ +#include /* for times(2) stuff */ +#include /* 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 +#include + +#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 /* 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); +} + + diff --git a/base/timing.h b/base/timing.h new file mode 100644 index 0000000..d2e7213 --- /dev/null +++ b/base/timing.h @@ -0,0 +1,3 @@ +/* timing routines */ +extern float CPUTime(void); +extern float ElapsedCPUTime(float since); diff --git a/base/wombat.c b/base/wombat.c new file mode 100644 index 0000000..9d65d32 --- /dev/null +++ b/base/wombat.c @@ -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 +#include + +#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); +} + diff --git a/base/xilinx.c b/base/xilinx.c new file mode 100644 index 0000000..3c15e33 --- /dev/null +++ b/base/xilinx.c @@ -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 +#include +#include + +#ifdef IBMPC +#include /* 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; + } +} diff --git a/base/xillib.c b/base/xillib.c new file mode 100644 index 0000000..acc64ba --- /dev/null +++ b/base/xillib.c @@ -0,0 +1,1264 @@ +/* "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. */ + + +/* xillib.c -- definitions of Xilinx cells for ACTEL cells. */ + + +/* define the following to make pads unique */ +/* this is necessary for ntk2adl, but is annoying for PLACE */ + +#undef USE_UNIQUE_GLOBALS + + +#include "config.h" +#include +#include "netgen.h" + +static int xilinx_lib_present = 0; + +int XilinxLibPresent(void) +{ + return xilinx_lib_present; +} + +void XilinxLib(void) +{ + int OldDebug; + + OldDebug = Debug; + Debug = 0; + + + CellDef("OUTBUF", -1); +#ifdef USE_UNIQUE_GLOBALS + UniqueGlobal("PAD"); +#else + Port("O"); +#endif + Port("I"); + SetClass(CLASS_MODULE); + EndCell(); + + + CellDef("INBUF", -1); + Port("O"); +#ifdef USE_UNIQUE_GLOBALS + UniqueGlobal("PAD"); +#else + Port("I"); +#endif + EndCell(); + + CellDef("CLKBUF", -1); + Port("O"); +#ifdef USE_UNIQUE_GLOBALS + UniqueGlobal("PAD"); +#else + Port("I"); +#endif + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("CLOCK", -1); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("TRIBUFF", -1); +#ifdef USE_UNIQUE_GLOBALS + UniqueGlobal("PAD"); +#else + Port("O"); +#endif + Port("I"); + Port("!T"); + SetClass(CLASS_MODULE); + EndCell(); + + + CellDef("BIBUF", -1); +#ifdef USE_UNIQUE_GLOBALS + UniqueGlobal("PAD"); +#else + Port("O"); +#endif + Port("I"); + Port("E"); + Port("IN"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND2", -1); + Port("1"); + Port("2"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND2A", -1); + Port("!1"); + Port("2"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND2B", -1); + Port("!1"); + Port("!2"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND2", -1); + Port("1"); + Port("2"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND2A", -1); + Port("!1"); + Port("2"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND2B", -1); + Port("!1"); + Port("!2"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR2", -1); + Port("1"); + Port("2"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR2A", -1); + Port("!1"); + Port("2"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR2B", -1); + Port("!1"); + Port("!2"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR2", -1); + Port("1"); + Port("2"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR2A", -1); + Port("!1"); + Port("2"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR2B", -1); + Port("!1"); + Port("!2"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND3", -1); + Port("1"); + Port("2"); + Port("3"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND3A", -1); + Port("!1"); + Port("2"); + Port("3"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND3B", -1); + Port("!1"); + Port("!2"); + Port("3"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND3C", -1); + Port("!1"); + Port("!2"); + Port("!3"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND3", -1); + Port("1"); + Port("2"); + Port("3"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND3A", -1); + Port("!1"); + Port("2"); + Port("3"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND3B", -1); + Port("!1"); + Port("!2"); + Port("3"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND3C", -1); + Port("!1"); + Port("!2"); + Port("!3"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR3", -1); + Port("1"); + Port("2"); + Port("3"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR3A", -1); + Port("!1"); + Port("2"); + Port("3"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR3B", -1); + Port("!1"); + Port("!2"); + Port("3"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR3C", -1); + Port("!1"); + Port("!2"); + Port("!3"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR3", -1); + Port("1"); + Port("2"); + Port("3"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR3A", -1); + Port("!1"); + Port("2"); + Port("3"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR3B", -1); + Port("!1"); + Port("!2"); + Port("3"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR3C", -1); + Port("!1"); + Port("!2"); + Port("!3"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND4", -1); + Port("1"); + Port("2"); + Port("3"); + Port("4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND4A", -1); + Port("!1"); + Port("2"); + Port("3"); + Port("4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND4B", -1); + Port("!1"); + Port("!2"); + Port("3"); + Port("4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND4C", -1); + Port("!1"); + Port("!2"); + Port("!3"); + Port("4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AND4D", -1); + Port("!1"); + Port("!2"); + Port("!3"); + Port("!4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND4", -1); + Port("1"); + Port("2"); + Port("3"); + Port("4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND4A", -1); + Port("!1"); + Port("2"); + Port("3"); + Port("4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND4B", -1); + Port("!1"); + Port("!2"); + Port("3"); + Port("4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND4C", -1); + Port("!1"); + Port("!2"); + Port("!3"); + Port("4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NAND4D", -1); + Port("!1"); + Port("!2"); + Port("!3"); + Port("!4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR4", -1); + Port("1"); + Port("2"); + Port("3"); + Port("4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR4A", -1); + Port("!1"); + Port("2"); + Port("3"); + Port("4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR4B", -1); + Port("!1"); + Port("!2"); + Port("3"); + Port("4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR4C", -1); + Port("!1"); + Port("!2"); + Port("!3"); + Port("4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OR4D", -1); + Port("!1"); + Port("!2"); + Port("!3"); + Port("!4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR4", -1); + Port("1"); + Port("2"); + Port("3"); + Port("4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR4A", -1); + Port("!1"); + Port("2"); + Port("3"); + Port("4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR4B", -1); + Port("!1"); + Port("!2"); + Port("3"); + Port("4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR4C", -1); + Port("!1"); + Port("!2"); + Port("!3"); + Port("4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("NOR4D", -1); + Port("!1"); + Port("!2"); + Port("!3"); + Port("!4"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + +/* +INBUF +CLKBUF +OUTBUF +TRIBUF +BIBUF +*/ + + + + + + CellDef("BUF", -1); + Port("I"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("BUFA", -1); + Port("I"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("INV", -1); + Port("I"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("INVA", -1); + Port("I"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("XOR", -1); + Port("1"); + Port("2"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("XNOR", -1); + Port("1"); + Port("2"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); +/* + CellDef("XO1", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("X01A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("XA1", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("XA1A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AX1", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AX1A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AX1B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AO1", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AO1A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AO1B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AO1C", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AOI1A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AOI1B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("MAJ3", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AO2", -1); + Port("A"); + Port("B"); + Port("C"); + Port("4"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AO2A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("4"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AOI2A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("4"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("AOI2B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("4"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA1", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA1A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA1B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA1C", -1); + Port("A"); + Port("B"); + Port("C"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA3", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA3A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA3B", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA2", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("Y"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("OA2A", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("MX2", -1); + Port("A"); + Port("B"); + Port("S"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("MX2A", -1); + Port("A"); + Port("B"); + Port("S"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("MX2B", -1); + Port("A"); + Port("B"); + Port("S"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("MX2C", -1); + Port("A"); + Port("B"); + Port("S"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("MX4", -1); + Port("D0"); + Port("D1"); + Port("D2"); + Port("D3"); + Port("S1"); + Port("S0"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("MXT", -1); + Port("A"); + Port("B"); + Port("C"); + Port("D"); + Port("S0A"); + Port("S0B"); + Port("S1"); + Port("O"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("HA1", -1); + Port("A"); + Port("B"); + Port("CO"); + Port("S"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("HA1A", -1); + Port("A"); + Port("B"); + Port("CO"); + Port("S"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("HA1B", -1); + Port("A"); + Port("B"); + Port("CO"); + Port("S"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("HA1C", -1); + Port("A"); + Port("B"); + Port("CO"); + Port("S"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("FA1A", -1); + Port("A"); + Port("B"); + Port("CI"); + Port("CO"); + Port("S"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("FA1B", -1); + Port("A"); + Port("B"); + Port("CI"); + Port("CO"); + Port("S"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("FA2A", -1); + Port("A0"); + Port("A1"); + Port("B"); + Port("CI"); + Port("CO"); + Port("S"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DL1", -1); + Port("D"); + Port("G"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DL1A", -1); + Port("D"); + Port("G"); + Port("QN"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DL1B", -1); + Port("D"); + Port("G"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DL1C", -1); + Port("D"); + Port("G"); + Port("QN"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DLC", -1); + Port("D"); + Port("G"); + Port("Q"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DLCA", -1); + Port("D"); + Port("G"); + Port("Q"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DLE", -1); + Port("D"); + Port("G"); + Port("Q"); + Port("E"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DLEA", -1); + Port("D"); + Port("G"); + Port("Q"); + Port("E"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DLEB", -1); + Port("D"); + Port("G"); + Port("Q"); + Port("E"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DLEC", -1); + Port("D"); + Port("G"); + Port("Q"); + Port("E"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DLM", -1); + Port("A"); + Port("B"); + Port("S"); + Port("G"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DLMA", -1); + Port("A"); + Port("B"); + Port("S"); + Port("G"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("JKF", -1); + Port("J"); + Port("K"); + Port("CLK"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("JKFPC", -1); + Port("J"); + Port("K"); + Port("CLK"); + Port("Q"); + Port("PRE"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("TFC", -1); + Port("T"); + Port("CLK"); + Port("Q"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFM", -1); + Port("A"); + Port("B"); + Port("S"); + Port("CLK"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFMA", -1); + Port("A"); + Port("B"); + Port("S"); + Port("CLK"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFMB", -1); + Port("A"); + Port("B"); + Port("S"); + Port("CLK"); + Port("Q"); + Port("CLR"); + SetClass(CLASS_MODULE); + EndCell(); +*/ + + CellDef("DF1", -1); + Port("D"); + Port("C"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DF1A", -1); + Port("D"); + Port("C"); + Port("!Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DF1B", -1); + Port("D"); + Port("!C"); + Port("Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DF1C", -1); + Port("D"); + Port("!C"); + Port("!Q"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFC1", -1); + Port("D"); + Port("C"); + Port("Q"); + Port("RD"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFC1A", -1); + Port("D"); + Port("!C"); + Port("Q"); + Port("RD"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFC1B", -1); + Port("D"); + Port("C"); + Port("Q"); + Port("!RD"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFC1C", -1); + Port("D"); + Port("C"); + Port("!Q"); + Port("RD"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFC1D", -1); + Port("D"); + Port("!C"); + Port("Q"); + Port("!RD"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFC1E", -1); + Port("D"); + Port("C"); + Port("!Q"); + Port("!RD"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFC1F", -1); + Port("D"); + Port("!C"); + Port("!Q"); + Port("RD"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFC1G", -1); + Port("D"); + Port("!C"); + Port("!Q"); + Port("!RD"); + SetClass(CLASS_MODULE); + EndCell(); +/* + CellDef("DFP1", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFP1A", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFP1B", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFP1C", -1); + Port("D"); + Port("CLK"); + Port("QN"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFP1D", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFP1E", -1); + Port("D"); + Port("CLK"); + Port("QN"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFP1F", -1); + Port("D"); + Port("CLK"); + Port("QN"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFP1G", -1); + Port("D"); + Port("CLK"); + Port("QN"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFPC", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("CLR"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFPCA", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("CLR"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); +*/ + + CellDef("DFE", -1); + Port("D"); + Port("C"); + Port("Q"); + Port("CE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFEA", -1); + Port("D"); + Port("!C"); + Port("Q"); + Port("CE"); + SetClass(CLASS_MODULE); + EndCell(); + +/* + CellDef("DFEB", -1); + Port("D"); + Port("C"); + Port("Q"); + Port("CE"); + Port("!RD"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFEC", -1); + Port("D"); + Port("CLK"); + Port("Q"); + Port("E"); + Port("CLR"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); + + CellDef("DFED", -1); + Port("D"); + Port("C"); + Port("Q"); + Port("CE"); + Port("PRE"); + SetClass(CLASS_MODULE); + EndCell(); +*/ + + + Debug = OldDebug; + xilinx_lib_present = 1; +} diff --git a/base/xnetgen.c b/base/xnetgen.c new file mode 100644 index 0000000..120aca1 --- /dev/null +++ b/base/xnetgen.c @@ -0,0 +1,2679 @@ +/* "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. */ + + +/* xnetgen.c: X11 interface to netgen */ + +/* + * define ONE of the following: + * + * X11_HP_WIDGETS + * X11_MOTIF_WIDGETS + * X11_ATHENA_WIDGETS + */ + + +#ifdef HAVE_X11 + +#include "config.h" +#include + +/* #define volatile */ /* hacks for /usr/include/sys/types.h */ +/* #define signed */ + +/* #define XLIB_ILLEGAL_ACCESS */ /* hack for SGI---not supposed to use Display->db */ + +#include +#include +#include +#include +#include + +#ifdef HPUX +#undef SIGCHLD +#endif + +#include +#include + +#include "netgen.h" +#include "timing.h" +#include "query.h" +#include "xnetgen.h" +#include "netcmp.h" +#include "objlist.h" +#include "print.h" +#include "dbug.h" + + + + +Widget toplevel = NULL; + +char GlobalFileName[100], + GlobalCellName[100], + GlobalOtherName[100], + GlobalDataName[100]; + +/********************************************************* + * Menu structure: attaches label string to a function, + * and optionally points to a sub-menu. + *********************************************************/ + +typedef struct menu_menu { + char *name; + void (*func)(); + struct menu_menu *submenu; + caddr_t data; +} menu_struct; + + +/********************************************************************** + USER - SUPPLIED ACTION COMMANDS +**********************************************************************/ + +Widget GlobalFileWidget; +Widget GlobalCellWidget; +Widget GlobalOtherWidget; +Widget GlobalDataWidget; + +char *get_file(void); +char *get_cell(void); +char *get_other(void); +char *get_data(void); + +static int timing = 0; +static float StartTime; + +void X_END(void) +{ + if (timing) Printf("Execution time: %0.2f\n", ElapsedCPUTime(StartTime)); + Printf("\n"); + X_display_refresh(); +} + +void X_START(void) +{ + *GlobalFileName = '\0'; + *GlobalCellName = '\0'; + *GlobalOtherName = '\0'; + *GlobalDataName = '\0'; + if (timing) StartTime = CPUTime(); +} + +void no_command(Widget w, Widget textwidget, caddr_t call_data) +{ + XBell(XtDisplay(w), 100); + Printf("No such command!\n"); + X_END(); +} + +void not_yet_implemented(Widget w, Widget textwidget, caddr_t call_data) +{ + XBell(XtDisplay(w), 100); + Printf("Command not yet implemented!\n"); + X_END(); +} + +/******************* OUTPUT FILE FORMATS *****************************/ + +void write_ntk(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Ntk(get_cell(), NULL); + X_END(); +} + +void write_actel(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Actel(get_cell(), NULL); + X_END(); +} + +void write_wombat(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Wombat(get_cell(), NULL); + X_END(); +} + +void write_ext(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Ext(get_cell()); + X_END(); +} + +void write_sim(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Sim(get_cell()); + X_END(); +} + +void write_spice(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + SpiceCell(get_cell(), -1, NULL); + X_END(); +} + +void write_esacap(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + EsacapCell(get_cell(), NULL); + X_END(); +} + +void write_ccode(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Ccode(get_cell(), NULL); + X_END(); +} + +void write_netgen(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + WriteNetgenFile(get_cell(), NULL); + X_END(); +} + +static menu_struct WriteMenu[] = { + { "NTK", write_ntk, NULL, NULL }, + { "Actel", write_actel, NULL, NULL }, + { "Wombat", write_wombat, NULL, NULL }, + { "Spice", write_spice, NULL, NULL }, + { "Esacap", write_esacap, NULL, NULL }, + { "Netgen", write_netgen, NULL, NULL }, + { "Ext", write_ext, NULL, NULL }, + { "Sim", write_sim, NULL, NULL }, + { "C code", write_ccode, NULL, NULL }, + { NULL } +}; + + +/******************* INPUT FILE FORMATS *****************************/ + +void read_ntk(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + ReadNtk(get_file()); + X_END(); +} + +void read_actel(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Printf("Reading ACTEL library.\n"); + X_END(); +} + +void read_ext(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + ReadExtHier(get_file()); + X_END(); +} + +void read_sim(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + ReadSim(get_file()); + X_END(); +} + +void read_spice(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + ReadSpice(get_file()); + X_END(); +} + +void read_netgen(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + ReadNetgenFile(get_file()); + X_END(); +} + +static menu_struct ReadMenu[] = { + { "NTK", read_ntk, NULL, NULL }, + { "Actel Library", read_actel, NULL, NULL }, + { "Spice", read_spice, NULL, NULL }, + { "Ext", read_ext, NULL, NULL }, + { "Sim", read_sim, NULL, NULL }, + { "Netgen", read_netgen, NULL, NULL }, + { NULL } +}; + + +/**************************** NETCMP MENU ****************************/ + +void initialize_netcmp_datastructures(Widget w, Widget textwidget, + caddr_t call_data) +{ + X_START(); + Printf("Comparing cells '%s' and '%s'\n", get_cell(), get_other()); + CreateTwoLists(get_cell(), get_other()); + Permute(); +#ifdef DEBUG_ALLOC + PrintCoreStats(); +#endif + X_END(); +} + +void iterate_netcmp(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + if (!Iterate()) Printf("Please iterate again\n"); + else Printf("No fractures made: NETCMP has converged\n"); + X_END(); +} + +void print_netcmp_automorphisms(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + PrintAutomorphisms(); + X_END(); +} + +void resolve_automorphisms(Widget w, Widget textwidget, caddr_t call_data) +{ + int automorphisms; + + X_START(); + while ((automorphisms = ResolveAutomorphisms()) > 0) ; + if (automorphisms == -1) Printf("Graphs do not match.\n"); + else Printf("Circuits match correctly.\n"); + X_END(); +} + +void converge_netcmp(Widget w, Widget textwidget, caddr_t call_data) +{ + int automorphisms; +#if 1 + X_START(); + while (!Iterate()) ; + automorphisms = VerifyMatching(); + if (automorphisms == -1) Printf("Graphs do not match.\n"); + else { + if (automorphisms) + Printf("Circuits match with %d automorphisms\n", automorphisms); + else Printf("Circuits match correctly.\n"); + } + X_END(); +#else + while (!Iterate()) ; + /* go check automorphisms */ + print_netcmp_automorphisms(w, textwidget, call_data); +#endif +} + +void print_netcmp_classes(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + PrintElementClasses(ElementClasses, -1, 0); + PrintNodeClasses(NodeClasses, -1, 0); + X_END(); +} + +void verify_netcmp(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + if (ElementClasses == NULL || NodeClasses == NULL) + Printf("Must initialize data structures first\n"); + else { + int automorphisms; + automorphisms = VerifyMatching(); + if (automorphisms == -1) Printf("Graphs do not match.\n"); + else { + if (automorphisms) + Printf("Circuits match with %d automorphisms\n", automorphisms); + else Printf("Circuits match correctly.\n"); + } + } + X_END(); +} + +void equivalence_netcmp_elements(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Printf("Equivalence elements '%s' and '%s'\n", get_data(), get_other()); + if (EquivalenceElements(get_data(), -1, get_other(), -1)) + Printf("Done.\n"); + else Printf("Unable to equivalence elements %s and %s\n", + get_data(), get_other()); + X_END(); +} + +void equivalence_netcmp_nodes(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Printf("Equivalence nodes '%s' and '%s'\n", get_data(), get_other()); + if (EquivalenceNodes(get_data(), -1, get_other(), -1)) + Printf("Done.\n"); + else Printf("Unable to equivalence nodes %s and %s\n", + get_data(), get_other()); + X_END(); +} + +void permute_netcmp_pins(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Printf("Cell '%s': permuting pins '%s' and '%s'\n", + get_cell(), get_data(), get_other()); + if (PermuteSetup(get_cell(), -1, get_data(), get_other())) + Printf("%s == %s\n",get_data(), get_other()); + else Printf("Unable to permute pins %s, %s\n",get_data(), get_other()); + X_END(); +} + +void permute_netcmp_transistors(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + if (PermuteSetup("n", -1, "drain", "source")) + Printf("n-channel: source == drain\n"); + if (PermuteSetup("p", -1, "drain", "source")) + Printf("p-channel: source == drain\n"); + if (PermuteSetup("e", -1, "bottom_a", "bottom_b")) + Printf("poly cap: permuting poly1 regions\n"); + if (PermuteSetup("r", -1, "end_a", "end_b")) + Printf("resistor: permuting endpoints\n"); + if (PermuteSetup("c", -1, "bot", "top")) + Printf("capacitor: permuting sides\n"); + X_END(); +} + +void exhaustive_netcmp_subdivision(Widget w, Widget textwidget, + caddr_t call_data) +{ + X_START(); + ExhaustiveSubdivision = !ExhaustiveSubdivision; + Printf("Exhaustive subdivision %s\n", + ExhaustiveSubdivision ? "ENABLED" : "DISABLED"); + X_END(); +} + +void restart_netcmp(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Printf("Resetting NETCMP data structures\n"); + RegroupDataStructures(); + X_END(); +} + +void summarize_netcmp_data(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + SummarizeElementClasses(ElementClasses); + SummarizeNodeClasses(NodeClasses); + X_END(); +} + +void sleep_ten_seconds(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + sleep(10); + X_END(); +} + +static menu_struct NetcmpMenu[] = { + { "Initialize", initialize_netcmp_datastructures, NULL, NULL }, + { "Iterate", iterate_netcmp, NULL, NULL }, + { "Converge", converge_netcmp, NULL, NULL }, + { "Print classes", print_netcmp_classes, NULL, NULL }, + { "Verify results", verify_netcmp, NULL, NULL }, + { "Print automorphisms", print_netcmp_automorphisms, NULL, NULL }, + { "Resolve automorphisms", resolve_automorphisms, NULL, NULL }, + { "Equivalence elements", equivalence_netcmp_elements, NULL, NULL }, + { "Equivalence nodes", equivalence_netcmp_nodes, NULL, NULL }, + { "Permute pins", permute_netcmp_pins, NULL, NULL }, + { "Permute source/drains", permute_netcmp_transistors, NULL, NULL }, + { "Exhaustive subdivision", exhaustive_netcmp_subdivision, NULL, NULL }, + { "Restart algorithm", restart_netcmp, NULL, NULL }, + { "Summarize datastructures", summarize_netcmp_data, NULL, NULL }, + { "SLEEP", sleep_ten_seconds, NULL, NULL}, + { NULL } +}; + +/**************************** PROTO MENU ****************************/ + + +/* embedding sub-menu */ + +void proto_embed_greedy(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + ProtoEmbed(get_cell(), 'g'); + X_END(); +} + +void proto_embed_anneal(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + ProtoEmbed(get_cell(), 'a'); + X_END(); +} + +void proto_embed_random(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + ProtoEmbed(get_cell(), 'r'); + X_END(); +} + +void proto_embed_bottup(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + ProtoEmbed(get_cell(), 'o'); + X_END(); +} + + +static menu_struct ProtoEmbedMenu[] = { + { "Greedy", proto_embed_greedy, NULL, NULL }, + { "Anneal", proto_embed_anneal, NULL, NULL }, + { "Random", proto_embed_random, NULL, NULL }, + { "BottomUp", proto_embed_bottup, NULL, NULL }, + { NULL } +}; + + +/* show-parameters sub-menu */ + +void proto_print_parameters(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + ProtoPrintParameters(); + X_END(); +} + +void proto_leaf_pinout(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + SetupLeafPinout(get_other()); + X_END(); +} + +void proto_rent_exp(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + SetupRentExp(get_other()); + X_END(); +} + +void proto_tree_fanout(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + SetupTreeFanout(get_other()); + X_END(); +} + +void proto_min_common_nodes(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + SetupMinCommonNodes(get_other()); + X_END(); +} + +void proto_min_used_leaves(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + SetupMinUsedLeaves(get_other()); + X_END(); +} + +static menu_struct ProtoConstMenu[] = { + { "Show parameters", proto_print_parameters, NULL, NULL }, + { "Leaf pinout", proto_leaf_pinout, NULL, NULL }, + { "Rent's rule exp", proto_rent_exp, NULL, NULL }, + { "Tree fanout", proto_tree_fanout, NULL, NULL }, + { "Common node reqs", proto_min_common_nodes, NULL, NULL }, + { "Leaf containment", proto_min_used_leaves, NULL, NULL }, + { NULL } +}; + + +void proto_toggle_logging(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + ToggleLogging(); + X_END(); +} + +void proto_toggle_exhaustive(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + ToggleExhaustive(); + X_END(); +} + +void proto_toggle_debug(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + ToggleDebug(); + X_END(); +} + +void proto_describe_cell(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + DescribeCell(get_cell(), 0); + X_END(); +} + + + +static menu_struct ProtoMenu[] = { + { "PROTOCHIP parameters", no_command, ProtoConstMenu, NULL }, + { "Embed cell", no_command, ProtoEmbedMenu, NULL }, + { "Toggle logging", proto_toggle_logging, NULL, NULL }, + { "Toggle exhaustive", proto_toggle_exhaustive, NULL, NULL }, + { "Toggle debug", proto_toggle_debug, NULL, NULL }, + { "Describe cell", proto_describe_cell, NULL, NULL }, + { NULL } +}; + + + +/**************************** PRINT MENU ******************************/ + + +void print_cell(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Printf("Contents of cell: %s\n", get_cell()); + PrintCell(get_cell()); + X_END(); +} + +void print_instances(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Printf("Instances within cell: %s\n", get_cell()); + PrintInstances(get_cell()); + X_END(); +} + +void describe_instance(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Printf("Describe instance: %s\n", get_cell()); + DescribeInstance(get_cell(), -1); + X_END(); +} + +void print_nodes(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Printf("Nodes in cell: %s\n", get_cell()); + PrintNodes(get_cell(), -1); + X_END(); +} + +void print_nodes_connected_to(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Fanout(get_cell(), get_data(), NODE); + X_END(); +} + +void print_element(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Printf("In cell %s\n", get_cell()); + PrintElement(get_cell(), get_data()); + X_END(); +} + +void print_ports(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Printf("Ports in cell: %s\n", get_cell()); + PrintPortsInCell(get_cell(), -1); + X_END(); +} + +void print_leaves(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Printf("Leaves in cell: %s\n", get_cell()); + PrintLeavesInCell(get_cell(), -1); + X_END(); +} + + +static menu_struct PrintMenu[] = { + { "Print cell", print_cell, NULL, NULL}, + { "Print nodes", print_nodes, NULL, NULL}, + { "Print fanout", print_nodes_connected_to, NULL, NULL}, + { "Print element", print_element, NULL, NULL}, + { "Print instances", print_instances, NULL, NULL}, + { "Describe instance", describe_instance, NULL, NULL}, + { "Print ports", print_ports, NULL, NULL}, + { "Print leaves", print_leaves, NULL, NULL}, + { NULL } +}; + + +/**************************** MAIN MENU *******************************/ + +void list_cells(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + PrintCellHashTable(1, -1); + X_END(); +} + +void read_cell(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Printf("Read file: %s\n", get_file()); + ReadNetlist(get_file()); + X_END(); +} + +void flatten_cell(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Printf("Flatten cell: %s\n", get_cell()); + Flatten(get_cell(), -1); + X_END(); +} + +void flatten_instances_of(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Printf("Flatten instances of: %s\n", get_cell()); + FlattenInstancesOf(get_cell()); + X_END(); +} + + +void print_all_leaves(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Printf("Leaves\n"); + PrintAllLeaves(); + X_END(); +} + +void dbug_command(Widget w, Widget textwidget, caddr_t call_data) +{ + X_START(); + Printf("DBUG command: %s\n", get_data()); + DBUG_PUSH(get_data()); + X_END(); +} + +void read_command_file(Widget w, Widget textwidget, caddr_t call_data) +{ + FILE *oldfile; + + X_START(); + Printf("Reading command file: %s\n", get_file()); + oldfile = promptstring_infile; + promptstring_infile = fopen(get_file(), "r"); + if (promptstring_infile == NULL) + Printf("Unable to open command file: %s\n", get_file()); + else { + Query(); + fclose(promptstring_infile); + Printf("Finished executing command file: %s\n", get_file()); + } + promptstring_infile = oldfile; + X_END(); +} + +void dump_screen_to_file(Widget w, Widget textwidget, caddr_t call_data) +/* toggle dumping log file based on status of LoggingFile */ +{ + Arg Args[10]; + int n; + + X_START(); + n = 0; + XtSetArg(Args[n], XtNstring, "TOGGLE LOG"); n++; + XtSetValues(w, Args, n); + + if (LoggingFile == NULL) { + /* install logging file */ + FILE *file; + file = fopen(get_file(), "r"); + if (file != NULL && strlen(get_file()) != 0) { + Printf("File %s exists already. Output written to 'netgen.log'.\n", + get_file()); + fclose(file); + file = fopen("netgen.log", "w"); + } + else file = fopen(get_file(), "w"); + if (file == NULL) Printf("Unable to open file.\n"); + else { + Printf("Logging enabled.\n"); + LoggingFile = file; + } +#if 0 + /* dump the contents of the main window, line by line */ + int i; + for (i = 0; i < data.nitems; i++) { + fputs(data.chars[i], file); + fputs("\n", file); + } +#endif + } + else { + /* log file is open, so close it */ + fclose(LoggingFile); + LoggingFile = NULL; + Printf("Logging file closed.\n"); + } + X_END(); +} + + +void toggle_timing(Widget w, Widget textwidget, caddr_t call_data) +{ + if (timing) { + Printf("Timing disabled.\n"); + timing = 0; + X_END; + } + else { + Printf("Timing of commands enabled.\n"); + StartTime = CPUTime(); + X_END(); + timing = 1; + } +} + + +void quit(Widget w, Widget textwidget, caddr_t call_data) +{ + if (LoggingFile != NULL) fclose(LoggingFile); + XtDestroyWidget(toplevel); + exit(0); +} + + +static menu_struct Menu[] = { + { "List cells", list_cells, NULL, NULL}, + { "Print", no_command, PrintMenu, NULL}, + { "Flatten cell", flatten_cell, NULL, NULL}, + { "Flatten instances of", flatten_instances_of, NULL, NULL}, + { "List all leaves", print_all_leaves, NULL, NULL}, + { "Read cell", read_cell, ReadMenu, NULL }, + { "Write cell", no_command, WriteMenu, NULL }, +/* + how to create a popup menu + { "popup", pop_it_up, NULL, NULL}, +*/ + { "NETCMP", no_command, NetcmpMenu, NULL}, + { "PROTOCHIP", no_command, ProtoMenu, NULL}, + { "DBUG command", dbug_command, NULL, NULL}, + { "Read command file", read_command_file, NULL, NULL}, + { "Toggle log file", dump_screen_to_file, NULL, NULL}, + { "Toggle timing", toggle_timing, NULL, NULL}, + { "Quit", quit, NULL, NULL}, + { NULL } +}; + +#if 0 +#define ItemsInMenu(a) (sizeof (a) / sizeof(a[0])) +#else +int ItemsInMenu(menu_struct *menulist) +{ + menu_struct *p; + int i; + + i = 0; + for (p = menulist; p->name != NULL; p++) i++; + return(i); +} +#endif + + +#if defined(X11_MOTIF_WIDGETS) || defined(X11_ATHENA_WIDGETS) + +/* menu stuff: emulate menus with persistent list widgets */ + +struct menu_list { + Widget widget; + menu_struct *menu; +}; + +/* the first component is the List widget that emulates the menu */ +struct menu_list MenuArray[] = { + {NULL, Menu}, + {NULL, WriteMenu}, + {NULL, ReadMenu}, + {NULL, PrintMenu}, + {NULL, NetcmpMenu}, + {NULL, ProtoEmbedMenu}, + {NULL, ProtoConstMenu}, + {NULL, ProtoMenu}, +}; +#endif /* MOTIF or ATHENA */ + + + +#ifdef X11_HP_WIDGETS + +/**********************************************************************/ +/* HP-Widget-specific code follows: */ +/**********************************************************************/ + + +#undef INTERNAL_ARGS +#define CELL_LIST_MENU + +#undef INCLUDE_FALLBACK /* requires R4 Toolkit */ + +#include +#include +#include +#include + +#include +#include +#include + +/* these are for the menus */ +#include +#include +#include +#include + +/* for the one-line editor */ +#include +#include + +#include +#include + +#include +#include +#include + + +#define MAXLINESIZE 300 +#define MAXLINES 200 +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MARGIN 5 + +typedef struct { + char *chars[MAXLINES]; /* Lines of text */ + int ll[MAXLINES]; /* Length of each line */ + int rbearing[MAXLINES]; /* right bearing of each line */ + int descent; /* descent below baseline */ + int foreground, /* Color used for text */ + background; + XFontStruct *font; /* The font struct */ + GC gc; /* A read/write GC */ + GC gcread; /* A read-only GC */ + Widget scrollbar; + Widget canvas; + Dimension canvas_height; /* canvas dimensions */ + Dimension canvas_width; + int fontheight; /* descent + ascent */ + int nitems; /* number of text lines */ + int top; /* line at top of window */ +} text_data, *text_data_ptr; + +text_data data; +text_data cells; + + +static XtResource resources[] = { + { XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), + XtOffset(text_data_ptr, font), XtRString, "Fixed" }, + { XtNforeground, XtCForeground, XtRPixel, sizeof(int), + XtOffset(text_data_ptr, foreground), XtRString, "Black"}, + { XtNbackground, XtCBackground, XtRPixel, sizeof(int), + XtOffset(text_data_ptr, background), XtRString, "White"} +}; + +String fallback_resources[] = { + "*yResizeable: True", + "*yAttachBottom: True", + NULL, + }; + +char *get_file(void) +{ + return (XwTextCopyBuffer(GlobalFileWidget)); +} + +char *get_cell(void) +{ + return (XwTextCopyBuffer(GlobalCellWidget)); +} + +char *get_other(void) +{ + return (XwTextCopyBuffer(GlobalOtherWidget)); +} + +char *get_data(void) +{ + return (XwTextCopyBuffer(GlobalDataWidget)); +} + + +add_line(text_data *data, char *buf) +{ + /* this should be followed by a "refresh" as soon as possible */ + int foreground, background, dir, ascent, desc; + XCharStruct char_info; + int i; + +#define JUMPSIZE 40 + if (data->nitems >= MAXLINES) { + /* need to shuffle everything forward */ + for (i = 0; i < JUMPSIZE; i++) XtFree(data->chars[i]); + + for (i = JUMPSIZE; i < MAXLINES; i++) { + data->chars[i-JUMPSIZE] = data->chars[i]; + data->ll[i - JUMPSIZE] = data->ll[i]; + data->rbearing[i - JUMPSIZE] = data->rbearing[i]; + } + data->nitems -= JUMPSIZE; + data->top -= JUMPSIZE; + } + + i = data->nitems; + data->chars[i] = XtMalloc(strlen(buf) + 1); + strcpy(data->chars[i], buf); + data->ll[i] = strlen(data->chars[i]); + XTextExtents(data->font, data->chars[i], data->ll[i], &dir, &ascent, + &desc, &char_info); + data->rbearing[i] = char_info.rbearing; + data->descent = desc; + data->fontheight = ascent + desc; + while ((data->nitems - data->top) * data->fontheight > data->canvas_height) + (data->top)++; + + (data->nitems)++; +} + + +void X_display_line(char *buf) +{ + char *pt, *tmpbuf, *startpt; + + if (toplevel == NULL) { + /* not using X windows */ + printf("%s", buf); + return; + } + tmpbuf = XtMalloc(strlen(buf) + 1); + strcpy(tmpbuf, buf); +#if 1 + /* eat last char if it is a '\n' */ + pt = strrchr(tmpbuf, '\n'); + if (pt != NULL && *(pt+1) == '\0') *pt = '\0'; + + pt = tmpbuf; + startpt = tmpbuf; + for (pt = tmpbuf; *pt != '\0'; pt++) { + if (*pt == '\n') { + /* flush this as a single line */ + *pt = '\0'; + add_line(&data, startpt); + *pt = 'a'; /* anything non-null */ + startpt = pt + 1; + } + } + add_line(&data, startpt); +#else + pt = tmpbuf; + startpt = tmpbuf; + while (*pt != '\0') { + if (*pt == '\n') { + /* eat trailing newlines */ + if (*(pt+1) != '\0') { + *pt = '\0'; + add_line(&data, startpt); + startpt = ++pt; + } + } + else pt++; + if (*pt == '\0') add_line(&data, startpt); + } +#endif + XtFree(tmpbuf); +} + +void X_display_cell(char *buf) +{ + /* should be the same as X_display_line above */ + add_line(&cells, buf); +} + + +load_file(text_data *data, char *filename) +{ + FILE *fp, *fopen(); + char buf[MAXLINESIZE]; + /* Open the file. */ + if ((fp = fopen(filename, "r")) == NULL) { + fprintf(stderr, "Unable to open %s\n", filename); + exit(1); + } + /* Read each line of the file into the buffer */ + while ((fgets(buf, MAXLINESIZE, fp)) != NULL) { + buf[strlen(buf) - 1] = '\0'; /* strip NL at end */ + add_line(data, buf); + } + + /* Close the file. */ + fclose(fp); +} + + + + +load_cells(text_data *cells) +{ + int i; + char buf[MAXLINESIZE]; + + i = 0; + for (i = 0; i < 10; i++) { + sprintf(buf, "line %d", i); + add_line(cells, buf); + } +} + +void scroll_bar_moved(Widget w, text_data *data, int sliderpos) +{ + XPoint points[4]; + Region region; + int xsrc, ysrc, xdest, ydest; + /* These points are the same for both cases, so set them here. */ + points[0].x = points[3].x = 0; + points[1].x = points[2].x = data->canvas_width; + xsrc = xdest = 0; + +/* fprintf(stderr,"items = %d; slider pos = %d; lines = %d\n", + data->nitems, sliderpos, data->canvas_height / data->fontheight); */ + if (sliderpos < data->top) { /* If we are scrolling down... */ + ysrc = 0; + /* Convert the slider's position (rows) to pixels. */ + ydest = (data->top - sliderpos) * data->fontheight; + /* Limit the destination to the window height. */ + if (ydest > data->canvas_height) + ydest = data->canvas_height; + /* Fill in the points array with the bounding box of the area that needs + to be redrawn - that is, the area that is not copied. */ + points[1].y = points[0].y = 0; + points[3].y = points[2].y = ydest + data->fontheight; + } else { /* If we are scrolling up... */ + ydest = 0; + /* Convert the slider's position (rows) to pixels. */ + ysrc = (sliderpos - data->top) * data->fontheight; + /* Limit the source to the window height. */ + if (ysrc > data->canvas_height) + ysrc = data->canvas_height; + /* Fill in the points array with the bounding box of the area that needs + to be redrawn. This area cannot be copied and must be redrawn. */ + points[1].y = points[0].y = data->canvas_height - ysrc; + points[2].y = points[3].y = data->canvas_height; + } + /* Set the top line of the text buffer. */ + data->top = sliderpos; + /* Copy the scrolled region to its new position. */ + XCopyArea(XtDisplay(data->canvas), XtWindow(data->canvas), + XtWindow(data->canvas), data->gcread, xsrc, ysrc, + data->canvas_width, data->canvas_height, xdest, ydest); + /* Clear the remaining area of any old text. */ + XClearArea(XtDisplay(w), XtWindow(data->canvas), points[0].x, points[0].y, + 0, points[2].y - points[0].y, 0); + /* Create a region from the points array, and call the XtNexpose callback + with the calculated region as call_data. */ + region = XPolygonRegion(points, 4, EvenOddRule); + XtCallCallbacks(data->canvas, XtNexpose, region); + /* Free the region. */ + XDestroyRegion(region); +} + +/****************************************************** + * slider.c: utility to make slider move to the sprite + * location when clicking the background of + * a scrollbar widget. + ******************************************************/ + +void slider_selected(Widget w, caddr_t ignore, int sliderpos) +{ + Arg Args[1]; + /* Move the slider bar to the selected point. */ + XtSetArg(Args[0], XtNsliderOrigin, sliderpos); + XtSetValues(w, Args, 1); + /* Call the callback list for XtNsliderMoved to + alter the colors appropriately. */ + XtCallCallbacks(w, XtNsliderMoved, sliderpos); +} + + +create_scrollbar(Widget parent, text_data *data) +{ + int n = 0; + Arg Args[10]; + + n = 0; +#ifdef INTERNAL_ARGS + XtSetArg(Args[n], XtNyResizable, (XtArgVal)True); n++; + XtSetArg(Args[n], XtNyAttachBottom, (XtArgVal)True); n++; + XtSetArg(Args[n], XtNxResizable, (XtArgVal)True); n++; + XtSetArg(Args[n], XtNxRefName, (XtArgVal)"scrollbar"); n++; + XtSetArg(Args[n], XtNxAddWidth, (XtArgVal)True); n++; + XtSetArg(Args[n], XtNxAttachRight, (XtArgVal)True); n++; +#endif + + data->scrollbar = XtCreateManagedWidget("scrollbar", XwscrollbarWidgetClass, + parent, NULL, 0); + XtAddCallback(data->scrollbar, XtNsliderMoved, scroll_bar_moved, data); + XtAddCallback(data->scrollbar, XtNareaSelected, slider_selected, data); + + /* Scrollbar movements are reported in terms of lines of text. */ + n = 0; + XtSetArg(Args[n], XtNsliderMin, 0); n++; + XtSetArg(Args[n], XtNsliderMax, 2*(data->nitems)); n++; + XtSetArg(Args[n], XtNsliderOrigin, data->top); n++; + XtSetArg(Args[n], XtNsliderExtent, data->nitems); n++; + XtSetValues(data->scrollbar, Args, n); +} + + +void refresh(text_data *data) +{ + /* redraw the data window, setting the valuator as required + to put the last line at the bottom */ + + int lines; + Arg Args[8]; + int n; + int bottom_of_screen, slider_size; + XPoint points[4]; + Region region; + + lines = 1; + if (data->fontheight == 0) bottom_of_screen = 0; + else { + lines = data->canvas_height / data->fontheight; + + if (lines > data->nitems) data->top = 0; + else + if (data->nitems - data->top > lines) data->top = data->nitems - lines; + + /* scrollbar movements are reported in terms of lines of text. */ + + bottom_of_screen = data->nitems - (data->canvas_height / data->fontheight); + if (bottom_of_screen <= 0) bottom_of_screen = 0; + } + /* fprintf(stderr,"bottom of screen = %d\n",bottom_of_screen); */ + + /* set up the valuator */ + n = 0; + XtSetArg(Args[n], XtNsliderMin, 0); n++; + XtSetArg(Args[n], XtNsliderMax, bottom_of_screen + lines); n++; + XtSetArg(Args[n], XtNsliderOrigin, data->top); n++; + XtSetArg(Args[n], XtNsliderExtent, lines); n++; + XtSetValues(data->scrollbar, Args, n); + + /* Redraw the entire canvas */ + points[0].x = points[3].x = 0; + points[1].x = points[2].x = data->canvas_width; + points[1].y = points[0].y = 0; + points[2].y = points[3].y = data->canvas_height; + + /* Clear the remaining area of any old text. */ + XClearArea(XtDisplay(data->canvas), XtWindow(data->canvas), + points[0].x, points[0].y, 0, points[2].y - points[0].y, 0); + /* Create a region from the points array, and call the XtNexpose callback + with the calculated region as call_data. */ + region = XPolygonRegion(points, 4, EvenOddRule); + XtCallCallbacks(data->canvas, XtNexpose, region); + /* Free the region. */ + XDestroyRegion(region); +} + +void X_display_refresh(void) +{ + if (toplevel == NULL) return; + refresh(&cells); + refresh(&data); +} + +void X_clear_display(void) +{ + int i; + + for (i = 0; i < data.nitems; i++) XtFree(data.chars[i]); + data.top = data.nitems = 0; + refresh(&data); +} + +void X_clear_cell(void) +{ + int i; + + for (i = 0; i < cells.nitems; i++) XtFree(cells.chars[i]); + cells.top = cells.nitems = 0; + refresh(&cells); +} + +create_gcs(text_data *data) +{ + XGCValues gcv; + Display *dpy = XtDisplay(data->canvas); + Window w = XtWindow(data->canvas); + int mask = GCFont | GCForeground | GCBackground; + int read_only_mask = GCForeground | GCBackground; + /* Create two graphics contexts. One is modifiable, one is read only. */ + gcv.foreground = data->foreground; + gcv.background = data->background; + gcv.font = data->font->fid; + data->gc = XCreateGC(dpy, w, mask, &gcv); + data->gcread = XtGetGC(data->canvas, read_only_mask, &gcv); +} + + +void handle_exposures(Widget w, text_data *data, Region region) +{ + int yloc = 0, index = data->top; + /* Set the clip mask of the GC. */ + XSetRegion(XtDisplay(w), data->gc, region); + /* Loop through each line until the bottom of the window is reached, + or we run out of lines. Redraw lines that intersect the exposed region */ + while (index < data->nitems && yloc < data->canvas_height) { + yloc += data->fontheight; + if (XRectInRegion(region, 0, yloc - data->fontheight, data->canvas_width, + data->fontheight) != RectangleOut) + XDrawImageString(XtDisplay(w), XtWindow(w), data->gc, MARGIN, yloc, + data->chars[index], data->ll[index]); + index++; + } +} + + +void getsize(Widget w, text_data *data, caddr_t call_data) +{ + Arg Args[2]; + + XtSetArg(Args[0], XtNheight, &data->canvas_height); + XtSetArg(Args[1], XtNwidth, &data->canvas_width); + XtGetValues(w, Args, 2); +} + + +/*********************************************************** + * one_line.c: Create a single line editable text field + ***********************************************************/ + +/* Just ring the terminal bell. */ +static void beep(Widget w, XEvent *event, String *params, int num_params) +{ + /* XBell(XtDisplay(w), 100); */ +} + +/* Associate the action "beep" with the function. */ +static XtActionsRec actionsTable[] = { + { "beep", beep }, +}; +/* + * Override all translations that enter a newline. + */ +static char defaultTranslations[] = + "CtrlJ: beep() \n\ + CtrlO: beep() \n\ + CtrlM: beep() \n\ + Return: beep()"; + +Widget create_one_line_text_widget(char *name, Widget parent) +{ + XFontStruct *font; + Widget w; + Arg Args[1]; + XtTranslations trans_table; + /* Add the actions and compile the translations. */ + XtAddActions(actionsTable, XtNumber(actionsTable)); + trans_table = XtParseTranslationTable(defaultTranslations); + /* Create a TextEdit widget. */ + XtSetArg(Args[0], XtNeditType, XwtextEdit); + w = XtCreateManagedWidget(name, XwtexteditWidgetClass, parent, Args, 1); + /* Install our translations. */ + XtOverrideTranslations(w, trans_table); + /* Get the font used by the widget. */ + XtSetArg(Args[0], XtNfont, &font); + XtGetValues(w, Args, 1); + /* Set the widget height according to the font height. */ +#define FONTHEIGHT(f) ((f)->max_bounds.ascent + (f)->max_bounds.descent) + + XtSetArg(Args[0], XtNheight, FONTHEIGHT(font) + 6); + XtSetValues(w, Args, 1); + + return(w); +} + +/**************************************************************************/ + +Widget create_menu_manager(Widget parent, char *mgrname) +{ + Widget shell = XtCreatePopupShell(mgrname, shellWidgetClass, parent, NULL,0); + Widget menu_mgr = + XtCreateManagedWidget(mgrname, XwpopupmgrWidgetClass, shell, NULL, 0); + return(menu_mgr); +} + + +void create_pane(Widget mgr, char *mgrname, char *name, + menu_struct *menulist, int nitems) +{ + Arg Args[1]; + Widget menupane, pane_shell; + int i; + WidgetList buttons; + /* Allocate a widget list to hold all button widgets. */ + buttons = (WidgetList) XtMalloc(nitems * sizeof(Widget)); + /* Create a popup shell to hold this pane. */ + pane_shell = XtCreatePopupShell("pane_shell", shellWidgetClass, mgr, + NULL, 0); + /* Create a Cascade menu pane, and attach it to the given menu manager. */ + XtSetArg(Args[0], XtNattachTo, (XtArgVal) mgrname); + menupane = XtCreateManagedWidget(name, XwcascadeWidgetClass, pane_shell, + Args, 1); + /* Create a menu button for each item in the menu. */ + for (i = 0; i < nitems; i++) { + buttons[i] = XtCreateWidget(menulist[i].name, XwmenubuttonWidgetClass, + menupane, NULL, 0); + XtAddCallback(buttons[i], XtNselect, menulist[i].func, menulist[i].data); + } + /* Manage all button widgets. */ + XtManageChildren(buttons, nitems); +} + + +/******************************************************* + Popup widgetry -- not currently used, but good to have around +*********************************************************/ + + +static char *fields[] = { "field1", "field2", "field3" }; +static char *labels[] = { "label1", "label2", "label3" }; + +void pop_it_down(Widget w, caddr_t client_data, caddr_t call_data) +{ + Widget bb, shell; + + bb = XtParent(w); + shell = XtParent(bb); + + XtPopdown(shell); + XtDestroyWidget(shell); +} + + +Widget create_filename_editor(Widget parent) +{ + Widget bb, popup, button; + + popup = + XtCreatePopupShell ("popup", overrideShellWidgetClass, parent, NULL, 0); + /* Create a BulletinBoard widget to hold the fields. */ + bb = XtCreateManagedWidget("board", XwbulletinWidgetClass, popup, NULL, 0); + + /* Create a "done" button and register a popdown callback. */ + button = XtCreateManagedWidget("done", XwpushButtonWidgetClass, bb, NULL, 0); + XtAddCallback(button, XtNrelease, pop_it_down, NULL); + + create_one_line_text_widget("field1",bb); + return popup; +} + + +void pop_it_up(Widget w, caddr_t client_data, caddr_t call_data) +{ + Widget shell; + Window root, child; + int root_x, root_y, win_x, win_y, mask; + + XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child, &root_x, + &root_y, &win_x, &win_y, &mask); + + shell = create_filename_editor(w); + + XtRealizeWidget(shell); + XtMoveWidget(shell, root_x - 30, root_y - 20); + + XtPopup(shell, XtGrabExclusive); +} + +/*********************************************************************/ + +Widget label_widget(Widget parent, char *string) +{ + Arg Args[10]; + int n; + + n = 0; + XtSetArg(Args[n], XtNstring, string); n++; + return XtCreateManagedWidget + ("label", XwstatictextWidgetClass, parent, Args, n); +} + +static jmp_buf jmpenv; + +static void handler() +/* static void handler(int sig) */ +{ + Fprintf(stderr,"\nInterrupt!!\n"); + Fflush(stderr); + X_END(); + longjmp(jmpenv,1); +} + + +static XrmOptionDescRec opTable[] = { +{"-sadfa","Netgen*yResizable", XrmoptionNoArg, (caddr_t) "True"}, +{"-sszyys","Netgen*yAttachBottom", XrmoptionNoArg, (caddr_t) "True"}, +}; + +/*char datastring[] = "*yResizable: True\n*yAttachBottom: True";*/ +char datastring[] = "*yAttachBottom: True"; + +/* +Fileview*canvas.xRefName: scrollbar +Fileview*canvas.xResizable: True +Fileview*canvas.xAddWidth: True +Fileview*canvas.xAttachRight: True +Fileview*canvas.yAttachTop: True +*/ + +void X_main_loop(int argc, char *argv[]) +{ + /* toplevel widget is global */ + Widget pane, frame, cells_frame, menu_mgr, title, data_entry; + Arg Args[10]; + int n; + XrmDatabase rdb; + + + /* if we're not using X, just call good old Query(); */ + if (getenv("DISPLAY") == NULL) { + Query(); + return; + } + +/* Xnetgen used to be Fileview */ +#ifdef INCLUDE_FALLBACK + XtAppContext app_con; + toplevel = XtAppInitialize(&app_con, "NewNetgen", NULL, 0, + &argc, argv, fallback_resources, NULL, 0); +#else + toplevel = XtInitialize(argv[0], "Netgen", + opTable, XtNumber(opTable), &argc, argv); +#endif + + + rdb = XrmGetStringDatabase(datastring); + if (rdb != NULL) + XrmMergeDatabases(rdb, &((XtDisplay(toplevel))->db)); + + XtGetApplicationResources + (toplevel, &data, resources, XtNumber(resources), NULL, 0); + /* Read the file specified in argv[1] into the text buffer. */ +#if 0 + load_file(&data, (argc == 2) ? argv[1] : NULL); +#else + X_display_line("Netgen" NETGEN_VERSION "." NETGEN_REVISION); +#endif + + XtGetApplicationResources + (toplevel, &cells, resources, XtNumber(resources), NULL, 0); +#if 0 + load_cells(&cells); +#else + X_display_line("Netgen" NETGEN_VERSION "." NETGEN_REVISION); +#endif + + n = 0; +#ifdef INTERNAL_ARGS + XtSetArg(Args[n], XtNyResizable, (XtArgVal)True); n++; + XtSetArg(Args[n], XtNyAttachBottom, (XtArgVal)True); n++; + XtSetArg(Args[n], XtNxResizable, (XtArgVal)True); n++; + XtSetArg(Args[n], XtNxRefName, (XtArgVal)"scrollbar"); n++; + XtSetArg(Args[n], XtNxAddWidth, (XtArgVal)True); n++; + XtSetArg(Args[n], XtNxAttachRight, (XtArgVal)True); n++; +#endif + /* Create a VPane widget as a base to allow children to be resized easily. */ + pane = XtCreateManagedWidget("pane", XwvPanedWidgetClass, toplevel, Args, n); + + /* create a top command and title area */ + title = label_widget(pane, NETGEN_VERSION); + + + /* create data entry area in the form of a RowCol widget */ + n = 0; + XtSetArg(Args[0], XtNcolumns, 2); n++; + data_entry = XtCreateManagedWidget("rowcol",XwrowColWidgetClass,pane,Args,n); + + label_widget(data_entry, "File name:"); + GlobalFileWidget = create_one_line_text_widget("field1", data_entry); + + label_widget(data_entry, "Cell name:"); + GlobalCellWidget = create_one_line_text_widget("field1", data_entry); + + label_widget(data_entry, "Element:"); + GlobalDataWidget = create_one_line_text_widget("field1", data_entry); + + label_widget(data_entry, "2nd cell/elem:"); + GlobalOtherWidget = create_one_line_text_widget("field1", data_entry); + + +#ifdef CELL_LIST_MENU + /* create the top cell list area */ + + n = 0; + cells_frame = XtCreateManagedWidget + ("framework", XwformWidgetClass, pane, Args, n); + create_scrollbar(cells_frame, &cells); + + /* Create the drawing surface. */ + n = 0; + XtSetArg(Args[n], XtNwidth, (XtArgVal)500); n++; + XtSetArg(Args[n], XtNheight, (XtArgVal)100); n++; + cells.canvas = XtCreateManagedWidget + ("canvas", XwworkSpaceWidgetClass, cells_frame, Args, n); + XtAddCallback(cells.canvas, XtNexpose, handle_exposures, &cells); + XtAddCallback(cells.canvas, XtNresize, getsize, &cells); +#endif + + /* create the viewing area */ + n = 0; +#ifdef INTERNAL_ARGS + XtSetArg(Args[n], XtNyResizable, (XtArgVal)True); n++; + XtSetArg(Args[n], XtNyAttachBottom, (XtArgVal)True); n++; + XtSetArg(Args[n], XtNxResizable, (XtArgVal)True); n++; + XtSetArg(Args[n], XtNxRefName, (XtArgVal)"scrollbar"); n++; + XtSetArg(Args[n], XtNxAddWidth, (XtArgVal)True); n++; + XtSetArg(Args[n], XtNxAttachRight, (XtArgVal)True); n++; +#endif +/* XtSetArg(Args[n], XtNxAttachTop, (XtArgVal)True); n++; */ + frame = XtCreateManagedWidget("framework", XwformWidgetClass, pane, Args, n); + create_scrollbar(frame, &data); + + /* Create the drawing surface. */ + n = 0; + XtSetArg(Args[n], XtNwidth, (XtArgVal)500); n++; + XtSetArg(Args[n], XtNheight, (XtArgVal)400); n++; + +#ifdef INTERNAL_ARGS + XtSetArg(Args[n], XtNyResizable, (XtArgVal)True); n++; + XtSetArg(Args[n], XtNyAttachBottom, (XtArgVal)True); n++; + XtSetArg(Args[n], XtNxResizable, (XtArgVal)True); n++; + XtSetArg(Args[n], XtNxRefName, (XtArgVal)"scrollbar"); n++; + XtSetArg(Args[n], XtNxAddWidth, (XtArgVal)True); n++; + XtSetArg(Args[n], XtNxAttachRight, (XtArgVal)True); n++; +#endif + data.canvas = XtCreateManagedWidget + ("canvas", XwworkSpaceWidgetClass, frame, Args, n); + XtAddCallback(data.canvas, XtNexpose, handle_exposures, &data); + XtAddCallback(data.canvas, XtNresize, getsize, &data); + + + /* Create the menu manager. */ + menu_mgr = create_menu_manager(title, "menu_mgr"); + /* Create the Main menu pane. */ + create_pane(menu_mgr, "menu_mgr", "Netgen Main Menu", Menu, + ItemsInMenu(Menu)); + /* Create sub menus for various items on the main menu. */ + create_pane(menu_mgr, "Print", "PRINT menu", PrintMenu, + ItemsInMenu(PrintMenu)); + create_pane(menu_mgr, "Write cell", "WRITE menu", WriteMenu, + ItemsInMenu(WriteMenu)); + create_pane(menu_mgr, "Read cell", "READ menu", ReadMenu, + ItemsInMenu(ReadMenu)); + create_pane(menu_mgr, "NETCMP", "NETCMP menu", NetcmpMenu, + ItemsInMenu(NetcmpMenu)); + create_pane(menu_mgr, "PROTOCHIP", "PROTOCHIP menu", ProtoMenu, + ItemsInMenu(ProtoMenu)); + /* Create sub-sub menus for Protochip sub-menu */ + create_pane(menu_mgr, "Embed cell", "EMBED Algorithm", ProtoEmbedMenu, + ItemsInMenu(ProtoEmbedMenu)); + create_pane(menu_mgr, "PROTOCHIP parameters", "PROTOCHIP Parameters", + ProtoConstMenu, ItemsInMenu(ProtoConstMenu)); + + XtRealizeWidget(toplevel); + + /* Create the graphics contexts after realizing the widgets + because create_gcs requires a valid window ID. */ + create_gcs(&data); + create_gcs(&cells); + + /* a little magic to initialize all windows to bottom */ + getsize(cells.canvas, &cells, NULL); + scroll_bar_moved(cells.scrollbar, &cells, 0); + refresh(&cells); + + getsize(data.canvas, &data, NULL); + scroll_bar_moved(data.scrollbar, &data, 0); + refresh(&data); + +#ifdef INCLUDE_FALLBACK + XtAppMainLoop(app_con); +#else + /* install a vector to trap ^C */ + setjmp(jmpenv); + signal(SIGINT,handler); + XtMainLoop(); +#endif +} + +#endif /* X11_HP_WIDGETS */ + +#ifdef X11_MOTIF_WIDGETS + +/*************************************/ +/* MOTIF widget code */ +/*************************************/ + +/* define the following for scrolled text windows */ +#undef USE_SCROLLING_TEXT + +#include +#include +#include +#include +#include +#include +#include +#include + +XmStringCharSet cs = "ISOLatin1"; + +static char prompt_response[100]; +int prompt_done; +int calling_editor; /* which string are we trying to get ? */ +#define FILE_NAME 1 +#define CELL_NAME 2 +#define OTHER_NAME 3 +#define DATA_NAME 4 + +void prompt_callback(Widget w, caddr_t closure, caddr_t call_data) +{ + char *c; + XmSelectionBoxCallbackStruct *cb = (XmSelectionBoxCallbackStruct *)call_data; + + XmStringGetLtoR(cb->value, cs, &c); + strcpy(prompt_response, c); + XtFree(c); + prompt_done = 1; +} + +void prompt_cancel_callback(Widget w, caddr_t closure, caddr_t call_data) +{ + *prompt_response = '\0'; + prompt_done = 1; +} + +void prompt_save_callback(Widget w, caddr_t closure, caddr_t call_data) +{ + prompt_callback(w, closure, call_data); + /* now we need to save the data in the original editor window */ + switch (calling_editor) { + case FILE_NAME: + XmTextSetString(GlobalFileWidget, prompt_response); + break; + case CELL_NAME: + XmTextSetString(GlobalCellWidget, prompt_response); + break; + case OTHER_NAME: + XmTextSetString(GlobalOtherWidget, prompt_response); + break; + case DATA_NAME: + XmTextSetString(GlobalDataWidget, prompt_response); + break; + } +} + +char *DialogWidget(char *prompt) +{ + Widget w; + Arg Args[10]; + int n; + + *prompt_response = '\0'; + prompt_done = 0; + n = 0; + XtSetArg(Args[n], XmNselectionLabelString, + XmStringCreateLtoR(prompt, cs)); n++; + XtSetArg(Args[n], XmNdialogType, XmDIALOG_PROMPT); n++; + XtSetArg(Args[n], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL); n++; + XtSetArg(Args[n], XmNautoUnmanage, True); n++; + XtSetArg(Args[n], XmNhelpLabelString, XmStringCreateLtoR("Save", cs)); n++; + + XtSetArg(Args[n], XmNminHeight, 100); n++; + XtSetArg(Args[n], XmNminWidth, 100); n++; + + w = XmCreatePromptDialog(toplevel, "prompt", Args, n); + XtAddCallback(w, XmNokCallback, prompt_callback, NULL); + XtAddCallback(w, XmNcancelCallback, prompt_cancel_callback, NULL); + XtAddCallback(w, XmNhelpCallback, prompt_save_callback, NULL); + XtManageChild(w); + + /* we want the application to WAIT for any callback */ + while (!prompt_done) + XtProcessEvent(XtIMAll); + + return(prompt_response); +} + +char *get_something(char *buf, Widget w, char *prompt) +{ + char *c; + + if (strlen(buf)) return(buf); + + c = XmTextGetString(w); + strcpy(buf, c); + XtFree(c); + if (strlen(buf) == 0) { + /* bring up a dialog widget to get the filename */ + strcpy(buf, DialogWidget(prompt)); + } + return (buf); +} + +char *get_file(void) +{ + calling_editor = FILE_NAME; + return(get_something(GlobalFileName, GlobalFileWidget, "Enter File Name")); +} + +char *get_cell(void) +{ + calling_editor = CELL_NAME; + return(get_something(GlobalCellName, GlobalCellWidget, "Enter Cell Name")); +} + +char *get_other(void) +{ + calling_editor = OTHER_NAME; + return(get_something(GlobalOtherName, GlobalOtherWidget, "Enter Name")); +} + +char *get_data(void) +{ + calling_editor = DATA_NAME; + return(get_something(GlobalDataName, GlobalDataWidget, "Enter Data")); +} + + +Widget pane, frame, cells_frame, menu_mgr, title, data_entry; + +#define DATABUFSIZ 4000 + +char data_buf[DATABUFSIZ]; +char *data_endptr = data_buf; + +void X_display_line(char *buf) +{ + if (toplevel == NULL) { + /* not using X windows */ + printf("%s", buf); + return; + } + + if (data_endptr + strlen(buf) > data_buf + DATABUFSIZ) { + char *cp; + /* find the next line */ + cp = data_buf + strlen(buf); + while (*cp != '\n' && cp < data_endptr) cp++; + + memcpy(data_buf, cp, data_endptr - cp + 1); + data_endptr -= (cp - data_buf); + } + /* now just copy the string */ + strcpy(data_endptr, buf); + data_endptr += strlen(buf); + memset(data_endptr, 0, data_buf + DATABUFSIZ - data_endptr - 1); +} + +#ifdef USE_SCROLLED_TEXT +void X_display_refresh(void) +{ + Arg Args[10]; + int n; + + short lines; + char *cp; + XmTextPosition offset, cursor; + Boolean showcur; + + if (toplevel == NULL) return; + + n = 0; + XtSetArg(Args[n], XmNrows, &lines); n++; + XtSetArg(Args[n], XmNtopPosition, &offset); n++; + XtSetArg(Args[n], XmNcursorPosition, &cursor); n++; + XtSetArg(Args[n], XmNautoShowCursorPosition, &showcur); n++; + XtGetValues(frame, Args, n); + printf("Before: %d lines in the display, %ld chars offset %ld cursor (showing %d)\n", + (int)lines, (long)offset, (long)cursor, (int)showcur); + + cp = data_endptr; + while (cp > data_buf && lines > 0) + if (*cp-- == '\n') lines--; + +printf("lines = %d, cp = %p, data_buf = %p\n", (int)lines, cp, data_buf); + if (lines == 0) cp++; + if (cp < data_buf) cp = data_buf; + + /* set the editor to display the string */ + n = 0; + XtSetArg(Args[n], XmNvalue, data_buf); n++; +#if 0 + printf("Setting offset to %d\n", (int)((XmTextPosition)(cp - data_buf))); + XtSetArg(Args[n], XmNtopPosition, (XmTextPosition)(cp - data_buf)); n++; +/* XtSetArg(Args[n], XmNtopPosition, (XmTextPosition)5); n++; */ +#else + XtSetArg(Args[n], XmNautoShowCursorPosition, (XtArgVal)True); n++; + printf("Setting cursor position to %d\n", + (int)((XmTextPosition)(data_endptr - data_buf))); + XtSetArg(Args[n], XmNcursorPosition, + (XmTextPosition)(data_endptr - data_buf)); n++; +#endif + + XtSetValues(frame, Args, n); + + n = 0; + XtSetArg(Args[n], XmNrows, &lines); n++; + XtSetArg(Args[n], XmNtopPosition, &offset); n++; + XtSetArg(Args[n], XmNcursorPosition, &cursor); n++; + XtGetValues(frame, Args, n); + printf("After: %d lines in the display, %ld chars offset %ld cursor\n", + (int)lines, (long)offset, (long)cursor); +} +#else /* not USE_SCROLLED_TEXT */ + +void X_display_refresh(void) +/* very simple code that scrolls the window as required */ +{ + Arg Args[10]; + int n; + + short lines; + char *cp; + + if (toplevel == NULL) return; + + n = 0; + XtSetArg(Args[n], XmNrows, &lines); n++; + XtGetValues(frame, Args, n); + + cp = data_endptr; + while (cp > data_buf && lines > 0) + if (*cp-- == '\n') lines--; + + if (lines == 0) cp++; + if (cp < data_buf) cp = data_buf; + + /* set the editor to display the string */ + n = 0; + XtSetArg(Args[n], XmNvalue, cp); n++; + XtSetValues(frame, Args, n); +} + +#endif /* not USE_SCROLLED_TEXT */ + + + +int menu_index_by_menu(menu_struct *mp) +{ + int i; + for (i = 0; i < (sizeof(MenuArray)/sizeof(MenuArray[0])); i++) + if (MenuArray[i].menu == mp) return(i); +printf("menu_index_by_menu: this should never happen\n"); + return(0); +} + + +int menu_index_by_widget(Widget w) +{ + int i; + for (i = 0; i < (sizeof(MenuArray)/sizeof(MenuArray[0])); i++) + if (MenuArray[i].widget == w) return(i); + fprintf(stderr,"menu_index_by_widget: this should never happen\n"); + return(0); +} + +menu_struct *find_menu_by_widget(Widget w) +{ + int i; + for (i = 0; i < (sizeof(MenuArray)/sizeof(MenuArray[0])); i++) + if (MenuArray[i].widget == w) return(MenuArray[i].menu); + fprintf(stderr,"find_menu_by_widget: this should never happen\n"); + return(NULL); +} + +void ActivateMenu(menu_struct *mp); + +void MenuCallback(Widget w, caddr_t closure, caddr_t call_data) +{ + XmListCallbackStruct *cb = (XmListCallbackStruct *)call_data; + int i, ItemCount; + menu_struct *menu; + + menu = find_menu_by_widget(w); + + ItemCount = ItemsInMenu(menu); + for (i = 0; i < ItemCount; i++) { + char *s; + XmStringGetLtoR(cb->item, cs, &s); + if (!strcmp(s, menu[i].name)) { + /* printf("Trying to run function: %s\n", menu[i].name); */ + if (menu[i].submenu != NULL) ActivateMenu(menu[i].submenu); + else (*(menu[i].func))(w, NULL, NULL); + break; + } + } + XmListDeselectAllItems(w); +} + +void MenuDestroyCallback(Widget w, caddr_t closure, caddr_t call_data) +{ + int menunum; + + menunum = menu_index_by_widget(w); + MenuArray[menunum].widget = NULL; +} + +Widget make_menu(menu_struct *menu) +/* returns the List widget for the menu, NOT the top shell widget */ +{ + int n; + Arg Args[20]; + Widget top, widget; + XmString *Items; + int ItemCount; + + top = + XtCreateApplicationShell("menuShell", topLevelShellWidgetClass, NULL, 0); + + ItemCount = ItemsInMenu(menu); + Items = (XmString *)CALLOC(ItemCount, sizeof(XmString)); + for (n = 0; n < ItemCount; n++) + Items[n] = (XmString)XmStringCreateLtoR(menu[n].name, cs); + + n = 0; + XtSetArg(Args[n], XmNitems, (XtArgVal)Items); n++; + XtSetArg(Args[n], XmNitemCount, (XtArgVal)ItemCount); n++; + XtSetArg(Args[n], XmNvisibleItemCount, (XtArgVal)ItemCount); n++; + XtSetArg(Args[n], XmNselectionPolicy, (XtArgVal)XmSINGLE_SELECT); n++; + + XtSetArg(Args[n], XmNlistMarginHeight, (XtArgVal)20); n++; + XtSetArg(Args[n], XmNlistMarginWidth, (XtArgVal)30); n++; + XtSetArg(Args[n], XmNborderWidth, (XtArgVal)10); n++; + + widget = XmCreateList(top,"menu", Args, n); + + XtManageChild(widget); + XtAddCallback(widget, XmNsingleSelectionCallback, MenuCallback, NULL); + XtAddCallback(widget, XmNdestroyCallback, MenuDestroyCallback, NULL); + +#if 0 + /* put all menus at a fixed position; this doesn't work for mwm */ + n = 0; + XtSetArg(Args[n], XmNx, (XtArgVal)20); n++; + XtSetArg(Args[n], XmNy, (XtArgVal)(30 + 50*menu_index_by_menu(menu))); n++; + XtSetValues(top, Args, n); +#endif + + XtRealizeWidget(top); + + /* put all menus at a fixed position */ + n = 0; + XtSetArg(Args[n], XmNx, (XtArgVal)20); n++; + XtSetArg(Args[n], XmNy, (XtArgVal)(30 + 50*menu_index_by_menu(menu))); n++; + XtSetValues(top, Args, n); + + return(widget); +} + + +void RaiseMenu(Widget w) +{ + /* just bring it up; remember to bring up the SHELL, the list's parent !!! */ + XMapRaised(XtDisplay(XtParent(w)), XtWindow(XtParent(w))); +} + +void ActivateMenu(menu_struct *mp) +/* if it exists, raise it, otherwise create it */ +{ + int menunum; + Widget w; + + menunum = menu_index_by_menu(mp); + w = MenuArray[menunum].widget; + + if (w != NULL) RaiseMenu(w); + else MenuArray[menunum].widget = make_menu(mp); +} + + +void ActivateTopMenuProc(Widget w, caddr_t closure, caddr_t call_data) +/* raise all menus that exist, and create the top-level if required */ +{ + int i; + + for (i = 0; i < sizeof(MenuArray)/sizeof(MenuArray[0]); i++) + if (MenuArray[i].widget != NULL) RaiseMenu(MenuArray[i].widget); + + /* make sure the main menu is raised in any event */ + ActivateMenu(Menu); +} + + + +Widget label_widget(Widget parent, char *string) +{ + Arg Args[10]; + int n; + Widget w; + + n = 0; + XtSetArg(Args[n], XmNlabelString, + (XtArgVal)XmStringCreate(string, cs)); n++; + w = XmCreateLabel(parent, "label", Args, n); + XtManageChild(w); + return w; +} + +Widget entry_widget(Widget parent, char *string) +{ + Arg Args[10]; + int n; + Widget w; + + n = 0; + XtSetArg(Args[n], XmNeditMode, (XtArgVal)XmSINGLE_LINE_EDIT); n++; + w = XmCreateText(data_entry, "entry", Args, n); + XtManageChild(w); + return w; +} + +Widget text_widget(Widget parent, char *string) +{ + Arg Args[10]; + int n; + Widget w; + + n = 0; + XtSetArg(Args[n], XmNeditable, (XtArgVal)False); n++; + XtSetArg(Args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; +#ifdef USE_SCROLLED_TEXT + XtSetArg(Args[n], XmNscrollHorizontal, (XtArgVal)False); n++; + XtSetArg(Args[n], XmNscrollVertical, (XtArgVal)True); n++; + w = XmCreateScrolledText(parent, string, Args, n); +#else + w = XmCreateText(parent, string, Args, n); +#endif + XtManageChild(w); + return w; +} + +void X_main_loop(int argc, char *argv[]) +{ + /* toplevel widget is global */ + Arg Args[10]; + int n; + + /* if we're not using X, just call good old Query(); */ + if (getenv("DISPLAY") == NULL) { + Query(); + return; + } + + toplevel = XtInitialize(argv[0], "Netgen", NULL, 0, &argc, argv); + /* create a vertical pane window to permit children to be resized */ + pane = XmCreatePanedWindow(toplevel,"pane",NULL, 0); + XtManageChild(pane); + + /* create a top command and title area */ + n = 0; + XtSetArg(Args[n], XmNlabelString, + (XtArgVal)XmStringCreate("Netgen" NETGEN_VERSION "." NETGEN_REVISION, cs)); + n++; + title = XmCreatePushButton(pane, "title", Args, n); + XtAddCallback(title, XmNactivateCallback, ActivateTopMenuProc, NULL); + XtManageChild(title); + + /* create a data entry area for the four text fields */ + n = 0; + XtSetArg(Args[n], XmNnumColumns, 2); n++; + XtSetArg(Args[n], XmNpacking, XmPACK_COLUMN); n++; + data_entry = XmCreateRowColumn(pane, "rowcol", Args, n); + XtManageChild(data_entry); + + /* put 4 labels in the rowcol widget, and four text editors */ + label_widget(data_entry, "File Name:"); + label_widget(data_entry, "Cell Name:"); + label_widget(data_entry, "Element:"); + label_widget(data_entry, "2nd cell/elem:"); + GlobalFileWidget = entry_widget(data_entry, NULL); + GlobalCellWidget = entry_widget(data_entry, NULL); + GlobalDataWidget = entry_widget(data_entry, NULL); + GlobalOtherWidget = entry_widget(data_entry, NULL); + + /* create two text widgets */ + cells_frame = text_widget(pane, "cells"); + frame = text_widget(pane, "text"); + +/* +Can't change scrolling policy after the window is created + n = 0; + XtSetArg(Args[n], XmNscrollingPolicy, (XtArgVal)XmAUTOMATIC); n++; + XtSetValues(XtParent(frame), Args, n); +*/ + + XtRealizeWidget(toplevel); + XtMainLoop(); +} +#endif /* X11_MOTIF_WIDGETS */ + + + +#ifdef X11_ATHENA_WIDGETS + +/*************************************/ +/* ATHENA widget code */ +/*************************************/ + +#include +#include +#include +#include +#include +#include + +XtAppContext app_con; + +int calling_editor; /* which string are we trying to get ? */ +#define FILE_NAME 1 +#define CELL_NAME 2 +#define OTHER_NAME 3 +#define DATA_NAME 4 + + +char *get_something(char *buf, Widget w, char *prompt) +{ + Arg Args[10]; + int n; + + char *c; + + if (strlen(buf)) return(buf); + + n = 0; + XtSetArg(Args[n], XtNstring, &c); n++; + XtGetValues(w, Args, n); + strcpy(buf, c); + return (buf); +} + +char *get_file(void) +{ + calling_editor = FILE_NAME; + return(get_something(GlobalFileName, GlobalFileWidget, "Enter File Name")); +} + +char *get_cell(void) +{ + calling_editor = CELL_NAME; + return(get_something(GlobalCellName, GlobalCellWidget, "Enter Cell Name")); +} + +char *get_other(void) +{ + calling_editor = OTHER_NAME; + return(get_something(GlobalOtherName, GlobalOtherWidget, "Enter Name")); +} + +char *get_data(void) +{ + calling_editor = DATA_NAME; + return(get_something(GlobalDataName, GlobalDataWidget, "Enter Data")); +} + + +Widget pane, frame, cells_frame, menu_mgr, title, data_entry; + +#define DATABUFSIZ 4000 + +char data_buf[DATABUFSIZ]; +char *data_endptr = data_buf; + +void X_display_line(char *buf) +{ + if (toplevel == NULL) { + /* not using X windows */ + printf("%s", buf); + return; + } + + if (data_endptr + strlen(buf) > data_buf + DATABUFSIZ) { + char *cp; + /* find the next line */ + cp = data_buf + strlen(buf); + while (*cp != '\n' && cp < data_endptr) cp++; + + memcpy(data_buf, cp, data_endptr - cp + 1); + data_endptr -= (cp - data_buf); + } + /* now just copy the string */ + strcpy(data_endptr, buf); + data_endptr += strlen(buf); + memset(data_endptr, 0, data_buf + DATABUFSIZ - data_endptr - 1); +} + +#ifdef USE_SCROLLED_TEXT +void X_display_refresh(void) +{ + Arg Args[10]; + int n; + + short lines; + char *cp; + XmTextPosition offset, cursor; + Boolean showcur; + + if (toplevel == NULL) return; + + n = 0; + XtSetArg(Args[n], XmNrows, &lines); n++; + XtSetArg(Args[n], XmNtopPosition, &offset); n++; + XtSetArg(Args[n], XmNcursorPosition, &cursor); n++; + XtSetArg(Args[n], XmNautoShowCursorPosition, &showcur); n++; + XtGetValues(frame, Args, n); + printf("Before: %d lines in the display, %ld chars offset %ld cursor (showing %d)\n", + (int)lines, (long)offset, (long)cursor, (int)showcur); + + cp = data_endptr; + while (cp > data_buf && lines > 0) + if (*cp-- == '\n') lines--; + +printf("lines = %d, cp = %p, data_buf = %p\n", (int)lines, cp, data_buf); + if (lines == 0) cp++; + if (cp < data_buf) cp = data_buf; + + /* set the editor to display the string */ + n = 0; + XtSetArg(Args[n], XmNvalue, data_buf); n++; +#if 0 + printf("Setting offset to %d\n", (int)((XmTextPosition)(cp - data_buf))); + XtSetArg(Args[n], XmNtopPosition, (XmTextPosition)(cp - data_buf)); n++; +/* XtSetArg(Args[n], XmNtopPosition, (XmTextPosition)5); n++; */ +#else + XtSetArg(Args[n], XmNautoShowCursorPosition, (XtArgVal)True); n++; + printf("Setting cursor position to %d\n", + (int)((XmTextPosition)(data_endptr - data_buf))); + XtSetArg(Args[n], XmNcursorPosition, + (XmTextPosition)(data_endptr - data_buf)); n++; +#endif + + XtSetValues(frame, Args, n); + + n = 0; + XtSetArg(Args[n], XmNrows, &lines); n++; + XtSetArg(Args[n], XmNtopPosition, &offset); n++; + XtSetArg(Args[n], XmNcursorPosition, &cursor); n++; + XtGetValues(frame, Args, n); + printf("After: %d lines in the display, %ld chars offset %ld cursor\n", + (int)lines, (long)offset, (long)cursor); +} +#else /* not USE_SCROLLED_TEXT */ + +void X_display_refresh(void) +/* very simple code that scrolls the window as required */ +{ + Arg Args[10]; + int n; + + Dimension height; + Position topmargin, botmargin; + XFontStruct *font; + short lines; + char *cp; + int fontheight; + + if (toplevel == NULL) return; + + n = 0; + XtSetArg(Args[n], XtNheight, &height); n++; + XtSetArg(Args[n], XtNtopMargin, &topmargin); n++; + XtSetArg(Args[n], XtNbottomMargin, &botmargin); n++; + XtSetArg(Args[n], XtNfont, &font); n++; + XtGetValues(frame, Args, n); + fontheight = font->max_bounds.ascent + font->max_bounds.descent; + printf("got height = %d, topmargin = %d, botmargin = %d, fontht = %d\n", + (int)height, (int)topmargin, (int)botmargin, fontheight); + + + lines = (height - topmargin - botmargin) / fontheight ; + + cp = data_endptr; + while (cp > data_buf && lines > 0) + if (*cp-- == '\n') lines--; + + if (lines == 0) cp++; + if (cp < data_buf) cp = data_buf; + + /* set the editor to display the string */ + n = 0; + XtSetArg(Args[n], XtNstring, cp); n++; + XtSetValues(frame, Args, n); +} + +#endif /* not USE_SCROLLED_TEXT */ + + +int menu_index_by_menu(menu_struct *mp) +{ + int i; + for (i = 0; i < (sizeof(MenuArray)/sizeof(MenuArray[0])); i++) + if (MenuArray[i].menu == mp) return(i); +printf("menu_index_by_menu: this should never happen\n"); + return(0); +} + + +int menu_index_by_widget(Widget w) +{ + int i; + for (i = 0; i < (sizeof(MenuArray)/sizeof(MenuArray[0])); i++) + if (MenuArray[i].widget == w) return(i); + fprintf(stderr,"menu_index_by_widget: this should never happen\n"); + return(0); +} + +menu_struct *find_menu_by_widget(Widget w) +{ + int i; + for (i = 0; i < (sizeof(MenuArray)/sizeof(MenuArray[0])); i++) + if (MenuArray[i].widget == w) return(MenuArray[i].menu); + fprintf(stderr,"find_menu_by_widget: this should never happen\n"); + return(NULL); +} + +void ActivateMenu(menu_struct *mp); + +void MenuCallback(Widget w, caddr_t closure, caddr_t call_data) +{ + XawListReturnStruct *cb = (XawListReturnStruct *)call_data; + int i, ItemCount; + menu_struct *menu; + + menu = find_menu_by_widget(w); + + ItemCount = ItemsInMenu(menu); + for (i = 0; i < ItemCount; i++) { + if (!strcmp(cb->string, menu[i].name)) { + /* printf("Trying to run function: %s\n", menu[i].name); */ + if (menu[i].submenu != NULL) ActivateMenu(menu[i].submenu); + else (*(menu[i].func))(w, NULL, NULL); + break; + } + } + XawListUnhighlight(w); +} + +void MenuDestroyCallback(Widget w, caddr_t closure, caddr_t call_data) +{ + int menunum; + + menunum = menu_index_by_widget(w); + MenuArray[menunum].widget = NULL; +} + +Widget make_menu(menu_struct *menu) +/* returns the List widget for the menu, NOT the top shell widget */ +{ + int n; + Arg Args[20]; + Widget top, widget; + String *Items; + int ItemCount; + + top = + XtAppCreateShell(NULL,"menuShell", applicationShellWidgetClass, + XtDisplay(toplevel), NULL, 0); + + ItemCount = ItemsInMenu(menu); + Items = (String *)CALLOC(ItemCount + 1, sizeof(String)); + + for (n = 0; n < ItemCount; n++) + Items[n] = XtNewString(menu[n].name); + Items[ItemCount] = NULL; + + n = 0; + XtSetArg(Args[n], XtNdefaultColumns, 1); n++; + XtSetArg(Args[n], XtNforceColumns, True); n++; + XtSetArg(Args[n], XtNlist, Items); n++; + XtSetArg(Args[n], XtNnumberStrings, ItemCount); n++; + widget = XtCreateManagedWidget("menu", listWidgetClass, top, Args, n); + XtAddCallback(widget, XtNcallback, MenuCallback, NULL); + XtAddCallback(widget, XtNdestroyCallback, MenuDestroyCallback, NULL); +/* XawListChange(widget, Items, ItemCount, 0, True); */ + + /* put all menus at a fixed position; this doesn't work for mwm */ + n = 0; + XtSetArg(Args[n], XtNx, (XtArgVal)20); n++; + XtSetArg(Args[n], XtNy, (XtArgVal)(30 + 50*menu_index_by_menu(menu))); n++; + XtSetValues(top, Args, n); + + XtRealizeWidget(top); + return(widget); +} + + +void RaiseMenu(Widget w) +{ + /* just bring it up; remember to bring up the SHELL, the list's parent !!! */ + XMapRaised(XtDisplay(XtParent(w)), XtWindow(XtParent(w))); +} + +void ActivateMenu(menu_struct *mp) +/* if it exists, raise it, otherwise create it */ +{ + int menunum; + Widget w; + + menunum = menu_index_by_menu(mp); + w = MenuArray[menunum].widget; + + if (w != NULL) RaiseMenu(w); + else MenuArray[menunum].widget = make_menu(mp); +} + + +void ActivateTopMenuProc(Widget w, caddr_t closure, caddr_t call_data) +/* raise all menus that exist, and create the top-level if required */ +{ + int i; + + for (i = 0; i < sizeof(MenuArray)/sizeof(MenuArray[0]); i++) + if (MenuArray[i].widget != NULL) RaiseMenu(MenuArray[i].widget); + + /* make sure the main menu is raised in any event */ + ActivateMenu(Menu); +} + + + +Widget label_widget(Widget parent, char *string) +{ + Arg Args[10]; + int n; + Widget w; + + n = 0; + XtSetArg(Args[n], XtNlabel, (XtArgVal)string); n++; + w = XtCreateManagedWidget("label", labelWidgetClass, parent, Args, n); + return w; +} + +Widget entry_widget(Widget parent, char *string) +{ + Arg Args[10]; + int n; + Widget w; + + n = 0; + XtSetArg(Args[n], XtNeditType, XawtextEdit); n++; + w = XtCreateManagedWidget("entry", asciiTextWidgetClass, + data_entry, Args, n); + return w; +} + +Widget text_widget(Widget parent, char *string) +{ + Arg Args[10]; + int n; + Widget w; + + n = 0; + XtSetArg(Args[n], XtNeditType, XawtextRead); n++; + w = XtCreateManagedWidget(string, asciiTextWidgetClass, + parent, Args, n); + return w; +} + +void make_data_entry_area(Widget parent) +{ + Widget l1, l2, l3, l4; + Arg Args[10]; + int n; + + /* put 4 labels in the rowcol widget, and four text editors */ + l1 = label_widget(data_entry, "File Name:"); + + l2 = label_widget(data_entry, "Cell Name:"); + n = 0; + XtSetArg(Args[n], XtNfromVert, l1); n++; + XtSetValues(l2, Args, n); + + l3 = label_widget(data_entry, "Element:"); + n = 0; + XtSetArg(Args[n], XtNfromVert, l2); n++; + XtSetValues(l3, Args, n); + + l4 = label_widget(data_entry, "2nd cell/elem:"); + n = 0; + XtSetArg(Args[n], XtNfromVert, l3); n++; + XtSetValues(l4, Args, n); + + GlobalFileWidget = entry_widget(data_entry, NULL); + n = 0; + XtSetArg(Args[n], XtNfromHoriz, l1); n++; + XtSetValues(GlobalFileWidget, Args, n); + + GlobalCellWidget = entry_widget(data_entry, NULL); + n = 0; + XtSetArg(Args[n], XtNfromHoriz, l2); n++; + XtSetArg(Args[n], XtNfromVert, GlobalFileWidget); n++; + XtSetValues(GlobalCellWidget, Args, n); + + GlobalDataWidget = entry_widget(data_entry, NULL); + n = 0; + XtSetArg(Args[n], XtNfromHoriz, l3); n++; + XtSetArg(Args[n], XtNfromVert, GlobalCellWidget); n++; + XtSetValues(GlobalDataWidget, Args, n); + + GlobalOtherWidget = entry_widget(data_entry, NULL); + n = 0; + XtSetArg(Args[n], XtNfromHoriz, l4); n++; + XtSetArg(Args[n], XtNfromVert, GlobalDataWidget); n++; + XtSetValues(GlobalOtherWidget, Args, n); +} + +String fallback_resources[] = { + "*input: True", + "*Paned*width: 350", + "*label.label: At least one of each Athena Widget.", + "*Dialog.label: I am a Dialog widget.", + "*Dialog.value: Enter new value here.", + "*Dialog*command*label: ok", + "*Dialog*resizable: True", + "*Viewport*allowVert: True", + "*scrollbar*orientation: horizontal", + "*scrollbar*length: 100", + "*text*height: 75", + "*text*editType: edit", + "*text*scrollVertical: whenNeeded", + "*text*scrollHorizonal: whenNeeded", + NULL, +}; + +void X_main_loop(int argc, char *argv[]) +{ + /* toplevel widget is global */ + Arg Args[10]; + int n; + + /* if we're not using X, just call good old Query(); */ + if (getenv("DISPLAY") == NULL) { + Query(); + return; + } + + toplevel = XtAppInitialize(&app_con, "Netgen", NULL, 0, &argc, argv, + fallback_resources, NULL, 0); + + /* create a vertical pane window to permit children to be resized */ + pane = XtCreateManagedWidget("pane", panedWidgetClass, toplevel,NULL, 0); + + /* create a top command and title area */ + n = 0; + XtSetArg(Args[n], XtNlabel, (XtArgVal)"Netgen" NETGEN_VERSION "." NETGEN_REVISION); + n++; + title = XtCreateManagedWidget("title", commandWidgetClass, pane, Args, n); + XtAddCallback(title, XtNcallback, ActivateTopMenuProc, NULL); + + /* create a data entry area for the four text fields */ +/* + n = 0; + data_entry = XtCreateManagedWidget("rowcol", boxWidgetClass, pane, Args, n); +*/ + n = 0; + data_entry = XtCreateManagedWidget("rowcol", formWidgetClass, pane, Args, n); + + make_data_entry_area(data_entry); + + /* create two text widgets */ + cells_frame = text_widget(pane, "cells"); + frame = text_widget(pane, "text"); + + XtRealizeWidget(toplevel); + XtAppMainLoop(app_con); +} +#endif /* X11_ATHENA_WIDGETS */ + +#endif /* HAVE_X11 */ + diff --git a/base/xnetgen.h b/base/xnetgen.h new file mode 100644 index 0000000..9dd80e7 --- /dev/null +++ b/base/xnetgen.h @@ -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 diff --git a/configure b/configure new file mode 100755 index 0000000..5361403 --- /dev/null +++ b/configure @@ -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 $* ) diff --git a/dbug/Makefile b/dbug/Makefile new file mode 100644 index 0000000..da7987f --- /dev/null +++ b/dbug/Makefile @@ -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 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 ". +# 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 + diff --git a/dbug/README.prof b/dbug/README.prof new file mode 100644 index 0000000..cfffe37 --- /dev/null +++ b/dbug/README.prof @@ -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: + + E + X + +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 diff --git a/dbug/analyze.c b/dbug/analyze.c new file mode 100644 index 0000000..30a28f4 --- /dev/null +++ b/dbug/analyze.c @@ -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 +#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); +} diff --git a/dbug/dbug.c b/dbug/dbug.c new file mode 100644 index 0000000..a1a4958 --- /dev/null +++ b/dbug/dbug.c @@ -0,0 +1,1881 @@ +/****************************************************************************** + * * + * 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.c runtime support routines for dbug package + * + * SCCS + * + * @(#)dbug.c 1.19 9/5/87 + * + * DESCRIPTION + * + * These are the runtime support routines for the dbug package. + * The dbug package has two main components; the user include + * file containing various macro definitions, and the runtime + * support routines which are called from the macro expansions. + * + * Externally visible functions in the runtime support module + * use the naming convention pattern "_db_xx...xx_", thus + * they are unlikely to collide with user defined function names. + * + * AUTHOR(S) + * + * Fred Fish (base code) + * Enhanced Software Technologies, Tempe, AZ + * asuvax!mcdphx!estinc!fnf + * + * Binayak Banerjee (profiling enhancements) + * seismo!bpa!sjuvax!bbanerje + */ + + +#include + +#ifndef NO_VARARGS +#include /* Use system supplied stdarg package */ +#else +#include "vargs.h" /* Use our "fake" varargs (WAAAY deprecated) */ +#endif + +#if amiga +#define HZ (50) /* Probably in some header somewhere */ +#endif + +#ifdef M_XENIX /* Some xenix compilers predefine this */ +#ifndef xenix +#define xenix 1 +#endif +#endif + +/* + * Manifest constants that should not require any changes. + */ + +#define FALSE 0 /* Boolean FALSE */ +#define TRUE 1 /* Boolean TRUE */ +#define EOS '\000' /* End Of String marker */ + +/* + * Manifest constants which may be "tuned" if desired. + */ + +#define PRINTBUF 1024 /* Print buffer size */ +#define INDENT 4 /* Indentation per trace level */ +#define MAXDEPTH 200 /* Maximum trace depth default */ + +/* + * The following flags are used to determine which + * capabilities the user has enabled with the state + * push macro. + */ + +#define TRACE_ON 000001 /* Trace enabled */ +#define DEBUG_ON 000002 /* Debug enabled */ +#define FILE_ON 000004 /* File name print enabled */ +#define LINE_ON 000010 /* Line number print enabled */ +#define DEPTH_ON 000020 /* Function nest level print enabled */ +#define PROCESS_ON 000040 /* Process name print enabled */ +#define NUMBER_ON 000100 /* Number each line of output */ +#define PROFILE_ON 000200 /* Print out profiling code */ +#define PID_ON 000400 /* Identify each line with process id */ + +#define TRACING (stack -> flags & TRACE_ON) +#define DEBUGGING (stack -> flags & DEBUG_ON) +#define PROFILING (stack -> flags & PROFILE_ON) +#define STREQ(a,b) (strcmp(a,b) == 0) + +/* + * Typedefs to make things more obvious. + */ + +#define VOID void /* Can't use typedef for most compilers */ +typedef int BOOLEAN; + +/* + * Make it easy to change storage classes if necessary. + */ + +#define LOCAL static /* Names not needed by outside world */ +#define IMPORT extern /* Names defined externally */ +#define EXPORT /* Allocated here, available globally */ +#define AUTO auto /* Names to be allocated on stack */ +#define REGISTER register /* Names to be placed in registers */ + +/* + * The default file for profiling. Could also add another flag + * (G?) which allowed the user to specify this. + * + * If the automatic variables get allocated on the stack in + * reverse order from their declarations, then define AUTOS_REVERSE. + * This is used by the code that keeps track of stack usage. For + * forward allocation, the difference in the dbug frame pointers + * represents stack used by the callee function. For reverse allocation, + * the difference represents stack used by the caller function. + * + */ + +#define PROF_FILE "dbugmon.out" +#define PROF_EFMT "E\t%ld\t%s\n" +#define PROF_SFMT "S\t%lx\t%lx\t%s\n" +#define PROF_XFMT "X\t%ld\t%s\n" + +#if M_I386 /* predefined by xenix 386 compiler */ +#define AUTOS_REVERSE 1 +#endif + +/* + * Variables which are available externally but should only + * be accessed via the macro package facilities. + */ + +EXPORT FILE *_db_fp_ = stderr; /* Output stream, default stderr */ +EXPORT FILE *_db_pfp_ = (FILE *)0; /* Profile stream, 'dbugmon.out' */ +EXPORT char *_db_process_ = "dbug"; /* Pointer to process name; argv[0] */ +EXPORT BOOLEAN _db_on_ = FALSE; /* TRUE if debugging currently on */ +EXPORT BOOLEAN _db_pon_ = FALSE; /* TRUE if debugging currently on */ + +/* + * Externally supplied functions. + */ + +#if (unix || xenix) /* Only needed for unix */ +IMPORT VOID perror (); /* Print system/library error */ +IMPORT int chown (); /* Change owner of a file */ +IMPORT int getgid (); /* Get real group id */ +IMPORT int getuid (); /* Get real user id */ +IMPORT int access (); /* Test file for access */ +#else +#if !(amiga && LATTICE) && !defined(__TURBOC__) +LOCAL VOID perror (); /* Fake system/library error print routine */ +#endif +#endif + +#ifdef __TURBOC__ +#include /* get perror */ +#endif + +# if BSD4_3 || sun +IMPORT int getrusage (); +#endif + +IMPORT int atoi (); /* Convert ascii to integer */ +IMPORT VOID exit (); /* Terminate execution */ +IMPORT int fclose (); /* Close a stream */ +IMPORT FILE *fopen (); /* Open a stream */ +IMPORT int fprintf (); /* Formatted print on file */ +IMPORT int vfprintf (); /* Varargs form of fprintf */ +IMPORT VOID free (); +IMPORT char *malloc (); /* Allocate memory */ +IMPORT int strcmp (); /* Compare strings */ +IMPORT char *strcpy (); /* Copy strings around */ +IMPORT size_t strlen (); /* Find length of string */ + +#ifndef fflush /* This is sometimes a macro */ +IMPORT int fflush (); /* Flush output for stream */ +#endif + + +/* + * The user may specify a list of functions to trace or + * debug. These lists are kept in a linear linked list, + * a very simple implementation. + */ + +struct link { + char *string; /* Pointer to link's contents */ + struct link *next_link; /* Pointer to the next link */ +}; + + +/* + * Debugging states can be pushed or popped off of a + * stack which is implemented as a linked list. Note + * that the head of the list is the current state and the + * stack is pushed by adding a new state to the head of the + * list or popped by removing the first link. + */ + +struct state { + int flags; /* Current state flags */ + int maxdepth; /* Current maximum trace depth */ + unsigned int delay; /* Delay after each output line */ + int level; /* Current function nesting level */ + FILE *out_file; /* Current output stream */ + FILE *prof_file; /* Current profiling stream */ + struct link *functions; /* List of functions */ + struct link *p_functions; /* List of profiled functions */ + struct link *keywords; /* List of debug keywords */ + struct link *processes; /* List of process names */ + struct state *next_state; /* Next state in the list */ +}; + +LOCAL struct state *stack = NULL; /* Linked list of stacked states */ + +/* + * Local variables not seen by user. + */ + +LOCAL int lineno = 0; /* Current debugger output line number */ +LOCAL char *func = "?func"; /* Name of current user function */ +LOCAL char *file = "?file"; /* Name of current user file */ +LOCAL BOOLEAN init_done = FALSE;/* Set to TRUE when initialization done */ +LOCAL char **framep = NULL; /* Pointer to current frame */ + +#if (unix || xenix || amiga || defined(__TURBOC__)) +LOCAL int jmplevel; /* Remember nesting level at setjmp () */ +LOCAL char *jmpfunc; /* Remember current function for setjmp */ +LOCAL char *jmpfile; /* Remember current file for setjmp */ +#endif + +LOCAL struct link *ListParse ();/* Parse a debug command string */ +LOCAL char *StrDup (); /* Make a fresh copy of a string */ +LOCAL VOID OpenFile (); /* Open debug output stream */ +LOCAL VOID OpenProfile (); /* Open profile output stream */ +LOCAL VOID CloseFile (); /* Close debug output stream */ +LOCAL VOID PushState (); /* Push current debug state */ +LOCAL VOID ChangeOwner (); /* Change file owner and group */ +LOCAL BOOLEAN DoTrace (); /* Test for tracing enabled */ +LOCAL BOOLEAN Writable (); /* Test to see if file is writable */ +LOCAL unsigned long Clock (); /* Return current user time (ms) */ +LOCAL long *DbugMalloc (); /* Allocate memory for runtime support */ +LOCAL char *BaseName (); /* Remove leading pathname components */ +LOCAL VOID DoPrefix (); /* Print debugger line prefix */ +LOCAL VOID FreeList (); /* Free memory from linked list */ +LOCAL VOID Indent (); /* Indent line to specified indent */ + + /* Supplied in Sys V runtime environ */ +LOCAL char *strtok (); /* Break string into tokens */ +LOCAL char *strrchr (); /* Find last occurance of char */ + +/* + * The following local variables are used to hold the state information + * between the call to _db_pargs_() and _db_doprnt_(), during + * expansion of the DBUG_PRINT macro. This is the only macro + * that currently uses these variables. + * + * These variables are currently used only by _db_pargs_() and + * _db_doprnt_(). + */ + +LOCAL int u_line = 0; /* User source code line number */ +LOCAL char *u_keyword = "?"; /* Keyword for current macro */ + +/* + * Miscellaneous printf format strings. + */ + +#define ERR_MISSING_RETURN "%s: missing DBUG_RETURN or DBUG_VOID_RETURN macro in function \"%s\"\n" +#define ERR_OPEN "%s: can't open debug output stream \"%s\": " +#define ERR_CLOSE "%s: can't close debug file: " +#define ERR_ABORT "%s: debugger aborting because %s\n" +#define ERR_CHOWN "%s: can't change owner/group of \"%s\": " + +/* + * Macros and defines for testing file accessibility under UNIX. + */ + +#if (unix || xenix) +# define A_EXISTS 00 /* Test for file existance */ +# define A_EXECUTE 01 /* Test for execute permission */ +# define A_WRITE 02 /* Test for write access */ +# define A_READ 03 /* Test for read access */ +# define EXISTS(pathname) (access (pathname, A_EXISTS) == 0) +# define WRITABLE(pathname) (access (pathname, A_WRITE) == 0) +#else +# define EXISTS(pathname) (FALSE) /* Assume no existance */ +#endif + +/* + * Translate some calls among different systems. + */ + +#if (unix || xenix) +# define Delay sleep +IMPORT unsigned int sleep (); /* Pause for given number of seconds */ +#endif + +#if amiga +IMPORT int Delay (); /* Pause for given number of ticks */ +#endif + + +/* + * FUNCTION + * + * _db_push_ push current debugger state and set up new one + * + * SYNOPSIS + * + * VOID _db_push_ (control) + * char *control; + * + * DESCRIPTION + * + * Given pointer to a debug control string in "control", pushes + * the current debug state, parses the control string, and sets + * up a new debug state. + * + * The only attribute of the new state inherited from the previous + * state is the current function nesting level. This can be + * overridden by using the "r" flag in the control string. + * + * The debug control string is a sequence of colon separated fields + * as follows: + * + * ::...: + * + * Each field consists of a mandatory flag character followed by + * an optional "," and comma separated list of modifiers: + * + * flag[,modifier,modifier,...,modifier] + * + * The currently recognized flag characters are: + * + * d Enable output from DBUG_ macros for + * for the current state. May be followed + * by a list of keywords which selects output + * only for the DBUG macros with that keyword. + * A null list of keywords implies output for + * all macros. + * + * D Delay after each debugger output line. + * The argument is the number of tenths of seconds + * to delay, subject to machine capabilities. + * I.E. -#D,20 is delay two seconds. + * + * f Limit debugging and/or tracing, and profiling to the + * list of named functions. Note that a null list will + * disable all functions. The appropriate "d" or "t" + * flags must still be given, this flag only limits their + * actions if they are enabled. + * + * F Identify the source file name for each + * line of debug or trace output. + * + * i Identify the process with the pid for each line of + * debug or trace output. + * + * g Enable profiling. Create a file called 'dbugmon.out' + * containing information that can be used to profile + * the program. May be followed by a list of keywords + * that select profiling only for the functions in that + * list. A null list implies that all functions are + * considered. + * + * L Identify the source file line number for + * each line of debug or trace output. + * + * n Print the current function nesting depth for + * each line of debug or trace output. + * + * N Number each line of dbug output. + * + * o Redirect the debugger output stream to the + * specified file. The default output is stderr. + * + * p Limit debugger actions to specified processes. + * A process must be identified with the + * DBUG_PROCESS macro and match one in the list + * for debugger actions to occur. + * + * P Print the current process name for each + * line of debug or trace output. + * + * r When pushing a new state, do not inherit + * the previous state's function nesting level. + * Useful when the output is to start at the + * left margin. + * + * t Enable function call/exit trace lines. + * May be followed by a list (containing only + * one modifier) giving a numeric maximum + * trace level, beyond which no output will + * occur for either debugging or tracing + * macros. The default is a compile time + * option. + * + * Some examples of debug control strings which might appear + * on a shell command line (the "-#" is typically used to + * introduce a control string to an application program) are: + * + * -#d:t + * -#d:f,main,subr1:F:L:t,20 + * -#d,input,output,files:n + * + * For convenience, any leading "-#" is stripped off. + * + */ + + +VOID _db_push_ (control) +char *control; +{ + REGISTER char *scan; + REGISTER struct link *temp; + + if (control && *control == '-') { + if (*++control == '#') { + control++; + } + } + control = StrDup (control); + PushState (); + scan = strtok (control, ":"); + for (; scan != NULL; scan = strtok ((char *)NULL, ":")) { + switch (*scan++) { + case 'd': + _db_on_ = TRUE; + stack -> flags |= DEBUG_ON; + if (*scan++ == ',') { + stack -> keywords = ListParse (scan); + } + break; + case 'D': + stack -> delay = 0; + if (*scan++ == ',') { + temp = ListParse (scan); + stack -> delay = DelayArg (atoi (temp -> string)); + FreeList (temp); + } + break; + case 'f': + if (*scan++ == ',') { + stack -> functions = ListParse (scan); + } + break; + case 'F': + stack -> flags |= FILE_ON; + break; + case 'i': + stack -> flags |= PID_ON; + break; + case 'g': + _db_pon_ = TRUE; + OpenProfile(PROF_FILE); + stack -> flags |= PROFILE_ON; + if (*scan++ == ',') { + stack -> p_functions = ListParse (scan); + } + break; + case 'L': + stack -> flags |= LINE_ON; + break; + case 'n': + stack -> flags |= DEPTH_ON; + break; + case 'N': + stack -> flags |= NUMBER_ON; + break; + case 'o': + if (*scan++ == ',') { + temp = ListParse (scan); + OpenFile (temp -> string); + FreeList (temp); + } else { + OpenFile ("-"); + } + break; + case 'p': + if (*scan++ == ',') { + stack -> processes = ListParse (scan); + } + break; + case 'P': + stack -> flags |= PROCESS_ON; + break; + case 'r': + stack -> level = 0; + break; + case 't': + stack -> flags |= TRACE_ON; + if (*scan++ == ',') { + temp = ListParse (scan); + stack -> maxdepth = atoi (temp -> string); + FreeList (temp); + } + break; + } + } + free (control); +} + + + +/* + * FUNCTION + * + * _db_pop_ pop the debug stack + * + * DESCRIPTION + * + * Pops the debug stack, returning the debug state to its + * condition prior to the most recent _db_push_ invocation. + * Note that the pop will fail if it would remove the last + * valid state from the stack. This prevents user errors + * in the push/pop sequence from screwing up the debugger. + * Maybe there should be some kind of warning printed if the + * user tries to pop too many states. + * + */ + +VOID _db_pop_ () +{ + REGISTER struct state *discard; + + discard = stack; + if (discard != NULL && discard -> next_state != NULL) { + stack = discard -> next_state; + _db_fp_ = stack -> out_file; + _db_pfp_ = stack -> prof_file; + if (discard -> keywords != NULL) { + FreeList (discard -> keywords); + } + if (discard -> functions != NULL) { + FreeList (discard -> functions); + } + if (discard -> processes != NULL) { + FreeList (discard -> processes); + } + if (discard -> p_functions != NULL) { + FreeList (discard -> p_functions); + } + CloseFile (discard -> out_file); + CloseFile (discard -> prof_file); + free ((char *) discard); + } +} + + +/* + * FUNCTION + * + * _db_enter_ process entry point to user function + * + * SYNOPSIS + * + * VOID _db_enter_ (_func_, _file_, _line_, + * _sfunc_, _sfile_, _slevel_, _sframep_) + * char *_func_; points to current function name + * char *_file_; points to current file name + * int _line_; called from source line number + * char **_sfunc_; save previous _func_ + * char **_sfile_; save previous _file_ + * int *_slevel_; save previous nesting level + * char ***_sframep_; save previous frame pointer + * + * DESCRIPTION + * + * Called at the beginning of each user function to tell + * the debugger that a new function has been entered. + * Note that the pointers to the previous user function + * name and previous user file name are stored on the + * caller's stack (this is why the ENTER macro must be + * the first "executable" code in a function, since it + * allocates these storage locations). The previous nesting + * level is also stored on the callers stack for internal + * self consistency checks. + * + * Also prints a trace line if tracing is enabled and + * increments the current function nesting depth. + * + * Note that this mechanism allows the debugger to know + * what the current user function is at all times, without + * maintaining an internal stack for the function names. + * + */ + +VOID _db_enter_ (_func_, _file_, _line_, _sfunc_, _sfile_, _slevel_, + _sframep_) +char *_func_; +char *_file_; +int _line_; +char **_sfunc_; +char **_sfile_; +int *_slevel_; +char ***_sframep_; +{ + long stackused; + + if (!init_done) { + _db_push_ (""); + } + *_sfunc_ = func; + func = _func_; + *_sfile_ = file; + file = BaseName (_file_); + stack -> level++; + *_slevel_ = stack -> level; + *_sframep_ = framep; + framep = (char **) _sframep_; + if (DoProfile ()) { + if (*framep == NULL) { + stackused = 0; + } else { + stackused = ((long)(*framep)) - ((long)(framep)); + stackused = stackused > 0 ? stackused : -stackused; + } + (VOID) fprintf (_db_pfp_, PROF_EFMT , Clock (), func); +#if AUTOS_REVERSE + (VOID) fprintf (_db_pfp_, PROF_SFMT, framep, stackused, *_sfunc_); +#else + (VOID) fprintf (_db_pfp_, PROF_SFMT, framep, stackused, func); +#endif + (VOID) fflush (_db_pfp_); + } + if (DoTrace ()) { + DoPrefix (_line_); + Indent (stack -> level); + (VOID) fprintf (_db_fp_, ">%s\n", func); + (VOID) fflush (_db_fp_); + (VOID) Delay (stack -> delay); + } +} + + +/* + * FUNCTION + * + * _db_return_ process exit from user function + * + * SYNOPSIS + * + * VOID _db_return_ (_line_, _sfunc_, _sfile_, _slevel_) + * int _line_; current source line number + * char **_sfunc_; where previous _func_ is to be retrieved + * char **_sfile_; where previous _file_ is to be retrieved + * int *_slevel_; where previous level was stashed + * + * DESCRIPTION + * + * Called just before user function executes an explicit or implicit + * return. Prints a trace line if trace is enabled, decrements + * the current nesting level, and restores the current function and + * file names from the defunct function's stack. + * + */ + +VOID _db_return_ (_line_, _sfunc_, _sfile_, _slevel_) +int _line_; +char **_sfunc_; +char **_sfile_; +int *_slevel_; +{ + if (!init_done) { + _db_push_ (""); + } + if (stack -> level != *_slevel_ && (TRACING || DEBUGGING || PROFILING)) { + (VOID) fprintf (_db_fp_, ERR_MISSING_RETURN, _db_process_, func); + } else if (DoProfile ()) { + (VOID) fprintf (_db_pfp_, PROF_XFMT, Clock(), func); + } else if (DoTrace ()) { + DoPrefix (_line_); + Indent (stack -> level); + (VOID) fprintf (_db_fp_, "<%s\n", func); + } + (VOID) fflush (_db_fp_); + (VOID) Delay (stack -> delay); + stack -> level = *_slevel_ - 1; + func = *_sfunc_; + file = *_sfile_; + if (framep != NULL) { + framep = (char **) *framep; + } +} + + +/* + * FUNCTION + * + * _db_pargs_ log arguments for subsequent use by _db_doprnt_() + * + * SYNOPSIS + * + * VOID _db_pargs_ (_line_, keyword) + * int _line_; + * char *keyword; + * + * DESCRIPTION + * + * The new universal printing macro DBUG_PRINT, which replaces + * all forms of the DBUG_N macros, needs two calls to runtime + * support routines. The first, this function, remembers arguments + * that are used by the subsequent call to _db_doprnt_(). +* + */ + +VOID _db_pargs_ (_line_, keyword) +int _line_; +char *keyword; +{ + u_line = _line_; + u_keyword = keyword; +} + + +/* + * FUNCTION + * + * _db_doprnt_ handle print of debug lines + * + * SYNOPSIS + * + * VOID _db_doprnt_ (format, va_alist) + * char *format; + * va_dcl; + * + * DESCRIPTION + * + * When invoked via one of the DBUG macros, tests the current keyword + * set by calling _db_pargs_() to see if that macro has been selected + * for processing via the debugger control string, and if so, handles + * printing of the arguments via the format string. The line number + * of the DBUG macro in the source is found in u_line. + * + * Note that the format string SHOULD NOT include a terminating + * newline, this is supplied automatically. + * + */ + +/*VARARGS1*/ + +#ifndef NO_VARARGS + +VOID _db_doprnt_ (char *format, ...) +{ + va_list args; + + va_start (args, format); + if (_db_keyword_ (u_keyword)) { + DoPrefix (u_line); + if (TRACING) { + Indent (stack -> level + 1); + } else { + (VOID) fprintf (_db_fp_, "%s: ", func); + } + (VOID) fprintf (_db_fp_, "%s: ", u_keyword); + (VOID) vfprintf (_db_fp_, format, args); + (VOID) fprintf (_db_fp_, "\n"); + (VOID) fflush (_db_fp_); + (VOID) Delay (stack -> delay); + } + va_end (args); +} + +#else + +VOID _db_doprnt_ (format, va_alist) +char *format; +va_dcl +{ + va_list args; + + va_start (args); + if (_db_keyword_ (u_keyword)) { + DoPrefix (u_line); + if (TRACING) { + Indent (stack -> level + 1); + } else { + (VOID) fprintf (_db_fp_, "%s: ", func); + } + (VOID) fprintf (_db_fp_, "%s: ", u_keyword); + (VOID) vfprintf (_db_fp_, format, args); + (VOID) fprintf (_db_fp_, "\n"); + (VOID) fflush (_db_fp_); + (VOID) Delay (stack -> delay); + } + va_end (args); +} + +#endif + + +/* + * FUNCTION + * + * ListParse parse list of modifiers in debug control string + * + * SYNOPSIS + * + * LOCAL struct link *ListParse (ctlp) + * char *ctlp; + * + * DESCRIPTION + * + * Given pointer to a comma separated list of strings in "cltp", + * parses the list, building a list and returning a pointer to it. + * The original comma separated list is destroyed in the process of + * building the linked list, thus it had better be a duplicate + * if it is important. + * + * Note that since each link is added at the head of the list, + * the final list will be in "reverse order", which is not + * significant for our usage here. + * + */ + +LOCAL struct link *ListParse (ctlp) +char *ctlp; +{ + REGISTER char *start; + REGISTER struct link *new; + REGISTER struct link *head; + + head = NULL; + while (*ctlp != EOS) { + start = ctlp; + while (*ctlp != EOS && *ctlp != ',') { + ctlp++; + } + if (*ctlp == ',') { + *ctlp++ = EOS; + } + new = (struct link *) DbugMalloc (sizeof (struct link)); + new -> string = StrDup (start); + new -> next_link = head; + head = new; + } + return (head); +} + + +/* + * FUNCTION + * + * InList test a given string for member of a given list + * + * SYNOPSIS + * + * LOCAL BOOLEAN InList (linkp, cp) + * struct link *linkp; + * char *cp; + * + * DESCRIPTION + * + * Tests the string pointed to by "cp" to determine if it is in + * the list pointed to by "linkp". Linkp points to the first + * link in the list. If linkp is NULL then the string is treated + * as if it is in the list (I.E all strings are in the null list). + * This may seem rather strange at first but leads to the desired + * operation if no list is given. The net effect is that all + * strings will be accepted when there is no list, and when there + * is a list, only those strings in the list will be accepted. + * + */ + +LOCAL BOOLEAN InList (linkp, cp) +struct link *linkp; +char *cp; +{ + REGISTER struct link *scan; + REGISTER BOOLEAN accept; + + if (linkp == NULL) { + accept = TRUE; + } else { + accept = FALSE; + for (scan = linkp; scan != NULL; scan = scan -> next_link) { + if (STREQ (scan -> string, cp)) { + accept = TRUE; + break; + } + } + } + return (accept); +} + + +/* + * FUNCTION + * + * PushState push current state onto stack and set up new one + * + * SYNOPSIS + * + * LOCAL VOID PushState () + * + * DESCRIPTION + * + * Pushes the current state on the state stack, and initializes + * a new state. The only parameter inherited from the previous + * state is the function nesting level. This action can be + * inhibited if desired, via the "r" flag. + * + * The state stack is a linked list of states, with the new + * state added at the head. This allows the stack to grow + * to the limits of memory if necessary. + * + */ + +LOCAL VOID PushState () +{ + REGISTER struct state *new; + + new = (struct state *) DbugMalloc (sizeof (struct state)); + new -> flags = 0; + new -> delay = 0; + new -> maxdepth = MAXDEPTH; + if (stack != NULL) { + new -> level = stack -> level; + } else { + new -> level = 0; + } + new -> out_file = stderr; + new -> functions = NULL; + new -> p_functions = NULL; + new -> keywords = NULL; + new -> processes = NULL; + new -> next_state = stack; + stack = new; + init_done = TRUE; +} + + +/* + * FUNCTION + * + * DoTrace check to see if tracing is current enabled + * + * SYNOPSIS + * + * LOCAL BOOLEAN DoTrace () + * + * DESCRIPTION + * + * Checks to see if tracing is enabled based on whether the + * user has specified tracing, the maximum trace depth has + * not yet been reached, the current function is selected, + * and the current process is selected. Returns TRUE if + * tracing is enabled, FALSE otherwise. + * + */ + +LOCAL BOOLEAN DoTrace () +{ + REGISTER BOOLEAN trace; + + trace = FALSE; + if (TRACING) { + if (stack -> level <= stack -> maxdepth) { + if (InList (stack -> functions, func)) { + if (InList (stack -> processes, _db_process_)) { + trace = TRUE; + } + } + } + } + return (trace); +} + + +/* + * FUNCTION + * + * DoProfile check to see if profiling is current enabled + * + * SYNOPSIS + * + * LOCAL BOOLEAN DoProfile () + * + * DESCRIPTION + * + * Checks to see if profiling is enabled based on whether the + * user has specified profiling, the maximum trace depth has + * not yet been reached, the current function is selected, + * and the current process is selected. Returns TRUE if + * profiling is enabled, FALSE otherwise. + * + */ + +LOCAL BOOLEAN DoProfile () +{ + REGISTER BOOLEAN profile; + + profile = FALSE; + if (PROFILING) { + if (stack -> level <= stack -> maxdepth) { + if (InList (stack -> p_functions, func)) { + if (InList (stack -> processes, _db_process_)) { + profile = TRUE; + } + } + } + } + return (profile); +} + + +/* + * FUNCTION + * + * _db_keyword_ test keyword for member of keyword list + * + * SYNOPSIS + * + * BOOLEAN _db_keyword_ (keyword) + * char *keyword; + * + * DESCRIPTION + * + * Test a keyword to determine if it is in the currently active + * keyword list. As with the function list, a keyword is accepted + * if the list is null, otherwise it must match one of the list + * members. When debugging is not on, no keywords are accepted. + * After the maximum trace level is exceeded, no keywords are + * accepted (this behavior subject to change). Additionally, + * the current function and process must be accepted based on + * their respective lists. + * + * Returns TRUE if keyword accepted, FALSE otherwise. + * + */ + +BOOLEAN _db_keyword_ (keyword) +char *keyword; +{ + REGISTER BOOLEAN accept; + + if (!init_done) { + _db_push_ (""); + } + accept = FALSE; + if (DEBUGGING) { + if (stack -> level <= stack -> maxdepth) { + if (InList (stack -> functions, func)) { + if (InList (stack -> keywords, keyword)) { + if (InList (stack -> processes, _db_process_)) { + accept = TRUE; + } + } + } + } + } + return (accept); +} + + +/* + * FUNCTION + * + * Indent indent a line to the given indentation level + * + * SYNOPSIS + * + * LOCAL VOID Indent (indent) + * int indent; + * + * DESCRIPTION + * + * Indent a line to the given level. Note that this is + * a simple minded but portable implementation. + * There are better ways. + * + * Also, the indent must be scaled by the compile time option + * of character positions per nesting level. + * + */ + +LOCAL VOID Indent (indent) +int indent; +{ + REGISTER int count; + AUTO char buffer[PRINTBUF]; + + indent *= INDENT; + for (count = 0; (count < (indent - INDENT)) && (count < (PRINTBUF - 1)); count++) { + if ((count % INDENT) == 0) { + buffer[count] = '|'; + } else { + buffer[count] = ' '; + } + } + buffer[count] = EOS; + (VOID) fprintf (_db_fp_, buffer); + (VOID) fflush (_db_fp_); +} + + +/* + * FUNCTION + * + * FreeList free all memory associated with a linked list + * + * SYNOPSIS + * + * LOCAL VOID FreeList (linkp) + * struct link *linkp; + * + * DESCRIPTION + * + * Given pointer to the head of a linked list, frees all + * memory held by the list and the members of the list. + * + */ + +LOCAL VOID FreeList (linkp) +struct link *linkp; +{ + REGISTER struct link *old; + + while (linkp != NULL) { + old = linkp; + linkp = linkp -> next_link; + if (old -> string != NULL) { + free (old -> string); + } + free ((char *) old); + } +} + + +/* + * FUNCTION + * + * StrDup make a duplicate of a string in new memory + * + * SYNOPSIS + * + * LOCAL char *StrDup (string) + * char *string; + * + * DESCRIPTION + * + * Given pointer to a string, allocates sufficient memory to make + * a duplicate copy, and copies the string to the newly allocated + * memory. Failure to allocated sufficient memory is immediately + * fatal. + * + */ + + +LOCAL char *StrDup (string) +char *string; +{ + REGISTER char *new; + + new = (char *) DbugMalloc (strlen (string) + 1); + (VOID) strcpy (new, string); + return (new); +} + + +/* + * FUNCTION + * + * DoPrefix print debugger line prefix prior to indentation + * + * SYNOPSIS + * + * LOCAL VOID DoPrefix (_line_) + * int _line_; + * + * DESCRIPTION + * + * Print prefix common to all debugger output lines, prior to + * doing indentation if necessary. Print such information as + * current process name, current source file name and line number, + * and current function nesting depth. + * + */ + + +LOCAL VOID DoPrefix (_line_) +int _line_; +{ +#if (unix || xenix) + extern int getpid (); +#endif + + lineno++; +#if (unix || xenix) + if (stack -> flags & PID_ON) { + (VOID) fprintf (_db_fp_, "%5d: ", getpid ()); + } +#endif + if (stack -> flags & NUMBER_ON) { + (VOID) fprintf (_db_fp_, "%5d: ", lineno); + } + if (stack -> flags & PROCESS_ON) { + (VOID) fprintf (_db_fp_, "%s: ", _db_process_); + } + if (stack -> flags & FILE_ON) { + (VOID) fprintf (_db_fp_, "%14s: ", file); + } + if (stack -> flags & LINE_ON) { + (VOID) fprintf (_db_fp_, "%5d: ", _line_); + } + if (stack -> flags & DEPTH_ON) { + (VOID) fprintf (_db_fp_, "%4d: ", stack -> level); + } + (VOID) fflush (_db_fp_); +} + + +/* + * FUNCTION + * + * OpenFile open new output stream for debugger output + * + * SYNOPSIS + * + * LOCAL VOID OpenFile (name) + * char *name; + * + * DESCRIPTION + * + * Given name of a new file (or "-" for stdout) opens the file + * and sets the output stream to the new file. + * + */ + +LOCAL VOID OpenFile (name) +char *name; +{ + REGISTER FILE *fp; + REGISTER BOOLEAN newfile; + + if (name != NULL) { + if (strcmp (name, "-") == 0) { + _db_fp_ = stdout; + stack -> out_file = _db_fp_; + } else { + if (!Writable (name)) { + (VOID) fprintf (_db_fp_, ERR_OPEN, _db_process_, name); + perror (""); + (VOID) fflush (_db_fp_); + (VOID) Delay (stack -> delay); + } else { + if (EXISTS (name)) { + newfile = FALSE; + } else { + newfile = TRUE; + } + fp = fopen (name, "a"); + if (fp == NULL) { + (VOID) fprintf (_db_fp_, ERR_OPEN, _db_process_, name); + perror (""); + (VOID) fflush (_db_fp_); + (VOID) Delay (stack -> delay); + } else { + _db_fp_ = fp; + stack -> out_file = fp; + if (newfile) { + ChangeOwner (name); + } + } + } + } + } +} + + +/* + * FUNCTION + * + * OpenProfile open new output stream for profiler output + * + * SYNOPSIS + * + * LOCAL VOID OpenProfile (name) + * char *name; + * + * DESCRIPTION + * + * Given name of a new file, opens the file + * and sets the profiler output stream to the new file. + * + * It is currently unclear whether the prefered behavior is + * to truncate any existing file, or simply append to it. + * The latter behavior would be desirable for collecting + * accumulated runtime history over a number of separate + * runs. It might take some changes to the analyzer program + * though, and the notes that Binayak sent with the profiling + * diffs indicated that append was the normal mode, but this + * does not appear to agree with the actual code. I haven't + * investigated at this time [fnf; 24-Jul-87]. + */ + +LOCAL VOID OpenProfile (name) +char *name; +{ + REGISTER FILE *fp; + REGISTER BOOLEAN newfile; + + if (name != NULL) { + if (!Writable (name)) { + (VOID) fprintf (_db_fp_, ERR_OPEN, _db_process_, name); + perror (""); + (VOID) fflush (_db_fp_); + (VOID) Delay (stack -> delay); + } else { + if (EXISTS (name)) { + newfile = FALSE; + } else { + newfile = TRUE; + } + fp = fopen (name, "w"); + if (fp == NULL) { + (VOID) fprintf (_db_fp_, ERR_OPEN, _db_process_, name); + perror (""); + (VOID) fflush (_db_fp_); + (VOID) Delay (stack -> delay); + } else { + _db_pfp_ = fp; + stack -> prof_file = fp; + if (newfile) { + ChangeOwner (name); + } + } + } + } +} + + +/* + * FUNCTION + * + * CloseFile close the debug output stream + * + * SYNOPSIS + * + * LOCAL VOID CloseFile (fp) + * FILE *fp; + * + * DESCRIPTION + * + * Closes the debug output stream unless it is standard output + * or standard error. + * + */ + +LOCAL VOID CloseFile (fp) +FILE *fp; +{ + if (fp != stderr && fp != stdout) { + if (fclose (fp) == EOF) { + (VOID) fprintf (stderr, ERR_CLOSE, _db_process_); + perror (""); + (VOID) fflush (stderr); + (VOID) Delay (stack -> delay); + } + } +} + + +/* + * FUNCTION + * + * DbugExit print error message and exit + * + * SYNOPSIS + * + * LOCAL VOID DbugExit (why) + * char *why; + * + * DESCRIPTION + * + * Prints error message using current process name, the reason for + * aborting (typically out of memory), and exits with status 1. + * This should probably be changed to use a status code + * defined in the user's debugger include file. + * + */ + +LOCAL VOID DbugExit (why) +char *why; +{ + (VOID) fprintf (stderr, ERR_ABORT, _db_process_, why); + (VOID) fflush (stderr); + (VOID) Delay (stack -> delay); + exit (1); +} + + +/* + * FUNCTION + * + * DbugMalloc allocate memory for debugger runtime support + * + * SYNOPSIS + * + * LOCAL long *DbugMalloc (size) + * int size; + * + * DESCRIPTION + * + * Allocate more memory for debugger runtime support functions. + * Failure to to allocate the requested number of bytes is + * immediately fatal to the current process. This may be + * rather unfriendly behavior. It might be better to simply + * print a warning message, freeze the current debugger state, + * and continue execution. + * + */ + +LOCAL long *DbugMalloc (size) +int size; +{ + register long *new; + + new = (long *) malloc ((unsigned int) size); + if (new == NULL) { + DbugExit ("out of memory"); + } + return (new); +} + + +/* + * This function may be eliminated when strtok is available + * in the runtime environment (missing from BSD4.1). + */ + +LOCAL char *strtok (s1, s2) +char *s1, *s2; +{ + static char *end = NULL; + REGISTER char *rtnval; + + rtnval = NULL; + if (s2 != NULL) { + if (s1 != NULL) { + end = s1; + rtnval = strtok ((char *) NULL, s2); + } else if (end != NULL) { + if (*end != EOS) { + rtnval = end; + while (*end != *s2 && *end != EOS) {end++;} + if (*end != EOS) { + *end++ = EOS; + } + } + } + } + return (rtnval); +} + + +/* + * FUNCTION + * + * BaseName strip leading pathname components from name + * + * SYNOPSIS + * + * LOCAL char *BaseName (pathname) + * char *pathname; + * + * DESCRIPTION + * + * Given pointer to a complete pathname, locates the base file + * name at the end of the pathname and returns a pointer to + * it. + * + */ + +LOCAL char *BaseName (pathname) +char *pathname; +{ + register char *base; + + base = strrchr (pathname, '/'); + if (base++ == NULL) { + base = pathname; + } + return (base); +} + + +/* + * FUNCTION + * + * Writable test to see if a pathname is writable/creatable + * + * SYNOPSIS + * + * LOCAL BOOLEAN Writable (pathname) + * char *pathname; + * + * DESCRIPTION + * + * Because the debugger might be linked in with a program that + * runs with the set-uid-bit (suid) set, we have to be careful + * about opening a user named file for debug output. This consists + * of checking the file for write access with the real user id, + * or checking the directory where the file will be created. + * + * Returns TRUE if the user would normally be allowed write or + * create access to the named file. Returns FALSE otherwise. + * + */ + +LOCAL BOOLEAN Writable (pathname) +char *pathname; +{ + REGISTER BOOLEAN granted; +#if (unix || xenix) + REGISTER char *lastslash; +#endif + +#if (!unix && !xenix) + granted = TRUE; +#else + granted = FALSE; + if (EXISTS (pathname)) { + if (WRITABLE (pathname)) { + granted = TRUE; + } + } else { + lastslash = strrchr (pathname, '/'); + if (lastslash != NULL) { + *lastslash = EOS; + } else { + pathname = "."; + } + if (WRITABLE (pathname)) { + granted = TRUE; + } + if (lastslash != NULL) { + *lastslash = '/'; + } + } +#endif + return (granted); +} + + +/* + * This function may be eliminated when strrchr is available + * in the runtime environment (missing from BSD4.1). + * Alternately, you can use rindex() on BSD systems. + */ + +LOCAL char *strrchr (s, c) +char *s; +char c; +{ + REGISTER char *scan; + + for (scan = s; *scan != EOS; scan++) {;} + while (scan > s && *--scan != c) {;} + if (*scan != c) { + scan = NULL; + } + return (scan); +} + + +/* + * FUNCTION + * + * ChangeOwner change owner to real user for suid programs + * + * SYNOPSIS + * + * LOCAL VOID ChangeOwner (pathname) + * + * DESCRIPTION + * + * For unix systems, change the owner of the newly created debug + * file to the real owner. This is strictly for the benefit of + * programs that are running with the set-user-id bit set. + * + * Note that at this point, the fact that pathname represents + * a newly created file has already been established. If the + * program that the debugger is linked to is not running with + * the suid bit set, then this operation is redundant (but + * harmless). + * + */ + +LOCAL VOID ChangeOwner (pathname) +char *pathname; +{ +#if (unix || xenix) + if (chown (pathname, getuid (), getgid ()) == -1) { + (VOID) fprintf (stderr, ERR_CHOWN, _db_process_, pathname); + perror (""); + (VOID) fflush (stderr); + (VOID) Delay (stack -> delay); + } +#endif +} + + +/* + * FUNCTION + * + * _db_setjmp_ save debugger environment + * + * SYNOPSIS + * + * VOID _db_setjmp_ () + * + * DESCRIPTION + * + * Invoked as part of the user's DBUG_SETJMP macro to save + * the debugger environment in parallel with saving the user's + * environment. + * + */ + +VOID _db_setjmp_ () +{ + jmplevel = stack -> level; + jmpfunc = func; + jmpfile = file; +} + + +/* + * FUNCTION + * + * _db_longjmp_ restore previously saved debugger environment + * + * SYNOPSIS + * + * VOID _db_longjmp_ () + * + * DESCRIPTION + * + * Invoked as part of the user's DBUG_LONGJMP macro to restore + * the debugger environment in parallel with restoring the user's + * previously saved environment. + * + */ + +VOID _db_longjmp_ () +{ + stack -> level = jmplevel; + if (jmpfunc) { + func = jmpfunc; + } + if (jmpfile) { + file = jmpfile; + } +} + + +/* + * FUNCTION + * + * DelayArg convert D flag argument to appropriate value + * + * SYNOPSIS + * + * LOCAL int DelayArg (value) + * int value; + * + * DESCRIPTION + * + * Converts delay argument, given in tenths of a second, to the + * appropriate numerical argument used by the system to delay + * that that many tenths of a second. For example, on the + * amiga, there is a system call "Delay()" which takes an + * argument in ticks (50 per second). On unix, the sleep + * command takes seconds. Thus a value of "10", for one + * second of delay, gets converted to 50 on the amiga, and 1 + * on unix. Other systems will need to use a timing loop. + * + */ + +LOCAL int DelayArg (value) +int value; +{ + unsigned int delayarg = 0; + +#if (unix || xenix) + delayarg = value / 10; /* Delay is in seconds for sleep () */ +#endif +#if amiga + delayarg = (HZ * value) / 10; /* Delay in ticks for Delay () */ +#endif + return (delayarg); +} + + +/* + * A dummy delay stub for systems that do not support delays. + * With a little work, this can be turned into a timing loop. + */ + +#if (!unix && !xenix && !amiga) +Delay () +{ +} +#endif + + +/* + * FUNCTION + * + * perror perror simulation for systems that don't have it + * + * SYNOPSIS + * + * LOCAL VOID perror (s) + * char *s; + * + * DESCRIPTION + * + * Perror produces a message on the standard error stream which + * provides more information about the library or system error + * just encountered. The argument string s is printed, followed + * by a ':', a blank, and then a message and a newline. + * + * An undocumented feature of the unix perror is that if the string + * 's' is a null string (NOT a NULL pointer!), then the ':' and + * blank are not printed. + * + * This version just complains about an "unknown system error". + * + */ + +#if !unix && !xenix && !(amiga && LATTICE) && !defined(__TURBOC__) + +LOCAL VOID perror (s) +char *s; +{ + if (s && *s != EOS) { + (VOID) fprintf (stderr, "%s: ", s); + } + (VOID) fprintf (stderr, "\n"); +} + +#endif /* !unix && !xenix && !(amiga && LATTICE) */ + +/* + * Here we need the definitions of the clock routine. Add your + * own for whatever system that you have. + */ + +#if (unix || xenix) + +/* # include */ +# if BSD4_3 || sun + +/* + * Definition of the Clock() routine for 4.3 BSD. + */ + +#include +#include + +/* + * Returns the user time in milliseconds used by this process so + * far. + */ + +LOCAL unsigned long Clock () +{ + struct rusage ru; + + (VOID) getrusage (RUSAGE_SELF, &ru); + return ((ru.ru_utime.tv_sec * 1000) + (ru.ru_utime.tv_usec / 1000)); +} + +#else /* unix or xenix, but not 4.3 or sun */ + +/* +#if 1 +#include +#include +#include + +#ifndef HZ +#define HZ 60 +#endif + +LOCAL unsigned long Clock () +{ + struct tms now; + long elapsed; + + times(&now); + + elapsed = now.tms_utime * 1000 * HZ; + return(elapsed); +} + +#else +LOCAL unsigned long Clock () +{ + return (0); +} +#endif +*/ + +# endif + +#else /* not unix or xenix */ + +#if amiga + +struct DateStamp { /* Yes, this is a hack, but doing it right */ + long ds_Days; /* is incredibly ugly without splitting this */ + long ds_Minute; /* off into a separate file */ + long ds_Tick; +}; + +static int first_clock = TRUE; +static struct DateStamp begin; +static struct DateStamp elapsed; + +LOCAL unsigned long Clock () +{ + register struct DateStamp *now; + register unsigned long millisec = 0; + extern VOID *AllocMem (); + + now = (struct DateStamp *) AllocMem ((long) sizeof (struct DateStamp), 0L); + if (now != NULL) { + if (first_clock == TRUE) { + first_clock = FALSE; + (VOID) DateStamp (now); + begin = *now; + } + (VOID) DateStamp (now); + millisec = 24 * 3600 * (1000 / HZ) * (now -> ds_Days - begin.ds_Days); + millisec += 60 * (1000 / HZ) * (now -> ds_Minute - begin.ds_Minute); + millisec += (1000 / HZ) * (now -> ds_Tick - begin.ds_Tick); + (VOID) FreeMem (now, (long) sizeof (struct DateStamp)); + } + return (millisec); +} + +#else /* not amiga */ +LOCAL unsigned long Clock () +{ + return (0); +} +#endif /* amiga */ +#endif /* unix */ diff --git a/dbug/dbug.h b/dbug/dbug.h new file mode 100644 index 0000000..7a211e6 --- /dev/null +++ b/dbug/dbug.h @@ -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 + * + * 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_ 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 diff --git a/dbug/doinstall.sh b/dbug/doinstall.sh new file mode 100644 index 0000000..707f193 --- /dev/null +++ b/dbug/doinstall.sh @@ -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 diff --git a/dbug/example1.c b/dbug/example1.c new file mode 100644 index 0000000..805b0a2 --- /dev/null +++ b/dbug/example1.c @@ -0,0 +1,12 @@ +#include + +main (argc, argv) +int argc; +char *argv[]; +{ + printf ("argv[0] = %d\n", argv[0]); + /* + * Rest of program + */ + printf ("== done ==\n"); +} diff --git a/dbug/example2.c b/dbug/example2.c new file mode 100644 index 0000000..66ee43c --- /dev/null +++ b/dbug/example2.c @@ -0,0 +1,17 @@ +#include + +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 +} diff --git a/dbug/example3.c b/dbug/example3.c new file mode 100644 index 0000000..0eeb75e --- /dev/null +++ b/dbug/example3.c @@ -0,0 +1,16 @@ +#include + +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 +} diff --git a/dbug/factorial.c b/dbug/factorial.c new file mode 100644 index 0000000..afecffe --- /dev/null +++ b/dbug/factorial.c @@ -0,0 +1,15 @@ +#include +/* User programs should use */ +#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); +} diff --git a/dbug/install.sh b/dbug/install.sh new file mode 100644 index 0000000..7226e01 --- /dev/null +++ b/dbug/install.sh @@ -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 +# +# The file is replaced with the file , after first +# moving 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 " + 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 + diff --git a/dbug/llib-ldbug b/dbug/llib-ldbug new file mode 100644 index 0000000..6a6c791 --- /dev/null +++ b/dbug/llib-ldbug @@ -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 + +#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_ () +{ +} diff --git a/dbug/main.c b/dbug/main.c new file mode 100644 index 0000000..6b4bbc0 --- /dev/null +++ b/dbug/main.c @@ -0,0 +1,27 @@ +#include +/* User programs should use */ +#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); +} diff --git a/dbug/mklintlib.sh b/dbug/mklintlib.sh new file mode 100644 index 0000000..6963016 --- /dev/null +++ b/dbug/mklintlib.sh @@ -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 +# + +if test $# -ne 2 +then + echo "usage: mklintlib " + 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 $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 diff --git a/dbug/ranlib.sh b/dbug/ranlib.sh new file mode 100644 index 0000000..c0cd0c7 --- /dev/null +++ b/dbug/ranlib.sh @@ -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 diff --git a/dbug/useful.h b/dbug/useful.h new file mode 100644 index 0000000..7598eda --- /dev/null +++ b/dbug/useful.h @@ -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 +# endif + +/* + * For BSD systems, you can include 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 +# 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 */ diff --git a/dbug/user.r b/dbug/user.r new file mode 100644 index 0000000..851165f --- /dev/null +++ b/dbug/user.r @@ -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 "\ %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 diff --git a/dbug/user.t b/dbug/user.t new file mode 100644 index 0000000..0ddc72e --- /dev/null +++ b/dbug/user.t @@ -0,0 +1,1450 @@ + + + + D B U G + + C Program Debugging Package + + by + + Fred Fish + + + + + IIIINNNNTTTTRRRROOOODDDDUUUUCCCCTTTTIIIIOOOONNNN + + + 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 aaaaddddbbbb and ssssddddbbbb debuggers + provided with the UUUUNNNNIIIIXXXX811119 operating system. + + + 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. + + + On the other hand, _d_b_u_g 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 + + + __________ + + 1. UNIX is a trademark of AT&T Bell Laboratories. + + + + + - 1 - + + + + + + + + DBUG User Manual June 12, 1989 + + + + forms of internal instrumentation where each developer has + their own, usually less capable, form of internal debugger. + In summary, because _d_b_u_g 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. + + + The _d_b_u_g 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. + + + The following list is a quick summary of the + capabilities of the _d_b_u_g package. Each capability can be + individually enabled or disabled at the time a program is + invoked by specifying the appropriate command line + arguments. + + o Execution trace showing function level control + flow in a semi-graphically manner using + indentation to indicate nesting depth. + + o Output the values of all, or any subset of, key + internal variables. + + o Limit actions to a specific set of named + functions. + + o Limit function trace to a specified nesting depth. + + o Label each output line with source file name and + line number. + + o Label each output line with name of current + process. + + o Push or pop internal debugging state to allow + execution with built in debugging defaults. + + o 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. + + + + + + - 2 - + + + + + + + + DBUG User Manual June 12, 1989 + + + + PPPPRRRRIIIIMMMMIIIITTTTIIIIVVVVEEEE DDDDEEEEBBBBUUUUGGGGGGGGIIIINNNNGGGG TTTTEEEECCCCHHHHNNNNIIIIQQQQUUUUEEEESSSS + + + 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. + + + + #include + + main (argc, argv) + int argc; + char *argv[]; + { + printf ("argv[0] = %d\n", argv[0]); + /* + * Rest of program + */ + printf ("== done ==\n"); + } + + + Figure 1 + Primitive Debugging Technique + + + + + + 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. + + + + - 3 - + + + + + + + + DBUG User Manual June 12, 1989 + + + + + + #include + + 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 + } + + + Figure 2 + Debug Disable Techniques + + + + + + 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 ####iiiiffffddddeeeeffff 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 ####iiiiffffddddeeeeffff arguments to match the + indentation of the code, but not all C preprocessors allow + this. The only requirement for the standard UUUUNNNNIIIIXXXX 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. + + + + + + + + + + + + - 4 - + + + + + + + + DBUG User Manual June 12, 1989 + + + + + + #include + + 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 + } + + + Figure 3 + More Readable Preprocessor Usage + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 5 - + + + + + + + + DBUG User Manual June 12, 1989 + + + + FFFFUUUUNNNNCCCCTTTTIIIIOOOONNNN TTTTRRRRAAAACCCCEEEE EEEEXXXXAAAAMMMMPPPPLLLLEEEE + + + We will start off learning about the capabilities of + the _d_b_u_g 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. + + + + #include + /* User programs should use */ + #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); + } + + + Figure 4 + Factorial Program Mainline + + + + + + The mmmmaaaaiiiinnnn function is responsible for processing any + command line option arguments and then computing and + printing the factorial of each non-option argument. + + + + - 6 - + + + + + + + + DBUG User Manual June 12, 1989 + + + + 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, + DDDDBBBBUUUUGGGG____OOOOFFFFFFFF, forces the macro expansions to be null). + + Also notice the inclusion of the header file ddddbbbbuuuugggg....hhhh + 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 DDDDBBBBUUUUGGGG____XXXXXXXX............XXXXXXXX. + + + The DDDDBBBBUUUUGGGG____EEEENNNNTTTTEEEERRRR macro informs that debugger that we have + entered the function named mmmmaaaaiiiinnnn. It must be the very first + "executable" line in a function, after all declarations and + before any other executable line. The DDDDBBBBUUUUGGGG____PPPPRRRROOOOCCCCEEEESSSSSSSS macro is + generally used only once per program to inform the debugger + what name the program was invoked with. The DDDDBBBBUUUUGGGG____PPPPUUUUSSSSHHHH 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 DDDDBBBBUUUUGGGG____PPPPRRRRIIIINNNNTTTT macro is used to + print the values of each argument for which a factorial is + to be computed. The DDDDBBBBUUUUGGGG____RRRREEEETTTTUUUURRRRNNNN 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. + + To use the debugger, the factorial program is invoked + with a command line of the form: + + factorial -#d:t 1 2 3 + + The mmmmaaaaiiiinnnn function recognizes the "-#d:t" string as a + debugger control string, and passes the debugger arguments + ("d:t") to the _d_b_u_g runtime support routines via the + DDDDBBBBUUUUGGGG____PPPPUUUUSSSSHHHH macro. This particular string enables output from + the DDDDBBBBUUUUGGGG____PPPPRRRRIIIINNNNTTTT 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 ttttwwwwoooo arguments, with + the second argument (a format string and list of printable + values) enclosed in parenthesis. + + 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: + + + + + + - 7 - + + + + + + + + DBUG User Manual June 12, 1989 + + + + -#d:t:o + -#d,in,out:f,main:F:L + + Note that previously enabled debugger actions can be + disabled by the control string "-#". + + + The definition of the factorial function, symbolized as + "N!", is given by: + + N! = N * N-1 * ... 2 * 1 + + 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. + + + + #include + /* User programs should use */ + #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); + } + + + Figure 5 + Factorial Function + + + + + + One advantage (some may not consider it so) to using + the _d_b_u_g 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 DDDDBBBBUUUUGGGG____RRRREEEETTTTUUUURRRRNNNN or DDDDBBBBUUUUGGGG____VVVVOOOOIIIIDDDD____RRRREEEETTTTUUUURRRRNNNN + macro. + + + + + - 8 - + + + + + + + + DBUG User Manual June 12, 1989 + + + + To build the factorial program on a UUUUNNNNIIIIXXXX system, + compile and link with the command: + + cc -o factorial main.c factorial.c -ldbug + + The "-ldbug" argument tells the loader to link in the + runtime support modules for the _d_b_u_g package. Executing the + factorial program with a command of the form: + + factorial 1 2 3 4 5 + + generates the output shown in figure 6. + + + + 1 + 2 + 6 + 24 + 120 + + + Figure 6 + factorial 1 2 3 4 5 + + + + + + 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". + + + + + + + + + + + + + + + + + + + + + + - 9 - + + + + + + + + DBUG User Manual June 12, 1989 + + + + + + | >factorial + | | >factorial + | | factorial + | | >factorial + | | | >factorial + | | | ' 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. + + + 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. + + + Note that there is no matching entry point "main>" for + the return point "factorial + | | find: find 3 factorial + | | >factorial + | | | find: find 2 factorial + | | | >factorial + | | | | find: find 1 factorial + | | | | result: result is 1 + | | | %s", stp, + stp -> name)); + + 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. + + EX: DBUG_SETJMP (env); + + 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. + + EX: DBUG_LONGJMP (env,val); + + + + + + + + + + + - 17 - + + + + + + + + DBUG User Manual June 12, 1989 + + + + DDDDEEEEBBBBUUUUGGGG CCCCOOOONNNNTTTTRRRROOOOLLLL SSSSTTTTRRRRIIIINNNNGGGG + + + The debug control string is used to set the state of + the debugger via the DDDDBBBBUUUUGGGG____PPPPUUUUSSSSHHHH 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. + + + d[,keywords] Enable output from macros with + specified keywords. A null list of + keywords implies that all keywords are + selected. + + 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. + + f[,functions] Limit debugger actions to the + specified list of functions. A null + list of functions implies that all + functions are selected. + + F Mark each debugger output line with + the name of the source file containing + the macro causing the output. + + 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. + + i Identify the process emitting each + line of debug or trace output with the + process id for that process. + + L Mark each debugger output line with + the source file line number of the + macro causing the output. + + n Mark each debugger output line with + the current function nesting depth. + + N Sequentially number each debugger + output line starting at 1. This is + useful for reference purposes when + + + + - 18 - + + + + + + + + DBUG User Manual June 12, 1989 + + + + debugger output is interspersed with + program output. + + 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. + + 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 + DDDDBBBBUUUUGGGG____PPPPRRRROOOOCCCCEEEESSSSSSSS macro. + + 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. + + r Used in conjunction with the DDDDBBBBUUUUGGGG____PPPPUUUUSSSSHHHH + macro to reset the current indentation + level back to zero. Most useful with + DDDDBBBBUUUUGGGG____PPPPUUUUSSSSHHHH macros used to temporarily + alter the debugger state. + + t[,N] Enable function control flow tracing. + The maximum nesting depth is specified + by N, and defaults to 200. + + + + + + + + + + + + + + + + + - 19 - + + + + + + + + DBUG User Manual June 12, 1989 + + + + HHHHIIIINNNNTTTTSSSS AAAANNNNDDDD MMMMIIIISSSSCCCCEEEELLLLLLLLAAAANNNNEEEEOOOOUUUUSSSS + + + One of the most useful capabilities of the _d_b_u_g 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. + + + 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. + + + It is not difficult to modify an existing compiler to + implement some of the functionality of the _d_b_u_g 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. + + + + + + + + + + + + + + + + + + + + + + + + + - 20 - + + + + + + + + DBUG User Manual June 12, 1989 + + + + CCCCAAAAVVVVEEEEAAAATTTTSSSS + + + The _d_b_u_g 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. + + + Programs which use memory allocation functions other + than mmmmaaaalllllllloooocccc will usually have problems using the standard + _d_b_u_g package. The most common problem is multiply allocated + memory. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 21 - + + + + + + + + + + D B U G + + C Program Debugging Package + + by +9 + Fred Fish +9 + + + _A_B_S_T_R_A_C_T + + + + This document introduces _d_b_u_g, a macro based C debugging + package which has proven to be a very flexible and useful + tool for debugging, testing, and porting C programs. + + + All of the features of the _d_b_u_g 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. + + + 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 _d_b_u_g package should _n_o_t be thought of as a + replacement or substitute for other debugging tools, but + simply as a useful _a_d_d_i_t_i_o_n to the program development and + maintenance environment. + + + + + + + + + + + + + + + + + + + +99 + + + + + + diff --git a/dbug/vargs.h b/dbug/vargs.h new file mode 100644 index 0000000..76f3def --- /dev/null +++ b/dbug/vargs.h @@ -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 */ diff --git a/defs.mak b/defs.mak new file mode 100644 index 0000000..1c132da --- /dev/null +++ b/defs.mak @@ -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} diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..cd06b2d --- /dev/null +++ b/doc/Makefile @@ -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 diff --git a/doc/netgen.doc b/doc/netgen.doc new file mode 100644 index 0000000..cb66e12 --- /dev/null +++ b/doc/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 SEPARATOR + +2) Ports - Oriented: + { PORT_DELIMITER PORT_DELIMITER }* \ + PORT_DELIMITER + +3) Ports - Global: + -- name propagates unchanged, but is bound to + locally-declared identifier of same name. + +4) Ports - Unique Global: + INSTANCE_DELIMITER SEPARATOR + +5) Flattened cells: + { SEPARATOR }* SEPARATOR + +6) Cells read from NTK: + INSTANCE_DELIMITER SEPARATOR + + + +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. diff --git a/install.log b/install.log new file mode 100644 index 0000000..adf09be --- /dev/null +++ b/install.log @@ -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' diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 0000000..b3cbf70 --- /dev/null +++ b/lib/Makefile @@ -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/$* diff --git a/lib/ntk2adl.sh b/lib/ntk2adl.sh new file mode 100644 index 0000000..fe55d1b --- /dev/null +++ b/lib/ntk2adl.sh @@ -0,0 +1,3 @@ +#!/bin/csh +echo ntk2adl $1 $2 +netgen A K $1 a $2 diff --git a/lib/spice b/lib/spice new file mode 100644 index 0000000..622ecbf --- /dev/null +++ b/lib/spice @@ -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" diff --git a/lib/spice.bot b/lib/spice.bot new file mode 100644 index 0000000..ab5fa9a --- /dev/null +++ b/lib/spice.bot @@ -0,0 +1,5 @@ +* End of SPICE deck. Put all simulation stuff here. + + + +.END diff --git a/lib/spice.top b/lib/spice.top new file mode 100644 index 0000000..4a1f841 --- /dev/null +++ b/lib/spice.top @@ -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 diff --git a/make.log b/make.log new file mode 100644 index 0000000..2dcec68 --- /dev/null +++ b/make.log @@ -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' diff --git a/netgen/Depend b/netgen/Depend new file mode 100644 index 0000000..f8f2ead --- /dev/null +++ b/netgen/Depend @@ -0,0 +1 @@ +netgen_main.o: netgen_main.c ../base/netgen.h ../base/objlist.h diff --git a/netgen/Makefile b/netgen/Makefile new file mode 100644 index 0000000..a388c75 --- /dev/null +++ b/netgen/Makefile @@ -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 diff --git a/netgen/inetcomp.c b/netgen/inetcomp.c new file mode 100644 index 0000000..9ca13a6 --- /dev/null +++ b/netgen/inetcomp.c @@ -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 +#include "netgen.h" + +#ifdef HAVE_GETOPT +#include +#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); +} diff --git a/netgen/netcomp.c b/netgen/netcomp.c new file mode 100644 index 0000000..2eb7813 --- /dev/null +++ b/netgen/netcomp.c @@ -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 +#include "netgen.h" + +#ifdef HAVE_GETOPT +#include +#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 [ []] \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] [ []]\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); +} diff --git a/netgen/netgen_main.c b/netgen/netgen_main.c new file mode 100644 index 0000000..47c5200 --- /dev/null +++ b/netgen/netgen_main.c @@ -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 +#ifdef ANSI_LIBRARY +#include /* 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); +} + diff --git a/netgen/ntk2adl.c b/netgen/ntk2adl.c new file mode 100644 index 0000000..9bf40e8 --- /dev/null +++ b/netgen/ntk2adl.c @@ -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 +#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 []\n"); + return (-1); + } + Initialize(); + ActelLib(); + + STRCPY(cellname, ReadNetlist(argv[1])); + if (argc == 3) STRCPY(cellname, argv[2]); + + Actel(cellname, NULL); + return(0); +} diff --git a/netgen/ntk2xnf.c b/netgen/ntk2xnf.c new file mode 100644 index 0000000..27b77b6 --- /dev/null +++ b/netgen/ntk2xnf.c @@ -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 +#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 []\n"); + return (-1); + } + Initialize(); + XilinxLib(); + + STRCPY(cellname, ReadNetlist(argv[1])); + if (argc == 3) STRCPY(cellname, argv[2]); + + Xilinx(cellname, NULL); + return(0); +} diff --git a/netgen/symbol.map b/netgen/symbol.map new file mode 100644 index 0000000..761890e --- /dev/null +++ b/netgen/symbol.map @@ -0,0 +1,4 @@ +NETGEN_1.1 { + global: Tclnetgen_Init; + local: *; +}; diff --git a/netgen/tclnetgen.so b/netgen/tclnetgen.so new file mode 100755 index 0000000000000000000000000000000000000000..5f0d15429355184db043b754421a598e63f61472 GIT binary patch literal 521888 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%0AZr&Y(u?z6#TfxS;lm(vI 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

#4I zoRLh}?Y8#FhOMI4WvQE@};pn;i?byDxw|q z9tWd^We>!O7)V#j;|Y!~V(w~x?jI;4}S*}=PDEz}KBzyvwCNYodqht%PF2*pr$oJD_x;wWFEZ))sdh4kCxA zbuc8}>6jW#R!Zf}L@-bpN@pfAx*KMmO9nvHxFqkri@L4Q=tY7VXtnCRsdj%bj`%8S zRAGb55yT>I zo-4yPL_tBRke97|#JX5u%J`e<*Gr3NLqrei44Gokbjqv3)8u^%lHoBZ6_j`cOg!9MR*XARHZ?;yva=GCFk~N-S6eHq z2OU9dJLSeWQerf-m~;~D$Q05oRz$rr<@{i_YiHE#${rGZRD?lD80aP_9#hB+XE4d7 z+i5WYXa`t|ar7X z_EJq&hE1!GZ*ov%k@K;E*^v+!%pFpU`sD2Yv;Tso1|ze9Se z3F%Fh$0kIG_^Y9mG#+jzKZdDkO&Z2P>UbmcF}1+r848mPs!M1I`X{n3IV>%gbu&&w zd-82^7NwNd=}tLLHl}uti^lK^b~r8m?MoJu2x78W0OAlj1#v)HIF!bURQjO8mBRvU zQN}jc5h3SGW@Cg-ZixoSmK`M~LlvA-NoElfjTdwT`vb^QH+0cfoLS<80j42|@B}L@ zUHV(oWD8&Ri?DFlML0~o>uT!_q}5$Hv{SYiL=a+& zTyjJY!QtB6YTf73j@xlacFc`UU>j)K4`K^~CEO2pr_y!~A57suM2djAQk^A!))X)& zv8Pdx24H}2#0@j7SJ)Dp0hD#p8VHMA*F_;P6 z*_6{yb^j9@Rp8&HN2j6AbkQvg9afNNqS%@F`gehF&tNmg^<%l0A4e005jRCrJ{b_HKIxT1ur!PZhOiNzEEqk)Ak`ryCF zgGwFQWC4e&ewPdnXkhr^R7x3fmVN!b-Mvf2<;uw`H}iDoqZ!YZ;3*UlGj=^~YoqsA ziEwG{5pZU5-MV$t(bpwh&~6F-zzmaoJfAbYTT{USCW;MAV#4DXPPSRc`?`7tTt`oP zU+cht)d2MhFj4h5UaQ0sKFUURCt;>_Rn<0%;}pnN_Pn5dcxXf(vvAlzK;XmYPDBt= zMp}st|G-)*&kEq70#s_VUULo&R8lxjE8(ytJoJao;rLn)Cp$CvH|)6)E8hvd&+3K^ z_5ciP4!==WVMnWiN={KwVKAtX0x1y~>WP0}9!u|`?6fr3wdY%v29oQA^*Kf37gKeO z4*ceWcp&&Ey^W9nuH2PGQGMvD(-&X|gbBkZ+p-XzP7B#8!pSCT6E`>QCgtQ1^iy_j zrTYj|P9EONCdzqv4pGQ`5*B5l%+Nk*g|{R&6XmEuwluQZn1M=hBAC`9gQJ;Jw0hA+ z1c7*dhrxCiY`gflQtvRr2JHG_S6<_x%D6N^I;1>hgi$JG{+2t>{wEs&7HlGSwv7|I zWa|~o8*`CK`Ip;H9}^SbE;vju{$igI-H@|6_CMM@?V<=3`ybjSIi5m$b%bO$uEY*- zZeWIp=Mm2!gNnvTWmpF`%byluW9@?MsmHLk<-D!lq%gJ#izQ5O#Dm;~Z^MoxoK8m( zUKnl(PeH;7R!>FmJm?$p~ImM_J!o(h+0ubhNQN;I>OdD?QHKP z9vm!s*)3P|E&sR|F1*J`~hR@DvztVWD6C1MH5gbQZ_x#J+$6?MyfkbHX zOrW2zm{_6GLFjGzV3mpv7D^w5s8OsMiO@1>R9S7d#ZY`IERE-1yz|h-Lk6b}!y2TC zE~=01gP$+q0T6kUO zLRsa2Mq`$wsIIG&unz$HjDQV%^Fty5S^tU=$7V?}n?pRTV$lbPG>XCURD~{oyhqKc zzjJWESS5&9dCXyL&~Bzp{2D=v&6Y@-XH(Q8ZLhj7+lsW8+tK?JqmkgmF=)XMIYk+JU z>chhmsgziHL#2e6cKd~1v2w0nTOY z@L@59gC!@c9espCj#uURZCU3hlHqo*?gq-b8kQmD@T@U>Yoa^`dlXp^%V|k2-HO%N z7+e=dTlnB9phQ}q!Sq~ZH3ZT6n`-Z1o%CU1iQ!?eq&3hUtTeEo@52vIjBqk7vPxMgR5)CH*r@;Q zS#!t{kN6e?eU9oB3;`M)R!McX{Zx@|+IodY&E%}6j+ zogc;Vu{>RY1q?=RLU&Y#F*ooWzdW`+w5CP>&Ubi39X3cFkL3XPI0;i8lQB7=7g<^k zVZ|p^2w=m<){SLlVJ&AfllnjcD#Viz_Jl5cvzVtIu`O6IgG**a8Q{s|uv*a{2v_4f z83t_s<1e1%XOqlEpkp}M$>*}uh@n*HQsc0)o=Bgt#|^ek+?{`9--MD%ri*!;5tmgT z5b@bqOXVsa(IS0@BdP`1ipB}C(B||ZNg;xb5#ys7%@cP$2F|6cvTy$8kfVq2%eck*aT&yI7G2AE5i!LWph_n5LE(M9lLN!>du_M zDdy3h{Kj;|c!~xN6lAX;q=0eG$v>q*;K4w_zZnRROM!7Fjei?59UxG5lSOQ8_h3b& z0vW{6W5%>Yk#%1o6}Aya%-B{|(=brRa{vW>{7)@}uNJYVJcJzn%v*;G@L{z$MC?aZRdiO)BCh*_gq-yzcij1*6!jfSeMeX_WQ9 ztOTCXM`-A@g#W%K1u`ir^?-{uF*%N{-KG&tUHQ|bRT}#t*t#ZI4qa9^sp|kI*;N8= zKk)#Ta1pPPNDd9*Us3p9SQZEVyNnx&SbT=8|9^mYqtMp)-;((_cQ4+KB_Dr1$bN=@ z^<7utFNZ8p&i&(^ck;gc%PjA&hmzJ_jpf`nk+SmjNc@j{q+$Jgk&(YH+g7NYyl+cs zeEGc;b#5`P!rRw>vM|HPUyqA5n9VaH{FQvp??l>v^G zXIlY(mHx>m-hM-!OXJJik@7!gd4DaCuu=I^gtw3$y0aDV*9+Jm-~PD#PLGxU@f<7f zud7)=%8O{@yliQ8uF?A z>8^;CziZO!_t)+nYYW8X_rqBE*`GBEfBoQxYRmia^XRSkB2{=PUGU3;^wtHxG(K_q z`0u+xEh^^AU&8X2{2$9dgt8)kU;c8Izx@AL{?S5QC@V{*MA+$U&r#Z zIj~;tzW;t4{~D`*{jW`a>wj$}7UO>O&;K*Z7iljhAm@`MCV17u&%7eqsIco=;DM`d3X@`8Z!+&T|!a5stkFas3?2 zpA;()`>Ep?Q&HuzX|2_N^0CJBKwN$fLa(>pe~W#sSO2mHt^DfuTY3LCUcbldU1y zo#iB&p81*O_MHg=ndRQo0I#*Vo@kbPum4(eo#p1#{FWawPquKcyc55%gWj7dXY>@a zVy2#m`4fEh;kBGviJu(9R{`HFA~!!@hZUbW?h?NV|I1^1E>-%O`txJp_4>75>8s=D z?aZ$f-`g#wU)zhu=C{OG|K9Y$(?3gmE%B!qf4)roq-TuYyo+;h0I%1cS?G8@df9I>l z_%!lQ5?}u{1EfFl8E?R+416=pyTzP$Yn9r$Pb$8*yCBw{bBSLPliODt@c%aH*OR`F z{I4NC``OxYzk&E(#Qpf*N_3 zl(pk=ySU}VfAxC<-bego;$spx+27|8>N@e!iRddg60Pe+ck;^)@U0 zUhZ+)dC%tv@^P~dRt~=2V~8&%KAY`aO1y7ZqxXDzf!C{dbpt#}KC5GV(hcbIz(s!^ z`4lD^K9}fU=hhL=e%kO}Qx|s`@!Q2f;d2J*ZzBGoGYwxu{88YdCnvK#UJe_9*X!5w zq#up7|BVLpv#<;mKf8(Y_xyJt{?{1p?csXzznAUw_Hd`y*k9tifls}5?%M!AxB=e8 z_PiX^lcN=f|JvhPs6=F97o*kWw`hI3F2#G_$cst?LUR|8%XcvCXJ{^ ze`W(d7bu^-+}cME()O>_zs`M~xO>d-orue&9)D4jx?nV6S!0?x$-}0GD{EgcU|E^u!QN&Mr&FCcVmroaPnO|;i(+4l59?}o3 zw+3d7+^r&h%9sJNUXsrU@pCgq|91}9XNZ6M>xTai`+E`b(O0d3pEWk_3g9vyw~5WW z?|VM9508-kX5#NNF}wdJ|2v5<{iz9Z3*x^ae(q0|^dm;AWzgD*0UpI>PFZy}%el75Sr{NG3V-JdbSxukC* ze#16a;UenE(Zn}!o#^LvH}R%_TD=nQ$|nh2+PRqZF8;dVqohA3W54fZzw*TYV}UVv z+HSit@%}H6ke4%v-*AsL@FKSJJmSwuV1~~Z$>%cSA9>9PU&efp&$Ym%ofpLX_&ucG zA#e0URNRM%&wbj;Z?cPff_P?)(Vs;8IpRA~AG|+$iTG8Vpc_d47V(o4#>a2JZHuKkMnwWCRYH{01odA5^&?M=1wbOq`Ey@d&Y%S-oh z;`=sRLprQk*w3G0Z=?k&-<~q{H*IDNhcgGvwL$^P+f$RF0_WxgO&wA4D@sbhx{@zdg<|~c=&g}1Ri9b#LAI7|u z&(p;J=Q;a*2KoP+_-t9A;d77Oc5f2@)U*-4NPJK9PsVX0{h*iUfxtx{KGkJ>4kiDC ziO1udqlkC!VuWjH&sPw?bj`e(UHuH{2R9nw zn>6SbDm~%~@;}L{cbAcVpQW|^x}5lb#m4db#P>YL8h#M@+)Vt!(+yzt?jGPG&wYPf ztLKl9{!g+n$A@mr{gL?1PZ%{kY%lf;5__jE_m3rsI>fIf< zjN`B@i z_c5b8p0_877Xky`LwooI;_>z1H;6A;X8n?VF8N#zT=eALn4Vk<+yQ_2$%Eue__>LE zZhGAyS>MX%PU8D>f_~Fr_e z-)~RiuMq#>14h3Y$5$Snka>4K{dG6#cLXl-`9iEc`;dMpX?)J7-X2Q)xIdU2{C>hB z;urtW7<;{4LVTa=4EK7q6u8uTW-RVnP5P;atl=MFJI9GPOPd-|`CMe?93RBmOhlIK}5j#?C!M{Et@{pVtxh$mccUeK*?g&)CJiO?>n38-Fg( z+zvb0xSze=2)#b;R&Qahxjd=pnhIlNIbqz`)%U8 zW=wA0zg$QB`{x<|J?ysoDe>3eHh{}8w}JTIzhd+Zr`(goUr8JNQp)F9;=BCVfVI>I zS+C1H?SIuebT#|+HgFl2wXu1+#cZQrcDoVExsH5h0~h+2WA=G3(w{*)++*Z!4)OkV zCg*+0=Wvhz+z7X$96n4uzW;nI@ty88`uoWLc;Ywq7=MN-?&HK4OWtXGe0&}Nm-y$d znEf0l{a3d(dO4qy&l$uY{;~nTG1z^TcwvR%=Mn!A@x@%&JWN_+*K95+7Y;^tTWnAb#nu4PQw-3tZ&y9yv%6A1{?i{|NUf zen9$DiGPz0>QwgYEaES3Yy20G{$k=&Jcz3h{}%B(HyCg_@gET{K4Sof+1)|>L)RJq zKT4MSdeRMC>UFo*#^I|-f3zI% z;j_l7cLDKF(0<;{_D>N1`7H+YlK%6=Kiq1-o5as2{vPUKAMuNb_q|~KdXe+!O5$_5 zzuH0i>xe&1#d#3x3i;ee{P8>O_wIIaj}o8rS8Hc8+y58h``loJM-YF5_~B=p9QfFx zo3*Qr%Q>eS{yy^G4!FqkAj*^G+3ijG8*ekh3rUaEY-+a;p#A?1@g>9`e$n`Qefuc! zXOA$#uh6dz65n>Y;p?f-Y2tfx9pw2;5dYpe)=`Ed?rh>0US@pc`9t}9gZT5?8?b=< zuOoo%5_i1C;+c+!fb{#Z{ST4;3F5zGJa7>4=ZQbC-rBi4<^LM- z?HE^|M*6KVF(qy}Xrl?{em`EsALK?tj`Rl-KZ*}H{*!WOBEIpn#=yth3yEJ(0h~-e zONoC!XAC?(K>W%9BV0-TCldel&DPGfA~Pcan1WF7YeBZTNlUa~<(7b7OuN+JW`NHybp<=B=#U6T~PP>9<vHjNr*Z#)Vr?-;+($kFo4bneAd?O9shj*|Fo*@3hz4m)9 z>Hk7JxxjG0Ui%yI-=qxxvt8U9#J|V$n*SiaBNjL^?_RjmfPnaWfJ^(o5R>Nt#4m{9 z3&^MctHxlEd=?Y`?2V>xXHq}AiMQQqgo{Xj9PvMK;qv76uFB{*- z-er8wr2gzlJpNqM0mR>Ew{~2@@oFLd=+(x*+itsd;$z&0=W^GrApSHrFs@;LPbR+U zSOffeZ3wuG*W#ni?;LrS1#oH7FJpY`>zyRMi~0R?iBH{mgtpMf&leJ3OT55+uZw}> z(A;g}`98blz6M<8#U#(`&*F`%$Y)(_Uf)3alkPFXFS5UP65o2va34S4NBo3q4gUoB z|AF`u3;?eo{u1#U8CNjuc5f2@!|$v@hGlLWgz_R!_sAmU;N`g^@gt9KQ{2mE58%?@ zT+BYapY-cucKZm@ubE>C^?@C&p&udrV)8eu?%Z^F87>Fupn$@x6S0MEoB=HNvdH?hfLk zE37@Q6aP8!Lt7002>Cxi{M}p^f0FdKflTE5B>fA_vVNW-{V88H20W&6uMofcZKJ!0 z^zRV=Bkkb`@!j{4FW9$BSjPbv$nEMuRkwYP-Ki?yLhWmtEKDnO~|8v3Qa|9LcZsLVUjWNRlw}E*4 z`N^j|{lnHCnq&78@ngAAljld}^A_>#FSmM6;{NUIciVVin)&h7rB*Va$80E``>H*^6SbIi8ueu7f$jVn@i$&IK%VE8&sD_Z&*ff6 z{CcjBK4RqVcH;N`%@}xny9>C;VJbF{eo6ZH^T1CKzcO~-^epk*=Z!zbWz5x;}@FCMc79!x%W z1DA1mJhpy$g!sBx{Psuk>HL#1_Hpua#OKX6#wGIq7x7(}8}Mt+({0~l@;{FID&7w7 zN&Irk0pXc`_9uQ9pD&sq-UM9s8y9oGw2$>JApL83>o3*X9Zh`cYsO%A@>xbc+r;)= zdrANN?~RZ5YbO#PI@v1Rk@4Os#J|MAlgAJ4bIKpjamC_+FOk0gT;p>B+y8CiU;ME( z@JDRt4~TDhnE~e$zn%Dec>o@t{dct+_Y)uck>QsZ>>elnL;m|$`FBV1d71c$J6V74 zp@24rLW;i|%^A+-y6uSH&gcAR8ymMD@m9w3T-LgI#CN{j2))1l2yoTIy$;qJK0fIp z{WjmTdcQ;dClTLzjx{_*e1!PvTnD9zf0Fo%j4MtgelhX0Ie|W4)wpjE&vRe2O#17H zUomRHWyEhLzVH?UPNF>TB7Q3U?D-5_enouSvu#|SBA@4o@A3x&ygzz_c-IDN;NMBV z?R#xp794K)4Xk%>;t$_p{C)cmBmU$yM##rs+#=#HzG8e%CI2qsC;ZNUPVzsA_~gfp zegOw8NBqitjPPL2iwTckXt+P8TMJy~?}M@Pf^&#(jNum%kH=|OkpGK+GX6ieX1S}C z9_v|e|Jlx)6o++*{d>;`$mg(TWAF~;@C5m6X^l4p#N%W3y2@e5xtK7K#v zE#mv!Xzjd-?VLTw^#3mMXEWXYz-8W@zr7Lu$*OUO5r6MO!~Obb0r404TrtBJw}kk$ zoJad{Tn32W{E)ThHoLeX;@3ZGz$Du_LHusUy(_nN`Z#P{QR;b`KY zA^xrh4Jfd~Uji<6;NF-V{*(9@V(Z6i$>;P9#%C+LxStT;MgHL!KF8U`-3eUz)8BbH zKMY*tyl9C~JNJ@Z+|zRmf9(4P{D$~Hi1+fm#?P;9_c!{#(U8zAy1j`HU1Rg{a`JgU z@!2m~1Le+={-`rkteZ;@}knx{G0i}qq*<|z! z$^R3?-=YAx-R#aG9{=}Kmk>XOdcKl;t^qD`{#PunxP|nk=dC>t+Qr>R{8`$=dli;)L_|>Mi28rj7pVY|oYl$hge>ck$Z;mv(N5&Fejteg}8w7dKN5 zJF}e!68{kQ<+{ngh4}sl8{sA^=30RZ|BW#@EGPXha92JTb3U#nen9M;WexHD7|8Q6 zS$7)ojZYb$-C6JFiT~isn=AjXP|?3k{9`;w_w(W##Lv4<$=wBZaaR%l)p}#>pS!q@ z`0rM2u9T0PTD$ecuatkdhtDo{+if8J=XnM!(Yww)K|KENr2a&_CAP2fD)IQgr+bI^ z)gRqlIs4~1H$TwkGuP^3u&U47T~j^0Ka!P zz(3Z2Po)8Vb_4vIz~|Jd_jces5~;cS>jr$DZh-#_c)fmY3qw?o|GvQM$!A^zd}#xG zbpw12@Otf;YCwNZ1NuuF(Ep$T{jCk~`y1f$8i9Ipc(DP#Il|p~{n{CLJw69Fz>jLc zr@sOHXaoH82KWUH_+Qz8{?-Qg{SELxG{9d4UQa$-ATZtq{(2?Pmv@b@)Rdi47$ zea)26A59JL)&_i5G{A=%@R@8te{KW%D;nT8HQ;kc1Nw&>;Lie|GgA!i?+y5Gbx3_Z z+y{6)Ie(x5zPJIOfd=%+2K1!{___x86%Fv48sHBA-?`3vQ66nT|4IXV%R?K;4R}4d z9om5Y=mvOy1AMdr|5F;!f2IL`aRdB&4e&b};J;~rKMTB`9=;B|o_w}HtUkUE@OpMq z-g8tBU($fjU<3Nm2Kea>@beq+zZ`hI{@&Jr{;mf2!@v>h%=o<2fPTyO*O$ZI4e$>% zz}tb>^ZUqIhu0}1AxslqXq)(GTYsXvYhW;uz-!Wr!3bVaESWgR@tSfZxsca8&wvsM zq|36m<0jI`Zd1a0xTiGbgS>$^-E_ne^B0119ioK1sMTJ(inrBE{tSCjtEK2o@U^Y_ z3-1Zelxs+lR{*bPP1!5Y!*`P_>fcGOKlCN%twJm>fG#=xDydS?#uQ%s4i-rE5~L-o zGVo7;2cG5pduGUJL?rj?82chWD)*j`GmUlaI_m;Kty%mYcOfMR%0xxVRE{^-k= z@k)64j$8Wj{8SP-p9Iic>-Ku~@Ta`J7jGAq+CXpldgQIXTD>L`zzezY?pXO#Mq(tn z>N}<73tn7}cfc!YFJ5up2`0z{(9zo7gf=C!$!sQBYMLjnk(PWt;O{f2%UjT;ldf0u zotBUr3k4*1tB55bt&>;$YK{eYt@|v6<4MD-X}`55q-VfOnJp!_)aa9Y`*d(&+G?~Oow1iP;|p7WWFe?u()eh0 z3wbNN=2{Un{K1=T^6K&s6pC7eWKzC{ss_NjnMoIwceABzu6Jji&x#wRKPpTC8AXqb zT3!5Ri?1zyqnf!oerI0YJkp{+ z@nprwg5j|+NoWKMlNv`-p+hV1l51#%yl=ajElu7Uj~6e?o6G$R(ZzZ+Eog3$Oxco! ztZBi51&bnisWfR-2KI8nyan@I2KVR9KgwmM<$7c_rBpRdR5_X{Nh}YOG{t0zH=b9@ zy~jpTWODQ=pQ3Ox@;}YUw-hCq=LY1}-kQ{%@6t!l^%eHfG(U~D#BC~ zmY@MV?28xzO$A{;y}h+xYIk6x_fRQ6qsM4il}5mAd#!0_`W_L1x=(aZ#vsmEvXX{${_Xi43o z$&|EOGn9i!UW@!hcoVpo47E|}X1c2>F8;Tqus(5WXm6O1&0c6P79DSTA3>IrYVNI0 z_={e=Fn%1S-oGK<=VZ{#Ib!rB&s>=~i!^uL(qwTcIb!Ayi4$s4Be zMDjLBQ#+>0%aBxq+H6T5WRzOPqlaC9w#duqkrFpEE?(NH(3sI%fS$an=n{^mWx}Ro zQV#%c8BLneQ_tSOz9Y#Jf`eA1%1LICWPlm?>Zh@k9*KM{kH&E|=>&amkuE{U26^*_ zHGvxPbE!zs?@q~ErU9FFDW2v}b1YdpC#2Y`$vNn?6~+ygU2{H2MWKulwrL&&I1tJJ z$)_MCXcrT6c1fN`L`|nkwqVIx)r~2sQ(d)Q(+TD<45iw9Lt!TNlxA{9N)(JtIWUFv zMoWed^WU<(OH2_R2iLbiOu^JDq)$jCi;`(1(5wR_lENj8A+!1X7!q2EkMGqNT9%GE|RmW-0VcP!*|LM5acEdGA|Xdo)d& z5&4vRNHC_;lFlj2pBK(YFJOgqA&dD2&)7IBoz2pe z``N~XCSG!)$|bj=l1YsXAc#+m#`15)l1Yw2g>qONa1Apvm890{`v-H16famlN*>Q* zfD}DQCWC+r#=0gSai=aX!bDrXcr|ISal;r(ca33#d*<|FCYtkB?OUYsM6FCkt@YIfFk zO?B0oRgr5LENehnQA%T><~{;N8aB`U?iEPO^Y}Z%`pY58#Rg0QPY7)!faqLd{z4$ns%np5nYu`wN8aZ zt@X2l%*Er08MA;c)Qd2q6T-ooY|*Wn35vF^RGUG!YM^3i8Ao!O4NT1z(w@U+u{yY> z+GO22?(Kml)gBxz<|h#)FnUw(hH@%$MyV!d_1c;ywWXTGuY)<7#equhQRb_K3q-0h zTl&Dr3`@A^W7bf9$m)f-tQ=bddV?vdDx)fs$-GGLPblNOTc|;W>-$qv#B@3j&2RaK?hs-F6^ph?+eviXaVO;1-Tsw3T+OG`U!<(w;LiV?46 zdM&XnqF^lGFj2h=4gIgE7WDvrK(qHs0%}C9K4+>J5ow>K)sg@o1C2bVp<|V-i1l(? z_gM}(jlVLDyy$-HW6= zXZN98BS_yyy*CeuL}lqTq&OvX%+suvPxko`FO8^Oq>0unjMzR@HRub1v8ak`MoMqg zqN)plICTSk;uASp!rZ6IAB!(@d*02#4X81(`A}#1>pg>HgHv`kHX4x#P|{TQ%uKb&8CTuIGkd|FvKAXtsb23cfh;tG z9)}4@ohvYs*jKe&)xQ1JY38F#b8@SS8K{h|I@I^5bu$4M;OWW;Xe-UTeRnou?O%~UZ(va8uPIW(e z7#5Tv9@NnC(8G0_uTrlS+A^EhViSB4H zL`D<8A=H(f@8wwMekTMe>GM2UYvpiL(iWq46-@`k@X-WK6eTlV~++?rotX z>MN^6uNpNJ70jPpc~H^bq^RMt;X5;Hx1c7$?2Hkhs*2vZN4EPn5&v^)u$-8orI z7QnoAYeqI75JReY&5ZkvZ1p2;$-;cUT8%95nAq4ej|Nak%t^bZiyv#T+J~y1VS5c} z?XZi1MLqmTGL3Q3l-s725^ecONj;VD0m6akFl(7t5-KFlNTTVg5jG-(#O9D0;@Cb) zWV@_OlOJlc#4l^IdsI0yk9Qw(kZQ4T%FP-9~G?zK4`F42B`PwVn7n-;PsqL~3j zsJeAh6)h%M7^C@qISW<>5MWd@dNT~IIbmRCZ42le;gkF^H`NWDTraUaBwNc8ZCYpuegKwg5IKWF@0c*qS)6N!a(LoX&lc{9;I~qkn zETLHqYBLlU&^oS?x@>PR+Rgp|`wIc`!ehL|=1M4~OB<62OL$3!&IVdyyTY|$iETzK zk!=7vb8q}gy~CojmNInipU4~z`b`w6rqV%RU<@_w$aZssj$0L#Ttu1 zLrz;M@goLNl}c9W9a&jbEKg4P$%a{~@dfhsCI*+c@u-8LDH91>Je*kC-Mgf|II_8%f+N!b1!xrwCz`fT4$RFUOW)5?Du%PWrGnAR7T1 zaoglj^~O9>Vf$#AYfub3c6X6zS3RB_tc89BYUj76RS0liZU7EV99z|=J4_fY8*a8# zV+B{c_Hk=q2B1S+jr1XCkP5?ykXmGRwd$jf+ZJwIhs+Q3K-vy{QUB6U-Th2|faA7OG`+Ch0Wia?Z|j^-OCV zd4+u=!g?f3!DARQASOT?e4GZT2Z?M=`1n^k=Xw@6oFewM4h%S~Nj2)gpcXK0Dnv9a z$W1I>ytKP(Nn4_&sikS5CXj~y$Q+sKgp0;rjJZI))2dnJG4my>dZ}ELEm8y=wJd<= zQibU{V4O11HMkrBf`9G?Ws^nQ%rngUJlW<-9&{QcEcNloGM%LIqur!`4i$ zmIlo%=hL;=L@8I$0JwX|!*=mITF8qs3ZGim`qh za~d~SUqE0nlgDtOQZCJ83n|%Rm+IxlgYi-j8|gxRvbH2@$l+<7TCjl-(N{dG<-3fo zCW(grwd{s5A?h?3?1D1oCvxc<8^Hvf$fOZyxCHL4iR(3~q`rZ2WvHZ^ zYdT-zlqKxqCbPB8kkTC!$PPbTPZx)SxauVmBiPro1r44akm4LV`b5aCoUc;}W{8c1 z%n&JN9uvRB`C;2jhNfo1H7`&)6oey@QZtnhHRUIRm^#_$)v*=BdT?Ib|3p`B0wa;C zMSD61mv;0dnwunm$dvM_qmD|HN;n9LOvFX5f`hMkNmO1KDvs5%lkQ@&aadt?MrMqn ziEW03s5dA&WK+;CiBW1R8lDNk!oa%Lk`=J$n4c*%99GoQ4V@Yk^R-aoqZ0|l-LMux z(TBFuAWSrjlAmRQwC8(sLB|Bv`EH`Fa>1@;YMD#1m<15CADf7!dO`^xkeSRNbSMtx zt`4BC`PX{o2|cfHRA~%;YAPwGl6q!6lRtXBB%hZ(W8ZU(BmS$U#93WzV8K^TjuJx& RR9Yq0=X5YORYbhx{{!2S-0}bb literal 0 HcmV?d00001 diff --git a/regexp/README b/regexp/README new file mode 100644 index 0000000..a96dee5 --- /dev/null +++ b/regexp/README @@ -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. diff --git a/regexp/fixtabs.c b/regexp/fixtabs.c new file mode 100644 index 0000000..8d58e42 --- /dev/null +++ b/regexp/fixtabs.c @@ -0,0 +1,17 @@ +#include + +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]); + } + } +} \ No newline at end of file diff --git a/regexp/makefile.pc b/regexp/makefile.pc new file mode 100644 index 0000000..78a7fc8 --- /dev/null +++ b/regexp/makefile.pc @@ -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 + +void +regerror(s) +char *s; +{ +#ifdef ERRAVAIL + error("regexp: %s", s); +#else + fprintf(stderr, "regexp(3): %s", s); + exit(1); +#endif + /* NOTREACHED */ +} diff --git a/regexp/regexp.3 b/regexp/regexp.3 new file mode 100644 index 0000000..6ee5e50 --- /dev/null +++ b/regexp/regexp.3 @@ -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 *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. diff --git a/regexp/regexp.c b/regexp/regexp.c new file mode 100644 index 0000000..bca391e --- /dev/null +++ b/regexp/regexp.c @@ -0,0 +1,1214 @@ +/* + * regcomp and regexec -- regsub and regerror are elsewhere + * + * 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. + * + * Beware that some of this code is subtly aware of the way operator + * precedence is structured in regular expressions. Serious changes in + * regular-expression syntax might require a total rethink. + */ +#include +#include "regexp.h" +#include "regmagic.h" + +/* + * The "internal use only" fields in regexp.h are present to pass info from + * compile to execute that permits the execute phase to run lots faster on + * simple cases. They are: + * + * regstart char that must begin a match; '\0' if none obvious + * reganch is the match anchored (at beginning-of-line only)? + * regmust string (pointer into program) that match must include, or NULL + * regmlen length of regmust string + * + * Regstart and reganch permit very fast decisions on suitable starting points + * for a match, cutting down the work a lot. Regmust permits fast rejection + * of lines that cannot possibly match. The regmust tests are costly enough + * that regcomp() supplies a regmust only if the r.e. contains something + * potentially expensive (at present, the only such thing detected is * or + + * at the start of the r.e., which can involve a lot of backup). Regmlen is + * supplied because the test in regexec() needs it and regcomp() is computing + * it anyway. + */ + +/* + * Structure for regexp "program". This is essentially a linear encoding + * of a nondeterministic finite-state machine (aka syntax charts or + * "railroad normal form" in parsing technology). Each node is an opcode + * plus a "next" pointer, possibly plus an operand. "Next" pointers of + * all nodes except BRANCH implement concatenation; a "next" pointer with + * a BRANCH on both ends of it is connecting two alternatives. (Here we + * have one of the subtle syntax dependencies: an individual BRANCH (as + * opposed to a collection of them) is never concatenated with anything + * because of operator precedence.) The operand of some types of node is + * a literal string; for others, it is a node leading into a sub-FSM. In + * particular, the operand of a BRANCH node is the first node of the branch. + * (NB this is *not* a tree structure: the tail of the branch connects + * to the thing following the set of BRANCHes.) The opcodes are: + */ + +/* definition number opnd? meaning */ +#define END 0 /* no End of program. */ +#define BOL 1 /* no Match "" at beginning of line. */ +#define EOL 2 /* no Match "" at end of line. */ +#define ANY 3 /* no Match any one character. */ +#define ANYOF 4 /* str Match any character in this string. */ +#define ANYBUT 5 /* str Match any character not in this string. */ +#define BRANCH 6 /* node Match this alternative, or the next... */ +#define BACK 7 /* no Match "", "next" ptr points backward. */ +#define EXACTLY 8 /* str Match this string. */ +#define NOTHING 9 /* no Match empty string. */ +#define STAR 10 /* node Match this (simple) thing 0 or more times. */ +#define PLUS 11 /* node Match this (simple) thing 1 or more times. */ +#define OPEN 20 /* no Mark this point in input as start of #n. */ + /* OPEN+1 is number 1, etc. */ +#define CLOSE 30 /* no Analogous to OPEN. */ + +/* + * Opcode notes: + * + * BRANCH The set of branches constituting a single choice are hooked + * together with their "next" pointers, since precedence prevents + * anything being concatenated to any individual branch. The + * "next" pointer of the last BRANCH in a choice points to the + * thing following the whole choice. This is also where the + * final "next" pointer of each individual branch points; each + * branch starts with the operand node of a BRANCH node. + * + * BACK Normal "next" pointers all implicitly point forward; BACK + * exists to make loop structures possible. + * + * STAR,PLUS '?', and complex '*' and '+', are implemented as circular + * BRANCH structures using BACK. Simple cases (one character + * per match) are implemented with STAR and PLUS for speed + * and to minimize recursive plunges. + * + * OPEN,CLOSE ...are numbered at compile time. + */ + +/* + * A node is one char of opcode followed by two chars of "next" pointer. + * "Next" pointers are stored as two 8-bit pieces, high order first. The + * value is a positive offset from the opcode of the node containing it. + * An operand, if any, simply follows the node. (Note that much of the + * code generation knows about this implicit relationship.) + * + * Using two bytes for the "next" pointer is vast overkill for most things, + * but allows patterns to get big without disasters. + */ +#define OP(p) (*(p)) +#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377)) +#define OPERAND(p) ((p) + 3) + +/* + * See regmagic.h for one further detail of program structure. + */ + + +/* + * Utility definitions. + */ +#ifndef CHARBITS +#define UCHARAT(p) ((int)*(unsigned char *)(p)) +#else +#define UCHARAT(p) ((int)*(p)&CHARBITS) +#endif + +#define FAIL(m) { regerror(m); return(NULL); } +#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') +#define META "^$.[()|?+*\\" + +/* + * Flags to be passed up and down. + */ +#define HASWIDTH 01 /* Known never to match null string. */ +#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */ +#define SPSTART 04 /* Starts with * or +. */ +#define WORST 0 /* Worst case. */ + +/* + * Global work variables for regcomp(). + */ +static char *regparse; /* Input-scan pointer. */ +static int regnpar; /* () count. */ +static char regdummy; +static char *regcode; /* Code-emit pointer; ®dummy = don't. */ +static long regsize; /* Code size. */ + +/* + * Forward declarations for regcomp()'s friends. + */ +#ifndef STATIC +#define STATIC static +#endif +STATIC char *reg(); +STATIC char *regbranch(); +STATIC char *regpiece(); +STATIC char *regatom(); +STATIC char *regnode(); +STATIC char *regnext(); +STATIC void regc(); +STATIC void reginsert(); +STATIC void regtail(); +STATIC void regoptail(); +#ifdef STRCSPN +STATIC int strcspn(); +#endif + +/* + - regcomp - compile a regular expression into internal code + * + * We can't allocate space until we know how big the compiled form will be, + * but we can't compile it (and thus know how big it is) until we've got a + * place to put the code. So we cheat: we compile it twice, once with code + * generation turned off and size counting turned on, and once "for real". + * This also means that we don't allocate space until we are sure that the + * thing really will compile successfully, and we never have to move the + * code and thus invalidate pointers into it. (Note that it has to be in + * one piece because free() must be able to free it all.) + * + * Beware that the optimization-preparation code in here knows about some + * of the structure of the compiled regexp. + */ +regexp * +regcomp(exp) +char *exp; +{ + register regexp *r; + register char *scan; + register char *longest; + register int len; + int flags; + extern char *malloc(); + + if (exp == NULL) + FAIL("NULL argument"); + + /* First pass: determine size, legality. */ + regparse = exp; + regnpar = 1; + regsize = 0L; + regcode = ®dummy; + regc(MAGIC); + if (reg(0, &flags) == NULL) + return(NULL); + + /* Small enough for pointer-storage convention? */ + if (regsize >= 32767L) /* Probably could be 65535L. */ + FAIL("regexp too big"); + + /* Allocate space. */ + r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize); + if (r == NULL) + FAIL("out of space"); + + /* Second pass: emit code. */ + regparse = exp; + regnpar = 1; + regcode = r->program; + regc(MAGIC); + if (reg(0, &flags) == NULL) + return(NULL); + + /* Dig out information for optimizations. */ + r->regstart = '\0'; /* Worst-case defaults. */ + r->reganch = 0; + r->regmust = NULL; + r->regmlen = 0; + scan = r->program+1; /* First BRANCH. */ + if (OP(regnext(scan)) == END) { /* Only one top-level choice. */ + scan = OPERAND(scan); + + /* Starting-point info. */ + if (OP(scan) == EXACTLY) + r->regstart = *OPERAND(scan); + else if (OP(scan) == BOL) + r->reganch++; + + /* + * If there's something expensive in the r.e., find the + * longest literal string that must appear and make it the + * regmust. Resolve ties in favor of later strings, since + * the regstart check works with the beginning of the r.e. + * and avoiding duplication strengthens checking. Not a + * strong reason, but sufficient in the absence of others. + */ + if (flags&SPSTART) { + longest = NULL; + len = 0; + for (; scan != NULL; scan = regnext(scan)) + if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) { + longest = OPERAND(scan); + len = strlen(OPERAND(scan)); + } + r->regmust = longest; + r->regmlen = len; + } + } + + return(r); +} + +/* + - reg - regular expression, i.e. main body or parenthesized thing + * + * Caller must absorb opening parenthesis. + * + * Combining parenthesis handling with the base level of regular expression + * is a trifle forced, but the need to tie the tails of the branches to what + * follows makes it hard to avoid. + */ +static char * +reg(paren, flagp) +int paren; /* Parenthesized? */ +int *flagp; +{ + register char *ret; + register char *br; + register char *ender; + register int parno; + int flags; + + *flagp = HASWIDTH; /* Tentatively. */ + + /* Make an OPEN node, if parenthesized. */ + if (paren) { + if (regnpar >= NSUBEXP) + FAIL("too many ()"); + parno = regnpar; + regnpar++; + ret = regnode(OPEN+parno); + } else + ret = NULL; + + /* Pick up the branches, linking them together. */ + br = regbranch(&flags); + if (br == NULL) + return(NULL); + if (ret != NULL) + regtail(ret, br); /* OPEN -> first. */ + else + ret = br; + if (!(flags&HASWIDTH)) + *flagp &= ~HASWIDTH; + *flagp |= flags&SPSTART; + while (*regparse == '|') { + regparse++; + br = regbranch(&flags); + if (br == NULL) + return(NULL); + regtail(ret, br); /* BRANCH -> BRANCH. */ + if (!(flags&HASWIDTH)) + *flagp &= ~HASWIDTH; + *flagp |= flags&SPSTART; + } + + /* Make a closing node, and hook it on the end. */ + ender = regnode((paren) ? CLOSE+parno : END); + regtail(ret, ender); + + /* Hook the tails of the branches to the closing node. */ + for (br = ret; br != NULL; br = regnext(br)) + regoptail(br, ender); + + /* Check for proper termination. */ + if (paren && *regparse++ != ')') { + FAIL("unmatched ()"); + } else if (!paren && *regparse != '\0') { + if (*regparse == ')') { + FAIL("unmatched ()"); + } else + FAIL("junk on end"); /* "Can't happen". */ + /* NOTREACHED */ + } + + return(ret); +} + +/* + - regbranch - one alternative of an | operator + * + * Implements the concatenation operator. + */ +static char * +regbranch(flagp) +int *flagp; +{ + register char *ret; + register char *chain; + register char *latest; + int flags; + + *flagp = WORST; /* Tentatively. */ + + ret = regnode(BRANCH); + chain = NULL; + while (*regparse != '\0' && *regparse != '|' && *regparse != ')') { + latest = regpiece(&flags); + if (latest == NULL) + return(NULL); + *flagp |= flags&HASWIDTH; + if (chain == NULL) /* First piece. */ + *flagp |= flags&SPSTART; + else + regtail(chain, latest); + chain = latest; + } + if (chain == NULL) /* Loop ran zero times. */ + (void) regnode(NOTHING); + + return(ret); +} + +/* + - regpiece - something followed by possible [*+?] + * + * Note that the branching code sequences used for ? and the general cases + * of * and + are somewhat optimized: they use the same NOTHING node as + * both the endmarker for their branch list and the body of the last branch. + * It might seem that this node could be dispensed with entirely, but the + * endmarker role is not redundant. + */ +static char * +regpiece(flagp) +int *flagp; +{ + register char *ret; + register char op; + register char *next; + int flags; + + ret = regatom(&flags); + if (ret == NULL) + return(NULL); + + op = *regparse; + if (!ISMULT(op)) { + *flagp = flags; + return(ret); + } + + if (!(flags&HASWIDTH) && op != '?') + FAIL("*+ operand could be empty"); + *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH); + + if (op == '*' && (flags&SIMPLE)) + reginsert(STAR, ret); + else if (op == '*') { + /* Emit x* as (x&|), where & means "self". */ + reginsert(BRANCH, ret); /* Either x */ + regoptail(ret, regnode(BACK)); /* and loop */ + regoptail(ret, ret); /* back */ + regtail(ret, regnode(BRANCH)); /* or */ + regtail(ret, regnode(NOTHING)); /* null. */ + } else if (op == '+' && (flags&SIMPLE)) + reginsert(PLUS, ret); + else if (op == '+') { + /* Emit x+ as x(&|), where & means "self". */ + next = regnode(BRANCH); /* Either */ + regtail(ret, next); + regtail(regnode(BACK), ret); /* loop back */ + regtail(next, regnode(BRANCH)); /* or */ + regtail(ret, regnode(NOTHING)); /* null. */ + } else if (op == '?') { + /* Emit x? as (x|) */ + reginsert(BRANCH, ret); /* Either x */ + regtail(ret, regnode(BRANCH)); /* or */ + next = regnode(NOTHING); /* null. */ + regtail(ret, next); + regoptail(ret, next); + } + regparse++; + if (ISMULT(*regparse)) + FAIL("nested *?+"); + + return(ret); +} + +/* + - regatom - the lowest level + * + * Optimization: gobbles an entire sequence of ordinary characters so that + * it can turn them into a single node, which is smaller to store and + * faster to run. Backslashed characters are exceptions, each becoming a + * separate node; the code is simpler that way and it's not worth fixing. + */ +static char * +regatom(flagp) +int *flagp; +{ + register char *ret; + int flags; + + *flagp = WORST; /* Tentatively. */ + + switch (*regparse++) { + case '^': + ret = regnode(BOL); + break; + case '$': + ret = regnode(EOL); + break; + case '.': + ret = regnode(ANY); + *flagp |= HASWIDTH|SIMPLE; + break; + case '[': { + register int class; + register int classend; + + if (*regparse == '^') { /* Complement of range. */ + ret = regnode(ANYBUT); + regparse++; + } else + ret = regnode(ANYOF); + if (*regparse == ']' || *regparse == '-') + regc(*regparse++); + while (*regparse != '\0' && *regparse != ']') { + if (*regparse == '-') { + regparse++; + if (*regparse == ']' || *regparse == '\0') + regc('-'); + else { + class = UCHARAT(regparse-2)+1; + classend = UCHARAT(regparse); + if (class > classend+1) + FAIL("invalid [] range"); + for (; class <= classend; class++) + regc(class); + regparse++; + } + } else + regc(*regparse++); + } + regc('\0'); + if (*regparse != ']') + FAIL("unmatched []"); + regparse++; + *flagp |= HASWIDTH|SIMPLE; + } + break; + case '(': + ret = reg(1, &flags); + if (ret == NULL) + return(NULL); + *flagp |= flags&(HASWIDTH|SPSTART); + break; + case '\0': + case '|': + case ')': + FAIL("internal urp"); /* Supposed to be caught earlier. */ + break; + case '?': + case '+': + case '*': + FAIL("?+* follows nothing"); + break; + case '\\': + if (*regparse == '\0') + FAIL("trailing \\"); + ret = regnode(EXACTLY); + regc(*regparse++); + regc('\0'); + *flagp |= HASWIDTH|SIMPLE; + break; + default: { + register int len; + register char ender; + + regparse--; + len = strcspn(regparse, META); + if (len <= 0) + FAIL("internal disaster"); + ender = *(regparse+len); + if (len > 1 && ISMULT(ender)) + len--; /* Back off clear of ?+* operand. */ + *flagp |= HASWIDTH; + if (len == 1) + *flagp |= SIMPLE; + ret = regnode(EXACTLY); + while (len > 0) { + regc(*regparse++); + len--; + } + regc('\0'); + } + break; + } + + return(ret); +} + +/* + - regnode - emit a node + */ +static char * /* Location. */ +regnode(op) +char op; +{ + register char *ret; + register char *ptr; + + ret = regcode; + if (ret == ®dummy) { + regsize += 3; + return(ret); + } + + ptr = ret; + *ptr++ = op; + *ptr++ = '\0'; /* Null "next" pointer. */ + *ptr++ = '\0'; + regcode = ptr; + + return(ret); +} + +/* + - regc - emit (if appropriate) a byte of code + */ +static void +regc(b) +char b; +{ + if (regcode != ®dummy) + *regcode++ = b; + else + regsize++; +} + +/* + - reginsert - insert an operator in front of already-emitted operand + * + * Means relocating the operand. + */ +static void +reginsert(op, opnd) +char op; +char *opnd; +{ + register char *src; + register char *dst; + register char *place; + + if (regcode == ®dummy) { + regsize += 3; + return; + } + + src = regcode; + regcode += 3; + dst = regcode; + while (src > opnd) + *--dst = *--src; + + place = opnd; /* Op node, where operand used to be. */ + *place++ = op; + *place++ = '\0'; + *place++ = '\0'; +} + +/* + - regtail - set the next-pointer at the end of a node chain + */ +static void +regtail(p, val) +char *p; +char *val; +{ + register char *scan; + register char *temp; + register int offset; + + if (p == ®dummy) + return; + + /* Find last node. */ + scan = p; + for (;;) { + temp = regnext(scan); + if (temp == NULL) + break; + scan = temp; + } + + if (OP(scan) == BACK) + offset = scan - val; + else + offset = val - scan; + *(scan+1) = (offset>>8)&0377; + *(scan+2) = offset&0377; +} + +/* + - regoptail - regtail on operand of first argument; nop if operandless + */ +static void +regoptail(p, val) +char *p; +char *val; +{ + /* "Operandless" and "op != BRANCH" are synonymous in practice. */ + if (p == NULL || p == ®dummy || OP(p) != BRANCH) + return; + regtail(OPERAND(p), val); +} + +/* + * regexec and friends + */ + +/* + * Global work variables for regexec(). + */ +static char *reginput; /* String-input pointer. */ +static char *regbol; /* Beginning of input, for ^ check. */ +static char **regstartp; /* Pointer to startp array. */ +static char **regendp; /* Ditto for endp. */ + +/* + * Forwards. + */ +STATIC int regtry(); +STATIC int regmatch(); +STATIC int regrepeat(); + +#ifdef DEBUG +int regnarrate = 0; +void regdump(); +STATIC char *regprop(); +#endif + +/* + - regexec - match a regexp against a string + */ +int +regexec(prog, string) +register regexp *prog; +register char *string; +{ + register char *s; + extern char *strchr(); + + /* Be paranoid... */ + if (prog == NULL || string == NULL) { + regerror("NULL parameter"); + return(0); + } + + /* Check validity of program. */ + if (UCHARAT(prog->program) != MAGIC) { + regerror("corrupted program"); + return(0); + } + + /* If there is a "must appear" string, look for it. */ + if (prog->regmust != NULL) { + s = string; + while ((s = strchr(s, prog->regmust[0])) != NULL) { + if (strncmp(s, prog->regmust, prog->regmlen) == 0) + break; /* Found it. */ + s++; + } + if (s == NULL) /* Not present. */ + return(0); + } + + /* Mark beginning of line for ^ . */ + regbol = string; + + /* Simplest case: anchored match need be tried only once. */ + if (prog->reganch) + return(regtry(prog, string)); + + /* Messy cases: unanchored match. */ + s = string; + if (prog->regstart != '\0') + /* We know what char it must start with. */ + while ((s = strchr(s, prog->regstart)) != NULL) { + if (regtry(prog, s)) + return(1); + s++; + } + else + /* We don't -- general case. */ + do { + if (regtry(prog, s)) + return(1); + } while (*s++ != '\0'); + + /* Failure. */ + return(0); +} + +/* + - regtry - try match at specific point + */ +static int /* 0 failure, 1 success */ +regtry(prog, string) +regexp *prog; +char *string; +{ + register int i; + register char **sp; + register char **ep; + + reginput = string; + regstartp = prog->startp; + regendp = prog->endp; + + sp = prog->startp; + ep = prog->endp; + for (i = NSUBEXP; i > 0; i--) { + *sp++ = NULL; + *ep++ = NULL; + } + if (regmatch(prog->program + 1)) { + prog->startp[0] = string; + prog->endp[0] = reginput; + return(1); + } else + return(0); +} + +/* + - regmatch - main matching routine + * + * Conceptually the strategy is simple: check to see whether the current + * node matches, call self recursively to see whether the rest matches, + * and then act accordingly. In practice we make some effort to avoid + * recursion, in particular by going through "ordinary" nodes (that don't + * need to know whether the rest of the match failed) by a loop instead of + * by recursion. + */ +static int /* 0 failure, 1 success */ +regmatch(prog) +char *prog; +{ + register char *scan; /* Current node. */ + char *next; /* Next node. */ + extern char *strchr(); + + scan = prog; +#ifdef DEBUG + if (scan != NULL && regnarrate) + fprintf(stderr, "%s(\n", regprop(scan)); +#endif + while (scan != NULL) { +#ifdef DEBUG + if (regnarrate) + fprintf(stderr, "%s...\n", regprop(scan)); +#endif + next = regnext(scan); + + switch (OP(scan)) { + case BOL: + if (reginput != regbol) + return(0); + break; + case EOL: + if (*reginput != '\0') + return(0); + break; + case ANY: + if (*reginput == '\0') + return(0); + reginput++; + break; + case EXACTLY: { + register int len; + register char *opnd; + + opnd = OPERAND(scan); + /* Inline the first character, for speed. */ + if (*opnd != *reginput) + return(0); + len = strlen(opnd); + if (len > 1 && strncmp(opnd, reginput, len) != 0) + return(0); + reginput += len; + } + break; + case ANYOF: + if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL) + return(0); + reginput++; + break; + case ANYBUT: + if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL) + return(0); + reginput++; + break; + case NOTHING: + break; + case BACK: + break; + case OPEN+1: + case OPEN+2: + case OPEN+3: + case OPEN+4: + case OPEN+5: + case OPEN+6: + case OPEN+7: + case OPEN+8: + case OPEN+9: { + register int no; + register char *save; + + no = OP(scan) - OPEN; + save = reginput; + + if (regmatch(next)) { + /* + * Don't set startp if some later + * invocation of the same parentheses + * already has. + */ + if (regstartp[no] == NULL) + regstartp[no] = save; + return(1); + } else + return(0); + } + break; + case CLOSE+1: + case CLOSE+2: + case CLOSE+3: + case CLOSE+4: + case CLOSE+5: + case CLOSE+6: + case CLOSE+7: + case CLOSE+8: + case CLOSE+9: { + register int no; + register char *save; + + no = OP(scan) - CLOSE; + save = reginput; + + if (regmatch(next)) { + /* + * Don't set endp if some later + * invocation of the same parentheses + * already has. + */ + if (regendp[no] == NULL) + regendp[no] = save; + return(1); + } else + return(0); + } + break; + case BRANCH: { + register char *save; + + if (OP(next) != BRANCH) /* No choice. */ + next = OPERAND(scan); /* Avoid recursion. */ + else { + do { + save = reginput; + if (regmatch(OPERAND(scan))) + return(1); + reginput = save; + scan = regnext(scan); + } while (scan != NULL && OP(scan) == BRANCH); + return(0); + /* NOTREACHED */ + } + } + break; + case STAR: + case PLUS: { + register char nextch; + register int no; + register char *save; + register int min; + + /* + * Lookahead to avoid useless match attempts + * when we know what character comes next. + */ + nextch = '\0'; + if (OP(next) == EXACTLY) + nextch = *OPERAND(next); + min = (OP(scan) == STAR) ? 0 : 1; + save = reginput; + no = regrepeat(OPERAND(scan)); + while (no >= min) { + /* If it could work, try it. */ + if (nextch == '\0' || *reginput == nextch) + if (regmatch(next)) + return(1); + /* Couldn't or didn't -- back up. */ + no--; + reginput = save + no; + } + return(0); + } + break; + case END: + return(1); /* Success! */ + break; + default: + regerror("memory corruption"); + return(0); + break; + } + + scan = next; + } + + /* + * We get here only if there's trouble -- normally "case END" is + * the terminating point. + */ + regerror("corrupted pointers"); + return(0); +} + +/* + - regrepeat - repeatedly match something simple, report how many + */ +static int +regrepeat(p) +char *p; +{ + register int count = 0; + register char *scan; + register char *opnd; + extern char *strchr(); /* MAS */ + + scan = reginput; + opnd = OPERAND(p); + switch (OP(p)) { + case ANY: + count = strlen(scan); + scan += count; + break; + case EXACTLY: + while (*opnd == *scan) { + count++; + scan++; + } + break; + case ANYOF: + while (*scan != '\0' && strchr(opnd, *scan) != NULL) { + count++; + scan++; + } + break; + case ANYBUT: + while (*scan != '\0' && strchr(opnd, *scan) == NULL) { + count++; + scan++; + } + break; + default: /* Oh dear. Called inappropriately. */ + regerror("internal foulup"); + count = 0; /* Best compromise. */ + break; + } + reginput = scan; + + return(count); +} + +/* + - regnext - dig the "next" pointer out of a node + */ +static char * +regnext(p) +register char *p; +{ + register int offset; + + if (p == ®dummy) + return(NULL); + + offset = NEXT(p); + if (offset == 0) + return(NULL); + + if (OP(p) == BACK) + return(p-offset); + else + return(p+offset); +} + +#ifdef DEBUG + +STATIC char *regprop(); + +/* + - regdump - dump a regexp onto stdout in vaguely comprehensible form + */ +void +regdump(r) +regexp *r; +{ + register char *s; + register char op = EXACTLY; /* Arbitrary non-END op. */ + register char *next; + extern char *strchr(); + + + s = r->program + 1; + while (op != END) { /* While that wasn't END last time... */ + op = OP(s); + printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */ + next = regnext(s); + if (next == NULL) /* Next ptr. */ + printf("(0)"); + else + printf("(%d)", (s-r->program)+(next-s)); + s += 3; + if (op == ANYOF || op == ANYBUT || op == EXACTLY) { + /* Literal string, where present. */ + while (*s != '\0') { + putchar(*s); + s++; + } + s++; + } + putchar('\n'); + } + + /* Header fields of interest. */ + if (r->regstart != '\0') + printf("start `%c' ", r->regstart); + if (r->reganch) + printf("anchored "); + if (r->regmust != NULL) + printf("must have \"%s\"", r->regmust); + printf("\n"); +} + +/* + - regprop - printable representation of opcode + */ +static char * +regprop(op) +char *op; +{ + register char *p; + static char buf[50]; + + (void) strcpy(buf, ":"); + + switch (OP(op)) { + case BOL: + p = "BOL"; + break; + case EOL: + p = "EOL"; + break; + case ANY: + p = "ANY"; + break; + case ANYOF: + p = "ANYOF"; + break; + case ANYBUT: + p = "ANYBUT"; + break; + case BRANCH: + p = "BRANCH"; + break; + case EXACTLY: + p = "EXACTLY"; + break; + case NOTHING: + p = "NOTHING"; + break; + case BACK: + p = "BACK"; + break; + case END: + p = "END"; + break; + case OPEN+1: + case OPEN+2: + case OPEN+3: + case OPEN+4: + case OPEN+5: + case OPEN+6: + case OPEN+7: + case OPEN+8: + case OPEN+9: + sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN); + p = NULL; + break; + case CLOSE+1: + case CLOSE+2: + case CLOSE+3: + case CLOSE+4: + case CLOSE+5: + case CLOSE+6: + case CLOSE+7: + case CLOSE+8: + case CLOSE+9: + sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE); + p = NULL; + break; + case STAR: + p = "STAR"; + break; + case PLUS: + p = "PLUS"; + break; + default: + regerror("corrupted opcode"); + break; + } + if (p != NULL) + (void) strcat(buf, p); + return(buf); +} +#endif + +/* + * The following is provided for those people who do not have strcspn() in + * their C libraries. They should get off their butts and do something + * about it; at least one public-domain implementation of those (highly + * useful) string routines has been published on Usenet. + */ +#ifdef STRCSPN +/* + * strcspn - find length of initial segment of s1 consisting entirely + * of characters not from s2 + */ + +static int +strcspn(s1, s2) +char *s1; +char *s2; +{ + register char *scan1; + register char *scan2; + register int count; + + count = 0; + for (scan1 = s1; *scan1 != '\0'; scan1++) { + for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */ + if (*scan1 == *scan2++) + return(count); + count++; + } + return(count); +} +#endif diff --git a/regexp/regexp.doc b/regexp/regexp.doc new file mode 100644 index 0000000..a96dee5 --- /dev/null +++ b/regexp/regexp.doc @@ -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. diff --git a/regexp/regexp.h b/regexp/regexp.h new file mode 100644 index 0000000..0481df0 --- /dev/null +++ b/regexp/regexp.h @@ -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(); diff --git a/regexp/regmagic.h b/regexp/regmagic.h new file mode 100644 index 0000000..bc6447d --- /dev/null +++ b/regexp/regmagic.h @@ -0,0 +1,5 @@ +/* + * The first byte of the regexp internal "program" is actually this magic + * number; the start node begins in the second byte. + */ +#define MAGIC 0234 diff --git a/regexp/regsub.c b/regexp/regsub.c new file mode 100644 index 0000000..f9152fb --- /dev/null +++ b/regexp/regsub.c @@ -0,0 +1,81 @@ +/* + * regsub + * + * 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. + */ +#include +#include "regexp.h" +#include "regmagic.h" + +#ifndef CHARBITS +#define UCHARAT(p) ((int)*(unsigned char *)(p)) +#else +#define UCHARAT(p) ((int)*(p)&CHARBITS) +#endif + +/* + - regsub - perform substitutions after a regexp match + */ +void +regsub(prog, source, dest) +regexp *prog; +char *source; +char *dest; +{ + register char *src; + register char *dst; + register char c; + register int no; + register int len; + extern char *strncpy(); + + if (prog == NULL || source == NULL || dest == NULL) { + regerror("NULL parm to regsub"); + return; + } + if (UCHARAT(prog->program) != MAGIC) { + regerror("damaged regexp fed to regsub"); + return; + } + + src = source; + dst = dest; + while ((c = *src++) != '\0') { + if (c == '&') + no = 0; + else if (c == '\\' && '0' <= *src && *src <= '9') + no = *src++ - '0'; + else + no = -1; + + if (no < 0) { /* Ordinary character. */ + if (c == '\\' && (*src == '\\' || *src == '&')) + c = *src++; + *dst++ = c; + } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) { + len = prog->endp[no] - prog->startp[no]; + (void) strncpy(dst, prog->startp[no], len); + dst += len; + if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */ + regerror("damaged match string"); + return; + } + } + } + *dst++ = '\0'; +} diff --git a/regexp/tests b/regexp/tests new file mode 100644 index 0000000..76b8f26 --- /dev/null +++ b/regexp/tests @@ -0,0 +1,120 @@ +abc abc y & abc +abc xbc n - - +abc axc n - - +abc abx n - - +abc xabcy y & abc +abc ababc y & abc +ab*c abc y & abc +ab*bc abc y & abc +ab*bc abbc y & abbc +ab*bc abbbbc y & abbbbc +ab+bc abbc y & abbc +ab+bc abc n - - +ab+bc abq n - - +ab+bc abbbbc y & abbbbc +ab?bc abbc y & abbc +ab?bc abc y & abc +ab?bc abbbbc n - - +ab?c abc y & abc +^abc$ abc y & abc +^abc$ abcc n - - +^abc abcc y & abc +^abc$ aabc n - - +abc$ aabc y & abc +^ abc y & +$ abc y & +a.c abc y & abc +a.c axc y & axc +a.*c axyzc y & axyzc +a.*c axyzd n - - +a[bc]d abc n - - +a[bc]d abd y & abd +a[b-d]e abd n - - +a[b-d]e ace y & ace +a[b-d] aac y & ac +a[-b] a- y & a- +a[b-] a- y & a- +a[b-a] - c - - +a[]b - c - - +a[ - c - - +a] a] y & a] +a[]]b a]b y & a]b +a[^bc]d aed y & aed +a[^bc]d abd n - - +a[^-b]c adc y & adc +a[^-b]c a-c n - - +a[^]b]c a]c n - - +a[^]b]c adc y & adc +ab|cd abc y & ab +ab|cd abcd y & ab +()ef def y &-\1 ef- +()* - c - - +*a - c - - +^* - c - - +$* - c - - +(*)b - c - - +$b b n - - +a\ - c - - +a\(b a(b y &-\1 a(b- +a\(*b ab y & ab +a\(*b a((b y & a((b +a\\b a\b y & a\b +abc) - c - - +(abc - c - - +((a)) abc y &-\1-\2 a-a-a +(a)b(c) abc y &-\1-\2 abc-a-c +a+b+c aabbabc y & abc +a** - c - - +a*? - c - - +(a*)* - c - - +(a*)+ - c - - +(a|)* - c - - +(a*|b)* - c - - +(a+|b)* ab y &-\1 ab-b +(a+|b)+ ab y &-\1 ab-b +(a+|b)? ab y &-\1 a-a +[^ab]* cde y & cde +(^)* - c - - +(ab|)* - c - - +)( - c - - + abc y & + abc n - - +a* y & +([abc])*d abbbcd y &-\1 abbbcd-c +([abc])*bcd abcd y &-\1 abcd-a +a|b|c|d|e e y & e +(a|b|c|d|e)f ef y &-\1 ef-e +((a*|b))* - c - - +abcd*efg abcdefg y & abcdefg +ab* xabyabbbz y & ab +ab* xayabbbz y & a +(ab|cd)e abcde y &-\1 cde-cd +[abhgefdc]ij hij y & hij +^(ab|cd)e abcde n x\1y xy +(abc|)ef abcdef y &-\1 ef- +(a|b)c*d abcd y &-\1 bcd-b +(ab|ab*)bc abc y &-\1 abc-a +a([bc]*)c* abc y &-\1 abc-bc +a([bc]*)(c*d) abcd y &-\1-\2 abcd-bc-d +a([bc]+)(c*d) abcd y &-\1-\2 abcd-bc-d +a([bc]*)(c+d) abcd y &-\1-\2 abcd-b-cd +a[bcd]*dcdcde adcdcde y & adcdcde +a[bcd]+dcdcde adcdcde n - - +(ab|a)b*c abc y &-\1 abc-ab +((a)(b)c)(d) abcd y \1-\2-\3-\4 abc-a-b-d +[a-zA-Z_][a-zA-Z0-9_]* alpha y & alpha +^a(bc+|b[eh])g|.h$ abh y &-\1 bh- +(bc+d$|ef*g.|h?i(j|k)) effgz y &-\1-\2 effgz-effgz- +(bc+d$|ef*g.|h?i(j|k)) ij y &-\1-\2 ij-ij-j +(bc+d$|ef*g.|h?i(j|k)) effg n - - +(bc+d$|ef*g.|h?i(j|k)) bcdd n - - +(bc+d$|ef*g.|h?i(j|k)) reffgz y &-\1-\2 effgz-effgz- +((((((((((a)))))))))) - c - - +(((((((((a))))))))) a y & a +multiple words of text uh-uh n - - +multiple words multiple words, yeah y & multiple words +(.*)c(.*) abcde y &-\1-\2 abcde-ab-de +\((.*), (.*)\) (a, b) y (\2, \1) (b, a) +abcd abcd y &-\&-\\& abcd-&-\abcd +a(bc)d abcd y \1-\\1-\\\1 bc-\1-\bc +[k] ab n - - diff --git a/regexp/tests.bad b/regexp/tests.bad new file mode 100644 index 0000000..8d154cb --- /dev/null +++ b/regexp/tests.bad @@ -0,0 +1,119 @@ +abc abc y & abc +abc xbc n - - +abc axc n - - +abc abx n - - +abc xabcy y & abc +abc ababc y & abc +ab*c abc y & abc +ab*bc abc y & abc +ab*bc abbc y & abbc +ab*bc abbbbc y & abbbbc +ab+bc abbc y & abbc +ab+bc abc n - - +ab+bc abq n - - +ab+bc abbbbc y & abbbbc +ab?bc abbc y & abbc +ab?bc abc y & abc +ab?bc abbbbc n - - +ab?c abc y & abc +^abc$ abc y & abc +^abc$ abcc n - - +^abc abcc y & abc +^abc$ aabc n - - +abc$ aabc y & abc +^ abc y & +$ abc y & +a.c abc y & abc +a.c axc y & axc +a.*c axyzc y & axyzc +a.*c axyzd n - - +a[bc]d abc n - - +a[bc]d abd y & abd +a[b-d]e abd n - - +a[b-d]e ace y & ace +a[b-d] aac y & ac +a[-b] a- y & a- +a[b-] a- y & a- +a[b-a] - c - - +a[]b - c - - +a[ - c - - +a] a] y & a] +a[]]b a]b y & a]b +a[^bc]d aed y & aed +a[^bc]d abd n - - +a[^-b]c adc y & adc +a[^-b]c a-c n - - +a[^]b]c a]c n - - +a[^]b]c adc y & adc +ab|cd abc y & ab +ab|cd abcd y & ab +()ef def y &-\1 ef- +()* - c - - +*a - c - - +^* - c - - +$* - c - - +(*)b - c - - +$b b n - - +a\ - c - - +a\(b a(b y &-\1 a(b- +a\(*b ab y & ab +a\(*b a((b y & a((b +a\\b a\b y & a\b +abc) - c - - +(abc - c - - +((a)) abc y &-\1-\2 a-a-a +(a)b(c) abc y &-\1-\2 abc-a-c +a+b+c aabbabc y & abc +a** - c - - +a*? - c - - +(a*)* - c - - +(a*)+ - c - - +(a|)* - c - - +(a*|b)* - c - - +(a+|b)* ab y &-\1 ab-b +(a+|b)+ ab y &-\1 ab-b +(a+|b)? ab y &-\1 a-a +[^ab]* cde y & cde +(^)* - c - - +(ab|)* - c - - +)( - c - - + abc y & +abc n - - +a* y & +([abc])*d abbbcd y &-\1 abbbcd-c +([abc])*bcd abcd y &-\1 abcd-a +a|b|c|d|e e y & e +(a|b|c|d|e)f ef y &-\1 ef-e +((a*|b))* - c - - +abcd*efg abcdefg y & abcdefg +ab* xabyabbbz y & ab +ab* xayabbbz y & a +(ab|cd)e abcde y &-\1 cde-cd +[abhgefdc]ij hij y & hij +^(ab|cd)e abcde n x\1y xy +(abc|)ef abcdef y &-\1 ef- +(a|b)c*d abcd y &-\1 bcd-b +(ab|ab*)bc abc y &-\1 abc-a +a([bc]*)c* abc y &-\1 abc-bc +a([bc]*)(c*d) abcd y &-\1-\2 abcd-bc-d +a([bc]+)(c*d) abcd y &-\1-\2 abcd-bc-d +a([bc]*)(c+d) abcd y &-\1-\2 abcd-b-cd +a[bcd]*dcdcde adcdcde y & adcdcde +a[bcd]+dcdcde adcdcde n - - +(ab|a)b*c abc y &-\1 abc-ab +((a)(b)c)(d) abcd y \1-\2-\3-\4 abc-a-b-d +[a-zA-Z_][a-zA-Z0-9_]* alpha y & alpha +^a(bc+|b[eh])g|.h$ abh y &-\1 bh- +(bc+d$|ef*g.|h?i(j|k)) effgz y &-\1-\2 effgz-effgz- +(bc+d$|ef*g.|h?i(j|k)) ij y &-\1-\2 ij-ij-j +(bc+d$|ef*g.|h?i(j|k)) effg n - - +(bc+d$|ef*g.|h?i(j|k)) bcdd n - - +(bc+d$|ef*g.|h?i(j|k)) reffgz y &-\1-\2 effgz-effgz- +((((((((((a)))))))))) - c - - +(((((((((a))))))))) a y & a +multiple words of text uh-uh n - - +multiple words multiple words, yeah y & multiple words +(.*)c(.*) abcde y &-\1-\2 abcde-ab-de +\((.*), (.*)\) (a, b) y (\2, \1) (b, a) +abcd abcd y &-\&-\\& abcd-&-\abcd +a(bc)d abcd y \1-\\1-\\\1 bc-\1-\bc \ No newline at end of file diff --git a/regexp/timer.c b/regexp/timer.c new file mode 100644 index 0000000..d6b98d8 --- /dev/null +++ b/regexp/timer.c @@ -0,0 +1,182 @@ +/* + * Simple timing program for regcomp(). + * + * 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. + * + * Usage: timer ncomp nexec nsub + * or + * timer ncomp nexec nsub regexp string [ answer [ sub ] ] + * + * The second form is for timing repetitions of a single test case. + * The first form's test data is a compiled-in copy of the "tests" file. + * Ncomp, nexec, nsub are how many times to do each regcomp, regexec, + * and regsub. The way to time an operation individually is to do something + * like "timer 1 50 1". + */ +#include + +struct try { + char *re, *str, *ans, *src, *dst; +} tests[] = { +#include "timer.t.h" +{ NULL, NULL, NULL, NULL, NULL } +}; + +#include "regexp.h" + +int errreport = 0; /* Report errors via errseen? */ +char *errseen = NULL; /* Error message. */ + +char *progname; + +/* ARGSUSED */ +main(argc, argv) +int argc; +char *argv[]; +{ + int ncomp, nexec, nsub; + struct try one; + char dummy[512]; + + if (argc < 4) { + ncomp = 1; + nexec = 1; + nsub = 1; + } else { + ncomp = atoi(argv[1]); + nexec = atoi(argv[2]); + nsub = atoi(argv[3]); + } + + progname = argv[0]; + if (argc > 5) { + one.re = argv[4]; + one.str = argv[5]; + if (argc > 6) + one.ans = argv[6]; + else + one.ans = "y"; + if (argc > 7) { + one.src = argv[7]; + one.dst = "xxx"; + } else { + one.src = "x"; + one.dst = "x"; + } + errreport = 1; + try(one, ncomp, nexec, nsub); + } else + multiple(ncomp, nexec, nsub); + exit(0); +} + +void +regerror(s) +char *s; +{ + if (errreport) + errseen = s; + else + error(s, ""); +} + +#ifndef ERRAVAIL +error(s1, s2) +char *s1; +char *s2; +{ + fprintf(stderr, "regexp: "); + fprintf(stderr, s1, s2); + fprintf(stderr, "\n"); + exit(1); +} +#endif + +int lineno = 0; + +multiple(ncomp, nexec, nsub) +int ncomp, nexec, nsub; +{ + register int i; + extern char *strchr(); + + errreport = 1; + for (i = 0; tests[i].re != NULL; i++) { + lineno++; + try(tests[i], ncomp, nexec, nsub); + } +} + +try(fields, ncomp, nexec, nsub) +struct try fields; +int ncomp, nexec, nsub; +{ + regexp *r; + char dbuf[BUFSIZ]; + register int i; + + errseen = NULL; + r = regcomp(fields.re); + if (r == NULL) { + if (*fields.ans != 'c') + complain("regcomp failure in `%s'", fields.re); + return; + } + if (*fields.ans == 'c') { + complain("unexpected regcomp success in `%s'", fields.re); + free((char *)r); + return; + } + for (i = ncomp-1; i > 0; i--) { + free((char *)r); + r = regcomp(fields.re); + } + if (!regexec(r, fields.str)) { + if (*fields.ans != 'n') + complain("regexec failure in `%s'", ""); + free((char *)r); + return; + } + if (*fields.ans == 'n') { + complain("unexpected regexec success", ""); + free((char *)r); + return; + } + for (i = nexec-1; i > 0; i--) + (void) regexec(r, fields.str); + errseen = NULL; + for (i = nsub; i > 0; i--) + regsub(r, fields.src, dbuf); + if (errseen != NULL) { + complain("regsub complaint", ""); + free((char *)r); + return; + } + if (strcmp(dbuf, fields.dst) != 0) + complain("regsub result `%s' wrong", dbuf); + free((char *)r); +} + +complain(s1, s2) +char *s1; +char *s2; +{ + fprintf(stderr, "try: %d: ", lineno); + fprintf(stderr, s1, s2); + fprintf(stderr, " (%s)\n", (errseen != NULL) ? errseen : ""); +} diff --git a/regexp/try.c b/regexp/try.c new file mode 100644 index 0000000..b7e3a45 --- /dev/null +++ b/regexp/try.c @@ -0,0 +1,238 @@ +/* + * Simple test program for regexp(3) stuff. Knows about debugging hooks. + * + * 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. + * + * Usage: try re [string [output [-]]] + * The re is compiled and dumped, regexeced against the string, the result + * is applied to output using regsub(). The - triggers a running narrative + * from regexec(). Dumping and narrative don't happen unless DEBUG. + * + * If there are no arguments, stdin is assumed to be a stream of lines with + * five fields: a r.e., a string to match it against, a result code, a + * source string for regsub, and the proper result. Result codes are 'c' + * for compile failure, 'y' for match success, 'n' for match failure. + * Field separator is tab. + */ +#include +#include "regexp.h" + +#ifdef ERRAVAIL +char *progname; +extern char *mkprogname(); +#endif + +#ifdef DEBUG +extern int regnarrate; +#endif + +char buf[BUFSIZ]; + +int errreport = 0; /* Report errors via errseen? */ +char *errseen = NULL; /* Error message. */ +int status = 0; /* Exit status. */ + +/* ARGSUSED */ +main(argc, argv) +int argc; +char *argv[]; +{ + regexp *r; + int i; + +#ifdef ERRAVAIL + progname = mkprogname(argv[0]); +#endif + + if (argc == 1) { + multiple(); + exit(status); + } + + r = regcomp(argv[1]); + if (r == NULL) + error("regcomp failure", ""); +#ifdef DEBUG + regdump(r); + if (argc > 4) + regnarrate++; +#endif + if (argc > 2) { + i = regexec(r, argv[2]); + printf("%d", i); + for (i = 1; i < NSUBEXP; i++) + if (r->startp[i] != NULL && r->endp[i] != NULL) + printf(" \\%d", i); + printf("\n"); + } + if (argc > 3) { + regsub(r, argv[3], buf); + printf("%s\n", buf); + } + exit(status); +} + +void +regerror(s) +char *s; +{ + if (errreport) + errseen = s; + else + error(s, ""); +} + +#ifndef ERRAVAIL +error(s1, s2) +char *s1; +char *s2; +{ + fprintf(stderr, "regexp: "); + fprintf(stderr, s1, s2); + fprintf(stderr, "\n"); + exit(1); +} +#endif + +int lineno; + +regexp badregexp; /* Implicit init to 0. */ + +multiple() +{ + char rbuf[BUFSIZ]; + char *field[5]; + char *scan; + int i; + regexp *r; + extern char *strchr(); + + errreport = 1; + lineno = 0; + while (fgets(rbuf, sizeof(rbuf), stdin) != NULL) { + rbuf[strlen(rbuf)-1] = '\0'; /* Dispense with \n. */ + lineno++; + scan = rbuf; + for (i = 0; i < 5; i++) { + field[i] = scan; + if (field[i] == NULL) { + complain("bad testfile format", ""); + exit(1); + } + scan = strchr(scan, '\t'); + if (scan != NULL) + *scan++ = '\0'; + } + try(field); + } + + /* And finish up with some internal testing... */ + lineno = 9990; + errseen = NULL; + if (regcomp((char *)NULL) != NULL || errseen == NULL) + complain("regcomp(NULL) doesn't complain", ""); + lineno = 9991; + errseen = NULL; + if (regexec((regexp *)NULL, "foo") || errseen == NULL) + complain("regexec(NULL, ...) doesn't complain", ""); + lineno = 9992; + r = regcomp("foo"); + if (r == NULL) { + complain("regcomp(\"foo\") fails", ""); + return; + } + lineno = 9993; + errseen = NULL; + if (regexec(r, (char *)NULL) || errseen == NULL) + complain("regexec(..., NULL) doesn't complain", ""); + lineno = 9994; + errseen = NULL; + regsub((regexp *)NULL, "foo", rbuf); + if (errseen == NULL) + complain("regsub(NULL, ..., ...) doesn't complain", ""); + lineno = 9995; + errseen = NULL; + regsub(r, (char *)NULL, rbuf); + if (errseen == NULL) + complain("regsub(..., NULL, ...) doesn't complain", ""); + lineno = 9996; + errseen = NULL; + regsub(r, "foo", (char *)NULL); + if (errseen == NULL) + complain("regsub(..., ..., NULL) doesn't complain", ""); + lineno = 9997; + errseen = NULL; + if (regexec(&badregexp, "foo") || errseen == NULL) + complain("regexec(nonsense, ...) doesn't complain", ""); + lineno = 9998; + errseen = NULL; + regsub(&badregexp, "foo", rbuf); + if (errseen == NULL) + complain("regsub(nonsense, ..., ...) doesn't complain", ""); +} + +try(fields) +char **fields; +{ + regexp *r; + char dbuf[BUFSIZ]; + + errseen = NULL; + r = regcomp(fields[0]); + if (r == NULL) { + if (*fields[2] != 'c') + complain("regcomp failure in `%s'", fields[0]); + return; + } + if (*fields[2] == 'c') { + complain("unexpected regcomp success in `%s'", fields[0]); + free((char *)r); + return; + } + if (!regexec(r, fields[1])) { + if (*fields[2] != 'n') + complain("regexec failure in `%s'", ""); + free((char *)r); + return; + } + if (*fields[2] == 'n') { + complain("unexpected regexec success", ""); + free((char *)r); + return; + } + errseen = NULL; + regsub(r, fields[3], dbuf); + if (errseen != NULL) { + complain("regsub complaint", ""); + free((char *)r); + return; + } + if (strcmp(dbuf, fields[4]) != 0) + complain("regsub result `%s' wrong", dbuf); + free((char *)r); +} + +complain(s1, s2) +char *s1; +char *s2; +{ + fprintf(stderr, "try: %d: ", lineno); + fprintf(stderr, s1, s2); + fprintf(stderr, " (%s)\n", (errseen != NULL) ? errseen : ""); + status = 1; +} diff --git a/rules.mak b/rules.mak new file mode 100644 index 0000000..b4a9904 --- /dev/null +++ b/rules.mak @@ -0,0 +1,40 @@ +# You shouldn't need to edit this file, see the defs.mak file + +module: lib${MODULE}.o + +depend: ${DEPEND_FILE} + +${DEPEND_FILE}: + ${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} ${DEPEND_FLAG} ${SRCS} > ${DEPEND_FILE} + +.c.o: + @echo --- compiling ${MODULE}/$*.o + ${RM} $*.o + ${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} -c $*.c + +lib${MODULE}.o: ${OBJS} + @echo --- linking lib${MODULE}.o + ${RM} lib${MODULE}.o + ${LINK} ${OBJS} -o lib${MODULE}.o ${EXTERN_LIBS} + +lib: lib${MODULE}.a + +lib${MODULE}.a: ${OBJS} ${LIB_OBJS} + @echo --- archiving lib${MODULE}.a + ${RM} lib${MODULE}.a + ${AR} ${ARFLAGS} lib${MODULE}.a ${OBJS} ${LIB_OBJS} + ${RANLIB} lib${MODULE}.a + +${MODULE}: lib${MODULE}.o ${EXTRA_LIBS} + @echo --- building main ${MODULE} + ${RM} ${MODULE} + ${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} lib${MODULE}.o ${EXTRA_LIBS} \ + -o ${MODULE} ${LIBS} ${LDFLAGS} + +clean: + ${RM} ${CLEANS} + +tags: ${SRCS} ${LIB_SRCS} + ctags ${SRCS} ${LIB_SRCS} + +include ${DEPEND_FILE} diff --git a/scripts/config.guess b/scripts/config.guess new file mode 100755 index 0000000..cd430f6 --- /dev/null +++ b/scripts/config.guess @@ -0,0 +1,1314 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. + +timestamp='2001-08-21' + +# This file 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 2 of the License, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner . +# Please send patches to . +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + + +dummy=dummy-$$ +trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +set_cc_for_build='case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int dummy(){}" > $dummy.c ; + for c in cc gcc c89 ; do + ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 ; + if test $? = 0 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + rm -f $dummy.c $dummy.o $dummy.rel ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # Netbsd (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # Determine the machine/vendor (is the vendor relevant). + case "${UNAME_MACHINE}" in + amiga) machine=m68k-unknown ;; + arm32) machine=arm-unknown ;; + atari*) machine=m68k-atari ;; + sun3*) machine=m68k-sun ;; + mac68k) machine=m68k-apple ;; + macppc) machine=powerpc-apple ;; + hp3[0-9][05]) machine=m68k-hp ;; + ibmrt|romp-ibm) machine=romp-ibm ;; + *) machine=${UNAME_MACHINE}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE}" in + i386|sparc|amiga|arm*|hp300|mvme68k|vax|atari|luna68k|mac68k|news68k|next68k|pc532|sun3*|x68k) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit 0 ;; + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + cat <$dummy.s + .data +\$Lformat: + .byte 37,100,45,37,120,10,0 # "%d-%x\n" + + .text + .globl main + .align 4 + .ent main +main: + .frame \$30,16,\$26,0 + ldgp \$29,0(\$27) + .prologue 1 + .long 0x47e03d80 # implver \$0 + lda \$2,-1 + .long 0x47e20c21 # amask \$2,\$1 + lda \$16,\$Lformat + mov \$0,\$17 + not \$1,\$18 + jsr \$26,printf + ldgp \$29,0(\$26) + mov 0,\$16 + jsr \$26,exit + .end main +EOF + eval $set_cc_for_build + $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null + if test "$?" = 0 ; then + case `./$dummy` in + 0-0) + UNAME_MACHINE="alpha" + ;; + 1-0) + UNAME_MACHINE="alphaev5" + ;; + 1-1) + UNAME_MACHINE="alphaev56" + ;; + 1-101) + UNAME_MACHINE="alphapca56" + ;; + 2-303) + UNAME_MACHINE="alphaev6" + ;; + 2-307) + UNAME_MACHINE="alphaev67" + ;; + 2-1307) + UNAME_MACHINE="alphaev68" + ;; + esac + fi + rm -f $dummy.s $dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit 0 ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit 0;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + sparc*:NetBSD:*) + echo `uname -p`-unknown-netbsd${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit 0 ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit 0 ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + eval $set_cc_for_build + $CC_FOR_BUILD $dummy.c -o $dummy \ + && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm -f $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + eval $set_cc_for_build + $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + case "${HPUX_REV}" in + 11.[0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + esac ;; + esac + fi ;; + esac + if [ "${HP_ARCH}" = "" ]; then + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + eval $set_cc_for_build + (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy` + if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi + rm -f $dummy.c $dummy + fi ;; + esac + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + eval $set_cc_for_build + $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + hppa*:OpenBSD:*:*) + echo hppa-unknown-openbsd + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3D:*:*:*) + echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit 0 ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i386-pc-interix + exit 0 ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux + exit 0 ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + mips:Linux:*:*) + case `sed -n '/^byte/s/^.*: \(.*\) endian/\1/p' < /proc/cpuinfo` in + big) echo mips-unknown-linux-gnu && exit 0 ;; + little) echo mipsel-unknown-linux-gnu && exit 0 ;; + esac + ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit 0 ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit 0 ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit 0 ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit 0 ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit 0 ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit 0 ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit 0 ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + ld_supported_targets=`cd /; ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit 0 ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit 0 ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit 0 ;; + esac + # Determine whether the default compiler is a.out or elf + cat >$dummy.c < +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-pc-linux-gnu\n", argv[1]); +# else + printf ("%s-pc-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-pc-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-pc-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + eval $set_cc_for_build + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit 0 ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit 0 ;; + i*86:*:5:[78]*) + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit 0 ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit 0 ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit 0 ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit 0 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Darwin:*:*) + echo `uname -p`-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + if test "${UNAME_MACHINE}" = "x86pc"; then + UNAME_MACHINE=pc + fi + echo `uname -p`-${UNAME_MACHINE}-nto-qnx + exit 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSR-[KW]:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit 0 ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit 0 ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit 0 ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit 0 ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit 0 ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit 0 ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit 0 ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit 0 ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit 0 ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit 0 ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit 0 ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit 0 ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +eval $set_cc_for_build +$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0 +rm -f $dummy.c $dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/scripts/config.log b/scripts/config.log new file mode 100644 index 0000000..ecd61c8 --- /dev/null +++ b/scripts/config.log @@ -0,0 +1,765 @@ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by netgen configure 1.3, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ ./configure + +## --------- ## +## Platform. ## +## --------- ## + +hostname = stravinsky +uname -m = x86_64 +uname -r = 3.18.3-201.fc21.x86_64 +uname -s = Linux +uname -v = #1 SMP Mon Jan 19 15:59:31 UTC 2015 + +/usr/bin/uname -p = x86_64 +/bin/uname -X = unknown + +/bin/arch = x86_64 +/usr/bin/arch -k = unknown +/usr/convex/getsysinfo = unknown +/usr/bin/hostinfo = unknown +/bin/machine = unknown +/usr/bin/oslevel = unknown +/bin/universe = unknown + +PATH: . +PATH: /bin +PATH: /sbin +PATH: /usr/bin +PATH: /usr/sbin +PATH: /usr/local/bin + + +## ----------- ## +## Core tests. ## +## ----------- ## + +configure:2395: checking build system type +configure:2409: result: x86_64-unknown-linux-gnu +configure:2429: checking host system type +configure:2442: result: x86_64-unknown-linux-gnu +configure:2462: checking target system type +configure:2475: result: x86_64-unknown-linux-gnu +configure:2566: checking for gcc +configure:2582: found /bin/gcc +configure:2593: result: gcc +configure:2822: checking for C compiler version +configure:2831: gcc --version >&5 +gcc (GCC) 4.9.2 20141101 (Red Hat 4.9.2-1) +Copyright (C) 2014 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +configure:2842: $? = 0 +configure:2831: gcc -v >&5 +Using built-in specs. +COLLECT_GCC=gcc +COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.9.2/lto-wrapper +Target: x86_64-redhat-linux +Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.9.2-20141101/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.9.2-20141101/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux +Thread model: posix +gcc version 4.9.2 20141101 (Red Hat 4.9.2-1) (GCC) +configure:2842: $? = 0 +configure:2831: gcc -V >&5 +gcc: error: unrecognized command line option '-V' +gcc: fatal error: no input files +compilation terminated. +configure:2842: $? = 4 +configure:2831: gcc -qversion >&5 +gcc: error: unrecognized command line option '-qversion' +gcc: fatal error: no input files +compilation terminated. +configure:2842: $? = 4 +configure:2862: checking whether the C compiler works +configure:2884: gcc -g conftest.c >&5 +configure:2888: $? = 0 +configure:2936: result: yes +configure:2939: checking for C compiler default output file name +configure:2941: result: a.out +configure:2947: checking for suffix of executables +configure:2954: gcc -o conftest -g conftest.c >&5 +configure:2958: $? = 0 +configure:2980: result: +configure:3002: checking whether we are cross compiling +configure:3010: gcc -o conftest -g conftest.c >&5 +configure:3014: $? = 0 +configure:3021: ./conftest +configure:3025: $? = 0 +configure:3040: result: no +configure:3045: checking for suffix of object files +configure:3067: gcc -c -g conftest.c >&5 +configure:3071: $? = 0 +configure:3092: result: o +configure:3096: checking whether we are using the GNU C compiler +configure:3115: gcc -c -g conftest.c >&5 +configure:3115: $? = 0 +configure:3124: result: yes +configure:3133: checking whether gcc accepts -g +configure:3153: gcc -c -g conftest.c >&5 +configure:3153: $? = 0 +configure:3194: result: yes +configure:3211: checking for gcc option to accept ISO C89 +configure:3274: gcc -c -g conftest.c >&5 +configure:3274: $? = 0 +configure:3287: result: none needed +configure:3312: checking how to run the C preprocessor +configure:3343: gcc -E conftest.c +configure:3343: $? = 0 +configure:3357: gcc -E conftest.c +conftest.c:11:28: fatal error: ac_nonexistent.h: No such file or directory + #include + ^ +compilation terminated. +configure:3357: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "netgen" +| #define PACKAGE_TARNAME "netgen" +| #define PACKAGE_VERSION "1.3" +| #define PACKAGE_STRING "netgen 1.3" +| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com" +| #define PACKAGE_URL "" +| #define NETGEN_VERSION "1.5" +| #define NETGEN_REVISION "39" +| /* end confdefs.h. */ +| #include +configure:3382: result: gcc -E +configure:3402: gcc -E conftest.c +configure:3402: $? = 0 +configure:3416: gcc -E conftest.c +conftest.c:11:28: fatal error: ac_nonexistent.h: No such file or directory + #include + ^ +compilation terminated. +configure:3416: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "netgen" +| #define PACKAGE_TARNAME "netgen" +| #define PACKAGE_VERSION "1.3" +| #define PACKAGE_STRING "netgen 1.3" +| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com" +| #define PACKAGE_URL "" +| #define NETGEN_VERSION "1.5" +| #define NETGEN_REVISION "39" +| /* end confdefs.h. */ +| #include +configure:3445: checking for library containing strerror +configure:3476: gcc -o conftest -g conftest.c >&5 +configure:3476: $? = 0 +configure:3493: result: none required +configure:3515: checking for a BSD-compatible install +configure:3583: result: /bin/install -c +configure:3637: checking for ranlib +configure:3653: found /bin/ranlib +configure:3664: result: ranlib +configure:3691: checking for gm4 +configure:3724: result: no +configure:3691: checking for gnum4 +configure:3724: result: no +configure:3691: checking for m4 +configure:3709: found /bin/m4 +configure:3721: result: /bin/m4 +configure:3762: checking for ld used by GCC +configure:3825: result: /bin/ld +configure:3832: checking if the linker (/bin/ld) is GNU ld +GNU ld version 2.24 +configure:3844: result: yes +configure:3851: checking for grep that handles long lines and -e +configure:3909: result: /bin/grep +configure:3914: checking for egrep +configure:3976: result: /bin/grep -E +configure:3981: checking for ANSI C header files +configure:4001: gcc -c -g conftest.c >&5 +configure:4001: $? = 0 +configure:4074: gcc -o conftest -g conftest.c >&5 +configure:4074: $? = 0 +configure:4074: ./conftest +configure:4074: $? = 0 +configure:4085: result: yes +configure:4098: checking for sys/types.h +configure:4098: gcc -c -g conftest.c >&5 +configure:4098: $? = 0 +configure:4098: result: yes +configure:4098: checking for sys/stat.h +configure:4098: gcc -c -g conftest.c >&5 +configure:4098: $? = 0 +configure:4098: result: yes +configure:4098: checking for stdlib.h +configure:4098: gcc -c -g conftest.c >&5 +configure:4098: $? = 0 +configure:4098: result: yes +configure:4098: checking for string.h +configure:4098: gcc -c -g conftest.c >&5 +configure:4098: $? = 0 +configure:4098: result: yes +configure:4098: checking for memory.h +configure:4098: gcc -c -g conftest.c >&5 +configure:4098: $? = 0 +configure:4098: result: yes +configure:4098: checking for strings.h +configure:4098: gcc -c -g conftest.c >&5 +configure:4098: $? = 0 +configure:4098: result: yes +configure:4098: checking for inttypes.h +configure:4098: gcc -c -g conftest.c >&5 +configure:4098: $? = 0 +configure:4098: result: yes +configure:4098: checking for stdint.h +configure:4098: gcc -c -g conftest.c >&5 +configure:4098: $? = 0 +configure:4098: result: yes +configure:4098: checking for unistd.h +configure:4098: gcc -c -g conftest.c >&5 +configure:4098: $? = 0 +configure:4098: result: yes +configure:4114: checking size of void * +configure:4119: gcc -o conftest -g conftest.c >&5 +configure:4119: $? = 0 +configure:4119: ./conftest +configure:4119: $? = 0 +configure:4133: result: 8 +configure:4147: checking size of unsigned int +configure:4152: gcc -o conftest -g conftest.c >&5 +configure:4152: $? = 0 +configure:4152: ./conftest +configure:4152: $? = 0 +configure:4166: result: 4 +configure:4180: checking size of unsigned long +configure:4185: gcc -o conftest -g conftest.c >&5 +configure:4185: $? = 0 +configure:4185: ./conftest +configure:4185: $? = 0 +configure:4199: result: 8 +configure:4213: checking size of unsigned long long +configure:4218: gcc -o conftest -g conftest.c >&5 +configure:4218: $? = 0 +configure:4218: ./conftest +configure:4218: $? = 0 +configure:4232: result: 8 +configure:4243: checking whether byte ordering is bigendian +configure:4258: gcc -c -g conftest.c >&5 +conftest.c:26:9: error: unknown type name 'not' + not a universal capable compiler + ^ +conftest.c:26:15: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'universal' + not a universal capable compiler + ^ +conftest.c:26:15: error: unknown type name 'universal' +configure:4258: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "netgen" +| #define PACKAGE_TARNAME "netgen" +| #define PACKAGE_VERSION "1.3" +| #define PACKAGE_STRING "netgen 1.3" +| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com" +| #define PACKAGE_URL "" +| #define NETGEN_VERSION "1.5" +| #define NETGEN_REVISION "39" +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define SIZEOF_VOID_P 8 +| #define SIZEOF_UNSIGNED_INT 4 +| #define SIZEOF_UNSIGNED_LONG 8 +| #define SIZEOF_UNSIGNED_LONG_LONG 8 +| /* end confdefs.h. */ +| #ifndef __APPLE_CC__ +| not a universal capable compiler +| #endif +| typedef int dummy; +| +configure:4303: gcc -c -g conftest.c >&5 +configure:4303: $? = 0 +configure:4321: gcc -c -g conftest.c >&5 +conftest.c: In function 'main': +conftest.c:32:4: error: unknown type name 'not' + not big endian + ^ +conftest.c:32:12: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'endian' + not big endian + ^ +configure:4321: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "netgen" +| #define PACKAGE_TARNAME "netgen" +| #define PACKAGE_VERSION "1.3" +| #define PACKAGE_STRING "netgen 1.3" +| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com" +| #define PACKAGE_URL "" +| #define NETGEN_VERSION "1.5" +| #define NETGEN_REVISION "39" +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define SIZEOF_VOID_P 8 +| #define SIZEOF_UNSIGNED_INT 4 +| #define SIZEOF_UNSIGNED_LONG 8 +| #define SIZEOF_UNSIGNED_LONG_LONG 8 +| /* end confdefs.h. */ +| #include +| #include +| +| int +| main () +| { +| #if BYTE_ORDER != BIG_ENDIAN +| not big endian +| #endif +| +| ; +| return 0; +| } +configure:4449: result: no +configure:4468: checking for ANSI C header files +configure:4572: result: yes +configure:4584: checking for setenv +configure:4584: gcc -o conftest -g conftest.c >&5 +configure:4584: $? = 0 +configure:4584: result: yes +configure:4584: checking for putenv +configure:4584: gcc -o conftest -g conftest.c >&5 +configure:4584: $? = 0 +configure:4584: result: yes +configure:4594: checking for vfork +configure:4594: gcc -o conftest -g conftest.c >&5 +configure:4594: $? = 0 +configure:4594: result: yes +configure:4602: checking dirent.h usability +configure:4602: gcc -c -g conftest.c >&5 +configure:4602: $? = 0 +configure:4602: result: yes +configure:4602: checking dirent.h presence +configure:4602: gcc -E -x c conftest.c +configure:4602: $? = 0 +configure:4602: result: yes +configure:4602: checking for dirent.h +configure:4602: result: yes +configure:4615: checking limits.h usability +configure:4615: gcc -c -g conftest.c >&5 +configure:4615: $? = 0 +configure:4615: result: yes +configure:4615: checking limits.h presence +configure:4615: gcc -E -x c conftest.c +configure:4615: $? = 0 +configure:4615: result: yes +configure:4615: checking for limits.h +configure:4615: result: yes +configure:4628: checking param.h usability +configure:4628: gcc -c -g conftest.c >&5 +conftest.c:63:19: fatal error: param.h: No such file or directory + #include + ^ +compilation terminated. +configure:4628: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "netgen" +| #define PACKAGE_TARNAME "netgen" +| #define PACKAGE_VERSION "1.3" +| #define PACKAGE_STRING "netgen 1.3" +| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com" +| #define PACKAGE_URL "" +| #define NETGEN_VERSION "1.5" +| #define NETGEN_REVISION "39" +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define SIZEOF_VOID_P 8 +| #define SIZEOF_UNSIGNED_INT 4 +| #define SIZEOF_UNSIGNED_LONG 8 +| #define SIZEOF_UNSIGNED_LONG_LONG 8 +| #define STDC_HEADERS 1 +| #define HAVE_SETENV 1 +| #define HAVE_PUTENV 1 +| #define HAVE_DIRENT_H 1 +| #define HAVE_LIMITS_H 1 +| /* end confdefs.h. */ +| #include +| #ifdef HAVE_SYS_TYPES_H +| # include +| #endif +| #ifdef HAVE_SYS_STAT_H +| # include +| #endif +| #ifdef STDC_HEADERS +| # include +| # include +| #else +| # ifdef HAVE_STDLIB_H +| # include +| # endif +| #endif +| #ifdef HAVE_STRING_H +| # if !defined STDC_HEADERS && defined HAVE_MEMORY_H +| # include +| # endif +| # include +| #endif +| #ifdef HAVE_STRINGS_H +| # include +| #endif +| #ifdef HAVE_INTTYPES_H +| # include +| #endif +| #ifdef HAVE_STDINT_H +| # include +| #endif +| #ifdef HAVE_UNISTD_H +| # include +| #endif +| #include +configure:4628: result: no +configure:4628: checking param.h presence +configure:4628: gcc -E -x c conftest.c +conftest.c:30:19: fatal error: param.h: No such file or directory + #include + ^ +compilation terminated. +configure:4628: $? = 1 +configure: failed program was: +| /* confdefs.h */ +| #define PACKAGE_NAME "netgen" +| #define PACKAGE_TARNAME "netgen" +| #define PACKAGE_VERSION "1.3" +| #define PACKAGE_STRING "netgen 1.3" +| #define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com" +| #define PACKAGE_URL "" +| #define NETGEN_VERSION "1.5" +| #define NETGEN_REVISION "39" +| #define STDC_HEADERS 1 +| #define HAVE_SYS_TYPES_H 1 +| #define HAVE_SYS_STAT_H 1 +| #define HAVE_STDLIB_H 1 +| #define HAVE_STRING_H 1 +| #define HAVE_MEMORY_H 1 +| #define HAVE_STRINGS_H 1 +| #define HAVE_INTTYPES_H 1 +| #define HAVE_STDINT_H 1 +| #define HAVE_UNISTD_H 1 +| #define SIZEOF_VOID_P 8 +| #define SIZEOF_UNSIGNED_INT 4 +| #define SIZEOF_UNSIGNED_LONG 8 +| #define SIZEOF_UNSIGNED_LONG_LONG 8 +| #define STDC_HEADERS 1 +| #define HAVE_SETENV 1 +| #define HAVE_PUTENV 1 +| #define HAVE_DIRENT_H 1 +| #define HAVE_LIMITS_H 1 +| /* end confdefs.h. */ +| #include +configure:4628: result: no +configure:4628: checking for param.h +configure:4628: result: no +configure:4639: checking for va_copy +configure:4657: gcc -o conftest -g conftest.c >&5 +configure:4657: $? = 0 +configure:4666: result: yes +configure:4674: checking for __va_copy +configure:4692: gcc -o conftest -g conftest.c >&5 +configure:4692: $? = 0 +configure:4701: result: yes +configure:4831: checking for tclConfig.sh +configure:4903: result: /usr/lib64/tclConfig.sh +configure:4919: checking for tkConfig.sh +configure:4992: result: /usr/lib64/tkConfig.sh +configure:5106: checking for wish executable +configure:5133: result: /usr/bin/wish +configure:5139: checking for tclsh executable +configure:5165: result: /usr/bin/tclsh +configure:5288: checking for X +configure:5427: gcc -o conftest -g conftest.c -lX11 >&5 +configure:5427: $? = 0 +configure:5477: result: libraries , headers +configure:5576: gcc -o conftest -g conftest.c -lX11 >&5 +configure:5576: $? = 0 +configure:5674: checking for gethostbyname +configure:5674: gcc -o conftest -g conftest.c >&5 +configure:5674: $? = 0 +configure:5674: result: yes +configure:5771: checking for connect +configure:5771: gcc -o conftest -g conftest.c >&5 +configure:5771: $? = 0 +configure:5771: result: yes +configure:5820: checking for remove +configure:5820: gcc -o conftest -g conftest.c >&5 +configure:5820: $? = 0 +configure:5820: result: yes +configure:5869: checking for shmat +configure:5869: gcc -o conftest -g conftest.c >&5 +configure:5869: $? = 0 +configure:5869: result: yes +configure:5927: checking for IceConnectionNumber in -lICE +configure:5952: gcc -o conftest -g conftest.c -lICE >&5 +configure:5952: $? = 0 +configure:5961: result: yes +configure:6677: creating ./config.status + +## ---------------------- ## +## Running config.status. ## +## ---------------------- ## + +This file was extended by netgen config.status 1.3, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = + CONFIG_HEADERS = + CONFIG_LINKS = + CONFIG_COMMANDS = + $ ./config.status + +on stravinsky + +config.status:781: creating defs.mak +config.status:884: WARNING: 'defs.mak.in' seems to ignore the --datarootdir setting + +## ---------------- ## +## Cache variables. ## +## ---------------- ## + +ac_cv_build=x86_64-unknown-linux-gnu +ac_cv_c___va_copy=yes +ac_cv_c_bigendian=no +ac_cv_c_compiler_gnu=yes +ac_cv_c_va_copy=yes +ac_cv_env_CC_set= +ac_cv_env_CC_value= +ac_cv_env_CFLAGS_set=set +ac_cv_env_CFLAGS_value=-g +ac_cv_env_CPPFLAGS_set= +ac_cv_env_CPPFLAGS_value= +ac_cv_env_CPP_set= +ac_cv_env_CPP_value= +ac_cv_env_LDFLAGS_set= +ac_cv_env_LDFLAGS_value= +ac_cv_env_LIBS_set= +ac_cv_env_LIBS_value= +ac_cv_env_XMKMF_set= +ac_cv_env_XMKMF_value= +ac_cv_env_build_alias_set= +ac_cv_env_build_alias_value= +ac_cv_env_host_alias_set= +ac_cv_env_host_alias_value= +ac_cv_env_target_alias_set= +ac_cv_env_target_alias_value= +ac_cv_func_connect=yes +ac_cv_func_gethostbyname=yes +ac_cv_func_putenv=yes +ac_cv_func_remove=yes +ac_cv_func_setenv=yes +ac_cv_func_shmat=yes +ac_cv_func_vfork=yes +ac_cv_have_x='have_x=yes ac_x_includes='\'''\'' ac_x_libraries='\'''\''' +ac_cv_header_dirent_h=yes +ac_cv_header_inttypes_h=yes +ac_cv_header_limits_h=yes +ac_cv_header_memory_h=yes +ac_cv_header_param_h=no +ac_cv_header_stdc=yes +ac_cv_header_stdint_h=yes +ac_cv_header_stdlib_h=yes +ac_cv_header_string_h=yes +ac_cv_header_strings_h=yes +ac_cv_header_sys_stat_h=yes +ac_cv_header_sys_types_h=yes +ac_cv_header_unistd_h=yes +ac_cv_host=x86_64-unknown-linux-gnu +ac_cv_lib_ICE_IceConnectionNumber=yes +ac_cv_objext=o +ac_cv_path_EGREP='/bin/grep -E' +ac_cv_path_GREP=/bin/grep +ac_cv_path_LD=/bin/ld +ac_cv_path_M4=/bin/m4 +ac_cv_path_install='/bin/install -c' +ac_cv_prog_CPP='gcc -E' +ac_cv_prog_ac_ct_CC=gcc +ac_cv_prog_ac_ct_RANLIB=ranlib +ac_cv_prog_cc_c89= +ac_cv_prog_cc_g=yes +ac_cv_prog_gnu_ld=yes +ac_cv_search_strerror='none required' +ac_cv_sizeof_unsigned_int=4 +ac_cv_sizeof_unsigned_long=8 +ac_cv_sizeof_unsigned_long_long=8 +ac_cv_sizeof_void_p=8 +ac_cv_target=x86_64-unknown-linux-gnu + +## ----------------- ## +## Output variables. ## +## ----------------- ## + +ALL_TARGET='tcl' +CC='gcc' +CFLAGS='-g -m64 -fPIC' +CPP='gcc -E -x c' +CPPFLAGS='' +DEFS='-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' +DEPEND_FLAG='-MM' +ECHO_C='' +ECHO_N='printf' +ECHO_T='' +EGREP='/bin/grep -E' +EXEEXT='' +EXTRA_LIB_SPECS='-ldl' +GREP='/bin/grep' +INC_SPECS='' +INSTALL_DATA='${INSTALL} -m 644' +INSTALL_PROGRAM='${INSTALL}' +INSTALL_SCRIPT='${INSTALL}' +INSTALL_TARGET='install-tcl' +LD='/bin/ld' +LDDL_FLAGS=' -shared -Wl,-soname,$@ -Wl,--version-script=${NETGENDIR}/netgen/symbol.map' +LDFLAGS='' +LD_RUN_PATH='' +LIBOBJS='' +LIBS='' +LIB_SPECS=' -L/usr/lib64 -ltk8.6 -L/usr/lib64 -ltcl8.6' +LTLIBOBJS='' +M4='/bin/m4' +OBJEXT='o' +PACKAGE='netgen' +PACKAGE_BUGREPORT='eda-dev@opencircuitdesign.com' +PACKAGE_NAME='netgen' +PACKAGE_STRING='netgen 1.3' +PACKAGE_TARNAME='netgen' +PACKAGE_URL='' +PACKAGE_VERSION='1.3' +PATH_SEPARATOR=':' +RANLIB='ranlib' +SCRIPTS='' +SHDLIB_EXT='.so' +SHELL='/bin/sh' +SHLIB_CFLAGS='-fPIC' +SHLIB_LD='' +SHLIB_LIB_SPECS='' +TCLSH_EXE='/usr/bin/tclsh' +TCL_LIB_DIR='/usr/lib' +VERSION='' +WISH_EXE='/usr/bin/wish' +XMKMF='' +X_CFLAGS='' +X_EXTRA_LIBS='' +X_LIBS='' +X_PRE_LIBS=' -lSM -lICE' +ac_ct_CC='gcc' +bindir='${exec_prefix}/bin' +build='x86_64-unknown-linux-gnu' +build_alias='' +build_cpu='x86_64' +build_os='linux-gnu' +build_vendor='unknown' +cadinstall=' tcltk' +datadir='${datarootdir}' +datarootdir='${prefix}/share' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +dvidir='${docdir}' +exec_prefix='${prefix}' +extra_defs=' -DCAD_DIR=\"${LIBDIR}\" -DTCL_DIR=\"${TCLDIR}\"' +extra_libs=' ${NETGENDIR}/tcltk/libtcltk.o' +gr_cflags='' +gr_dflags=' -DX11 -DXLIB' +gr_libs=' -lX11' +gr_srcs=' ${TK_SRCS}' +host='x86_64-unknown-linux-gnu' +host_alias='' +host_cpu='x86_64' +host_os='linux-gnu' +host_vendor='unknown' +htmldir='${docdir}' +includedir='${prefix}/include' +infodir='${datarootdir}/info' +ld_extra_libs='' +ld_extra_objs='' +libdir='${exec_prefix}/lib' +libexecdir='${exec_prefix}/libexec' +localedir='${datarootdir}/locale' +localstatedir='${prefix}/var' +mandir='${datarootdir}/man' +modules=' tcltk' +oldincludedir='/usr/include' +pdfdir='${docdir}' +prefix='/usr/local' +program_transform_name='s,x,x,' +programs=' tcltk' +psdir='${docdir}' +sbindir='${exec_prefix}/sbin' +sharedstatedir='${prefix}/com' +sub_extra_libs='' +sysconfdir='${prefix}/etc' +target='x86_64-unknown-linux-gnu' +target_alias='' +target_cpu='x86_64' +target_os='linux-gnu' +target_vendor='unknown' +top_extra_libs='' +unused='' + +## ----------- ## +## confdefs.h. ## +## ----------- ## + +/* confdefs.h */ +#define PACKAGE_NAME "netgen" +#define PACKAGE_TARNAME "netgen" +#define PACKAGE_VERSION "1.3" +#define PACKAGE_STRING "netgen 1.3" +#define PACKAGE_BUGREPORT "eda-dev@opencircuitdesign.com" +#define PACKAGE_URL "" +#define NETGEN_VERSION "1.5" +#define NETGEN_REVISION "39" +#define STDC_HEADERS 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STRING_H 1 +#define HAVE_MEMORY_H 1 +#define HAVE_STRINGS_H 1 +#define HAVE_INTTYPES_H 1 +#define HAVE_STDINT_H 1 +#define HAVE_UNISTD_H 1 +#define SIZEOF_VOID_P 8 +#define SIZEOF_UNSIGNED_INT 4 +#define SIZEOF_UNSIGNED_LONG 8 +#define SIZEOF_UNSIGNED_LONG_LONG 8 +#define STDC_HEADERS 1 +#define HAVE_SETENV 1 +#define HAVE_PUTENV 1 +#define HAVE_DIRENT_H 1 +#define HAVE_LIMITS_H 1 +#define HAVE_VA_COPY 1 +#define HAVE___VA_COPY 1 +#define DBUG_OFF 1 +#define TCL_NETGEN 1 +#define linux 1 +#define SYSV 1 +#define ISC 1 + +configure: exit 0 diff --git a/scripts/config.status b/scripts/config.status new file mode 100755 index 0000000..461ea37 --- /dev/null +++ b/scripts/config.status @@ -0,0 +1,938 @@ +#! /bin/sh +# Generated by configure. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by netgen $as_me 1.3, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +# Files that config.status was made for. +config_files=" defs.mak" + +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to ." + +ac_cs_config="'CFLAGS=-g'" +ac_cs_version="\ +netgen config.status 1.3 +configured by ./configure, generated by GNU Autoconf 2.69, + with options \"$ac_cs_config\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='/home/tim/gitsrc/netgen-1.5/scripts' +srcdir='..' +INSTALL='/bin/install -c' +test -n "$AWK" || AWK=awk +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +if $ac_cs_recheck; then + set X /bin/sh './configure' 'CFLAGS=-g' $ac_configure_extra_args --no-create --no-recursion + shift + $as_echo "running CONFIG_SHELL=/bin/sh $*" >&6 + CONFIG_SHELL='/bin/sh' + export CONFIG_SHELL + exec "$@" +fi + +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "defs.mak") CONFIG_FILES="$CONFIG_FILES defs.mak" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +cat >>"$ac_tmp/subs1.awk" <<\_ACAWK && +S["LTLIBOBJS"]="" +S["LIBOBJS"]="" +S["INSTALL_TARGET"]="install-tcl" +S["ALL_TARGET"]="tcl" +S["LD_RUN_PATH"]="" +S["SHLIB_CFLAGS"]="-fPIC" +S["DEPEND_FLAG"]="-MM" +S["gr_srcs"]=" ${TK_SRCS}" +S["gr_libs"]=" -lX11" +S["gr_dflags"]=" -DX11 -DXLIB" +S["gr_cflags"]="" +S["cadinstall"]=" tcltk" +S["programs"]=" tcltk" +S["unused"]="" +S["modules"]=" tcltk" +S["sub_extra_libs"]="" +S["top_extra_libs"]="" +S["ld_extra_objs"]="" +S["ld_extra_libs"]="" +S["extra_defs"]=" -DCAD_DIR=\\\"${LIBDIR}\\\" -DTCL_DIR=\\\"${TCLDIR}\\\"" +S["extra_libs"]=" ${NETGENDIR}/tcltk/libtcltk.o" +S["SCRIPTS"]="" +S["PACKAGE"]="netgen" +S["VERSION"]="" +S["TCL_LIB_DIR"]="/usr/lib" +S["TCLSH_EXE"]="/usr/bin/tclsh" +S["WISH_EXE"]="/usr/bin/wish" +S["LIB_SPECS"]=" -L/usr/lib64 -ltk8.6 -L/usr/lib64 -ltcl8.6" +S["INC_SPECS"]="" +S["EXTRA_LIB_SPECS"]="-ldl" +S["SHLIB_LIB_SPECS"]="" +S["LDDL_FLAGS"]=" -shared -Wl,-soname,$@ -Wl,--version-script=${NETGENDIR}/netgen/symbol.map" +S["LD"]="/bin/ld" +S["SHLIB_LD"]="" +S["SHDLIB_EXT"]=".so" +S["X_EXTRA_LIBS"]="" +S["X_LIBS"]="" +S["X_PRE_LIBS"]=" -lSM -lICE" +S["X_CFLAGS"]="" +S["XMKMF"]="" +S["EGREP"]="/bin/grep -E" +S["GREP"]="/bin/grep" +S["M4"]="/bin/m4" +S["RANLIB"]="ranlib" +S["INSTALL_DATA"]="${INSTALL} -m 644" +S["INSTALL_SCRIPT"]="${INSTALL}" +S["INSTALL_PROGRAM"]="${INSTALL}" +S["CPP"]="gcc -E -x c" +S["OBJEXT"]="o" +S["EXEEXT"]="" +S["ac_ct_CC"]="gcc" +S["CPPFLAGS"]="" +S["LDFLAGS"]="" +S["CFLAGS"]="-g -m64 -fPIC" +S["CC"]="gcc" +S["target_os"]="linux-gnu" +S["target_vendor"]="unknown" +S["target_cpu"]="x86_64" +S["target"]="x86_64-unknown-linux-gnu" +S["host_os"]="linux-gnu" +S["host_vendor"]="unknown" +S["host_cpu"]="x86_64" +S["host"]="x86_64-unknown-linux-gnu" +S["build_os"]="linux-gnu" +S["build_vendor"]="unknown" +S["build_cpu"]="x86_64" +S["build"]="x86_64-unknown-linux-gnu" +S["target_alias"]="" +S["host_alias"]="" +S["build_alias"]="" +S["LIBS"]="" +S["ECHO_T"]="" +S["ECHO_N"]="-n" +S["ECHO_C"]="" +S["DEFS"]="-DPACKAGE_NAME=\\\"netgen\\\" -DPACKAGE_TARNAME=\\\"netgen\\\" -DPACKAGE_VERSION=\\\"1.3\\\" -DPACKAGE_STRING=\\\"netgen\\ 1.3\\\" -DPACKAGE_BUGREPORT=\\\"eda-dev@open"\ +"circuitdesign.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 -D"\ +"SIZEOF_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 -DHA"\ +"VE_LIMITS_H=1 -DHAVE_VA_COPY=1 -DHAVE___VA_COPY=1 -DDBUG_OFF=1 -DTCL_NETGEN=1 -Dlinux=1 -DSYSV=1 -DISC=1" +S["mandir"]="${datarootdir}/man" +S["localedir"]="${datarootdir}/locale" +S["libdir"]="${exec_prefix}/lib" +S["psdir"]="${docdir}" +S["pdfdir"]="${docdir}" +S["dvidir"]="${docdir}" +S["htmldir"]="${docdir}" +S["infodir"]="${datarootdir}/info" +S["docdir"]="${datarootdir}/doc/${PACKAGE_TARNAME}" +S["oldincludedir"]="/usr/include" +S["includedir"]="${prefix}/include" +S["localstatedir"]="${prefix}/var" +S["sharedstatedir"]="${prefix}/com" +S["sysconfdir"]="${prefix}/etc" +S["datadir"]="${datarootdir}" +S["datarootdir"]="${prefix}/share" +S["libexecdir"]="${exec_prefix}/libexec" +S["sbindir"]="${exec_prefix}/sbin" +S["bindir"]="${exec_prefix}/bin" +S["program_transform_name"]="s,x,x," +S["prefix"]="/usr/local" +S["exec_prefix"]="${prefix}" +S["PACKAGE_URL"]="" +S["PACKAGE_BUGREPORT"]="eda-dev@opencircuitdesign.com" +S["PACKAGE_STRING"]="netgen 1.3" +S["PACKAGE_VERSION"]="1.3" +S["PACKAGE_TARNAME"]="netgen" +S["PACKAGE_NAME"]="netgen" +S["PATH_SEPARATOR"]=":" +S["SHELL"]="/bin/sh" +_ACAWK +cat >>"$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + ac_datarootdir_hack=' + s&@datadir@&${datarootdir}&g + s&@docdir@&${datarootdir}/doc/${PACKAGE_TARNAME}&g + s&@infodir@&${datarootdir}/info&g + s&@localedir@&${datarootdir}/locale&g + s&@mandir@&${datarootdir}/man&g + s&\${datarootdir}&${prefix}/share&g' ;; +esac +ac_sed_extra=" + +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + + + + esac + +done # for ac_tag + + +as_fn_exit 0 diff --git a/scripts/config.sub b/scripts/config.sub new file mode 100755 index 0000000..12ebc78 --- /dev/null +++ b/scripts/config.sub @@ -0,0 +1,1410 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. + +timestamp='2001-08-13' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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 2 of the License, 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit 0;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | storm-chaos* | os2-emx* | windows32-*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | c4x | clipper \ + | d10v | d30v | dsp16xx \ + | fr30 \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | m32r | m68000 | m68k | m88k | mcore \ + | mips16 | mips64 | mips64el | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el | mips64vr4300 \ + | mips64vr4300el | mips64vr5000 | mips64vr5000el \ + | mipsbe | mipsel | mipsle | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | ns16k | ns32k \ + | openrisc \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | s390 | s390x \ + | sh | sh[34] | sh[34]eb | shbe | shle \ + | sparc | sparc64 | sparclet | sparclite | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic80 | tron \ + | v850 \ + | we32k \ + | x86 | xscale \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alphapca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armv*-* \ + | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c54x-* \ + | clipper-* | cray2-* | cydra-* \ + | d10v-* | d30v-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | m32r-* \ + | m68000-* | m680[01234]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | mcore-* \ + | mips-* | mips16-* | mips64-* | mips64el-* | mips64orion-* \ + | mips64orionel-* | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* | mipsbe-* | mipsel-* \ + | mipsle-* | mipstx39-* | mipstx39el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | s390-* | s390x-* \ + | sh-* | sh[34]-* | sh[34]eb-* | shbe-* | shle-* \ + | sparc-* | sparc64-* | sparc86x-* | sparclite-* \ + | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* \ + | t3e-* | tahoe-* | thumb-* | tic30-* | tic54x-* | tic80-* | tron-* \ + | v850-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xmp-* | xps100-* | xscale-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [cjt]90) + basic_machine=${basic_machine}-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon) + basic_machine=i686-pc + ;; + pentiumii | pentium2) + basic_machine=i686-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sparclite-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=t3e-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + windows32) + basic_machine=i386-pc + os=-windows32-msvcrt + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4 | sh3eb | sh4eb) + basic_machine=sh-unknown + ;; + sparc | sparcv9 | sparcv9b) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + c4x*) + basic_machine=c4x-none + os=-coff + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto*) + os=-nto-qnx + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/scripts/configure b/scripts/configure new file mode 100755 index 0000000..64fb4e1 --- /dev/null +++ b/scripts/configure @@ -0,0 +1,7724 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for netgen 1.3. +# +# Report bugs to . +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and +$0: eda-dev@opencircuitdesign.com about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='netgen' +PACKAGE_TARNAME='netgen' +PACKAGE_VERSION='1.3' +PACKAGE_STRING='netgen 1.3' +PACKAGE_BUGREPORT='eda-dev@opencircuitdesign.com' +PACKAGE_URL='' + +ac_unique_file="rules.mak" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='LTLIBOBJS +LIBOBJS +INSTALL_TARGET +ALL_TARGET +LD_RUN_PATH +SHLIB_CFLAGS +DEPEND_FLAG +gr_srcs +gr_libs +gr_dflags +gr_cflags +cadinstall +programs +unused +modules +sub_extra_libs +top_extra_libs +ld_extra_objs +ld_extra_libs +extra_defs +extra_libs +SCRIPTS +PACKAGE +VERSION +TCL_LIB_DIR +TCLSH_EXE +WISH_EXE +LIB_SPECS +INC_SPECS +EXTRA_LIB_SPECS +SHLIB_LIB_SPECS +LDDL_FLAGS +LD +SHLIB_LD +SHDLIB_EXT +X_EXTRA_LIBS +X_LIBS +X_PRE_LIBS +X_CFLAGS +XMKMF +EGREP +GREP +M4 +RANLIB +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +CPP +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +with_gnu_ld +with_interpreter +with_tcl +with_tk +with_tclincls +with_tkincls +with_tcllibs +with_tklibs +with_widgets +with_x +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP +XMKMF' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures netgen 1.3 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/netgen] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +X features: + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of netgen 1.3:";; + esac + cat <<\_ACEOF + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-interpreter=arg enable interpreter + --with-tcl=DIR Find tclConfig.sh in DIR + --with-tk=DIR Find tkConfig.sh in DIR + --with-tclincls=DIR Find tcl.h in DIR + --with-tkincls=DIR Find tk.h in DIR + --with-tcllibs=DIR Find Tcl library in DIR + --with-tklibs=DIR Find Tk library in DIR + --with-widgets=arg select widget set + --with-x use the X Window System + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + XMKMF Path to xmkmf, Makefile generator for X Window System + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +netgen configure 1.3 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES +# -------------------------------------------- +# Tries to find the compile-time value of EXPR in a program that includes +# INCLUDES, setting VAR accordingly. Returns whether the value could be +# computed +ac_fn_c_compute_int () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=0 ac_mid=0 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid; break +else + as_fn_arith $ac_mid + 1 && ac_lo=$as_val + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) < 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=-1 ac_mid=-1 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=$ac_mid; break +else + as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + ac_lo= ac_hi= +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid +else + as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in #(( +?*) eval "$3=\$ac_lo"; ac_retval=0 ;; +'') ac_retval=1 ;; +esac + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +static long int longval () { return $2; } +static unsigned long int ulongval () { return $2; } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (($2) < 0) + { + long int i = longval (); + if (i != ($2)) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ($2)) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + echo >>conftest.val; read $3 &5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} +( $as_echo "## -------------------------------------------- ## +## Report this to eda-dev@opencircuitdesign.com ## +## -------------------------------------------- ##" + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by netgen $as_me 1.3, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + +ac_aux_dir= +for ac_dir in . "$srcdir"/.; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in . \"$srcdir\"/." "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +$as_echo_n "checking target system type... " >&6; } +if ${ac_cv_target+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +$as_echo "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + +PACKAGE=netgen +NETGEN_VERSION=`cat ../VERSION | cut -d. -f1-2` +NETGEN_REVISION=`cat ../VERSION | cut -d. -f3` +cat >>confdefs.h <<_ACEOF +#define NETGEN_VERSION "${NETGEN_VERSION}" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define NETGEN_REVISION "${NETGEN_REVISION}" +_ACEOF + + +ALL_TARGET="standard" +INSTALL_TARGET="install-netgen" + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing strerror" >&5 +$as_echo_n "checking for library containing strerror... " >&6; } +if ${ac_cv_search_strerror+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char strerror (); +int +main () +{ +return strerror (); + ; + return 0; +} +_ACEOF +for ac_lib in '' cposix; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_strerror=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_strerror+:} false; then : + break +fi +done +if ${ac_cv_search_strerror+:} false; then : + +else + ac_cv_search_strerror=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_strerror" >&5 +$as_echo "$ac_cv_search_strerror" >&6; } +ac_res=$ac_cv_search_strerror +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + +for ac_prog in gm4 gnum4 m4 +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_M4+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $M4 in + [\\/]* | ?:[\\/]*) + ac_cv_path_M4="$M4" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_M4="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +M4=$ac_cv_path_M4 +if test -n "$M4"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $M4" >&5 +$as_echo "$M4" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$M4" && break +done +test -n "$M4" || M4="no" + +if test x$M4 = xno; then + as_fn_error $? "M4 is required" "$LINENO" 5 +fi + + +if test "$CPP" = "$CC -E" ; then + CPP="$CPP -x c" +fi + + +#------------------------------------------------------------ +# AC_PROG_LD - find the path to the GNU or non-GNU linker +# (This stuff ripped from libtool) +#------------------------------------------------------------ + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by GCC" >&5 +$as_echo_n "checking for ld used by GCC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case "$ac_prog" in + # Accept absolute paths. + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${ac_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + ac_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + ac_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$ac_cv_path_LD" +if test -n "$LD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${ac_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + ac_cv_prog_gnu_ld=yes +else + ac_cv_prog_gnu_ld=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gnu_ld" >&5 +$as_echo "$ac_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$ac_cv_prog_gnu_ld + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 +$as_echo_n "checking size of void *... " >&6; } +if ${ac_cv_sizeof_void_p+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_void_p" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (void *) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_void_p=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 +$as_echo "$ac_cv_sizeof_void_p" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_VOID_P $ac_cv_sizeof_void_p +_ACEOF + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned int" >&5 +$as_echo_n "checking size of unsigned int... " >&6; } +if ${ac_cv_sizeof_unsigned_int+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned int))" "ac_cv_sizeof_unsigned_int" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_unsigned_int" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (unsigned int) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_unsigned_int=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_int" >&5 +$as_echo "$ac_cv_sizeof_unsigned_int" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_UNSIGNED_INT $ac_cv_sizeof_unsigned_int +_ACEOF + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned long" >&5 +$as_echo_n "checking size of unsigned long... " >&6; } +if ${ac_cv_sizeof_unsigned_long+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned long))" "ac_cv_sizeof_unsigned_long" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_unsigned_long" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (unsigned long) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_unsigned_long=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_long" >&5 +$as_echo "$ac_cv_sizeof_unsigned_long" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_UNSIGNED_LONG $ac_cv_sizeof_unsigned_long +_ACEOF + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned long long" >&5 +$as_echo_n "checking size of unsigned long long... " >&6; } +if ${ac_cv_sizeof_unsigned_long_long+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned long long))" "ac_cv_sizeof_unsigned_long_long" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_unsigned_long_long" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (unsigned long long) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_unsigned_long_long=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_long_long" >&5 +$as_echo "$ac_cv_sizeof_unsigned_long_long" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_UNSIGNED_LONG_LONG $ac_cv_sizeof_unsigned_long_long +_ACEOF + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 +$as_echo_n "checking whether byte ordering is bigendian... " >&6; } +if ${ac_cv_c_bigendian+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_bigendian=unknown + # See if we're dealing with a universal compiler. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __APPLE_CC__ + not a universal capable compiler + #endif + typedef int dummy; + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # Check for potential -arch flags. It is not universal unless + # there are at least two -arch flags with different values. + ac_arch= + ac_prev= + for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do + if test -n "$ac_prev"; then + case $ac_word in + i?86 | x86_64 | ppc | ppc64) + if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then + ac_arch=$ac_word + else + ac_cv_c_bigendian=universal + break + fi + ;; + esac + ac_prev= + elif test "x$ac_word" = "x-arch"; then + ac_prev=arch + fi + done +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test $ac_cv_c_bigendian = unknown; then + # See if sys/param.h defines the BYTE_ORDER macro. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ + && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ + && LITTLE_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to _BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +#ifndef _BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # Compile a test program. + if test "$cross_compiling" = yes; then : + # Try to guess by grepping values from an object file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +short int ascii_mm[] = + { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; + short int ascii_ii[] = + { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; + int use_ascii (int i) { + return ascii_mm[i] + ascii_ii[i]; + } + short int ebcdic_ii[] = + { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; + short int ebcdic_mm[] = + { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; + int use_ebcdic (int i) { + return ebcdic_mm[i] + ebcdic_ii[i]; + } + extern int foo; + +int +main () +{ +return use_ascii (foo) == use_ebcdic (foo); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then + ac_cv_c_bigendian=yes + fi + if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi + fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long int l; + char c[sizeof (long int)]; + } u; + u.l = 1; + return u.c[sizeof (long int) - 1] == 1; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_c_bigendian=no +else + ac_cv_c_bigendian=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 +$as_echo "$ac_cv_c_bigendian" >&6; } + case $ac_cv_c_bigendian in #( + yes) + $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h +;; #( + no) + ;; #( + universal) + +$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h + + ;; #( + *) + as_fn_error $? "unknown endianness + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; + esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + + +for ac_func in setenv putenv +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +ac_fn_c_check_func "$LINENO" "vfork" "ac_cv_func_vfork" +if test "x$ac_cv_func_vfork" = xyes; then : + +fi + + +for ac_header in dirent.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "dirent.h" "ac_cv_header_dirent_h" "$ac_includes_default" +if test "x$ac_cv_header_dirent_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DIRENT_H 1 +_ACEOF + +fi + +done + + +for ac_header in limits.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default" +if test "x$ac_cv_header_limits_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIMITS_H 1 +_ACEOF + +fi + +done + + +for ac_header in param.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "param.h" "ac_cv_header_param_h" "$ac_includes_default" +if test "x$ac_cv_header_param_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_PARAM_H 1 +_ACEOF + +fi + +done + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for va_copy" >&5 +$as_echo_n "checking for va_copy... " >&6; } +if ${ac_cv_c_va_copy+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +va_list ap1, ap2; + va_copy(ap1,ap2); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_c_va_copy="yes" +else + ac_cv_c_va_copy="no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_va_copy" >&5 +$as_echo "$ac_cv_c_va_copy" >&6; } +if test "$ac_cv_c_va_copy" = "yes" +then + +$as_echo "#define HAVE_VA_COPY 1" >>confdefs.h + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __va_copy" >&5 +$as_echo_n "checking for __va_copy... " >&6; } +if ${ac_cv_c___va_copy+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +va_list ap1, ap2; + __va_copy(ap1,ap2); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_c___va_copy="yes" +else + ac_cv_c___va_copy="no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c___va_copy" >&5 +$as_echo "$ac_cv_c___va_copy" >&6; } +if test "$ac_cv_c___va_copy" = "yes" +then + +$as_echo "#define HAVE___VA_COPY 1" >>confdefs.h + +fi + +# Note that it is essential to disable the DBUG packages, as it is +# not ANSI-compliant and won't compile without quite a bit of work. +$as_echo "#define DBUG_OFF 1" >>confdefs.h + + +extra_defs="$extra_defs -DCAD_DIR=\\\"\${LIBDIR}\\\"" +X_LIBS= +X_CFLAGS= +CPPFLAGS= +INC_SPECS= +DEPEND_FLAG= +SHLIB_CFLAGS="" +LD_RUN_PATH="" +WISH_EXE="" +TCLSH_EXE="" +CXX= + +modules="" +unused="" +cadinstall="" +extra_libs="" +other_srcs="" +top_extra_libs="" +sub_extra_libs="" +ld_extra_libs="" +ld_extra_objs="" +programs="" +rl_defs= +rl_libs= +gr_cflags= +gr_dflags= +gr_libs= +gr_srcs= +gr_hsrcs= +gr_hprog= + +netgen_with_tcl="yes" +netgen_with_tk="yes" +netgen_with_tcl_includes="" +netgen_with_tk_includes="" +netgen_with_tcl_libraries="" +netgen_with_tk_libraries="" + + +usingTcl=1 +usingX11= + + + +# Check whether --with-interpreter was given. +if test "${with_interpreter+set}" = set; then : + withval=$with_interpreter; + if test "$withval" = "no" -o "$withval" = "NO"; then + usingTcl= + elif test "$withval" = "scheme" -o "$withval" = "SCHEME"; then + usingScheme=1 + usingTcl= + elif test "$withval" != "tcl" -a "$withval" != "TCL"; then + echo "Unknown option to --with-interpreter: Must be scheme, tcl, or no." + exit 1 + fi + +fi + + + +# Check whether --with-tcl was given. +if test "${with_tcl+set}" = set; then : + withval=$with_tcl; + netgen_with_tcl=$withval + if test "$withval" = "no" -o "$withval" = "NO"; then + usingTcl= + elif test $usingScheme ; then + echo Attempt to enable both Tcl and Scheme interpreters. + echo Disabling Tcl, and using Scheme instead. + usingTcl= + fi + +fi + + + + +# Check whether --with-tk was given. +if test "${with_tk+set}" = set; then : + withval=$with_tk; netgen_with_tk=$withval +fi + + +# Check whether --with-tclincls was given. +if test "${with_tclincls+set}" = set; then : + withval=$with_tclincls; netgen_with_tcl_includes=$withval +fi + + +# Check whether --with-tkincls was given. +if test "${with_tkincls+set}" = set; then : + withval=$with_tkincls; netgen_with_tk_includes=$withval +fi + + +# Check whether --with-tcllibs was given. +if test "${with_tcllibs+set}" = set; then : + withval=$with_tcllibs; netgen_with_tcl_libraries=$withval +fi + + +# Check whether --with-tklibs was given. +if test "${with_tklibs+set}" = set; then : + withval=$with_tklibs; netgen_with_tk_libraries=$withval +fi + + +# ----------------------------------------------------------------------- +# Find the Tcl build configuration file "tclConfig.sh" +# ----------------------------------------------------------------------- + +if test $usingTcl ; then + TCL_INC_DIR="." + TK_INC_DIR="." + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tclConfig.sh" >&5 +$as_echo_n "checking for tclConfig.sh... " >&6; } + tcl_config_sh="" + + if test "$netgen_with_tcl" = "no" ; then + netgen_with_tcl="" + elif test "$netgen_with_tcl" != "yes" ; then + # + # Verify that a tclConfig.sh file exists in the directory specified + # by --with-tcl. + # + for dir in \ + $netgen_with_tcl + do + if test -r "$dir/tclConfig.sh" ; then + tcl_config_sh="$dir/tclConfig.sh" + break + elif test -r "$dir/lib/tclConfig.sh" ; then + tcl_config_sh="$dir/lib/tclConfig.sh" + break + elif test -r "$dir/unix/tclConfig.sh" ; then + tcl_config_sh="$dir/unix/tclConfig.sh" + break + fi + done + else + # + # Otherwise, search for Tcl configuration file. + # + + # 1. Search previously named locations. + + for dir in \ + $prefix \ + $exec_prefix + do + if test -r "$dir/tclConfig.sh" ; then + tcl_config_sh="$dir/tclConfig.sh" + break + elif test -r "$dir/lib/tclConfig.sh" ; then + tcl_config_sh="$dir/lib/tclConfig.sh" + break + elif test -r "$dir/unix/tclConfig.sh" ; then + tcl_config_sh="$dir/unix/tclConfig.sh" + break + fi + done + + # 2. Search standard locations. + + if test "x$tcl_config_sh" = "x" ; then + for dir in \ + `ls -dr /usr/local/tcl/tcl[7-9].[0-9]* 2>/dev/null` \ + /usr/local/tcl \ + /usr/local/lib \ + /usr/lib64 \ + /usr/local \ + `ls -dr /usr/lib/tcl[7-9].[0-9]* 2>/dev/null` \ + /sw/lib \ + /usr + do + if test -r "$dir/tclConfig.sh" ; then + tcl_config_sh="$dir/tclConfig.sh" + break + elif test -r "$dir/lib/tclConfig.sh" ; then + tcl_config_sh="$dir/lib/tclConfig.sh" + break + fi + done + fi + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${tcl_config_sh}" >&5 +$as_echo "${tcl_config_sh}" >&6; } + + if test "x$tcl_config_sh" = "x" ; then + echo "Can't find Tcl configuration script \"tclConfig.sh\"" + echo "Reverting to non-Tcl compilation" + usingTcl= + fi +fi + +# ----------------------------------------------------------------------- +# Find the Tk build configuration file "tkConfig.sh" +# ----------------------------------------------------------------------- + +if test $usingTcl ; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tkConfig.sh" >&5 +$as_echo_n "checking for tkConfig.sh... " >&6; } + tk_config_sh="" + if test "$netgen_with_tk" != "yes"; then + # + # Verify that a tkConfig.sh file exists in the directory specified + # by --with-tcl or --with-tk. + # + for dir in \ + $netgen_with_tk \ + $netgen_with_tcl + do + if test -r "$dir/tkConfig.sh" ; then + tk_config_sh="$dir/tkConfig.sh" + break + elif test -r "$dir/lib/tkConfig.sh" ; then + tk_config_sh="$dir/lib/tkConfig.sh" + break + elif test -r "$dir/unix/tkConfig.sh" ; then + tk_config_sh="$dir/unix/tkConfig.sh" + break + fi + done + else + # + # Search for Tk configuration file. + # + + # + # 1. Search previously named locations. + # + for dir in \ + $prefix \ + $exec_prefix + do + if test -r "$dir/tkConfig.sh" ; then + tk_config_sh="$dir/tkConfig.sh" + break + elif test -r "$dir/lib/tkConfig.sh" ; then + tk_config_sh="$dir/lib/tkConfig.sh" + break + elif test -r "$dir/unix/tkConfig.sh" ; then + tk_config_sh="$dir/unix/tkConfig.sh" + break + fi + done + # + # 2. Search standard locations. + # + if test "x$tk_config_sh" = "x" ; then + for dir in \ + `ls -dr /usr/local/tcl/tcl[7-9].[0-9]* 2>/dev/null` \ + `ls -dr /usr/local/tk/tk[7-9].[0-9]* 2>/dev/null` \ + /usr/local/tcl \ + /usr/local/lib \ + /usr/lib64 \ + /usr/local \ + `ls -dr /usr/lib/tcl[7-9].[0-9]* 2>/dev/null` \ + `ls -dr /usr/lib/tk[7-9].[0-9]* 2>/dev/null` \ + /sw/lib \ + ${x_libraries} \ + /usr + do + if test -r "$dir/tkConfig.sh" ; then + tk_config_sh="$dir/tkConfig.sh" + break + elif test -r "$dir/lib/tkConfig.sh" ; then + tk_config_sh="$dir/lib/tkConfig.sh" + break + fi + done + fi + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${tk_config_sh}" >&5 +$as_echo "${tk_config_sh}" >&6; } + + if test "x$tk_config_sh" = "x" ; then + echo "can't find Tk configuration script \"tkConfig.sh\"" + echo "Reverting to non-Tcl compilation" + usingTcl= + fi +fi + +# ----------------------------------------------------------------------- +# Source in the Tcl/Tk configuration scripts. +# ----------------------------------------------------------------------- + +if test $usingTcl ; then + . $tcl_config_sh + . $tk_config_sh + + if test "$TCL_VERSION" = "7.6" -a "$TK_VERSION" = "4.2" ; then + : + elif test "$TCL_VERSION" = "7.5" -a "$TK_VERSION" = "4.1" ; then + : + elif test "$TCL_VERSION" = "$TK_VERSION" ; then + : + else + echo "Mismatched Tcl/Tk versions ($TCL_VERSION != $TK_VERSION)" + echo "Reverting to non-Tcl compile" + usingTcl= + fi +fi + +if test $usingTcl ; then + if test "x${netgen_with_tcl_includes}" != "x" ; then + if test -r "${netgen_with_tcl_includes}/tcl.h" ; then + TCL_INC_DIR=${netgen_with_tcl_includes} + else + echo "Can't find tcl.h in \"${netgen_with_tcl_includes}\"" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + else + for dir in \ + ${TCL_PREFIX}/include/tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION} \ + ${TCL_PREFIX}/include \ + ${TCL_SRC_DIR}/generic \ + ${TCL_INC_DIR} + do + if test -r "$dir/tcl.h" ; then + TCL_INC_DIR=$dir + break + fi + done + if test "x${TCL_INC_DIR}" = "x" ; then + echo "Can't find tcl.h header file" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + fi +fi + +if test $usingTcl ; then + if test "x${netgen_with_tk_includes}" != "x" ; then + if test -r "${netgen_with_tk_includes}/tk.h" ; then + TK_INC_DIR=${netgen_with_tk_includes} + else + echo "Can't find tk.h in \"${netgen_with_tk_includes}\"" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + else + for dir in \ + ${TK_PREFIX}/include/tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION} \ + ${TK_PREFIX}/include \ + ${TK_SRC_DIR}/generic \ + ${TK_INC_DIR} \ + ${TCL_INC_DIR} + do + if test -r "$dir/tk.h" ; then + TK_INC_DIR=$dir + break + fi + done + if test "x${TK_INC_DIR}" = "x" ; then + echo "Can't find tk.h header file" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + fi +fi + +if test $usingTcl ; then + case $target in + *-sunos4*|*-*-netbsd*|NetBSD-*|FreeBSD-*|OpenBSD-*) + TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}" + TK_LIB_NAME="tk${TK_MAJOR_VERSION}${TK_MINOR_VERSION}" + ;; + *) + TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}" + TK_LIB_NAME="tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}" + ;; + esac + + loclib=`echo ${TCL_LIB_SPEC} | sed -e 's/.*-L//' -e 's/ .*//'` + + if test "x${TCL_LIB_SPEC}" = "x" ; then + TCL_LIB_SPEC="-l${TCL_LIB_NAME}" + fi + if test "x${TK_LIB_SPEC}" = "x" ; then + TK_LIB_SPEC="-l${TK_LIB_NAME}" + fi + +# Find the version of "wish" that corresponds to TCL_EXEC_PREFIX +# We really ought to run "ldd" to confirm that the linked libraries match. + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wish executable" >&5 +$as_echo_n "checking for wish executable... " >&6; } + for dir in \ + ${TK_EXEC_PREFIX}/bin \ + ${TK_EXEC_PREFIX} + do + for wishexe in \ + wish \ + wish${TK_VERSION} \ + wish.exe \ + wish${TK_VERSION}.exe + do + if test -r "$dir/$wishexe" ; then + WISH_EXE=$dir/$wishexe + break + fi + done + if test "x${WISH_EXE}" != "x" ; then + break + fi + done + if test "x${WISH_EXE}" = "x" ; then + echo "Warning: Can't find executable for \"wish\". You may have to" + echo "manually set the value for WISH_EXE in the netgen startup script." + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${WISH_EXE}" >&5 +$as_echo "${WISH_EXE}" >&6; } + fi + +# Find the version of "tclsh" that corresponds to TCL_EXEC_PREFIX + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tclsh executable" >&5 +$as_echo_n "checking for tclsh executable... " >&6; } + for dir in \ + ${TK_EXEC_PREFIX}/bin \ + ${TK_EXEC_PREFIX} + do + for tclshexe in \ + tclsh \ + tclsh${TK_VERSION} \ + tclsh.exe \ + tclsh${TK_VERSION}.exe + do + if test -r "$dir/$tclshexe" ; then + TCLSH_EXE=$dir/$tclshexe + break + fi + done + if test "x${TCLSH_EXE}" != "x" ; then + break + fi + done + if test "x${TCLSH_EXE}" = "x" ; then + echo "Warning: Can't find executable for \"tclsh\"." + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${TCLSH_EXE}" >&5 +$as_echo "${TCLSH_EXE}" >&6; } + fi + +# Have to define SHDLIB_EXT here even though we have to do it below, too. + case $target in + *-hpux*) + SHDLIB_EXT=".sl" + SHDLIB_EXT_ALT=".sl" + ;; + *cygwin*) + SHDLIB_EXT=".dll" + SHDLIB_EXT_ALT=".dll.a" + ;; + *darwin*) + SHDLIB_EXT=".dylib" + SHDLIB_EXT_ALT=".dylib" + ;; + *) + SHDLIB_EXT=".so" + SHDLIB_EXT_ALT=".so" + ;; + esac + + if test "x${netgen_with_tcl_libraries}" != "x" ; then + for libname in \ + "${netgen_with_tcl_libraries}/lib${TCL_LIB_FILE}" \ + "${netgen_with_tcl_libraries}/lib${TCL_LIB_NAME}${SHDLIB_EXT}" \ + "${netgen_with_tcl_libraries}/lib${TCL_LIB_NAME}${SHDLIB_EXT_ALT}" + do + if test -r "$libname" ; then + TCL_LIB_DIR="${netgen_with_tcl_libraries}" + break + fi + done + + if test "x${TCL_LIB_DIR}" = "x" ; then + echo "Can't find tcl library in \"${netgen_with_tcl_libraries}\"" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + else + for libname in \ + "${loclib:=${TCL_EXEC_PREFIX}/lib}/lib${TCL_LIB_NAME}${SHDLIB_EXT}" \ + "${loclib:=${TCL_EXEC_PREFIX}/lib}/lib${TCL_LIB_NAME}${SHDLIB_EXT_ALT}" \ + "${loclib:=${TCL_EXEC_PREFIX}/lib64}/lib${TCL_LIB_NAME}${SHDLIB_EXT}" + do + if test -r "$libname" ; then + TCL_LIB_DIR="${TCL_EXEC_PREFIX}/lib" + break + fi + done + if test "x${TCL_LIB_DIR}" = "x" ; then + echo "Can't find tcl library" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + fi +fi + +if test $usingTcl ; then + if test "x${netgen_with_tk_libraries}" != "x" ; then + for libname in \ + "${netgen_with_tk_libraries}/${TCL_LIB_FILE}" \ + "${netgen_with_tk_libraries}/lib${TK_LIB_NAME}${SHDLIB_EXT}" \ + "${netgen_with_tk_libraries}/lib${TK_LIB_NAME}${SHDLIB_EXT_ALT}" + do + if test -r "$libname" ; then + TK_LIB_DIR="${netgen_with_tk_libraries}" + break + fi + done + if test "x${TK_LIB_DIR}" = "x" ; then + echo "Can't find tk library in \"${netgen_with_tk_libraries}\"" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + else + for libname in \ + "${loclib:=${TK_EXEC_PREFIX}/lib}/lib${TK_LIB_NAME}${SHDLIB_EXT}" \ + "${loclib:=${TK_EXEC_PREFIX}/lib}/lib${TK_LIB_NAME}${SHDLIB_EXT_ALT}" \ + "${loclib:=${TK_EXEC_PREFIX}/lib64}/lib${TK_LIB_NAME}${SHDLIB_EXT}" + do + if test -r "$libname" ; then + TK_LIB_DIR="${TK_EXEC_PREFIX}/lib" + break + fi + done + if test "x${TK_LIB_DIR}" = "x" ; then + echo "Can't find tk library" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + fi +fi + + + + +# Check whether --with-widgets was given. +if test "${with_widgets+set}" = set; then : + withval=$with_widgets; + if test "$withval" = "xw" -o "$withval" = "Xw"; then + usingX11=1 + usingTcl= + gr_dflags="${gr_dflags} -DHAVE_X11 -DX11_HP_WIDGETS" + gr_libs="${gr_libs} -lXw -lXt" + elif test "$withval" = "Xm" -o "$withval" = "Motif"; then + usingX11=1 + usingTcl= + gr_dflags="${gr_dflags} -DHAVE_X11 -DX11_MOTIF_WIDGETS" + gr_libs="${gr_libs} -lXm -lXt" + else + usingX11=1 + usingTcl= + gr_dflags="${gr_dflags} -DHAVE_X11 -DX11_ATHENA_WIDGETS" + gr_libs="${gr_libs} -lXaw -lXmu -lXt -lXext" + fi + +fi + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 +$as_echo_n "checking for X... " >&6; } + + +# Check whether --with-x was given. +if test "${with_x+set}" = set; then : + withval=$with_x; +fi + +# $have_x is `yes', `no', `disabled', or empty when we do not yet know. +if test "x$with_x" = xno; then + # The user explicitly disabled X. + have_x=disabled +else + case $x_includes,$x_libraries in #( + *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #( + *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then : + $as_echo_n "(cached) " >&6 +else + # One or both of the vars are not set, and there is no cached value. +ac_x_includes=no ac_x_libraries=no +rm -f -r conftest.dir +if mkdir conftest.dir; then + cd conftest.dir + cat >Imakefile <<'_ACEOF' +incroot: + @echo incroot='${INCROOT}' +usrlibdir: + @echo usrlibdir='${USRLIBDIR}' +libdir: + @echo libdir='${LIBDIR}' +_ACEOF + if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then + # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. + for ac_var in incroot usrlibdir libdir; do + eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" + done + # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. + for ac_extension in a so sl dylib la dll; do + if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && + test -f "$ac_im_libdir/libX11.$ac_extension"; then + ac_im_usrlibdir=$ac_im_libdir; break + fi + done + # Screen out bogus values from the imake configuration. They are + # bogus both because they are the default anyway, and because + # using them would break gcc on systems where it needs fixed includes. + case $ac_im_incroot in + /usr/include) ac_x_includes= ;; + *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; + esac + case $ac_im_usrlibdir in + /usr/lib | /usr/lib64 | /lib | /lib64) ;; + *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; + esac + fi + cd .. + rm -f -r conftest.dir +fi + +# Standard set of common directories for X headers. +# Check X11 before X11Rn because it is often a symlink to the current release. +ac_x_header_dirs=' +/usr/X11/include +/usr/X11R7/include +/usr/X11R6/include +/usr/X11R5/include +/usr/X11R4/include + +/usr/include/X11 +/usr/include/X11R7 +/usr/include/X11R6 +/usr/include/X11R5 +/usr/include/X11R4 + +/usr/local/X11/include +/usr/local/X11R7/include +/usr/local/X11R6/include +/usr/local/X11R5/include +/usr/local/X11R4/include + +/usr/local/include/X11 +/usr/local/include/X11R7 +/usr/local/include/X11R6 +/usr/local/include/X11R5 +/usr/local/include/X11R4 + +/usr/X386/include +/usr/x386/include +/usr/XFree86/include/X11 + +/usr/include +/usr/local/include +/usr/unsupported/include +/usr/athena/include +/usr/local/x11r5/include +/usr/lpp/Xamples/include + +/usr/openwin/include +/usr/openwin/share/include' + +if test "$ac_x_includes" = no; then + # Guess where to find include files, by looking for Xlib.h. + # First, try using that file with no special directory specified. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # We can compile using X headers with no special include directory. +ac_x_includes= +else + for ac_dir in $ac_x_header_dirs; do + if test -r "$ac_dir/X11/Xlib.h"; then + ac_x_includes=$ac_dir + break + fi +done +fi +rm -f conftest.err conftest.i conftest.$ac_ext +fi # $ac_x_includes = no + +if test "$ac_x_libraries" = no; then + # Check for the libraries. + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS=$LIBS + LIBS="-lX11 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +XrmInitialize () + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + LIBS=$ac_save_LIBS +# We can link X programs with no special library path. +ac_x_libraries= +else + LIBS=$ac_save_LIBS +for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` +do + # Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl dylib la dll; do + if test -r "$ac_dir/libX11.$ac_extension"; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi # $ac_x_libraries = no + +case $ac_x_includes,$ac_x_libraries in #( + no,* | *,no | *\'*) + # Didn't find X, or a directory has "'" in its name. + ac_cv_have_x="have_x=no";; #( + *) + # Record where we found X for the cache. + ac_cv_have_x="have_x=yes\ + ac_x_includes='$ac_x_includes'\ + ac_x_libraries='$ac_x_libraries'" +esac +fi +;; #( + *) have_x=yes;; + esac + eval "$ac_cv_have_x" +fi # $with_x != no + +if test "$have_x" != yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 +$as_echo "$have_x" >&6; } + no_x=yes +else + # If each of the values was on the command line, it overrides each guess. + test "x$x_includes" = xNONE && x_includes=$ac_x_includes + test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries + # Update the cache value to reflect the command line values. + ac_cv_have_x="have_x=yes\ + ac_x_includes='$x_includes'\ + ac_x_libraries='$x_libraries'" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 +$as_echo "libraries $x_libraries, headers $x_includes" >&6; } +fi + +if test "$no_x" = yes; then + # Not all programs may use this symbol, but it does not hurt to define it. + +$as_echo "#define X_DISPLAY_MISSING 1" >>confdefs.h + + X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= +else + if test -n "$x_includes"; then + X_CFLAGS="$X_CFLAGS -I$x_includes" + fi + + # It would also be nice to do this for all -L options, not just this one. + if test -n "$x_libraries"; then + X_LIBS="$X_LIBS -L$x_libraries" + # For Solaris; some versions of Sun CC require a space after -R and + # others require no space. Words are not sufficient . . . . + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -R must be followed by a space" >&5 +$as_echo_n "checking whether -R must be followed by a space... " >&6; } + ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries" + ac_xsave_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + X_LIBS="$X_LIBS -R$x_libraries" +else + LIBS="$ac_xsave_LIBS -R $x_libraries" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + X_LIBS="$X_LIBS -R $x_libraries" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: neither works" >&5 +$as_echo "neither works" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_c_werror_flag=$ac_xsave_c_werror_flag + LIBS=$ac_xsave_LIBS + fi + + # Check for system-dependent libraries X programs must link with. + # Do this before checking for the system-independent R6 libraries + # (-lICE), since we may need -lsocket or whatever for X linking. + + if test "$ISC" = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" + else + # Martyn Johnson says this is needed for Ultrix, if the X + # libraries were built with DECnet support. And Karl Berry says + # the Alpha needs dnet_stub (dnet does not exist). + ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char XOpenDisplay (); +int +main () +{ +return XOpenDisplay (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5 +$as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; } +if ${ac_cv_lib_dnet_dnet_ntoa+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldnet $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dnet_ntoa (); +int +main () +{ +return dnet_ntoa (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dnet_dnet_ntoa=yes +else + ac_cv_lib_dnet_dnet_ntoa=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5 +$as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; } +if test "x$ac_cv_lib_dnet_dnet_ntoa" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" +fi + + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5 +$as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; } +if ${ac_cv_lib_dnet_stub_dnet_ntoa+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldnet_stub $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dnet_ntoa (); +int +main () +{ +return dnet_ntoa (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dnet_stub_dnet_ntoa=yes +else + ac_cv_lib_dnet_stub_dnet_ntoa=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5 +$as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; } +if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" +fi + + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$ac_xsave_LIBS" + + # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, + # to get the SysV transport functions. + # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4) + # needs -lnsl. + # The nsl library prevents programs from opening the X display + # on Irix 5.2, according to T.E. Dickey. + # The functions gethostbyname, getservbyname, and inet_addr are + # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking. + ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" +if test "x$ac_cv_func_gethostbyname" = xyes; then : + +fi + + if test $ac_cv_func_gethostbyname = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 +$as_echo_n "checking for gethostbyname in -lnsl... " >&6; } +if ${ac_cv_lib_nsl_gethostbyname+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_nsl_gethostbyname=yes +else + ac_cv_lib_nsl_gethostbyname=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 +$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } +if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" +fi + + if test $ac_cv_lib_nsl_gethostbyname = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5 +$as_echo_n "checking for gethostbyname in -lbsd... " >&6; } +if ${ac_cv_lib_bsd_gethostbyname+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lbsd $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_bsd_gethostbyname=yes +else + ac_cv_lib_bsd_gethostbyname=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5 +$as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; } +if test "x$ac_cv_lib_bsd_gethostbyname" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" +fi + + fi + fi + + # lieder@skyler.mavd.honeywell.com says without -lsocket, + # socket/setsockopt and other routines are undefined under SCO ODT + # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary + # on later versions), says Simon Leinen: it contains gethostby* + # variants that don't use the name server (or something). -lsocket + # must be given before -lnsl if both are needed. We assume that + # if connect needs -lnsl, so does gethostbyname. + ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" +if test "x$ac_cv_func_connect" = xyes; then : + +fi + + if test $ac_cv_func_connect = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 +$as_echo_n "checking for connect in -lsocket... " >&6; } +if ${ac_cv_lib_socket_connect+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $X_EXTRA_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char connect (); +int +main () +{ +return connect (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_socket_connect=yes +else + ac_cv_lib_socket_connect=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5 +$as_echo "$ac_cv_lib_socket_connect" >&6; } +if test "x$ac_cv_lib_socket_connect" = xyes; then : + X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" +fi + + fi + + # Guillermo Gomez says -lposix is necessary on A/UX. + ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove" +if test "x$ac_cv_func_remove" = xyes; then : + +fi + + if test $ac_cv_func_remove = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5 +$as_echo_n "checking for remove in -lposix... " >&6; } +if ${ac_cv_lib_posix_remove+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lposix $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char remove (); +int +main () +{ +return remove (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_posix_remove=yes +else + ac_cv_lib_posix_remove=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5 +$as_echo "$ac_cv_lib_posix_remove" >&6; } +if test "x$ac_cv_lib_posix_remove" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" +fi + + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat" +if test "x$ac_cv_func_shmat" = xyes; then : + +fi + + if test $ac_cv_func_shmat = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5 +$as_echo_n "checking for shmat in -lipc... " >&6; } +if ${ac_cv_lib_ipc_shmat+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lipc $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shmat (); +int +main () +{ +return shmat (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ipc_shmat=yes +else + ac_cv_lib_ipc_shmat=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5 +$as_echo "$ac_cv_lib_ipc_shmat" >&6; } +if test "x$ac_cv_lib_ipc_shmat" = xyes; then : + X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" +fi + + fi + fi + + # Check for libraries that X11R6 Xt/Xaw programs need. + ac_save_LDFLAGS=$LDFLAGS + test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" + # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to + # check for ICE first), but we must link in the order -lSM -lICE or + # we get undefined symbols. So assume we have SM if we have ICE. + # These have to be linked with before -lX11, unlike the other + # libraries we check for below, so use a different variable. + # John Interrante, Karl Berry + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5 +$as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; } +if ${ac_cv_lib_ICE_IceConnectionNumber+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lICE $X_EXTRA_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char IceConnectionNumber (); +int +main () +{ +return IceConnectionNumber (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ICE_IceConnectionNumber=yes +else + ac_cv_lib_ICE_IceConnectionNumber=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5 +$as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; } +if test "x$ac_cv_lib_ICE_IceConnectionNumber" = xyes; then : + X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" +fi + + LDFLAGS=$ac_save_LDFLAGS + +fi + +if test "x$no_x" != "x"; then + if test $usingX11 ; then + echo Cannot find X11---will attempt to compile anyway. + echo Graphics options will be NULL only! + usingX11= + fi + if test $usingTcl ; then + echo "Cannot compile TCL version without X11, disabling." + usingTcl= + fi +fi + + +if test $usingTcl ; then + usingX11=1 + cadinstall="$cadinstall tcltk" + modules="$modules tcltk" + programs="$programs tcltk" + ALL_TARGET="tcl" + INSTALL_TARGET="install-tcl" + $as_echo "#define TCL_NETGEN 1" >>confdefs.h + + extra_libs="$extra_libs \${NETGENDIR}/tcltk/libtcltk.o" + extra_defs="$extra_defs -DTCL_DIR=\\\"\${TCLDIR}\\\"" +else + programs="$programs netgen" + unused="$unused tcltk" +fi + + + +if test $usingTcl ; then + if test $usingX11 ; then + gr_dflags="$gr_dflags -DX11 -DXLIB" + gr_libs="$gr_libs -lX11" + gr_srcs="$gr_srcs \${TK_SRCS}" + else + gr_srcs="$gr_srcs \${NULL_SRCS}" + fi +else + if test $usingX11 ; then + gr_dflags="$gr_dflags -DX11 -DXLIB" + gr_libs="$gr_libs -lX11" + gr_srcs="$gr_srcs \${X11_SRCS}" + fi +fi + + +case $target in + *-linux*) + $as_echo "#define linux 1" >>confdefs.h + + $as_echo "#define SYSV 1" >>confdefs.h + + $as_echo "#define ISC 1" >>confdefs.h + + case $target in + *x86_64*) + CFLAGS="${CFLAGS} -m64 -fPIC" + ;; + esac + if test -f /usr/lib/libbsd-compat.a ; then + gr_libs="$gr_libs -lbsd-compat" + elif test -f /usr/lib/libbsd.a ; then + gr_libs="$gr_libs -lbsd" + fi + ;; + *solaris*) + $as_echo "#define SYSV 1" >>confdefs.h + + ;; + *irix*) + $as_echo "#define SYSV 1" >>confdefs.h + + $as_echo "#define IRIX 1" >>confdefs.h + + $as_echo "#define _BSD_SIGNALS 1" >>confdefs.h + + ;; + *sysv*) + $as_echo "#define SYSV 1" >>confdefs.h + + ;; + *cygwin*) + $as_echo "#define CYGWIN 1" >>confdefs.h + + $as_echo "#define i386 1" >>confdefs.h + + $as_echo "#define WIN32 1" >>confdefs.h + + ;; + *darwin*) + $as_echo "#define macosx 1" >>confdefs.h + + if test "$CPP" = "cc -E" ; then + CPPFLAGS="$CPPFLAGS -no-cpp-precomp" + fi + ;; +esac +# ----------------------------------------------------------------------- +# Tcl/Tk configuration +# ----------------------------------------------------------------------- + +if test $usingTcl ; then + +# ----------------------------------------------------------------------- +# +# Tk libraries and header files +# +# ----------------------------------------------------------------------- + if test "${TK_INC_DIR}" != "/usr/include" ; then + INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}" + fi + if test "${TK_LIB_DIR}" = "/usr/lib" -o \ + "${TK_LIB_DIR}" = "/usr/lib64" ; then + LIB_SPECS="${LIB_SPECS} ${TK_LIB_SPEC}" + else + LIB_SPECS="${LIB_SPECS} -L${TK_LIB_DIR} ${TK_LIB_SPEC}" + if test "x${loader_run_path}" = "x" ; then + loader_run_path="${TK_LIB_DIR}" + else + loader_run_path="${TK_LIB_DIR}:${loader_run_path}" + fi + fi + +# ----------------------------------------------------------------------- +# +# Tcl libraries and header files +# +# Add a header file directory specification only if the Tcl headers reside +# in a different directory from Tk's. +# +## ----------------------------------------------------------------------- + if test "${TCL_INC_DIR}" != "/usr/include" -a \ + "${TCL_INC_DIR}" != "${TK_INC_DIR}" ; then + INC_SPECS="${INC_SPECS} -I${TCL_INC_DIR}" + fi + + if test "${TCL_LIB_DIR}" = "/usr/lib" -o \ + "${TCL_LIB_DIR}" = "/usr/lib64" -o \ + "${TCL_LIB_DIR}" = "${TK_LIB_DIR}" ; then + LIB_SPECS="${LIB_SPECS} ${TCL_LIB_SPEC}" + else + LIB_SPECS="${LIB_SPECS} -L${TCL_LIB_DIR} ${TCL_LIB_SPEC}" + if test "x${loader_run_path}" = "x" ; then + loader_run_path="${TCL_LIB_DIR}" + else + loader_run_path="${TCL_LIB_DIR}:${loader_run_path}" + fi + fi + +#-------------------------------------------------------------------- +# +# Check if we can generate shared libraries on this system. Set flags +# to generate shared libraries for systems that we know about. Start +# with the values found in tclConfig.sh, make changes as we know about +# the different systems. +# +#-------------------------------------------------------------------- + +# Initialize shared library build variables + + SHLIB_LD="" + LDDL_FLAGS="-shared" + SHDLIB_EXT=".so" + EXTRA_LIB_SPECS="" + + build_shared="yes" + + case $target in + *-aix4.[2-9]*) + # No Position-Independent flags needed + + # Use the installed export file or the one found in the source directory. + + if test -r "${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" ; then + tcl_exp="${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" + else + tcl_exp="${TCL_SRC_DIR}/unix/lib.exp" + fi + if test -r "${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" ; then + tk_exp="${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" + else + tk_exp="${TK_SRC_DIR}/unix/lib.exp" + fi + + full_src_path=`cd ${srcdir}; pwd` + + # Use shell-script to link shared library + LD="${full_src_path}/cf/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry -bI:${tk_exp} -bI:${tcl_exp}" + + SHLIB_LIB_SPECS="${aix_lib_specs} -lc" + + LDFLAGS="-L${loader_run_path}" + EXTRA_LIB_SPECS="-ldl" + ;; + + *-aix*) + # No Position-Independent flags needed + + # Use the installed export file or the one found in the source directory. + + if test -r "${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" ; then + tcl_exp="${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" + else + tcl_exp="${TCL_SRC_DIR}/unix/lib.exp" + fi + if test -r "${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" ; then + tk_exp="${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" + else + tk_exp="${TK_SRC_DIR}/unix/lib.exp" + fi + + full_src_path=`cd ${srcdir}/cf; pwd` + + # Use shell-script to link shared library + + LD="${full_src_path}/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry -bI:${tk_exp} -bI:${tcl_exp}" + SHLIB_LIB_SPECS="${aix_lib_specs} -lc" + LDFLAGS="-L${loader_run_path}" + EXTRA_LIB_SPECS="-lld" + ;; + + *-bsdi2*|*-bsdi3*) + LD="shlicc" + LDDL_FLAGS="-r" + EXTRA_LIB_SPECS="-ldl" + ;; + + *darwin*) + SHDLIB_EXT=".dylib" + LDDL_FLAGS="-dynamiclib -flat_namespace -undefined suppress -noprebind" + LDFLAGS="${LDFLAGS} ${LIB_SPECS}" + CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common" + ;; + + *cygwin*) + SHDLIB_EXT=".dll" + $as_echo "#define USE_DL_IMPORT 1" >>confdefs.h + + LDDL_FLAGS='-shared -Wl,--enable-auto-image-base' + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + ld_extra_libs=${LIB_SPECS} + sub_extra_libs='-L${NETGENDIR}/netgen -ltclnetgen' + ;; + + *-bsdi4*) + SHLIB_CFLAGS="-export-dynamic -fPIC" + LDDL_FLAGS='-shared -Wl,-E -Wl,-soname,$@' + ;; + + *-dgux*) + SHLIB_CFLAGS="-K PIC" + LDDL_FLAGS="-G" + EXTRA_LIB_SPECS="-ldl" + ;; + + *-hpux*) + if test "$GCC" = "no" ; then + $as_echo "#define _HPUX_SOURCE 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if ${ac_cv_lib_dld_shl_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : + found=yes +else + found=no +fi + + if test "${found}" = "yes" ; then + SHLIB_CFLAGS="+z" + LDDL_FLAGS="-b -E -n +s +b,${loader_run_path}:." + SHDLIB_EXT=".sl" + + # The run path is included in both LDFLAGS and LDDL_FLAGS + # because SHLIB_LD is ld and LD is cc/gcc. + + LDFLAGS="-Wl,-E -Wl,+s,+b,${loader_run_path}:." + EXTRA_LIB_SPECS="-ldld" + fi + ;; + + *-irix64-6.5*) + LDDL_FLAGS="-32 -shared -rdata_shared" + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + ;; + + *-irix-56.*|*-irix64-*) + LDDL_FLAGS="-shared -rdata_shared" + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + LDFLAGS="" + if test "$GCC" = "yes" ; then + SHLIB_CFLAGS="-mabi=n32 $SHLIB_CFLAGS" + LDDL_FLAGS="-mabi=n32 $LDDL_FLAGS" + LDFLAGS="-mabi=n32 $LDFLAGS" + else + CFLAGS="-n32 $CFLAGS" + LDFLAGS="-n32 $LDFLAGS" + fi + ;; + + *-linux*) + LDDL_FLAGS=' -shared -Wl,-soname,$@' + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + LDFLAGS="" + EXTRA_LIB_SPECS="-ldl" + ;; + + *-mp-ras-02*) + SHLIB_CFLAGS="-G -K PIC" + LDDL_FLAGS="" + ;; + + *-mp-ras-*) + SHLIB_CFLAGS="-G -K PIC" + LDDL_FLAGS="-Wl,-Bexport" + ;; + + *-ncr-sysv4-*2*) + SHLIB_CFLAGS="-K PIC" + LDDL_FLAGS="-G" + + EXTRA_LIB_SPECS="-ldl" + ;; + + *-ncr-sysv4*) + SHLIB_CFLAGS="-K PIC" + LDDL_FLAGS="-G -Wl,-Bexport" + + LDFLAGS="-Wl,-Bexport" + EXTRA_LIB_SPECS="-ldl" + ;; + + *-freebsd*) + # Not available on all versions: check for include file. + SHLIB_CFLAGS="-fpic" + LDDL_FLAGS="-shared ${LIB_SPECS}" + CFLAGS="${CFLAGS} -l/usr/X11R6/include" + ;; + + *-netbsd*|*-openbsd*) + # Not available on all versions: check for include file. + ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" +if test "x$ac_cv_header_dlfcn_h" = xyes; then : + test_ok=yes +else + test_ok=no +fi + + + if test "$test_ok" = yes; then + SHLIB_CFLAGS="-fPIC" + LDDL_FLAGS="-shared ${LIB_SPEC}" + fi + ;; + + *-nextstep*) + LDDL_FLAGS="-nostdlib -r" + ;; + + *-osf1-1.012*) + # OSF/1 1.[012] from OSF, and derivatives, including Paragon OSF/1 + + # Warning: Ugly Makefile Hack + # Make package name same as library name + + SHLIB_LD='ld -R -export $@:' + ;; + + *-osf1-1.*) + # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2 + + SHLIB_CFLAGS="-fpic" + SHLIB_LD="ld -shared" + ;; + + *-osf1V*) + # Digital OSF/1 + + LDDL_FLAGS='-shared -expect_unresolved "*"' + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + LDFLAGS="" + ;; + + *-sco*) + # Note, dlopen is available only on SCO 3.2.5 and greater. However, + # this test works, since "uname -s" was non-standard in 3.2.4 and + # below. + + SHLIB_CFLAGS="-Kpic -belf" + LDDL_FLAGS="-G" + LDFLAGS="-belf -Wl,-Bexport" + ;; + + *-sni-sysv*) + + SHLIB_CFLAGS="-K PIC" + LDDL_FLAGS="-G" + + EXTRA_LIB_SPECS="-ldl" + ;; + + *-sunos4*) + + SHLIB_CFLAGS="-PIC" + LDDL_FLAGS="-assert pure-text" + + EXTRA_LIB_SPECS="-ldl" + ;; + + *-solaris2*) + + if test "$with_gnu_ld" = "yes" ; then + LDDL_FLAGS='-shared -Wl,-E -Wl,-soname,$@ ${LIB_SPEC}' + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + else + LDDL_FLAGS="-shared -mimpure-text" + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -R ${loader_run_path}" + fi + fi + EXTRA_LIB_SPECS="-ldl" + ;; + + *-mips-dde-sysv*) + + SHLIB_CFLAGS="-KPIC" + LDDL_FLAGS="-G" + + EXTRA_LIB_SPECS="-ldl" + ;; + + *-pc-sysv4* | *-unixware-5*) + SHLIB_CFLAGS="-G -KPIC" + LDDL_FLAGS=" -Wl,-Bexport" + ;; + + esac + +# If we're running gcc, then set SHLIB_CFLAGS flags for compiling +# shared libraries for gcc, instead of those of the vendor's compiler. + + if test "$GCC" = "yes" ; then + case $target in + *cygwin*) + ;; + *) + SHLIB_CFLAGS="-fPIC" + ;; + esac + fi + if test "$with_gnu_ld" = "yes" ; then + LDDL_FLAGS="${LDDL_FLAGS} -Wl,--version-script=\${NETGENDIR}/netgen/symbol.map" + fi + + + + + + + + + + + + + + + +fi + +if test "$GCC" = "yes" ; then + DEPEND_FLAG="-MM" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +ac_config_files="$ac_config_files defs.mak" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by netgen $as_me 1.3, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +netgen config.status 1.3 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "defs.mak") CONFIG_FILES="$CONFIG_FILES defs.mak" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + + +ECHO_N=printf + +echo +echo "-----------------------------------------------------------" +echo "Configuration Summary (principle requirements):" +echo + +${ECHO_N} "Tcl/Tk: " +if test $usingTcl ; then + echo "yes" +else + echo "no" + echo + echo " Without Tcl/Tk, you cannot run the enhanced version of netgen" + echo " with scripting ability, console window, convenience commands" + echo " such as \"lvs\", and other useful features. If you did not" + echo " specifically disable Tcl/Tk on the configure command line, then" + echo " getting this message means that you do not have Tcl/Tk headers" + echo " and/or libraries installed, or they are not in a standard path." + echo " Try using configure options --with-tcl=

and --with-tk=." + echo +fi + +echo "-----------------------------------------------------------" +echo + +echo "Use 'make' to compile and 'make install' to install." +echo +echo "Errors may not be printed to stdout: see files 'make.log' " +echo " and 'install.log' for a complete error summary." +echo +echo "-----------------------------------------------------------" +echo + +cp defs.mak .. diff --git a/scripts/configure.in b/scripts/configure.in new file mode 100644 index 0000000..80723b5 --- /dev/null +++ b/scripts/configure.in @@ -0,0 +1,1302 @@ +dnl Process this file with autoconf to produce a configure script. +dnl Use autoconf 2.52 or newer. + +AC_INIT(netgen, 1.3, eda-dev@opencircuitdesign.com) +AC_PREREQ(2.52) +AC_CONFIG_SRCDIR(rules.mak) +AC_CONFIG_AUX_DIR(.) + +AC_CANONICAL_SYSTEM + +dnl pass the version string on the the makefiles +PACKAGE=netgen +NETGEN_VERSION=`cat ../VERSION | cut -d. -f1-2` +NETGEN_REVISION=`cat ../VERSION | cut -d. -f3` +AC_DEFINE_UNQUOTED(NETGEN_VERSION, "${NETGEN_VERSION}") +AC_DEFINE_UNQUOTED(NETGEN_REVISION, "${NETGEN_REVISION}") + +dnl Override default target when compiling under TCL +ALL_TARGET="standard" +INSTALL_TARGET="install-netgen" + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_CPP +AC_ISC_POSIX +AC_PROG_INSTALL +AC_PROG_RANLIB + +dnl GNU M4 is preferred due to some of the option switches. +AC_PATH_PROGS([M4], [gm4 gnum4 m4], [no]) +if test x$M4 = xno; then + AC_MSG_ERROR([M4 is required]) +fi + +dnl check size of pointer for correct behavior on 64-bit systems +dnl If the C preprocessor is GCC, we need to force the flag to +dnl assert that input files are of type C, or else the preprocessing +dnl stage will not execute correctly on the ".in" files in the scmos +dnl directory. + +if test "$CPP" = "$CC -E" ; then + CPP="$CPP -x c" +fi + +dnl check if the linker is a GNU linker + +#------------------------------------------------------------ +# AC_PROG_LD - find the path to the GNU or non-GNU linker +# (This stuff ripped from libtool) +#------------------------------------------------------------ +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld assume the C compiler uses GNU ld [[default=no]]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +dnl ###not for PostgreSQL### AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case "$ac_prog" in + # Accept absolute paths. +changequote(,)dnl + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' +changequote([,])dnl + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(ac_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + ac_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + ac_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$ac_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_PROG_LD_GNU +]) + +AC_DEFUN([AC_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + ac_cv_prog_gnu_ld=yes +else + ac_cv_prog_gnu_ld=no +fi]) +with_gnu_ld=$ac_cv_prog_gnu_ld +]) + +AC_PROG_LD + +AC_CHECK_SIZEOF([void *], 4) +AC_CHECK_SIZEOF([unsigned int], 4) +AC_CHECK_SIZEOF([unsigned long], 4) +AC_CHECK_SIZEOF([unsigned long long], 8) + +dnl Check byte arrangement for doubleint routines +AC_C_BIGENDIAN + +dnl Check for required header files +AC_HEADER_STDC + +dnl Need either setenv or putenv +AC_CHECK_FUNCS(setenv putenv) + +dnl Check for vfork +AC_CHECK_FUNC(vfork) + +dnl Check for +AC_CHECK_HEADERS(dirent.h) + +dnl Check for +AC_CHECK_HEADERS(limits.h) + +dnl Check for +AC_CHECK_HEADERS(param.h) + +dnl Check for va_copy +AC_CACHE_CHECK([for va_copy], ac_cv_c_va_copy, + AC_TRY_LINK( + [#include ], + [va_list ap1, ap2; + va_copy(ap1,ap2); + ], + [ac_cv_c_va_copy="yes"], + [ac_cv_c_va_copy="no"]) + ) +if test "$ac_cv_c_va_copy" = "yes" +then + AC_DEFINE(HAVE_VA_COPY, 1, [Define if we have va_copy]) +fi +AC_CACHE_CHECK([for __va_copy], ac_cv_c___va_copy, + AC_TRY_LINK( + [#include ], + [va_list ap1, ap2; + __va_copy(ap1,ap2); + ], + [ac_cv_c___va_copy="yes"], + [ac_cv_c___va_copy="no"]) + ) +if test "$ac_cv_c___va_copy" = "yes" +then + AC_DEFINE(HAVE___VA_COPY, 1, [Define if we have __va_copy]) +fi + +# Note that it is essential to disable the DBUG packages, as it is +# not ANSI-compliant and won't compile without quite a bit of work. +AC_DEFINE(DBUG_OFF) + +extra_defs="$extra_defs -DCAD_DIR=\\\"\${LIBDIR}\\\"" +X_LIBS= +X_CFLAGS= +CPPFLAGS= +INC_SPECS= +DEPEND_FLAG= +SHLIB_CFLAGS="" +LD_RUN_PATH="" +WISH_EXE="" +TCLSH_EXE="" +CXX= + +modules="" +unused="" +cadinstall="" +extra_libs="" +other_srcs="" +top_extra_libs="" +sub_extra_libs="" +ld_extra_libs="" +ld_extra_objs="" +programs="" +rl_defs= +rl_libs= +gr_cflags= +gr_dflags= +gr_libs= +gr_srcs= +gr_hsrcs= +gr_hprog= + +netgen_with_tcl="yes" +netgen_with_tk="yes" +netgen_with_tcl_includes="" +netgen_with_tk_includes="" +netgen_with_tcl_libraries="" +netgen_with_tk_libraries="" + +dnl We will attempt to configure with Tcl/Tk and OpenGL. However, +dnl if checks for the appropriate header and library files fail, +dnl we will revert to non-Tcl and/or non-OpenGL compilation. +dnl Compilation for Tcl/Tk may be explicitly prohibited by using +dnl --with-tcl=no or --with-interpreter=no, and OpenGL may be +dnl disabled with --with-opengl=no + +usingTcl=1 +usingX11= + +dnl Compile-time options below. . . + +AC_ARG_WITH(interpreter, +[ --with-interpreter=[arg] enable interpreter], [ + if test "$withval" = "no" -o "$withval" = "NO"; then + usingTcl= + elif test "$withval" = "scheme" -o "$withval" = "SCHEME"; then + usingScheme=1 + usingTcl= + elif test "$withval" != "tcl" -a "$withval" != "TCL"; then + echo "Unknown option to --with-interpreter: Must be scheme, tcl, or no." + exit 1 + fi +], ) + +AC_ARG_WITH(tcl, +[ --with-tcl=DIR Find tclConfig.sh in DIR], [ + netgen_with_tcl=$withval + if test "$withval" = "no" -o "$withval" = "NO"; then + usingTcl= + elif test $usingScheme ; then + echo Attempt to enable both Tcl and Scheme interpreters. + echo Disabling Tcl, and using Scheme instead. + usingTcl= + fi +], ) + +dnl ---------------------------------------------------------------- +dnl Do our best to find Tcl/Tk. If we can't, then flag a warning +dnl and don't set the usingTcl variable. +dnl +dnl This has been broken up into a number of sections, each of which +dnl depends independently on the setting of usingTcl. +dnl ---------------------------------------------------------------- + +AC_ARG_WITH(tk, [ --with-tk=DIR Find tkConfig.sh in DIR], + netgen_with_tk=$withval) +AC_ARG_WITH(tclincls, [ --with-tclincls=DIR Find tcl.h in DIR], + netgen_with_tcl_includes=$withval) +AC_ARG_WITH(tkincls, [ --with-tkincls=DIR Find tk.h in DIR], + netgen_with_tk_includes=$withval) +AC_ARG_WITH(tcllibs, [ --with-tcllibs=DIR Find Tcl library in DIR], + netgen_with_tcl_libraries=$withval) +AC_ARG_WITH(tklibs, [ --with-tklibs=DIR Find Tk library in DIR], + netgen_with_tk_libraries=$withval) + +# ----------------------------------------------------------------------- +# Find the Tcl build configuration file "tclConfig.sh" +# ----------------------------------------------------------------------- + +if test $usingTcl ; then + TCL_INC_DIR="." + TK_INC_DIR="." + + AC_MSG_CHECKING([for tclConfig.sh]) + tcl_config_sh="" + + if test "$netgen_with_tcl" = "no" ; then + netgen_with_tcl="" + elif test "$netgen_with_tcl" != "yes" ; then + # + # Verify that a tclConfig.sh file exists in the directory specified + # by --with-tcl. + # + for dir in \ + $netgen_with_tcl + do + if test -r "$dir/tclConfig.sh" ; then + tcl_config_sh="$dir/tclConfig.sh" + break + elif test -r "$dir/lib/tclConfig.sh" ; then + tcl_config_sh="$dir/lib/tclConfig.sh" + break + elif test -r "$dir/unix/tclConfig.sh" ; then + tcl_config_sh="$dir/unix/tclConfig.sh" + break + fi + done + else + # + # Otherwise, search for Tcl configuration file. + # + + # 1. Search previously named locations. + + for dir in \ + $prefix \ + $exec_prefix + do + if test -r "$dir/tclConfig.sh" ; then + tcl_config_sh="$dir/tclConfig.sh" + break + elif test -r "$dir/lib/tclConfig.sh" ; then + tcl_config_sh="$dir/lib/tclConfig.sh" + break + elif test -r "$dir/unix/tclConfig.sh" ; then + tcl_config_sh="$dir/unix/tclConfig.sh" + break + fi + done + + # 2. Search standard locations. + + if test "x$tcl_config_sh" = "x" ; then + for dir in \ + `ls -dr /usr/local/tcl/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ + /usr/local/tcl \ + /usr/local/lib \ + /usr/lib64 \ + /usr/local \ + `ls -dr /usr/lib/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ + /sw/lib \ + /usr + do + if test -r "$dir/tclConfig.sh" ; then + tcl_config_sh="$dir/tclConfig.sh" + break + elif test -r "$dir/lib/tclConfig.sh" ; then + tcl_config_sh="$dir/lib/tclConfig.sh" + break + fi + done + fi + fi + + AC_MSG_RESULT([${tcl_config_sh}]) + + if test "x$tcl_config_sh" = "x" ; then + echo "Can't find Tcl configuration script \"tclConfig.sh\"" + echo "Reverting to non-Tcl compilation" + usingTcl= + fi +fi + +# ----------------------------------------------------------------------- +# Find the Tk build configuration file "tkConfig.sh" +# ----------------------------------------------------------------------- + +if test $usingTcl ; then + + AC_MSG_CHECKING([for tkConfig.sh]) + tk_config_sh="" + if test "$netgen_with_tk" != "yes"; then + # + # Verify that a tkConfig.sh file exists in the directory specified + # by --with-tcl or --with-tk. + # + for dir in \ + $netgen_with_tk \ + $netgen_with_tcl + do + if test -r "$dir/tkConfig.sh" ; then + tk_config_sh="$dir/tkConfig.sh" + break + elif test -r "$dir/lib/tkConfig.sh" ; then + tk_config_sh="$dir/lib/tkConfig.sh" + break + elif test -r "$dir/unix/tkConfig.sh" ; then + tk_config_sh="$dir/unix/tkConfig.sh" + break + fi + done + else + # + # Search for Tk configuration file. + # + + # + # 1. Search previously named locations. + # + for dir in \ + $prefix \ + $exec_prefix + do + if test -r "$dir/tkConfig.sh" ; then + tk_config_sh="$dir/tkConfig.sh" + break + elif test -r "$dir/lib/tkConfig.sh" ; then + tk_config_sh="$dir/lib/tkConfig.sh" + break + elif test -r "$dir/unix/tkConfig.sh" ; then + tk_config_sh="$dir/unix/tkConfig.sh" + break + fi + done + # + # 2. Search standard locations. + # + if test "x$tk_config_sh" = "x" ; then + for dir in \ + `ls -dr /usr/local/tcl/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr /usr/local/tk/tk[[7-9]].[[0-9]]* 2>/dev/null` \ + /usr/local/tcl \ + /usr/local/lib \ + /usr/lib64 \ + /usr/local \ + `ls -dr /usr/lib/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr /usr/lib/tk[[7-9]].[[0-9]]* 2>/dev/null` \ + /sw/lib \ + ${x_libraries} \ + /usr + do + if test -r "$dir/tkConfig.sh" ; then + tk_config_sh="$dir/tkConfig.sh" + break + elif test -r "$dir/lib/tkConfig.sh" ; then + tk_config_sh="$dir/lib/tkConfig.sh" + break + fi + done + fi + fi + AC_MSG_RESULT([${tk_config_sh}]) + + if test "x$tk_config_sh" = "x" ; then + echo "can't find Tk configuration script \"tkConfig.sh\"" + echo "Reverting to non-Tcl compilation" + usingTcl= + fi +fi + +# ----------------------------------------------------------------------- +# Source in the Tcl/Tk configuration scripts. +# ----------------------------------------------------------------------- + +if test $usingTcl ; then + . $tcl_config_sh + . $tk_config_sh + + if test "$TCL_VERSION" = "7.6" -a "$TK_VERSION" = "4.2" ; then + : + elif test "$TCL_VERSION" = "7.5" -a "$TK_VERSION" = "4.1" ; then + : + elif test "$TCL_VERSION" = "$TK_VERSION" ; then + : + else + echo "Mismatched Tcl/Tk versions ($TCL_VERSION != $TK_VERSION)" + echo "Reverting to non-Tcl compile" + usingTcl= + fi +fi + +if test $usingTcl ; then + if test "x${netgen_with_tcl_includes}" != "x" ; then + if test -r "${netgen_with_tcl_includes}/tcl.h" ; then + TCL_INC_DIR=${netgen_with_tcl_includes} + else + echo "Can't find tcl.h in \"${netgen_with_tcl_includes}\"" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + else + for dir in \ + ${TCL_PREFIX}/include/tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION} \ + ${TCL_PREFIX}/include \ + ${TCL_SRC_DIR}/generic \ + ${TCL_INC_DIR} + do + if test -r "$dir/tcl.h" ; then + TCL_INC_DIR=$dir + break + fi + done + if test "x${TCL_INC_DIR}" = "x" ; then + echo "Can't find tcl.h header file" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + fi +fi + +if test $usingTcl ; then + if test "x${netgen_with_tk_includes}" != "x" ; then + if test -r "${netgen_with_tk_includes}/tk.h" ; then + TK_INC_DIR=${netgen_with_tk_includes} + else + echo "Can't find tk.h in \"${netgen_with_tk_includes}\"" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + else + for dir in \ + ${TK_PREFIX}/include/tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION} \ + ${TK_PREFIX}/include \ + ${TK_SRC_DIR}/generic \ + ${TK_INC_DIR} \ + ${TCL_INC_DIR} + do + if test -r "$dir/tk.h" ; then + TK_INC_DIR=$dir + break + fi + done + if test "x${TK_INC_DIR}" = "x" ; then + echo "Can't find tk.h header file" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + fi +fi + +if test $usingTcl ; then + case $target in + *-sunos4*|*-*-netbsd*|NetBSD-*|FreeBSD-*|OpenBSD-*) + TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}" + TK_LIB_NAME="tk${TK_MAJOR_VERSION}${TK_MINOR_VERSION}" + ;; + *) + TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}" + TK_LIB_NAME="tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}" + ;; + esac + + loclib=`echo ${TCL_LIB_SPEC} | sed -e 's/.*-L//' -e 's/ .*//'` + + if test "x${TCL_LIB_SPEC}" = "x" ; then + TCL_LIB_SPEC="-l${TCL_LIB_NAME}" + fi + if test "x${TK_LIB_SPEC}" = "x" ; then + TK_LIB_SPEC="-l${TK_LIB_NAME}" + fi + +# Find the version of "wish" that corresponds to TCL_EXEC_PREFIX +# We really ought to run "ldd" to confirm that the linked libraries match. + + AC_MSG_CHECKING([for wish executable]) + for dir in \ + ${TK_EXEC_PREFIX}/bin \ + ${TK_EXEC_PREFIX} + do + for wishexe in \ + wish \ + wish${TK_VERSION} \ + wish.exe \ + wish${TK_VERSION}.exe + do + if test -r "$dir/$wishexe" ; then + WISH_EXE=$dir/$wishexe + break + fi + done + if test "x${WISH_EXE}" != "x" ; then + break + fi + done + if test "x${WISH_EXE}" = "x" ; then + echo "Warning: Can't find executable for \"wish\". You may have to" + echo "manually set the value for WISH_EXE in the netgen startup script." + AC_MSG_RESULT(no) + else + AC_MSG_RESULT([${WISH_EXE}]) + fi + +# Find the version of "tclsh" that corresponds to TCL_EXEC_PREFIX + + AC_MSG_CHECKING([for tclsh executable]) + for dir in \ + ${TK_EXEC_PREFIX}/bin \ + ${TK_EXEC_PREFIX} + do + for tclshexe in \ + tclsh \ + tclsh${TK_VERSION} \ + tclsh.exe \ + tclsh${TK_VERSION}.exe + do + if test -r "$dir/$tclshexe" ; then + TCLSH_EXE=$dir/$tclshexe + break + fi + done + if test "x${TCLSH_EXE}" != "x" ; then + break + fi + done + if test "x${TCLSH_EXE}" = "x" ; then + echo "Warning: Can't find executable for \"tclsh\"." + AC_MSG_RESULT(no) + else + AC_MSG_RESULT([${TCLSH_EXE}]) + fi + +# Have to define SHDLIB_EXT here even though we have to do it below, too. + case $target in + *-hpux*) + SHDLIB_EXT=".sl" + SHDLIB_EXT_ALT=".sl" + ;; + *cygwin*) + SHDLIB_EXT=".dll" + SHDLIB_EXT_ALT=".dll.a" + ;; + *darwin*) + SHDLIB_EXT=".dylib" + SHDLIB_EXT_ALT=".dylib" + ;; + *) + SHDLIB_EXT=".so" + SHDLIB_EXT_ALT=".so" + ;; + esac + + if test "x${netgen_with_tcl_libraries}" != "x" ; then + for libname in \ + "${netgen_with_tcl_libraries}/lib${TCL_LIB_FILE}" \ + "${netgen_with_tcl_libraries}/lib${TCL_LIB_NAME}${SHDLIB_EXT}" \ + "${netgen_with_tcl_libraries}/lib${TCL_LIB_NAME}${SHDLIB_EXT_ALT}" + do + if test -r "$libname" ; then + TCL_LIB_DIR="${netgen_with_tcl_libraries}" + break + fi + done + + if test "x${TCL_LIB_DIR}" = "x" ; then + echo "Can't find tcl library in \"${netgen_with_tcl_libraries}\"" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + else + for libname in \ + "${loclib:=${TCL_EXEC_PREFIX}/lib}/lib${TCL_LIB_NAME}${SHDLIB_EXT}" \ + "${loclib:=${TCL_EXEC_PREFIX}/lib}/lib${TCL_LIB_NAME}${SHDLIB_EXT_ALT}" \ + "${loclib:=${TCL_EXEC_PREFIX}/lib64}/lib${TCL_LIB_NAME}${SHDLIB_EXT}" + do + if test -r "$libname" ; then + TCL_LIB_DIR="${TCL_EXEC_PREFIX}/lib" + break + fi + done + if test "x${TCL_LIB_DIR}" = "x" ; then + echo "Can't find tcl library" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + fi +fi + +if test $usingTcl ; then + if test "x${netgen_with_tk_libraries}" != "x" ; then + for libname in \ + "${netgen_with_tk_libraries}/${TCL_LIB_FILE}" \ + "${netgen_with_tk_libraries}/lib${TK_LIB_NAME}${SHDLIB_EXT}" \ + "${netgen_with_tk_libraries}/lib${TK_LIB_NAME}${SHDLIB_EXT_ALT}" + do + if test -r "$libname" ; then + TK_LIB_DIR="${netgen_with_tk_libraries}" + break + fi + done + if test "x${TK_LIB_DIR}" = "x" ; then + echo "Can't find tk library in \"${netgen_with_tk_libraries}\"" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + else + for libname in \ + "${loclib:=${TK_EXEC_PREFIX}/lib}/lib${TK_LIB_NAME}${SHDLIB_EXT}" \ + "${loclib:=${TK_EXEC_PREFIX}/lib}/lib${TK_LIB_NAME}${SHDLIB_EXT_ALT}" \ + "${loclib:=${TK_EXEC_PREFIX}/lib64}/lib${TK_LIB_NAME}${SHDLIB_EXT}" + do + if test -r "$libname" ; then + TK_LIB_DIR="${TK_EXEC_PREFIX}/lib" + break + fi + done + if test "x${TK_LIB_DIR}" = "x" ; then + echo "Can't find tk library" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + fi +fi + +dnl ---------------------------------------------------- +dnl End of Tcl/Tk search +dnl ---------------------------------------------------- + +dnl The X11 version of the non-Tcl-based netgen is so awful +dnl we don't really want to advertise it. So, you have to +dnl specifically do "--with-widgets=" to get HAVE_X11 set; +dnl otherwise, you get the command-line interface, which is +dnl much more pleasant. + +AC_ARG_WITH(widgets, +[ --with-widgets=[arg] select widget set], [ + if test "$withval" = "xw" -o "$withval" = "Xw"; then + usingX11=1 + usingTcl= + gr_dflags="${gr_dflags} -DHAVE_X11 -DX11_HP_WIDGETS" + gr_libs="${gr_libs} -lXw -lXt" + elif test "$withval" = "Xm" -o "$withval" = "Motif"; then + usingX11=1 + usingTcl= + gr_dflags="${gr_dflags} -DHAVE_X11 -DX11_MOTIF_WIDGETS" + gr_libs="${gr_libs} -lXm -lXt" + else + usingX11=1 + usingTcl= + gr_dflags="${gr_dflags} -DHAVE_X11 -DX11_ATHENA_WIDGETS" + gr_libs="${gr_libs} -lXaw -lXmu -lXt -lXext" + fi +], ) + +dnl Check for X enabled/disabled + +AC_PATH_XTRA +if test "x$no_x" != "x"; then + if test $usingX11 ; then + echo Cannot find X11---will attempt to compile anyway. + echo Graphics options will be NULL only! + usingX11= + fi + if test $usingTcl ; then + echo "Cannot compile TCL version without X11, disabling." + usingTcl= + fi +fi + +dnl ---------------------------------------------------------------- +dnl Once we're sure what, if any, interpreter is being compiled, +dnl set all the appropriate definitions. For Tcl/Tk, override +dnl the default install targets: allows compiling tcl version with +dnl "make" instead of requiring "make tcl" +dnl ---------------------------------------------------------------- + +if test $usingTcl ; then + usingX11=1 + cadinstall="$cadinstall tcltk" + modules="$modules tcltk" + programs="$programs tcltk" + ALL_TARGET="tcl" + INSTALL_TARGET="install-tcl" + AC_DEFINE(TCL_NETGEN) + extra_libs="$extra_libs \${NETGENDIR}/tcltk/libtcltk.o" + extra_defs="$extra_defs -DTCL_DIR=\\\"\${TCLDIR}\\\"" +else + programs="$programs netgen" + unused="$unused tcltk" +fi + +dnl If usingAthena is set, and we are using X11, then no widget +dnl set has been selected with "--with-widgets", so we default +dnl to the X11 Athena widget set. + +dnl ---------------------------------------------------------------- +dnl Handle graphics based on the setting of "usingTcl", "usingX11", +dnl "usingOGL", and "usingBLT" +dnl ---------------------------------------------------------------- + +if test $usingTcl ; then + if test $usingX11 ; then + gr_dflags="$gr_dflags -DX11 -DXLIB" + gr_libs="$gr_libs -lX11" + gr_srcs="$gr_srcs \${TK_SRCS}" + else + gr_srcs="$gr_srcs \${NULL_SRCS}" + fi +else + if test $usingX11 ; then + gr_dflags="$gr_dflags -DX11 -DXLIB" + gr_libs="$gr_libs -lX11" + gr_srcs="$gr_srcs \${X11_SRCS}" + fi +fi + +dnl ---------------------------------------------------------------- +dnl Define system-specific settings +dnl ---------------------------------------------------------------- + +case $target in + *-linux*) + AC_DEFINE(linux) + AC_DEFINE(SYSV) + dnl Defining "ISC" prevents compiler failure on redefinition of "wchar_t" + AC_DEFINE(ISC) + dnl 64-bit support for AMD Opteron + case $target in + *x86_64*) + CFLAGS="${CFLAGS} -m64 -fPIC" + ;; + esac + if test -f /usr/lib/libbsd-compat.a ; then + gr_libs="$gr_libs -lbsd-compat" + elif test -f /usr/lib/libbsd.a ; then + gr_libs="$gr_libs -lbsd" + fi + ;; + *solaris*) + AC_DEFINE(SYSV) + ;; + *irix*) + AC_DEFINE(SYSV) + AC_DEFINE(IRIX) + AC_DEFINE(_BSD_SIGNALS) + ;; + *sysv*) + AC_DEFINE(SYSV) + ;; + *cygwin*) + AC_DEFINE(CYGWIN) + AC_DEFINE(i386) + AC_DEFINE(WIN32) + ;; + *darwin*) + AC_DEFINE(macosx) + if test "$CPP" = "cc -E" ; then + CPPFLAGS="$CPPFLAGS -no-cpp-precomp" + fi + ;; +esac +# ----------------------------------------------------------------------- +# Tcl/Tk configuration +# ----------------------------------------------------------------------- + +if test $usingTcl ; then + +# ----------------------------------------------------------------------- +# +# Tk libraries and header files +# +# ----------------------------------------------------------------------- + if test "${TK_INC_DIR}" != "/usr/include" ; then + INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}" + fi + if test "${TK_LIB_DIR}" = "/usr/lib" -o \ + "${TK_LIB_DIR}" = "/usr/lib64" ; then + LIB_SPECS="${LIB_SPECS} ${TK_LIB_SPEC}" + else + LIB_SPECS="${LIB_SPECS} -L${TK_LIB_DIR} ${TK_LIB_SPEC}" + if test "x${loader_run_path}" = "x" ; then + loader_run_path="${TK_LIB_DIR}" + else + loader_run_path="${TK_LIB_DIR}:${loader_run_path}" + fi + fi + +# ----------------------------------------------------------------------- +# +# Tcl libraries and header files +# +# Add a header file directory specification only if the Tcl headers reside +# in a different directory from Tk's. +# +## ----------------------------------------------------------------------- + if test "${TCL_INC_DIR}" != "/usr/include" -a \ + "${TCL_INC_DIR}" != "${TK_INC_DIR}" ; then + INC_SPECS="${INC_SPECS} -I${TCL_INC_DIR}" + fi + + if test "${TCL_LIB_DIR}" = "/usr/lib" -o \ + "${TCL_LIB_DIR}" = "/usr/lib64" -o \ + "${TCL_LIB_DIR}" = "${TK_LIB_DIR}" ; then + LIB_SPECS="${LIB_SPECS} ${TCL_LIB_SPEC}" + else + LIB_SPECS="${LIB_SPECS} -L${TCL_LIB_DIR} ${TCL_LIB_SPEC}" + if test "x${loader_run_path}" = "x" ; then + loader_run_path="${TCL_LIB_DIR}" + else + loader_run_path="${TCL_LIB_DIR}:${loader_run_path}" + fi + fi + +#-------------------------------------------------------------------- +# +# Check if we can generate shared libraries on this system. Set flags +# to generate shared libraries for systems that we know about. Start +# with the values found in tclConfig.sh, make changes as we know about +# the different systems. +# +#-------------------------------------------------------------------- + +# Initialize shared library build variables + + SHLIB_LD="" + LDDL_FLAGS="-shared" + SHDLIB_EXT=".so" + EXTRA_LIB_SPECS="" + + build_shared="yes" + + case $target in + *-aix4.[[2-9]]*) + # No Position-Independent flags needed + + # Use the installed export file or the one found in the source directory. + + if test -r "${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" ; then + tcl_exp="${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" + else + tcl_exp="${TCL_SRC_DIR}/unix/lib.exp" + fi + if test -r "${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" ; then + tk_exp="${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" + else + tk_exp="${TK_SRC_DIR}/unix/lib.exp" + fi + + full_src_path=`cd ${srcdir}; pwd` + + # Use shell-script to link shared library + LD="${full_src_path}/cf/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry -bI:${tk_exp} -bI:${tcl_exp}" + + SHLIB_LIB_SPECS="${aix_lib_specs} -lc" + + LDFLAGS="-L${loader_run_path}" + EXTRA_LIB_SPECS="-ldl" + ;; + + *-aix*) + # No Position-Independent flags needed + + # Use the installed export file or the one found in the source directory. + + if test -r "${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" ; then + tcl_exp="${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" + else + tcl_exp="${TCL_SRC_DIR}/unix/lib.exp" + fi + if test -r "${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" ; then + tk_exp="${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" + else + tk_exp="${TK_SRC_DIR}/unix/lib.exp" + fi + + full_src_path=`cd ${srcdir}/cf; pwd` + + # Use shell-script to link shared library + + LD="${full_src_path}/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry -bI:${tk_exp} -bI:${tcl_exp}" + SHLIB_LIB_SPECS="${aix_lib_specs} -lc" + LDFLAGS="-L${loader_run_path}" + EXTRA_LIB_SPECS="-lld" + ;; + + *-bsdi2*|*-bsdi3*) + LD="shlicc" + LDDL_FLAGS="-r" + EXTRA_LIB_SPECS="-ldl" + ;; + + *darwin*) + SHDLIB_EXT=".dylib" + LDDL_FLAGS="-dynamiclib -flat_namespace -undefined suppress -noprebind" + LDFLAGS="${LDFLAGS} ${LIB_SPECS}" + CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common" + ;; + + *cygwin*) + SHDLIB_EXT=".dll" + AC_DEFINE(USE_DL_IMPORT) + LDDL_FLAGS='-shared -Wl,--enable-auto-image-base' + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + ld_extra_libs=${LIB_SPECS} + sub_extra_libs='-L${NETGENDIR}/netgen -ltclnetgen' + ;; + + *-bsdi4*) + SHLIB_CFLAGS="-export-dynamic -fPIC" + LDDL_FLAGS='-shared -Wl,-E -Wl,-soname,$@' + ;; + + *-dgux*) + SHLIB_CFLAGS="-K PIC" + LDDL_FLAGS="-G" + EXTRA_LIB_SPECS="-ldl" + ;; + + *-hpux*) + if test "$GCC" = "no" ; then + AC_DEFINE(_HPUX_SOURCE) + fi + AC_CHECK_LIB(dld, shl_load, [found=yes], [found=no]) + if test "${found}" = "yes" ; then + SHLIB_CFLAGS="+z" + LDDL_FLAGS="-b -E -n +s +b,${loader_run_path}:." + SHDLIB_EXT=".sl" + + # The run path is included in both LDFLAGS and LDDL_FLAGS + # because SHLIB_LD is ld and LD is cc/gcc. + + LDFLAGS="-Wl,-E -Wl,+s,+b,${loader_run_path}:." + EXTRA_LIB_SPECS="-ldld" + fi + ;; + + *-irix64-6.5*) + LDDL_FLAGS="-32 -shared -rdata_shared" + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + ;; + + *-irix-[56].*|*-irix64-*) + LDDL_FLAGS="-shared -rdata_shared" + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + LDFLAGS="" + if test "$GCC" = "yes" ; then + SHLIB_CFLAGS="-mabi=n32 $SHLIB_CFLAGS" + LDDL_FLAGS="-mabi=n32 $LDDL_FLAGS" + LDFLAGS="-mabi=n32 $LDFLAGS" + else + CFLAGS="-n32 $CFLAGS" + LDFLAGS="-n32 $LDFLAGS" + fi + ;; + + *-linux*) + LDDL_FLAGS=' -shared -Wl,-soname,$@' + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + LDFLAGS="" + EXTRA_LIB_SPECS="-ldl" + ;; + + *-mp-ras-02*) + SHLIB_CFLAGS="-G -K PIC" + LDDL_FLAGS="" + ;; + + *-mp-ras-*) + SHLIB_CFLAGS="-G -K PIC" + LDDL_FLAGS="-Wl,-Bexport" + ;; + + *-ncr-sysv4-*2*) + SHLIB_CFLAGS="-K PIC" + LDDL_FLAGS="-G" + + EXTRA_LIB_SPECS="-ldl" + ;; + + *-ncr-sysv4*) + SHLIB_CFLAGS="-K PIC" + LDDL_FLAGS="-G -Wl,-Bexport" + + LDFLAGS="-Wl,-Bexport" + EXTRA_LIB_SPECS="-ldl" + ;; + + *-freebsd*) + # Not available on all versions: check for include file. + SHLIB_CFLAGS="-fpic" + LDDL_FLAGS="-shared ${LIB_SPECS}" + CFLAGS="${CFLAGS} -l/usr/X11R6/include" + ;; + + *-netbsd*|*-openbsd*) + # Not available on all versions: check for include file. + AC_CHECK_HEADER(dlfcn.h, test_ok=yes, test_ok=no) + if test "$test_ok" = yes; then + SHLIB_CFLAGS="-fPIC" + LDDL_FLAGS="-shared ${LIB_SPEC}" + fi + ;; + + *-nextstep*) + LDDL_FLAGS="-nostdlib -r" + ;; + + *-osf1-1.[012]*) + # OSF/1 1.[012] from OSF, and derivatives, including Paragon OSF/1 + + # Warning: Ugly Makefile Hack + # Make package name same as library name + + SHLIB_LD='ld -R -export $@:' + ;; + + *-osf1-1.*) + # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2 + + SHLIB_CFLAGS="-fpic" + SHLIB_LD="ld -shared" + ;; + + *-osf1V*) + # Digital OSF/1 + + LDDL_FLAGS='-shared -expect_unresolved "*"' + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + LDFLAGS="" + ;; + + *-sco*) + # Note, dlopen is available only on SCO 3.2.5 and greater. However, + # this test works, since "uname -s" was non-standard in 3.2.4 and + # below. + + SHLIB_CFLAGS="-Kpic -belf" + LDDL_FLAGS="-G" + LDFLAGS="-belf -Wl,-Bexport" + ;; + + *-sni-sysv*) + + SHLIB_CFLAGS="-K PIC" + LDDL_FLAGS="-G" + + EXTRA_LIB_SPECS="-ldl" + ;; + + *-sunos4*) + + SHLIB_CFLAGS="-PIC" + LDDL_FLAGS="-assert pure-text" + + EXTRA_LIB_SPECS="-ldl" + ;; + + *-solaris2*) + + if test "$with_gnu_ld" = "yes" ; then + LDDL_FLAGS='-shared -Wl,-E -Wl,-soname,$@ ${LIB_SPEC}' + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + else + LDDL_FLAGS="-shared -mimpure-text" + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -R ${loader_run_path}" + fi + fi + EXTRA_LIB_SPECS="-ldl" + ;; + + *-mips-dde-sysv*) + + SHLIB_CFLAGS="-KPIC" + LDDL_FLAGS="-G" + + EXTRA_LIB_SPECS="-ldl" + ;; + + *-pc-sysv4* | *-unixware-5*) + SHLIB_CFLAGS="-G -KPIC" + LDDL_FLAGS=" -Wl,-Bexport" + ;; + + esac + +# If we're running gcc, then set SHLIB_CFLAGS flags for compiling +# shared libraries for gcc, instead of those of the vendor's compiler. + + if test "$GCC" = "yes" ; then + case $target in + *cygwin*) + ;; + *) + SHLIB_CFLAGS="-fPIC" + ;; + esac + fi + if test "$with_gnu_ld" = "yes" ; then + LDDL_FLAGS="${LDDL_FLAGS} -Wl,--version-script=\${NETGENDIR}/netgen/symbol.map" + fi + + AC_SUBST(SHDLIB_EXT) + AC_SUBST(SHLIB_LD) + AC_SUBST(LD) + AC_SUBST(LDDL_FLAGS) + AC_SUBST(SHLIB_LIB_SPECS) + + AC_SUBST(EXTRA_LIB_SPECS) + AC_SUBST(LDFLAGS) + AC_SUBST(INC_SPECS) + AC_SUBST(LIB_SPECS) + AC_SUBST(WISH_EXE) + AC_SUBST(TCLSH_EXE) + AC_SUBST(TCL_LIB_DIR) + +fi + +if test "$GCC" = "yes" ; then + DEPEND_FLAG="-MM" +fi + +dnl Substitute all variables + +AC_SUBST(VERSION) +AC_SUBST(PACKAGE) +AC_SUBST(SCRIPTS) +AC_SUBST(extra_libs) +AC_SUBST(extra_defs) +AC_SUBST(ld_extra_libs) +AC_SUBST(ld_extra_objs) +AC_SUBST(top_extra_libs) +AC_SUBST(sub_extra_libs) +AC_SUBST(modules) +AC_SUBST(unused) +AC_SUBST(programs) +AC_SUBST(cadinstall) + +AC_SUBST(gr_cflags) +AC_SUBST(gr_dflags) +AC_SUBST(gr_libs) +AC_SUBST(gr_srcs) + +AC_SUBST(X_LIBS) +AC_SUBST(X_CFLAGS) +AC_SUBST(CPPFLAGS) +AC_SUBST(CFLAGS) +AC_SUBST(DEPEND_FLAG) +AC_SUBST(SHLIB_CFLAGS) +AC_SUBST(LD_RUN_PATH) + +AC_SUBST(ALL_TARGET) +AC_SUBST(INSTALL_TARGET) + +AC_OUTPUT(defs.mak) + +dnl +dnl Print configuration and report problems + +ECHO_N=printf + +echo +echo "-----------------------------------------------------------" +echo "Configuration Summary (principle requirements):" +echo + +${ECHO_N} "Tcl/Tk: " +if test $usingTcl ; then + echo "yes" +else + echo "no" + echo + echo " Without Tcl/Tk, you cannot run the enhanced version of netgen" + echo " with scripting ability, console window, convenience commands" + echo " such as \"lvs\", and other useful features. If you did not" + echo " specifically disable Tcl/Tk on the configure command line, then" + echo " getting this message means that you do not have Tcl/Tk headers" + echo " and/or libraries installed, or they are not in a standard path." + echo " Try using configure options --with-tcl= and --with-tk=." + echo +fi + +echo "-----------------------------------------------------------" +echo + +echo "Use 'make' to compile and 'make install' to install." +echo +echo "Errors may not be printed to stdout: see files 'make.log' " +echo " and 'install.log' for a complete error summary." +echo +echo "-----------------------------------------------------------" +echo + +dnl Put "defs.mak" in the top-level directory +cp defs.mak .. diff --git a/scripts/configure.in.orig b/scripts/configure.in.orig new file mode 100644 index 0000000..b1849fb --- /dev/null +++ b/scripts/configure.in.orig @@ -0,0 +1,1307 @@ +dnl Process this file with autoconf to produce a configure script. +dnl Use autoconf 2.52 or newer. + +AC_INIT(netgen, 1.3, magic-hackers@csl.cornell.edu) +AC_PREREQ(2.52) +AC_CONFIG_SRCDIR(rules.mak) +AC_CONFIG_AUX_DIR(.) + +AC_CANONICAL_SYSTEM + +dnl pass the version string on the the makefiles +PACKAGE=netgen +NETGEN_VERSION=`cat ../VERSION | cut -d. -f1-2` +NETGEN_REVISION=`cat ../VERSION | cut -d. -f3` +AC_DEFINE_UNQUOTED(NETGEN_VERSION, "${NETGEN_VERSION}") +AC_DEFINE_UNQUOTED(NETGEN_REVISION, "${NETGEN_REVISION}") + +dnl Override default target when compiling under TCL +ALL_TARGET="standard" +INSTALL_TARGET="install-netgen" + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_CPP +AC_ISC_POSIX +AC_PROG_INSTALL +AC_PROG_RANLIB + +dnl GNU M4 is preferred due to some of the option switches. +AC_PATH_PROGS([M4], [gm4 gnum4 m4], [no]) +if test x$M4 = xno; then + AC_MSG_ERROR([M4 is required]) +fi + +dnl check size of pointer for correct behavior on 64-bit systems +dnl If the C preprocessor is GCC, we need to force the flag to +dnl assert that input files are of type C, or else the preprocessing +dnl stage will not execute correctly on the ".in" files in the scmos +dnl directory. + +if test "$CPP" = "gcc -E" ; then + CPP="$CPP -x c" +fi + +dnl check if the linker is a GNU linker + +#------------------------------------------------------------ +# AC_PROG_LD - find the path to the GNU or non-GNU linker +# (This stuff ripped from libtool) +#------------------------------------------------------------ +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld assume the C compiler uses GNU ld [[default=no]]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +dnl ###not for PostgreSQL### AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case "$ac_prog" in + # Accept absolute paths. +changequote(,)dnl + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' +changequote([,])dnl + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(ac_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + ac_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + ac_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$ac_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_PROG_LD_GNU +]) + +AC_DEFUN([AC_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + ac_cv_prog_gnu_ld=yes +else + ac_cv_prog_gnu_ld=no +fi]) +with_gnu_ld=$ac_cv_prog_gnu_ld +]) + +AC_PROG_LD + +AC_CHECK_SIZEOF([void *], 4) +AC_CHECK_SIZEOF([unsigned int], 4) +AC_CHECK_SIZEOF([unsigned long], 4) +AC_CHECK_SIZEOF([unsigned long long], 8) + +dnl Check byte arrangement for doubleint routines +AC_C_BIGENDIAN + +dnl Check for required header files +AC_HEADER_STDC + +dnl Need either setenv or putenv +AC_CHECK_FUNCS(setenv putenv) + +dnl Check for vfork +AC_CHECK_FUNC(vfork) + +dnl Check for +AC_CHECK_HEADERS(dirent.h) + +dnl Check for +AC_CHECK_HEADERS(limits.h) + +dnl Check for +AC_CHECK_HEADERS(param.h) + +dnl Check for va_copy +AC_CACHE_CHECK([for va_copy], ac_cv_c_va_copy, + AC_TRY_LINK( + [#include ], + [va_list ap1, ap2; + va_copy(ap1,ap2); + ], + [ac_cv_c_va_copy="yes"], + [ac_cv_c_va_copy="no"]) + ) +if test "$ac_cv_c_va_copy" = "yes" +then + AC_DEFINE(HAVE_VA_COPY, 1, [Define if we have va_copy]) +fi +AC_CACHE_CHECK([for __va_copy], ac_cv_c___va_copy, + AC_TRY_LINK( + [#include ], + [va_list ap1, ap2; + __va_copy(ap1,ap2); + ], + [ac_cv_c___va_copy="yes"], + [ac_cv_c___va_copy="no"]) + ) +if test "$ac_cv_c___va_copy" = "yes" +then + AC_DEFINE(HAVE___VA_COPY, 1, [Define if we have __va_copy]) +fi + +# Note that it is essential to disable the DBUG packages, as it is +# not ANSI-compliant and won't compile without quite a bit of work. +AC_DEFINE(DBUG_OFF) + +extra_defs="$extra_defs -DCAD_DIR=\\\"\${LIBDIR}\\\"" +X_LIBS= +X_CFLAGS= +CPPFLAGS= +INC_SPECS= +DEPEND_FLAG= +SHLIB_CFLAGS="" +LD_RUN_PATH="" +WISH_EXE="" +TCLSH_EXE="" +CXX= + +modules="" +unused="" +cadinstall="" +extra_libs="" +other_srcs="" +top_extra_libs="" +sub_extra_libs="" +ld_extra_libs="" +ld_extra_objs="" +programs="" +rl_defs= +rl_libs= +gr_cflags= +gr_dflags= +gr_libs= +gr_srcs= +gr_hsrcs= +gr_hprog= + +netgen_with_tcl="yes" +netgen_with_tk="yes" +netgen_with_tcl_includes="" +netgen_with_tk_includes="" +netgen_with_tcl_libraries="" +netgen_with_tk_libraries="" + +dnl We will attempt to configure with Tcl/Tk and OpenGL. However, +dnl if checks for the appropriate header and library files fail, +dnl we will revert to non-Tcl and/or non-OpenGL compilation. +dnl Compilation for Tcl/Tk may be explicitly prohibited by using +dnl --with-tcl=no or --with-interpreter=no, and OpenGL may be +dnl disabled with --with-opengl=no + +usingTcl=1 +usingX11= + +dnl Compile-time options below. . . + +AC_ARG_WITH(interpreter, +[ --with-interpreter=[arg] enable interpreter], [ + if test "$withval" = "no" -o "$withval" = "NO"; then + usingTcl= + elif test "$withval" = "scheme" -o "$withval" = "SCHEME"; then + usingScheme=1 + usingTcl= + elif test "$withval" != "tcl" -a "$withval" != "TCL"; then + echo "Unknown option to --with-interpreter: Must be scheme, tcl, or no." + exit 1 + fi +], ) + +AC_ARG_WITH(tcl, +[ --with-tcl=DIR Find tclConfig.sh in DIR], [ + netgen_with_tcl=$withval + if test "$withval" = "no" -o "$withval" = "NO"; then + usingTcl= + elif test $usingScheme ; then + echo Attempt to enable both Tcl and Scheme interpreters. + echo Disabling Tcl, and using Scheme instead. + usingTcl= + fi +], ) + +dnl ---------------------------------------------------------------- +dnl Do our best to find Tcl/Tk. If we can't, then flag a warning +dnl and don't set the usingTcl variable. +dnl +dnl This has been broken up into a number of sections, each of which +dnl depends independently on the setting of usingTcl. +dnl ---------------------------------------------------------------- + +AC_ARG_WITH(tk, [ --with-tk=DIR Find tkConfig.sh in DIR], + netgen_with_tk=$withval) +AC_ARG_WITH(tclincls, [ --with-tclincls=DIR Find tcl.h in DIR], + netgen_with_tcl_includes=$withval) +AC_ARG_WITH(tkincls, [ --with-tkincls=DIR Find tk.h in DIR], + netgen_with_tk_includes=$withval) +AC_ARG_WITH(tcllibs, [ --with-tcllibs=DIR Find Tcl library in DIR], + netgen_with_tcl_libraries=$withval) +AC_ARG_WITH(tklibs, [ --with-tklibs=DIR Find Tk library in DIR], + netgen_with_tk_libraries=$withval) + +# ----------------------------------------------------------------------- +# Find the Tcl build configuration file "tclConfig.sh" +# ----------------------------------------------------------------------- + +if test $usingTcl ; then + TCL_INC_DIR="." + TK_INC_DIR="." + + AC_MSG_CHECKING([for tclConfig.sh]) + tcl_config_sh="" + + if test "$netgen_with_tcl" = "no" ; then + netgen_with_tcl="" + elif test "$netgen_with_tcl" != "yes" ; then + # + # Verify that a tclConfig.sh file exists in the directory specified + # by --with-tcl. + # + for dir in \ + $netgen_with_tcl + do + if test -r "$dir/tclConfig.sh" ; then + tcl_config_sh="$dir/tclConfig.sh" + break + elif test -r "$dir/lib/tclConfig.sh" ; then + tcl_config_sh="$dir/lib/tclConfig.sh" + break + elif test -r "$dir/unix/tclConfig.sh" ; then + tcl_config_sh="$dir/unix/tclConfig.sh" + break + fi + done + else + # + # Otherwise, search for Tcl configuration file. + # + + # 1. Search previously named locations. + + for dir in \ + $prefix \ + $exec_prefix + do + if test -r "$dir/tclConfig.sh" ; then + tcl_config_sh="$dir/tclConfig.sh" + break + elif test -r "$dir/lib/tclConfig.sh" ; then + tcl_config_sh="$dir/lib/tclConfig.sh" + break + elif test -r "$dir/unix/tclConfig.sh" ; then + tcl_config_sh="$dir/unix/tclConfig.sh" + break + fi + done + + # 2. Search standard locations. + + if test "x$tcl_config_sh" = "x" ; then + for dir in \ + `ls -dr /usr/local/tcl/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ + /usr/local/tcl \ + /usr/local/lib \ + /usr/local \ + `ls -dr /usr/lib/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ + /sw/lib \ + /usr/lib \ + /usr/lib64 \ + /usr + do + if test -r "$dir/tclConfig.sh" ; then + tcl_config_sh="$dir/tclConfig.sh" + break + elif test -r "$dir/lib/tclConfig.sh" ; then + tcl_config_sh="$dir/lib/tclConfig.sh" + break + fi + done + fi + fi + + AC_MSG_RESULT([${tcl_config_sh}]) + + if test "x$tcl_config_sh" = "x" ; then + echo "Can't find Tcl configuration script \"tclConfig.sh\"" + echo "Reverting to non-Tcl compilation" + usingTcl= + fi +fi + +# ----------------------------------------------------------------------- +# Find the Tk build configuration file "tkConfig.sh" +# ----------------------------------------------------------------------- + +if test $usingTcl ; then + + AC_MSG_CHECKING([for tkConfig.sh]) + tk_config_sh="" + if test "$netgen_with_tk" != "yes"; then + # + # Verify that a tkConfig.sh file exists in the directory specified + # by --with-tcl or --with-tk. + # + for dir in \ + $netgen_with_tk \ + $netgen_with_tcl + do + if test -r "$dir/tkConfig.sh" ; then + tk_config_sh="$dir/tkConfig.sh" + break + elif test -r "$dir/lib/tkConfig.sh" ; then + tk_config_sh="$dir/lib/tkConfig.sh" + break + elif test -r "$dir/unix/tkConfig.sh" ; then + tk_config_sh="$dir/unix/tkConfig.sh" + break + fi + done + else + # + # Search for Tk configuration file. + # + + # + # 1. Search previously named locations. + # + for dir in \ + $prefix \ + $exec_prefix + do + if test -r "$dir/tkConfig.sh" ; then + tk_config_sh="$dir/tkConfig.sh" + break + elif test -r "$dir/lib/tkConfig.sh" ; then + tk_config_sh="$dir/lib/tkConfig.sh" + break + elif test -r "$dir/unix/tkConfig.sh" ; then + tk_config_sh="$dir/unix/tkConfig.sh" + break + fi + done + # + # 2. Search standard locations. + # + if test "x$tk_config_sh" = "x" ; then + for dir in \ + /usr/local \ + /usr \ + `ls -dr /usr/local/lib/tk[[7-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr /usr/lib/tk[[7-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr /usr/local/tk/tk[[7-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr /usr/local/tk[[7-9]].[[0-9]]* 2>/dev/null` \ + /usr/local/tk \ + `ls -dr /usr/local/lib/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr /usr/lib/tcl/tk[[7-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr /usr/local/tcl/tcl[[7-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr /usr/share/tcltk/tk[[7-9]].[[0-9]]* 2>/dev/null` \ + /sw/lib \ + /usr/lib \ + /usr/lib64 \ + ${x_libraries} + do + if test -r "$dir/tkConfig.sh" ; then + tk_config_sh="$dir/tkConfig.sh" + break + elif test -r "$dir/lib/tkConfig.sh" ; then + tk_config_sh="$dir/lib/tkConfig.sh" + break + fi + done + fi + fi + AC_MSG_RESULT([${tk_config_sh}]) + + if test "x$tk_config_sh" = "x" ; then + echo "can't find Tk configuration script \"tkConfig.sh\"" + echo "Reverting to non-Tcl compilation" + usingTcl= + fi +fi + +# ----------------------------------------------------------------------- +# Source in the Tcl/Tk configuration scripts. +# ----------------------------------------------------------------------- + +if test $usingTcl ; then + . $tcl_config_sh + . $tk_config_sh + + if test "$TCL_VERSION" = "7.6" -a "$TK_VERSION" = "4.2" ; then + : + elif test "$TCL_VERSION" = "7.5" -a "$TK_VERSION" = "4.1" ; then + : + elif test "$TCL_VERSION" = "$TK_VERSION" ; then + : + else + echo "Mismatched Tcl/Tk versions ($TCL_VERSION != $TK_VERSION)" + echo "Reverting to non-Tcl compile" + usingTcl= + fi +fi + +if test $usingTcl ; then + if test "x${netgen_with_tcl_includes}" != "x" ; then + if test -r "${netgen_with_tcl_includes}/tcl.h" ; then + TCL_INC_DIR=${netgen_with_tcl_includes} + else + echo "Can't find tcl.h in \"${netgen_with_tcl_includes}\"" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + else + for dir in \ + ${TCL_PREFIX}/include/tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION} \ + ${TCL_PREFIX}/include \ + ${TCL_SRC_DIR}/generic \ + ${TCL_INC_DIR} + do + if test -r "$dir/tcl.h" ; then + TCL_INC_DIR=$dir + break + fi + done + if test "x${TCL_INC_DIR}" = "x" ; then + echo "Can't find tcl.h header file" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + fi +fi + +if test $usingTcl ; then + if test "x${netgen_with_tk_includes}" != "x" ; then + if test -r "${netgen_with_tk_includes}/tk.h" ; then + TK_INC_DIR=${netgen_with_tk_includes} + else + echo "Can't find tk.h in \"${netgen_with_tk_includes}\"" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + else + for dir in \ + ${TK_PREFIX}/include/tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION} \ + ${TK_PREFIX}/include \ + ${TK_SRC_DIR}/generic \ + ${TK_INC_DIR} \ + ${TCL_INC_DIR} + do + if test -r "$dir/tk.h" ; then + TK_INC_DIR=$dir + break + fi + done + if test "x${TK_INC_DIR}" = "x" ; then + echo "Can't find tk.h header file" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + fi +fi + +if test $usingTcl ; then + case $target in + *-sunos4*|*-*-netbsd*|NetBSD-*|FreeBSD-*|OpenBSD-*) + TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}" + TK_LIB_NAME="tk${TK_MAJOR_VERSION}${TK_MINOR_VERSION}" + ;; + *) + TCL_LIB_NAME="tcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}" + TK_LIB_NAME="tk${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}" + ;; + esac + + loclib=`echo ${TCL_LIB_SPEC} | sed -e 's/.*-L//' -e 's/ .*//'` + + if test "x${TCL_LIB_SPEC}" = "x" ; then + TCL_LIB_SPEC="-l${TCL_LIB_NAME}" + fi + if test "x${TK_LIB_SPEC}" = "x" ; then + TK_LIB_SPEC="-l${TK_LIB_NAME}" + fi + +# Find the version of "wish" that corresponds to TCL_EXEC_PREFIX +# We really ought to run "ldd" to confirm that the linked libraries match. + + AC_MSG_CHECKING([for wish executable]) + for dir in \ + ${TK_EXEC_PREFIX}/bin \ + ${TK_EXEC_PREFIX} + do + for wishexe in \ + wish \ + wish${TK_VERSION} \ + wish.exe \ + wish${TK_VERSION}.exe + do + if test -r "$dir/$wishexe" ; then + WISH_EXE=$dir/$wishexe + break + fi + done + if test "x${WISH_EXE}" != "x" ; then + break + fi + done + if test "x${WISH_EXE}" = "x" ; then + echo "Warning: Can't find executable for \"wish\". You may have to" + echo "manually set the value for WISH_EXE in the netgen startup script." + AC_MSG_RESULT(no) + else + AC_MSG_RESULT([${WISH_EXE}]) + fi + +# Find the version of "tclsh" that corresponds to TCL_EXEC_PREFIX + + AC_MSG_CHECKING([for tclsh executable]) + for dir in \ + ${TK_EXEC_PREFIX}/bin \ + ${TK_EXEC_PREFIX} + do + for tclshexe in \ + tclsh \ + tclsh${TK_VERSION} \ + tclsh.exe \ + tclsh${TK_VERSION}.exe + do + if test -r "$dir/$tclshexe" ; then + TCLSH_EXE=$dir/$tclshexe + break + fi + done + if test "x${TCLSH_EXE}" != "x" ; then + break; + fi + done + if test "x${TCLSH_EXE}" = "x" ; then + echo "Warning: Can't find executable for \"tclsh\"." + AC_MSG_RESULT(no) + else + AC_MSG_RESULT([${TCLSH_EXE}]) + fi + +# Have to define SHDLIB_EXT here even though we have to do it below, too. + case $target in + *-hpux*) + SHDLIB_EXT=".sl" + SHDLIB_EXT_ALT=".sl" + ;; + *cygwin*) + SHDLIB_EXT=".dll" + SHDLIB_EXT_ALT=".dll.a" + ;; + *darwin*) + SHDLIB_EXT=".dylib" + SHDLIB_EXT_ALT=".dylib" + ;; + *) + SHDLIB_EXT=".so" + SHDLIB_EXT_ALT=".so" + ;; + esac + + if test "x${netgen_with_tcl_libraries}" != "x" ; then + for libname in \ + "${netgen_with_tcl_libraries}/lib${TCL_LIB_FILE}" \ + "${netgen_with_tcl_libraries}/lib${TCL_LIB_NAME}${SHDLIB_EXT}" \ + "${netgen_with_tcl_libraries}/lib${TCL_LIB_NAME}${SHDLIB_EXT_ALT}" + do + if test -r "$libname" ; then + TCL_LIB_DIR="${netgen_with_tcl_libraries}" + break + fi + done + + if test "x${TCL_LIB_DIR}" = "x" ; then + echo "Can't find tcl library in \"${netgen_with_tcl_libraries}\"" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + else + for libname in \ + "${loclib:=${TCL_EXEC_PREFIX}/lib}/lib${TCL_LIB_NAME}${SHDLIB_EXT}" \ + "${loclib:=${TCL_EXEC_PREFIX}/lib64}/lib${TCL_LIB_NAME}${SHDLIB_EXT}" \ + "${loclib:=${TCL_EXEC_PREFIX}/lib}/lib${TCL_LIB_NAME}${SHDLIB_EXT_ALT}" + do + if test -r "$libname" ; then + TCL_LIB_DIR="${TCL_EXEC_PREFIX}/lib" + break + fi + done + if test "x${TCL_LIB_DIR}" = "x" ; then + echo "Can't find tcl library" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + fi +fi + +if test $usingTcl ; then + if test "x${netgen_with_tk_libraries}" != "x" ; then + for libname in \ + "${netgen_with_tk_libraries}/${TCL_LIB_FILE}" \ + "${netgen_with_tk_libraries}/lib${TK_LIB_NAME}${SHDLIB_EXT}" \ + "${netgen_with_tk_libraries}/lib${TK_LIB_NAME}${SHDLIB_EXT_ALT}" + do + if test -r "$libname" ; then + TK_LIB_DIR="${netgen_with_tk_libraries}" + break + fi + done + if test "x${TK_LIB_DIR}" = "x" ; then + echo "Can't find tk library in \"${netgen_with_tk_libraries}\"" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + else + for libname in \ + "${loclib:=${TK_EXEC_PREFIX}/lib}/lib${TK_LIB_NAME}${SHDLIB_EXT}" \ + "${loclib:=${TK_EXEC_PREFIX}/lib}/lib${TK_LIB_NAME}${SHDLIB_EXT_ALT}" \ + "${loclib:=${TK_EXEC_PREFIX}/lib64}/lib${TK_LIB_NAME}${SHDLIB_EXT}" + do + if test -r "$libname" ; then + TK_LIB_DIR="${TK_EXEC_PREFIX}/lib" + break + fi + done + if test "x${TK_LIB_DIR}" = "x" ; then + echo "Can't find tk library" + echo "Reverting to non-Tcl compile" + usingTcl= + fi + fi +fi + +dnl ---------------------------------------------------- +dnl End of Tcl/Tk search +dnl ---------------------------------------------------- + +dnl The X11 version of the non-Tcl-based netgen is so awful +dnl we don't really want to advertise it. So, you have to +dnl specifically do "--with-widgets=" to get HAVE_X11 set; +dnl otherwise, you get the command-line interface, which is +dnl much more pleasant. + +AC_ARG_WITH(widgets, +[ --with-widgets=[arg] select widget set], [ + if test "$withval" = "xw" -o "$withval" = "Xw"; then + usingX11=1 + usingTcl= + gr_dflags="${gr_dflags} -DHAVE_X11 -DX11_HP_WIDGETS" + gr_libs="${gr_libs} -lXw -lXt" + elif test "$withval" = "Xm" -o "$withval" = "Motif"; then + usingX11=1 + usingTcl= + gr_dflags="${gr_dflags} -DHAVE_X11 -DX11_MOTIF_WIDGETS" + gr_libs="${gr_libs} -lXm -lXt" + else + usingX11=1 + usingTcl= + gr_dflags="${gr_dflags} -DHAVE_X11 -DX11_ATHENA_WIDGETS" + gr_libs="${gr_libs} -lXaw -lXmu -lXt -lXext" + fi +], ) + +dnl Check for X enabled/disabled + +AC_PATH_XTRA +if test "x$no_x" != "x"; then + if test $usingX11 ; then + echo Cannot find X11---will attempt to compile anyway. + echo Graphics options will be NULL only! + usingX11= + fi + if test $usingTcl ; then + echo "Cannot compile TCL version without X11, disabling." + usingTcl= + fi +fi + +dnl ---------------------------------------------------------------- +dnl Once we're sure what, if any, interpreter is being compiled, +dnl set all the appropriate definitions. For Tcl/Tk, override +dnl the default install targets: allows compiling tcl version with +dnl "make" instead of requiring "make tcl" +dnl ---------------------------------------------------------------- + +if test $usingTcl ; then + usingX11=1 + cadinstall="$cadinstall tcltk" + modules="$modules tcltk" + programs="$programs tcltk" + ALL_TARGET="tcl" + INSTALL_TARGET="install-tcl" + AC_DEFINE(TCL_NETGEN) + extra_libs="$extra_libs \${NETGENDIR}/tcltk/libtcltk.o" + extra_defs="$extra_defs -DTCL_DIR=\\\"\${TCLDIR}\\\"" +else + programs="$programs netgen" + unused="$unused tcltk" +fi + +dnl If usingAthena is set, and we are using X11, then no widget +dnl set has been selected with "--with-widgets", so we default +dnl to the X11 Athena widget set. + +dnl ---------------------------------------------------------------- +dnl Handle graphics based on the setting of "usingTcl", "usingX11", +dnl "usingOGL", and "usingBLT" +dnl ---------------------------------------------------------------- + +if test $usingTcl ; then + if test $usingX11 ; then + gr_dflags="$gr_dflags -DX11 -DXLIB" + gr_libs="$gr_libs -lX11" + gr_srcs="$gr_srcs \${TK_SRCS}" + else + gr_srcs="$gr_srcs \${NULL_SRCS}" + fi +else + if test $usingX11 ; then + gr_dflags="$gr_dflags -DX11 -DXLIB" + gr_libs="$gr_libs -lX11" + gr_srcs="$gr_srcs \${X11_SRCS}" + fi +fi + +dnl ---------------------------------------------------------------- +dnl Define system-specific settings +dnl ---------------------------------------------------------------- + +case $target in + *-linux*) + AC_DEFINE(linux) + AC_DEFINE(SYSV) + dnl Defining "ISC" prevents compiler failure on redefinition of "wchar_t" + AC_DEFINE(ISC) + dnl 64-bit support for AMD Opteron + case $target in + *x86_64*) + CFLAGS="${CFLAGS} -m64 -fPIC" + ;; + esac + if test -f /usr/lib/libbsd-compat.a ; then + gr_libs="$gr_libs -lbsd-compat" + elif test -f /usr/lib/libbsd.a ; then + gr_libs="$gr_libs -lbsd" + fi + ;; + *solaris*) + AC_DEFINE(SYSV) + ;; + *irix*) + AC_DEFINE(SYSV) + AC_DEFINE(IRIX) + AC_DEFINE(_BSD_SIGNALS) + ;; + *sysv*) + AC_DEFINE(SYSV) + ;; + *cygwin*) + AC_DEFINE(CYGWIN) + AC_DEFINE(i386) + AC_DEFINE(WIN32) + ;; + *darwin*) + AC_DEFINE(macosx) + if test "$CPP" = "cc -E" ; then + CPPFLAGS="$CPPFLAGS -no-cpp-precomp" + fi + ;; +esac +# ----------------------------------------------------------------------- +# Tcl/Tk configuration +# ----------------------------------------------------------------------- + +if test $usingTcl ; then + +# ----------------------------------------------------------------------- +# +# Tk libraries and header files +# +# ----------------------------------------------------------------------- + if test "${TK_INC_DIR}" != "/usr/include" ; then + INC_SPECS="${INC_SPECS} -I${TK_INC_DIR}" + fi + if test "${TK_LIB_DIR}" = "/usr/lib" -o \ + "${TK_LIB_DIR}" = "/usr/lib64" ; then + LIB_SPECS="${LIB_SPECS} ${TK_LIB_SPEC}" + else + LIB_SPECS="${LIB_SPECS} -L${TK_LIB_DIR} ${TK_LIB_SPEC}" + if test "x${loader_run_path}" = "x" ; then + loader_run_path="${TK_LIB_DIR}" + else + loader_run_path="${TK_LIB_DIR}:${loader_run_path}" + fi + fi + +# ----------------------------------------------------------------------- +# +# Tcl libraries and header files +# +# Add a header file directory specification only if the Tcl headers reside +# in a different directory from Tk's. +# +## ----------------------------------------------------------------------- + if test "${TCL_INC_DIR}" != "/usr/include" -a \ + "${TCL_INC_DIR}" != "${TK_INC_DIR}" ; then + INC_SPECS="${INC_SPECS} -I${TCL_INC_DIR}" + fi + + if test "${TCL_LIB_DIR}" = "/usr/lib" -o \ + "${TCL_LIB_DIR}" = "/usr/lib64" -o \ + "${TCL_LIB_DIR}" = "${TK_LIB_DIR}" ; then + LIB_SPECS="${LIB_SPECS} ${TCL_LIB_SPEC}" + else + LIB_SPECS="${LIB_SPECS} -L${TCL_LIB_DIR} ${TCL_LIB_SPEC}" + if test "x${loader_run_path}" = "x" ; then + loader_run_path="${TCL_LIB_DIR}" + else + loader_run_path="${TCL_LIB_DIR}:${loader_run_path}" + fi + fi + +#-------------------------------------------------------------------- +# +# Check if we can generate shared libraries on this system. Set flags +# to generate shared libraries for systems that we know about. Start +# with the values found in tclConfig.sh, make changes as we know about +# the different systems. +# +#-------------------------------------------------------------------- + +# Initialize shared library build variables + + SHLIB_LD="" + LDDL_FLAGS="-shared" + SHDLIB_EXT=".so" + EXTRA_LIB_SPECS="" + + build_shared="yes" + + case $target in + *-aix4.[[2-9]]*) + # No Position-Independent flags needed + + # Use the installed export file or the one found in the source directory. + + if test -r "${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" ; then + tcl_exp="${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" + else + tcl_exp="${TCL_SRC_DIR}/unix/lib.exp" + fi + if test -r "${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" ; then + tk_exp="${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" + else + tk_exp="${TK_SRC_DIR}/unix/lib.exp" + fi + + full_src_path=`cd ${srcdir}; pwd` + + # Use shell-script to link shared library + LD="${full_src_path}/cf/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry -bI:${tk_exp} -bI:${tcl_exp}" + + SHLIB_LIB_SPECS="${aix_lib_specs} -lc" + + LDFLAGS="-L${loader_run_path}" + EXTRA_LIB_SPECS="-ldl" + ;; + + *-aix*) + # No Position-Independent flags needed + + # Use the installed export file or the one found in the source directory. + + if test -r "${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" ; then + tcl_exp="${TCL_LIB_DIR}/lib${TCL_LIB_NAME}.exp" + else + tcl_exp="${TCL_SRC_DIR}/unix/lib.exp" + fi + if test -r "${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" ; then + tk_exp="${TK_LIB_DIR}/lib${TK_LIB_NAME}.exp" + else + tk_exp="${TK_SRC_DIR}/unix/lib.exp" + fi + + full_src_path=`cd ${srcdir}/cf; pwd` + + # Use shell-script to link shared library + + LD="${full_src_path}/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry -bI:${tk_exp} -bI:${tcl_exp}" + SHLIB_LIB_SPECS="${aix_lib_specs} -lc" + LDFLAGS="-L${loader_run_path}" + EXTRA_LIB_SPECS="-lld" + ;; + + *-bsdi2*|*-bsdi3*) + LD="shlicc" + LDDL_FLAGS="-r" + EXTRA_LIB_SPECS="-ldl" + ;; + + *darwin*) + SHDLIB_EXT=".dylib" + LDDL_FLAGS="-dynamiclib -flat_namespace -undefined suppress -noprebind" + LDFLAGS="${LDFLAGS} ${LIB_SPECS}" + CFLAGS="${CFLAGS} ${X_CFLAGS} ${INC_SPECS} -I/sw/include -fno-common" + ;; + + *cygwin*) + SHDLIB_EXT=".dll" + AC_DEFINE(USE_DL_IMPORT) + LDDL_FLAGS='-shared -Wl,--enable-auto-image-base' + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + ld_extra_libs=${LIB_SPECS} + sub_extra_libs='-L${NETGENDIR}/netgen -ltclnetgen' + ;; + + *-bsdi4*) + SHLIB_CFLAGS="-export-dynamic -fPIC" + LDDL_FLAGS='-shared -Wl,-E -Wl,-soname,$@' + ;; + + *-dgux*) + SHLIB_CFLAGS="-K PIC" + LDDL_FLAGS="-G" + EXTRA_LIB_SPECS="-ldl" + ;; + + *-hpux*) + if test "$GCC" = "no" ; then + AC_DEFINE(_HPUX_SOURCE) + fi + AC_CHECK_LIB(dld, shl_load, [found=yes], [found=no]) + if test "${found}" = "yes" ; then + SHLIB_CFLAGS="+z" + LDDL_FLAGS="-b -E -n +s +b,${loader_run_path}:." + SHDLIB_EXT=".sl" + + # The run path is included in both LDFLAGS and LDDL_FLAGS + # because SHLIB_LD is ld and LD is cc/gcc. + + LDFLAGS="-Wl,-E -Wl,+s,+b,${loader_run_path}:." + EXTRA_LIB_SPECS="-ldld" + fi + ;; + + *-irix64-6.5*) + LDDL_FLAGS="-32 -shared -rdata_shared" + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + ;; + + *-irix-[56].*|*-irix64-*) + LDDL_FLAGS="-shared -rdata_shared" + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + LDFLAGS="" + if test "$GCC" = "yes" ; then + SHLIB_CFLAGS="-mabi=n32 $SHLIB_CFLAGS" + LDDL_FLAGS="-mabi=n32 $LDDL_FLAGS" + LDFLAGS="-mabi=n32 $LDFLAGS" + else + CFLAGS="-n32 $CFLAGS" + LDFLAGS="-n32 $LDFLAGS" + fi + ;; + + *-linux*) + LDDL_FLAGS=' -shared -Wl,-soname,$@' + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + LDFLAGS="" + EXTRA_LIB_SPECS="-ldl" + ;; + + *-mp-ras-02*) + SHLIB_CFLAGS="-G -K PIC" + LDDL_FLAGS="" + ;; + + *-mp-ras-*) + SHLIB_CFLAGS="-G -K PIC" + LDDL_FLAGS="-Wl,-Bexport" + ;; + + *-ncr-sysv4-*2*) + SHLIB_CFLAGS="-K PIC" + LDDL_FLAGS="-G" + + EXTRA_LIB_SPECS="-ldl" + ;; + + *-ncr-sysv4*) + SHLIB_CFLAGS="-K PIC" + LDDL_FLAGS="-G -Wl,-Bexport" + + LDFLAGS="-Wl,-Bexport" + EXTRA_LIB_SPECS="-ldl" + ;; + + *-freebsd*) + # Not available on all versions: check for include file. + SHLIB_CFLAGS="-fpic" + LDDL_FLAGS="-shared ${LIB_SPECS}" + CFLAGS="${CFLAGS} -l/usr/X11R6/include" + ;; + + *-netbsd*|*-openbsd*) + # Not available on all versions: check for include file. + AC_CHECK_HEADER(dlfcn.h, test_ok=yes, test_ok=no) + if test "$test_ok" = yes; then + SHLIB_CFLAGS="-fPIC" + LDDL_FLAGS="-shared ${LIB_SPEC}" + fi + ;; + + *-nextstep*) + LDDL_FLAGS="-nostdlib -r" + ;; + + *-osf1-1.[012]*) + # OSF/1 1.[012] from OSF, and derivatives, including Paragon OSF/1 + + # Warning: Ugly Makefile Hack + # Make package name same as library name + + SHLIB_LD='ld -R -export $@:' + ;; + + *-osf1-1.*) + # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2 + + SHLIB_CFLAGS="-fpic" + SHLIB_LD="ld -shared" + ;; + + *-osf1V*) + # Digital OSF/1 + + LDDL_FLAGS='-shared -expect_unresolved "*"' + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + LDFLAGS="" + ;; + + *-sco*) + # Note, dlopen is available only on SCO 3.2.5 and greater. However, + # this test works, since "uname -s" was non-standard in 3.2.4 and + # below. + + SHLIB_CFLAGS="-Kpic -belf" + LDDL_FLAGS="-G" + LDFLAGS="-belf -Wl,-Bexport" + ;; + + *-sni-sysv*) + + SHLIB_CFLAGS="-K PIC" + LDDL_FLAGS="-G" + + EXTRA_LIB_SPECS="-ldl" + ;; + + *-sunos4*) + + SHLIB_CFLAGS="-PIC" + LDDL_FLAGS="-assert pure-text" + + EXTRA_LIB_SPECS="-ldl" + ;; + + *-solaris2*) + + if test "$with_gnu_ld" = "yes" ; then + LDDL_FLAGS='-shared -Wl,-E -Wl,-soname,$@ ${LIB_SPEC}' + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -Wl,-rpath,${loader_run_path}" + fi + else + LDDL_FLAGS="-shared -mimpure-text" + if test "x${loader_run_path}" != "x" ; then + LD_RUN_PATH="${LD_RUN_PATH} -R ${loader_run_path}" + fi + fi + EXTRA_LIB_SPECS="-ldl" + ;; + + *-mips-dde-sysv*) + + SHLIB_CFLAGS="-KPIC" + LDDL_FLAGS="-G" + + EXTRA_LIB_SPECS="-ldl" + ;; + + *-pc-sysv4* | *-unixware-5*) + SHLIB_CFLAGS="-G -KPIC" + LDDL_FLAGS=" -Wl,-Bexport" + ;; + + esac + +# If we're running gcc, then set SHLIB_CFLAGS flags for compiling +# shared libraries for gcc, instead of those of the vendor's compiler. + + if test "$GCC" = "yes" ; then + case $target in + *cygwin*) + ;; + *) + SHLIB_CFLAGS="-fPIC" + ;; + esac + fi + if test "$with_gnu_ld" = "yes" ; then + LDDL_FLAGS="${LDDL_FLAGS} -Wl,--version-script=\${NETGENDIR}/netgen/symbol.map" + fi + + AC_SUBST(SHDLIB_EXT) + AC_SUBST(SHLIB_LD) + AC_SUBST(LD) + AC_SUBST(LDDL_FLAGS) + AC_SUBST(SHLIB_LIB_SPECS) + + AC_SUBST(EXTRA_LIB_SPECS) + AC_SUBST(LDFLAGS) + AC_SUBST(INC_SPECS) + AC_SUBST(LIB_SPECS) + AC_SUBST(WISH_EXE) + AC_SUBST(TCLSH_EXE) + AC_SUBST(TCL_LIB_DIR) + +fi + +if test "$GCC" = "yes" ; then + DEPEND_FLAG="-MM" +fi + +dnl Substitute all variables + +AC_SUBST(VERSION) +AC_SUBST(PACKAGE) +AC_SUBST(SCRIPTS) +AC_SUBST(extra_libs) +AC_SUBST(extra_defs) +AC_SUBST(ld_extra_libs) +AC_SUBST(ld_extra_objs) +AC_SUBST(top_extra_libs) +AC_SUBST(sub_extra_libs) +AC_SUBST(modules) +AC_SUBST(unused) +AC_SUBST(programs) +AC_SUBST(cadinstall) + +AC_SUBST(gr_cflags) +AC_SUBST(gr_dflags) +AC_SUBST(gr_libs) +AC_SUBST(gr_srcs) + +AC_SUBST(X_LIBS) +AC_SUBST(X_CFLAGS) +AC_SUBST(CPPFLAGS) +AC_SUBST(CFLAGS) +AC_SUBST(DEPEND_FLAG) +AC_SUBST(SHLIB_CFLAGS) +AC_SUBST(LD_RUN_PATH) + +AC_SUBST(ALL_TARGET) +AC_SUBST(INSTALL_TARGET) + +AC_OUTPUT(defs.mak) + +dnl +dnl Print configuration and report problems + +ECHO_N=printf + +echo +echo "-----------------------------------------------------------" +echo "Configuration Summary (principle requirements):" +echo + +${ECHO_N} "Tcl/Tk: " +if test $usingTcl ; then + echo "yes" +else + echo "no" + echo + echo " Without Tcl/Tk, you cannot run the enhanced version of netgen" + echo " with scripting ability, console window, convenience commands" + echo " such as \"lvs\", and other useful features. If you did not" + echo " specifically disable Tcl/Tk on the configure command line, then" + echo " getting this message means that you do not have Tcl/Tk headers" + echo " and/or libraries installed, or they are not in a standard path." + echo " Try using configure options --with-tcl= and --with-tk=." + echo +fi + +echo "-----------------------------------------------------------" +echo + +echo "Use 'make' to compile and 'make install' to install." +echo +echo "Errors may not be printed to stdout: see files 'make.log' " +echo " and 'install.log' for a complete error summary." +echo +echo "-----------------------------------------------------------" +echo + +dnl Put "defs.mak" in the top-level directory +cp defs.mak .. diff --git a/scripts/defs.mak b/scripts/defs.mak new file mode 100644 index 0000000..1c132da --- /dev/null +++ b/scripts/defs.mak @@ -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} diff --git a/scripts/defs.mak.in b/scripts/defs.mak.in new file mode 100644 index 0000000..aa52464 --- /dev/null +++ b/scripts/defs.mak.in @@ -0,0 +1,82 @@ +# defs.mak.in -- +# source file for autoconf-generated "defs.mak" for netgen + +# @configure_input@ +# Feel free to change the values in here to suit your needs. +# Be aware that running scripts/configure again will overwrite +# any changes! + +SHELL = @SHELL@ + +prefix = ${BUILDROOT}@prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +libdir = @libdir@ +mandir = @mandir@ + +VERSION = @VERSION@ + +SCRIPTS = ${NETGENDIR}/scripts + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ + +# Override standard "make" target when compiling under TCL +ALL_TARGET = @ALL_TARGET@ +INSTALL_TARGET = @INSTALL_TARGET@ + +# 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 = @extra_libs@ +LD_EXTRA_LIBS = @ld_extra_libs@ +LD_SHARED = @ld_extra_objs@ +TOP_EXTRA_LIBS = @top_extra_libs@ +SUB_EXTRA_LIBS = @sub_extra_libs@ + +MODULES += @modules@ +UNUSED_MODULES += @unused@ +PROGRAMS += @programs@ +INSTALL_CAD_DIRS += @cadinstall@ + +RM = rm -f +CP = cp +AR = @AR@ +ARFLAGS = crv +LINK = @LD@ -r +LD = @LD@ +M4 = @M4@ +RANLIB = @RANLIB@ +SHDLIB_EXT = @SHDLIB_EXT@ +LDDL_FLAGS = @LDDL_FLAGS@ +LD_RUN_PATH = @LD_RUN_PATH@ +LIB_SPECS = @LIB_SPECS@ +WISH_EXE = @WISH_EXE@ +TCL_LIB_DIR = @TCL_LIB_DIR@ + +CC = @CC@ +CPP = @CPP@ +CXX = @CXX@ + +CPPFLAGS = -I. -I${NETGENDIR} @CPPFLAGS@ +DFLAGS = @extra_defs@ @DEFS@ -DSHDLIB_EXT=\"@SHDLIB_EXT@\" -DNDEBUG +CFLAGS = @CFLAGS@ @SHLIB_CFLAGS@ @INC_SPECS@ + +DEPEND_FILE = Depend +DEPEND_FLAG = @DEPEND_FLAG@ +EXEEXT = @EXEEXT@ + +GR_CFLAGS = @X_CFLAGS@ @gr_cflags@ +GR_DFLAGS = @gr_dflags@ -DNDEBUG +GR_LIBS = @gr_libs@ @X_LIBS@ +GR_SRCS = @gr_srcs@ + +OBJS = ${SRCS:.c=.o} +LIB_OBJS = ${LIB_SRCS:.c=.o} +CLEANS = ${OBJS} ${LIB_OBJS} lib${MODULE}.a lib${MODULE}.o ${MODULE} diff --git a/scripts/install-sh b/scripts/install-sh new file mode 100755 index 0000000..e9de238 --- /dev/null +++ b/scripts/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/scripts/makedbh b/scripts/makedbh new file mode 100755 index 0000000..3338a35 --- /dev/null +++ b/scripts/makedbh @@ -0,0 +1,187 @@ +#!/bin/csh -f +# +# makes the "database.h" (1st argument, $1) file from "database.h.in" +# (2nd argument, $2), setting various mask operation definitions +# according to the number of words implied by the value of TT_MAXTYPES + +# The following mess grabs the value of TT_MAXTYPES from database.h.in +# +set maxtypes=`sed -n -e '/^#define[[:space:]]*TT_MAXTYPES/s/#define[[:space:]]*TT_MAXTYPES[[:space:]]*//p' < $1 | sed -e 's/\/\*[[:print:]]*\*\/[[:space:]]*//g' ` +# +# Alternative method works with outdated versions of sed/ed. +# +if ($maxtypes == "") then + set maxtypes=`sed -n -e '/^#define[ ]*TT_MAXTYPES/s/#define[ ]*TT_MAXTYPES[ ]*//p' < $1 | sed -e 's/\/\*.*\*\/[ ]*//g' ` +endif +# +# If we can't generate database.h correctly, nothing is going to compile. +# +if ($maxtypes == "") then + echo "Bad sed script in scripts/makedbh: Cannot generate database/database.h!" + exit +endif + +# Find derived values from bits per word +# Note that bits-per-word should be determined from the compiler, but +# 32 bits per word has always been hardwired into magic. +# +set bpw = 32 + +# @ wordmask=$bpw - 1 +# set wordshift=`echo "c=l($bpw); d=l(2); scale=0; c/d" | bc -l` +# @ maskwords=$maxtypes + $bpw - 1 +# @ maskwords/=$bpw + +@ maskwords=$maxtypes + $bpw - 1 +@ maskwords/=$bpw + + +# Generate the main part of the database.h file from database.h.in +cat $1 > $2 + +# Generate a list of integers from 0 to the value of "maskwords" - 1 +set count="" +@ maskwords-- +while (${maskwords} >= 0) + set count=`echo ${count} ${maskwords}` + @ maskwords-- +end + +# Definitions + +echo "#define TTMaskZero(m) ( \" >> $2 +foreach i (${count}) + echo -n " (m)->tt_words[$i] = 0" >> $2 + if ($i == 0) then + echo ")" >> $2 + echo "" >> $2 + else + echo ", \" >> $2 + endif +end + +echo "#define TTMaskIsZero(m) ( \" >> $2 +foreach i (${count}) + echo -n " (m)->tt_words[$i] == 0" >> $2 + if ($i == 0) then + echo ")" >> $2 + echo "" >> $2 + else + echo " && \" >> $2 + endif +end + +echo "#define TTMaskEqual(m, n) ( \" >> $2 +foreach i (${count}) + echo -n " (m)->tt_words[$i] == (n)->tt_words[$i]" >> $2 + if ($i == 0) then + echo ")" >> $2 + echo "" >> $2 + else + echo " && \" >> $2 + endif +end + +echo "#define TTMaskIntersect(m, n) ( \" >> $2 +foreach i (${count}) + echo -n " ((m)->tt_words[$i] & (n)->tt_words[$i])" >> $2 + if ($i == 0) then + echo ")" >> $2 + echo "" >> $2 + else + echo " || \" >> $2 + endif +end + +echo "#define TTMaskCom(m) ( \" >> $2 +foreach i (${count}) + echo -n " ((m)->tt_words[$i] = ~(m)->tt_words[$i])" >> $2 + if ($i == 0) then + echo ")" >> $2 + echo "" >> $2 + else + echo ", \" >> $2 + endif +end + +echo "#define TTMaskCom2(m, n) ( \" >> $2 +foreach i (${count}) + echo -n " ((m)->tt_words[$i] = ~(n)->tt_words[$i])" >> $2 + if ($i == 0) then + echo ")" >> $2 + echo "" >> $2 + else + echo ", \" >> $2 + endif +end + +echo "#define TTMaskSetMask(m, n) ( \" >> $2 +foreach i (${count}) + echo -n " ((m)->tt_words[$i] |= (n)->tt_words[$i])" >> $2 + if ($i == 0) then + echo ")" >> $2 + echo "" >> $2 + else + echo ", \" >> $2 + endif +end + +echo "#define TTMaskSetMask3(m, n, o) ( \" >> $2 +foreach i (${count}) + echo -n " ((m)->tt_words[$i] |= (n)->tt_words[$i] | (o)->tt_words[$i])" \ + >> $2 + if ($i == 0) then + echo ")" >> $2 + echo "" >> $2 + else + echo ", \" >> $2 + endif +end + +echo "#define TTMaskAndMask(m, n) ( \" >> $2 +foreach i (${count}) + echo -n " ((m)->tt_words[$i] &= (n)->tt_words[$i])" >> $2 + if ($i == 0) then + echo ")" >> $2 + echo "" >> $2 + else + echo ", \" >> $2 + endif +end + +echo "#define TTMaskAndMask3(m, n, o) ( \" >> $2 +foreach i (${count}) + echo -n " ((m)->tt_words[$i] = (n)->tt_words[$i] & (o)->tt_words[$i])" \ + >> $2 + if ($i == 0) then + echo ")" >> $2 + echo "" >> $2 + else + echo ", \" >> $2 + endif +end + +echo "#define TTMaskClearMask(m, n) ( \" >> $2 +foreach i (${count}) + echo -n " ((m)->tt_words[$i] &= ~(n)->tt_words[$i])" >> $2 + if ($i == 0) then + echo ")" >> $2 + echo "" >> $2 + else + echo ", \" >> $2 + endif +end + +echo "#define TTMaskClearMask3(m, n, o) ( \" >> $2 +foreach i (${count}) + echo -n " ((m)->tt_words[$i] = (n)->tt_words[$i] & ~(o)->tt_words[$i])" \ + >> $2 + if ($i == 0) then + echo ")" >> $2 + else + echo ", \" >> $2 + endif +end + +echo "" >> $2 +echo "#endif /* _DATABASE_H */" >> $2 diff --git a/scripts/missing b/scripts/missing new file mode 100755 index 0000000..0a7fb5a --- /dev/null +++ b/scripts/missing @@ -0,0 +1,283 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright 1996, 1997, 1999, 2000 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# 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 2, 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., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch]" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing 0.3 - GNU automake" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then + # We have makeinfo, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + tar) + shift + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + fi + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar ${1+"$@"} && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar ${1+"$@"} && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" ${1+"$@"} && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" ${1+"$@"} && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/scripts/mkdirs b/scripts/mkdirs new file mode 100755 index 0000000..b0057ab --- /dev/null +++ b/scripts/mkdirs @@ -0,0 +1,32 @@ +#!/bin/sh +# +# mkdirs - a work-alike for `mkdir -p' +# +# Chet Ramey +# chet@po.cwru.edu + +for dir +do + + test -d "$dir" && continue + + tomake=$dir + while test -n "$dir" ; do + # dir=${dir%/*} + # dir=`expr "$dir" ':' '\(/.*\)/[^/]*'` + if dir=`expr "$dir" ':' '\(.*\)/[^/]*'`; then + tomake="$dir $tomake" + else + dir= + fi + done + + for d in $tomake + do + test -d "$d" && continue + echo mkdir "$d" + mkdir "$d" + done +done + +exit 0 diff --git a/scripts/netgen.spec.in b/scripts/netgen.spec.in new file mode 100644 index 0000000..74e2261 --- /dev/null +++ b/scripts/netgen.spec.in @@ -0,0 +1,45 @@ +Name: netgen +Version: @VERSION@ +Release: 1 +Summary: LVS netlist comparison tool +Group: Applications/Engineering +License: GPL +URL: http://www.opencircuitdesign.com/netgen/index.html +Source: http://www.opencircuitdesign.com/netgen/archive/%{name}-%{version}.tgz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +BuildRequires: libX11-devel, libXt-devel, tcl-devel, tk-devel +Requires: libX11, libXt, tcl, tk + +%description +Netgen is a tool for comparing netlists, a process known as LVS. This is an +important step in the integrated circuit design flow, ensuring that the +geometry that has been laid out matches the expected circuit. Even for small +circuits, LVS can be done much faster than simulation, and provides feedback +that makes it easier to find an error than does a simulation. + +%prep +%setup -q + +%build +%configure \ + --with-tcl=%{_libdir} \ + --with-tk=%{_libdir} \ + --with-tclincls=%{_includedir} \ + --with-tkincls=%{_includedir} \ + --with-tcllibs=%{_libdir} \ + --with-tklibs=%{_libdir} +make + +%install +rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root,-) +%doc Changes Copying README TO_DO VERSION +%{_bindir}/netgen +%{_libdir}/netgen/* + diff --git a/tcltk/Depend b/tcltk/Depend new file mode 100644 index 0000000..db3f46f --- /dev/null +++ b/tcltk/Depend @@ -0,0 +1,3 @@ +tclnetgen.o: tclnetgen.c ../base/config.h ../base/pdutils.h \ + ../base/netgen.h ../base/objlist.h ../base/objlist.h ../base/netcmp.h \ + ../base/dbug.h ../base/print.h ../base/query.h ../base/hash.h diff --git a/tcltk/Makefile b/tcltk/Makefile new file mode 100644 index 0000000..ab10e58 --- /dev/null +++ b/tcltk/Makefile @@ -0,0 +1,49 @@ +MODULE = tcltk +NETGENDIR = .. +SRCS = tclnetgen.c + +include ${NETGENDIR}/defs.mak + +EXTRA_LIBS = ${MAIN_EXTRA_LIBS} + +DFLAGS += -DNETGEN_DATE="\"`date`\"" +LIBS += -lm +CLEANS += netgen.sh netgen.tcl netgenexec${EXEEXT} +CFLAGS += -I${NETGENDIR}/base + +TCL_FILES = \ + $(DESTDIR)${TCLDIR}/tkcon.tcl \ + $(DESTDIR)${TCLDIR}/console.tcl \ + $(DESTDIR)${TCLDIR}/netgen.tcl + +tcl-main: netgenexec${EXEEXT} netgen.tcl netgen.sh + +install-tcl: netgenexec${EXEEXT} $(DESTDIR)${BINDIR}/netgen.sh ${TCL_FILES} + ${RM} $(DESTDIR)${TCLDIR}/netgenexec${EXEEXT} + ${CP} netgenexec${EXEEXT} $(DESTDIR)${TCLDIR}/netgenexec${EXEEXT} + +netgenexec${EXEEXT}: netgenexec.c + ${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} netgenexec.c -o netgenexec${EXEEXT} \ + ${LDFLAGS} ${LIBS} ${LIB_SPECS} + +netgen.tcl: netgen.tcl.in + sed -e /TCL_DIR/s%TCL_DIR%${TCLDIR}%g \ + -e /SHDLIB_EXT/s%SHDLIB_EXT%${SHDLIB_EXT}%g \ + netgen.tcl.in > netgen.tcl + +netgen.sh: netgen.sh.in + sed -e /TCL_DIR/s%TCL_DIR%${TCLDIR}%g \ + -e /TCLLIB_DIR/s%TCLLIB_DIR%${TCL_LIB_DIR}%g \ + -e /WISH_EXE/s%WISH_EXE%${WISH_EXE}%g \ + netgen.sh.in > netgen.sh + +$(DESTDIR)${TCLDIR}/%: % + ${RM} $(DESTDIR)${TCLDIR}/$* + ${CP} $* $(DESTDIR)${TCLDIR}/$* + +$(DESTDIR)${BINDIR}/netgen.sh: netgen.sh + ${RM} $(DESTDIR)${BINDIR}/netgen.sh $(DESTDIR)${BINDIR}/netgen + ${CP} netgen.sh $(DESTDIR)${BINDIR}/netgen + (cd $(DESTDIR)${BINDIR}; chmod 0755 netgen) + +include ${NETGENDIR}/rules.mak diff --git a/tcltk/console.tcl b/tcltk/console.tcl new file mode 100644 index 0000000..d4aa557 --- /dev/null +++ b/tcltk/console.tcl @@ -0,0 +1,4 @@ +# Tcl commands to run in the console before netgen is initialized +# +puts stdout "Running NetGen Console Functions" +bind .text {netgen::interrupt} diff --git a/tcltk/netgen.sh.in b/tcltk/netgen.sh.in new file mode 100755 index 0000000..27bdc8b --- /dev/null +++ b/tcltk/netgen.sh.in @@ -0,0 +1,54 @@ +#!/bin/sh +# +# For installation, put this file (netgen.sh) in a standard executable path. +# Put startup script "netgen.tcl" and shared library "tclnetgen.so" +# in ${CAD_ROOT}/netgen/tcl/, with a symbolic link from file +# ".wishrc" to "netgen.tcl". +# +# This script starts irsim under the Tcl interpreter, +# reading commands from a special .wishrc script which +# launches irsim and retains the Tcl interactive interpreter. + +# Parse for the argument "-c[onsole]". If it exists, run netgen +# with the TkCon console. Strip this argument from the argument list. + +TKCON=true +BATCH= +NETGEN_WISH=WISH_EXE +export NETGEN_WISH + +# Hacks for Cygwin +if [ ${TERM:=""} = "cygwin" ]; then + export PATH="$PATH:TCLLIB_DIR" + export DISPLAY=${DISPLAY:=":0"} +fi + +# Preserve quotes in arguments (thanks, Stackoverflow!) +arglist='' +for i in "$@" ; do + case $i in + -noc*) TKCON=;; + -bat*) BATCH=true; TKCON=;; + *) arglist="$arglist${arglist:+ }\"${i//\"/\\\"}\"";; + esac +done + +if [ $TKCON ]; then + + exec TCL_DIR/tkcon.tcl \ + -eval "source TCL_DIR/console.tcl" \ + -slave "package require Tk; set argc $#; set argv [list $arglist]; \ + source TCL_DIR/netgen.tcl" + +else + +# +# Run the stand-in for wish (netgenexec), which acts exactly like "wish" +# except that it replaces ~/.wishrc with netgen.tcl. This executable is +# *only* needed when running without the console; the console itself is +# capable of sourcing the startup script. +# + + exec TCL_DIR/netgenexec -- "$@" + +fi diff --git a/tcltk/netgen.tcl.in b/tcltk/netgen.tcl.in new file mode 100644 index 0000000..37e41b5 --- /dev/null +++ b/tcltk/netgen.tcl.in @@ -0,0 +1,347 @@ +# Wishrc startup for ToolScript (netgen) +# +# For installation: Put this file and also tclnetgen.so into +# directory ${CAD_ROOT}/netgen/tcl/, and set the "load" line below +# to point to the location of tclnetgen.so. Also see comments +# in shell script "netgen.sh". +# + +# Check namespaces for existence of other applications +set UsingMagic 0 +set UsingXCircuit 0 +set UsingIRSIM 0 +set batchmode 0 +set nlist [namespace children] +foreach i $nlist { + switch $i { + ::magic { set UsingMagic 1 } + ::xcircuit { set UsingXCircuit 1 } + ::irsim { set UsingIRSIM 1 } + } +} + +load TCL_DIR/tclnetgenSHDLIB_EXT + +#---------------------------------------------------------------- +# Define the "lvs" command as a way of calling the netgen options +# for standard compare, essentially the same as the old "netcomp" +# standalone program. +# +# Use the "canonical" command to parse the file and cell names, +# although if the cells have not been read in yet, then the +# original syntax of filename or {filename cellname} is required. +#---------------------------------------------------------------- + +proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out}} { + + # Allow name1 or name2 to be a list of {filename cellname}, + # A single , or any valid_cellname form if the + # file has already been read. + + if {[catch {set flist1 [canonical $name1]}]} { + if {[llength $name1] == 2} { + set file1 [lindex $name1 0] + set cell1 [lindex $name1 1] + } else { + set file1 $name1 + set cell1 $name1 + } + puts stdout "Reading netlist file $file1" + set fnum1 [netgen::readnet $file1] + } else { + set cell1 [lindex $flist1 0] + set fnum1 [lindex $flist1 1] + set flist1 [canonical $fnum1] + set file1 [lindex $flist1 0] + } + + if {[catch {set flist2 [canonical $name2]}]} { + if {[llength $name2] == 2} { + set file2 [lindex $name2 0] + set cell2 [lindex $name2 1] + } else { + set file2 $name2 + set cell2 $name2 + } + puts stdout "Reading netlist file $file2" + set fnum2 [netgen::readnet $file2] + } else { + set cell2 [lindex $flist2 0] + set fnum2 [lindex $flist2 1] + set flist2 [canonical $fnum2] + set file2 [lindex $flist2 0] + } + + if {$fnum1 == $fnum2} { + puts stderr "Both cells are in the same netlist: Cannot compare!" + return + } + + set clist1 [cells list $fnum1] + set cidx [lsearch -regexp $clist1 ^$cell1$] + if {$cidx < 0} { + puts stderr "Cannot find cell $cell1 in file $file1" + return + } else { + set cell1 [lindex $clist1 $cidx] + } + set clist2 [cells list $fnum2] + set cidx [lsearch -regexp $clist2 ^$cell2$] + if {$cidx < 0} { + puts stderr "Cannot find cell $cell2 in file $file2" + return + } else { + set cell2 [lindex $clist2 $cidx] + } + + netgen::compare assign "$fnum1 $cell1" "$fnum2 $cell2" + + if {[file exists $setupfile]} { + puts stdout "Reading setup file $setupfile" + # Instead of sourcing the setup file, run each line so we can + # catch individual errors and not let them halt the LVS process + set perrors 0 + if {![catch {open $setupfile r} fsetup]} { + set sline 0 + set command {} + while {[gets $fsetup line] >= 0} { + incr sline + append command $line "\n" + if {[info complete $command]} { + if {[catch {uplevel 1 [list namespace eval netgen $command]} msg]} { + set msg [string trimright $msg "\n"] + puts stderr "Error $setupfile:$sline (ignoring), $msg" + incr perrors + } + set command {} + } + } + close $fsetup + } else { + puts stdout "Error: Cannot read the setup file $setupfile" + } + + if {$perrors > 0} { + puts stdout "Warning: There were errors reading the setup file" + } + } else { + netgen::permute default ;# transistors and resistors + netgen::combine default ;# standard parallel/serial allowances + } + + puts stdout "Comparison output logged to file $logfile" + netgen::log file $logfile + netgen::log start + netgen::log echo off + set endval [netgen::compare hierarchical "$fnum1 $cell1" "$fnum2 $cell2"] + if {$endval == {}} { + netgen::log put "No cells in queue!\n" + return + } + set properr {} + while {$endval != {}} { + netgen::run converge + netgen::log echo on + if {[verify equivalent]} { + # Resolve automorphisms by pin and property + netgen::run resolve + set result [verify unique] + if {$result == 0} { + netgen::log put " Networks match locally but not globally.\n" + netgen::log put " Probably connections are swapped.\n" + netgen::log put " Check the end of logfile ${logfile} for implicated nodes.\n" + netgen::verify nodes + + # Flatten the non-matching subcircuit (but not the top-level cells) + if {[netgen::print queue] != {}} { + netgen::log put " Flattening non-matched subcircuits $endval" + netgen::flatten class "[lindex $endval 0] $fnum1" + netgen::flatten class "[lindex $endval 1] $fnum2" + } + } else { + # Match pins + netgen::log echo off + equate pins "$fnum1 [lindex $endval 0]" "$fnum2 [lindex $endval 1]" + netgen::log echo on + } + if {$result == 2} {lappend properr [lindex $endval 0]} + } else { + # Flatten the non-matching subcircuit (but not the top-level cells) + if {[netgen::print queue] != {}} { + netgen::log put " Flattening non-matched subcircuits $endval" + netgen::flatten class "[lindex $endval 0] $fnum1" + netgen::flatten class "[lindex $endval 1] $fnum2" + } + } + netgen::log echo off + set endval [netgen::compare hierarchical] + } + netgen::log echo off + puts stdout "Result: " nonewline + netgen::log echo on + netgen::verify only + if {$properr != {}} { + netgen::log put "The following cells had property errors: $properr\n" + } + netgen::log end + puts stdout "LVS Done." +} + +# It is important to make sure no netgen commands overlap with Tcl built-in +# commands, because otherwise the namespace import will fail. + +proc pushnamespace { name } { + + set y [namespace eval ${name} info commands ::${name}::*] + set z [info commands] + + foreach v $y { + regsub -all {\*} $v {\\*} i + set x [namespace tail $i] + if {[lsearch $z $x] < 0} { + namespace import $i + } else { + puts "Warning: ${name} command '$x' use fully-qualified name '$v'" + } + } +} + +proc popnamespace { name } { + set z [info commands] + set l [expr [string length ${name}] + 5] + + while {[set v [lsearch $z ${name}_tcl_*]] >= 0} { + set y [lindex $z $v] + set w [string range $y $l end] + interp alias {} ::$w {} + rename ::$y ::$w + puts "Info: replacing ::$w with ::$y" + } + namespace forget ::${name}::* +} + +set auto_noexec 1 ;# don't EVER call UNIX commands w/o "shell" in front + +#---------------------------------------------------------------------- +# Cross-Application section +#---------------------------------------------------------------------- + +# Setup IRSIM assuming that the Tcl version is installed. +# We do not need to rename procedure irsim to NULL because it is +# redefined in a script, which simply overwrites the original. + +proc irsim { args } { + global CAD_ROOT + set irsimscript [glob -nocomplain ${CAD_ROOT}/irsim/tcl/irsim.tcl] + if { ${irsimscript} == {} } { + puts stderr "\"irsim\" requires Tcl-based IRSIM version 9.6 or newer." + puts stderr "Could not find script \"irsim.tcl\". If IRSIM is installed in a" + puts stderr "place other than CAD_ROOT (=${CAD_ROOT}), use the command" + puts stderr "\"source /irsim.tcl\" before doing \"irsim\"." + } else { + source $irsimscript + eval {irsim} $args + } +} + +# Setup Xcircuit assuming that the Tcl version is installed. + +proc xcircuit { args } { + global CAD_ROOT + global argc + global argv + set xcircscript [glob -nocomplain ${CAD_ROOT}/xcircuit*/xcircuit.tcl] + if { ${xcircscript} == {} } { + puts stderr "\"xcircuit\" requires Tcl-based XCircuit version 3.1 or newer." + puts stderr "Could not find script \"xcircuit.tcl\". If XCircuit is installed in a" + puts stderr "place other than CAD_ROOT (=${CAD_ROOT}), use the command" + puts stderr "\"source /xcircuit.tcl\"." + } else { + # if there are multiple installed versions, choose the highest version. + if {[llength $xcircscript] > 1} { + set xcircscript [lindex [lsort -decreasing -dictionary $xcircscript] 0] + } + set argv $args + set argc [llength $args] + uplevel #0 source $xcircscript + } +} + +# Setup Magic assuming that the Tcl version is installed. + +proc magic { args } { + global CAD_ROOT + global argc + global argv + set magicscript [glob -nocomplain ${CAD_ROOT}/magic/tcl/magic.tcl] + if { ${magicscript} == {} } { + puts stderr "\"magic\" requires Tcl-based Magic version 7.2 or newer." + puts stderr "Could not find script \"magic.tcl\". If Magic is installed in a" + puts stderr "place other than CAD_ROOT (=${CAD_ROOT}), use the command" + puts stderr "\"source /magic.tcl\"." + } else { + set argv $args + set argc [llength $args] + uplevel #0 source $magicscript + } +} + +#---------------------------------------------------------------------------- +# Have we called netgen from tkcon or a clone thereof? If so, set NetgenConsole +#---------------------------------------------------------------------------- + +if {! $UsingMagic } { + if {[lsearch [interp aliases] tkcon] != -1} { + set NetgenConsole tkcon + wm withdraw . + } +} + +pushnamespace netgen + +#---------------------------------------------------------------------------- +# For now, if we are standalone, pop down the default Tk window. +# Sometime later we may wish to provide a standalone GUI frontend in Tk +# to improve upon the original X11 "xnetgen" frontend. If so, its +# definitions would go below. + +if {! $UsingMagic } { + if {[lsearch [interp aliases] tkcon] != -1} { + if {[string range [wm title .] 0 3] == "wish"} { + wm withdraw . + } + } +} + +#---------------------------------------------------------------------------- +# No-console mode drops "--" in front of the argument list and "-noc" +# is retained, so remove them. Internally, the console will be determined +# by checking for a slave interpreter, so there is no need for any +# action here other than removing the argument. + +if {[lindex $argv 0] == "--"} { + incr argc -1 + set argv [lrange $argv 1 end] +} + +if {[string range [lindex $argv 0] 0 3] == "-noc"} { + incr argc -1 + set argv [lrange $argv 1 end] +} + +if {[string range [lindex $argv 0] 0 3] == "-bat"} { + incr argc -1 + set argv [lrange $argv 1 end] + set batchmode 1 +} + +#---------------------------------------------------------------------------- +# Anything on the command line is assumed to be a netgen command to evaluate + +if {[catch {eval $argv}]} { + puts stdout "$errorInfo" +} +if {$batchmode == 1} {quit} + +#---------------------------------------------------------------------------- +# Netgen start function drops back to interpreter after initialization & setup diff --git a/tcltk/netgenexec.c b/tcltk/netgenexec.c new file mode 100644 index 0000000..c7e5b34 --- /dev/null +++ b/tcltk/netgenexec.c @@ -0,0 +1,86 @@ +/*----------------------------------------------------------------------*/ +/* netgenexec.c */ +/* */ +/* Written by R. Timothy Edwards for MultiGiG, Inc., November 2004 */ +/* This file mainly lifted from the main application routine for */ +/* "wish" from the Tk distribution. */ +/* */ +/* This is a compact re-write of the "wish" executable that calls */ +/* Tk_MainEx with application-specific processing. Specifically, */ +/* "wish" doesn't allow the startup script (~/.wishrc) to be renamed. */ +/* However, for netgen running as an extension of Tcl, we want to */ +/* source the netgen.tcl file instead of ~/.wishrc. So, all this file */ +/* really does is to set the Tcl variable "tcl_rcFileName" to */ +/* netgen.tcl, so that it will be processed as the startup script, */ +/* followed by a drop back to the Tcl interpreter command-line main */ +/* loop. */ +/* */ +/* This is a standalone executable. However, it is only called when */ +/* "-noconsole" is specified on the UNIX command-line. When the */ +/* console is used, the console is capable of sourcing the netgen.tcl */ +/* script itself, and so it uses "wish" as the executable. However, */ +/* the console redirects standard input, so it prevents netgen from */ +/* being used in a batch processing mode. Thus, to batch-process with */ +/* netgen, use "netgen -noc < script.tcl" or, interactively, */ +/* "netgen -noc << EOF" followed by commands entered from stdin */ +/* and ending with "EOF". */ +/* */ +/* The "netgenexec" method replaces the former use of "wish" with the */ +/* "netgen" script setting HOME to point to the directory containing */ +/* ".wishrc", a symbolic link to "netgen.tcl". That failed to work on */ +/* remote systems because the $HOME environment variable is also used */ +/* to find the user's .Xauthority file to authenticate the X11 */ +/* connection. */ +/* */ +/* Update: Because "netgenexec" avoids the Tk console, no part of Tk */ +/* is ever invoked. Making "netgenexec" run Tk_Init just causes it to */ +/* require graphics accessibility that it does not need. All calls to */ +/* Tk have been replaced with Tcl calls. */ +/*----------------------------------------------------------------------*/ + +#include + +// #include +#include + +/*----------------------------------------------------------------------*/ +/* Application initiation. This is exactly like the AppInit routine */ +/* for "wish", minus the cruft, but with "tcl_rcFileName" set to */ +/* "netgen.tcl" instead of "~/.wishrc". */ +/*----------------------------------------------------------------------*/ + +int +netgen_AppInit(interp) + Tcl_Interp *interp; +{ + if (Tcl_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } + // if (Tk_Init(interp) == TCL_ERROR) { + // return TCL_ERROR; + // } + // Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit); + Tcl_StaticPackage(interp, "Tcl", Tcl_Init, Tcl_Init); + + /* This is where we replace the home ".wishrc" file with */ + /* netgen's startup script. */ + + Tcl_SetVar(interp, "tcl_rcFileName", TCL_DIR "/netgen.tcl", TCL_GLOBAL_ONLY); + return TCL_OK; +} + +/*----------------------------------------------------------------------*/ +/* The main procedure; replacement for "wish". */ +/*----------------------------------------------------------------------*/ + +int +main(argc, argv) + int argc; + char **argv; +{ + // Tk_Main(argc, argv, netgen_AppInit); + Tcl_Main(argc, argv, netgen_AppInit); + return 0; +} + +/*----------------------------------------------------------------------*/ diff --git a/tcltk/tclnetgen.c b/tcltk/tclnetgen.c new file mode 100644 index 0000000..9276fb6 --- /dev/null +++ b/tcltk/tclnetgen.c @@ -0,0 +1,3852 @@ +/* "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. */ + +/* tclnetgen.c --- Tcl interpreter interface for using netgen */ + +#include +#include /* for getenv */ +#include + +#include + +#include "config.h" +#include "netgen.h" +#include "objlist.h" +#include "netcmp.h" +#include "dbug.h" +#include "print.h" +#include "query.h" /* for ElementNodes() */ +#include "hash.h" + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +/*-----------------------*/ +/* Tcl 8.4 compatibility */ +/*-----------------------*/ + +#ifndef CONST84 +#define CONST84 +#endif + +Tcl_Interp *netgeninterp; +Tcl_Interp *consoleinterp; +int ColumnBase = 0; +char *LogFileName = NULL; + +extern int PropertyErrorDetected; + +/* Function prototypes for all Tcl command callbacks */ + +int _netgen_readnet(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_readlib(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_canonical(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_writenet(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_flatten(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_nodes(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_elements(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_debug(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_protochip(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_instances(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_contents(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_describe(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_cells(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_ports(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_model(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_leaves(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_quit(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_reinit(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netgen_log(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +#ifdef HAVE_MALLINFO +int _netgen_printmem(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +#endif +int _netgen_help(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netcmp_matching(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netcmp_compare(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netcmp_iterate(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netcmp_summary(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netcmp_print(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netcmp_run(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netcmp_verify(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netcmp_automorphs(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netcmp_equate(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netcmp_ignore(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netcmp_permute(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netcmp_combine(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netcmp_property(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netcmp_exhaustive(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netcmp_restart(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netcmp_global(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); +int _netcmp_convert(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]); + +typedef struct _Cmd { + char *name; + int (*handler)(); + char *helptext; +} Command; + +/*------------------------------------------------------*/ +/* All netgen commands under Tcl are defined here */ +/*------------------------------------------------------*/ + +Command netgen_cmds[] = { + {"readnet", _netgen_readnet, + "[] []\n " + "read a netlist file (default format=auto)"}, + {"readlib", _netgen_readlib, + " []\n " + "read a format library"}, + {"canonical", _netgen_canonical, + "\n " + "return top-level cellname and file number"}, + {"writenet", _netgen_writenet, + " \n " + "write a netlist file"}, + {"flatten", _netgen_flatten, + "[class] \n " + "flatten a hierarchical cell"}, + {"nodes", _netgen_nodes, + "[] \n " + "print nodes of an element or cell"}, + {"elements", _netgen_elements, + "[] \n " + "print elements of a node or cell"}, + {"debug", _netgen_debug, + "on|off|\n " + "turn debugging on or off or debug a command"}, + {"protochip", _netgen_protochip, + "\n " + "embed protochip structure"}, + {"instances", _netgen_instances, + "\n " + "list instances of the cell"}, + {"contents", _netgen_contents, + "\n " + "list contents of the cell"}, + {"describe", _netgen_describe, + "\n " + "describe the cell"}, + {"cells", _netgen_cells, + "[list|-all|-top] [filename]\n " + "print known cells, optionally from filename only\n " + "-all: print all cells, including primitives\n " + "-top: print all top-level cells"}, + {"ports", _netgen_ports, + "\n " + "print ports of the cell"}, + {"model", _netgen_model, + " \n " + "equate a model name with a device class"}, + {"leaves", _netgen_leaves, + "[]\n " + "print leaves of the cell"}, + {"quit", _netgen_quit, + "\n " + "exit netgen and Tcl"}, + {"reinitialize", _netgen_reinit, + "\n " + "reintialize netgen data structures"}, + {"log", _netgen_log, + "[file |start|end|reset|suspend|resume|echo]\n " + "enable or disable output log to file"}, +#ifdef HAVE_MALLINFO + {"memory", _netgen_printmem, + "\n " + "print memory statistics"}, +#endif + {"help", _netgen_help, + "\n " + "print this help information"}, + NULL +}; + +Command netcmp_cmds[] = { + {"compare", _netcmp_compare, + " \n " + "declare two cells for netcomp netlist comparison"}, + {"global", _netcmp_global, + " \n " + "declare a node (with possible wildcards) in the\n " + "hierarchy of to be of global scope"}, + {"convert", _netcmp_convert, + "\n " + "convert global nodes to local nodes and pins\n " + "in cell "}, + {"iterate", _netcmp_iterate, + "\n " + "do one netcomp iteration"}, + {"summary", _netcmp_summary, + "[elements|nodes]\n " + "summarize netcomp internal data structure"}, + {"print", _netcmp_print, + "\n " + "print netcomp internal data structure"}, + {"run", _netcmp_run, + "[converge|resolve]\n " + "converge: run netcomp to completion (convergence)\n " + "resolve: run to completion and resolve symmetries"}, + {"verify", _netcmp_verify, + "[elements|nodes|only|equivalent|unique]\n " + "verify results"}, + {"symmetries", _netcmp_automorphs, + "\n " + "print symmetries"}, + {"equate", _netcmp_equate, + "elements [] [] \n " + "nodes [] [] \n " + "pins [[] [] ]\n " + "classes [] []\n " + "elements: equate two elements\n " + "nodes: equate two nodes\n " + "classes: equate two device classes\n " + "pins: match pins between two cells"}, + + {"ignore", _netcmp_ignore, + "class \n " + "class: ignore any instances of class named "}, + + {"permute", _netcmp_permute, + "[transistors|resistors|capacitors|]\n " + ": permute named pins on device model\n " + "resistor: enable resistor permutations\n " + "capacitor: enable capacitor permutations\n " + "transistor: enable transistor permutations\n " + "(none): enable transistor and resistor permutations"}, + {"combine", _netcmp_combine, + "[transistors|resistors|capacitors|]\n " + " [|]: enable combinations of device model\n " + "resistor: enable resistor serial/parallel combinations\n " + "capacitor: enable capacitor parallel combinations\n " + "transistor: enable transistor parallel combinations\n " + "(none): enable standard combinations"}, + {"property", _netcmp_property, + "| [...]\n " + ": name of a device type (capacitor, etc.)\n " + ": name of a device model\n " + ": name of the property to compare"}, + + {"exhaustive", _netcmp_exhaustive, + "\n " + "toggle exhaustive subdivision"}, + {"restart", _netcmp_restart, + "\n " + "start over (reset data structures)"}, + {"matching", _netcmp_matching, + "[element|node] \n " + "return the corresponding node or element name\n " + "in the compared cell"}, + NULL +}; + +/*------------------------------------------------------*/ +/* Common function to parse a Tcl object as either a */ +/* netlist file name or a file number. */ +/*------------------------------------------------------*/ + +int +CommonGetFilenameOrFile(Tcl_Interp *interp, Tcl_Obj *fobj, int *fnumptr) +{ + int result, llen; + int fnum, ftest; + char *filename; + struct nlist *tp; + + result = Tcl_GetIntFromObj(interp, fobj, &ftest); + if (result != TCL_OK) { + Tcl_ResetResult(interp); + filename = Tcl_GetString(fobj); + tp = LookupCell(filename); + if (tp == NULL) { + Tcl_SetResult(interp, "No such file.\n", NULL); + return TCL_ERROR; + } + else if (!(tp->flags & CELL_TOP)) { + Tcl_SetResult(interp, "Name is not a file.\n", NULL); + return TCL_ERROR; + } + else fnum = tp->file; + } + else { + fnum = ftest; + } + *fnumptr = fnum; + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Common function to parse a cell name. This allows */ +/* several variants on the syntax: */ +/* */ +/* (1) */ +/* Assumes cellname is unique and finds the cell */ +/* and file number. */ +/* */ +/* (2) { } */ +/* Finds the cell, given the name and file number */ +/* as a list of length 2. */ +/* */ +/* (3) { } */ +/* Finds the cell, given the name and filename of */ +/* the file containing the cell. */ +/* */ +/* (4) { } */ +/* is also allowed and is backwards-compatible */ +/* with the arguments for "lvs". */ +/* */ +/* (5) { } */ +/* likewise. */ +/* */ +/* (6) */ +/* refers to the top-level cell of file */ +/* */ +/* (7) -circuit1 */ +/* the first circuit being compared, after the */ +/* "compare" command has been issued. */ +/* */ +/* (8) -circuit2 */ +/* the first circuit being compared, after the */ +/* "compare" command has been issued. */ +/* */ +/* (9) -current */ +/* the most recent circuit/file to be read, */ +/* after a "readnet" or "readlib" has been issued. */ +/* */ +/* Note that is equivalent to the top-level */ +/* cellname. That allows the order of elements to be */ +/* arbitrary. */ +/* */ +/* Function returns a Tcl result, and fills in a */ +/* pointer to the cell structure, and the file number */ +/* (which is a copy of , if provided as an */ +/* argument). */ +/* */ +/* == -1 or "*" is (theoretically) treated by */ +/* all commands as a wildcard matching all netlists. */ +/*------------------------------------------------------*/ + +int +CommonParseCell(Tcl_Interp *interp, Tcl_Obj *objv, + struct nlist **tpr, int *fnumptr) +{ + Tcl_Obj *tobj, *fobj; + int result, llen; + int fnum, ftest, index; + char *filename, *cellname; + struct nlist *tp, *tp2; + + char *suboptions[] = { + "-circuit1", "-circuit2", "-current", "*", NULL + }; + enum SubOptionIdx { + CIRCUIT1_IDX, CIRCUIT2_IDX, CURRENT_IDX, WILDCARD_IDX + }; + + result = Tcl_ListObjLength(interp, objv, &llen); + if (result != TCL_OK) return TCL_ERROR; + + if (llen == 2) { + + fnum = -1; + + result = Tcl_ListObjIndex(interp, objv, 0, &tobj); + if (result != TCL_OK) return TCL_ERROR; + + /* Is 1st argument an integer? */ + + result = Tcl_GetIntFromObj(interp, tobj, &ftest); + if (result != TCL_OK) { + Tcl_ResetResult(interp); + + /* Is 1st argument a special keyword? */ + if (Tcl_GetIndexFromObj(interp, tobj, (CONST84 char **)suboptions, + "special", 0, &index) == TCL_OK) { + switch (index) { + case CIRCUIT1_IDX: + if (Circuit1 == NULL) { + Tcl_SetResult(interp, "No circuit has been" + " declared for comparison\n", NULL); + return TCL_ERROR; + } + fnum = Circuit1->file; + result = Tcl_ListObjIndex(interp, objv, 1, &tobj); + if (result != TCL_OK) return TCL_ERROR; + break; + case CIRCUIT2_IDX: + if (Circuit2 == NULL) { + Tcl_SetResult(interp, "No circuit has been" + " declared for comparison\n", NULL); + return TCL_ERROR; + } + fnum = Circuit2->file; + result = Tcl_ListObjIndex(interp, objv, 1, &tobj); + if (result != TCL_OK) return TCL_ERROR; + break; + case CURRENT_IDX: + if (CurrentCell == NULL) { + Tcl_SetResult(interp, "No current cell\n", NULL); + return TCL_ERROR; + } + fnum = CurrentCell->file; + result = Tcl_ListObjIndex(interp, objv, 1, &tobj); + if (result != TCL_OK) return TCL_ERROR; + break; + case WILDCARD_IDX: + fnum = -2; + result = Tcl_ListObjIndex(interp, objv, 1, &tobj); + if (result != TCL_OK) return TCL_ERROR; + break; + } + } + else { + Tcl_ResetResult(interp); + fnum = -1; + } + + /* Is 2nd argument an integer? */ + + if (fnum == -1) { + result = Tcl_ListObjIndex(interp, objv, 1, &fobj); + if (result != TCL_OK) return TCL_ERROR; + + result = Tcl_GetIntFromObj(interp, fobj, &ftest); + if (result != TCL_OK) { + Tcl_ResetResult(interp); + + /* Check if 2nd item is a reserved keyword */ + if (Tcl_GetIndexFromObj(interp, fobj, + (CONST84 char **)suboptions, + "special", 0, &index) == TCL_OK) { + switch (index) { + case CIRCUIT1_IDX: + if (Circuit1 == NULL) { + Tcl_SetResult(interp, "No circuit has been" + " declared for comparison\n", NULL); + return TCL_ERROR; + } + fnum = Circuit1->file; + break; + case CIRCUIT2_IDX: + if (Circuit2 == NULL) { + Tcl_SetResult(interp, "No circuit has been" + " declared for comparison\n", NULL); + return TCL_ERROR; + } + fnum = Circuit2->file; + break; + case CURRENT_IDX: + if (CurrentCell == NULL) { + Tcl_SetResult(interp, "No current cell\n", NULL); + return TCL_ERROR; + } + fnum = CurrentCell->file; + break; + case WILDCARD_IDX: + filename = NULL; + fnum = -1; + break; + } + } + else { + Tcl_ResetResult(interp); + filename = Tcl_GetString(fobj); + } + + /* Okay, neither argument is an integer, so */ + /* parse both as cell names and figure out */ + /* which one is the same as the top level, */ + /* and call that the filename. */ + } + else { + filename = NULL; + fnum = ftest; + } + } + else if (fnum == -2) { + filename = NULL; + fnum = -1; + } + else + filename = Tcl_GetString(fobj); + } + else { + filename = NULL; + fnum = ftest; + + result = Tcl_ListObjIndex(interp, objv, 1, &tobj); + if (result != TCL_OK) return TCL_ERROR; + } + cellname = Tcl_GetString(tobj); + + if (fnum == -1) { + + /* If fnum is a wildcard, then we insist that there */ + /* must be at least one cell matching the cellname, */ + /* although the routines should be applied to all */ + /* cells of the given name in all netlists. */ + + tp = LookupCell(cellname); + if (tp == NULL) { + Tcl_SetResult(interp, "No such cellname!\n", NULL); + return TCL_ERROR; + } + if (filename != NULL) { + tp2 = LookupCell(filename); + if (tp2 == NULL) { + Tcl_SetResult(interp, "No such cellname!\n", NULL); + return TCL_ERROR; + } + } + else tp2 = NULL; + + if (!(tp->flags & CELL_TOP)) { + if ((tp2 != NULL) && !(tp2->flags & CELL_TOP)) { + // Error: Neither name is a file! + Tcl_SetResult(interp, "No filename in list!\n", NULL); + return TCL_ERROR; + } + else if (tp2 != NULL) { + // tp2 is file top, tp is cell + fnum = tp2->file; + tp = LookupCellFile(cellname, fnum); + if (tp == NULL) { + Tcl_SetResult(interp, "Cell is not in file!\n", NULL); + return TCL_ERROR; + } + } + } + else { + // Arguments are reversed + + fnum = tp->file; + tp = LookupCellFile(filename, fnum); + if (tp == NULL) { + Tcl_SetResult(interp, "Cell is not in file!\n", NULL); + return TCL_ERROR; + } + } + } + else { + /* File number was given, so just plug it in */ + tp = LookupCellFile(cellname, fnum); + if (tp == NULL) { + Tcl_SetResult(interp, "No such cell or bad file number!\n", NULL); + return TCL_ERROR; + } + } + + } else { + /* Only one name given; check if it matches subOption */ + + if (Tcl_GetIndexFromObj(interp, objv, (CONST84 char **)suboptions, + "special", 0, &index) == TCL_OK) { + + switch (index) { + case CIRCUIT1_IDX: + if (Circuit1 == NULL) { + Tcl_SetResult(interp, "No circuit has been" + " declared for comparison\n", NULL); + return TCL_ERROR; + } + tp = Circuit1; + fnum = Circuit1->file; + break; + case CIRCUIT2_IDX: + if (Circuit2 == NULL) { + Tcl_SetResult(interp, "No circuit has been" + " declared for comparison\n", NULL); + return TCL_ERROR; + } + tp = Circuit2; + fnum = Circuit2->file; + break; + case CURRENT_IDX: + if (CurrentCell == NULL) { + Tcl_SetResult(interp, "No current cell\n", NULL); + return TCL_ERROR; + } + tp = CurrentCell; + fnum = CurrentCell->file; + break; + case WILDCARD_IDX: + Tcl_SetResult(interp, "Wildcards must be used with " + "a valid cellname\n", NULL); + return TCL_ERROR; + } + } + else { + Tcl_ResetResult(interp); + + /* Check if it is a file number */ + + result = Tcl_GetIntFromObj(interp, objv, &fnum); + if (result != TCL_OK) { + Tcl_ResetResult(interp); + + /* Only one name, which is a cellname. If not a */ + /* top-level cell, then it should be a unique name. */ + + filename = Tcl_GetString(objv); + tp = LookupCell(filename); + if (tp == NULL) { + Tcl_SetResult(interp, "No such cell!\n", NULL); + return TCL_ERROR; + } + if (tp->flags & CELL_TOP) + fnum = tp->file; + else + fnum = -1; // Use wildcard + } + else { + /* Given a file number, need to find the top-level cell */ + tp = FirstCell(); + while (tp != NULL) { + if (tp->flags & CELL_TOP) + if (tp->file == fnum) + break; + tp = NextCell(); + } + if (tp == NULL) { + Tcl_SetResult(interp, "No such file number!\n", NULL); + return TCL_ERROR; + } + } + } + } + + *tpr = tp; + *fnumptr = fnum; + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netgen_canonical */ +/* Syntax: netgen::canonical */ +/* Formerly: (none) */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_canonical(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + int result; + struct nlist *np; + int filenum; + Tcl_Obj *lobj; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "valid_filename"); + return TCL_ERROR; + } + + result = CommonParseCell(interp, objv[1], &np, &filenum); + if (result != TCL_OK) return result; + + lobj = Tcl_NewListObj(0, NULL); + + Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj(np->name, -1)); + Tcl_ListObjAppendElement(interp, lobj, Tcl_NewIntObj(filenum)); + Tcl_SetObjResult(interp, lobj); + + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* The following code breaks up the Query() command */ +/* from query.c into individual functions w/arguments */ +/*------------------------------------------------------*/ + +/*------------------------------------------------------*/ +/* Function name: _netgen_readnet */ +/* Syntax: netgen::readnet [format] [] */ +/* Formerly: read r, K, Z, G, and S */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_readnet(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *formats[] = { + "automatic", "ext", "extflat", "sim", "ntk", "spice", + "netgen", "actel", "xilinx", NULL + }; + enum FormatIdx { + AUTO_IDX, EXT_IDX, EXTFLAT_IDX, SIM_IDX, NTK_IDX, + SPICE_IDX, NETGEN_IDX, ACTEL_IDX, XILINX_IDX + }; + struct nlist *tc; + int result, index, filenum = -1; + char *retstr = NULL, *savstr = NULL; + + if (objc > 1) { + + /* If last argument is a number, then force file to belong to */ + /* the same netlist as everything else in "filenum". */ + + if (Tcl_GetIntFromObj(interp, objv[objc - 1], &filenum) != TCL_OK) { + Tcl_ResetResult(interp); + filenum = -1; + } + else if (filenum < 0) { + Tcl_SetResult(interp, "Cannot use negative file number!", NULL); + return TCL_ERROR; + } + else { + objc--; + } + } + + if (objc == 1 || objc > 3) { + Tcl_WrongNumArgs(interp, 1, objv, "?format? file ?filenum?"); + return TCL_ERROR; + } + else if (objc > 1) { + if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)formats, + "format", 0, &index) != TCL_OK) { + if (objc == 3) + + return TCL_ERROR; + else { + Tcl_ResetResult(interp); + index = AUTO_IDX; + } + } + } + + switch (index) { + case ACTEL_IDX: + case XILINX_IDX: + if (objc != 2) { + Fprintf(stderr, "Warning: argument \"%s\" ignored. Reading %s library.\n", + Tcl_GetString(objv[2]), formats[index]); + } + break; + + case AUTO_IDX: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "file"); + return TCL_ERROR; + } + retstr = Tcl_GetString(objv[1]); + break; + + default: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "format file"); + return TCL_ERROR; + } + retstr = Tcl_GetString(objv[2]); + break; + } + + if (retstr) savstr = STRDUP(retstr); + + // Check if the file is already loaded + + tc = LookupCell(savstr); + if (tc != NULL) { + if ((filenum != -1) && (filenum != tc->file)) { + Tcl_SetResult(interp, "File is already loaded as a" + " different file number.", NULL); + return TCL_ERROR; + } + filenum = tc->file; + } + else { + + switch(index) { + case AUTO_IDX: + retstr = ReadNetlist(savstr, &filenum); + break; + case EXT_IDX: + retstr = ReadExtHier(savstr, &filenum); + break; + case EXTFLAT_IDX: + retstr = ReadExtFlat(savstr, &filenum); + break; + case SIM_IDX: + retstr = ReadSim(savstr, &filenum); + break; + case NTK_IDX: + retstr = ReadNtk(savstr, &filenum); + break; + case SPICE_IDX: + retstr = ReadSpice(savstr, &filenum); + break; + case NETGEN_IDX: + retstr = ReadNetgenFile(savstr, &filenum); + break; + case ACTEL_IDX: + ActelLib(); + retstr = formats[index]; + break; + case XILINX_IDX: + XilinxLib(); + retstr = formats[index]; + break; + } + } + + /* Return the file number to the interpreter */ + Tcl_SetObjResult(interp, Tcl_NewIntObj(filenum)); + + if (savstr) FREE(savstr); + return (retstr == NULL) ? TCL_ERROR : TCL_OK; +} + +/*--------------------------------------------------------*/ +/* Function name: _netgen_readlib */ +/* Syntax: netgen::readlib [] [] */ +/* Formerly: read X, A */ +/* Results: */ +/* Side Effects: */ +/*--------------------------------------------------------*/ + +int +_netgen_readlib(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *formats[] = { + "actel", "spice", "xilinx", NULL + }; + enum FormatIdx { + ACTEL_IDX, SPICE_IDX, XILINX_IDX + }; + int result, index, fnum = -1; + char *repstr; + + if (objc > 1) { + + /* If last argument is a number, then force file to belong to */ + /* the same netlist as everything else in "fnum". */ + + if (Tcl_GetIntFromObj(interp, objv[objc - 1], &fnum) != TCL_OK) { + Tcl_ResetResult(interp); + fnum = -1; + } + else if (fnum < 0) { + Tcl_SetResult(interp, "Cannot use negative file number!", NULL); + return TCL_ERROR; + } + else { + objc--; + } + } + + if (objc == 1 || objc > 3) { + Tcl_WrongNumArgs(interp, 1, objv, "format [file]"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)formats, + "format", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + switch(index) { + case ACTEL_IDX: + case XILINX_IDX: + if (objc == 3) { + Tcl_WrongNumArgs(interp, 1, objv, "actel | xilinx"); + return TCL_ERROR; + } + break; + case SPICE_IDX: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "spice file"); + return TCL_ERROR; + } + break; + } + + switch(index) { + case ACTEL_IDX: + ActelLib(); + break; + case SPICE_IDX: + repstr = Tcl_GetString(objv[2]); + ReadSpiceLib(repstr, &fnum); + break; + case XILINX_IDX: + XilinxLib(); + break; + } + + Tcl_SetObjResult(interp, Tcl_NewIntObj(fnum)); + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netgen_writenet */ +/* Syntax: netgen::write format cellname [filenum] */ +/* Formerly: k, x, z, w, o, g, s, E, and C */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_writenet(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *formats[] = { + "ext", "sim", "ntk", "actel", + "spice", "wombat", "esacap", "netgen", "ccode", "xilinx", NULL + }; + enum FormatIdx { + EXT_IDX, SIM_IDX, NTK_IDX, ACTEL_IDX, + SPICE_IDX, WOMBAT_IDX, ESACAP_IDX, NETGEN_IDX, CCODE_IDX, XILINX_IDX + }; + int result, index, filenum; + char *repstr; + + if (objc != 3 && objc != 4) { + Tcl_WrongNumArgs(interp, 1, objv, "format file"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)formats, + "format", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + repstr = Tcl_GetString(objv[2]); + + if (objc == 4) { + result = Tcl_GetIntFromObj(interp, objv[3], &filenum); + if (result != TCL_OK) return result; + } + else filenum = -1; + + switch(index) { + case EXT_IDX: + Ext(repstr, filenum); + break; + case SIM_IDX: + Sim(repstr, filenum); + break; + case NTK_IDX: + Ntk(repstr,""); + break; + case ACTEL_IDX: + if (ActelLibPresent() == 0) { + Fprintf(stderr, "Warning: Actel library was not loaded.\n"); + Fprintf(stderr, "Try \"readlib actel\" before reading the netlist.\n"); + } + Actel(repstr,""); + break; + case SPICE_IDX: + SpiceCell(repstr, filenum, ""); + break; + case WOMBAT_IDX: + Wombat(repstr,NULL); + break; + case ESACAP_IDX: + EsacapCell(repstr,""); + break; + case NETGEN_IDX: + WriteNetgenFile(repstr,""); + break; + case CCODE_IDX: + Ccode(repstr,""); + break; + case XILINX_IDX: + if (XilinxLibPresent() == 0) { + Fprintf(stderr, "Warning: Xilinx library was not loaded.\n"); + Fprintf(stderr, "Try \"readlib xilinx\" before reading the netlist.\n"); + } + Xilinx(repstr,""); + break; + } + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netgen_flatten */ +/* Syntax: netgen::flatten mode */ +/* Formerly: f and F */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_flatten(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *repstr, *file; + int result, llen, filenum; + struct nlist *tp; + + if ((objc < 2) || (objc > 3)) { + Tcl_WrongNumArgs(interp, 1, objv, "?class? valid_cellname"); + return TCL_ERROR; + } + + result = CommonParseCell(interp, objv[objc - 1], &tp, &filenum); + if (result != TCL_OK) return result; + repstr = tp->name; + + if (objc == 3) { + char *argv = Tcl_GetString(objv[1]); + if (!strcmp(argv, "class")) + FlattenInstancesOf(repstr, filenum); + else { + Tcl_WrongNumArgs(interp, 1, objv, "class valid_cellname"); + return TCL_ERROR; + } + } + else + Flatten(repstr, filenum); + return TCL_OK; +} + +/*--------------------------------------------------------------*/ +/* Function name: _netgen_nodes */ +/* Syntax: netgen::nodes [-list ] [] */ +/* Formerly: n and N */ +/* Results: */ +/* Side Effects: */ +/*--------------------------------------------------------------*/ + +int +_netgen_nodes(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *estr = NULL, *istr = NULL, *cstr, *fstr; + char *optstart; + int dolist = 0; + int fnum, result; + struct nlist *np = NULL; + + if (objc > 1) { + optstart = Tcl_GetString(objv[1]); + if (*optstart == '-') optstart++; + if (!strcmp(optstart, "list")) { + dolist = 1; + objv++; + objc--; + } + } + + if ((objc < 1 || objc > 3) || (objc == 2)) { + Tcl_WrongNumArgs(interp, 1, objv, "?element? ?cell file?"); + return TCL_ERROR; + } + + if (objc == 1) { + if (CurrentCell == NULL) { + Tcl_WrongNumArgs(interp, 1, objv, "(cell name required)"); + return TCL_ERROR; + } + cstr = CurrentCell->name; + fnum = CurrentCell->file; + } + else { + result = CommonParseCell(interp, objv[objc - 1], &np, &fnum); + if (result != TCL_OK) return result; + + cstr = np->name; + // If element was specified: + if (objc == 3) estr = Tcl_GetString(objv[objc - 2]); + } + + if (estr) { + if (*estr != '/') { + istr = (char *)Tcl_Alloc(strlen(estr) + 2); + sprintf(istr, "/%s", estr); + estr = istr; + } + } + + if (estr) { + if (dolist) { + struct objlist *ob, *nob; + Tcl_Obj *lobj, *pobj; + int ckto; + + if (np == NULL) np = LookupCellFile(cstr, fnum); + + if (np == NULL) { + Tcl_SetResult(interp, "No such cell.", NULL); + if (istr) Tcl_Free(istr); + return TCL_ERROR; + } + + ckto = strlen(estr); + for (ob = np->cell; ob != NULL; ob = ob->next) { + if (!strncmp(estr, ob->name, ckto)) { + if (*(ob->name + ckto) == '/' || *(ob->name + ckto) == '\0') + break; + } + } + if (ob == NULL) { + Tcl_SetResult(interp, "No such element.", NULL); + if (istr) Tcl_Free(istr); + return TCL_ERROR; + } + lobj = Tcl_NewListObj(0, NULL); + for (; ob != NULL; ob = ob->next) { + if (!strncmp(estr, ob->name, ckto)) { + if (*(ob->name + ckto) != '/' && *(ob->name + ckto) != '\0') + continue; + + pobj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, pobj, + Tcl_NewStringObj(ob->name + ckto + 1, -1)); + + for (nob = np->cell; nob != NULL; nob = nob->next) { + if (nob->node == ob->node) { + if (nob->type < FIRSTPIN) { + Tcl_ListObjAppendElement(interp, pobj, + Tcl_NewStringObj(nob->name, -1)); + break; + } + } + } + Tcl_ListObjAppendElement(interp, lobj, pobj); + } + } + Tcl_SetObjResult(interp, lobj); + } + else + ElementNodes(cstr, estr, fnum); + } + else + PrintNodes(cstr, fnum); + + if (istr) Tcl_Free(istr); + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netgen_elements */ +/* Syntax: netgen::elements [-list ] [] */ +/* Formerly: e */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_elements(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *nstr = NULL, *cstr; + struct objlist * (*ListSave)(); + char *optstart; + int dolist = 0; + int fnum = -1; + int result; + struct nlist *np = NULL; + + if (objc > 1) { + optstart = Tcl_GetString(objv[1]); + if (*optstart == '-') optstart++; + if (!strcmp(optstart, "list")) { + dolist = 1; + objv++; + objc--; + } + } + + if (objc < 1 || objc > 2) { + Tcl_WrongNumArgs(interp, 1, objv, "?node? valid_cellname"); + return TCL_ERROR; + } + + if (objc == 1) { + if (CurrentCell == NULL) { + Tcl_WrongNumArgs(interp, 1, objv, "(cell name required)"); + return TCL_ERROR; + } + cstr = CurrentCell->name; + } + else { + result = CommonParseCell(interp, objv[objc - 1], &np, &fnum); + if (result != TCL_OK) return result; + + cstr = np->name; + if (objc == 3) + nstr = Tcl_GetString(objv[1]); + } + + if (nstr) { + if (dolist) { + struct objlist *ob; + Tcl_Obj *lobj; + int nodenum; + + if (np == NULL) np = LookupCellFile(cstr, fnum); + + if (np == NULL) { + Tcl_SetResult(interp, "No such cell.", NULL); + return TCL_ERROR; + } + + for (ob = np->cell; ob != NULL; ob = ob->next) { + if (match(nstr, ob->name)) { + nodenum = ob->node; + break; + } + } + if (ob == NULL) { + Tcl_SetResult(interp, "No such node.", NULL); + return TCL_ERROR; + } + lobj = Tcl_NewListObj(0, NULL); + for (ob = np->cell; ob != NULL; ob = ob->next) { + if (ob->node == nodenum && ob->type >= FIRSTPIN) { + char *obname = ob->name; + if (*obname == '/') obname++; + Tcl_ListObjAppendElement(interp, lobj, + Tcl_NewStringObj(obname, -1)); + } + } + Tcl_SetObjResult(interp, lobj); + } + else + Fanout(cstr, nstr, ALLELEMENTS); + } + else { + PrintAllElements(cstr, fnum); + } + + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netgen_debug */ +/* Syntax: netgen::debug [on|off] or debug command */ +/* Formerly: D */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_debug(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *yesno[] = { + "on", "off", NULL + }; + enum OptionIdx { + YES_IDX, NO_IDX, CMD_IDX + }; + int result, index; + char *command; + + if (objc == 1) + index = YES_IDX; + else { + if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)yesno, + "option", 0, &index) != TCL_OK) { + index = CMD_IDX; + } + } + + switch(index) { + case YES_IDX: + Debug = TRUE; + break; + case NO_IDX: + Debug = FALSE; + break; + case CMD_IDX: + /* Need to redefine DBUG_PUSH! */ + command = Tcl_GetString(objv[1]); + DBUG_PUSH(command); + } + + if (index != CMD_IDX) + Printf("Debug mode is %s\n", Debug?"ON":"OFF"); + + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netgen_protochip */ +/* Syntax: netgen::protochip */ +/* Formerly: P */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_protochip(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + if (objc != 1) { + Tcl_WrongNumArgs(interp, 1, objv, "(no arguments)"); + return TCL_ERROR; + } + PROTOCHIP(); + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netgen_instances */ +/* Syntax: netgen::instances valid_cellname */ +/* Formerly: i */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_instances(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *repstr; + int result; + int fnum = -1; + struct nlist *np = NULL; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "valid_cellname"); + return TCL_ERROR; + } + + result = CommonParseCell(interp, objv[1], &np, &fnum); + if (result != TCL_OK) return result; + + repstr = np->name; + PrintInstances(repstr, fnum); + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netgen_contents */ +/* Syntax: netgen::contents valid_cellname */ +/* Formerly: c */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_contents(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *repstr; + int result; + int fnum = -1; + struct nlist *np = NULL; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "valid_cellname"); + return TCL_ERROR; + } + result = CommonParseCell(interp, objv[1], &np, &fnum); + if (result != TCL_OK) return result; + + repstr = np->name; + PrintCell(repstr, fnum); + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netgen_describe */ +/* Syntax: netgen::describe valid_cellname */ +/* Formerly: d */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_describe(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *repstr; + int file = -1; + int result; + struct nlist *np = NULL; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "valid_cellname"); + return TCL_ERROR; + } + + result = CommonParseCell(interp, objv[1], &np, &file); + if (result != TCL_OK) return result; + + repstr = np->name; + DescribeInstance(repstr, file); + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netgen_cells */ +/* Syntax: netgen::cells [list|all] [valid_filename] */ +/* Formerly: h and H */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_cells(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *repstr, *filename = NULL; + char *optstart; + int filenum = -1; + struct nlist *np = NULL; + int result, dolist = 0; + + if (objc > 1) { + optstart = Tcl_GetString(objv[1]); + if (*optstart == '-') optstart++; + if (!strcmp(optstart, "list")) { + dolist = 1; + objv++; + objc--; + } + } + + if (objc == 1) { + PrintCellHashTable((dolist) ? 2 : 0, -1); + } + else if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "[-all|-top|valid_filename]"); + return TCL_ERROR; + } + else { + Tcl_Obj *lobj; + + repstr = Tcl_GetString(objv[1]); + if (!strncmp(repstr, "-top", 4)) { + if (dolist) + lobj = Tcl_NewListObj(0, NULL); + else + Fprintf(stdout, "Top level cells: "); + np = FirstCell(); + while (np != NULL) { + if (np->flags & CELL_TOP) { + if (dolist) + Tcl_ListObjAppendElement(interp, lobj, + Tcl_NewStringObj(np->name, -1)); + else + Fprintf(stdout, "%s ", np->name); + } + np = NextCell(); + } + if (dolist) + Tcl_SetObjResult(interp, lobj); + else + Fprintf(stdout, "\n"); + + return TCL_OK; + } + else if (strncmp(repstr, "-all", 4)) { + result = CommonParseCell(interp, objv[1], &np, &filenum); + if (result != TCL_OK) return result; + } + PrintCellHashTable((dolist) ? 2 : 1, filenum); + } + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netgen_model */ +/* Syntax: netgen::model valid_cellname class */ +/* Formerly: (nothing) */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_model(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + struct nlist *tp; + char *model, *retclass; + unsigned char class; + int fnum = -1; + int result, index, nports; + + char *modelclasses[] = { + "undefined", "nmos", "pmos", "pnp", "npn", + "resistor", "capacitor", "diode", + "inductor", "module", "blackbox", "xline", + "moscap", "mosfet", "bjt", "subcircuit", NULL + }; + enum OptionIdx { + UNDEF_IDX, NMOS_IDX, PMOS_IDX, PNP_IDX, NPN_IDX, + RES_IDX, CAP_IDX, DIODE_IDX, INDUCT_IDX, + MODULE_IDX, BLACKBOX_IDX, XLINE_IDX, MOSCAP_IDX, + MOSFET_IDX, BJT_IDX, SUBCKT_IDX + }; + + if (objc != 3 && objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "valid_cellname [class]"); + return TCL_ERROR; + } + + result = CommonParseCell(interp, objv[1], &tp, &fnum); + if (result != TCL_OK) return result; + + if (objc == 3) { + model = Tcl_GetString(objv[2]); + nports = NumberOfPorts(model); + + if (Tcl_GetIndexFromObj(interp, objv[2], (CONST84 char **)modelclasses, + "class", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + switch (index) { + case UNDEF_IDX: + class = CLASS_UNDEF; + break; + case NMOS_IDX: + if (nports != 4 && nports != 3) goto wrongNumPorts; + class = (nports == 4) ? CLASS_NMOS4 : CLASS_NMOS; + break; + case PMOS_IDX: + if (nports != 4 && nports != 3) goto wrongNumPorts; + class = (nports == 4) ? CLASS_PMOS4 : CLASS_PMOS; + break; + case PNP_IDX: + if (nports != 3) goto wrongNumPorts; + class = CLASS_PNP; + break; + case NPN_IDX: + if (nports != 3) goto wrongNumPorts; + class = CLASS_NPN; + break; + case RES_IDX: + if (nports != 2 && nports != 3) goto wrongNumPorts; + class = (nports == 2) ? CLASS_RES : CLASS_RES3; + break; + case CAP_IDX: + if (nports != 2 && nports != 3) goto wrongNumPorts; + class = (nports == 2) ? CLASS_CAP : CLASS_CAP3; + break; + case DIODE_IDX: + if (nports != 2) goto wrongNumPorts; + class = CLASS_DIODE; + break; + case INDUCT_IDX: + if (nports != 2) goto wrongNumPorts; + class = CLASS_INDUCTOR; + break; + case XLINE_IDX: + if (nports != 4) goto wrongNumPorts; + class = CLASS_XLINE; + break; + case BJT_IDX: + if (nports != 3) goto wrongNumPorts; + class = CLASS_BJT; + break; + case MOSFET_IDX: + if (nports != 4 && nports != 3) goto wrongNumPorts; + class = (nports == 4) ? CLASS_FET4 : CLASS_FET; + break; + case MOSCAP_IDX: + if (nports != 3) goto wrongNumPorts; + class = CLASS_ECAP; + break; + case MODULE_IDX: + case BLACKBOX_IDX: + class = CLASS_MODULE; + break; + case SUBCKT_IDX: + class = CLASS_SUBCKT; + break; + } + tp->class = class; + } + else { + class = tp->class; + + switch (class) { + case CLASS_NMOS: case CLASS_NMOS4: + retclass = modelclasses[NMOS_IDX]; + break; + + case CLASS_PMOS: case CLASS_PMOS4: + retclass = modelclasses[PMOS_IDX]; + break; + + case CLASS_FET3: case CLASS_FET4: case CLASS_FET: + retclass = "mosfet"; + break; + + case CLASS_BJT: + retclass = "bipolar"; + break; + + case CLASS_NPN: + retclass = modelclasses[NPN_IDX]; + break; + + case CLASS_PNP: + retclass = modelclasses[PNP_IDX]; + break; + + case CLASS_RES: case CLASS_RES3: + retclass = modelclasses[RES_IDX]; + break; + + case CLASS_CAP: case CLASS_ECAP: case CLASS_CAP3: + retclass = modelclasses[CAP_IDX]; + break; + + case CLASS_SUBCKT: + retclass = modelclasses[SUBCKT_IDX]; + break; + + default: /* (includes case CLASS_UNDEF) */ + retclass = modelclasses[UNDEF_IDX]; + break; + } + Tcl_SetResult(interp, retclass, NULL); + } + return TCL_OK; + +wrongNumPorts: + Tcl_SetResult(interp, "Wrong number of ports for device", NULL); + return TCL_ERROR; +} + +/*------------------------------------------------------*/ +/* Function name: _netgen_ports */ +/* Syntax: netgen::ports cell */ +/* Formerly: p */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_ports(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *repstr; + int result; + struct nlist *np; + int filenum = -1; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "valid_cellname"); + return TCL_ERROR; + } + + result = CommonParseCell(interp, objv[1], &np, &filenum); + if (result != TCL_OK) return result; + repstr = np->name; + + PrintPortsInCell(repstr, filenum); + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netgen_leaves */ +/* Syntax: netgen::leaves [valid_cellname] */ +/* Formerly: l and L */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_leaves(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *repstr; + int result; + int filenum = -1; + struct nlist *np; + + if (objc != 1 && objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "[valid_cellname]"); + return TCL_ERROR; + } + if (objc == 1) { + Printf("List of all leaf cells:\n"); + PrintAllLeaves(); + } + else { + result = CommonParseCell(interp, objv[1], &np, &filenum); + if (result != TCL_OK) return result; + + repstr = np->name; + ClearDumpedList(); + PrintLeavesInCell(repstr, filenum); + } + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netgen_quit */ +/* Syntax: netgen::quit */ +/* Formerly: q and Q */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_quit(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + if (objc != 1) { + Tcl_WrongNumArgs(interp, 1, objv, "(no arguments)"); + return TCL_ERROR; + } + + /* Call tkcon's exit routine, which will make sure */ + /* the history file is updated before final exit. */ + + if (consoleinterp == interp) + Tcl_Exit(TCL_OK); + else + Tcl_Eval(interp, "catch {tkcon eval exit}\n"); + + return TCL_OK; /* Not reached */ +} + +/*------------------------------------------------------*/ +/* Function name: _netgen_reinit */ +/* Syntax: netgen::reinitialize */ +/* Formerly: I */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_reinit(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + if (objc != 1) { + Tcl_WrongNumArgs(interp, 1, objv, "(no arguments)"); + return TCL_ERROR; + } + Initialize(); + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netgen_log */ +/* Syntax: netgen::log [option...] */ +/* Formerly: (xnetgen command only) */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_log(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *yesno[] = { + "start", "end", "reset", "suspend", "resume", "file", "echo", "put", NULL + }; + enum OptionIdx { + START_IDX, END_IDX, RESET_IDX, SUSPEND_IDX, RESUME_IDX, FILE_IDX, + ECHO_IDX, PUT_IDX + }; + int result, index, i; + char *tmpstr; + FILE *file; + + if (objc == 1) { + index = (LoggingFile) ? RESUME_IDX : START_IDX; + } + else { + if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)yesno, + "option", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + } + + switch(index) { + case START_IDX: + case RESUME_IDX: + if (LoggingFile) { + Tcl_SetResult(interp, "Already logging output.", NULL); + return TCL_ERROR; + } + break; + case END_IDX: + case RESET_IDX: + case SUSPEND_IDX: + if (!LoggingFile) { + Tcl_SetResult(interp, "Not logging data.", NULL); + return TCL_ERROR; + } + /* Don't leave echo off if we're stopping the log */ + if (NoOutput) NoOutput = FALSE; + break; + } + + switch(index) { + case START_IDX: + case RESUME_IDX: + case RESET_IDX: + if (LogFileName == NULL) { + Tcl_SetResult(interp, "No log file declared. " + "Use \"log file \"", NULL); + return TCL_ERROR; + } + break; + } + + switch(index) { + case START_IDX: + LoggingFile = fopen(LogFileName, "w"); + break; + case RESUME_IDX: + LoggingFile = fopen(LogFileName, "a"); + break; + case END_IDX: + fclose(LoggingFile); + LoggingFile = FALSE; + break; + case RESET_IDX: + fclose(LoggingFile); + LoggingFile = fopen(LogFileName, "w"); + break; + case SUSPEND_IDX: + fclose(LoggingFile); + LoggingFile = FALSE; + break; + case FILE_IDX: + if (objc == 2) + Tcl_SetResult(interp, LogFileName, NULL); + else { + if (LoggingFile) { + fclose(LoggingFile); + LoggingFile = FALSE; + Printf("Closed old log file \"%s\".\n", LogFileName); + } + tmpstr = Tcl_GetString(objv[2]); + if (LogFileName) Tcl_Free(LogFileName); + LogFileName = (char *)Tcl_Alloc(1 + strlen(tmpstr)); + strcpy(LogFileName, tmpstr); + } + break; + case PUT_IDX: + // All arguments after "log put" get sent to stdout through Tcl, + // and also to the logfile, if the logfile is enabled. + for (i = 2; i < objc; i++) { + Fprintf(stdout, Tcl_GetString(objv[i])); + } + if (!NoOutput) Printf("\n"); + return TCL_OK; + case ECHO_IDX: + if (objc == 2) { + Tcl_SetResult(interp, (NoOutput) ? "off" : "on", NULL); + } + else { + int bval; + result = Tcl_GetBooleanFromObj(interp, objv[2], &bval); + if (result == TCL_OK) + NoOutput = (bval) ? FALSE : TRUE; + else + return result; + } + if (Debug) + Printf("Echoing log file \"%s\" output to console %s\n", + LogFileName, (NoOutput) ? "disabled" : "enabled"); + return TCL_OK; + } + if ((index != FILE_IDX) && (index != ECHO_IDX)) + Printf("Logging to file \"%s\" %s\n", LogFileName, + (LoggingFile) ? "enabled" : "disabled"); + + return TCL_OK; +} + +#ifdef HAVE_MALLINFO +/*------------------------------------------------------*/ +/* Function name: _netgen_printmem */ +/* Syntax: netgen::memory */ +/* Formerly: m */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netgen_printmem(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + if (objc != 1) { + Tcl_WrongNumArgs(interp, 1, objv, "(no arguments)"); + return TCL_ERROR; + } + PrintMemoryStats(); + return TCL_OK; +} +#endif + +/*------------------------------------------------------*/ +/* The following code breaks up the NETCOMP() command */ +/* from netcmp.c into individual functions w/arguments */ +/*------------------------------------------------------*/ + +/*------------------------------------------------------*/ +/* Function name: _netcmp_compare */ +/* Syntax: */ +/* netgen::compare valid_cellname1 valid_cellname2 */ +/* Formerly: c */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netcmp_compare(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *name1, *name2, *file1, *file2; + int fnum1, fnum2; + int dohierarchy = FALSE; + int assignonly = FALSE; + int argstart = 1, qresult, llen, result; + struct Correspond *nextcomp; + struct nlist *tp; + + if (objc > 1) { + if (!strncmp(Tcl_GetString(objv[argstart]), "assign", 6)) { + assignonly = TRUE; + argstart++; + } + else if (!strncmp(Tcl_GetString(objv[argstart]), "hier", 4)) { + dohierarchy = TRUE; + argstart++; + } + } + + fnum1 = -1; + fnum2 = -1; + + if (((objc - argstart) == 2) || ((dohierarchy && ((objc - argstart) == 0)))) { + + if (dohierarchy && ((objc - argstart) == 0)) { + + qresult = GetCompareQueueTop(&name1, &fnum1, &name2, &fnum2); + if (qresult == -1) { + Tcl_Obj *lobj; + + // When queue is empty, return a null list + lobj = Tcl_NewListObj(0, NULL); + Tcl_SetObjResult(interp, lobj); + return TCL_OK; + } + } + else if ((objc - argstart) == 2) { + + result = CommonParseCell(interp, objv[argstart], &tp, &fnum1); + if (result != TCL_OK) return TCL_ERROR; + else if (fnum1 == -1) { + Tcl_SetResult(interp, "Cannot use wildcard with compare command.\n", + NULL); + return TCL_ERROR; + } + name1 = tp->name; + argstart++; + + result = CommonParseCell(interp, objv[argstart], &tp, &fnum2); + if (result != TCL_OK) return TCL_ERROR; + else if (fnum2 == -1) { + Tcl_SetResult(interp, "Cannot use wildcard with compare command.\n", + NULL); + return TCL_ERROR; + } + name2 = tp->name; + + if (dohierarchy) { + RemoveCompareQueue(); + qresult = CreateCompareQueue(name1, fnum1, name2, fnum2); + if (qresult != 0) { + Tcl_AppendResult(interp, "No such cell ", + (qresult == 1) ? name1 : name2, NULL); + return TCL_ERROR; + } + GetCompareQueueTop(&name1, &fnum1, &name2, &fnum2); + } + else if (assignonly) { + AssignCircuits(name1, fnum1, name2, fnum2); + return TCL_OK; + } + } + } + else { + Tcl_WrongNumArgs(interp, 1, objv, + "[hierarchical] valid_cellname1 valid_cellname2"); + return TCL_ERROR; + } + + if (fnum1 == fnum2) { + Tcl_SetResult(interp, "Cannot compare two cells in the same netlist.", + NULL); + return TCL_ERROR; + } + + CleanupPins(name1, fnum1); // Remove unconnected pins + CleanupPins(name2, fnum2); // Remove unconnected pins + + UniquePins(name1, fnum1); // Check for and remove duplicate pins + UniquePins(name2, fnum2); // Check for and remove duplicate pins + + // Resolve global nodes into local nodes and ports + if (dohierarchy) { + ConvertGlobals(name1, fnum1); + ConvertGlobals(name2, fnum2); + } + + // Run cleanup a 2nd time; this corrects for cells that have no ports + // but define global nodes that are brought out as ports by + // ConvertGlobals(). + + CleanupPins(name1, fnum1); + CleanupPins(name2, fnum2); + + CreateTwoLists(name1, fnum1, name2, fnum2); + while (PrematchLists(name1, fnum1, name2, fnum2) > 0) { + Fprintf(stdout, "Making another compare attempt.\n"); + CreateTwoLists(name1, fnum1, name2, fnum2); + } + + // Return the names of the two cells being compared, if doing "compare + // hierarchical" + + if (dohierarchy) { + Tcl_Obj *lobj; + + lobj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj(name1, -1)); + Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj(name2, -1)); + Tcl_SetObjResult(interp, lobj); + } + +#ifdef DEBUG_ALLOC + PrintCoreStats(); +#endif + + /* Arrange properties in the two compared cells */ + /* ResolveProperties(name1, fnum1, name2, fnum2); */ + + Permute(); /* Apply permutations */ + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netcmp_iterate */ +/* Syntax: netgen::iterate */ +/* Formerly: i */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netcmp_iterate(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + if (objc != 1) { + Tcl_WrongNumArgs(interp, 1, objv, "(no arguments)"); + return TCL_ERROR; + } + if (!Iterate()) + Printf("Please iterate again.\n"); + else + Printf("No fractures made: we're done.\n"); + + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netcmp_summary */ +/* Syntax: netgen::summary [elements|nodes] */ +/* Formerly: s */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netcmp_summary(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *options[] = { + "nodes", "elements", NULL + }; + enum OptionIdx { + NODE_IDX, ELEM_IDX + }; + int result, index = -1; + + if (objc != 1 && objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "?nodes|elements?"); + return TCL_ERROR; + } + if (objc == 2) { + if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)options, + "option", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + } + + if (objc == 1 || index == ELEM_IDX) + SummarizeElementClasses(ElementClasses); + + if (objc == 1 || index == NODE_IDX) + SummarizeNodeClasses(NodeClasses); + + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netcmp_print */ +/* Syntax: netgen::print [elements|nodes|queue] */ +/* [legal|illegal] */ +/* Formerly: P */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netcmp_print(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *options[] = { + "nodes", "elements", "queue", NULL + }; + enum OptionIdx { + NODE_IDX, ELEM_IDX, QUEUE_IDX + }; + + /* Note: The order is such that the type passed to PrintElementClasses() + * or PrintNodeClasses() is -1 for all, 0 for legal, and 1 for illegal + */ + char *classes[] = { + "legal", "illegal", NULL + }; + enum ClassIdx { + LEGAL_IDX, ILLEGAL_IDX + }; + + int result, index = -1, class = -1, dolist = 0; + int fnum1, fnum2; + char *optstart; + + if (objc > 1) { + optstart = Tcl_GetString(objv[1]); + if (*optstart == '-') optstart++; + if (!strcmp(optstart, "list")) { + dolist = 1; + objv++; + objc--; + } + } + + if (objc < 1 || objc > 3) { + Tcl_WrongNumArgs(interp, 1, objv, "?nodes|elements|queue? ?legal|illegal?"); + return TCL_ERROR; + } + if (objc >= 2) { + if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)options, + "option", 0, &index) != TCL_OK) { + if ((objc == 2) && (Tcl_GetIndexFromObj(interp, objv[1], + (CONST84 char **)classes, "class", 0, &class) != TCL_OK)) { + return TCL_ERROR; + } + } + } + if (objc == 3 && index != QUEUE_IDX) { + if (Tcl_GetIndexFromObj(interp, objv[2], (CONST84 char **)classes, + "class", 0, &class) != TCL_OK) { + return TCL_ERROR; + } + } + else if (objc == 3) { + Tcl_WrongNumArgs(interp, 1, objv, "queue [no arguments]"); + return TCL_ERROR; + } + + enable_interrupt(); + if (objc == 1 || index == NODE_IDX) + PrintNodeClasses(NodeClasses, class, dolist); + + if (objc == 1 || index == ELEM_IDX) + PrintElementClasses(ElementClasses, class, dolist); + + if (objc == 2 && index == QUEUE_IDX) { + char *name1, *name2; + Tcl_Obj *lobj; + result = PeekCompareQueueTop(&name1, &fnum1, &name2, &fnum2); + lobj = Tcl_NewListObj(0, NULL); + if (result != -1) { + Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj(name1, -1)); + Tcl_ListObjAppendElement(interp, lobj, Tcl_NewStringObj(name2, -1)); + } + Tcl_SetObjResult(interp, lobj); + } + + disable_interrupt(); + + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netcmp_run */ +/* Syntax: netgen::run [converge|resolve] */ +/* Formerly: r and R */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netcmp_run(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *options[] = { + "converge", "resolve", NULL + }; + enum OptionIdx { + CONVERGE_IDX, RESOLVE_IDX + }; + int result, index; + int automorphisms; + + if (objc == 1) + index = RESOLVE_IDX; + else { + if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)options, + "option", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + } + + switch(index) { + case CONVERGE_IDX: + if (ElementClasses == NULL || NodeClasses == NULL) { + return TCL_OK; + } + else { + enable_interrupt(); + while (!Iterate() && !InterruptPending); + _netcmp_verify(clientData, interp, 1, NULL); + disable_interrupt(); + } + break; + case RESOLVE_IDX: + if (ElementClasses == NULL || NodeClasses == NULL) { + // Printf("Must initialize data structures first.\n"); + // return TCL_ERROR; + return TCL_OK; + } + else { + enable_interrupt(); + while (!Iterate() && !InterruptPending); + automorphisms = VerifyMatching(); + if (automorphisms == -1) + Fprintf(stdout, "Netlists do not match.\n"); + else if (automorphisms == 0) + Fprintf(stdout, "Netlists match uniquely.\n"); + else { + // First try to resolve automorphisms uniquely using + // property matching + automorphisms = ResolveAutomorphsByProperty(); + if (automorphisms == 0) + Fprintf(stdout, "Netlists match uniquely.\n"); + else { + + // Next, attempt to resolve automorphisms uniquely by + // using the pin names + automorphisms = ResolveAutomorphsByPin(); + } + + if (automorphisms == 0) + Fprintf(stdout, "Netlists match uniquely.\n"); + else + // Anything left is truly indistinguishable + Fprintf(stdout, "Netlists match with %d symmetr%s.\n", + automorphisms, (automorphisms == 1) ? "y" : "ies"); + + while ((automorphisms = ResolveAutomorphisms()) > 0); + if (automorphisms == -1) Fprintf(stdout, "Netlists do not match.\n"); + else Fprintf(stdout, "Circuits match correctly.\n"); + } + if (PropertyErrorDetected) { + Fprintf(stdout, "There were property errors.\n"); + PrintPropertyResults(); + } + disable_interrupt(); + } + break; + } + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netcmp_verify */ +/* Syntax: netgen::verify [option] */ +/* options: nodes, elements, only, all, */ +/* equivalent, or unique. */ +/* Formerly: v */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netcmp_verify(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *options[] = { + "nodes", "elements", "properties", "only", "all", "equivalent", "unique", NULL + }; + enum OptionIdx { + NODE_IDX, ELEM_IDX, PROP_IDX, ONLY_IDX, ALL_IDX, EQUIV_IDX, UNIQUE_IDX + }; + int result, index = -1; + int automorphisms; + + if (objc != 1 && objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, + "?nodes|elements|only|all|equivalent|unique?"); + return TCL_ERROR; + } + if (objc == 2) { + if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)options, + "option", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + } + + if (ElementClasses == NULL || NodeClasses == NULL) { + Fprintf(stderr, "Cell has no elements and/or nodes.\n"); + Tcl_SetObjResult(interp, Tcl_NewIntObj(-1)); + // return TCL_ERROR; + return TCL_OK; + } + else { + automorphisms = VerifyMatching(); + if (automorphisms == -1) { + enable_interrupt(); + if (objc == 1 || index == NODE_IDX || index == ALL_IDX) { + if (Debug == TRUE) + PrintIllegalNodeClasses(); // Old style + else + FormatIllegalNodeClasses(); // Side-by-side + } + if (objc == 1 || index == ELEM_IDX || index == ALL_IDX) { + if (Debug == TRUE) + PrintIllegalElementClasses(); // Old style + else + FormatIllegalElementClasses(); // Side-by-side + } + disable_interrupt(); + if (index == EQUIV_IDX || index == UNIQUE_IDX) + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); + else + Fprintf(stdout, "Netlists do not match.\n"); + } + else { + if (automorphisms) { + if (index == EQUIV_IDX) + Tcl_SetObjResult(interp, Tcl_NewIntObj((int)automorphisms)); + else if (index == UNIQUE_IDX) + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); + else + Printf("Circuits match with %d symmetr%s.\n", + automorphisms, (automorphisms == 1) ? "y" : "ies"); + } + else { + if ((index == EQUIV_IDX) || (index == UNIQUE_IDX)) { + if (PropertyErrorDetected == 0) + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1)); + else + Tcl_SetObjResult(interp, Tcl_NewIntObj(2)); + } + else { + Fprintf(stdout, "Circuits match uniquely.\n"); + if (PropertyErrorDetected != 0) + Fprintf(stdout, "Property errors were found.\n"); + } + } + if ((index == PROP_IDX) && (PropertyErrorDetected != 0)) { + PrintPropertyResults(); + } + } + } + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netcmp_automorphs */ +/* Syntax: netgen::automorphisms */ +/* Formerly: a */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netcmp_automorphs(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + if (objc != 1) { + Tcl_WrongNumArgs(interp, 1, objv, "(no arguments)"); + return TCL_ERROR; + } + PrintAutomorphisms(); + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netcmp_convert */ +/* Syntax: netgen::convert */ +/* Formerly: nonexistant function */ +/* Results: none */ +/* Side Effects: one or more global nodes changed to */ +/* local scope and ports. */ +/*------------------------------------------------------*/ + +int +_netcmp_convert(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *cellname; + int filenum = -1; + int result; + struct nlist *np; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "valid_cellname"); + return TCL_ERROR; + } + result = CommonParseCell(interp, objv[1], &np, &filenum); + if (result != TCL_OK) return result; + cellname = np->name; + + ConvertGlobals(cellname, filenum); + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netcmp_global */ +/* Syntax: netgen::global */ +/* Formerly: nonexistant function */ +/* Results: returns number of matching nets found */ +/* Side Effects: one or more nodes changed to global */ +/* scope. */ +/*------------------------------------------------------*/ + +int +_netcmp_global(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *filename, *cellname, *pattern; + int numchanged = 0, p, fnum, llen, result; + struct nlist *tp; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, " [...]"); + return TCL_ERROR; + } + + /* Check if first argument is a file number */ + + result = CommonParseCell(interp, objv[1], &tp, &fnum); + if (result != TCL_OK) return result; + cellname = tp->name; + + for (p = 2; p < objc; p++) { + pattern = Tcl_GetString(objv[p]); + numchanged += ChangeScope(fnum, cellname, pattern, NODE, GLOBAL); + } + + Tcl_SetObjResult(interp, Tcl_NewIntObj(numchanged)); + return TCL_OK; +} + + +/*------------------------------------------------------*/ +/* Function name: _netcmp_ignore */ +/* Syntax: netgen::ignore [class] */ +/* Formerly: no such command */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netcmp_ignore(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *options[] = { + "class", NULL + }; + enum OptionIdx { + CLASS_IDX + }; + int result, index; + int file = -1; + struct nlist *np; + char *name = NULL, *name2 = NULL; + + if (objc >= 3) { + if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)options, + "option", 0, &index) == TCL_OK) { + objc--; + objv++; + } + result = CommonParseCell(interp, objv[1], &np, &file); + if (result != TCL_OK) return result; + name = np->name; + } + else { + Tcl_WrongNumArgs(interp, 1, objv, "[class] valid_cellname"); + return TCL_ERROR; + } + IgnoreClass(name, file); + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netcmp_equate */ +/* Syntax: netgen::equate [elements|nodes|classes|pins] */ +/* Formerly: e and n */ +/* Results: */ +/* Side Effects: */ +/*------------------------------------------------------*/ + +int +_netcmp_equate(ClientData clientData, + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *options[] = { + "nodes", "elements", "classes", "pins", NULL + }; + enum OptionIdx { + NODE_IDX, ELEM_IDX, CLASS_IDX, PINS_IDX + }; + int result, index; + char *name1 = NULL, *name2 = NULL; + struct nlist *tp1, *tp2; + struct objlist *ob1, *ob2; + int file1, file2; + int i, l1, l2, ltest, lent; + Tcl_Obj *tobj1, *tobj2, *tobj3; + + if ((objc != 2) && (objc != 4) && (objc != 6)) { + Tcl_WrongNumArgs(interp, 1, objv, "?nodes|elements|classes|pins? name1 name2"); + return TCL_ERROR; + } + else { + if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)options, + "option", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + } + + /* Something is going on here. . . */ + if (index > PINS_IDX) index = PINS_IDX; + + /* 4-argument form only available for "equate classes", or for other */ + /* options if Circuit1 and Circuit2 have been declared. */ + + if ((objc == 2) && (index == PINS_IDX)) { + if (Circuit1 == NULL || Circuit2 == NULL) { + Tcl_SetResult(interp, "Circuits not being compared, must specify netlists.", + NULL); + return TCL_ERROR; + } + tp1 = Circuit1; + file1 = Circuit1->file; + tp2 = Circuit2; + file2 = Circuit2->file; + + name1 = tp1->name; + name2 = tp2->name; + } + else if ((objc == 4) && (index != CLASS_IDX) && (index != PINS_IDX)) { + if (Circuit1 == NULL || Circuit2 == NULL) { + Tcl_SetResult(interp, "Circuits not being compared, must specify netlists.", + NULL); + return TCL_ERROR; + } + tp1 = Circuit1; + file1 = Circuit1->file; + tp2 = Circuit2; + file2 = Circuit2->file; + + name1 = Tcl_GetString(objv[2]); + name2 = Tcl_GetString(objv[3]); + } + + else if ((objc == 4) && ((index == CLASS_IDX) || (index == PINS_IDX))) { + result = CommonParseCell(interp, objv[2], &tp1, &file1); + if (result != TCL_OK) { + if (index == CLASS_IDX) { + Fprintf(stdout, "Cell to equate does not exist.\n"); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); + return result; + } + Tcl_SetResult(interp, "No such object.", NULL); + return TCL_ERROR; + } + result = CommonParseCell(interp, objv[3], &tp2, &file2); + if (result != TCL_OK) { + if (index == CLASS_IDX) { + Fprintf(stdout, "Cell to equate does not exist.\n"); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); + return result; + } + Tcl_SetResult(interp, "No such object.", NULL); + return TCL_ERROR; + } + if (file1 == file2) { + if (index == CLASS_IDX) { + Fprintf(stdout, "Cells to equate are in the same netlist.\n"); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); + return TCL_ERROR; + } + Tcl_SetResult(interp, "Objects in the same netlist cannot be equated.", + NULL); + return TCL_ERROR; + } + name1 = tp1->name; + name2 = tp2->name; + } + + else if (objc == 6) { + result = CommonParseCell(interp, objv[2], &tp1, &file1); + if (result != TCL_OK) { + if (index == CLASS_IDX) { + Fprintf(stdout, "Cell to equate does not exist.\n"); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); + } + return result; + } + result = CommonParseCell(interp, objv[4], &tp2, &file2); + if (result != TCL_OK) { + if (index == CLASS_IDX) { + Fprintf(stdout, "Cell to equate does not exist.\n"); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); + } + return result; + } + + if (file1 == file2) { + if (index == CLASS_IDX) { + Tcl_ResetResult(interp); + Fprintf(stdout, "Cells to equate are in the same netlist.\n"); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); + return TCL_ERROR; + } + Tcl_SetResult(interp, "Cannot equate within the same netlist!\n", + NULL); + return TCL_ERROR; + } + name1 = Tcl_GetString(objv[3]); + name2 = Tcl_GetString(objv[5]); + } + else { + Tcl_WrongNumArgs(interp, 1, objv, "?nodes|elements|classes|pins? name1 name2"); + return TCL_ERROR; + } + + switch(index) { + case NODE_IDX: + if (NodeClasses == NULL) { + Fprintf(stderr, "Cell has no nodes.\n"); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); + return TCL_OK; + } + if (EquivalenceNodes(name1, file1, name2, file2)) { + Fprintf(stdout, "Nodes %s and %s are equivalent.\n", name1, name2); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1)); + } + else { + Fprintf(stderr, "Unable to equate nodes %s and %s.\n",name1, name2); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); + } + break; + + case ELEM_IDX: + if (ElementClasses == NULL) { + Fprintf(stderr, "Cell has no elements.\n"); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); + return TCL_OK; + } + if (EquivalenceElements(name1, file1, name2, file2)) { + Fprintf(stdout, "Elements %s and %s are equivalent.\n", name1, name2); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1)); + } + else { + Fprintf(stderr, "Unable to equate elements %s and %s.\n",name1, name2); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); + } + break; + + case PINS_IDX: + if (ElementClasses == NULL) { + Fprintf(stderr, "Cell has no elements.\n"); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); + return TCL_OK; + } + if (tp1 == Circuit1 && tp2 == Circuit2) { + if (MatchPins(tp1, tp2)) { + Fprintf(stdout, "Cell pin lists are equivalent.\n"); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1)); + } + else { + Fprintf(stdout, "Cell pin lists for %s and %s altered to match.\n", + name1, name2); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); + } + } + else { + Fprintf(stderr, "Function not yet defined outside of LVS scope.\n"); + } + break; + + case CLASS_IDX: + + if (objc == 6) { + + /* Apply additional matching of pins */ + /* Objects must be CLASS_MODULE or CLASS_SUBCKT */ + + if (tp1->class != CLASS_MODULE && tp1->class != CLASS_SUBCKT) { + Tcl_SetResult(interp, "Device class is not black box" + " or subcircuit!", NULL); + return TCL_ERROR; + } + if (tp2->class != tp1->class) { + Tcl_SetResult(interp, "Device classes are different," + " cannot match pins!", NULL); + return TCL_ERROR; + } + + /* Count the list items, and the number of ports in each cell */ + result = Tcl_ListObjLength(interp, objv[3], &l1); + if (result != TCL_OK) return TCL_ERROR; + result = Tcl_ListObjLength(interp, objv[5], &l2); + if (result != TCL_OK) return TCL_ERROR; + if (l1 != l2) { + Tcl_SetResult(interp, "Pin lists are different length," + " cannot match pins!", NULL); + return TCL_ERROR; + } + ltest = 0; + for (ob1 = tp1->cell; ob1 != NULL; ob1 = ob1->next) { + if (ob1->type == PORT) ltest++; + } + if (ltest != l1) { + Tcl_SetResult(interp, "List length does not match " + " number of pins in cell.", NULL); + return TCL_ERROR; + } + ltest = 0; + for (ob2 = tp2->cell; ob2 != NULL; ob2 = ob2->next) { + if (ob2->type == PORT) ltest++; + } + if (ltest != l2) { + Tcl_SetResult(interp, "List length does not match " + " number of pins in cell.", NULL); + return TCL_ERROR; + } + + /* 1st pin list: Check that all list items have 1 or 2 */ + /* entries, and that all of them have the same number */ + + result = Tcl_ListObjIndex(interp, objv[3], 0, &tobj1); + if (result != TCL_OK) return result; + result = Tcl_ListObjLength(interp, tobj1, &lent); + if (result != TCL_OK) return result; + if (lent > 2) { + Tcl_SetResult(interp, "All list items must have one" + " or two entries.", NULL); + return TCL_ERROR; + } + + for (i = 1; i < l1; i++) { + result = Tcl_ListObjIndex(interp, objv[3], i, &tobj1); + if (result != TCL_OK) return result; + result = Tcl_ListObjLength(interp, tobj1, <est); + if (result != TCL_OK) return result; + if (ltest != lent) { + Tcl_SetResult(interp, "All list items must have the" + " same number of entries.", NULL); + return TCL_ERROR; + } + } + + /* If the first pin is a list of 2, then all items */ + /* must be lists of two. If the cell is a */ + /* placeholder, then match the pin number against */ + /* the 2nd list item, and rename the pin. */ + + if (lent == 2) { + for (i = 0; i < l1; i++) { + result = Tcl_ListObjIndex(interp, objv[3], i, &tobj1); + result = Tcl_ListObjIndex(interp, tobj1, 0, &tobj2); + if (result != TCL_OK) return result; + result = Tcl_ListObjIndex(interp, tobj1, 1, &tobj3); + if (result != TCL_OK) return result; + + for (ob1 = tp1->cell; ob1 != NULL; ob1 = ob1->next) { + if (ob1->type == PORT) { + if ((*matchfunc)(ob1->name, Tcl_GetString(tobj3))) { + FREE(ob1->name); + ob1->name = strsave(Tcl_GetString(tobj2)); + Tcl_GetIntFromObj(interp, tobj3, &ob1->model.port); + break; + } + } + } + } + } + + /* If the first pin is a list of 1, then all items */ + /* must be single items. If the cell is a */ + /* placeholder, then flag an error; relying on */ + /* numerical order would be ambiguous. */ + + else { /* lent == 1 */ + if (tp1->flags & CELL_PLACEHOLDER) { + Tcl_SetResult(interp, "No pin order information " + " for the cell.", NULL); + return TCL_ERROR; + } + /* else nothing to do here. . . need to parse */ + /* the second list before we can do anything. */ + } + + /* 2st pin list: Check that all list items have 1 or 2 */ + /* entries, and that all of them have the same number */ + + result = Tcl_ListObjIndex(interp, objv[5], 0, &tobj2); + if (result != TCL_OK) return result; + result = Tcl_ListObjLength(interp, tobj2, &lent); + if (result != TCL_OK) return result; + if (lent > 2) { + Tcl_SetResult(interp, "All list items must have one" + " or two entries.", NULL); + return TCL_ERROR; + } + + for (i = 1; i < l2; i++) { + result = Tcl_ListObjIndex(interp, objv[5], i, &tobj2); + if (result != TCL_OK) return result; + result = Tcl_ListObjLength(interp, tobj2, <est); + if (result != TCL_OK) return result; + if (ltest != lent) { + Tcl_SetResult(interp, "All list items must have the" + " same number of entries.", NULL); + return TCL_ERROR; + } + } + + /* Repeat for the 2nd cell: If the first pin is a */ + /* list of 2, then all items must be lists of two. */ + /* If the cell is a placeholder, then match the pin */ + /* number against the 2nd list item, and rename the */ + /* pin. */ + + if (lent == 2) { + for (i = 0; i < l2; i++) { + result = Tcl_ListObjIndex(interp, objv[5], i, &tobj1); + result = Tcl_ListObjIndex(interp, tobj1, 0, &tobj2); + if (result != TCL_OK) return result; + result = Tcl_ListObjIndex(interp, tobj1, 1, &tobj3); + if (result != TCL_OK) return result; + + for (ob2 = tp2->cell; ob2 != NULL; ob2 = ob2->next) { + if (ob2->type == PORT) { + if ((*matchfunc)(ob2->name, Tcl_GetString(tobj3))) { + FREE(ob2->name); + ob2->name = strsave(Tcl_GetString(tobj2)); + Tcl_GetIntFromObj(interp, tobj3, &ob2->model.port); + break; + } + } + } + } + } + + /* On the 2nd cell, if the first pin is a list of */ + /* 1, and the cell is a placeholder, then we have */ + /* no idea how to order the pins and must flag an */ + /* error. */ + + else { /* lent == 1 */ + if (tp2->flags & CELL_PLACEHOLDER) { + Tcl_SetResult(interp, "No pin order information " + " for the cell.", NULL); + return TCL_ERROR; + } + } + + /* Now that all pins are assigned by name, reorder */ + /* the pin lists of the 2nd cell to match the */ + /* order of the 1st. */ + + /* Reorder the pin lists of instances of the 2nd */ + /* cell to match the order of the 1st. */ + + // pindata.cell2 = tp2; + // RecurseCellHashTable2(pinorder, (void *)(&pindata)); + } + + if (EquivalenceClasses(tp1->name, file1, tp2->name, file2)) { + Fprintf(stdout, "Device classes %s and %s are equivalent.\n", + tp1->name, tp2->name); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1)); + } + else { + Fprintf(stderr, "Unable to equate device classes %s and %s.\n", + tp1->name, tp2->name); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); + } + break; + } + return TCL_OK; +} + +/*------------------------------------------------------*/ +/* Function name: _netcmp_property */ +/* Syntax: netgen::property | [